ExpressionEngine: Conditional template embed - expressionengine

I'm having a bit of an issue with Expression Engine parse order and conditional logic.
I want to embed a template based on a conditional statement within a channel.
Something like this:
{exp:channel:entries channel="project" limit="3"}
{if count >2}
<h1>title{/h1}
{if:else}
{embed="test/.test.html}
{/if}
{/exp:channel:entries}
The problem is that the embed gets called multiple time from the loop. I tried using Stash to set a variable (then call the embed if the variable was set), but it's too late or too early in the parse order.
Does anyone know of a way to conditionally embed based on channel values?

What version of EE are you using? EE 2.9 brings substantial changes (improvements!) to how conditionals are handled. I'm not on EE 2.9 yet but by my reading of the 'Rendering Stages' documentation what you are trying should work as written in 2.9.
Note that conditionals are evaluated in step 19 and embeds in step 21.
In earlier versions of EE embeds were processed before "complex conditionals". See the 2.9 announcement and changelog for details.

Related

Shopware 6 - bug with Email template variables

Did someone has a problem with email templates?
In my case when I use email template in Flow builder for trigger "checkout.order.payment_method.changed" email template with type "order confirmation" doesn't work properly. Problem with variables: currency and addresses are null but other variables works properly.
Interesting when I use the same template in Flow builder for trigger "checkout.order.placed" all vars working properly.
p.s. I've updated all extensions and my Shopware version is v6.4.9.0 Stable Version
Maybe it's a Shopware bug or conflict between plugins?
There are some inconsistencies regarding the data available between different Flow-Builder Events. I noticed something similar and created an issue for it here.
Maybe you can add your case there as this sounds related.
Without knowing the exact content of your order confirmation template, eg if it is the default content or if you made changes, it is hard to tell why this wouldn't work. I tested this on the latest release as of today 6.4.13.0 and the combination of said trigger and template seems to work fine. Looking at the history of the OrderStateChangeEventListener, the criteria for the order should've included currency and addresses associations for a while already, including your version. As #newgennerd already said there could potentially be differences between the criteria used for fetching order for state change events and those used for order placed events, as the latter would be the common use case for the order confirmation. So you should keep that in mind.

Override twig template from plugin

I would like to override a block from a twig template from a plugin in my own plugin.
I have overridden native shopware templates in the past, but I have troubles with plugin templates.
The plugin I am trying to adjust is FroshProductCompare and I am also using FroshDevelopmentHelper to easily retrieve the template I am trying to adjust.
Via the development helper, I found out that the template is located at
vendor/store.shopware.com/froshproductcompare/src/Resources/views/storefront/component/compare/section/overview.html.twig
So I created the file at
custom/plugins/ExamplePlugin/Resources/views/storefront/component/compare/section/overview.html.twig
and added
{% sw_extends "#FroshProductCompare/storefront/component/compare/section/overview.html.twig" %}
to the first line of the file.
I have also tried
{% sw_extends "#Storefront/storefront/component/compare/section/overview.html.twig" %}
I have built the storefront and cleared the cache multiple times and I have also reinstalled the plugins in different orders without success.
I found similar questions, which are not the same.
E.G. How to do a template multiple inheritance in Shopware 6?
But the difference here is, that the block is not native to shopware and is created by the plugin.
Any ideas?
The issue is most likely due to plugin load order.
tl;dr: Older plugins (based on installation date) take precedence over newer plugins. But if you want to make sure your plugins take precedence defined the load order in your theme.
It starts with finding the right template in \Shopware\Core\Framework\Adapter\Twig\TemplateFinder::find you can see a queue is build based \Shopware\Core\Framework\Adapter\Twig\TemplateFinder::getNamespaceHierarchy which in turn gets it from \Shopware\Core\Framework\Adapter\Twig\NamespaceHierarchy\NamespaceHierarchyBuilder. The method return the first found template to the order is the key.
The NamespaceHierarchyBuilder is tagged with shopware.twig.hierarchy_builder which is used to inject the following builders:
Shopware\Core\Framework\Adapter\Twig\NamespaceHierarchy\BundleHierarchyBuilder with priority 1000
Shopware\Storefront\Theme\Twig\ThemeNamespaceHierarchyBuilder with priority 500
Since you want to overwrite a template from a plugin with a plugin BundleHierarchyBuilder is the interesting one (all plugins are simply symfony bundles).
BundleHierarchyBuilder is getting the bundles from the kernel (\Shopware\Core\Kernel). The kernel registers the bundles in \Shopware\Core\Kernel::registerBundles and uses an instance of \Shopware\Core\Framework\Plugin\KernelPluginLoader\KernelPluginLoader to load the plugins. The used instance is \Shopware\Core\Framework\Plugin\KernelPluginLoader\DbalKernelPluginLoader as you can see in \Shopware\Core\HttpKernel::createPluginLoader.
As described in this answer DbalKernelPluginLoader loads the plugins based on the installation date. So plugins with an older installation date will be higher up in the list in the TemplateFinder and their template will be returned.
I would actually recommend you this solution: Define the load order in your own theme.

Using conditionals with stash:variable in stash:embed

I'm having Stash issues when using stash:variables within channel entry conditionals.
template.html
{stash:embed name="pages" stash:paginate="y"}
pages.html
{exp:channel:entries channel="page" dynamic="no" limit="{stash:limit}" disable="categories|category_fields|member_data"}
<h2>{title}<h2>
{if '{stash:paginate}' == 'y'}
{!-- pagination code --}
{/if}
{/exp:channel:entries}
Setting a limit using {stash:limit} works great, but I can't seem to show/hide pagination using stash:paginate="y". Pagination seems to always show regardless of the stash variable.
I expect it's a parse order thing, your first var is working because its parsed properly and your second var is not being parsed before the exp:channel.
Try parse=inward on your exp:channel
I'm no master with stash yet but similar experience suggests parse order is in play
I used stash for the first time recently and it does take some getting used to. I found I had to use the Parse="inward" tag and be mindful of using "value" vs 'value' (single quote vs double quote). Little things like that made all the difference. Bottom line...parse order is one of the most important aspects of EE, yet I and many others don't understand well enough. That is my homework for today: parse order and all it's minutia.

If entry id then show certain content

I've been trying to make something visible only on certain entry_id in expressionengine
{if entry_id="33"}
... show certain content
{/if}
is this even possible in eemcs?
thanks
Sure - but you need to use the {entry_id} variable within a tag pair that provides that variable. For example within a {exp:channel:entires} tag pair.
If you're using url_titles in the URI you may want to think about using segment variables instead. For example:
{if segment_2 == "blog-post"} You're on a blog post{if}
This is what's referred to as a simple conditional in EE, and it's fast enough.
One very important thing to remember in EE is that the standard if:else/else:if routine of an advanced conditional can be very slow, primarily because EE renders all of the code segments and then works its if:else magic. If you find yourself testing many ids or groups, this slows the site down proportionally. In fact, sometimes EEs parse order can stop if:else from functioning entirely.
Instead, consider Mark Croxton's Switchee, a fantastic free plugin that lets you have as many conditions, even nested conditions, without slowdown. It parses just the conditions, then when triggered, is smart enough to descend and run the right code segment:

ExpressionEngine show channel content outside of loop

I know this sounds crazy, but I need to show some post information outside of the loop in the expression engine channel module. Is this possible?
You could use EE's SQL Query template tags (if you know, or have access to the database table names and know what to look for in the database):
http://expressionengine.com/user_guide/modules/query/index.html
Basically, you'd output only what you need - it doesn't have to belong to a channel, or anything specific. The one kicker is that you'd have to know the basics of SQL syntax, but if you have a small working knowledge of it, you can do tons of additional things with it.
If you're not keen on SQL, you could simply embed a template within the template that you're working on. Here's a simple example that assumes you're editing the index and meta templates inside of a template group called 'news':
index template contents:
{exp:channel:entries channel="news"}
<div class="entry">
<h1>{title}</h1>
<div class="content">{body}</div>
{embed="news/meta" this_entry_id="{entry_id}"}
</div>
{/exp:channel:entries}
meta template contents:
{exp:channel:entries channel="news" dynamic="no" limit="1" entry_id="{embed:this_entry_id}"}
<div class="meta">
<p>{entry_date}</p>
<p>{author}</p>
</div>
{/exp:channel:entries}
As you can see, the index template is embedding the meta template. Note that we're passing a parameter to the meta template so that it knows which entry ID to print information about. If you're unfamiliar with EE's template embedding feature, you can read more about it in the EE docs. Embedding templates in other templates is a great way to access the {exp:channel:entries} loop multiple times.
There's an add-on called MX Jumper that allows you to "set" a variable from inside your entries loop and then "get" it elsewhere in the template (before or after in the HTML loop doesn't matter because it parses later).
Alternatively, the approach that's all the rage now is to use the add-on Stash to store any and all elements you need to use distinctly as stash variables that you set and then get - similar to the above, except that once you set them, getting them has to happen at a later parsing stage. The beauty of this approach is stash will store the "set" variables for reuse either at a user or site level, and you can determine what the expiry period is - which then results in better performance. When you apply this broadly using the "template partials" mindset, you can store everything with stash, and then call them into a small number of wrapper templates. This makes it possible to use stash to set, for example, your entry title, then get it three separate times in the wrapper template without any additional load - no need for separate loops within your template - one loop to set the variable, and then you can call that variable as needed in your template - it's kind of like creating global variables on the fly.
I would also suggest looking at Stash.

Resources