Updated on | #modx, #cache, #plugin | 0 User comments

Pagespeed - Speed Up Modx plugin or snippet by caching

Caching is probably the most important technique you should use in MODX projects. Of course, scaling your hardware is one of the best solution for load problems, but you have to take some money in your hand to buy hardware as well as to finance electrical power. I'm using a Server in my home environment with the objective to save electricity. Hence, I've bought the AMD E2-2000 Mini-ITX-Mainboard E2KM1I-DELUXE from ASUS, which has to do all the work. I don't want to scale my hardware, which is why I need another solution, called caching, for MODX.

There are many tutorials about caching plugins or snippets in MODX. A great caching guideline was written by Mark Hamstra, where the following points are my three golden rules:

  • Don't call the Wayfinder snippet uncached!
  • Cache the if snippet always when you are using static content
  • Only user-specific output needs to be uncached

That means, never add the exclamation mark (!) in front of the dollar sign ($) for Chunks, the plus sign (+) for placeholders, the percentage sign (%) for lexicons and an asterix (*) for resource fields and template variables if you are using none user-specific content.

Analyze performance with timing-tags

There are several timing tags in MODX Revolution:

TagNameDescription
[ ^qt^]Query TimeShows how long MODx took talking to the database
[ ^q^]Query CountShows how many database queries MODx made
[ ^p^]Parse TimeShows how long MODx took to parse the page
[ ^t^]Total TimeShows the total time taken to parse/ render the page
[ ^s^]Source Showsthe source of page, whether is database or cache

Insert the following line into your template (without whitespaces between [ and ^) <div>MODX stats: Database: [ ^qt^], [ ^q^] Queries, Application: [ ^p^], Total: [ ^t^], Source: [ ^s^]</div> and you will see this on your page: MODX stats: Database: 0.0011 s, 1 Queries, Application: 2.0825 s, Total: 2.0836 s, Source: cache. If you want to analyze the timings more in detail, Jason Coward discusses how to quickly check the execution time of a particular Snippet or Chunk.

I'm using the following plugins, that needs a lot of time:

  • Markdown to HTML: I'm writing all articles in Markdown, where I use Pandoc to translate it into HTML
  • Table of Contents: Convert the HTML header tags into a table of contents
  • Parse all HTML heater tags in order to create anchors

Especially Pandoc needs a lot of time. That's the reason why I started to code this Plugin template.

Caching plugin content in MODX

MODX uses different partitions for separate types of data being cached. A partition is a folder in the 'core/cache/' directory, where you can cache any type of data. The following code shows how to cache the resource content from a plugin.

Graph 1: LudwigSpeedUp Cache Statistics
  1. <?php
  2. define( 'PKG_NAME', "MyPackage" );
  3. define( 'PKG_NAME', strtolower(PKG_NAME) );
  4. define( 'PKG_PLUGIN_NAME', 'MyPluginName');
  5. define( 'PKG_PLUGIN_EVENT_FIRE', "OnWebPagePrerender");
  6.  
  7. // Using Modx Cache for 1h per URL
  8. $e = &$modx->Event;
  9. switch ($e->name)
  10. {
  11.     case PKG_PLUGIN_EVENT_FIRE:
  12.  
  13.         // Content
  14.         $output= $modx->resource->_output;
  15.  
  16.         // Variables
  17.         $id= $modx->resource->get('id');
  18.         $editedon= $modx->resource->get('editedon');
  19.  
  20.         // Parameters for Caching
  21.         $cache_expires= 3600*24*7*4;    // 1 Month in seconds
  22.         $cache= array(  "opt" => array( xPDO::OPT_CACHE_KEY => PKG_NAME,
  23.                                         xPDO::OPT_CACHE_EXPIRES => $cache_expires ),
  24.                         "name" => PKG_NAME_LOWER .'_'. PKG_PLUGIN_NAME .'_'. md5( $editedon .'_'. $id ) );
  25.         $cache_raw= $modx->cacheManager->get($cache["name"], $cache["opt"]);
  26.  
  27.         // Get Data from Cache
  28.         if (empty($cache_raw) || is_null($cache_raw) || ( $editedon != $cache_raw["editedon"] ) )
  29.         {
  30.             // INSERT YOUR FUNCTION HERE
  31.             /* Example
  32.  
  33.             // Generate Content from Function 1
  34.             $output= generate_function1( $output );
  35.  
  36.             // Generate Content from Function 2
  37.             $output= generate_function2( $output );
  38.  
  39.             */
  40.  
  41.             // Cache results
  42.             $cache_raw= array("editedon" => $editedon, "content" => $output);
  43.             $modx->cacheManager->set($cache["name"], $cache_raw, $cache_expires, $cache["opt"]);
  44.  
  45.         }
  46.  
  47.         $modx->resource->_output= $cache_raw["content"];
  48.         break;
  49. }
  50.  
  51. return('');

There are a couple of points to note in addition:

  • The output is cached for 1 month. If you want a different cache TTL, change the $cache_expires variable to the amount of seconds you would like to cache the output for.

Apache Rewrite Rule

I'm using the SEO Friendly URL option in MODX. To use this in LudwigSpeedUp you need to include the following lines into the MODX settings in Apache2:

  1. # LudwigSpeedUp (e.g. /assets/components/ludwigspeedup/services_MzSwMItPrSgpSgQA.css)
  2. RewriteCond %{REQUEST_FILENAME} !-f
  3. RewriteCond %{REQUEST_FILENAME} !-d
  4. RewriteRule ^(.*)/ludwigspeedup/services_(.*).(js|css)$ $1/ludwigspeedup/services.php?$3=$2 [L,QSA]

Summary

Caching plugins is a great option to speed up MODX. But it's only one option in the world of speed optimization. Guido Gallenkamp wrote about other lever arms like mod_expires module in Apache2, which helps you to manage the Expires HTTP header and max-age directive of Cache-Control HTTP header in server responses.

I'm working on a plugin, which helps to optimize timings in MODX. It's an alpha version, so please don't use it in an productive environment.

New Extra to optimize MODX

At first you have to clone the code from GitHub:

  1. cd /tmp
  2. git clone --recursive https://github.com/MoonMaker/modx.git
  3. cd modx/SpeedUp/_build/

Change your modx path in build.config.php:

  1. nano /tmp/modx/SpeedUp/_build/build.config.php
  1. define('MODX_BASE_PATH', '/var/www/modx/');

Now you are able to build the schema:

  1. php -f /tmp/modx/SpeedUp/_build/build.schema.php

The last step is to build the transport package and to change the package owner:

  1. sudo php -f /tmp/modx/SpeedUp/_build/build.transport.php
  2. chown -R www-data:www-data /var/www/modx/
  3. chown -R www-data:www-data /var/www/modx/*

The Add-on package will be generated in /var/www/modx/core/packages. You can use the ModX Package Manager to install it.

  • Turbocharge MODX: Sepia River shows some facts about alternative caching methods in MODX

Well, what do you think?

Comments powered by LudwigDisqus for ModX