Improving MODX Page Speed for Google Or any other CMS

Improving your website's page speed is important, but Google pushed the issue in July 2018 by officially making it a ranking factor.  How do you stack up?

Check your speed score

We beleive in knowing as much as possible about your site. If you haven't already, take a moment to check your website's Google Speed Score. There are many tools out there, but we feel checking using Google's tool is important if search visibility is important to you.

We were able to improve our page speed score considerably from 50s-60s to 90+.

Optimizing Images

Image optimization is one of the easiest things you can do to improve your page speed. It starts with making sure you're serving the right sized images. We've seen many cases where full sized images are being served. We always encourage uploading high quality images, but then make sure we scale down automatically for specific uses, like headings, cards, thumbnails, etc.

Here are the 3 main ways we optimize images for speed.

Lazy Load

Lazy loading is delaying image loading until after the page has fully loaded and / or when the user scrolls near the image. This is especially important for users with metered connections.

There are a number of lazy loading plugins that can be used.

  • jQuery.Lazy - Supports backgrounds as well traditional image tags


We use a tried and true php script called PHPThumb, the backbone of most CMS image resizing solutions.

Our MODX websites use this extensively with very granular control over size, format and quality.

  • PThumb - Great documentation and options

Next Gen Formats

Where and when possible use, Next Gen Image formats, these include JPEG2000 and the new webp formats.

While not explicitly in this list, we also encourage use for SVG for the web when possible as it's much smaller than PNG or JPEG images as well.

To get the best user experience, we'll combine lazy loading with automated image resizing. The idea is to automatically build a small thumbnail that represents the image to be displayed so there is not a hole in the content for the image. Then lazy load in the higher resolution and quality image on scroll to keep the experience fast.

Here is an example for our website here of how we use Lazy Loading with phpthumb based image resizing for cards. Notice the two distinct pthumb instances.

<a href="/[[~[[+id]]]]" 
class="item-img img-hover lazy" 
style="background-image: url([[+tv.core-resource-image:pthumb=`&h=50&w=70&zc=T`]])">

Static Resources Caching

.htaccess to the rescue!

Static resource caching tells the browser to not load files over and over again and use previously downloaded copies. This helps both the user and the web server as the transfer never needs to take place for subsequent page loads.

Many web servers use Apache and it uses a file called .htaccess to control how it reponds in many situations, think of it as a per-site configuration file.

Below is an except from our .htaccess file, you can find many other examples by searching for the term ".htaccess browser cache"

# ########################
# Leverage browser caching
# ########################

<IfModule mod_expires.c>
  ExpiresActive On
  ExpiresByType image/gif A2592000
  ExpiresByType image/jpeg A2592000
  ExpiresByType image/jpg A2592000
  ExpiresByType image/png A2592000
  ExpiresByType image/x-icon A2592000
  ExpiresByType text/css A86400
  ExpiresByType text/javascript A86400
  ExpiresByType application/x-shockwave-flash A2592000
 # <FilesMatch "\.(gif¦jpe?g¦png¦ico¦css¦js¦swf)$">
 # Header set Cache-Control "public"
 # </FilesMatch>

<FilesMatch "\.(ico|pdf|jpg|jpeg|svg|png|gif|html|htm|xml|txt|woff2|js|css|xsl)$">
Header set Cache-Control "max-age=31536050"

# ########################
# Enable compression
# ########################

<IfModule mod_deflate.c>
  AddOutputFilterByType DEFLATE application/javascript
  AddOutputFilterByType DEFLATE application/rss+xml
  AddOutputFilterByType DEFLATE application/
  AddOutputFilterByType DEFLATE application/x-font
  AddOutputFilterByType DEFLATE application/x-font-opentype
  AddOutputFilterByType DEFLATE application/x-font-otf
  AddOutputFilterByType DEFLATE application/x-font-truetype
  AddOutputFilterByType DEFLATE application/x-font-ttf
  AddOutputFilterByType DEFLATE application/x-javascript
  AddOutputFilterByType DEFLATE application/xhtml+xml
  AddOutputFilterByType DEFLATE application/xml
  AddOutputFilterByType DEFLATE font/opentype
  AddOutputFilterByType DEFLATE font/otf
  AddOutputFilterByType DEFLATE font/ttf
  AddOutputFilterByType DEFLATE image/svg+xml
  AddOutputFilterByType DEFLATE image/x-icon
  AddOutputFilterByType DEFLATE text/css
  AddOutputFilterByType DEFLATE text/html
  AddOutputFilterByType DEFLATE text/javascript
  AddOutputFilterByType DEFLATE text/plain
  AddType x-font/otf .otf
  AddType x-font/ttf .ttf
  AddType x-font/eot .eot
  AddType x-font/woff .woff
  AddType image/x-icon .ico

Combine and Minify

Faster together

Many websites that use 3rd party plugins will just keep adding and adding javascript and css resources to be loaded with little thought given to page speed. It's important to try and combine those files into one, and minify or compress them. This reduces the number of requests the web browser needs to make, improving page speed.

We use a MODX Extra called MinifyX for combining Javascript and CSS into separate files as well as compression. During site development we'll often turn this off so they are not constantly being combined, but once in production we use it.


In this example use the palceholders and respectivly for where to place those files in the markup

Content Delivry and Asynchronus Loading

It's all in the cloud

We try and use Content Delivery networks for things like:

  • Bootstrap CSS and JS
  • JQuery
  • Google Fonts
  • Font Awesome

For loading local stylesheets you can use the rel="preload" in the link tag keep it from blocking rendering. However not all browsers support this attribute.

<link rel="preload" href="">

A more clever method is loadCSS

The last bit we finally tracked down was asynchronously loading in the Google Font Loader with the help from Locked Down Design.

<!--- Old Slow Code-->
	<script async src=""></script>
    google: {
      families: ['Source+Sans+Pro:400,300,600,400italic,700', 'Roboto Condensed:400,700','Roboto+Slab']
<!--- Locked Down Fast Code-->
<script type="text/javascript">
  WebFontConfig = {
    google: { families: ['Source+Sans+Pro:400,300,600,400italic,700', 'Roboto Condensed:400,700','Roboto+Slab'] }
  (function() {
    var wf = document.createElement('script');
    wf.src = ('https:' == document.location.protocol ? 'https' : 'http') +
    wf.type = 'text/javascript';
    wf.async = 'true';
    var s = document.getElementsByTagName('script')[0];
    s.parentNode.insertBefore(wf, s);
  })(); </script>

Recent Posts

MODX Cloud NGINX Rule for ssl and www redirect

Replace "" with your domain. This example uses www as the end point, if you prefer non-www just change the two domain variations around in the first if statement. if ($host = "") { return 301 $scheme://$request_uri; } if…

PDF From Adobe Illustrator not showing a mask transparency right on macOS Preview or Windows? Here is the fix

So you sent a small preview PDF to the client, it looks great. Then you export the Press Quality version and it looks different, why? Let's dig in.

The Status of Liquid Web Cloud Sites Formerly of Rackspace in 2018

We've been a cloudsites customer since our inception, it's had ups and downs, here is what we think about it now.