ExpressionEngine Stash tutorial - Level 2

Published and filed under ExpressionEngine

Filed under ExpressionEngine

This is the second in a series of articles on Stash for ExpressionEngine. Here we’ll delve a bit deeper and separate our concerns.

Recap

In the first part of this series, we introduced some Stash techniques into a typical ExpressionEngine templating approach.

At that previous level, our main template was doing three jobs:

  1. Data fetching
  2. Markup assembly
  3. Output display

These tasks were all mixed together. As your templates grow this mixing can cause your coding to become both convoluted and repetitive; at this level, we’ll impose a stricter separation of these three tasks in order to maintain simplicity and order.

Why bother?

There are several problems with the previous basic approach that we’ll be solving here:

  • Your layout markup was spread across two templates, requiring an extra embed tag and making updates to the layout markup inconvenient
  • Worse, your layout markup in those templates was incomplete - you have opening tags in one template and closing tags in another, which can get confusing when you reach a complex level of nested markup
  • In an example used in the basic approach (duplicated below) we built up a chunk of markup in the main template for output elsewhere in that same template. However, the markup for those list items can end up quite far away from its surrounding markup, which can get confusing as your templates grow, and also requires some deciphering when you revisit a template you made a year ago:

a ‘flawed’ example from the previous approach

{!-- ====================================
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}

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 Template”
At this level, we’ll be using a single template for your output display, which I’ll call your “layout template”.
Data-fetching
Typically your data-fetching will involve channel entries tags, but could use any other ExpressionEngine tags that get content from the database.
Markup-assembly
Once you have your content, you typically need to wrap it with various chunks of html markup. This is the markup-assembly stage
Display output
Once you have your content marked up with html, it’s ready to output to the browser. I’ll call this the display output stage.

Starting at the end…

Here’s a visual representation of the technique we’ll be using at this level. We’ll be using a single layout template to do the display output, while your main template will take care of the data-fetching and the markup assembly.

LAYOUT EMBED

This embed contains your complete layout, including opening and closing html and body tags, and is responsible for your display output

MAIN TEMPLATE

A single template to control:

  • data-fetching
  • markup-assembly

This template will not output anything to the browser.

The general idea

With this approach, the separation between the display output and everything else is total – your main template cannot output anything directly to the browser. However, in terms of the separation between the data-fetching and the markup-assembly, you can and should vary the degree of separation according to how complex your content requirements are.

Let me demonstrate — firstly we’ll use no separation between the data-fetching and the markup-assembly:

main template:

{exp:stash:set parse_tags="yes"}
    {exp:channel:entries channel="articles" limit="1"}
        {stash:title}{title}{/stash:title}
        {stash:content}
            <h1>{title}</h1>
            <article>{body}</article>
            <footer>{author}</footer>
        {/stash:content}
    {/exp:channel:entries}
{/exp:stash:set}
{embed="site/layout"}

layout template:

<html>
    <head>
        {exp:stash:title}
    </head>
    <body>
        {exp:stash:content}
    </body>
</html>

In our main template, there is no separation between the data-fetching and the markup-assembly – we have an h1 tag, an article tag and a footer tag, all smashed together into a single Stash variable called ‘content’.

This works really nicely for simple pages, and as you can see our layout template is now cleaner.

Let’s take this a step further and separate the markup-assembly from the data-fetching: our layout template will remain the same, while our main template would look something like this:

{!-- ====================================
FETCH THE DATA and STORE INTO A 'data' VARIABLE
========================================= --}

{exp:stash:set_list name="data" parse_tags="yes"}
    {exp:channel:entries channel="articles" limit="1"}
        {stash:the-title}{title}{/stash:the-title}
        {stash:the-body}{body}{/stash:the-body}
        {stash:the-author}{author}{/stash:the-author}
    {/exp:channel:entries}
{/exp:stash:set_list}

{!-- ====================================
ASSEMBLE THE MARKUP
========================================= --}

{exp:stash:get_list name="data"}
    {exp:stash:set}
        {stash:title}{the-title}{/stash:title}
        {stash:content}
            <h1>{the-title}</h1>
            <article>{the-body}</article>
            <footer>{the-author}</footer>
        {/stash:content}
    {/exp:stash:set}
{/exp:stash:get_list}

{embed="site/layout"}

Spend a few moments reflecting on the seemingly subtle difference between this template and its predecessor: here we’re separating out the markup-assembly and the data-fetching into two sections of the same template. The data-fetching section strives to be completely free from any markup – its sole purpose is to fetch data and save it into named variables. The markup-assembly section then becomes a simple matter of sticking together all your previously saved components into whatever order you like with whatever markup you like.

But why should we bother with this? After all, this template has twice the amount of code as its predecessor.

First things first — if, in your judgement, your content requirements for a particular template are not complex (and have little chance of growing in complexity in the future), then simply don’t use this technique – stop reading now and use the previous template instead. There really is no value in complicating your template code for only puritanical gains.

In particular, when you start encountering nested loops (such as those for categories, related entries and grid/matrix data), this approach itself starts to increase in complexity which may outweigh the benefit when used with simple content requirements.

However, if you’re dealing with complex content — for example, items that can be categorised, filtered and displayed in multiple ways, or content that is frequently growing or changing structure or is part of a larger content framework — the benefits of indulging in this level of separation will soon become evident. Here you can:

  • Gather data from multiple sources and easily combine them into a unified output [example]
  • Gain more precise control over the final display via an extra layer of filtering, grouping and ordering [example]
  • Easily cache the entire dataset to improve performance
  • Reuse the same data in different types of output – e.g., PDFs, XML feeds, JSON data
  • Reuse exactly the same markup patterns for multiple types of display [↓ example]

The final point about reusing the markup pattern is one we’ll explore in more detail in the advanced approach (coming soon). At this intermediate level, since we’re using a single template to do both the data-fetching and the markup assembly, we are limited in the extent to which we can reuse the markup pattern by the fact that ExpressionEngine’s template routing is tied directly to your URLs.

A more complex example

I mentioned that this approach should only be used where the complexity of the content requires it… So we’re going to need a real-life complex example!

I recently had the pleasure of building a template for web designer Alissa J. Robinson, who was designing an ecommerce site for a local specialist ‘board game café’ based in Oxford called Thirsty Meeples. They stock over 1500 board games which are available for sale online and/or available to play in the café. Additionally, the individual game designers and publishing companies are held in dedicated channels that can be searched upon, giving them the flexibility in future to take advantage of their data in countless ways, as well as offering them the opportunity to create extended services for their suppliers.

Before I introduce the template, let me make the following disclaimers…

  • I tend to have a personal preference of single large templates over lots of small templates, and it’s entirely probable that this puts me in a minority!
  • The template that follows could have been split into lots of smaller templates and snippets, but in my opinion this would have increased its complexity further.
  • In the interests of brevity and sanity I have removed the sections of the template that deal with single entry board game views, as for our current purposes we’ll just be focusing on the listings views. I have also simplified some of the markup.
  • The template makes use of several other third-party add-ons — notably Expresso Store, Playa, Switchee, PT Checkboxes, Low Search, Low Alphabet and Low Variables — but the core techniques are achieved with Stash

The template we’re going to be studying is the games/index template which you can see in action on the Thirsty Meeples games page. (I won’t attempt to embed it directly in this article, it’s a bit of a monster!).

This large template deals with 6 different kinds of board game listings:

  1. the main paginated list (/games)
  2. the list filtered by category (/games/cat/{category_url_title})
  3. the list filtered alphabetically (/games/alphalist/x)
  4. the list filtered by publisher (/games/publisher/{url_title})
  5. the list filtered by designer (/games/designer/{url_title})
  6. the list filtered down to search keywords (/games/search)

Take another look at the simple example above where we separated the data-fetching from the markup-assembly but kept both in the same template: we’re using exactly the same technique here – there’s just a lot more of it!

At the top there are 4 data-fetching sections that deal with the differences in those 6 different kinds of listings (1 & 2 are shared, as are 4 & 5), but notice that there is only 1 markup-assembly section, (from line 185 onwards). The most important part to notice is the Stash get_list tag pair between lines 248 and 290 where we are retrieving the previously stored data and looping through it to display all the games for each listing type with the same markup. Using native ExpressionEngine techniques it would have been extremely difficult (maybe impossible?) to avoid duplicating this markup 6 times for the different kinds of listings.

This template also makes use of Stash’s caching mechanisms by saving the retrieved datasets, contributing to huge gains in back end performance. Due to the fact that we’re using set_list and get_list, saving the entire named datasets is as trivial as adding save="yes" and replace="no" and scope="site" parameters — too easy!

Next Steps

So, you skipped to the end, eh? Shame on you.

No, seriously though, there’s a lot to digest here — especially if you usually fall more on the designer side of the designer/developer fence. You may have already spotted a drawback with this intermediate approach: here’s a clue — going back to our Thirsty Meeples example, each of our 6 types of listings are all contained inside the games/index template. So what? Isn’t that where they belong?

In the advanced approach (coming soon) we’ll take a look at what the drawback is, how to solve it… and whether it’s worth it.

Advanced Stash - Coming Soon

Comments

Adam

Adam

In the example where you separate the data fetching and the markup…if you wanted to return more than 1 entry, would it be as simple as increasing the limit? I am using that code, trying to gather and display all of my entries in a channel, and it is only outputting 1 entry. I have removed the limit, and experimented with different limit numbers. When I do that, it shows me the entry that represents that number. Otherwise, I’m using the same code you have. Thanks!

James

James

Hi Adam,

You have several options for outputting multiple entries.  See the docs on the append and append_list tags. In this particular example however (and since the set_list tag is on the outside of the channel:entries tag, it will automatically recognise the loop and create separate rows for each entry) I would simply move the get_list tag on line 17 to the inside of the {stash:content}...{/stash:content} variable and use a hardcoded title. This will loop over the ‘data’ variable saving into the ‘content’ variable.

Adam

Adam

That did the trick, James. Thanks! I’ve been using stash on my last few projects for templating, but I felt like I was guessing a bit while doing it. This tutorial has confirmed some things for me, and I’m feeling much better about my current project. Looking forward to the advanced lesson.

Chris

Chris

Brilliant contribution and much appreciated.  Can you please include Mustash in your level 3 or 4 tutorial.

Dave

Dave

Amazing tutorial.  Really looking forward to the next Chapter. smile

J Wurmitzer

J Wurmitzer

Can’t wait for the advanced stash tutorial - please let us know roughly when you will be able to share that with us!!

Jae Barclay

Jae Barclay

Hi James,

Thanks for the awesome tutorial. I’m definitely looking forward to the “Advanced” chapter.

In my experience using Stash, the times when I need to resort to using embedded templates are when I need/would like to re-use the same assembly markup code on multiple templates/sections.

In other words, in the gist example you’ve provided, let’s say I needed to output the same listing options (by categories, search, etc.) using a completely different channel. I’d then have to copy and paste the same markup assembly part of the code to another main template, which would require manual updates on two or more templates if design ever changed.

For example, if Thirsty Meeples added video games, and the 1000 new videos games they’ve acquired needed to be displayed in the same manner as the board games, wouldn’t it be a better trade-off to have the markup assembling part of the code as a separate/embedded template that’s shared by both the board game channels and the new video game channel?

So, is there another way to avoid embedded templates at all while sharing the same markup assembling code on two or more main templates? Perhaps it would it be a part of the advanced chapter?

Thanks so much!

Jon Thomas

Jon Thomas

Still planning on doing the advanced part of the series? I’m really curious to see how you’ll split these templates out.

Rick

Rick

Me too! Would love to see the advanced tutorial

James

James

It’s been in the works for a while, but never seem to get enough time to polish it off properly, sorry about the delay, hopefully won’t be much longer. I was fearing that the new native “template layouts” functionality introduced in 2.8 might make some of this obsolete, but actually in practice Stash is still far more powerful than template layouts, though the general idea behind them is similar to part-1 of this series.

Jon Thomas

Jon Thomas

I’m actually using a mixture of both. For layouts, I’m using native, but I’m still using Stash all over the place. If you get time to include advantages/disadvantages of both, that would be interesting to see. But, my code is definitely still around the quality of your second article, so I’m really looking forward to seeing how I can improve upon it from your third article. From directory structure, to partialing things out for re-use to Snippets vs. Stash embeds. Etc. I want to know all the things! wink

Von Bartels

Von Bartels

I’d love to see part 3 of this series. I’m especially interested in using stash in combination with native layouts as Jon Thomas suggests above.

What's on your mind?