First, let me start with the code I'm attempting to use:
{% if modal == true %}
{% block header %}{% endblock %}
{% block footer %}{% endblock %}
{% endif %}
What I'm trying to accomplish is to not show my header and footer blocks ONLY if the variable called modal is true. I also have this below the if statement:
{% block content %}
{{ dump(modal) }}
{% endblock %}
What happens here is that my override for emptying the header and footer blocks always runs regardless of if the value of modal is true or otherwise. So, I run this with modal passed in as false and the result is that the header and footer still don't show. The output of the dump command accurately shows true or false, but the condition always seems to evaluate to true in the if statement.
Can blocks not be wrapped in a conditional statement, or is there something additional I need to do to make this work?
Thanks for any help you can offer.
Define
{% block footer %}Some standard content{% endblock %}
in parent twig template.
Then in template where you want to decide if display content of footer you can do:
{% block footer %}
{% if not modal == true %}
{{ parent() }}
{% endif %}
{% endblock %}
If the modal is true - footer will be empty, if not - in footer will be printed "Some standard content"
Blocks don't care about any logic around it, as said in the documentation:
A block provides a way to change how a certain part of a template is rendered but it does not interfere in any way with the logic around it.
You should put that logic inside the block, not on the outerside, as you can see on the last example in that article.
Related
layout.twig
<main class="main">
{% block content %}{% endblock content %}
</main>
{% block footer %}{% endblock %}
page.twig
{% extends 'layout.twig' %}
{% block content %}
{#abc#}
{% block footer %}
{#123#}
{% endblock footer %}
{% endblock content %}
When I do this. Footer block renders twice. Once after content block and once the place it should be
NOTE: I simplifed the templates to make them more readable. The problem I see is I cannot use block inside another block. if I use it renders twice.
I have to use footer inside block content. I don't want to include extends and content in every page. Because it is same. I use something like below.
$tm['p'] = "{% extends '" . $layout . "' %}{% block content %}";
$tm['p'] .= $page;
$tm['p'] .= "{% endblock content %}";
$load = new \Twig_Loader_Array($tm);
$tw = new \Twig_Environment($load);
print $tw->render("p", $dat);
I think it's because you're nesting a previously define block insinde another previously defined one when overriding one. A block is usually used to define placement for output elements, so it's kind of wrong that you're placing footer inside content and where it should be actually means after content block, where you defined it in layout.twig, that's the right place according to your template files. If you need to override footer, you should simply do this outside of content block inpage.twig like this:.
{% extends 'layout.twig' %}
{% block footer %}
{#123#}
{% endblock footer %}
{% block content %}
{#abc#}
{% endblock content %}
Please note, the order of overridden blocks in page.twig is not important because you already made the decision about this in layout.twig.
Looking at your example, I think you want to place footer inside <main></main> not the content block. If so, you might need to modify layout.twig. Some changes like the following:
layout.twig
<main class="main">
{% block content %}{% endblock content %}
{% block footer %}{% endblock footer %}
</main>
Templates are useful when you want to design page layout and elements' placements, and later only change their content not their placements. So you should design your layout.twig according to your needs, and if you need an alternate layout, feel free to create an additional one. For example if you need two layouts, one with footer inside the content and one with footer outside the content.
And about not repeating extends and blocks (content as you pointed) in every page: In my opinion it is not a good idea to remove the extends tag from top of the page. It is good for reference, to know which page template is extending which layout. And what you are doing is writing template source code as PHP strings. This is not a good practice. I suggest you consider saving your templates in separate files like you did with layout.twig and page.twig and put all fixed content inside them. And if you find yourself repeating some code very often, then you might want to rethink about your templates structure because on of the main advantages of templates hierarchy is to avoid writing common code by reusing it.
I've been beating my head against this for a while, because while it's "easy" to do in raw PHP, the result is not extendable due to PHP's lack of decent built-in templating syntax. So I installed Twig assuming it would have a built-in explode function for iterating amongst blocks. But there seems to be no way of dividing content into an arbitrary number of subsections.
I considered using {% embed %}, but the document is to be styled according to which sections appear in the parent template. And in what order (which is variable; this is for a form with a lot of business logic in it.)
I've built the form in PHP and gotten it to work as a "very pretty" static page with easily an arbitrary number of subsections, all working and interactive regardless of which are displayed (based on e.g. user privileges), but templatizing it is the challenge.
The static (twigless) version relies on me exporting the parsed content to an array which can then be wrapped with the appropriately-styled div's for each visible section. This works, but requires me to use included html and object buffering which looks awful and would not be easy to maintain:
$content = include("form_content_html.php"); // return an object-buffered array
// I was including the escaped values here using if isset($data) and echo short tags.
foreach ($content as $section) { /* do something; */ }
$template = include("form_template_subsection.php");
$formview->addSubsectionTemplate($template);
echo $formview->addSubsection($content,$i++,$type);
// fill section of $type with $content[$i] if isset
echo $formview->addSubsection($content,$i++,$sometype);
// $types have different css class for certain effects
// etc. not the best approach.
(I need to escape all user / db content before binding it to the form values, but since the form fields are highly customized I separated them into their own content layer so that's the only layer that has content that needs to be escaped at present.)
So forget that, now I'm using Twig. (note: not Symfony2, as the project is on a shared webhost.)
I don't think there's a way of {%extend%}ing the parent template such that some of the child template blocks are "dropped into" the named parent template containers, with the rest ignored; which is what I'm looking for since that way I can put all the logic into the top level (which sections of the form to make visible, etc.) and pass in the values first.
Note that the style of the form sections is dictated by the structure of the parent template, not by the child content. E.g. section 1 may display content 1 and call css on content 2 in section 2; or section 1 and 2 with the same css may display different content.
If I split up the form into 15 content-only subtemplates, and then conditionally included them in the parent file, it would work. But that would seem to defeat the purpose of using a template engine? Although I suppose Twig makes it much easier to work with included files containing html snippets in this way, so let me know if that is a preferred solution.
Should I divide the content node up into numbered {% block1 %}, {% block2 %} etc. subsections and then renderBlock in my PHP view class?
If Twig had a {% section %}...{% section %} syntax allowing you to split up the template into chunks and then parse each chunk as an array of block elements... well, I half-expected that, and wish I could add one myself.
Is this a possible solution? From the Twig documentation:
Horizontal reuse is a way to achieve the same goal as multiple
inheritance, but without the associated complexity:
{% extends "base.html" %}
{% use "blocks.html" %}
{% block title %}{% endblock %}
{% block content %}{% endblock %}
The use statement tells Twig to import the blocks defined in
blocks.html into the current template (it's like macros, but for
blocks):
{# blocks.html #}
{% block sidebar %}{% endblock %}
Note: The use tag only imports a template if it does not
extend another template, if it does not define macros, and if the body
is empty. But it can use other templates.
Well, that's a bit thoroughly less than unclear.
(Does "it" refer to the imported template being able to use other templates, or does "it" mean a template can use more than one template, or both? and if the body is empty, does that mean the body of the imported block tag? If so then perhaps it is not a solution.)
Would it be possible to do something like this:
{# form_template.html #}
{% extends "form_content.html" %}
{% block section1 %}
<div class="{{ style1 }}"><div class="{{ style2 }}">etc.
{{ parent() }}
</div></div>{% endblock %}
Or this?
...
{# form.html #}
{% use "form_content.html" %}
{% for sections as i %}
{% block wrapper_elements %}{% block section{{i.name}} %}{% endblock %}
{% endblock %}
{% endfor %}
{# form_content.html #}
{% use "form_fields.html" %}
{% block section1 %}{% if field1 %}
Actual content here: {% block field1 %}{% endblock %} And here
{% else %} {% endif %}
{% endblock %}
{% block section2 %}More actual content here{% block section2 %}
But if so, how to iterate over the sections prior to calling each one in form.html?
I've found the solution, I think:
(From the Twig documentation)
The set tag can also be used to 'capture' chunks of text:
{% set foo %}
<div id="pagination">
...
</div>
{% endset %}
Ergo, set can be used to iterate over anonymous consecutive blocks:
{% set i=0, out=[] %}{# declare top scope #}
{% block initialize_content %}{# use once #}
{% set i=0, out=[] %}{# prevent dupes #}
{% set foo %}
<div id="pagination">...</div>
{% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}
{{ escape_variables_here }} ... more html
{% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}
{{ variables_all_scoped_to_same_context }} ... more html
{# so dividers can be moved "up and down" if necessary ... #}
{% endset %}{% set out=out|merge({ i: foo}) %}{% set i=i+1 %}{% set foo %}
{# ... like this. ^^a tag/macro could probably define this #}
{% endset %}{% set out=out|merge({ i: foo}) %}
{# or loop over i = 0..n or i = loop.index0 #}
{% endblock initialize_content %} {# end setter #}
{% block content %}
{% if key is defined and out.key is defined %}{{ out.key |raw }}{% endif %}
{# output top-scoped var (outputs nothing if setter not called) #}
{# the setter doesn't have to be in its own block, but that allows
the variables in the content to be redefined in setter's scope. #}
{% endblock %}
(cf. Setting element of array from Twig )
I'm creating a real estate website with the template Realia. This theme is based on Twig files and here's my problem. I have a front end submission where we can add a custom post ( a property ). I want to add a custom field to this form. The code which get and display the field is made and work because it is in a php file ;
<?php acf_form_head(); ?>
<?php acf_form( array(
'field_groups' => array(1943),
'form' => false,
) ); ?>
But now I want to save the data of my field and the button "Add my property" is in a Twig file..
Here's the button code
<div class="form-actions">
{% set value = wp.__('Save', 'aviators') %}
<input type="submit" class="btn btn-primary" value="{{ value }}">
</div>
{% endif %}
</form>
According to this documentation , the acf code is acf_form_head() but I dunno how to put it in my code. I try {{ acf_form_head() }}, {{ wp.acf_form_head() }} and some other sentence but nothing works... I tried to to find the "save" function which is on this php file but I don't know to edit it..
Please, could someone help me ?
Thank in advance
Jennifer O.
As far as i know wp-realia theme.
{{ }}
These tags are used for outputting some thing to browser or calling methods.
add wp. before calling any function wp. means that this functions is user defined or core function. if you call function without wp. prefix it means you are calling twig template function.
{% %}
These tag are used for calling core twig functions eg {% if my_var %}.
For your scenario you want to call acf_form_head() function in header to print css/js and necessary files in the header so you can make a block in the realia/templates/helpers/header.twig file in head tag eg:
{% block header_block %}{% endblock %}
then in your custom twig template file reference that block and put your content in it:
{# we tell our custom template to extends from layout.twig #}
{% extends 'layout.twig' %}
{# Add acf_form_head() function in our header block #}
{% block header_block %}
{{ wp.acf_form_head() }}
{% endblock %}
{# add this content to our content block which is define in layout.twig file #}
{% block content %}
{% if wp.have_posts() %}
{% for post in posts %}
{{ wp_query.the_post() }}
My custom field: {{ wp.the_field('my_custom_field') }}
{{ wp.acf_form() }}
{% endfor %}
{% endif %}
{% endblock %}
Hope it will help you.
I wanted to do something like this:
{{ include("tpl.html")|f }}
But that doesn't seem to work, it just printed tpl.html without any filtering, then I tried:
{% filter f %}
{% include "tpl.html" %}
{% endfilter %}
And it worked. I just wonder, why can't I use shorter one? Do I misunderstand something?
Thanks in advance.
Sorry for being that long to come back :-)
The fact is that the include function writes on the template.
If you do :
{% set s = include('FuzHomeBundle:Default:test.html.twig') %}
Which is not supposed to display something, you'll get the content of the file output anyway, and the s variable will be set to null.
If you do instead :
{% filter upper %}
{% include 'FuzHomeBundle:Default:test.html.twig' %}
{% endfilter %}
or
{% filter upper %}
{{ include('FuzHomeBundle:Default:test.html.twig' }}
{% endfilter %}
The filter tag will compile some code that control output buffer.
To apply a filter on a section of code, you have to wrap it with the filter tag:
{% filter f %}
...
{% endfilter %}
What you were trying originally is to filter a variable which in twig is defined by the double parenthesis:
{{ variable name|filter }}
to read more check out the twig documentation on filters here
I want to achieve the following thing:
I have a basic template for all of my pages, named "_page_base.twig". It contains the header and footer.
Then I have a Template for different areas of the page: "topic.twig", "section.twig" and "article.twig" - each of them extending the "_page_base.twig", thats working well so far.
Now I want to write my articles. I would love to save them as .twig file as well, since I can edit the complete markup in my editor and just upload it.
Since I can't say that my article files just extend "article.twig" (multiple inheritance is not possible) I could tell the "article.twig" that it should use blocks from my different article-content twigfiles.
The problem is: "use" statements have to be hardcoded!
My current solution is to add {% use "[PLACEHOLDER]" %} into the "article.twig" and then loading the template into a string, replacing the placeholder to the correct article-content.twig and then passing the whole thing to the template engine. What a mess.
Have you guys any idea for a better solution?
You can try with include tag. Since this tag accepts a dynamic name template to include, you just only need to define a variable which contains the name of article twig template.
{# on article.twig#}
{% set articles = ['someArticle.twig', ...] %}
{% for article in articles %}
{% include article %}
{% endfor %}
{# on someArticle.twig #}
... Article text ...
In the case of you need to customize some content inside of someArticle.twig you could stage the next level: embed tag. You should define a block tag inside of someArticle.twig, this block will be the placeholder to the custom values.
{# on article.twig#}
{% set articles=['someArticle.twig', ...] %}
{% for article in articles %}
{% embed article %}
{% block inside_text_article %}
... custom text ...
{% endblock %}
{% endembed %}
{% endfor %}
{# on someArticle.twig #}
... article text ...
{% block inside_text_article %}default values{% endblock %}
... article text ...
https://github.com/fabpot/Twig/issues/17 - no dynamic namespaces
LiipThemeBundle might be a solution:
http://symfony2bundles.org/liip/LiipThemeBundle
Unless I am not understanding the question, displaying a single article only requires that it also extends __page_base.twig.
In the case that you would need to display multiple articles, you could have a template dedicated to showing a list of articles which would also extend __page_base.twig and pass the article list to this template.