WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. Join them; it only takes a minute:

Sign up
Here's how it works:
  1. Anybody can ask a question
  2. Anybody can answer
  3. The best answers are voted up and rise to the top

Besides installing W3 Total Cache or another caching plugin what steps can I take to make sure that my theme and site run as fast as possible.

share|improve this question
if you run your site on vps , you should try redis cache. – ahmetlutfu Apr 5 '14 at 22:58

13 Answers 13

You could install WordPress on Nginx. There are a number of resources to help:

Some performance information from that last link (which appears to be a bit different setup than the others):

So I decided to put a proxy in front of wordpress to static cache as much as possible. ALL non-authenticated traffic is served directly from the nginx file cache, taking some requests (such as RSS feed generation) from 6 pages/second to 7000+ pages/second. Oof. Nginx also handles logging and gzipping, leaving the heavier backend apaches to do what they do best: serve dynamic wordpress pages only when needed.


On nginx – it’s so efficient it’s scary. I’ve never seen it use more than 10 to 15 meg of RAM and a blip of CPU, even under our heaviest load. Our ganglia graphs don’t lie: we halved our memory requirements, doubled our outgoing network throughput and completely leveled out our load. We have had basically no problems since we set this up.

share|improve this answer
Anyone have any stats on the speed savings of using Nginx? – Mike Lee Aug 18 '10 at 15:07
Mike, I added another link, and some information from that post. – tnorthcutt Aug 18 '10 at 15:14
I moved my main blog from a 1G server running Apache to a 512M server runing Nginx. Runs more smoothly, despite the decrease in RAM. Admittedly, I have other services running on the 1G server, though (email, imap, mailman, several other low-traffic web sites). – Dougal Campbell Jun 7 '12 at 20:26
NB running WordPress on nginx is different from using nginx as a proxy cache in front of Wordpress. – sam May 2 '13 at 21:08

Set client-side expiries for things like css, images, JavaScript etc which don't need to be redownloaded for each page view. This, by far, made the biggest difference to my site loading times. The fastest download is the download that never happened ...

# BEGIN Expire headers
<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresDefault "access plus 7200 seconds"
  ExpiresByType image/x-icon "access plus 2592000 seconds"
  ExpiresByType image/jpeg "access plus 2592000 seconds"
  ExpiresByType image/png "access plus 2592000 seconds"
  ExpiresByType image/gif "access plus 2592000 seconds"
  ExpiresByType application/x-shockwave-flash "access plus 2592000 seconds"
  ExpiresByType text/css "access plus 2592000 seconds"
  ExpiresByType text/javascript "access plus 2592000 seconds"
  ExpiresByType application/x-javascript "access plus 2592000 seconds"
  ExpiresByType text/html "access plus 7200 seconds"
  ExpiresByType application/xhtml+xml "access plus 7200 seconds"
# END Expire headers

# BEGIN Cache-Control Headers
<IfModule mod_headers.c>
  <FilesMatch "\\.(ico|jpe?g|png|gif|swf|gz)$">
    Header set Cache-Control "max-age=2592000, public"
  <FilesMatch "\\.(css)$">
    Header set Cache-Control "max-age=2592000, public"
  <FilesMatch "\\.(js)$">
    Header set Cache-Control "max-age=2592000, private"
<filesMatch "\\.(html|htm)$">
Header set Cache-Control "max-age=7200, public"
# Disable caching for scripts and other dynamic files
<FilesMatch "\.(pl|php|cgi|spl|scgi|fcgi)$">
Header unset Cache-Control
# END Cache-Control Headers

You may pre-gzip everything you reasonably can (7-zip is a good tool for this) & upload it in the same place as the file you just gzipped. Change .htaccess to serve the pre-gzipped files, as below. The caveat here is you need to remember to re-gzip them if/when you update things. This cuts out the CPU overhead, apart from parsing .htaccess.

RewriteEngine on
#Check to see if browser can accept gzip files. If so and we have it - serve it!
ReWriteCond %{HTTP:accept-encoding} gzip
RewriteCond %{HTTP_USER_AGENT} !Safari
#make sure there's no trailing .gz on the url
ReWriteCond %{REQUEST_FILENAME} !^.+\.gz$
#check to see if a .gz version of the file exists.
RewriteCond %{REQUEST_FILENAME}.gz -f
#All conditions met so add .gz to URL filename (invisibly)
RewriteRule ^(.+) $1.gz [QSA,L]

This is just a raw answer. There are a lot of variations on this theme. I blogged about this and added quite a few references to more in-depth articles at http://icanhazdot.net/2010/03/23/some-wordpress-stuff/. Read that and, more importantly, the references I point to - they are good resources.

Be aware that if you tinker often then users will need to refresh their cache.

A plugin I found very useful too is wp-minify. The thing to watch with this one is that you should exclude page-specific items (contact form, front page slider etc) so you're not re-downloading the whole set of css, JS etc for each page. It is a good way to minify, combine & compress your baseline CSS, JS etc. It cuts down on http requests a lot. Wp-minify plays well with supercache and also with expiry headers that I detailed above.

Use Yslow in Firebug (Firefox) or similar to monitor your http requests and what is and isn't compressed. Have a look at expiry headers in there too. You will soon see what you can improve.

share|improve this answer
In case someone plans to copy/paste your Rewrites, there's an instance of "ReWrite" that should be corrected. – Nerdling Dec 12 '10 at 23:13
which instance? – CAD bloke Dec 19 '10 at 6:52
@Nerdling Could you please point out which instance needs fixing? I'd like to use the above code. – helgatheviking Dec 28 '12 at 15:38
It may be related to mod gzip being deprecated in later versions of Apache. I had to change mine to mod deflate recently. – CAD bloke Dec 28 '12 at 21:36
This is good advice for improving client performance, but it doesn't directly affect WordPress's use of server resources. – sam May 2 '13 at 21:18

Minimize the number of plugins you run to only what you really need. Especially be aware of plugins that add javascript and CSS code on every page load, even when that code isn't being used on the page.

If you are creating your own theme from scratch, break your CSS down so that features that are only need for particular page templates or view types (single post, archives, category, etc) are only loaded when needed.

Configure W3TC to use a CDN (like Amazon CloudFront, or any of the others supported by W3TC).

See if the Minify options work for you (some plugins generate js/css that won't minify nicely, so be sure to test your site after activating the minify feature).

If you have full control of your MySQL server, make sure that you have the query_cache turned on. Use a MySQL tuning script to find other ways to optimize your database config.

If using a CDN is problematic for some reason, configure mod_expires in your apache setup. Set expiration times as long as reasonable for static types like images, css, javascript, video, audio, etc.

share|improve this answer

Run memcached and use an object cache to reduce the number of database queries. This caches data from the database, rather than pages. Not sure if w3-total-cache already does this.

Make sure you are running an opcode cache like APC. (There are several more available.)

share|improve this answer
APC really makes wordpress a lot more responsive, especially the admin pages. BUT, there are some potential configuration conflicts between WP-SuperCache and APC. These don't seem to affect W3 Cache. – WhIteSidE Aug 12 '10 at 15:50
There's an excellent post from Mark Jaquith on this:APC Object Cache Backend for WordPress. You can use batcache happily with APC. – icc97 Oct 21 '14 at 14:26

In addition to using a disk caching plugin like wp-cache, put your blog on a host volume that has the "noatime" property set on it. Otherwise, SSH into your host (if your webhost provides that) and routinely run this command on your files every few days:

chattr -R +A ~/*

The ~/* means "my files under my home directory". You can change that path as you see fit. You can also set this up on a cron job in cpanel if your webhost provides that.

For more info about atime property, see this. It speeds up Linux disk read performance greatly.

Sometimes your site is being hammered by spiders. You can use a tool like SpyderSpanker or Chennai Central to filter out spiders who don't help bring more page rank to your site and merely slow it down, and then throttle good spiders (like Google, Bing, etc.) by sending them random HTTP 304 Not Modified messages.

Another thing I see is just poorly written plugins. If you learn how to make plugins, you begin to see how some plugins are inefficiently coded, or even find timebombs, such as a database table that fills and fills and never gets cleaned out, storing things such as incoming connection data.

Beyond all the other solutions here, you can also create a WordPress web farm of your blog by hosting it on several web node PCs that all connect back to one single database and one single disk volume for the files (such as a volume mounted over NFS). Check out Ultra Monkey for how to get that all going.

share|improve this answer

A few answers off the top of my head:

1) Minimize the number of HTTP requests the browser has to make to your host by concatenating JavaScript and CSS where possible/practical.

2) Offload as much of your image/media serving to 3rd party CDNs as possible, particularly if you're using shared hosting.

3) Try reducing the number of posts you're displaying on the front page in order to cut down on total render time.

3a) Try using a theme that presents a few featured posts in full on the front page and all other, older posts as excerpts.

share|improve this answer
+1 for reducing number of posts, this gives a tremendous boost with no cost. People don't really need to see ten old posts, I just set my conf to eight. – ripper234 Apr 23 '11 at 14:25

Caching the WordPress Menu also gives you a performance boost. Especially if you have a lot of Pages or a giant Menu Structure, this should be considered.

Do it in 2 easy steps. At first, create a function that gets or creates the menu, instead of calling wp_nav_menu directly.

function get_cached_menu( $menuargs ) {

    if ( !isset( $menuargs['menu'] ) ) {

        $theme_locations = get_nav_menu_locations();
        $nav_menu_selected_id = $theme_locations[$menuargs['theme_location']];
        $termslug = get_term_by( 'id', $nav_menu_selected_id, 'nav_menu' );
        $transient = 'menu_' . $termslug->slug . '_transient';

    } else {

        $transient = 'menu_' . $menuargs['menu'] . '_transient';


    if ( !get_transient( $transient ) ) { // check if the menu is already cached

        $menuargs['echo'] = '0'; // set the output to return
        $this_menu = wp_nav_menu( $menuargs ); // build the menu with the given $menuargs
        echo $this_menu; // output the menu for this run
        set_transient( $transient, $this_menu ); // set the transient, where the build HTML is saved

    } else {

        echo get_transient( $transient ); // just output the cached version



In your theme, replace the wp_nav_menus with get_cached_menu. Now, everytime the menu is called, you have one Databasequery instead of the whole Menubuilding.

Menus don't change often - but you also have to hook into the wp_update_nav_menu action to delete the old transients.

Do it like this:

add_action('wp_update_nav_menu', 'my_delete_menu_transients');

function my_delete_menu_transients($nav_menu_selected_id) {

    $termslug = get_term_by( 'id', $nav_menu_selected_id, 'nav_menu' );

    $transient = 'menu_' . $termslug->slug . '_transient';

    delete_transient( $transient ); 


The Menu will be generated the next time the page is called - and use the cached version until someone updates the menu again.

Updated Version

Thanks @helgatheviking for pointing out a mistake between slugs and IDs. I updated the functions so it works both with theme_position and menu (for a direct call of the menu).

The menus are always saved with the name of the Menu, not the position in the Theme.

share|improve this answer
This seems like a really cool idea. I'm having a problem with the code however. When we're clearing out the transient, the $nav_menu_selected_id is a number, while when calling the get_cached_menu() the menu_id is a string variable, because that parameter becomes the CSS ID for the <ul> element. – helgatheviking Dec 28 '12 at 15:40
Thank you very much @helgatheviking I corrected this mistake and added functionality for theme_position as well. – fischi Dec 28 '12 at 16:25
Awesome! This is working for me now as intended. – helgatheviking Dec 28 '12 at 17:06
Yeah. So this is my late Christmas Present for you ;) – fischi Dec 28 '12 at 17:11

Use a database class that is trimmed for optimization. We made good experiences with own code to reduce memory usage and database access speed. Next to that, you can optimize the database structure itself by some small changes that do a lot as well.

Part of the database class code can be found in the wordpress trac, it did not made it into core (Ticket #11799 and related).

share|improve this answer
Interesting solution. Here's the URL to the Trac Ticket in case anyone's interested too: core.trac.wordpress.org/ticket/11799 – Mike Lee Aug 18 '10 at 15:06

For a highly trafficked site, you should tune all MySQL buffers for the content that is in place now. Regardless of the version of WordPress, the MySQL layer can have its configuration computed.

In fact, if you have InnoDB data without enabling innodb_file_per_table, you need to cleanup InnoDB by segmenting each table into its own physical tablespace. It is possible to do decent MySQL tuning even if you have a limited hardware. There are many scenarios for doing such InnoDB optimizations.

IMHO, you cannot plan good settings for my.cnf without knowing the amount of data to configure for. You would have to periodically load a current dataset from production into a staging environment, perform optimizations and come away with the numbers to configure in the my.cnf of the production server.

share|improve this answer

you could enable global output compression. this will gzip everything going out automatically if the browser supports it. This drastically reduces the size of files transferred, but does increase your CPU load.

share|improve this answer
This will tend to make your site "feel" much slower. The Yahoo! technical documents suggest flushing you code right after the end of head and before the beginning of body so that scripts and styles can start loading. By buffering the entire page, you prevent this from happening, and so the page "feels" slow because the user has to wait for WordPress to render the entire page before the user sees anything. – WhIteSidE Aug 12 '10 at 15:53
Scott was not speaking about buffering the whole page but using apache output compression. That's something different, only if you use the PHP output compression via the output buffer this would have the deficiencies you describe vaguely. But not per-se anyway because in the end, buffering output can make things faster. This has something to do with I/O on your server. – hakre Aug 18 '10 at 8:51

I recently spoke about this subject at WordCamp Houston. All of the above recommendations are great and the important thing is to make sure all the front end stuff is fully optimized then you can start working on the caching and server performance issues.

Progressive rendering will make your pages feel faster because the user will see the page content before it is fully loaded. To do this make sure any blocking js is at the very bottom of the page and css is at the top.

Also if you use a lot of social media buttons you can customize the scripts to make them load in an iframe after the page is fully loaded. I wrote a tutorial on how to do it with the TweetMeMe re tweet button (now obsolete since Twitter released their own retweet button) but can still be applied to other share buttons.

For server performance look into Nginx as a front end proxy for static content with Apache handling the heavy PHP and MySQL lifting.

share|improve this answer

Since nobody mentioned it yet, one of the most important steps to enhance server performance in conjunction with any LAMP setup would be to switch to apache worker thread and mod_fcgid.

This freed up 500MB of memory on my virtual private server.

share|improve this answer
I've tried this before, but I've never been able to get a stable apache worker + fcgi environment running. If anybody knows of some good setup instructions for this under Ubuntu, please post them. I'd especially be grateful for instructions that detail some of the Apache config directives that affect the FCGI behavior, and explain how tweaking them might affect memory usage, performance, etc. Currently, I'm using a forked apache with an nginx front-in proxy cache server. – Dougal Campbell Feb 28 '11 at 14:51
Define stable. My installation is running very stable, but you would need 2GB of RAM in my config. You just have to read and tweak. apache's documentation on fcgi is fairly extensive. – Stephan Kristyn Mar 9 '11 at 10:50
try to check virtualmin.com its very stable and free – Ünsal Korkmaz Sep 11 '11 at 5:41

Guide for checking plugin slow down

There's a beautifully simple plugin called Page Load Time, which adds timer to your page footer. Its actually only four lines of code:

function ur_pageload_footer() {
    printf(__('Page in %s seconds', 'pageload'), timer_stop());
add_action('wp_footer', 'ur_pageload_footer')


  1. Create a spreadsheet
  2. List out all your active plugins and put them in there
  3. Refresh the page three times noting the page load time each turn
  4. Go through your plugins one by one deactivating them
  5. Repeat step 3
  6. Note the order that you deactivated the plugins

Your spreadsheet should look something like

| Run 1 | Run 2 | Run 3 | Order | Plugin |

So if after deactivating a plugin the page response time increases significanly then you can see if you can avoid that plugin.

I found two plugins that caused 'significant' slow down mqtranslate and (the rather old but good) Multi-level Navigation Plugin.

share|improve this answer
It would be really cool to automate this process is phantomjs and selenium(or something similar) so it runs automatically and spits out a little report at the end. – Paul Sheldrake Nov 18 '14 at 17:44

Your Answer


By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.