-
Notifications
You must be signed in to change notification settings - Fork 20
Caching
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").
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.
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'.
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.
DO use addressable URIs
/products/shoes/mens/9
AVOID query strings (but if you must, don't cache these pages)
/products?cat=shoe&type=mens&size=9
AVOID absolute URLs in templates (unless you are sure your site will only be accessed via a single canonical domain)
http://shoes.com/assets/scripts/myscript.js
https://shoes.com/assets/scripts/myscript.js
https://shoes.co.uk/assets/scripts/myscript.js
AVOID random entries (but if you must, don't cache these pages)
{exp:channel:entries orderby="random"}
DON'T cache page 2+ of paginated lists
/products/shoes/mens/9/P30
DON'T cache 404s or invalid URIs
/404
/products/shoes/mens/9/unexpected-extra-segment
/products/shoes/mens/hey-i-should-be-a-number
{!-- 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();
},
{!-- simply add to the bottom of the template --}
{exp:stash:static logged_out_only="yes"}
{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}
{!-- 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}
{if no_results}
{redirect="404"}
{/if}
{/exp:channel:entries}
{!-- this will be escaped --}
{stash:nocache}
Hi, {screen_name}
{/stash:nocache}
{!-- save a list of 5 latest jobs for an hour --}
{exp:stash:set_list
name="jobs"
parse="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}
{!-- save a html fragment for an hour, and output --}
{exp:stash:set
name="my_job"
parse="yes"
save="yes"
scope="site"
refresh="60"
replace="no"
output="yes"
}
{exp:channel:entries channel="jobs" limit="1"}
{title}
{/exp:channel:entries}
{/exp:stash:set}
Getting started
Using Stash
Using Mustash
- Mustash
- Installing Mustash
- Managing variables
- Managing bundles
- Cache-breaking rules
- Mustash plugins
- Mustash Varnish plugin
- Mustash plugin development
- Mustash API
Template design patterns
Tag reference
- {exp:stash:set}
- {exp:stash:get}
- {exp:stash:block}
- {exp:stash:set_value}
- {exp:stash:append}
- {exp:stash:append_value}
- {exp:stash:prepend}
- {exp:stash:prepend_value}
- {exp:stash:copy}
- {exp:stash:context}
- {exp:stash:is_empty}
- {exp:stash:not_empty}
- {exp:stash:set_list}
- {exp:stash:get_list}
- {exp:stash:append_list}
- {exp:stash:prepend_list}
- {exp:stash:split_list}
- {exp:stash:join_lists}
- {exp:stash:list_count}
- {exp:stash:unset}
- {exp:stash:flush_cache}
- {exp:stash:bundle}
- {stash:embed}
- {exp:stash:extend}
- {exp:stash:parse}
- {exp:stash:cache}
- {exp:stash:static}
- {exp:stash:finish}
- {exp:stash:not_found}
- Short tag syntax
- Using Stash methods in your own add-ons