ExpressionEngine Stash tutorial - Level 1

Published and filed under ExpressionEngine

Filed under ExpressionEngine

This tutorial suggests how to take your first steps with Mark Croxton’s Stash module for ExpressionEngine. It assumes you have a working knowledge of ExpressionEngine templating. If you want to make serious improvements to your templating, try my suggestions for intermediate or advanced (coming soon) setups. If you haven’t already, be sure to read the overview.

Terminology

Throughout this article I’ll make references to:

“Main Template”
This is the template which is called up by the URL or via the native Pages module (see how ExpressionEngine routes your urls to templates). There will only ever be one.
“Layout Templates”
At this level, these are your embedded head and foot templates. At the intermediate level we’ll condense these down into a single layout template, and at the advanced level (coming soon) we’ll use multiple layout fragments.

Starting at the end…

Here’s a visual representation of what we’ll be creating at this level. It’s deliberately very similar to how you may have arranged your ExpressionEngine templates without Stash, using what I call the ‘dynamic sandwich’ approach – where you have embed tags at the top and bottom of your template and output dynamic content directly in the middle like this:

Classic Dynamic Sandwich

HEAD EMBED

Simple embed with opening html tags and placeholder variables. No ExpressionEngine tags. No complex logic.

MAIN TEMPLATE

A single template to control:

  • data fetching
  • markup assembly
  • output to browser
FOOT EMBED

Simple embed with closing html tags and placeholder variables. No ExpressionEngine tags. No complex logic.

{embed="site/head"}
{exp:channel:entries...}
    <h1>{title}</h1>
    <article>{body}</article>
{/exp:channel:entries}
{embed="site/foot"}

Your main template here is doing three jobs, each of which are mixed together:

  1. Data fetching – i.e., {title} and {body} ExpressionEngine variables
  2. Markup assembly – i.e., h1 and article html tags
  3. Output display – i.e., spitting out the final result to the browser

On simple sites, there’s really nothing wrong with mixing each of these three jobs together; indeed it’s one of ExpressionEngine’s most attractive features for non-technical users that it allows this to happen. At this level we’ll keep those three jobs mixed together but still make use of Stash to clean up our layout templates.

At the more advanced levels we’ll get increasingly stricter about separating those jobs in order to give ourselves more flexibility.

Why Bother?

At this level the main reason you should use Stash is simplification.

It’s common to hear Stash touted as a way of improving template performance. Whilst this is certainly true, at this level it shouldn’t be your focus – performance gains here are a side-effect of the simplification of your templates (and in many cases, ExpressionEngine’s built-in tag-caching will negate the otherwise punitive effects of calling a channel entries tag multiple times in a single template).

Forget anything complicated you’ve read about “MVC” or “MVVM” or MV-whatever… this is actually very simple – at this level we’re aiming for three things:

  • Improving template maintainability and readability by fetching data from the database only once and reducing the amount of repeated code
  • Simplifying templates by moving complex and segment-based logic out of your layout templates in favour of simple flags and placeholders – Your main template will be the one doing any heavy lifting.
  • Making all templates adhere to a consistent and repeatable architecture

Practical uses without changing your core approach

Here we’ll use Stash to:

Setting page titles and meta data

There are approximately 300 ways to do this in ExpressionEngine, but even putting aside the performance concerns, the native ways are flawed, inelegant and just plain ugly – Maybe in the past you’ve tried one or all of these:

  • embed variables to pass static data or snippets from the main template to the header template?
  • putting your embedded head template on the inside of a channel entries tag in order to pass dynamic data through embed variables?
  • putting extra channel entries tags or snippets on the inside of your quoted embed variables?!!
  • some kind of third-party “SEO” add-on in your head template to fetch the right data?
  • huge conditional statements in your head template to account for all possibilities, combined with further channel entries tags to fetch the data?
  • using channel entries tags in your head template and relying on their default dynamic property to find the right entry data?

These were dark days.

Using Stash techniques to do this, we’ll keep the data-fetching where it’s supposed to be – with the rest of the content in the main template – while ensuring that our layout templates remain clean and simple. We’ll also avoid the unpleasantness of putting an embed inside a channel entries tag (don’t forget that the channel entries tag is a loop. It may be all fine while you’ve got limit="1" in there, but as soon as you start building listings, an embed inside a loop will see your load time exponentially increase, and in any case, it’s not a repeatable architecture and is just not good form – it would be easy to accidentally create serious scalability problems for yourself without really noticing it at first).

Here’s one of many ways you can do it in Stash:

main template:

{embed="site/head"}
{exp:stash:set name="extra-head-data"}
    <link href="special-css-just-for-this-view.css">
{/exp:stash:set}

{exp:stash:set name="extra-foot-data"}
    <script src="special-javascript-for-single-product-views.js"></script>
{/exp:stash:set}

{exp:channel:entries limit="1" channel="products"}
    {exp:stash:set}
        {stash:title}{title}{/stash:title}
        {stash:meta-desc}{summary}{/stash:meta-desc}
    {/exp:stash:set}
    <h1>{title}</h1>
    {body}
{/exp:channel:entries}
{embed="site/foot"}

Alternatively, if you’re already using some kind of plugin for chopping up strings of text (there are lots of them) you could make this a bit more sophisticated by not requiring an editor to enter a separate summary field, and instead take the first 20 words of the body copy if there’s no summary. Here we’ll make use of a Stash utility that strips out html (you can’t have any html tags inside your meta tags):

{embed="site/head"}
{exp:stash:set name="extra-head-data"}
    <link href="special-css-just-for-this-view.css">
{/exp:stash:set}

{exp:stash:set name="extra-foot-data"}
    <script src="special-javascript-for-single-product-views.js"></script>
{/exp:stash:set}

{exp:channel:entries limit="1" channel="products"}
    {exp:stash:set parse_conditionals="yes"}
        {stash:title}{title}{/stash:title}
        {stash:meta-desc}
            {if summary}
                {summary}
            {if:else}
                {exp:eehive_hacksaw words="20"}{body}{/exp:eehive_hacksaw}
            {/if}
        {/stash:meta-desc}
    {/exp:stash:set}
    <h1>{title}</h1>
    {body}
{/exp:channel:entries}
{embed="site/foot"}

site/head template:

    <html>
    <head>
        {exp:stash:title}
        <meta name="description" content="{exp:stash:get name='meta-desc' strip_tags='yes' trim='yes'}">
        {exp:stash:extra-head-data}
    </head>
    <body>

site/foot template:

        {exp:stash:extra-foot-data}
    </body>
    </html>

As you can see, our main template is still outputting its content directly (the h1 and {body} tags), just like you’ve always done. But for the title, meta data, and extra CSS and JavaScript, we’re using Stash to set variables which are later retrieved in the layout templates.

This is cleaner because:

  • All your data-fetching stuff is now in one place, and executed once;
  • You have no awkward embed variables;
  • Your embeds are sitting safely outside your loops;
  • Your layout templates no longer have to access the database and become more readable;
  • You have a repeatable architecture regardless of whether you’re outputting lists of entries or single ones.

As your templates grow in complexity it also gives you room to manipulate your content without polluting the simplicity of your layout templates or repeatedly re-fetching the same data.

Now let’s build on this technique to incorporate some dynamic switches into our layout templates:

Creating dynamic switches

Your layout templates (site/head and site/foot) will likely need to deal with several different kinds of layouts. Again, there are lots of different ways of dealing with this successfully. In some cases if the changes are substantial you may even prefer to use a completely different pair of templates combined with shared snippets for things like doctype and standard stylesheets instead of this approach… Personally I almost always prefer sticking with just one dynamic layout unless I’m building a micro-site.

Stash can help with this in countless ways, but here’s a couple of techniques I use often:

  1. ↓ Setting flags in your main template to trigger different behaviours in your layout templates
  2. ↓ Triggering different behaviours in your layout templates based on pre-existing Stash variables and setting a class name on your body or html tag to delegate layout changes to CSS

Remember, the idea here is to keep your layout templates as simple as possible, so avoid putting lots of complicated logic inside them.

1. Setting flags

In this example, we’ll enable an author to create per-entry semi-private articles that are excluded from Google’s search listings with a standard meta no-index tag.

In our main template we could just add the meta no-index tag to our ‘extra-head-data’ variable. Alternatively we could hardcode some conditional statements into the layout template. But in this case it would be better to keep the ‘implementation’ details (the nitty-gritty of exactly what should happen) in the layout template, by creating a simple flag in the main template to trigger the desired behaviours in the layout template.

It’s better this way because it gives us the flexibility to define what other things should happen to any private entries across multiple channels and templates – Maybe we want them all to have a bright red border and a giant padlock graphic, or maybe when you build version 5 of the site two years from now you’ll want to implement a special set of extra analytics tracking or add extra security by requiring the viewer to be logged in, or validate the visitor against an IP address range etc etc.

Using a simple flag in the main template allows us to keep all those implementation details in one place: imagine if you wanted to use this particular functionality on 5 channels and their associated templates – say, Subscriber-only Articles, Private Sales Reports, Non-public Intranet Articles etc. Delegating all the implementation details to the layout template ensures that you don’t need to edit those 5 main templates to make functional changes. Futhermore, using a flag instead of, say, hardcoding segment conditionals in your layout templates, means you don’t have to maintain a list of those 5 channels and repeatedly call it up in lots of places in your layout.

main template:

{embed="site/head"}
{exp:channel:entries limit="1" channel="proposals" disable="categories|pagination|member_data"}
    {exp:stash:set parse_conditionals="yes"}
        {if {proposals_options:selected option='private'}}{stash:private}true{/stash:private}{/if}
        {stash:title}{title}{/stash:title}
        {stash:meta-desc}{summary}{/stash:meta-desc}
    {/exp:stash:set}
    <h1>{title}</h1>
    {body}
{/exp:channel:entries}
{embed="site/foot"}

site/head template:

    <html>
    <head>
        {exp:stash:title}
        <meta name="description" content="{exp:stash:meta-desc}">
        {if '{exp:stash:private}'}{/if}
    </head>
    <body>

(NB: this example also makes use of the P&T checkbox group fieldtype from their popular Field Pack add-on, though you could do the same with the native checkbox fieldtype in a more awkward way.)

2. Switching based on pre-existing variables

In this example, we’ll assess an existing Stash variable to toggle a sidebar on and off in the layout template.

This is similar to the flag approach above, but here we’re using an existing custom field – {sidebar_content} – to make layout decisions rather than creating new Stash variables:

{embed="site/head"}
{exp:channel:entries limit="1" channel="proposals" disable="categories|pagination|member_data"}
    {exp:stash:set parse_conditionals="yes"}
        {stash:sidebar-content}{sidebar_content}{/stash:sidebar-content}
        {stash:page-class}{if sidebar_content}withSidebar{if:else}fullWidth{/if}{/stash:page-class}
        {stash:title}{title}{/stash:title}
        {stash:meta-desc}{summary}{/stash:meta-desc}
    {/exp:stash:set}
    <h1>{title}</h1>
    {body}
{/exp:channel:entries}
{embed="site/foot"}

site/head template:

    <html>
    <head>
        {exp:stash:title}
        <meta name="description" content="{exp:stash:meta-desc}">
        {if '{exp:stash:private}'}{/if}
    </head>
    <body class="{exp:stash:page-class}">
        {if '{exp:stash:not_empty name="sidebar-content"}'}<aside>{exp:stash:sidebar-content}</aside>{/if}

Build up chunks of content

Wayyy back in the day Microsoft Word had (has?) a little-known feature called the “Spike”, which acted like a litter-picking spike, such that you could go through your document highlighting chunks of text, pressing a key combination to add them to the spike, then later on you could dump the spike’s contents elsewhere in the order in which you added them – like a more advanced version of the clipboard.

This concept has been a staple of procedural programming and most forms of web content data output, but in ExpressionEngine it’s impossible since your data is fetched and output in the same breath.

Simple Example

Using native ExpressionEngine techniques, you may have used tricks like the one below to give you a little more control inside your loops while ensuring you don’t output empty tags if no content exists:

{exp:channel:entries limit="20" channel="events" ...}
    {if no_results}
        There are no events
    {if:else}
        {if count == 1}
            <h3>Upcoming events</h3>
            <div>
            <ul>
        {/if}
            <li>
                <a href="{url_title_path=events}">
                    <h3>{title}</h3>
                    <p>{summary}</p>
                </a>
            </li>
        {if count == total_results}
            </ul>
            </div>
        {/if}
    {/if}
{/exp:channel:entries}

Whilst there’s nothing particularly wrong with that, it illustrates how limited you are in what you can achieve when your data-output is coupled to your data-fetching, and it’s quite ugly to read with the nested conditionals. When the content requirements grow, you’ll quickly hit the ceiling of what can be done with that kind of approach.

With Stash we can break apart the data-fetching and the data-output, allowing us to gradually build up a buffer of content from multiple sources without the overhead or inelegance of fetching the data from the database over and over again whenever we need it or relying on clumsy loop counters and conditionals.

This is how that same example might look using Stash:

{!-- ====================================
STORE THE LIST ITEMS
========================================= --}

{exp:stash:set parse_tags="yes" name="event-list"}
    {exp:channel:entries limit="20" channel="events" ...}
        <li>
             <a href="{url_title_path=events}">
                 <h3>{title}</h3>
                 <p>{summary}</p>
             </a>
        </li>
    {/exp:channel:entries}
{/exp:stash:set}

{!-- ====================================
START OUTPUT
========================================= --}

{if {exp:stash:not_empty name="event-list"}}
    <h3>Upcoming events</h3>
    <div>
        <ul>   
            {exp:stash:get name="event-list"}
        </ul>
    </div>
{if:else}
    There are no events
{/if}

As you can see, our output section is now much cleaner and simpler. In the intermediate level of this series, we’ll take this idea a step further to keep things even cleaner.

A more complex example

Now let’s say we have an “events” channel which contains events that are free to attend and others which require an attendance fee. We’d like to output them all on to a single page, but have the free events grouped and styled differently from the paid events. For the purposes of this example let’s also assume that we’ll be using ExpressionEngine’s native categories system to differentiate between the two.

First let’s consider the various ways you could handle this situation natively without Stash:

  1. Use two sets of channel entries tags, using the category parameter to output different data
  2. Use a single native category_archive tag with a nested channel entries tag to fetch any custom fields

First of all, what’s wrong with these native approaches?

Using two sets of channel entries is like driving to the supermarket in the morning to buy some bread, then coming home to put it in the toaster before going out to the same supermarket again to buy some jam for your breakfast toast. By the time you’re back it’ll be time for lunch already and your toast will be cold.

It’s not a huge inefficiency and your server is not going to fall over and explode because of it, but imagine if we had a dozen categories instead of just two (say, for seminar subjects) and wanted to achieve a similar goal. If you duplicate that logic 12 times you really will feel the difference in performance, and you’ll also need to maintain 12 sets of markup that are basically the same as each other.

A snippet and/or extra embed may ease the pain a little, but you’ll still end up with 12 blocks of code that need to be edited whenever things change, and then you’ve also got yet another abstraction to manage (exacerbated by the fact that the current version of ExpressionEngine doesn’t natively support snippets as files!).

Now let’s say you need to display future events and past events from each category in different places on the page, styled differently. Without the approaches afforded by Stash this would require multiple round-trips to the database and/or some convoluted conditional logic and embedded templates.

Even putting aside inefficiency and duplication of maintenance effort, it’s just not an elegant way of working and only becomes worse as your content requirements grow.

Using a channel entries tag nested inside a category_archive tag might seem like a better solution as it involves less code and easier maintenance, but under the covers this will be hugely inefficient. You should go to great lengths to avoid nesting loops in ExpressionEngine – especially loops which make database calls. It will not scale at all well. Every new event and category your client adds will exponentially increase the loading time in this scenario. If you’re lucky, your editors will call you to complain about the 8-second load times before you hit your php memory limit!

Let’s take a look at how we might do this with Stash:

{!--  ============================================
FETCH THE DATA and ASSEMBLE SOME MARKUP AROUND IT
================================================== --}

{exp:channel:entries channel="events" dynamic="no"}
    {categories}
        {exp:stash:append name="events-{category_url_title}"}
            <li><a href="{url_title_path=events}">{title}</a></li>
        {/exp:stash:append}
    {/categories}
{/exp:channel:entries}

{!--  ============================================
OUTPUT THE DATA. Stash:parse is needed to side-step
EE parse-order issues here.
================================================== --}

{exp:stash:parse}
    {if {exp:stash:not_empty name="events-free"}}
        <h3>Our free events</h3>
        <ul>
            {exp:stash:get name="events-free"}
        </ul>
    {/if}
    
    {if {exp:stash:not_empty name="events-paid"}}
        <h3>Our special events</h3>
        <ul>
            {exp:stash:get name="events-paid"}
        </ul>
    {/if}
{/exp:stash:parse}

A note on parse order

I mentioned in the overview section that it won’t be long before you encounter issues with parse order when doing anything more than trivial in ExpressionEngine, and this is especially true when using Stash.

If you’re using the intermediate or advanced approaches outlined in this series, parse order issues are largely avoided – but when you’re using a single template to do both the setting and getting of variables, you can run into difficulty.

I don’t think I’ll ever truly understand the details of ExpressionEngine’s parse order, (and frankly I don’t believe anyone should bother trying)… but I do have some workarounds that can help when using Stash – in order of preference:

  1. Do your getting and setting in different templates (see the intermediate approach)
  2. Promote your Stash tags to “first-class citizens” in the hierarchy… By which I mean, aim to have your set and get tags at the same hierarchical level of the template. If they’re both at the same level of nesting, the parse order is simplified and you can get variables after you’ve set them just as you’d expect. If your set tags are nested inside a channel entries tag, you won’t be able to output the variables later in the template unless your get tag is also nested in another tag. (Using set_list and get_list on the outside of channel entries tags instead of set and get can help here, but that’s outside the scope of this level).
  3. Use Stash embeds and their process and priority parameters (again, overly complex for this level)
  4. Use the parse tag to manipulate the parse order (as I’m doing in the example above).
  5. Use native ExpressionEngine embeds and embed variables

Next Steps

Hopefully these basic changes should give you the confidence to start using these techniques without the need to recode an entire site. You may have already noticed a few areas here that can be improved upon: the intermediate level will impose a slightly stricter separation of the three concerns we touched on here (data fetching, markup assembly and display output).

Proceed to Part 2

Comments

Jon Thomas

Jon Thomas

Wow, this was just the introduction I was looking for. Your breakdown and explanation is so much better than anything else I’ve found. Thanks for taking the time to explain it this way!

-Jon

Jim

Jim

I full agree with Jon - this is the first tutorial that made any sense to me. Thank you! So looking forward to step 3…

One comment though - If a code snippet requires a third-party item, perhaps note it BEFORE the snippet. I will amend my reading style, but I charge into code before reading further; I probably spent a half-hour or more (erm, more…) on the first setting-flags example, trying to get the conditional to work. I presumed it was an internal Stash thing, and only after replacing it with a simple EE conditional, getting it to work, and then reading on did I realise it was a P&E checkbox….doh!

Jonathan Schofield

Jonathan Schofield

Coming to this 2 and a half years late, it is several shades of brilliant. Thanks so much. Onwards!

What's on your mind?