Neatly Polished Update, with Sample Lesson

Neatly Polished is clear, friendly, in-depth online front-end web development classes

It has been a long time coming (my goodness, those lessons took a lot longer to write than I expected), but I’m happy to say that all 26+ lessons in my Neatly Polished course on WordPress Theme Development are finally live.

In case you aren’t familiar with this project, Neatly Polished is a subscription-model site I created for more in-depth tutorials and lessons than are really reasonable to provide for free via this blog. There are the lessons, plus a support forum where I answer questions and discuss the lessons (and other stuff, sometimes) with participants.

The first full “course” is on WordPress Theme Development, and basically walks through all the files you’d use in a WordPress theme, along with the various theme components and some workflow tips throughout. You can check out the entire course outline, along with a single full sample lesson, on page templates.

Subscriptions run $29 for a monthly membership and $79 for a quarterly membership, and include all current and future content for the life of the membership.

Future plans for the site include a similar course on Shopify theme development, as well as mini-courses on things like PHP basics, HTML/ CSS layout modules, and other TBD topics. You can keep up to date with what’s going on over there (since I don’t post here about everything) via Twitter and/or by signing up for the Neatly Polished email list.

I’m pretty excited about this project, in part because of the fabulous feedback I’ve gotten that has both helped me keep improving the lessons over time, and also has just made me feel even more sure that sharing what I know like this is the right thing to be doing.

I’ll leave you with some of the awesome things members have said about the lessons and program:

“Awesome lesson! I have used many fabulous tutorials (free and paid) on WordPress theme development, but find that even though the information is valuable , it is not “streamlined” as well as yours.”

Very specific. The checklist was clutch. I was missing 3 things (due to my horrible skimming skills and my antsy pants that are so excited to be learning this stuff). With the checklist, I was able to make sure that I didn’t miss a beat!”

“Great! Can’t believe I picked this up so quickly. Really appreciate your simple and easy to follow instructions.”

If you’d like to register, you can do so here.

Top Hidden Costs of Website Projects

7 Common (But Easily Overlooked) Website Costs

Over a couple of years of client projects, one thing I’ve learned is that there are a lot of costs for website that site owners often don’t know to anticipate or plan for. It is not fun being the bearer of unexpected news about additional costs, so I try to be pretty up front about these potential “extra” costs at the contract and invoicing stage of the project.

There are seven main costs that many clients may not know about (especially if it’s their first big web project):

1. Hosting (Especially Quality Hosting)

While most clients know that they’ll have to pay for hosting of some sort, many don’t realize that quality business-level hosting can be pricey. While inexpensive shared hosting may be okay for some sites, there are definite downsides to cut-rate hosting (everything from reliability to security issues to variable customer service quality).

Once you move beyond inexpensive shared hosting, the cost for hosting can vary wildly and tends to increase pretty rapidly in price. This can be a real surprise for clients, and is something worth discussing early in the process. It helps to be able to discuss the benefits of more premium hosting services.

Typical Cost: $3-6/ month for inexpensive shared hosting, $15/ month and up for premium hosting

2. Domain Registration

If you’ve been working with websites for awhile, it’s easy to forget that the concepts of domain registration versus hosting are not actually that obvious to the general internet user. It’s a good idea to check in early with clients to make sure they’ve got a domain registered, and you’ll also want to help them understand the cost for registration.

Some things clients may not know about domain registration include:

  • It’s a recurring (usually yearly) cost
  • Some (but not all) hosting providers include a year or more of free domain registration with a new plan
  • There are add-on services needed along with the domain for things like privacy or added security
  • The domain can be registered separately from the hosting, if desired

I’ve found that clients also appreciate tips on registering similar domains, such as the .org version of the primary domain or a common misspelling.

Typical Cost: starts at about $10/ year per domain registration alone (more for high-value domains and certain TLDs)

3. Email Accounts

Some hosting providers include email of some sort (forwarding accounts, or even email inboxes) with hosting plans, others do not. Since many people are used to free personal email accounts, it may not occur to them that business-class email often comes at a cost and that the cost may be per-email-address.

I typically recommend Google Apps for Work as a great business-class email option, and that service runs $5/ inbox/ month, or $50/ inbox/ year.

Typical Cost: $50 per inbox per year

4. Licenses

It’s not uncommon for clients to believe that any and all functionalities and design elements within a website are part of the overall project cost, but I tend to separate out license fees from my rates unless I already have an unlimited developer license for a particular purpose.

One of the reasons I do it this way is that I prefer to have licenses for each project in the client’s name. This is especially true for things with recurring costs like subscription font services, but is also true for one-off licenses that require a new license for each site.

Font Licenses

I’ve written at length on web fonts and licensing, but those are not topics that the average site owner is going to know a lot about.

Ideally, font licensing comes up in the design phase of a project but I like to cover myself by also bringing it up in my invoices and contracts. That way I don’t have to be the one telling the client late in the project that the fonts they’ve fallen in love with are going to cost them a lot of money.

Typical Cost: varies widely from free to hundreds of dollars per year depending on font(s) chosen, traffic levels, etc.

Software Licenses

Beyond font licensing, some jQuery plugins, WordPress plugins, and Shopify apps come at added cost. For example, MagicZoom is a very popular jQuery plugin for e-commerce product zoom functionality, and it has a per-site cost unless you’ve got a developer license you’re using for all your clients.

This is another place where it’s a good idea to talk early about special functionality requirements and for the designer and developer to be on the same page about functionality that is “free” (or built into a regular scope of work) versus functionality that may have associated extra licensing costs.

Typical Cost: varies – jQuery plugins tend to run $30-100 for a one-time license, premium WordPress plugins and Shopify apps often have yearly or monthly recurring costs

5. Security Provisions

Depending on the type of site and the setup, there may be added security needs.

SSL and Dedicated IPs

If you’re running any kind of secure content through your site, you’ll likely need an SSL certificate, which is an added yearly cost for most hosting accounts. SSL also requires a dedicated IP address, another added cost in some cases (especially on shared hosting).

Typical Cost: on one shared host, a dedicated IP address is just over $3 per month on top of a regular hosting plan; SSL certificates tend to run $20-50 per year up to $200+ for wildcard coverage

Monitoring Services

Even if you’re not storing or using sensitive information, it can be helpful to have security monitoring on your site. For WordPress, this typically looks like third-party services that keep an eye out for hacked sites or for necessary updates/ upgrades. Some clients may also want ongoing help with their site updates, which is a long-term cost that will need to be negotiated.

Typical Cost: leading provider Sucuri has an antivirus plan runs $89.99/ year for a single site

6. Backup/ Restore

This is another feature that depends on the site and hosting provider, but that sometimes incurs extra costs. Regular automated backups and a one-click restore are one of the reasons I really like WP Engine hosting [affiliate link], but other hosting providers may not include those things standard, or may only allow access to parts of the backups.

Sometimes you can add better backup systems through a hosting provider for an additional cost, or there are third-party tools and services such as VaultPress and BackupBuddy.

Typical Cost: VaultPress runs $55/ year for their “Lite” backup/ restore plan

7. SPAM Filtering (WordPress)

For WordPress blogs, in particular, there’s typically a need for additional SPAM filtering. While there are some free options out there, I prefer using Akismet as it’s a tried-and-true provider that does a good job filtering out SPAM with few false positives. You can use it for free for a personal blog, but it does have a fee for commercial sites.

Typical Cost: Akismet is $5/ month

Total Cost

Looking at a “typical” WordPress business site that includes a blog a reasonable cost breakdown might be something like:

Shared Hosting:

Since it’s a lower price point, shared hosting is often a good place for a new business to start. The downsides are usually reliability and service/ support, and as traffic grows or as storage needs increase, shared hosting may become less of a viable option.

Service Yearly Cost
Domain Registration $10
Whois Privacy $3
Hosting $60
Email (provided by hosting) $0
Sucuri Monitoring $90
VaultPress Backup Bundle (includes Akismet) $99
Total: $262 (plus any one-time licensing fees)

Premium Hosting:

While clearly more expensive, premium hosting can be worth the price for ease of use, uptime and site speed, and quality of customer service. Premium hosting providers also often optimize for things like traffic spikes and dedicated WordPress hosting providers have WordPress-specific features that can save site owners time.

Service Yearly Cost
Domain Registration $10
Whois Privacy $3
WP Engine (“Personal” Plan*) $348
Email $50
Akismet $60
Total: $471 (plus any one-time licensing fees)

* The personal plan is the lowest plan offered by WP Engine and is based on the number of visits per month, despite the name it can be used for business sites.

There you have it – an overview of some of the most common website project costs along with some very approximate numbers for rough budgeting purposes. I’m sure I’m missing something(s), so if you’ve got something that pops up a lot in your projects that I haven’t mentioned, post it in a comment.

Marking Posts as New in WordPress

I was updating my bookmarks page and wanted a way to indicate the stuff that I’d added recently, which led me to thinking about how to identify posts from a particular timeframe.

The Question

How can I mark recent posts based on a particular timeframe?

The Result

I considered a couple of options (listed below) and ended up with a fairly simple solution using relative time, something WordPress has built-in. On the front-end, it just adds a little clock icon next to the title of any resource added within the last 30 days:

new resource indicator

Potential Solutions

My first thought was that I could use PHP to check whether the post date was within a certain range.

1. Compare Year and Month

I was thinking maybe I’d check the post year against the current year, then if it matched I’d check against the current month. However, I dismissed that before I got past about 20 characters of code because I realized that it would throw off the time frame of the results depending on where in the month we are. Oh well, we all have bad ideas sometimes.

2. Date Calculations

Then I was thinking I’d use PHP to check the date against a relative time frame, e.g. the last 30 days. Something like the reverse of this Stack Overflow question and solution.

That would work, but then I remembered that WordPress has relative post date built in, where you can display the time as “1 day ago” or “30 minutes ago” using the function human_diff_time (function reference). Hooray, even better!

3. Using Relative Time

So then I was thinking, with that relative time I just need to check and see if we’re in the right time frames to be what I’d consider “recent.” The numerical values returned won’t be useful but the words are definitely useful. I double checked when the transition in words happens by looking at the core code underneath that function. I was able to confirm that anything with a relative time in minutes, hours or days has been posted in the last 30 days, and I’d consider that recent.

Full Solution

Here’s the full solution I ended up with (limited to just the template code within the loop, since the rest of the template is irrelevant to the question):

<?php while ( $the_query->have_posts() ) : $the_query->the_post(); ?>
        $postdate = human_time_diff( get_the_time('U'), current_time('timestamp') ); // get the post date in relative time
        $recentvals = array('min','mins','hour','hours','day','days'); // the values I consider "recent"
    <li class="filterable">
        <a href="<?php the_field('url'); ?>">
            <span class="project-title"><?php the_title(); ?><?php foreach ( $recentvals as $recentval ) : if ( strpos($postdate, $recentval) !== FALSE) : echo ' <i class="fa fa-clock-o"></i><span style="display:none;">new</span>'; endif; endforeach; ?></span>
        <span class="small"><?php the_field('description'); ?></span>
<?php endwhile; ?>

The Breakdown

Let’s take a closer look piece by piece at what this code does:

Set Variables

First up, there are two pieces of information I want to use in my comparison. That’s this part of the code:

        $postdate = human_time_diff( get_the_time('U'), current_time('timestamp') ); // get the post date in relative time
        $recentvals = array('min','mins','hour','hours','day','days'); // the values I consider "recent"

There are two variables set up here:

  1. The post’s relative publication date, meaning how long ago it was posted in words (e.g. “20 mins” or “2 days”)
  2. The time frames I want to include as “recent,” using the words provided by that relative time function (options are: “mins,” “hours”, “days,” “weeks,” “months,” and “years” and the singular of each of those)

For the first, I just used WordPress’s built-in function, straight off the Codex page except I’m assigning it to a variable rather than echoing it (displaying it) on the page.

For the second, I have created an array of the words I’ll accept as “recent,” using both the singular and plural forms. I’m actually not sure if it’s possible to just use the singular and I don’t feel like testing it so I’ve just used both for safety’s sake.

Compare the Two

Next, I need to figure out whether the current post date for each post contains any of the words in my array. I referenced this thread on Stack Overflow for this code:

foreach ( $recentvals as $recentval ) : 
    if ( strpos($postdate, $recentval) !== FALSE) : 
        echo ' <i class="fa fa-clock-o"></i><span style="display:none;">new</span>'; 

This runs through each of the allowed time frame words in my array and compares them against the post date. If one comes up as a match, it prints out the code in the echo line.

Show the Icon, Plus Search

The printed HTML from that snippet is:

<i class="fa fa-clock-o"></i><span style="display:none;">new</span>

That creates the Font Awesome clock icon along with a hidden span (I know, I know, lazy inline CSS). The hidden span is there so that it’s possible to use the in-page “search” function to pull up the new posts.

Implementation Keys

If you’re going to implement this yourself, the key things to remember are:

  1. The code needs to be within the loop, including the bit where you set the variables.
  2. You’ll need to determine which words constitute “recent” and update your array accordingly.
  3. You’ll likely also need to update your icon/ display HTML to fit your purposes (whether it’s just displaying text or adding in an image or another icon font or whatever).

Display Top WordPress Posts by Page Views

A recent client project has a component that shows top posts by views, which took some figuring out. WordPress doesn’t log views by post out of the box, but the Jetpack plugin does so that’s what we used as our data set. There are a couple Stack Overflow threads that talk about querying the posts by view count using Jetpack but none of them have the full code necessary so I thought it’d be useful to share how I did it.

Posts by views carousel

the end result

The post display is done using a custom loop via WP_Query, and the carousel in this particular example is done with bxSlider, which I use all the time for sliders and carousels.

Full Template Code

Here’s the full code for that area, which would go in the template file for the particular page or area you’re displaying the posts within. In this case, they’re on every page in the header so they’re in the theme’s header.php file.

The first and last lines are a conditional that checks for the stats function. If it returns false because the function isn’t there (e.g. if there’s no Jetpack installed) then nothing else will happen, preventing errors or other weirdness.

The Breakdown

Let’s run through the pieces of that snippet. (I won’t be covering the CSS and jQuery in this tutorial, since the focus is on getting the content to appear on the page, but let me know in the comments if you’d like to see a tutorial on carousels.)

Grab Top Posts’ IDs

The first few lines are getting the posts by views as registered by Jetpack:

The first line pulls up the top posts by views, using the last 21 days’ worth of data (that’s the first parameter in the array). The -1 value means that we are not limiting the number of posts returned. In the client project, I used custom fields for the number of days so that the client can change that if they’d like, and I also set a high but not unlimited value for the items returned since unlimited seems kind of unnecessary (the default is 100 if you omit that parameter entirely).

Set Custom Query Arguments

The remaining lines in that snippet create an array of post IDs for the posts returned by that first line, which is key because we need that array to plug into the post__in parameter for our query:

If you’ve ever built a custom loop using WP_Query, the above snippet will likely be familiar. It’s the arguments for our query, the first of which, post_type specifies that we want to pull only posts (the stats will return both posts and pages).

Major hat tip to Greg Rickaby for helping me level this up by adding a transient, which is essentially like a cookie and stores the query for a specified length of time, which speeds things up.

The other two parameters are post/ page specifics. First, post__in (that’s two underscores in there) specifies that we only want to return posts with IDs in that array we just built. Finally, posts_per_page limits the number of posts displayed on the page, overriding any other pagination you may have going on (from your regular loop settings, for example). I gave the client a setting for that value as well, so that she can control the number of posts in the carousel herself.

Create The Loop

Finally, the rest of the code is a standard WordPress loop structure:

In this construct, each item is wrapped in an <a> element (could just as well be a <div>) that links to the post permalink, and then the post thumbnail and title are displayed. I’ve arranged the markup so that I can have the title appear over the thumbnail on hover using CSS.

And there you have it, a snippet that returns top posts by views!

Introducing Emi, a Gulp and Sass-ready WordPress Starter Theme

Hey, did you know that April is Autism Awareness Month? It’s true! One of my kids is autistic, and since autism occurs in approximately 1 in 68 individuals you probably also know someone with autism. If you’d like to learn more about what autism is, I recommend this description. The Thinking Person’s Guide to Autism is another great resource.

Now, on to Emi…

Emi WordPress Starter Theme

I recently quietly made the repo for Emi, my WordPress Starter Theme available to the public, but it’s about time I actually announced the release.

Emi is a true starter theme – it’s got a foundational set of files and codes to jump start theme development, but it is not meant to be used as-is. It isn’t meant to be used with child themes, either. Instead, Emi should be directly edited and modified for custom theme projects.


Emi comes with a few features built-in. Note that these features may not be for everyone, but they’re in there since they are what we use in our workflow. While I’m happy to be making Emi public so others can use it, modify it, etc., at root it’s still a tool that I use regularly and so the feature set is specific to how I use it.

Template Files

Emi’s got the template files that I use most often, including:

  • 503.php, to be used with the Maintenance Mode plugin as a landing page during active development (tutorial here)
  • archive.php, with code for archive-specific page titles
  • functions.php, with some useful theme options enabled and some starter snippets for other common customizations
  • Page templates for full width layouts and two kinds of redirects

Folder Structure

We’re constantly revising and rethinking our folder structure based on best practices and what makes sense for our purposes, and I’m pretty happy with what we’ve got now. Most of the template files are in the main directory.

We’ve split out the Sass files in their own /scss/ directory, which has some additional directories for custom page styling and blog styling.

There’s also an /inc/ directory for modules or pieces of code, and a subdirectory at /inc/functions/ for modules that are specific to the functions.php file.

Finally, there’s an /assets/ directory that contains theme javascript and subdirectories for images and for any vendor files we add to the theme (e.g. jQuery plugins).


The template files have been updated to use HTML5, with HTML5 Shiv to help out older browsers.


Emi uses Sass to make CSS authoring both easier and more powerful. The main actual Sass features in use are the file structure/ partials, variables, and nesting.

You’ll find the variable definitions in /scss/_base.scss and a few starter mixins (including a sticky footer and HTML5 input support) in /scss/_mixins.scss. All the partials are combined in /scss/style.scss.

We use Autoprefixer to automatically add all the necessary browser prefixes to newer CSS features, which is part of the Gulp task for processing our Sass.


We’ve integrated Gulp into our theme work (we also tried Grunt but found Gulp to be much faster), so it’s integrated into Emi as well. Gulp is a task runner, and the gulpfile.js file in Emi is set up with the tasks we use in our workflow:

Sass Processing
The gulp styles task processes the Sass files and also runs Autoprefixer before spitting out the minified CSS into the theme’s main style.css file.

Image Compression
The gulp images task compresses images from the /assets/images/originals/ directory, spitting the compressed files into the main /assets/images/ directory.

Watch Task
Finally, the gulp watch task runs continuously, watching for new images or changes to the Sass files and triggering the appropropriate task automatically. It also is hooked up with LiveReload.

You can download Emi from GitHub, and it’s under an M.I.T. license so you’re welcome to do with it what you will.

We’re constantly tweaking and improving it and would love your help! You can submit bugs or suggestions for improvements via the GitHub issues tracker, and feel free to send pull requests if you fix any open issues.