More Stash examples

By John Faulds

As promised in the last post I'm going to delve a bit more into some Stash examples I've used on other ExpressionEngine projects.

Shortcodes with Stash

If you're unfamiliar with the term ‘shortcode’, it comes from Wordpress and gives an author the ability to drop a block of code into their WYSIWYG editor where they want it which is pretty useful if you want to have some paragraphs of text, a block of code that does something else like a gallery or form or list of related entries, and can then follow up with more content without needing to split things up into separate fields.

In Wordpress a shorcode would look like [name_of_shortcode] and you could place that anywhere in the body of your entry and it would be converted into whatever code was contained within the file (usually a plugin) that the shortcode was called from.

<p>Lorem ipsum dolor sit amet…</p>

[name_of_shortcode]

<p>Lorem ipsum dolor sit amet…</p>
	
An example of a post with ‘shortcode’

To do the same sort of thing with native ExpressionEngine functionality, you'd need separate fields: one for each block of text that would need to be separated by other code in the template. And in the template, you'd need to use either separate channel entries tags for each block or use embeds so that you could insert code from other channels in between the fields.

But with Stash, you can do pretty much the same thing as you would in Wordpress. Here's a couple of different examples.

Example 1

This example comes from the SpinePlus website which was redesigned earlier this year. The subheadings, paragraphs of text and the large single image at the bottom of the page come from a single entry in a Site Pages channel. The headshots of the visiting practitioners come from a Staff channel. Here's how it's done:

{exp:stash:set name="st_shortcode"}
<ul>
	{exp:channel:entries
		channel="staff"
	}
	<li>
		{exp:imgsizer:size src="{image}" width="150" alt=""}
		<h2>{title}</h2>
		<p>{position}</p>
	</li>
	{/exp:channel:entries}
</ul>
{/exp:stash:set}

{exp:stash:set name="st_content" parse_tags="yes"}

	{exp:channel:entries
		channel="site"
		url_title="{last_segment}"
	}
		{exp:allow_eecode}
			{body}
		{/exp:allow_eecode}
	{/exp:channel:entries}

{/exp:stash:set name="st_content"}
	
The SpinePlus Team page template

The information for the practitioners is saved to its own Stash variable which is then inserted into the body of the main page entry with {exp:stash:get name="st_shortcode"} at the point where it should appear. Then in {st_content} which is the Stash which displays the content on the page, we wrap the {body} tag in Allow EE Code plugin tags so that the Stash variable actually gets parsed (remember the parse_tags parameter).

Example 2

This example is still in development but it's doing a similar thing except that the Packages channel is being used to insert some content in the middle of the body of another entry and then after it too all using a single channel entries tag. This is because the content inserted into the body contains in-page anchors to the content that appears further down the page.

{exp:channel:entries
	channel="packages"
}
	{!-- Using some regex on the title to pull out certain entries --}
	{exp:stash:append name="st_packages" match="#^((?!Standard).)*$#" against="{title}"}
		<dt><a href="#{url_title}">{title} Service Package</a></dt><dd>{package_price}</dd>
	{/exp:stash:append}

	{!-- Picking out entries that have a detail page --}
	{exp:stash:append name="st_packages_full" match="#y#" against="{has_detail_page}"}
		<h3 id="{url_title}">{title} Service Package <span>{package_price} {package_price_extended}</span></h3>
		{package_description}
	{/exp:stash:append}

{/exp:channel:entries}

{exp:channel:entries
	channel="site"
	url_title="packages"
}
	{exp:stash:set_value name="st_page_title" value="{title}"}

	{exp:stash:set name="st_content" parse_tags="yes"}
		{exp:allow_eecode}
		{body}
		{/exp:allow_eecode}

		{stash:st_packages_full}

	{/exp:stash:set}

{/exp:channel:entries}
	

As with the previous example, {st_packages} is inserted into the body of the entry wrapped in {exp:allow_eecode}.

Displaying other items from the same category

This example isn't online either because the requirements changed after it had been done. Originally the brief was to display a list of entries from the same category on a product's individual entry page (later a Playa field was used instead to choose which entries would be related to it).

So what we had to do was get the category that the product belonged to (only one category was assigned from this particular group), and then output a list of other entries from that category. Content specific to the individual entry also needed to be displayed above and below the related entries.

{exp:stash:parse}

	{exp:channel:entries
		channel="{segment_1}"
	}

		{!-- Get the category ID of the product whose page we're on --}
		{categories limit="1"}
			{exp:stash:set_value name="st_category_id" value="{category_id}"}
		{/categories}

		{exp:stash:set name="st_content"}

			Individual entry content goes here…

			{!--  We don't want this to be parsed here since it will be filled with a value later on --}
			{stash:nocache}{exp:stash:get name="st_related_products"}{/stash:nocache}

			More individual entry content goes here…

		{/exp:stash:set}

	{/exp:channel:entries}

{/exp:stash:parse}

{!-- Get the entries from the same category --}
{exp:stash:set name="st_related_products" parse_tags="yes"}

	{exp:channel:entries
		channel="{segment_1}"
		category="{exp:stash:get name='st_category_id'}"
		limit="10"
		parse="inward"
		url_title="not {segment_3}"
	}

		<li><a href="{path={segment_1}/view/{url_title}}/" title="{title}">{products_images limit="1"}{exp:ce_img:single src="{image}" max_width="130" max_height="130" attributes='alt=""'}{/products_images}</a></li>

	{/exp:channel:entries}

{/exp:stash:set}
	

The tricky thing about this example was working around ExpressionEngine's parse order which meant that the category_id wasn't being parsed until after it was required by the channel entries tag where it was required as a parameter.

As is often the case, I had to ask Mark Croxton for some help and the solution was to force the opening block to parse {st_category_id} with {exp:stash:parse} wrapped around the whole block, and then {stash:nocache} around {exp:stash:get name="st_related_products"} to make sure it wasn't parsed until later.

Stash within a Stash

This example was used for the individual product pages on the Barben website.

Each page has a carousel of other products in the same category which are displayed below the main product. But the position of the carousel is also controlled by a start variable which equals the count of the entry. So we needed two Stash variables: one for the carousel code and one for the count of the entry.

{!-- Force Stash to parse tags and conditionals --}
{exp:stash:set parse_tags="yes" parse_conditionals="yes"}

	{stash:st_prod_nav}

		{exp:channel:entries
			channel="{segment_1}"
			category="{segment_3}"
		}
			{ if count==1}
			<nav class="carousel">
				<ul>
					{/ if}
					<li><a href="{url_title_path=xxxx}">{exp:ce_img:single src="{p_thumb}" max_width="140" max_height="140"}<span>{title}</span></a></li>
					{ if url_title==segment_3}{stash:st_start}start: {count}{/stash:st_start}{/ if}
				{ if count==total_results}</ul>
			</nav>
			{/ if}

		{/exp:channel:entries}

	{/stash:st_prod_nav}

{/exp:stash:set}

<article role="main">
	{st_content}
</article>

{!-- The nav gets called here --}
{exp:stash:get name="st_prod_nav"}

…

<script>
	$('.carousel ul').jcarousel({
		buttonNextHTML: '<span id="next" class="carousel-nav"></span>',
		buttonPrevHTML: '<span id="prev" class="carousel-nav"></span>',
		{exp:stash:get name="st_start"} // The count variable gets called here
	});
</script>
	

As mentioned before, a lot of these examples have been arrived at with the help of Mark, so major thanks to him for not only developing such a powerful and useful add-on, but for also being on hand to answer questions about it.

So that's it; I'm out of interesting examples for now, but when I've got a few more up my sleeve, will post them here. As before, if you've got any interesting examples yourselves, feel free to share in the comments.