I gave this talk at WordCamp Norway 2013. It covers several tips and tricks that will make you a better theme developer.

You can follow the slides and the notes/transcript below. If you have any questions or comments, feel free to ping me here or on Twitter, I’m always happy to help :)

1. get_template_part is Your Friend

The get_template_part function is used to include template files in your theme, but it’s not just a regular php include or require. It’s quite a unique way to include files because of its fallback model and child theme awareness. To understand that, let’s take look at some quick examples:

get_template_part( 'something' );

This will attempt to include something.php in our theme. However, if we’re running a child theme, get_template_part will look for something.php in our child theme first, and if that does not exist, it will fall back the parent theme’s something.php.

Here’s a more complex example with the optional second argument:

get_template_part( 'something', 'else' );

This will first look for a file named something-else.php and if that’s not found, it’ll look for something.php instead.

In a child theme environment it gets a little tricky. It will first look for something-else.php in our child theme, then something-else.php in our parent theme. If not found, it’ll look for something.php in our child theme, and finally, something.php our parent theme.

There are many great examples with post navigation, breadcrumbs, pagination, etc. Many themes, including Twenty Eleven and Twenty Twelve, use get_template_part to break down posts output based on their format:

get_template_part( 'content', get_post_format() );

If the post is a gallery post, this will include content-gallery.php. If it’s a quote, it will look for content-quote.php, and so on. And if we’re creating a child theme, we can easily override the output of our quotes by creating our own content-quote.php file.

To summarize that, get_template_part is a great way to break your theme down into smaller chunks, and because of its fallback model and child theme awareness, it will add some flexibility to your parent theme.

Resources:

2. Enqueue Scripts and Styles

When working with Javascript or CSS files in WordPress, you should never hard-code them in your header.php, but instead use wp_enqueue_script and wp_enqueue_style , and let WordPress take care of the rest. You should also make sure you do that within the wp_enqueue_scripts action and never within the global scope.

function my_scripts_and_styles() { wp_enqueue_script( 'my-script', ... ); wp_enqueue_style( 'my-style', ... ); } add_action( 'wp_enqueue_scripts', 'my_scripts_and_styles' );

Following these simple rules will make sure that your scripts and styles are loaded properly, and in the correct order. It’ll also make sure that such scripts and styles could easily be removed by a child theme or a plugin with wp_dequeue_script and wp_dequeue_style .

function remove_my_scripts_and_styles() { wp_dequeue_script( 'my-script' ); wp_dequeue_style( 'my-style' ); } add_action( 'wp_enqueue_scripts', 'remove_my_scripts_and_styles', 11 );

This is especially important when in the context of a child theme, because a child theme might not want to use all of its parent’s scripts and styles, and having a way to remove or replace them without overriding the whole header.php file makes your parent theme easier to work with.

A nice bonus of using these enqueue functions is the automatic dependancy resolution. For example, if your javascript file uses the jQuery and jQuery UI libraries, you simply tell wp_enqueue_script about it, and WordPress will take care of loading these dependancies before loading your script.

wp_enqueue_script( 'my-script', get_template_directory_uri() . 'script.js', array( 'jquery', 'jquery-ui-core' ) );

Finally, it’s worth noting the difference between the two functions used to get the current theme’s URL, which are often used when enqueuing scripts and styles.

get_template_directory_uri(); // parent theme get_stylesheet_directory_uri(); // child theme

We’ve got the get_template_directory_uri which returns the URL for the parent theme, and get_stylesheet_directory_uri which returns the one for the child theme. When we’re not running a child theme, both functions will return the same result, but it’s easy enough to spot an error, just by switching to a child theme and seeing if things break.

Resources:

wp_enqueue_script and wp_dequeue_script in the Codex

get_template_directory_uri and get_stylesheet_directory_uri

3. Customizer > Theme Options

Many WordPress themes come bundled with a theme options page, to customize the appearance of the theme, but in version 3.4, WordPress introduced the Theme Customizer. It’s a great end user experience, and easy enough to incorporate in your themes, using its very simple and flexible API.

The Customizer has pre-built controls for things like text, checkboxes, radio groups and dropdown selects, as well as more complex controls such as the color picker and the image uploader. Any of these controls can easily be extended to fit your needs, which you can then reuse in any of your projects.

While themes can implement the same settings in both, the Customizer and a Theme Options page, I think that developers should stop doing that, and focus only on the Customizer, because it’s just so much easier for both the users and the developers. After all, it’s been made to customize themes.

Resources:

4. Add an Editor Style

I’m not a big fan of the visual editor in WordPress, and I think one of the reasons is that most WordPress themes don’t add an editor style. Out of over 1,600 themes in the WordPress.org directory, only 200 had an editor style. So what’s the point of using the visual editor, if what I see looks nothing like what I get?

It’s very easy to add an editor style to your theme. All you have to do is call add_editor_style during your theme setup in functions.php, and add an editor-style.css file to your theme. You don’t have to write the whole CSS from scratch, in fact, 99% of it is going to be copy-pasted from your original stylesheet.

add_editor_style();

Themes with an editor style look prettier on the inside, and spare users a whole lot of frustration and time, which they otherwise spend previewing their posts and aligning their images before publishing.

Resources:

add_editor_style Codex entry

Twenty Eleven is a theme with a good editor style

5. Avoid Using query_posts

This is my favorite. We have three ways to query in WordPress: we can use the WP_Query class directly, we can use the get_posts function, or the query_posts function. Each of these methods performs a secondary query to the WordPress database, but query_posts does this in a very special way, where one would think they’re altering the main query.

That’s a wrong assumption and what happens in reality, is that query_posts does not alter, but replaces the main query with a new one and if you don’t know what you’re doing, you might end up breaking things like pagination, titles, etc.

Here’s my rule of thumb: if you really want a secondary query and not alter the main query, use WP_Query or get_posts , whichever you prefer. They don’t have that query_posts magic happening under the hood, which makes them safer to use.

If you want to modify the main query, you have two options. The pre_get_posts action, and the less popular request filter.

I asked on Twitter what were the most common use cases for query_posts in WordPress, and the top three were featured posts, custom post types on the front end, and minor things like exclude a category from the stream.

The last two are pretty simple with the pre_get_posts action:

function my_pre_get_posts( $query ) { if ( ! $query->is_main_query() || is_admin() ) return; $query->set( 'post_type', array( 'post', 'book' ); $query->set( 'tag__not_in', array( 2, 6 ) ); } add_action( 'pre_get_posts', 'my_pre_get_posts' );

The pre_get_posts action is fired for each and every query, including our main query, but also things like navigation menus and any custom queries we run, so first, we make sure that the query we’re working with is the main query, and let’s also not break the output in our admin panel.

Then we can use the set method to set any query variables, like post type, or the categories we’d like to exclude.

Featured posts are slightly more complicated, because you need a secondary loop, as well as a filter on the main loop. There are many different approaches for featured posts, and one of my favorite is to use sticky posts.

Let’s assume our theme has an area for five featured posts. We’ll need a secondary query to grab five posts which are set to sticky, let’s wrap that into a function.

function my_get_featured_posts() { $sticky = get_option( 'sticky_posts' ); if ( empty( $sticky ) ) return new WP_Query(); $args = array( 'posts_per_page' => 5, 'post__in' => $sticky, ); return new WP_Query( $args ); }

This is quite simple, we read the sticky_posts option which is an array of sticky post IDs, and we use that array in the post__in argument to the new WP_Query, which we return.

Now, wherever our featured content area is, we’ll just use this new function to query for featured posts:

$featured_posts = my_get_featured_posts(); while ( $featured_posts->have_posts() ) { $featured_posts->the_post(); the_title(); the_excerpt(); } wp_reset_postdata();

Since we’ll most likely want our featured posts on our home page only, we can limit that with simple conditional statements, like this:

if ( is_home() && ! is_paged() ) { $featured_posts = my_get_featured_posts(); while ( $featured_posts->have_posts() ) { $featured_posts->the_post(); the_title(); the_excerpt(); } wp_reset_postdata(); }

Now comes the tricky part. To avoid showing duplicate posts, we will want to exclude these featured posts from our main query. As we have already seen, we can do this with the pre_get_posts action:

function my_pre_get_posts( $query ) { if ( ! $query->is_main_query() ) return; if ( ! $query->is_home() || is_admin() ) return; $exclude_ids = array(); $featured_posts = my_get_featured_posts(); if ( $featured_posts->have_posts() ) foreach ( $featured_posts->posts as $post ) $exclude_ids[] = $post->ID; $query->set( 'post__not_in', $exclude_ids ); $query->set( 'ignore_sticky_posts', true ); } add_action( 'pre_get_posts', 'my_pre_get_posts' );

First of all we make sure we’re working with the main query and the one that is run on our home page, and not in the admin. Then we use our function to get featured posts and put their IDs in an array. We use that array to exclude these posts from the query, and finally set the ignore_sticky_posts argument to true, which will prevent WP_Query from prepending any sticky posts to our query.

Again, using sticky posts is just one of the ways to implement featured posts in themes, but the principle is similar in other methods as well.

Anyways, back to my point. Don’t use query_posts , because query_posts is evil. Use the pre_get_posts action or the request filter to modify the main query, and WP_Query or get_posts for secondary queries.

Resources:

6. Never Start from Scratch

If you’ve ever made a new WordPress theme from an empty folder, you’ll know it’s a pain. There are several ways to speed up theme development, including child themes, theme frameworks and starter themes.

Child themes are useful when you want to make some minor changes to an existing theme, like add a sideboard, or a menu, change the colors and so on. Such changes can be made in just a few lines of code, especially if the parent theme is coded in a proper way. If you’re looking for a good parent theme, my advice is to start with Twenty Eleven and Twenty Twelve.

Theme frameworks are often large libraries of custom functions, actions and filters, with their own developer docs and communities. They’re mostly used to create new themes, though some frameworks come in a form of a parent theme. There’s often a steep learning curve to get started with a framework, even for highly skilled WordPress developers.

Starter themes on the other hand, are usually lightweight themes with minor styling or no styles at all. These are meant to be copied, renamed and built into full-feature themes that are completely independent, unlike child themes or themes built with frameworks. It is also common to fork a starter theme to adapt it to your own needs, thus create your own starter theme, which you can use as a base for all your future projects. If you’re looking for a good starter theme, check out Underscores.

To wrap up, don’t reinvent the wheel. Code reuse is a good programming practice. Try out some of these options, and see what works best for you.

7. Know Your Tools

Here’s a short list of some of the tools I use for better theme development.

Theme Check is a plugin that runs several thousand tests against a theme and tells you what’s wrong with it. If you’re planning to submit your theme to the WordPress.org directory, passing Theme Check is required.

Theme Unit Test is an XML file with a lot of dummy data, useful to see how your theme handles the different types of content, including images, post formats, comments, embeds and more. This is also required for WordPress.org.

Log Deprecated Notices is a plugin that will let you know whether your theme or plugin is using any deprecated functions or arguments.

Debug Bar, Debug Bar Extender, Debug Bar Console – these three plugins are a must for all WordPress developers. They are like like Firebug for WordPress. You can inspect queries, cache and other helpful debugging info, and with the Console plugin, you can have a PHP and MySQL console right in your browser.

Monster Widget – this neat little plugin allows you to place a single widget that will render all the WordPress core widgets. It’s like the theme unit test, only for your sidebars.

WordPress Beta Tester is a plugin that allows you to run the development version of WordPress and make sure your themes are compatible with the next WordPress release.

Core Control is a plugin plugin that allows you to log and debug HTTP requests, cron tasks and more.

That’s about it. If you have any questions, poke me.