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.

Tools

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.

Operations

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];
    }
    add_filter('script_loader_src','_remove_script_version',15,1);
    add_filter('style_loader_src','_remove_script_version',15,1);
    

     

  • 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
      </IfModule>
      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>
       <FilesMatch "\.(html|htm)$">
        Header set Cache-Control "max-age=31536000, must-revalidate"
       </FilesMatch>
      </IfModule>
      

     

  • 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
     </FilesMatch>
    </IfModule>
    
  • 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!

Enjoy!

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)){
     unset($variables['tabs'][$group_key][$key]);
    }
   }
  }
 }
}

Enjoy!

Drupal 7: Add a class to the body

Drupal Today I had to add a class to the body so know if I was logged in as “administrator” like role, it needed to have the permission to modify any content of the type MYTYPE.

To add a class to the body you have to work on the template_preprocess_html for your theme, like the snippet below.


function MYTHEME_preprocess_html(&$vars) {
  if(user_access("edit any MYTYPE content")){
   $vars['classes_array'][] = "MYCLASS";
  }
}

The user_access() will check if the current user (if there isn’t one specified) has the selected permission, the permission is the one you can see from the permission administration page, if you are using Drupal in another language then refer to the base English interface to know what to write there.

Enjoy!

Drupal 7: Manually update jQuery version

Drupal Today for a customer I had to use a special plugin for jQuery that needs a jQuery version equal or major than 1.6.1.

As you know Drupal 7 is shipped with jQuery 1.4.4 and so is not ready for the plugin I need to use, there is a plugin that update jQuery and jQuery UI but where is the fun?

The procedure is pretty quick:

  • Download the jQuery version you need from from the official source.
  • Place the jQuery version you downloaded in your theme js’s folder (like MYTHEME/js/).
  • Create/Modify your theme’s template.php file as described below.

That is.

Now for the template.php, you need to use the hook_js_alter to replace the native jQuery:

function MYTHEME_js_alter(&$javascript) {
  //We define the path of our new jquery core file
  //assuming we are using the minified version 1.8.3
  $jquery_path = drupal_get_path('theme','MYTHEME') . '/js/jquery-1.8.3.min.js';

  //We duplicate the important information from the Drupal one
  $javascript[$jquery_path] = $javascript['misc/jquery.js'];
  //..and we update the information that we care about
  $javascript[$jquery_path]['version'] = '1.8.3';
  $javascript[$jquery_path]['data'] = $jquery_path;

  //Then we remove the Drupal core version
  unset($javascript['misc/jquery.js']);
}

After we clear the cache we will have the new jQuery version.

Keep in mind that changing the jQuery version may create some incompatibility issues with the other Drupal core scripts.

Enjoy!

Drupal SA-CORE-2012-003 quick fix

Drupal Recently Drupal released the new version (7.16) to fix a security issue that would allow an attacker to reinstall an existing Drupal site with an external database server and then execute custom PHP code, more information available here: http://drupal.org/node/1815912.

There are many way to prevent this instead of updating a Drupal installation (always recommended), probably the quickest is to deny access to the interested file with few lines for the .htaccess file:


<Files install.php>
  deny from all
  ErrorDocument 403 "Access denied."
</Files>

Enjoy!