Skip to content

Caching

Mark Croxton edited this page Dec 13, 2016 · 30 revisions

Do cache

Global fragments: rendered partials, such as navigational elements, footers, sidebars and other reusable, globally visible page elements (scope="site").

Addressable pages: the unique output of individual pages in your site, where the URI alone is sufficient to generate all possible interaction states ("URI addressability").

Don't cache

Non-global fragments: Partials that generate output that is specific to the URI or user.

Non-addressable pages: where the URI of a page alone is not sufficient to determine it's interaction state. E.g. forms that POST data, shopping carts, 404 pages.

Dynamic content: which is dependent on a user session, form action or search query. E.g. Search results, logged-in member data, contact forms.

Cache planning

Build for URI addressability: as far as possible plan your site so that all interaction states are represented by a unique URI.

Stay DRY: separate out commonly used global page fragments into snippets, Low Variables or Stash embeds. Cache structured data, not marked-up data, so you can re-use the data with different markups.

Group like items: use context and/or bundles to create groups of related cached items, so that they can be targetted for cache-breaking.

Use layers: use fragment-caching inside page-caching to allow for progressive cache rebuilds and avoid 'stampedes'.

Common pitfalls, and how to avoid them

Domain aliases - Cached domain-specific absolute URLs can lead to serious complications like broken AJAX requests due to cross-domain restrictions. Ideally you should only allow access to your website via a single known domain. If you can't be sure of this, try to eliminate links containing absolute URLs entirely from your templates.

Non-strict URLs - It's very important to ensure that your templates return a 404 if additional segments are added to the URL or an entry doesn't exist. URL variants can bloat your cache.

Before caching, validate the routes into your website:

{!-- no results --}
{if no_results}
   {redirect="404"}
{/if}

{!-- additional segments --}
{if segment_4}
   {redirect="404"}
{/if}

I highly recommend using Resource Router to define and validate known routes:

'blog/:url_title' => function($router, $wildcard) {
   // valid blog entry (channel 2)?
   if ($wildcard->isValidUrlTitle(array('channel_id' => 2))) {
      
      // route to template
      $router->setTemplate('blog/post');
   }
},

// any other rules here

// send any other non-matching routes to 404
'.*' => function($router) {
    $router->set404();
},

Page caching examples

Static caching

{!-- simply add to the bottom of the template --}
{exp:stash:static logged_out_only="yes"}

Database caching, escaping some regions so they remain dynamic

{!-- templates/default_site/blog/index.html --}
{exp:stash:cache unprefix="entry"}

	{stash:embed:layouts:standard}

	{!-- capture channel data for a single entry --}  
	{exp:channel:entries channel="blog" limit="1"}    

		{exp:stash:set}        
	    	{stash:pg_title}{title}{/stash:pg_title}       
	    	{stash:pg_intro}{cf_blog_intro}{/stash:pg_intro}        
	    	{stash:pg_body}{cf_blog_body}{/stash:pg_body}     
		{/exp:stash:set} 

		{if entry:no_results}
			{redirect="404"}
		{/if}

	{/exp:channel:entries}
	
	{!-- this will be escaped --}   
	{stash:nocache}     
	   Hi, {screen_name}   
	{/stash:nocache}

{/exp:stash:cache}

Or with {stash:embed}

  {!-- templates/default_site/blog/index.html --}
  {stash:embed  
     name="@URI:base"  
     file_name="viewmodels:base_vm"  
     parse_stage="both"
  }

  {!-- stash_templates/viewmodels/base_vm.html --}
  {stash:embed:layouts:standard}

  {!-- capture channel data for a single entry --}  
  {exp:channel:entries channel="blog" limit="1"}       
     {exp:stash:set}        
        {stash:pg_title}{title}{/stash:pg_title}       
        {stash:pg_intro}{cf_blog_intro}{/stash:pg_intro}        
        {stash:pg_body}{cf_blog_body}{/stash:pg_body}     
     {/exp:stash:set} 
  {/exp:channel:entries}
  
  {!-- this will be escaped --}   
  {stash:nocache}     
     Hi, {screen_name}   
  {/stash:nocache}

Fragment caching

  {!-- save a list of 5 latest jobs for an hour --}
  {exp:stash:set_list 	
     name="jobs"	
     parse_tags="yes"	
     save="yes"	
     scope="site"	
     refresh="60"	
     replace="no"}	
     {exp:channel:entries channel="jobs" limit="5"}			
        {stash:job_title}{title}{/stash:pg_title}			
        {stash:job_url}{url_title}{/stash:job_url}	
     {/exp:channel:entries}
  {/exp:stash:set_list}
Clone this wiki locally