#wcphx: Five tenets to mastering WordPress development

Enlightenment is knowing what your code is doing and why. Thankfully, instead of having to depend on your inner calm, there are a number of tools and strategies you can use to better see what’s going on. We’ll survey a range of topics you should explore to turn your frustration into bliss.

Feeling better already? In this session, we’ll touch on everything from debugging to best practices to coding standards to version control to performance and optimization. You’ll hear the insights WordPress.com VIP shares every day.

Session notes are below the slides.

Who am I?

My name is Daniel Bachhuber and I work as a code wrangler on Automattic’s WordPress.com VIP team. We work with publishers like TIME, The New York Times, TechCrunch, Cheezburger, and more who use WordPress at scale.

The point of this presentation is to cover the things you mostly learn the hard way. Now you can learn them the easy way. Some of these topics were covered by Erick’s talk this morning… I’ll quickly review.

Why is this talk important?

  • Make your code secure, performant, and protect against the future
  • Let others love your code too

1. Do it locally

Set yourself up for success

→ WP_DEBUG opens your eyes


  • It’s a quick and easy way to see what’s going wrong with your code for fatal errors
  • See PHP notices and other things you might normally miss
  • Make sure you’re using the best WordPress functions for the job

WP_DEBUG does the following:

  • Turns on the display of PHP errors and warnings
  • Triggers notices for deprecated functions

Slide: Show the whitescreen of death and then with WP_DEBUG on

5 ways to debug WordPress” and “Debugging WordPress” – Andrew Nacin

→ Know thy codebase; when in doubt, ack


  • Code is gospel. You might read tutorials or examples on the web that say one thing or the other; code will tell you the truth.
  • Reading code is a literacy of WordPress development. Dive into it to figure out what’s going on.

Use ack to quickly search your code base. It’s better and faster than grep.

Slides: Different usages of ack

Some usage:

  • ack ‘function my_function_name’ for the source of a function
  • ack ‘/crazy-regex/’

Slide: Files you might commonly need to reference

[sourcecode language=”php”]
// Some of your functions for sanitizing input
// and formatting output, including esc_*(),
// sanitize_*(), and capital_P_dangit()

// Post manipulation, including
// register_post_type(), get_posts(), etc.

// Reference for modifying the Query

// Functions you can override in your theme
// or plugin

→ Install Debug Bar, it’s like Firebug for your WordPress

By default, the Debug Bar gives you information about the execution of the page.

Slide: Debug Bar by default

Define SAVEQUERIES to do the following:

  • Saves each query
  • Identifies which function calls it
  • Saves how long it took to run

Slide: Debug Bar with SAVEQUERIES

Debug Bar Extender adds some profiling information

Slide: Debug Bar Extender

→ Use version control and write descriptive commit messages

Version control is an awesome historical record of your project. SVN and Git are two popular types of version control, the former is used for the WordPress.org project and the latter was popularized by Github, a social coding site.

Version control gives you these advantages:

  • More easily communicate the changes you’re making with the rest of your team.
  • Work on multiple features at the same time.
  • Roll back if necessary; better than backups.
  • Automated deployment — no more copy and pasting over FTP.

Slide: What a diff on Github looks like

What makes a good commit message:

  • Consider your audience: writing for coworkers and for historical purposes.
  • Explain why you made the change, not what it was. What it was should be self-explanatory from the code
  • Link to Trac tickets or other relevant conversation.

Slide: What good and bad commit messages look like

Neat example of Wired Magazine accepting contributions via Github for an article.

2. Follow best practices

Let others love your code too

→ Don’t modify core. Do extend it properly.

Why: your changes will get blown away, you won’t upgrade regularly, and the sky will fall on your head.

WordPress has an extensive system of action and filter hooks you can use to extend functionality and modify values. It’s the “window into WordPress”.

Sometimes you will need to do ugly workarounds. Don’t worry, it’s better than modifying core.

Slide: Filter workaround for core problem with custom statuses

If you find something limiting in the API, open a Trac ticket!

→ Prefix all the things

Prefix all of your functions and variables to avoid collisions; better yet, write your functionality into classes.

In WordPress, prefix everything” – Andrew Nacin

Slide: Example of non-prefixed vs. prefixed

→ Coding standards are standards for a reason

Why: You’re not the only one working with your code. WordPress’ coding standards are a common language for others to understand your code.

  • Tabs, not spaces, for indentation. Allows the most flexibility between clients.
  • under_score for functions and variables. Everyone else does.
  • Capitalize_Classes. This too.
  • use-hyphens-to-separate-words-in-files.php. This three.

Slide: The coding standards I run into most commonly with VIP

3. Use the correct hooks and APIs

There are so many

→ Use the WP_HTTP class for remote requests

The transport mechanisms available for WordPress to use vary from server to server, especially if you’re releasing code to be used on shared servers. That’s why you should use the WP_HTTP class… it uses the best mechanism available.

Slide: different HTTP functions you can use

→  Find the proper action for your action

‘init’ isn’t everything. Invest some time into finding the right action to avoid bugginess later. Make sure all order of execution code in your functions.php and/or plugin is hooked into an action.

‘after_setup_theme’ is a good place for:

  • Registering nav menus
  • Setting your post thumbnail sizes
  • Adding theme support

Slide: after_setup_theme

‘wp_enqueue_scripts’ is where you should enqueue all of your scripts and styles. Define a dependency if you need to. Enqueuing on ‘wp_print_styles’ may cause issues.

You can also minimize HTTP requests by only enqueuing them on the pages you need them.

Slide: wp_enqueue_scripts


  • ‘add_meta_boxes’ is a good place to register your meta boxes
  • ‘admin_menu’ for adding admin menus
  • ‘widgets_init’ is a good place for registering widgets

4. Protect yourself

Don’t trust strangers

→ Properly handle your user-submitted data

Validate that the data is what you need. Follow a whitelist approach

Sanitize what the user has submitted:

  • sanitize_text_field() // strips tags, checks for invalid UTF-8, remove line breaks, tabs and extra white space
  • intval() // integer value
  • wp_filter_post_kses() // sanitize for allowed HTML tags and attr
  • sanitize_title() // strip PHP and HTML tags
  • sanitize_key() // lowercase alphanumeric characters, dashes and underscores

Slide: All of the core sanitize functions you can use

Make sure you sanitize your data at the point of accessing it.

Slide: Sanitize at the point of using your data

Data Validation” in the WordPress.org codex
wp-includes/formatting.php includes all of the functions

→ Escape data on output

There are different escaping functions you can use to protect your HTML. Make sure your HTML is what it’s supposed to be:

  • esc_html() // escape for data within HTML, checks for invalid UTF-8
  • esc_attr() // escape for HTML attributes, checks for invalid UTF-8
  • esc_js() // escape single quotes, htmlspecialchar ” < > &, fix line endings.
  • esc_textarea() // escapes data for use in a textarea
  • esc_url() // removes a bunch of invalid characters from your URL, makes it good

Slide: Different escaping functions you can use

Slide: Escape at the point of printing data

→ Nonce (numbers used once) to make sure people are who they say they are

Use Nonces for security (XSRF) and checking user intention (Edit vs. Quick Edit)

Nonces are temporary (24 hours), tied to specific users (if authenticated) and actions, and in some cases, referrers.

Slide: Adding a nonce to your form, and then checking for it on form process

WordPress 2.0.3: Nonces” – Mark Jaquith

→ When you must use SQL, $wpdb->prepare()

$wpdb->prepare() properly escapes strings.

Use %s and %d depending on whether you’re using a string or a digit; quote marks will be auto-added for strings.

Slide: Usage of $wpdb->prepare

Protect queries against SQL injection attacks” in the WordPress.org codex.

5. Optimize

Performance matters — make it fast

→ Know your Query

query_posts() should be used in one and only case if you need to modify main query of page. It sets a lot of global variables and will lead to obscure and horrible bugs if used in any other place and for any other purpose.

get_posts() is very similar in mechanics and accepts same arguments, but returns array of posts, doesn’t modify global variables and is safe to use anywhere.

WP_Query class power both behind the scenes, but you can also create and work with own object of it. Bit more complex, less restrictions, also safe to use anywhere.

Slide: Different ways of the Query

WP_Query actually does four SQL queries

  • Main posts get
  • postmeta get
  • taxonomy terms get
  • SQL calc rows

Slide: How you can disable extra queries on the Query

Slide: How you should modify the query

When should you use WP_Query vs query_posts() vs get_posts()?
You don’t know Query” – Andrew Nacin

→ Cache expensive data

If a given set of data takes more than ~200 ms to generate, you should cache it.

WordPress has three different types of caching:

  • Transients -Transient data, persistent across page loads but could expire at any time.
  • Object cache – Page load by page load, unless you use an object caching backend like memcache or APC.
  • Options – Data will always persist, maybe can’t handle a lot of it.

→ Cache remote requests, or offload to the frontend

Remote requests are when your code has to pull some data from somewhere else. Retrieving that data can be expensive. Uncached, every millisecond the remote request takes are milliseconds added to the page load. And these are for every visit to your site.

Sometimes, we can rely on the API to be fast enough that we can just request and cache on the frontend.

Slide: Remote request on the PHP end

Oh, but we actually need new live data all the time. Trying to invalidate the cache and repopulate all of the time is bad news bear. Let’s just move this to some Javascript on the frontend

Slide: Offload the request entirely to the frontend

The beginning

The best thing you can do is read others’ code and share your own. If you have a friend or colleague you can match up with, swap code and leave feedback for each other. It’s tremendously beneficial for both parties. A good WordPress developer never stops learning.


Juliana February 26, 2012 Reply

I’m just beginning the basics of exploring code, but I really enjoyed your presentation yesterday. The information about caching was incredibly insightful, and I was super stoked that I actually knew what you were talking about.

I actually AM a poet, and after having the opportunity to sit in on a discussion like this, I completely see how code really IS poetry. Mass respect.

Andrew Nacin February 26, 2012 Reply

Very solid deck of slides. Nice job. Wish I were there.

Noticed a few random things while reading through them:
* On this slide, the pre_get_posts is being used improperly — it will alter all queries, not just the main query. (is_home(), in particular, is the fallback conditional, so this will damage random queries including nav menus.) This is why many people just end up resorting to query_posts(). Use $query->is_main_query() to identify that you are on the main query. query_posts() should never, ever be used — using it to “modify the main query on the page” is wasteful and is full of problems in itself.
* (Further worth mentioning that when using WP_Query, particularly WP_Query->the_post(), you need to reset the globals with wp_reset_postdata().)
* On this slide, sanitize_title() is wrongly described as a way to sanitize PHP and HTML tags. You want to use sanitize_text_field() to clear a field of all HTML. sanitize_title() is like sanitize_key() but more powerful and flexible; its main job is to generate permalinks from post titles, for example.
* On “Different escaping functions you can use,” it’s a good roundup, but while it explains what they do (UTF-8 validation, yay), it doesn’t effectively explain when and why to use them. For example, esc_js() is only good when dealing with an attribute such as onclick="", and only when the attribute is double-quoted. esc_url() should be used every single time you add a URL into an attribute, and esc_attr() should be used every time you put a non-URL into an attribute. If you use esc_attr() for an href or src attribute, you are doing it wrong and creating an XSS hole.
* Coding standards are split between camelCase and underscores for functions and methods (this is in PHP — underscores lose out in many other languages), so it’s probably not fair to say everyone else does this. It is, of course, popular.
* “Use Nonces for security (XSRF) and checking user intention (Edit vs. Quick Edit)” — Not entirely sure if I understand this. Checking user intention is the security/CSRF part.
* check_admin_referrer() is actually spelled check_admin_referer(), to keep with the incorrect spelling of referer in the original RFC.
* On this slide, isset( $_POST ) is used. $_POST is always set. Rather, check if ( $_POST ).

Daniel Bachhuber February 26, 2012 Reply

Good points 🙂 Thanks Nacin

Rilwis March 7, 2012 Reply

Very nice slide. This is a good reference for all developers. Just one thing I want to ask more: you said that using git or svn can help deploying code. Can you give me an instructions on that?
Thank you very much.
@nacin: thanks for your comment, it answers some of my questions.

Daniel Bachhuber March 7, 2012 Reply

Basically, the simplest way to use SVN to deploy your code is to have your production servers hold SVN checkouts of your code base (preferably trunk) and then your deploy script will connect to each machine and run svn up. The particulars of how this works will obviously depend on your environment.

Tracey March 7, 2012 Reply

Hey Daniel,

That talk was absolutely brilliant! So many great tips that I will be putting into practice.

I have come from a java web dev background where I used an IDE to develop and test/debug as I went along, currently I’m using text wrangler and firebug to code for WordPress but that’s about it (will now use the debug bar which sounds great), do you use an IDE for your WordPress development?

Daniel Bachhuber March 18, 2012 Reply

Thanks Tracy, glad you found it useful 🙂

I don’t use an IDE for WordPress development. I use Sublime Text or vim, depending on what I’m working on. To be honest, most WP developers I know use Coda at the most and generally just a text editor. Definitely interested in hearing what you find though.

Leave a Reply