Overview
When using Static Caching or the cache tag, the rendered contents will be remembered for the next request. That's great for performance, but if you have something in there that you'd like to keep dynamic (such as authenticated user data, randomized elements, or listings), you'd normally have to disable static caching for the whole page.
With the nocache
tag, you can keep the entirety of the page cached (when using Static Caching) or chunks of the page cached (when using the cache tag), with specific parts remaining dynamic:
{{ nav }} ... {{ /nav }} {{ nocache }} {{ if logged_in }} Welcome back, {{ current_user:name }} {{ else }} Hello, Guest! {{ /if }}{{ /nocache }} {{ content }}
<statamic:nav> ... </statamic:nav> <statamic:nocache> @if ($logged_in) Welcome back, {{ $current_user->name }} @else Hello, guest! @endif</statamic:nocache> {!! $content !!}
Forms
Before the nocache
tag existed, a common reason to exclude a page from static caching would be if there was a form on there.
Forms contain a CSRF token for security, which is unique to each user visiting. If you submit the form using someone elses token (which could happen when static caching is enabled) the form won't work.
CSRF tokens are now updated automatically.
However, if your form has logic in it, like validation or success messages, you'll need to keep the form:create
dynamic by wrapping in nocache
tags.
{{ nocache }} {{ form:create }} ... {{ /form:create }}{{ /nocache }}
<statamic:nocache> <statamic:form:create> ... </statamic:form:create></statamic:nocache>
Blade
You can use the "no cache" feature in Blade too, although you should use the dedicated Blade directive or the Statamic Elements tag instead of trying to use Statamic::tag
.
To keep a part of your template dynamic, move it into a partial then use the @nocache
directive just like you would use the @include
directive.
@include('mypartial') {{-- this will be cached --}}@nocache('mypartial') {{-- this will be dynamic --}}
If you'd like to make a section of the current template dynamic without extracting a dedicated partial, you may use the <statamic:nocache>
tag:
<statamic:nocache> ...</statamic:nocache>
Caveats
Most of the time you can probably get away with wrapping something in a nocache
tag and it will just work! However there are some situations where you will need to be more aware of how the tag works in order to get predictable results.
When to wrap
For example, let's say you have a collection of stocks. Each entry contains information about the stock, except for the price. You have a custom tag that will get the up-to-the-second stock price using an API.
{{ collection:stocks }} <li> {{ company }} {{ symbol }} {{ get_price :of="symbol" }} </li>{{ /collection:stocks }}
<statamic:collection:stocks> <li> {{ $company }} {{ $symbol }} <statamic:get_price :of="$symbol" /> </li></statamic:collection:stocks>
If you turned on static caching now, then the whole listing would be cached, including the prices.
In this example, you should put a nocache
inside the loop.
{{ collection:stocks }} <li> {{ company }} {{ symbol }} {{ nocache }} {{ get_price :of="symbol" }} {{ /nocache }} </li>{{ /collection:stocks }}
<statamic:collection:stocks> <li> {{ $company }} {{ $symbol }} <statamic:nocache> <statamic:get_price :of="$symbol" /> </statamic:nocache> </li></statamic:collection:stocks>
By putting it inside the loop, it means that the collection:stocks
tag wouldn't need to re-query for entries on each subsequent request.
You'd then also rely on static caching invalidation rules to invalidate the entire page when one of your stock entries change.
An example where you would want to put a nocache
tag around a loop would be when re-querying every request would be important. For example, a randomized section:
{{ nocache }} {{ collection:blog featured:is="true" sort="random" }} ... {{ /collection:blog }}{{ /nocache }}
<statamic:nocache> <statamic:collection:blog featured:is="true" sort="random" > ... </statamic:collection:blog></statamic:nocache>
Context
The nocache
tag will remember the "context", which are the variables available at that point in the template.
Here we'll use a loop to illustrate what happens:
title: Movie Reviewsreviews: - name: Top Gun rating: 58% - name: Citizen Kane rating: 99% - name: Jack and Jill rating: 3%
{{ reviews }} <div class="movie"> {{ nocache }} {{ name }} {{ rating }} {{ title }} {{ /nocache }} </div>{{ /reviews }}
@foreach ($reviews as $review) <div class="movie"> <statamic:nocache> {{ $review->name }} {{ $review->rating}} {{ $review->title }} </statamic:nocache> </div>@endforeach
<div class="movie"> Top Gun 58% Movie Reviews </div><div class="movie"> Citizen Kane 99% Movie Reviews </div><div class="movie"> Jack and Jill 3% Movie Reviews </div>
Within each of those nocache tags, you'd have access to the iteration specific variables:
-
name
,rating
(e.g.name
would beTop Gun
, thenCitizen Kane
, etc) - special loop variables (e.g.
first
,last
,count
) - any cascading variables (e.g. from outer tags, or top level page variables like
now
,page
, etc)
All of the top level variables will be filtered out and replaced with fresh versions on subsequent requests.
Now lets say you update title
to Ratings
and Top Gun's rating
to 60%
. The first line out of output will now look like this:
<div class="movie"> Top Gun 58% Ratings </div>
Only the title
's change would be reflected, since the reviews
value was remembered. If you wanted this to be dynamic, you should wrap the loop rather than putting it inside the loop, as explained in when to wrap.
{{ nocache }} {{ reviews }} <div class="movie"> {{ nocache }} {{ name }} {{ rating }} {{ title }} {{ /nocache }} </div> {{ /reviews }}{{ /nocache }}
<statamic:nocache> @foreach ($reviews as $review) <div class="movie"> <statamic:nocache> {{ $review->name }} {{ $review->rating }} {{ $review->title }} </statamic:nocache> </div> @endforeach</statamic:nocache>
<div class="movie"> Top Gun 60% Ratings </div>
Performance
Sometimes, you may notice the contents of the nocache
taking a while to load. This is often caused by Statamic hydrating all of the variables from the context.
To improve performance, you can explicitly select the variables you need:
{{ nocache select="this|that" }}
<statamic:nocache select="this|that"></statamic:nocache>
Alternatively, you can use the @auto
placeholder for Statamic to extract the variables from the template (this is similar to the @shallow
placeholder in the nav tag):
{{ nocache select="@auto" }}
<statamic:nocache select="@auto"> </statamic:nocache>
It's worth noting, the nocache
tag won't be able to extract variables used inside partials or PHP files like custom tags. You will need to explicitly define the variables you need in these cases.
You can also combine them to extract the variables from the template and add additional ones:
{{ nocache select="@auto|this|that" }}
<statamic:nocache select="@auto|this|that"> </statamic:nocache>
Full Measure Static Caching
When using the file
static cache driver (aka. "full measure") the pages will be stored as plain html
files on your server.
On any pages that use a nocache
tag, a small snippet of JavaScript will be injected just before the closing </body>
tag.
The nocache fragments will be retrieved from the server using an AJAX request. Because of this, there may be a slight delay before the fragments are replaced. This is similar to a "FOUC" or "flash of unstyled content". In this case, there will be empty <span>
tags until they are replaced by the real fragments.
You can optionally define the inner html of these span
tags, if you wanted to have a "loading" state, for example.
use Statamic\Facades\StaticCache; StaticCache::nocachePlaceholder('Loading...');// orStaticCache::nocachePlaceholder('<svg>...</svg>');
You may wish to run some additional Javascript code once the nocache fragments on the page have been replaced, to enable this a custom event is dispatched that you may register an event listener for.
document.addEventListener('statamic:nocache.replaced', (event) => { alert('nocache fragments have been replaced!');});
Database
Behind the scenes, the nocache
tag needs to store some data somewhere. This includes the contents of the template chunks, the available variables at that point of the template, which pages it's being used on, etc.
By default, these are stored in the cache. However, with increased traffic or site size, you may eventually run into resource usage issues. In this case, it's possible to store the nocache data in a database.
- Configure the database driver in
config/statamic/static_caching.php
:'nocache' => 'database' - Generate the migration:
php please nocache:migration
- Run the migration:
php artisan migrate
- Clear the static cache. Things may be out of sync if you have previously cached pages but the nocache regions don't exist in the DB yet.
php please static:clear