Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Stash: core principles

Stash: core principles

Presentation to #eeconf 14 October 2013

Mark Croxton

October 14, 2013
Tweet

More Decks by Mark Croxton

Other Decks in Technology

Transcript

  1. Capture text and fragments of code to be re-used elsewhere

    in your templates. Pass the output of one or more tags as the input to other tags. Change the order in which template tags and variables are parsed. Cache fragments of data, so that the tags that generated it do not need to be re-run on subsequent views. Variable
  2. Set a variable - tag pair {exp:stash:set name="foo"}bar{/exp:stash:set} OR {exp:stash:foo}bar{/exp:stash:foo}

    Set a variable - single tag {exp:stash:set_value name="foo" value="bar"} Set a multiple variables at once {exp:stash:set} {stash:title}A title{/stash:title} {stash:content}Some content{/stash:content} {/exp:stash:set} Se
  3. Set variable 'foo' {exp:stash:set name="foo"}Romans{/exp:stash:set} Append to 'foo' {exp:stash:append name="foo"}

    ever done for us? {/exp:stash:append} Prepend to 'foo' {exp:stash:prepend_value name="foo" value="What have the "} Appen & prepen
  4. Get a variable - prints 'bar' {exp:stash:get name="foo"} OR {exp:stash:foo}

    Get a variable, provide a default value {exp:stash:get name="foo" default="bar"} Get a variable into a block {exp:stash:block name="foo"} Where are you two from, nose city? {/exp:stash:block} Ge
  5. {!-- set a variable --} {exp:stash:set name="url_title"}brian{/exp:stash:set} {!-- pass the

    variable to a tag as a parameter... --} {exp:channel:entries url_title="{exp:stash:get name='url_title'}" channel="people" parse="inward"} {/exp:channel:entries} {!-- ...or, replace the variable into a tag --} {exp:stash:parse} {exp:channel:entries url_title="{stash:url_title}"} channel="people" {/exp:channel:entries} {/exp:stash:parse}
  6. Determines which session array a variable is stored in. type="variable"

    (default) The native Stash array. Can be ouput with placeholder {stash:my_var} inside Stash embeds & Stash tags. type="snippet" An EE snippet. Like other snippets, access as {my_var} inside EE embeds and use in advanced conditionals. Variabl t
  7. {!-- Set a native stash variable --} {exp:stash:set name="person"}Brian{/exp:stash:set} {!--

    Comparison - watch out for quotes! --} {if "{exp:stash:get name='person'}" == "Brian"} You silly sods! {/if} {!-- Is the variable empty? --} {if "{exp:stash:not_empty name='person'}"} He's not the Messiah. He's a very naughty boy! {/if} {!-- Switchee has native support --} {exp:switchee variable="stash:person" parse="inward"} {case value="Brian"} Blessed are the cheesemakers. {/case} {/exp:switchee}
  8. {!-- Set a snippet variable --} {exp:stash:set name="person" type="snippet"} Brian{/exp:stash:set}

    {!-- Comparison --} {if person == "Brian"} You silly sods! {/if} {!-- Is the variable empty? --} {if person} He's not the Messiah. He's a very naughty boy! {/if} {!-- in an embed or inside {exp:stash:parse} --} {if person == "Brian"} I'm {person}, and so's my wife! {/if}
  9. Provides a 'namespace' for related variables. Contexts may be environmental

    (a URI segment or entry_id), arbitrary ('my_context'), or an @ pointer: context="@URI" Points to the full URI of the current page. context="@" Points to the current static context set by the {exp:stash:context name="my_context"} tag. Cont
  10. {!-- {cf_dept} is the department the person works in --}

    {exp:channel:entries channel="staff"} {exp:stash:append name="staff" context="{cf_dept}"} {cf_first_name} {cf_last_name}, {/exp:stash:append} {/exp:channel:entries} {!-- get staff members in the 'dogsbody' dept --} {exp:stash:get name="staff" context="dogsbody"} {!-- context is just a prefix. Same output: --} {exp:stash:get name="dogsbody:staff"} {!-- use @ pointers to make your code DRY --} {exp:stash:context name="dogsbody"} {exp:stash:get name="@:staff"}
  11. Parsed from template root inwards Outermost layer of tags are

    parsed, top to bottom Nested tags are exposed Repeated passes made until all layers are parsed Modul ta pars order
  12. Look inside tagdata for immediate descendents If a module tag

    is found, parse it first If a plugin tag is found, check for descendents... Results in parse order from innermost outwards Parse="inward" makes plugin behave like a module Plugi ta pars order
  13. {exp:channel:entries channel="{segment_1}"} {exp:stash:set name="content"} {exp:word_limit total="4"} {cf_content} {/exp:word_limit} {/exp:stash:set} {/exp:channel:entries}

    {!-- this is parsed before the variable is set --} {exp:stash:get name="content" default="if you can see this, it's not working!"} 1 1 2 3
  14. {exp:channel:entries channel="{segment_1}"} {exp:stash:set name="content"} {exp:word_limit total="4"} {cf_content} {/exp:word_limit} {/exp:stash:set} {/exp:channel:entries}

    {!-- this is parsed before the variable is set --} {exp:stash:get name="content" default="if you can see this, it's not working!"} 1 1
  15. {exp:stash:set name="content"} {exp:word_limit total="4"} He's not the messiah, he's a

    very naughty boy! {/exp:word_limit} {/exp:stash:set} {!-- this is parsed before the variable is set --} if you can see this, it's not working! 2
  16. Stash: process="start" (embeds only) Snippets, config, segment, date and embed

    vars Simple conditionals PHP on input Preload replace vars {exp:tag}tag vars{/exp:tags} (Stash: process="inline") PHP on output Advanced conditionals Embeds (recursive) Stash: process="end" Redirect, user defined & standard globals Templat pars order 1 2 3 4 5 6 7 8 9
  17. {exp:channel:entries channel="{segment_1}"} {exp:stash:set name="content"} {exp:word_limit total="4"} {cf_content} {/exp:word_limit} {/exp:stash:set} {/exp:channel:entries}

    {!-- if this doesn't work, the kitten gets it --} {exp:stash:get name="content" default="if you can see this, it's not working!" process="end"}
  18. Stash: process="start" (embeds only) Snippets, config, segment, date and embed

    vars Stash vars, Stash embed vars Simple conditionals {exp:tag}tag vars{/exp:tags} Advanced conditionals Stash: process="end" Stas pars order 1 2 3 4 5 6 7
  19. {exp:channel:entries channel="{segment_1}"} {exp:stash:set name="content" parse_tags="yes"} {exp:word_limit total="20"} {cf_content} {/exp:word_limit} {/exp:stash:set}

    {/exp:channel:entries} {!-- by jove, it works! Unbag the kittens! --} {exp:stash:get name="content" default="if you can see this, it's not working!" process="end"}
  20. parse_depth="X" (1) How many layers of the onion to peel

    off. parse_tags="yes|no" (no) Parse {exp:tags} recursively. parse_vars="yes|no" (no) Parse stash and other global variables recursively. parse_conditionals="yes|no" (no) Parse simple and advanced conditionals. Tunin th Stas parser
  21. save="yes|no" ("no") Cache a variable. replace="yes|no" ("yes") Regenerate the cached

    variable if it already exists? refresh="X" (1440) Number of minutes to cache the variable until it expires. {stash:nocache}Don't cache me{/stash:nocache} Region remains unparsed until it is retrieved. Cachin option
  22. Determines the visibility of saved variables. scope="local" (default) Exists in

    memory. Expires once the page has rendered. scope="site" Globally visible to all. Set once until expires or replaced. scope="user" Linked to the user's session ID, only visible to that user. Expires when the user’s browser session ends. Scop
  23. {!-- cache the footer nav for a day --} {exp:stash:set

    name="footer" scope="site" save="yes" refresh="1440" replace="no" parse_tags="yes"} {exp:taxonomy:nav tree_id="4" display_root="no" style="linear" depth="1"} <li><a href="{node_url}">{node_title}</a></li> {/exp:taxonomy:nav} {/exp:stash:set}
  24. <form method="post"> <label>Adjust contrast</label> <select name="contrast"> <option value="s">Standard</option> <option value="hc">High

    contrast</option> </select> </form> {!-- save the form value for the user's session --} {exp:stash:get name="contrast" scope="user" save="yes" match="#^s$|^hc$#" default="s" dynamic="yes"}
  25. Structured data that can be cached and re-used to improve

    template performance. Sort, randomise, paginate, fractionalise and filter with regular expressions, in ways that go far beyond what is possible with standard tag pairs such as channel entries. Nested lists allow you to capture multi-dimensional arrays, such as a Playa tag nested within a Matrix. List
  26. 1 dimensio Name: Brian Cohen Age: 32 2 dimension 1

    Name: Brian Cohen Age: 32 Job: Not the Messiah 1 Name: Mr Creosote Age: 62 Job: Gluttony 2 Name: Norwegian Blue Age: 20 Job: Parrot (deceased) 3 Job: Not the Messiah
  27. Set a one-dimensional list of key-value pairs {exp:stash:set_list name="characters"} {stash:name}Mr

    Creosote{/stash:name} {stash:job}Gluttony{/stash:job} {/exp:stash:set_list} Append / prepend a row to create a two-dimensional list {exp:stash:append_list name="characters"} {stash:name}Norwegian Blue{/stash:name} {stash:job}Parrot (deceased){/stash:job} {/exp:stash:append_list} Se on dimensiona lis
  28. Capturing a 2D list with append {exp:channel:entries channel="characters"} {exp:stash:append_list name="characters"}

    {stash:name}{cf_name}{/stash:name} {/exp:stash:append_list} {/exp:channel:entries} Parsing wrapped tags, then capturing a 2D list {exp:stash:set_list name="characters" parse_tags="yes"} {exp:channel:entries channel="characters"} {stash:name}{cf_name}{/stash:name} {/exp:channel:entries} {/exp:stash:set_list} Se tw dimensiona lis 1 1 2 2
  29. Output a 1 or 2 dimensional list {exp:stash:get_list name="characters"} <div

    class="{switch='one|two'}"> <h1>Character {count}: {name}</h1> <p>Job: {job}</p> <p>{absolute_count} of {absolute_results}</p> </div> {if no_results} {redirect="site/404"} {/if} {/exp:stash:get_list} Ge lis
  30. Order/sort {exp:stash:get_list name="characters" orderby="age" sort="asc" sort_type="string"} {name} - {job} {/exp:stash:get_list}

    Randomize specific columns {exp:stash:get_list name="characters" orderby="random:name,job"} {name} - {job} {/exp:stash:get_list} Sortin
  31. Fraction {exp:stash:get_list name="characters" limit="1/3"} <li>{name}</li> {/exp:stash:get_list} {exp:stash:get_list name="characters" limit="1/3" offset="1/3"}

    <li>{name}</li> {/exp:stash:get_list} {exp:stash:get_list name="characters" offset="2/3"} <li>{name}</li> {/exp:stash:get_list}
  32. 3+ dimension Name: Brian Cohen 31:items 32:items Age: 32 Unique

    ID: 31 1 Name: Mr Creosote Age: 62 Unique ID: 32 2 Object: Gourd Used for: Holy water Value: Half a dinare 1 Item: Stone Used for: Heretics Value : About one stone 2 Object: Wafer-thin mint Used for: Scoffing Value: Complimentary 1 Object: Chocolate frog Used for: Eating Value : 1 million pounds 2 Job: Not the Messiah Job: Gluttony
  33. {exp:stash:set_list name="characters" parse_tags="yes" parse_depth="2"} {exp:channel:entries channel="characters" limit="2"} {stash:name}{title}{/stash:name} {stash:entry_id}{entry_id}{/stash:entry_id} {exp:stash:set_list:nested

    name="items" parse_tags="yes" context="{entry_id}"} {cf_items} {stash:item}{title}{/stash:item} {/cf_items} {/exp:stash:set_list:nested} {/exp:channel:entries} {/exp:stash:set_list}
  34. {exp:stash:set_list name="characters" parse_tags="yes" parse_depth="2"} {exp:channel:entries channel="characters" limit="2"} {stash:name}{title}{/stash:name} {stash:entry_id}{entry_id}{/stash:entry_id} {exp:stash:set_list:nested

    name="items" parse_tags="yes" context="{entry_id}"} {cf_items} {stash:item}{title}{/stash:item} {/cf_items} {/exp:stash:set_list:nested} {/exp:channel:entries} {/exp:stash:set_list} 1 2 3 4
  35. {exp:stash:set_list name="characters" parse_tags="yes" parse_depth="2"} {exp:channel:entries channel="characters" limit="2"} {stash:name}{title}{/stash:name} {stash:entry_id}{entry_id}{/stash:entry_id} {exp:stash:set_list:nested

    name="items" parse_tags="yes" context="{entry_id}"} {cf_items} {stash:item}{title}{/stash:item} {/cf_items} {/exp:stash:set_list:nested} {/exp:channel:entries} {/exp:stash:set_list} 1
  36. {exp:stash:set_list name="characters" parse_tags="yes" parse_depth="2"} {stash:name}Brian Cohen{/stash:name} {stash:entry_id}1{/stash:entry_id} {exp:stash:set_list:nested name="items" parse_tags="yes"

    context="1"} {exp:playa:children entry_id="1" field="cf_items"} {stash:item}{title}{/stash:item} {/exp:playa:children} {/exp:stash:set_list:nested} {stash:name}Mr Creosote{/stash:name} {stash:entry_id}2{/stash:entry_id} {exp:stash:set_list:nested name="items" parse_tags="yes" context="2"} {exp:playa:children entry_id="2" field="cf_items"} {stash:item}{title}{/stash:item} {/exp:playa:children} {/exp:stash:set_list:nested} {/exp:stash:set_list} 2 2
  37. {exp:stash:set_list name="characters" parse_tags="yes" parse_depth="2"} {stash:name}Brian Cohen{/stash:name} {stash:entry_id}1{/stash:entry_id} {exp:stash:set_list:nested name="items" parse_tags="yes"

    context="1"} {stash:item}Gourd{/stash:item} {stash:item}Stone{/stash:item} {/exp:stash:set_list:nested} {stash:name}Mr Creosote{/stash:name} {stash:entry_id}2{/stash:entry_id} {exp:stash:set_list:nested name="items" parse_tags="yes" context="2"} {stash:item}Wafer thin mint{/stash:item} {stash:item}Chocolate frog{/stash:item} {/exp:stash:set_list:nested} {/exp:stash:set_list} 3 3
  38. {!-- Get the list of entries --} {exp:stash:get_list name="characters"} <h1>{count}:

    {name}</h1> <ul> {!-- Get the related entries list for each row --} {exp:stash:get_list:nested name="items" context="{entry_id}" prefix="related"} <li>{related:count} : {item}</li> {/exp:stash:get_list:nested} </ul> {/exp:stash:get_list}
  39. {!-- Get the list of entries --} {exp:stash:get_list name="characters"} <h1>{count}:

    {name}</h1> <ul> {!-- Get the related entries list for each row --} {exp:stash:get_list:nested name="items" context="{entry_id}" prefix="related"} <li>{related:count} : {item}</li> {/exp:stash:get_list:nested} </ul> {/exp:stash:get_list} 2 1
  40. {-- Filter a list by a regular expression --} {exp:stash:get_list

    name="people" match="#^A#" against="last_name"} {last_name}, {first_name} {/exp:stash:get_list} {!-- NOT matching a pattern (negative lookahead) --} {exp:stash:get_list name="people" match="#^(?!(A|B|C)).*#" against="last_name"} {last_name}, {first_name} {/exp:stash:get_list} {!-- Unique list rows --} {exp:stash:get_list name="people" unique="yes"} {last_name}, {first_name} {/exp:stash:get_list}
  41. 100 Brian Litzinger 9.8 Anna Brown 10.1 John D. Wells

    10.6 Lodewijk Schutte 11.1 Eric Lamb 12.8 Runner Time Mrs Flinger 19.1 Eric Lamb 19.3 Justin Kimbrell 20.6 Carl W Crawley 21.1 Erik Reagan 22.2 Runner Time Brandon Kelly 43.2 Steven Grant 43.7 Jack McDade 44.6 Paulo Elias 46.8 Adrian Macneil 47.2 Runner Time m 400m Adrienne L. Travis 1:40.9 Iain Urquhart 1:41.5 Nicholas Bottari 1:42.4 Rob Sanchez 1:45.8 Ryan Masuga 5:25.5 Runner Time 800m 200m
  42. {!-- for a given event, capture and cache related race

    data --} {exp:stash:set_list name="race_data" parse_tags="yes" parse_depth="2" save="yes" scope="site" replace="no"} {exp:playa:parents entry_id="{segment_3}" field="cf_race"} {stash:runner}{cf_runner}{/stash:runner} {stash:distance}{cf_distance}{/stash:distance} {stash:time}{cf_time}{/stash:time} {/exp:playa:parents} {/exp:stash:set_list} {!-- our list looks something like this --} 1 runner: Brian Litzinger distance: 100 time: 9.8 2 runner: Mrs Flinger distance: 200 time: 19.1 3 runner: Eric Lamb distance: 100 time: 12.8
  43. {!-- get a list of the unique race distances, e.g.

    100m, 200m, 400m --} {exp:stash:get_list name="race_data" scope="site" unique="distance"} <table> <caption>Results for {distance}</caption> <tr> <th>Runner</th> <th>Time</th> </tr> {!-- for each unique distance show runners and their time in order --} {exp:stash:get_list:nested name="race_data" scope="site" prefix="result" orderby="time" match="#^{distance}$#" against="distance"} <tr> <td>{result:runner}</td> <td>{result:time}</td> </tr> {/exp:stash:get_list:nested} </table> {/exp:stash:get_list}
  44. Take time to understand parse order. It’s essential to using

    Stash effectively. Set, get, append and prepend template variables; pass to tags, use in conditionals. Use scope to determine variable visibility, context and @pointers to namespace and re-use variables. Subvert parse order with post-processing & Stash parsing. Capture multi-dimensional lists from looping tag pairs and use nesting and filtering to group and multi-sort your data. Cache variables and lists to speed up your templates. Summar