Extension, Module

Archived
Forum
(read-only)

Stash

ExpressionEngine 2, ExpressionEngine 3, ExpressionEngine 4, ExpressionEngine 5, ExpressionEngine 6

Back to this add-on's main page
View Other Add-ons From Mark Croxton

     

Having Trouble With Stash Embeds

Support Request

brianrivet
brianrivet

Hi Mark

I’m trying to figure out how to use Stash Embeds better based on our conversation in the other thread, but I’m not having much luck and I was hoping you could help.

Here’s what I am trying to do. I have a freeform form page that I am trying to set up, but I need to set up the form differently based on the member group of the current user. I have a switchee tag set up that is checking the group and then based on the group it writes the form in in different ways.

For one group, I check to see what company the user is associated with. I have to do this with Zoo Visitor member details tag. I set one of my stash variables to the returned value, like I did in the other thread. Next I need to get a list of the reps who are associated with the logged in customer’s business. I have to do that with a Low Variables results tag because the standard channel entry search doesn’t check relationship fields. The thing is I am trying to pass the stash variable with the customer’s company id into the Low Search Results as a parameter. I’ve tried this a number of ways and can’t seem to get it to work. I’ve tried setting the parse=“inward” on the Low Search tag in the hopes that it would parse the stash variable, but it doesn’t. Currently I am trying to get it to work by putting the Low Search tag into a Stash embed and passing the company stash variable in as a parameter. When I do this, the code from the embed is returned unparsed, even when I have the parse=“yes” parameter. Also it looks like it is holding a cached version of the embed template because even when I change the code in it the same old code is returned.

The output of the list of reps is going to need to be used as a parameter on a Freeform form, so I am thinking the embed is the way to go, but I am at a loss as to what I am doing wrong. Any help you can give me would be appreciated. I’m going to post my template code in follow up posts on this thread. It is my hope that if you can help me to understand how to use the embed better it may help me to resolve the issues I am having in the other thread as well.

Thanks,

Brian

brianrivet
# 1
brianrivet

Here’s the code for the stash embed:

{stash:nocache}
{stash
:company}
{exp
:low_search:results channel="zoo_visitor" dynamic="no" status="Representatives-id7|Super_Admins-id1" default:child:rep_customers="{stash:company}" parse="inward"}
 recipient{count}
="{title}"
{/exp:low_search:results}
{
/stash:nocache} 
brianrivet
# 2
brianrivet

And here’s my main template:

{if logged_out}
  {redirect
="/login"}
{
/if}

{if logged_in}

 {embed
="layout/.backend"}
 
 {exp
:stash:set name="SEO"}
  
<title>Contact Mockler Beverage</title>
 
{/exp:stash:set}
 
 
 
 
 {exp
:switchee variable 'global:logged_in_group_id' parse='inward'}

  {case 
default='Yes'}
   
   {exp
:stash:set name="pageContent"}
    
    
<div class="header-wrapper header-arrow-wrapper">
     <
h2 class="header-arrow header-arrow-gold"><span>Ordering</span></h2>
    </
div>
    
    <
p>Your user group does not have access to this areaPlease <a href="mailto:contact@mocklerbeverage.com">contact Mockler Beverage</a> for login credentials.</p
   
   
{/exp:stash:set}      
   
  {
/case}
  
  {case value
='6'}
       
   {exp
:stash:set name="myCompany"}
    {exp
:zoo_visitor:details}
           {visitor
:customer_business}{visitor:customer_business:entry_id}{/visitor:customer_business}
    {
/exp:zoo_visitor:details}
   {
/exp:stash:set}
   
   
   
   
   {exp
:stash:set name="pageContent"}
   
    
<div class="header-wrapper header-arrow-wrapper">
     <
h2 class="header-arrow header-arrow-gold"><span>Contact</span></h2>
    </
div>
    
    <
class="industry-text">For questions or inquiries call <span class="bold-red">{exp:low_variables:parse var='office_phone'} [ext.{exp:low_variables:parse var='sales_ext'}]</span></p>
    
    <
div class="header-wrapper header-normal">
     <
h3 class="header-left header-red smaller-header">Email Your Representative</h3>
    </
div>
    
    <
div id="form-success-message">  
     <
p>Your message has been sentWe will be in touch with you shortly.</p>
    </
div>
    
    
    <
div id="form-wrapper">
       
     
{exp:freeform:form
     form
:id="login-contact-form"
     
form:role="form"
     
form_name="login_contact"
     
required="first_name|last_name|email|subject|user_message"      
     
return="utilities/contactSuccess"
     
notify_admin="no"
     
recipients="yes"
     
     
{stash:embed name="rep-recipients" stash:company="{exp:stash:myCompany}" parse="yes"}
               
     recipient_template
="login_contact_form"
     
parse="inward"     
     
}
     
     
     
     
<input type="hidden" name="first_name" value="{visitor:global:member_firstname}">
     <
input type="hidden" name="last_name" value="{visitor:global:member_lastname}">
     <
input type="hidden" name="email" value="{logged_in_email}">
      
     
     <
div class="row">
     
      <
div class="form-group col-sm-12">
       <
label for="subject" class="sr-only">Subject</label>
       <
input type="text" name="subject" id="subject"  class="form-control" placeholder="Subject" tabindex="1">
      </
div>
      
     </
div>
     
          
     <
div class="row">
     
      <
div class="form-group col-sm-12">
       <
label for="user_message" class="sr-only">Message</label>
       <
textarea name="user_message" cols="" rows="10"  class="form-control" id="user_message" tabindex="5" placeholder="Your Message"></textarea>
      </
div>
      
     </
div>
     
     
{exp:snaptcha:field}
         
     
<div class="row">
     
      <
div class="form-group col-sm-12">
       <
button type="submit" class="btn btn-blue" value="Submit">Submit</button><span class="processing-message"><img src="/assets/images/ajax-loader.gif"></span>   
      </
div>
      
     </
div>
     
     
     
{/exp:freeform:form}
    
</div><!--form-wrapper-->
    
    
       
    <
ul>
     
{stash:embed name="rep-recipients" stash:company="{exp:stash:myCompany}" parse="yes"}
    
</ul>
    
   
{/exp:stash:set}   
  
  {
/case} 
  

  
 {
/exp:switchee}
  
 
 
{
/if} 


I removed two switchee blocks that were not complete yet so it would make it easier to read.

brianrivet
# 3
brianrivet

Hi Mark,

I’ve been working on trying to revamp the way I have the templates set up for the site I’ve been posting about in this and my other thread. Please disregard the previous posts in this thread and the other as they reflect old code that I am not longer going to use. I’ve revamped a page in the site to use something close to the template inheritance approach you describe in the documentation. I think I am making some progress, but I am still having trouble though.

So far I have a main template for the page that acts as a controller. I also have a model template that pulls the necessary data for different views depending on the log in group the current user belongs to. My default case acts as expected showing the message that needs to be displayed if a user is not in the right user group.

The next one is my customer group. I am using the model to pull the company id number for the logged in customer. I then have a partial that is used to extend the content area in my layout template and it should be returning a list of announcement entries related to that customer’s company. However, all I get is a no results reply. I get it if I try to use the stash variable for the customer company id or if I hard code the number in. The thing is looking at the entries there should be at least 1 post being returned. I don’t know if the embed template is wrong or if my partial is being cached or what the problem is. I’m including my templates in the next couple of posts. Hopefully this will be better than my previous attempts.

Any help you can render will be greatly appreciated.

Thanks,

Brian

brianrivet
# 4
brianrivet

Here’s my base layout template, it seems to work fine:

<!DOCTYPE HTML>
<
html>
    
    <
head>
        <
meta charset="utf-8">
  <
meta http-equiv="X-UA-Compatible" content="IE=Edge">
  <
title>{if pg_title}{pg_title} {/if}Mockler Beverage</title>
  <
meta name="robots" content="noindex">
  <
meta name="googlebot" content="noindex">
  <
meta name="viewport" content="width=device-width, initial-scale=1.0">
  <
meta name="format-detection" content="telephone=no">
  
  
  <!-- 
Fav and touch icons -->
  <
link rel="shortcut icon" href="/favicon.ico">
  
  <!--
[if lt IE 9]>
   
[removed][removed] 
  
<![endif]-->
  
  
[removed][removed]
  [removed]try{Typekit
.load({ asynctrue });}catch(e){}[removed]
  
  
  
  
<link href="/assets/css/bootstrap.css" rel="stylesheet">
  <
link href="/assets/css/bootstrap-datetimepicker-build.css" rel="stylesheet">
  <
link href="/assets/css/owl.carousel.css" rel="stylesheet">
  <
link href="/assets/css/backend-theme.css" rel="stylesheet">
  
  
  <!--
[if lt IE 9]
   
[removed][removed]
   
<link href="/assets/css/ie8.css" rel="stylesheet">  
  <!
[endif]-->
  
  
  
[removed]
   
if (navigator.userAgent.match(/IEMobile\/10\.0/)) {
    
var msViewportStyle document.createElement("style")
    
msViewportStyle.appendChild(
    
document.createTextNode(
     
"@-ms-viewport{width:auto!important}"
    
)
   )
   
document.getElementsByTagName("head")[0].appendChild(msViewportStyle)
   
}
  [removed]
  
  [removed][removed]
  [removed][removed]
  
  
    
</head>
    <
body class="backend">
        
{backend-layoutHeader}
  
  
<section class="page-row content-area">
         <
hr class="gold-double">
         <
div class="container">
             <
div class="row">
                 <
aside class="side-bar">
                     <
div class="nav-wrapper-top">
                         <
nav>
                             <
ul>
                                 <
li><a href="{path='login/dashboard'}">Dashboard</a></li>
                                 <
li><a href="{path='login/announcements'}">Announcements</a></li>
                                 <
li><a href="{path='login/ordering'}">Ordering</a></li>
                                 <
li><a href="{path='login/documents'}">Documents</a></li>
                                 <
li><a href="{path='login/contact'}">Contact</a></li>
                             </
ul>
                         </
nav>
                     </
div>
                     <
class="visible-xs" id="nav-toggle"><span>Menu</span></a>
                     
                     <
div class="times-wrapper">
                         <
div class="dock-times hidden-xs">
                             <
h3>Dock Sale Times</h3>
                             <
p><b>Monday Thursday</b><br>4 p.mCST</p>
                             <
p><b>Friday</b><br>4 p.mCST</p>
                         </
div><!--"Before the DOCK-times.."*said Obi Wan Kenobi*-->
                         <
div class="receiving-times hidden-xs">
                             <
h3>Receiving Times</h3>
                             <
p><b>Monday Friday</b><br>6 a.m. - 12 p.mCST</p>
                         </
div>
                     </
div>
                 </
aside>
                 
                 <
main>
                  
                  
{exp:stash:block:header}
                   
<div class="header-wrapper header-arrow-wrapper">
        <
h2 class="header-arrow header-arrow-gold"><span>{pg_title}</span></h2>
       </
div>
                  
{/exp:stash:block:header}
                  
                  
                  {exp
:stash:block:content}
                  
                      {if pg_body}{pg_body}{
/if}
                  
                  {
/exp:stash:block:content}
                     
                     
<div class="times-wrapper">
                         <
div class="dock-times visible-xs">
                             <
h3>Dock Sale Times</h3>
                             <
p><b>Monday Thursday</b><br>4 p.mCST</p>
                             <
p><b>Friday</b><br>4 p.mCST</p>
                         </
div><!--"Before the DOCK-times.."*said Obi Wan Kenobi*-->
                         <
div class="receiving-times visible-xs">
                             <
h3>Receiving Times</h3>
                             <
p><b>Monday Friday</b><br>6 a.m. - 12 p.mCST</p>
                         </
div>
                     </
div>
                 
                 </
main>
             
             </
div>
         </
div>
         
     </
section
  
  
        
{backend-layoutFooter}
        {exp
:stash:get name='postFooter'}
        {scripts}
        {exp
:stash:get name='pageScripts'}
    
</body>
</
html
brianrivet
# 5
brianrivet

Here’s the template in my site templates folder that is acting as the controller:

{!-- ============================================================================= 
     
Announcement Listing
  
     
checks to see if user is logged in. If not redirects to login.
     - If 
logged incollects data on current user to use in partial embeds that pull announcement listings
     
============================================================================= --}


{if logged_out}
  {redirect
="/login"}
{
/if}

{if logged_in}

 {stash
:embed:layouts:backend-base}
 
 {exp
:stash:set type="snippet"}
  {stash
:pg_title}Announcements{/stash:pg_title}  
 {
/exp:stash:set}
  
 {exp
:switchee variable 'global:logged_in_group_id' parse='inward'}

   {case 
default='Yes'}
    
    {exp
:stash:extend name="block:content" with="partials:no-access-response"}   
        
    
   {
/case}
   
   {case value
='6'}
        
    {exp
:stash:extend name="block:content" with="partials:announcement-list-customer"}
    
    {stash
:embed:models:customer process="start" parse="yes"}      
   
   {
/case}
   
   {case value
='7'}
   
       
   
   {
/case}
   
   {case value
='1'}
   
       
   
   {
/case}
   
   
   
  {
/exp:switchee}
 
 
 
{
/if} 


Here is the template acting as the model for users whose login group is 6 :

{exp:stash:set type="snippet"}
 {stash
:custCompany}
  {exp
:zoo_visitor:details}
   {visitor
:customer_business}{visitor:customer_business:entry_id}{/visitor:customer_business}
  {
/exp:zoo_visitor:details}
 {stash
:custCompany}
{
/exp:stash:set} 


And here is the partial that should be displaying the list:

{stash:nocache}

 
<p>{stash:custCompany}</p>
 
 <
p>{custCompany}</p>
 
 
{exp:low_search:results channel="announcements" dynamic="no" limit="10" paginate="bottom" default:child:announcement_related_customers="{custCompany}" parse="inward"}
       
  {if low_search_no_results}
<p>You have no announcements at this time.</p>{/if}
  
                       
         
         
<div class="announcement{exp:channel_images:images entry_id='{entry_id}' limit='1' category='thumbnail'}-image{/exp:channel_images:images}-row">
             <
div class="row">
                 
{exp:channel_images:images entry_id='{entry_id}' limit="1" category='thumbnail'}
                 
<div class="image-wrapper">
                     <
img class="announcement-image" src="{image:url:thumbnail}" alt="{image:title}">
                 </
div>
                 
{/exp:channel_images:images}
                 
<div class="announcement-content-wrapper">
                     <
h3>{title}</h3>
                     
{announcement_blurb}
                     
<div class="date-posted">Date Posted{entry_date format="%n-%j-%y"}</div>
                     <
a href="{path='login/announcements/{url_title}'}" class="btn btn-default">VIEW</a>
                 </
div>
             </
div>
         </
div>
         
         
           
  
{paginate}
    {pagination_links}
     {pagination
-code}
    {
/pagination_links}
  {
/paginate}
 {
/exp:low_search:results}
 
{
/stash:nocache} 

 

brianrivet
# 6
brianrivet

Sorry about the template posts all over the place. I was having a hard time with it and have redone the templates several times. I am hoping this is closer to working.

Mark Croxton
# 7
Developer
Mark Croxton

I think you’re getting mixed up here. If you’re not actually caching then wrapping your embed code with {stash:nocache} will simply escape anything it wraps from being parsed at all.

{stash:nocache}
{stash
:company}
{exp
:low_search:results channel="zoo_visitor" dynamic="no" status="Representatives-id7|Super_Admins-id1" default:child:rep_customers="{stash:company}" parse="inward"}
 recipient{count}
="{title}"
{/exp:low_search:results}
{
/stash:nocache} 

Should just be:

{exp:low_search:results channel="zoo_visitor" dynamic="no" status="Representatives-id7|Super_Admins-id1" default:child:rep_customers="{stash:company}" parse="inward"}
 recipient{count}
="{title}"
{/exp:low_search:results} 

The conditional logic in your templates is making them unnecessarily complex, as you are mixing up routing logic with display logic.

When I created Switchee there was no other way to do routing but now you have multiple options including the built-in template routes, Resource Router and Construct. Of these Resource Router is by far the most powerful choice. I would recommend you use Resource Router to manage the routing based on the logged in user group id, so that you directly load the template you want rather than nest a series of embeds inside a Switchee. That means less tag nesting and less workarounds for EE’s parsing weirdness.

https://github.com/rsanchez/resource_router

Each template can then deal directly with it’s own logic and you will find everything much more maintainable going forward :)

Finally, please check out the presentation here for some ideas on how to structure things (including using Resource Router)
https://speakerdeck.com/croxton/stash-the-right-way

 

brianrivet
# 8
brianrivet

ok based on your recommended reading, I went back and simplified using Resource Router. I had used it before, but never using a callback etc. like this. I was able to get the routing part to work so I was able to eliminate pretty much all of the conditionals and the switchee statements. However, I am still not getting the results I would expect.

When I am logged in as a customer if I got to the announcement screen, based on the setting currently in the entries, I would expect to get 1 result. That is what I get if I put the low search results tag in a blank template by itself and hard wire the customer number instead of using a variable.

Now, Here’s my code, this is the initial controller template that a customer login user gets routed to for announcements:

{stash:embed:layouts:backend-base}
 
 {exp
:stash:set type="global"}
  {stash
:pg_title}Announcements{/stash:pg_title}  
 {
/exp:stash:set}
  
 
        
 {exp
:stash:extend name="block:content" with="partials:announcement-list-customer"}
    
 {stash
:embed:models:customer process="start" parse="yes"


This is the model template pulling the customer company id:

{exp:stash:set type="global"}
 {stash
:custCompany}
  {exp
:zoo_visitor:details}
   {visitor
:customer_business}{visitor:customer_business:entry_id}{/visitor:customer_business}
  {
/exp:zoo_visitor:details}
 {stash
:custCompany}
{
/exp:stash:set} 

And this is the partial that should be returning the list of announcements (expecting 1 result):

<p>{stash:custCompany}</p>
 
 <
p>{custCompany}</p>
 
 
{exp:low_search:results channel="announcements" dynamic="no" limit="10" paginate="bottom" default:child:announcement_related_customers="{stash:custCompany}" parse="inward"}
       
  {if low_search_no_results}
<p>You have no announcements at this time.</p>{/if}
  
                       
         
         
<div class="announcement{exp:channel_images:images entry_id='{entry_id}' limit='1' category='thumbnail'}-image{/exp:channel_images:images}-row">
             <
div class="row">
                 
{exp:channel_images:images entry_id='{entry_id}' limit="1" category='thumbnail'}
                 
<div class="image-wrapper">
                     <
img class="announcement-image" src="{image:url:thumbnail}" alt="{image:title}">
                 </
div>
                 
{/exp:channel_images:images}
                 
<div class="announcement-content-wrapper">
                     <
h3>{title}</h3>
                     
{announcement_blurb}
                     
<div class="date-posted">Date Posted{entry_date format="%n-%j-%y"}</div>
                     <
a href="{path='login/announcements/{url_title}'}" class="btn btn-default">VIEW</a>
                 </
div>
             </
div>
         </
div>
         
         
           
  
{paginate}
    {pagination_links}
     {pagination
-code}
    {
/pagination_links}
  {
/paginate}
  
 {
/exp:low_search:results} 

I have the two paragraph tags at the top because I was trying to verify how the variable tag should be written to verify the output.

The output I am getting is the no results output. The weird thing is the paragraph tags are not there either. I would expect even if it didn’t return a value I would at least see the empty paragraph tags in the returned html but they aren’t there either. That makes me wonder if there is some sort of caching going on.

 

 

Mark Croxton
# 9
Developer
Mark Croxton

When capturing anything into a Stash variable, you also capture the whitespace and line breaks around it. Unfortunately EE isn’t smart enough to ignore those when you pass them inside a parameter value. You can either manually close up the spaces around the value being captured or use the trim=“yes” parameter. Also, you need to ensure that the value is actually parsed before you capture it, otherwise you will capture the literal tags and not their output. Finally, type=“global” creates a global variable {custCompany} (parsed by EE natively) whereas type=“variable” (the default) creates a stash variable {stash:custCompany) (only parsed by Stash inside Stash embeds or tags). The later is more efficient but less versatile (mainly because you can’t use it in {if/else} style conditionals).

{exp:stash:set name="custCompany" parse="yes" type="global"}{exp:zoo_visitor:details}{visitor:customer_business}{visitor:customer_business:entry_id}{/visitor:customer_business}{/exp:zoo_visitor:details}{/exp:stash:set} 

Open up your template debug and verify that ‘custCompany’ is being set to the id you want (look for a line beginning Stash: SET custCompany ...)

When you pass the variable to your tag there is no need to use parse=“inward” if the value being passed has already been parsed: (parse=“inward” basically tells EE to parse each parameter one by one)”

{exp:low_search:results 
    channel
="announcements" 
    
dynamic="no" 
    
limit="10" 
    
paginate="bottom" 
    
default:child:announcement_related_customers="{custCompany}"
}
...
{/exp:low_search:results} 

 

brianrivet
# 10
brianrivet

Ok, I made the change by adding the trim parameter. I also set it to global and then changed the value in the low results tags to {custCompany} so it would access it as a global variable. I’m still getting no results though.

I checked the template debugging and I am not finding a line with Stash set where it is setting the value that I would expect (the customer number I would expect to get set is 1398). However, I am seeing a line in there related to the model that says {exp:stash:set type=“snippet”}

It says it retrieved the template {exp:stash:set type=“snippet”} {stash:custCompany} {exp:zoo_visitor:details} {visitor:customer_business}{visitor:customer_business:entry_id}{/visitor:customer_business} {/exp:zoo_visitor:details} {stash:custCompany} {/exp:stash:set}

That looks like the code from my customer model template but it isn’t the current version that I just pushed up to the server. I even went in via ftp to verify that the changes had been written, so I’m not exactly sure where that code is coming from. I don’t know that the snippet type would matter, but the model code is exactly like what you sent back with it set to global and parse set to yes. The only difference is I added the trim parameter.

brianrivet
# 11
brianrivet

I just tried changing all of the content in the partial to be static, or at least using a value hard wired into the low search tag and it stilled returned no results. I then went into a different template made a change and had it load it as well and the page did not reflect the changes. The only thing I can think of is that my stash templates are getting cached, but I don’t know how to prevent it or at least force it to refresh.. Can you help me to sort that out?

brianrivet
# 12
brianrivet

I was able to determine that caching was the problem. I set up a template with the flush cache tag, viewed it then went to the page again and it brought up the expected results. Now here’s my next question. If nocache prevents the template tags inside from parsing, then how do I set up stash templates that can be processed whenever requested (as in I don’t want them to cache). Many of the pages I’m setting up in this part of the site are dynamic in that they generate the listings of entries etc. based on the current logged in user’s group and other related fields to their zoo visitor entry. That being the case I’d prefer they didn’t cache, but I am not finding a way to do this or at least I am not understanding that part of the documentation. Is Mustash needed to do this?

Mark Croxton
# 13
Developer
Mark Croxton

Stash saves a template file after reading it and then on subsequent views Stash will load the template from the database, rather than going back to the file. During development you can add replace=“yes” to any stash embeds to have them check with the file each time. Otherwise you will need to clear the stash cache when making changes to the file.

It’s important to understand that ‘caching’ in this sense means saving the template as it is with all the tags etc, before it is parsed, not the fully-parsed and rendered output of the template code.

So there is no need to use {stash:nocache} tags at all unless you are using Stash’s caching tag {exp:stash:cache} or saving rendered html fragments inside a stash:set.

brianrivet
# 14
brianrivet

Thanks Mark. I will use the replace tag at least during development. Once I did the cache flush the template came up and is rendering the expected content, so I think that is all I needed. Thanks so much for your help and for your patience. I appreciate it!