Back to Top

Speed Up WordPress: A Developer’s POV

Previous Post:

Speed Up WordPress: A Developer’s POV

As an end-user, you might find WordPress ridiculously slow sometimes, not because WordPress itself is slow, but rather the way you’re using WordPress is not optimized. That’s why speeding up WordPress is a topic that can never get old. Mashable talked about it more than a year ago, Noupe has recently published an article about it, and even a design magazine blog has done the same thing.

All articles found on the Internet regarding speeding up WordPress mainly tell you what you should do from an end-user’s point of view (use Cache plugins, for example). If you’re a WordPress developer, there are many other things you can do to speed up WordPress, internally. Apply some tips shared in this article to your plugins or themes, and you’re helping the WordPress community a great deal.

One obvious thing you should do before even trying to optimize things is to find a good host, or at least recommend your users to do so. The reason is rather simple: bad hosts will fail even when you use / develop highly optimized plugins or themes. Try installing WordPress on a shared host with low PHP memory limit and you will understand what I mean.

Choosing a good web host that meets your expectations is never an easy task, and that’s why there are so many hosting review websites out there. You can check out this webhosting review site, especially their WordPress hosting search page if you’re still on your way finding a suitable home for your WordPress blog.

Alright, let’s move on to the 5 actual tips for developers, shall we?

1. Enqueue Javascript and CSS files

It’s no doubt that enqueueing Javascript and CSS files has become a WordPress standard these days. The advantages of enqueueing are rather obvious:

  • You just need to register needed files (what, when, and where) and WordPress will take care of the rest. You can then deregister those files programmatically whenever you want.
  • If other plugins / themes make use of the same Javascript or CSS files (typically a Javascript framework like jQuery), WordPress will only print one instance of the shared files, thus saving you from sacrificing web loading speed for duplicate media files.
  • Other plugins / themes can combine / minify any JS or CSS files used on your site easily (using my BWP Minify plugin, for example), which reduces HTTP requests, and in turn increases website’s speed.
  • Other developers can deregister JS, CSS files registered by your plugins / themes, which allows them to easily build a custom page on which only certain JS, CSS files are loaded.

Of course, you can’t simply use enqueueing functions and expect that your website will be faster. You have to enqueue things the right way.

There are many tutorials about enqueueing things with WordPress on wp_enqueue_script’s codex page, and amongst all articles listed in the Resources section, I highly suggest this nice guide by Scribu (an experienced WordPress developer, author of the awesome FEE plugin).

Follow other WordPress Standards

Apart from enqueueing Javascript and CSS files, it is also recommended that you follow other WordPress Standards (which should not be confused with the Coding Standard that can be found here).

For some basic standards, check out Writing a Plugin and Theme Development Codex pages. For actual WordPress Standards, search and study various documentation pages of WordPress APIs and template functions. It will not be an easy task, I know, but they will help you optimize your plugins or themes greatly later on.

2. Separate back end and front end

Separating back-end and front-end codes is not something new or difficult, but many developers still forget (or are simply too lazy) to do so. The logic is rather straightforward: what belongs to the front end should not be loaded in the back end, and vice versa.

In its simplest form, separation can be achieved by basically splitting your functions into two sections. For example, if you have a plugin file like this:

  1. function bwp_process_post_contents($content) {}
  2. add_filter('the_content', 'bwp_process_post_contents', 99999);
  3. // Functions to build admin page
  4. add_action('init', 'bwp_admin_init');
  5. function bwp_admin_init() {}
  6. function bwp_admin_function_1() {}
  7. function bwp_admin_function_2() {}
function bwp_process_post_contents($content) {}
add_filter('the_content', 'bwp_process_post_contents', 99999);
// Functions to build admin page
add_action('init', 'bwp_admin_init');
function bwp_admin_init() {}
function bwp_admin_function_1() {}
function bwp_admin_function_2() {}

Instead of wasting your expensive server’s resources and WordPress’s generation time on including things that aren’t even used to serve the page to your visitors, you should use a conditional statement like below to split things up:

  1. function bwp_process_post_contents($content) {}
  2. add_filter('the_content', 'bwp_process_post_contents', 99999);
  3. // Function to build admin page
  4. if (is_admin()) :
  5. add_action('init', 'bwp_admin_init');
  6. function bwp_admin_init() {}
  7. function bwp_admin_function_1() {}
  8. function bwp_admin_function_2() {}
  9. endif;
function bwp_process_post_contents($content) {}
add_filter('the_content', 'bwp_process_post_contents', 99999);
// Function to build admin page
if (is_admin()) :
add_action('init', 'bwp_admin_init');
function bwp_admin_init() {}
function bwp_admin_function_1() {}
function bwp_admin_function_2() {}
endif;

Taking this approach to a higher level, you can separate your codes in three completely different files, as shown below:

  1. /* the main plugin file */
  2. $plugin_file = (is_admin()) ? 'bwp_plugin_admin' : 'bwp_plugin';
  3. // Include things that should be shared between your plugin's front end and back end
  4. include_once(dirname(__FILE__) . '/common.php');
  5. // Include front-end file and back-end file separately
  6. include_once(dirname(__FILE__) . '/' . $plugin_file . '.php');
  7.  
  8. /* bwp_plugin.php */
  9. function bwp_process_post_contents($content) {}
  10. add_filter('the_content', 'bwp_process_post_contents', 99999);
  11.  
  12. /* bwp_plugin_admin.php */
  13. add_action('init', 'bwp_admin_init');
  14. function bwp_admin_init() {}
  15. function bwp_admin_function_1() {}
  16. function bwp_admin_function_2() {}
/* the main plugin file */
$plugin_file = (is_admin()) ? 'bwp_plugin_admin' : 'bwp_plugin';
// Include things that should be shared between your plugin's front end and back end
include_once(dirname(__FILE__) . '/common.php');
// Include front-end file and back-end file separately
include_once(dirname(__FILE__) . '/' . $plugin_file . '.php');

/* bwp_plugin.php */
function bwp_process_post_contents($content) {}
add_filter('the_content', 'bwp_process_post_contents', 99999);

/* bwp_plugin_admin.php */
add_action('init', 'bwp_admin_init');
function bwp_admin_init() {}
function bwp_admin_function_1() {}
function bwp_admin_function_2() {}

This way, if your plugin does most work inside wp-admin, your plugin’s footprint on the front end will be negligible, and if most work is done on the front end, your plugin will not slow down WordPress’s admin area at all.

3. Use WordPress APIs and Helper Functions

WordPress itself has many useful APIs (such as the wpdb Class) and helper functions (such as make_clickable) that you can make use of instead of writing your own functions. Using those ready-made functions will most of the time gives you two benefits: first, you don’t need to reinvent the wheel, and second, you can enjoy an optimized function written by experts all around the world.

To list a few useful functions that I find myself using a lot when developing plugins:

  • checked()1, disabled()2, selected()3: Helps you add appropriate checked, disabled and selected attributes to HTML form fields.
  • esc_attr(), esc_url(), esc_html(), etc.: Data validating and escaping functions. See Data Validation codex page for more details.
  • wp_remote_post()4 / wp_remote_get()5: Retrieves a URL using the HTTP POST / GET method, returning results in an array. Results include HTTP headers and content.
  • plugins_url()6: Retrieves the url to the plugins directory or to a specific file within that directory.
  • plugin_dir_url()7 / plugin_dir_path()8: Similar to the above, these two functions help you determine the absolute URL / Path to a single plugin’s folder, given the plugin __FILE__.
  • wp_insert_post()9: Inserts posts (and pages) in the database. It sanitizes variables, does some checks, fills in missing variables like date/time, etc.
  • wp_new_comment()10: Adds a new comment to the database.
  • wpdb Database Class APIs: $wpdb->prepare(), $wpdb->insert(), $wpdb->update(), etc.
  • WP_Query APIs: get_query_var(), wp_reset_query(), wp_reset_postdata(), get_queried_object(), etc.
  • Template tags: is_home(), is_single(), etc.
  • And many others…

Most, if not all functions listed above make great use of WordPress’s internal object cache, which reduces the total number of database queries needed for each page. Such optimization will obviously result in faster page loading.

4. Don’t use query_posts() when not needed

As stated in previous tip, WordPress APIs are very useful, but it doesn’t mean that you should use them all the time. And, amongst all WordPress APIs and helper functions, query_posts() is the perfect example of an API that you should NOT blindly use.

The reason is quite simple: in some (if not many) situations, query_posts() is actually an overkill because it makes use of many internal parts of WordPress, which might actually slow down your plugins or themes.

For example, when you want to know the title of the newest movie (a custom post type) on your blog, if you use query_posts(), WordPress will get and store a lot of unnecessary things (such as post meta) because it thinks you’re going to use them anyway, which you unfortunately won’t. To get the title in a more efficient way, do this instead:

  1. $the_movie_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE post_type = 'movie' ORDER BY post_time DESC LIMIT 1");
$the_movie_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE post_type = 'movie' ORDER BY post_time DESC LIMIT 1");

Of course, the above method will render template functions like the_title() useless, but you can work around that by using these 2 lines of codes:

  1. $the_movie_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE post_type = 'movie' ORDER BY post_time DESC LIMIT 1");
  2. echo apply_filters('the_title', $the_movie_title);
$the_movie_title = $wpdb->get_var("SELECT post_title FROM $wpdb->posts WHERE post_type = 'movie' ORDER BY post_time DESC LIMIT 1");
echo apply_filters('the_title', $the_movie_title);

In a more special case, when you want to have a customized list of posts such as latest 5 posts from each post type, using query_posts() is also highly discouraged. The reason is described clearly in this article, which has shown us noticeable difference in generation time between query_posts() and our own custom codes.

This tip can actually be applied to other WordPress APIs and helper functions, such as get_permalink(), get_term_link(), etc. but let’s talk about that in another dedicated article, shall we ;)?

5. Cache frequently used variables

First of all, don’t fret when you hear the word cache, as there’s actually nothing special about it: instead of re-generating some data every single time, you query and store them in one place (the cache), and then use them for different purposes at different places by simply getting from that one place.

To make things simple, we will only talk about the two most basic caching methods: store data in a variable and reuse that variable, or make use of WordPress’s internal object cache.

If the former method is what you prefer, check out this article of mine about WordPress Global Variables to have a better understanding of what you can do to re-use as many variables as possible, using global variables.

If you choose the later method, you can have something similar to this:

  1. function bwp_get_var($key)
  2. {
  3.     return wp_cache_get($key, 'bwp');
  4. }
  5. function bwp_set_var($key, $data, $expire)
  6. {
  7.     return wp_cache_set($key, $data, 'bwp', $expire);
  8. }
  9. // An expensive MySQL query
  10. $result = $wpdb->get_results('SELECT * FROM ' . $wpdb->posts . ' ORDER BY RAND() LIMIT 5');
  11. bwp_set_var('5-random-post-result-set', $result);
function bwp_get_var($key)
{
	return wp_cache_get($key, 'bwp');
}
function bwp_set_var($key, $data, $expire)
{
	return wp_cache_set($key, $data, 'bwp', $expire);
}
// An expensive MySQL query
$result = $wpdb->get_results('SELECT * FROM ' . $wpdb->posts . ' ORDER BY RAND() LIMIT 5');
bwp_set_var('5-random-post-result-set', $result);

Now, whenever you want to use the result set, simply call the getter function with appropriate key and the data will be ready for use within any block of codes:

  1. $result = bwp_get_var('5-random-post-result-set');
  2. // Print the 5 posts
  3. foreach ($result as $post)
  4. {
  5.     // Print post's contents
  6. }
$result = bwp_get_var('5-random-post-result-set');
// Print the 5 posts
foreach ($result as $post)
{
	// Print post's contents
}

One major benefit of using object cache is the huge speed boost for your plugins or themes if an opcode cacher such as Memcached, XCache, or APC is also installed.  To learn more about WordPress object cache, I suggest that you check out WP_Object_Cache’s codex page and this article by Mark Jaquith.

The Bottom Line

Develop with users in mind

It’s all about users, and it’s a fact. All tips listed above will indeed help you optimize your plugins or themes, but it’s still users that determine your product’s success. Don’t try to implement things that are not going to be used by anyone as it will only make your plugin unnecessarily heavier.

Since WordPress loads all plugins when it initializes itself, your plugin’s files are also loaded every single time WordPress is loaded, even when your plugin doesn’t do a thing. For example, if your plugin only processes post contents when a visitor reads a single post, does it need to be included when that visitor visits the homepage? Of course not.

So please, do your users a favour and load your plugins only when they are needed. Otherwise, your users will have to struggle and either hack your plugin’s files, or use a hackish method called Selective Plugin Loading, neither of which are recommended.

Combined strength

Up until now, speeding up WordPress still sounds a lot like a user’s or a sysadmin’s task, because when people talk about that term, they tend to think about it from an end-user’s POV. From a developer’s POV, it’s obvious that if you improve something internally without the help of extra plugins or softwares, your product will be much more efficient and, of course, faster.

To have a truly faster WordPress, developers must join force with users by writing optimized WordPress plugins and themes, and then users can again optimize those plugins or themes further if needed. This way, a blazingly fast WordPress is within the reach of any WordPress user, even a starter.

That’s it for this article! I hope you guys, especially WordPress developers, will find it useful. For a better WordPress and beyond!

References

  1. http://codex.wordpress.org/Function_Reference/checked []
  2. http://codex.wordpress.org/Function_Reference/disabled []
  3. http://codex.wordpress.org/Function_Reference/selected []
  4. http://codex.wordpress.org/Function_API/wp_remote_post []
  5. http://codex.wordpress.org/Function_API/wp_remote_get []
  6. http://codex.wordpress.org/Function_Reference/plugins_u ... lugins_url []
  7. http://codex.wordpress.org/Function_Reference/plugin_di ... in_dir_url []
  8. http://codex.wordpress.org/Function_Reference/plugin_di ... n_dir_path []
  9. http://codex.wordpress.org/Function_Reference/wp_insert ... nsert_post []
  10. http://codex.wordpress.org/Function_Reference/wp_new_co ... ew_comment []
Elegant Themes - Designed with Modest Elegance
Print Article Trackback Trackback to this Article   Subscribe to Comments RSS Subscribe to Comments RSS

7 Opinions for Speed Up WordPress: A Developer’s POV

  1. User's Gravatar
    1
    Pothi Kalimuthu March 8, 2012 at 3:30 pm – Permalink

    Awesome details. I wish every developer has these in mind while developing the theme or plugins.

  2. User's Gravatar
    2
    Adrian April 27, 2012 at 1:22 pm – Permalink

    Very detailed and great tips.
    Some of them i’ve tried already.

  3. User's Gravatar
    3
    Plato P. September 25, 2013 at 6:39 pm – Permalink

    Hello,
    I would like to know if the plugin Better Minify will be resource intensive on an average VPS? My blog has around 1000 posts and I don’t want my site to crash after installing this plugin. I am sorry but one js and css script optimizer literally made the server reboot. Please do reply.

    And thanks for the guide!

    • User's Gravatar
      5
      Khang Minh October 6, 2013 at 9:51 pm – Permalink

      That will depend on other factors as well, for example: the number of visitors/pageviews, the number of js/css on your site. If you have a high traffic website it’s better to have pre-minified js/css served from a static domain/cloud server.

      Nevertheless, I believe BWP Minify can function well.

  4. User's Gravatar
    4
    stefano October 3, 2013 at 5:42 pm – Permalink

    Hi, thank you for this fantastic job, I’m learning tu use but I undestand it is great.
    There is one question but, google says that sitemap of google news it is different from ordinary sitemap, so they make you thing you have to submit individually, but reading your indication I understand you have to send one sitemap.
    So my double is: sitemap is one ore two with the second for google news? And if it is, where I can find?

    • User's Gravatar
      6
      Khang Minh October 6, 2013 at 9:53 pm – Permalink

      There’s only one sitemapindex (sitemapindex.xml or sitemap.xml), and the news sitemap is also included, but you must submit the news sitemap separately to Google News.

  5. User's Gravatar
    7
    Tom January 24, 2014 at 6:34 am – Permalink

    Thx for these nice tips. This helps to speed up my new WordPress blog

Speak Up Your Mind!

An asterisk (*) indicates a required field and must be filled.




  • Web page and e-mail addresses turn into links automatically.
  • Wrap codes in: <code lang=""></code> or <pre lang="" extra="">
  • Lines and paragraphs break automatically.

Next Post: