Configurable partial - php

I have a component in my templating engine (that works well so far) that kind of needs to take an argument.
The component is a navigation on a website. In the CMS there can be many navigations (main, footer, side) but I can't get the logic for Mustache right.
My template `top.mustache':
<div id="wrap-top">
<div id="top">
{{> #navigation }}
{{ main }}
{{> /navigation }}
</div>
</div>
And then navigation.mustache is just:
<div class="nav">
{{ #navigation }}
</div>
In PHP I'm rendering it as follows:
$mustache->render("top", [
"navigation" => [
"main" => "HTML HERE"
]
];
The thing is that I don't want to create multiple tags like navigation_main or navigation_footer because the code is the same. The links may be different but that's handled in PHP where HTML is being generated.
The key is to not have to create mustache files for the names of the navigations. How do I put this all together? Just for the purpose of the question, let's say I do this:
{{ #navigation }}
{{ main }}
{{ /navigation }}
<-- some other html -->
{{ #navigation }}
{{ footer }}
{{ /navigation }}
And the result would be:
<div class="nav"><-- links from main here --></div>
<-- some other html -->
<div class="nav"><-- links from footer here --></div>
The reason is that the names of navigations can vary. In PHP I can prepare the array with all available options but how to use only one partial template?

Related

Shopify (liquid) - add class to div if page template is equal to

Is this possible? I'm working on an existing website and I need to overwrite some styles but only on pages that use my new templates as overwriting the main styles might break the other pages. This is the markup:
<div id="page">
<main role="main" id="MainContent">
{{ content_for_layout }}
</main>
{% section 'footer' %}
</div>
So adding a class to the page or main element would be ideal.
I've managed to achieve this with an if statement to display content but only on a certain template, like this:
{% if template == 'page.job-detail' %}
<!-- CODE HERE -->
{% endif %}
Not sure how that'd work in relation to classes on a div? There's probably a few pages I'd need to include so an array or a way I was specify multiple templates would be ideal. Templates like "page.faq", "page.jobs", "page.job-detail".
Why don't you just add a custom class to all of your pages and target that based on the templates you like to target.
So you can add the following to the body tag.
<body class="template-{{ template | replace: '.', '-' | replace: '/', '-' }}">
And you will get classes like:
template-page-faq
template-page-jobs
template-collection
template-index
template-customer-login
etc..
From there you can use only CSS to style only what you need using the above classes.
In your template name, you can add a string that would give you a hint that it is a custom page like so,
"page.custom-faq", "page.custom-jobs", "page.custom-job-detail"
And you can do this to your HTML
<div id="page">
<main role="main" id="MainContent" class="{% if template.suffix contains 'custom' %}your-custom-class-here{% endif %}">
{{ content_for_layout }}
</main>
{% section 'footer' %}
</div>
template-{{ template | replace: '.', '-' | handle }}
Will print template-page-donate for page template with the name "donate"

PyroCMS theme custom navigation structure

I've searched everywhere but can't seem to find anything in the documentation or anywhere else. I've created my own custom theme, copypasting stuff from the Starter theme which ships with PyroCMS. In my navigation partial there is this twig directive:
{{ structure()
.linkAttributesDropdown({'data-toggle': 'dropdown'})
.listClass('nav navbar-nav navbar-right')
.childListClass('dropdown-menu')
.render()|raw }}
This works when using the Bootstrap framework. I am using Purecss.io and I want to assign different classes and assign classes to more elements. My navigation should look like this:
<ul class="pure-menu-list">
<li class="pure-menu-item pure-menu-selected">
<a href="http://local.dev" class="pure-menu-link" >Home</a>
</li>
<li class="pure-menu-item pure-menu-has-children pure-menu-allow-hover">
Item with children
<ul class="pure-menu-children">
<li class="pure-menu-item">
Child 1
</li>
<li class="pure-menu-item">
Child 2
</li>
</ul>
</li>
</ul>
I've tried the folling in my partial:
{{ structure()
.linkAttributesDropdown({'class': 'pure-menu-item pure-menu-has-children pure-menu-allow-hover'})
.listClass('pure-menu-list')
.elementClass('pure-menu-item')
.childListClass('pure-menu-children')
.render() }}
But that doesn't do the trick.
How would I accomplish this? Where can I find documentation for the used functions structure(), listClass() etc.?
Thanks in advance!
Unfortunately this portion of the system is still being developed but I can show you the macro and how to interact with it:
https://github.com/anomalylabs/pages-module/blob/master/resources/views/macro.twig
The chaining you are seeing is how you set the options so structure().fooBar(value) set's the foo_bar option to value in the options collection.
For elementClass you are probably looking for linkClass. Also don't forget to escape with |raw!
Looks like this will give you your desired markup:
{{ structure()
.currentClass('pure-menu-selected')
.dropdownClass('pure-menu-has-children pure-menu-allow-hover')
.linkAttributesDropdown({'class': 'pure-menu-item pure-menu-has-children pure-menu-allow-hover'})
.listClass('pure-menu-list')
.itemClass('pure-menu-item')
.linkClass('pure-menu-link')
.childListClass('pure-menu-children')
.render()|raw }}
Here's some information:
The very basic default looks like the following and will create an unordered list with all your existing pages. If you have set/toggled a page to be NOT enabled, then it will not show up.
{{ structure()|raw }}
Change the class of the list element
{{ structure().list_class('navigation')|raw }}
Change the list tag to something else than unordered list:
{{ structure().list_tag('dl')|raw }}
Change list element
{{ structure().link_tag('dt')|raw }}
Show children of only a specific page
{{ structure().root('/my-page')|raw }} or page-id {{ structure().root('9')|raw }}
Set class for the element with children
{{ structure().dropdown_class('has-children')|raw }}
Set a class to every li item:
{{ structure().item_class('has-children')|raw }}
Set a class to the link
{{ structure().link_class('my-class')|raw }}
Add a title attribute to the link
{{ structure().link_attributes({'title':'Title attribute'})|raw }}

Set Twig variable inside an include and use it afterward

imagine you have a twig template (tplA.twig) that include an other one
<p>Twig template A</p>
{% set test = "in tpl A" %}
<p>first, variable is: {{ test }}</p>
{% include "tplB.twig" %}
<p>and the variable is: {{ test }}</p>
and the included template (tplB.twig)
<div>Content of tpl B</div>
{% set test = "now is tpl B" %}
What is the best way to set/change a variable in an included template and use it in the master template? How to use globals? Note that I can't use blocks and extends, and I'm not using Symfony.
Many thanks
EDIT
The real context is a very basic multilingual structure. For a page, I have one master template:
<h1>{{ i18n('mainTitle') }}</h1>
<h2>current language (fr, en): {{ ln }}</h2>
<!-- here a list of photos, but not in a foreach loop -->
<div>
<div>
<img src="/same/for/all/languages-a.jpg" alt="localized A" />
<span>localized A</span>
</div>
<div>
<img src="/same/for/all/languages-b.jpg" alt="localized B" />
<span>localized B</span>
</div>
<!-- etc. -->
</div>
It is a very small website, so I didn't created a complex structure with database, and I wanted to manage all this stuff in the template.
The thing is: how is it possible to display the right localized strings? What I thought about was to include a localized template, to separate concerns. Something like:
<!-- before the photos list -->
{% include ln ~ '/photos-list.twig' %}
<!-- then the photos list -->
And inside this template, I would have setted all the variables in the right locale, so I could use them in my photos list. (as explained in the first part of my question)
note that I have this structure for all others pages. Text content is separated in the locale folder, and each page has a master template (again, it's a very basic personal website)
What I did finally was to insert a hudge if statement before the photos list. If locale is fr, set variables with french texts, if it's en, set variables with english texts.
That does the trick, so I'm ok with that ^^
Why don't you move the second call of {{ test }} in tplB ( for this occasion ) ?
<div>Content of tpl B</div>
{% set test = "now is tpl B" %}
<p>and the variable is: {{ test }}</p>

create a twig filter that wraps output in HTML

I created a filter in Twig that wraps some HTML around the output. E.g.
{{ 'this is a "test"'|display }}
outputs
<div id="container">
<div id="content">
this is a "test"
</div>
<div id="toolbar">
edit
</div>
</div>
The dilemma is, I would like that subsequent filters are applied only on the original content, and not on the entire html. E.g.
{{ 'this is a "test"'|display|upper|e }}
outputs
&LT;DIV ID=&QUOT;CONTAINER&QUOT;&GT;
&LT;DIV ID=&QUOT;CONTENT&QUOT;&GT;
THIS IS A &QUOT;TEST&QUOT;
&LT;/DIV&GT;
&LT;DIV ID=&QUOT;TOOLBAR&QUOT;&GT;
&LT;A HREF=&QUOT;/EDIT.PHP&QUOT;&GT;EDIT&LT;/A&GT;
&LT;/DIV&GT;
&LT;/DIV&GT;
but as you can imagine, I would prefer the output like this
<div id="container">
<div id="content">
THIS IS A &QUOT;TEST&QUOT;
</div>
<div id="toolbar">
edit
</div>
</div>
Changing the filter order to
{{ 'this is a "test"'|upper|e|display }}
would work for the upper filter, but not for the escape filter, because it places itself always at the end of the filter queue. Also it should work with autoescape=true.
Reading the twig documentation, I can't find a standard way to do what I want. Has someone maybe tried something similar? Or has someone an idea to work around the problem?
Thanks in advance!
Try:
{{ 'this is a "test"'|upper|e|display }}
Filter your content in first place and then wrap it.

Symfony2: collection form field type with data-prototype

I have a Team to which I would like to add players (objects of Player). I've set up the form "type" classes correctly. Here's the relevant part of my view:
{% for index, player in form.players %}
<div id="template" data-prototype="{{ form_widget(form.players.get('prototype')) | e }}">
<span class="title">{{ index }}</span>
{{ form_row(player.name) }}
</div>
{% endfor %}
My problem is that data-prototype attribute doesn't include the span tag; it only contains the output of {{ form_row(player.name) }}. Is there a way to include the whole content of div#template in the data-prototype attribute?
This was bugging me too. I customized a field type and even made simple form types with a reduced fieldset (for more complex objects), but it just didn't feel right. I've come up with a solution that should do the trick :)
First - I think your <div id="team" data-prototype="..."> should be outside your loop.
Next, your prototype is just a form view object, so if you pass it to a template you can render fields by hand and customize the output. Note: autoescape has no effect on included content, so use 'filter escape'.
<div id="playerFields" data-prototype="{% filter escape %}{% include 'AcmeTeamBundle:Team:prototypePlayer.html.twig' with {'form': form.players.get('prototype')} %}{% endfilter %}">
Then in your prototypePlayer.html.twig, just render each field as you normally would in a form view.
<div>
<span class="title">{{ form_label(form.name) }}</span>
{{ form_row(form.name) }}
<span class="age">{{ form_label(form.age) }}</span>
{{ form_row(form.age) }}
{# render whatever else you like from your Form/PlayerType class... #}
<div>
My template has a different data structure to your question, but it should help :)
Cheers,
Chris
Deprecation Warning:
As of Symfony 2.1, .get() is deprecated and the above will not work. Replace form.players.get('prototype') with form.players.vars.prototype to fix this in later versions of Symfony.

Categories