WordPress is in my blood. I wish I could say I’ve been there since the start, but over the course of my ~10 year journey you could say I’ve learnt a thing or two.

Yet all too often I see the same common rookie mistakes I once made myself. So if today is the start of your journey, let me save you a few headbangers, drop those wtfs and carry on coding.

My pagination is broken

Chances are you’re using your own query – something like:


Not only will this break any pagination-related template functions, you’re also needlessly introducing another query – WordPress has already set one up for you, why would you do this? WHY? THINK OF THE CHILDREN.

Enter custom queries. Rather than confuse the hell outta WordPress with your own query, tell WordPress what it should do for the main query:


Not only does this address a double query or pagination bug, you keep your logic out your template files – so they can get on with doing what they do best; templating.

My (custom) loop is broken

Ouch. Make sure you haven’t forgotten the_post() in your while loop, otherwise you’ll be hanging around for a while (I’ll show myself out). Also make sure you’re operating on the right one:



My (custom) loop is slow

Now this ain’t a silver bullet, but a few things to be aware of – if you don’t need pagination, set no_found_rows to true. This will save a query and MySQL needn’t calculate the whole result set.

If you don’t need post objects, set the fields argument to ids. This will skip post meta and term caching, won’t put anything in the object cache, and will return just the post ID’s.

As always, make sure you’re not doing anything too intensive within the loop – Query Monitor is an extremely useful plugin for finding bottlenecks in your code. For example, if you have many different authors within a loop and you’re using author-related template tags, it might be worth caching all authors at once:



You don’t always need “the loop”

Wha? Yeah, you heard me. If you just need to iterate over some posts and do something, you might not need the (expensive) loop:


Make sure not to clash with the global $post (hence the underscore). This saves a lot of uneccessary setup, hooks and filters, and you no longer need to wp_reset_postdata() at the end.

I can’t see any errors

Doesn’t mean they aren’t there. Always, always develop with debugging turned on. You’ll write better, more robust code, and you’ll know a bug won’t be creeping into launch.

Okay, now I get undefined index

More of a PHP issue than a WordPress one, but you know what they say, assumption is the mother of all… problems. And that’s why you get stung with those undefined indexes.



Sanity lies in sanitization

It’s the universal rule that transcends WordPress – make sure all input is sanitized and all output is escaped. WordPress boasts a host of helpers to get you started, primarily the aptly named sanitize_* and esc_* family of functions.

For database queries, use the prepare method:


Don’t forget awesome helper methods:


Check out the class reference on wpdb for a full breakdown.


Don’t reinvent the wheel

With 1000’s of functions in core, it’s not surprising many go unnoticed – before you start your next masterpiece, check the codex, check the developer reference, check the source, and ask around. If you’re thinking “I need to get the login URL”, then google “wordpress get login url” – oh look, what’s that? wp_login_url(). Need to get an array of integers? wp_parse_id_list() is your friend.

Filter helpers

In many cases you just want to pass back a standard value (true, false, zero etc.) – no need for yet another function, WordPress has several at hand:



It’s all in the name

Whilst neither WordPress nor PHP care what you call your new function (well, as long as it doesn’t already exist), there’s merit in keeping a consistent (& unique) naming structure:


Stick with WordPress coding standards, use a unique prefix (or namespaces for the more experienced), and keep it short but descriptive – it should be clear what something does from the name alone.

Similarly, use patterns like get_* for functions that return data, do_* for those that process actions, you get the idea – whatever suits your project.

Trust me, you’ll thank yourself when you revisit it a year later, or when you get a fatal error: cannot redeclare… since all your function names are as generic as popular music – ooh, controversial opinion bonus.