Speed up WordPress with some optimization


Hello everyone,
recently I had to optimize a wordpress website that was really slow, in the end I achieved this result:

www.webpagetest.org result

Test done thanks to http://www.webpagetest.org/

I believe it is an acceptable result, it could be better by using a CDN, but I thought it would be not worth the effort (at least for now).

I’ll explain the tools and the procedures I used to speed up the website.


The above-mentioned tools helped me understanding the situation and where to work to fix one by one all the problems along with WordPress’s Codex.


WordPress administration interface related operations:

  • Checking the installed plugins:The easier step, and one of the most effective, available. Many WordPress users tend to get overexcited by the huge amount of plugins available and might end up install a lot of them.
    Usually a plugin interact with the database or simply interact with the WordPress installation by implementing new features, widgets, theme modifications, fancy shortcodes, introducing new JavaScript files and/or CSS files bloating the website with a lot of things to handle, this generate 2 important problems:

    1. More database queries
    2. Higher RAM consumption

    This 2 things together will slow down by a lot your website so is important to understand what your website need and what you need and can me implemented with few lines of code.

    Taking as example Twitter, you can find many plugins that will display your recent tweets or allow others to follow you. There is no need to use plugins for something so simple, Twitter is kind enough to offer the code snippets needed to achieve this, they are available here: https://twitter.com/settings/widgets.

    A lot of other situations like this one can be simplified by using snippets offered by the service itself (Facebook, Google+, Linkedin, Instagram and many other offer snippets). Don’t use a plugin when you can instead use few lines of code, it is usually a matter of seconds (copy & paste).

  • Caching:
    Using a valid caching system will enable your WordPress website to go really fast (the access speed to the website I optimized went from 2 seconds to less than 400ms by just adding a wordpress’s plugin to handle the cache).There are many WordPress plugins that handle the cache and allow customization of what-to-cache-and-how but unless you really know what you are doing it is better to grab a simple plugin and enable the recommended options (just keep in mind that recommended doesn’t mean default).I used WP Super Cache and I’m very happy with it, it works without spending hours to configure it and the gain in performance is huge, keep in mind that it is not bug free so keep an eye about updates.

    Few steps are needed to have a basic-intermediate configuration:

    1. From the “Easy” tab select “Caching on (Recommended)
    2. From the “Advanced” tab select:
      • Cache hits to this website for quick access.(Recommended)
      • Use PHP to serve cache files.
      • Compress pages so they’re served more quickly to visitors.(Recommended)
      • Cache rebuild. Serve a supercache file to anonymous users while a new file is being generated.(Recommended)
    3. Again in the “Advanced” tab configure the Cache Timeout and the Scheduler so the stale cached files will get properly removed

    With this few steps you will get a huge boost in access speed but you will have to manually empty the cache (from the Settings menu in your WordPress administration) if you need to have a page or a post updated instantly or wait for the cache timeout.

    You can also use the “Preload” tab to cache every published post and page on your site automatically, be warned that preloading creates lots of files since the caching is done for every post and page (from the newest to the oldest), you will also be able to set the time between each refresh, depending on the amount of visits and other parameters (server resources, frequency of new contents etc…) you may want a short interval (30 minutes) or a larger one (60+).

  • Image optimization:
    From the tool list I mentioned Compress JPG and Compress PNG, they are awesome tools that can greatly reduce the disk space occupied by the images and therefore speed up the website by reducing the weight of the pages, it is important that you also resize the images to the actual needs, there is no need to have skyscraper-sized images for a homepage slider or a showcase, unless you actually want to share such things and even in this case, linking to the bigger image is preferred.

The situation so far

At this point the other optimizations are on the code, if you are not familiar with coding related knowledge (WordPress structure, PHP, FTP/SSH, CSS, JavaScript, HTML, etc…) you may stop reading here and have a partially optimized website, it will perform better than the initial state but it will not be at its better level.

Code optimization

WordPress’s code is not that bad, but some basic changes can be made to optimize it.

  • Script to the bottom:
    Moving the scripts to the bottom of the HTML document is really the most basic and know technique to speed up the pages since JavaScript files block the downloads of the other assets and prevent parallel downloads from any domain.
    To instruct wordpress to move all the scripts to the bottom, you can use this small snippet in the functions.php :

    remove_action('wp_head', 'wp_print_scripts');
    remove_action('wp_head', 'wp_print_head_scripts', 9);
    remove_action('wp_head', 'wp_enqueue_scripts', 1);
    add_action('wp_footer', 'wp_print_scripts', 5);
    add_action('wp_footer', 'wp_enqueue_scripts', 5);
    add_action('wp_footer', 'wp_print_head_scripts', 5);
  • Remove unnecessary query tags from CSS & JavaScript files:
    The query tags serve the purpose to always send the correct version of the file regardless the cached version of it.
    This snippet will strip away the query tag, it is also possible to specify a NULL value instead of FALSE or a version when enqueuing the resources, but I haven’t tested it.

    function _remove_script_version($src) {
     $parts = explode( '?', $src );
     return $parts[0];
  • Generic theme optimization:
    Since (almost) everyone use external resources in a webpage (google fonts, social network widgets, tracking codes, CDNs for JavaScript libraries, etc..) it is important to keep in mind that each request to an external source will incur a DNS lookup.To avoid that, you have to modify your <head> with few lines of code that will prefetch the DNS as soon as possible speeding up the process.Here a snippet that will show the most use of the DNS prefetching technique on the most commonly used domains:

    <link rel="dns-prefetch" href="//fonts.googleapis.com">
    <link rel="dns-prefetch" href="//platform.twitter.com">
    <link rel="dns-prefetch" href="//www.google-analytics.com">
    <link rel="dns-prefetch" href="//themes.googleusercontent.com">
    <link rel="dns-prefetch" href="//p.twitter.com">
    <link rel="dns-prefetch" href="//cdn.api.twitter.com">

    More information on the topic is available here: http://calendar.perfplanet.com/2012/speed-up-your-site-using-prefetching/.

  • CSS homepage optimization:
    Assuming you are still reading, I would like to share the tool I’ve made while working on the homepage optimization.I believe that the homepage is a critical part of the website, and should then (if/when possible) perform as better as possible (would be better if the performance was great on the whole website of course).Since I’m not (yet) a master in the ways of Shell my script is not the best around, and I’m sure it can be a lot better, but it get the job done.

    The idea behind the tool is to take in input the list of the CSS classes thare are not used in the homepage (thanks to the Google Chrome’s Audit tab of the developers tools) and the CSS file(s) that are used (after formatting it with this tool with the option “Insert a line breaks after ‘}’ characters.”) and it will output a new file that will not have the unneded classes.

  • .htaccess caching management:
    Assuming you can’t modify the virtual host configuration, you can modify (and should) the .htaccess file to define directives that will help speeding up the website.From apache.org:

    You should avoid using .htaccess files completely if you have access to httpd main server config file. Using .htaccess files slows down your Apache http server. Any directive that you can include in a .htaccess file is better set in a Directory block, as it will have the same effect with better performance.

    There are few modifications possible:

    • ETag removal:
      More information available here: http://developer.yahoo.com/performance/rules.html#etags.

      # 'FileETag None' is not enough for every server.
      <IfModule mod_headers.c>
       Header unset ETag
      FileETag None
    • Far future expire header:
      With this few lines of code we set the expiry date to 1 year in the future.

      <IfModule mod_headers.c>
       <FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|js|css|swf)$">
        Header set Cache-Control "max-age=31536000, public"
       <FilesMatch "\.(html|htm)$">
        Header set Cache-Control "max-age=31536000, must-revalidate"
  • Other .htaccess modifications:
    Lastly we can also force Internet Explorer to always show the website at latest version, it may fallback to IE7 and if it is available it will use ChromeFrame if it’s installed.

    <IfModule mod_headers.c>
     Header set X-UA-Compatible "IE=edge,chrome=1"
     <FilesMatch "\.(appcache|crx|css|eot|gif|htc|ico|jpe?g|js|m4a|m4v|manifest|mp4|oex|oga|ogg|ogv|otf|pdf|png|safariextz|svg|svgz|ttf|vcf|webm|webp|woff|xml|xpi)$">
      Header unset X-UA-Compatible
  • Apache configuration:
    To maximize the speed of the connection it is also important to correctly configure the Keep-Alive setting to allow a single HTTP session to permit mutliple requests to be sent over the same TCP connection. More information are available at the apache.org website.

And that is all, it took me a lot of time, but I’m more than happy to share my knowledge and discoveries with everyone who care about this stuffs.

The WordPress website I optimized is www.oss4b.it and here is a recent report about the situation on the website.

Unfortunately I didn’t had the chance to work on the database optimization, but I’m looking forward to try Percona Server as I was lucky enough to be at the conference and speak with a Percona expert, was very interesting!

I’m open to questions and suggestions as I believe some things could have been done better and that there are a lot of tools that I don’t know of!



2014 in review

The WordPress.com stats helper monkeys prepared a 2014 annual report for this blog.

Here’s an excerpt:

The concert hall at the Sydney Opera House holds 2,700 people. This blog was viewed about 20,000 times in 2014. If it were a concert at Sydney Opera House, it would take about 7 sold-out performances for that many people to see it.

Click here to see the complete report.

Set a custom CSS class to an image in Drupal 7

Drupal I’m working for a customer to create a Bootstrap 3 theme from scratch, since I’ve to create a kind of portfolio-like page with some thumbnails I needed to apply the Bootstrap’s CSS class img-thumbnail to all the images.

It took some time but the action is possible and take few steps, it assume that you are using a custom image style type to display your image(s):

1. In your template.php file you need to define a new override function like this:

function fancythemename_preprocess_image(&$variables) {
 if (isset($variables['style_name'])) {
  if ($variables['style_name'] == 'fancystylename')
   $variables['attributes']['class'][] = 'img-thumbnail'; //bootstrap class

That is,
happy coding!

2013 in review

The WordPress.com stats helper monkeys prepared a 2013 annual report for this blog.

Here’s an excerpt:

The concert hall at the Sydney Opera House holds 2,700 people. This blog was viewed about 17,000 times in 2013. If it were a concert at Sydney Opera House, it would take about 6 sold-out performances for that many people to see it.

Click here to see the complete report.

Fixing MySQL error 29 (ErrCode: 13) in Ubuntu

Ubuntu 12.04 Recently I had to work with a large amount of data that had to be imported into MySQL via a script after being modified. I’ve found that using LOAD DATA was the quickest way to do the job.

If you are using Ubuntu for your server (or you have to work with a server using Ubuntu) you will find this error when trying to use the query:

ERROR 29 (HY000): File '....' not found (Errcode: 13)

After few seconds on Google you will find many users that managed to get over the error using the keyword LOCAL, but if you keep your MySQL updated you will see that it will not work as it could generate a security issue in your server.

To overcome this issue there is a simple workaround that require you to modify the MySQL’s AppArmor file and define directory where the program can read and write.

Be aware that allowing MySQL to read and write in a directory could lead to security problems, always review this kind of changes with a System Administrator.

The workaround is really quick:

  1. Open the file /etc/apparmor.d/usr.sbin.mysqld as root with your favourite text editor
  2. You should see a list of paths where AppArmor allow MySQL to write and read, at the end of this list add the directory where you would like that MySQL will be able to read and write following the pattern used in all the previous entries. For instance:
    #Other contents
    /usr/sbin/mysqld {
        #Other contents
        /var/log/mysql.log rw,
        /var/log/mysql.err rw,
        #Other contents
        #This will be your dir definition
        /tmp/ r,
        /tmp/* rw,
        #Other contents

    Then save and close the file.

  3. After you have successfully modified the file it is time to tell AppArmor that it needs to reload the configurations, so as root execute the following command:
    # /etc/init.d/apparmor reload
  4. Then restart MySQL, as root execute the following command:
    # service mysql restart

At this point you have allowed MySQL to write and read contents into your defined directory, only do this if you know what you are doing! I take no responsibility for any damage or data loss caused by a server not correctly secured.

Be careful & have fun!

Writing a custom FormBuilder in Rails 4.0.x

Ruby on rails For my tutorial application on Rails I wanted to use the Bootstrap 3 form layout instead of the one offered by form_for.

Since my needs where simple, I avoided special gems (like Formtastic or Simple_Form) and developed a custom FormBuilder to do the job.

The documentation about is good but was not enough for me, the basic structure is easy to understand:

  • Extend ActionView::Helpers::FormBuilder
  • Define a custom method or…
  • …override superclass methods

Therefore the result should be something like this structure:

class MySuperFormBuilder < ActionView::Helpers::FormBuilder

 # Defining a new method for the custom FormBuilder
 def better_text_field(method, options = {})
  #your custom code goes here

 # Overriding a superclass method
 def text_field(method, options = {})
  #your custom code goes here


Having defined your new FormBuilder you need to call it inside the form_for like this:

<% form_for( ... , :builder => MySuperFormBuilder ) do |f| %>

Or you can force it globally by adding this line into your application.rb file:

ActionView::Base.default_form_builder = MySuperFormBuilder

This is more like an exercise than something that you would need to do on a per-project base, you can find my custom implementation on GitHub.

Drupal 7: how to hide unwanted tabs

DrupalAssuming you want to hide some tabs from a specific page, content type, user role, specific URLs or other discriminating criteria, you need to work on the $variables variable and unset the unneeded tabs.

The following snippet will remove “subscriptions” and “favorites” tabs to all the non “editor” users:

if($variables['user']->uid > 1 && !in_array('editor', $variables['user']->roles) && !in_array('administrator', $variables['user']->roles)) {
 $to_be_removed = array('user/%/subscriptions', 'user/%/favorites');
 foreach ($variables['tabs'] as $group_key => $tab_group) {
  if (is_array($tab_group)) {
   foreach ($tab_group as $key => $tab) {
    if (isset($tab['#link']['path']) && in_array($tab['#link']['path'], $to_be_removed)){