Joomla site slow? Here's some pointers (part 1)
Is your Joomla site a bit slow and laggy? We'll discuss some reasons why and some solutions you can put in place right now to speed things up a bit. This is a big topic with a lot to cover so here's part one.
There's no getting around the fact that as technology moves forward websites are getting bigger. A CMS like Joomla (or Worpress, Expression Engine, Drupal, etc) contains thousands of lines of code to provide the functionality, scalability and security required by even the smallest of modern websites.
Couple a large framework with an endlessly growing library of extensions, plugins and templates tempting us with their easy bolt-on functionality and it's easy for sites to swell beyond what a moderate broadband connection can handle.
Many news and blog sites load in excess of 100 assets on a single page load. That might sound like an exraordinarily high number but it's actually not uncommon. Here's a quick run down of what you might see if you look at the source of a typical blog or news style site with a list of articles down the page and call out modules on the side.
- Multiple CSS files loaded by the template.
- The Joomla template itself will use many images in the design. Perhaps accounting for up to 30 images.
- At least one template JS file. Usually more especially for responsive sites.
- 2 to 4+ Google Webfonts or @fontcace files.
- Joomla core JS files (mootools-core.js, core.js, modal.js, caption.js).
- Most extensions load JQuery too and a separate file containing the required scripts
- There is a menu JS and CSS file.
- Multiple news images for the summary down the home page.
- JS and CSS files loaded from Twitter to provide the follow and tweet buttons.
- Facebook loads CSS and JS for tlike buttons and streams. Multiple images in the facebook stream.
- Do you also have a Google+ button, instagram, pinterest buttons, etc. They all include code that loads files from external servers.
- Do you have a slideshow or news ticker ? That's another JS file, CSS file, and multiple images.
- What about your modules? The sign up, click here, more info modules that include a little icon or teaser image. Tabbed content modules load more JS and images.
- Login modules often include js files for validation or to spawn a modal window.
We could go on. So... what to do about it?
Remove the bloat
The obvious answer is to remove the excess. Cut back to bare basics. It makes a huge difference. Here's a side by side comparison with two of our sites. Both are PHP sites hosted on the same server, same account type, by the same Australian host. Testing using webpagetest.org. On first load, one site takes around 9 seconds to fully load the other takes around 3 seconds.
http://joomstore.com.au/blog. Our blog site - the site you are reading now. This site suffers from much of what I've described above. It's a fairly standard blog site but requires over 70 assets
http://bytebank.com.au. Our hosting/domains sales site. It's a simple content based site that also acts as a container to provide the console functionality.
The major difference between the two sites is the number of requests made. These are the calls for all the assets - Javascript, CSS and images - outlined above. Joomstore, 76 requests. Bytebank, 14 requests.
All the extra functionality added to the blog site has added 253% to the loading time. These comparisons have been carried out on finished sites but not with the optimisations outlined in this article. Keep reading through to part 2 to see the difference.
In many cases, removing functionality isn't an option. Especially, if it means limiting necessary interaction or reducing the quality of the user experience. There are other steps we can take.
Set up compression and caching
This can be a complicated subject. As a software developer I spend my day writing PHP and Javascript. Managing server environments goes a little outside my professional realm so I don't confess to be an absolute expert in this field. However, here is a quick run down.
Compression
This is where the output from your website is compressed before being sent across the internet. The users web browser will decompress the files before displaying your site. This ultimtately means faster loading times due to less data to transmit. The server may take a slightly longer time to respond but the reduction in download speed more than makes up for it. Read more about Gzip compression on Wikipedea.
Caching
There's two sides to this. Caching at the server level and caching by the browser.
In Joomla, you can activate caching in the System tab of your Global Configuration. The Caching options are Conservative and Progressive. I've always had better results using Conservative caching and this is the setting I recommend. Progressive caching tends to be too aggressive. It often serves cached versions of modules which should be dynamic. It can mess with comments modules, menus and the like. Please test it on your site before settling on one or the other.
Using Joomla's cache means that the CMS doesn't have to go through it's complete processing cycle to determine what to display. It matches the URL to what is cached and outputs the cached version. Quick and easy.
The down side of caching is any changes you make to your site aren't immediately visible. I've had a few frustrated emails asking why changes to articles aren't reflected on the front end. It's due to caching. To overcome this, I highly recommend the Cache Cleaner plugin from NoNumber.nl. It adds a small button to the status bar of your Joomla admin area which allows you to clear the Joomla cache from anywhere in your admin. There's a free version and a commercial version with extra features.
Most web browsers will cache your assets automatically but there are ways to tell browsers what to cache and how long for. We do this by setting "expires" headers.
Following is code that I use in most Joomla builds. What this code does is enable GZip compression and sets expires headers. It asks browsers to cache most of your files for one week. Some files, like XML, it sets the cache time to zero. That way Google can always get an up to date sitemap and feed readers aren't getting cached versions. This code has evolved over serveral years and may not be optimal for your server configuration but I find it works pretty well for our sites on a LAMP server.
# The following enables GZip and Expires headers.
<FilesMatch "\.(ico|pdf|flv|jpg|jpeg|png|gif|swf|mp3|mp4|html|css|js|woff)$">
Header set Cache-Control "public"
Header set Cache-Control "max-age=604800"
</FilesMatch>
<ifmodule mod_expires.c="">
ExpiresActive on
# Perhaps better to whitelist expires rules? Perhaps.
ExpiresDefault "access plus 1 week"
# cache.appcache needs re-requests
# in FF 3.6 (thx Remy ~Introducing HTML5)
ExpiresByType text/cache-manifest "access plus 0 seconds"
# Data
ExpiresByType text/xml "access plus 0 seconds"
ExpiresByType application/xml "access plus 0 seconds"
ExpiresByType application/json "access plus 0 seconds"
# RSS feed
ExpiresByType application/rss+xml "access plus 1 hour"
# Favicon (cannot be renamed)
ExpiresByType image/x-icon "access plus 1 week"
# Media: images, video, audio
ExpiresByType image/gif "access plus 1 week"
ExpiresByType image/png "access plus 1 week"
ExpiresByType image/jpg "access plus 1 week"
ExpiresByType image/jpeg "access plus 1 week"
ExpiresByType video/ogg "access plus 1 week"
ExpiresByType audio/ogg "access plus 1 week"
ExpiresByType video/mp4 "access plus 1 week"
ExpiresByType video/webm "access plus 1 week"
# HTC files (css3pie)
ExpiresByType text/x-component "access plus 1 week"
# Webfonts
ExpiresByType font/truetype "access plus 1 week"
ExpiresByType font/opentype "access plus 1 week"
ExpiresByType application/x-font-woff "access plus 1 week"
ExpiresByType image/svg+xml "access plus 1 week"
ExpiresByType application/vnd.ms-fontobject "access plus 1 week"
# CSS and JavaScript
ExpiresByType text/css "access plus 1 year"
ExpiresByType application/j-avascript "access plus 1 year"
ExpiresByType text/j-avascript "access plus 1 year"
<ifmodule mod_headers.c="">
Header append Cache-Control "public"
</ifmodule>
</ifmodule>
<IfModule mod_gzip.c>
mod_gzip_on Yes
mod_gzip_dechunk Yes
mod_gzip_item_include file \.(html?|txt|css|js|php|pl)$
mod_gzip_item_include handler ^cgi-script$
mod_gzip_item_include mime ^text/.*
mod_gzip_item_include mime ^application/x-javascript.*
mod_gzip_item_exclude mime ^image/.*
mod_gzip_item_exclude rspheader ^Content-Encoding:.*gzip.*
</IfModule>
Simply add this code to the end of your .htaccess file in your site root. Paste it just after all the Joomla code.
If this code generates a 500 Internal Server error you'll need to discuss with your host what options are supported.
Part two of this article will be published on Monday 15th April, 2013. Subscribe to our newsletter or Twitter feed to be the first to know.
Check out part 2 of this article.
EDIT. 15 April 2013: The code above works for most of the Joomla installations we handle. However, if GZip still isn't being applied to your files try replacing the last part of the code which relates to GZip with the following.
# compress text, html, javascript, css, xml:
AddOutputFilterByType DEFLATE text/plain
AddOutputFilterByType DEFLATE text/html
AddOutputFilterByType DEFLATE text/xml
AddOutputFilterByType DEFLATE text/css
AddOutputFilterByType DEFLATE application/xml
AddOutputFilterByType DEFLATE application/xhtml+xml
AddOutputFilterByType DEFLATE application/rss+xml
AddOutputFilterByType DEFLATE application/j-avascript
AddOutputFilterByType DEFLATE application/x-javascript
# Or, compress certain file types by extension:
<files *.html>
SetOutputFilter DEFLATE
</files>
Use Google Page Speed to analyse your site.