Skip to content

Instantly share code, notes, and snippets.

@croxton
Last active April 8, 2018 02:24
Show Gist options
  • Save croxton/9d012297096892ca5c10 to your computer and use it in GitHub Desktop.
Save croxton/9d012297096892ca5c10 to your computer and use it in GitHub Desktop.
Stash and conditionals in EE 2.9

With Stash you have always been able to create global variables and evaluate them in the same template using if/else conditionals:

{exp:stash:set_value name="var" value="cheese" type="snippet"}

{if var == "cheese"}
  	We have cheese!
{if:else}
  	Where's the cheese, gromit? 
{/if}

This still works as it always has in ExpressionEngine 2.9. However, despite the new conditionals parser in 2.9 evaluating "when ready" this control structure will still result in all tags inside every condition being parsed (as it did previously in older versions of EE). Let's modify the conditional to illustrate the problem:

{exp:stash:set_value name="var" value="cheese" type="snippet"}

{if var == "monkey"}
   	{exp:stash:set_value name="test" value="monkey"}
{if:else}
   {if var == "cheese"}
	   {exp:stash:set_value name="test" value="cheese"}
   {if:else}
	   {exp:stash:set_value name="test" value="tennis"}
   {/if}
{/if}

{!-- Expected output: cheese. Actual output: tennis --}
{exp:stash:test}

In this case the "test" variable is set three times, and so ends up with the value "tennis". This happens because conditionals are evaulated before and after tags are parsed in a given "layer" of the template, but NOT in-between tags.

How to solve this problem? We could use Switchee or IfElse, because, as tags, they evaluate after any preceding tags and before any following tags:

Switchee

{exp:stash:set_value name="var" value="cheese" type="snippet"}

{exp:switchee variable="global:var" parse="inward"}  	
	{case value="monkey"}
		{exp:stash:set_value name="test" value="monkey"}
	{/case}
	{case default="yes"}
		{switchee variable="global:var" parse="inward"}
			{case value="cheese"}
				{exp:stash:set_value name="test" value="cheese"}
			{/case}
			{case default="yes"}
				{exp:stash:set_value name="test" value="tennis"}
			{/case}
		{/switchee}
	{/case}
{/exp:switchee}

{!-- output: cheese --}
{exp:stash:test process="end"}

IfElse

{exp:stash:set_value name="var" value="cheese" type="snippet"}

{exp:ifelse parse="inward"}
{if var == "monkey"}
		{exp:stash:set_value name="test" value="monkey"}
{if:else}
	{if var == "cheese"}
   			{exp:stash:set_value name="test" value="cheese"}
	{if:else}
   			{exp:stash:set_value name="test" value="tennis"}
	{/if}
{/if}
{/exp:ifelse}

{!-- output: cheese--}
{exp:stash:test process="end"}

Or, we can put the conditional inside a Stash parse block:

Stash:parse

{exp:stash:set_value name="var" value="cheese" type="snippet"}

{exp:stash:parse}
{if var == "monkey"}
   	{exp:stash:set_value name="test" value="monkey"}
{if:else}
   {if var == "cheese"}
	   {exp:stash:set_value name="test" value="cheese"}
   {if:else}
	   {exp:stash:set_value name="test" value="tennis"}
   {/if}
{/if}
{/exp:stash:parse}

{!-- output: cheese--}
{exp:stash:test}
@proimage
Copy link

This happens because conditionals are evaulated before and after tags are parsed in a given "layer" of the template, but NOT in-between tags.

Could you explain this bit some more? Specifically, which parts of your sample template are considered to be conditionals, tags, or layers?

@croxton
Copy link
Author

croxton commented Jul 16, 2014

The template parser makes multiple passes of the template from top to bottom, each time parsing the outermost layer of tags ({exp:my:tag} are what I mean by tags). On the following pass the next layer of tags down are parsed (that were nested inside the tags that make up the first layer) . If the previous pass has exposed more tags these are parsed too. And so on until no more tags exist. I liken it to peeling an onion.

In 2.9 EE attempts to parse if/else conditionals before each pass and after the very last pass (or you can think of it as after each pass and before the very first pass), and will do so only if they are "ready" - the variables being evaluated actually exist. Previously, simple conditionals were parsed just before the first pass only, and advanced conditionals were parsed at the end of the very last pass only.

The new behaviour is much more powerful and useful, but it's important to appreciate that if you set a variable in one pass it will not be evaluated until the next pass. You cannot evaluate it in a conditional sitting on the same layer as you set it.

@proimage
Copy link

Thanks, that clarifies things a bunch! You rock, btw. Anyone told you that in the past 5 minutes? ;)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment