Timber/Twig define Block - wordpress

I'm new to Timber/Twig, but so far I'm loving it!
I would like to have a folder with partials/components or "blocks" as Timber/Twig calls them, so I could have say a "video.twig" component, that can be reused through out the page.
1) How can I "register" the components/block in a folder?
2) How can I "feed" the component/block with data? I would like to do something like this:
{% block component DATA %}

The syntax in include looks like this:
{% include "comment.twig" with {comment:cmt} %}
It may work for the block too. Give it a shot.

Related

Timber get_posts in template/view

I have an ACF field that allows a choice of post types, these are then going to be put in a carousel. There could be any number as every module on the page is controlled by the admin users.
In the carousel template, I want to be able to get the recent posts for the selected post type. I can to this with:
{% set items = fn('get_posts', {'post_type': 'team' }) %}
Is there a way to do this without calling it as a function? I was thinking along the lines of:
{% set items = Posts(params) %}
Is this possible or is the function call the only/best way?
Thanks
Currently, what you want to do is not possible. You could use Timber::get_posts through the array notation to get an array of Timber posts instead of regular WordPress posts:
{% set items = fn(['Timber\Timber', 'get_posts'], { 'post_type': 'team' }) %}
But in the future, the recommended way to get posts will be to use Timber\PostQuery. In the upcoming version 2 of Timber, we will add a PostQuery function to Twig. This means that you’ll be able to do something like this:
{% for items in PostQuery(params) %}
{# Display item #}
{% endfor }
This would work well for simpler use cases. I’d also recommend what Luckyfella said, it may be better to not have this in Twig at all, but prepare everything in PHP and then pass the items on to the Twig view.

Symfony generate css

I need a little help.
Imagine that in database for every user have stored color of background.
Everytime when user login, first for that user in some folder is generated css file with name of id of user and included in html template.
I need help to understand how to generate css file ?
Thanks.
I Symfony with FOSUserBundle, you can use app.user to get the user in your twig files.
If you open a MySQL console and enter describe fos_user; then you will see all the fields you can use in your Twig file. So in your table you could store for each of the FOS users a color
Then in Twig you could use something like this:
{% if app.user %}
{% set backColor = app.user.color %}
{% else %}
{% set backColor = 'none' %}
{% endif %}
...
<body style="background-color:{{ backColor }};">
You get the idea...
You might want to figure out a way to store the color preference for the FOS user using a Symfony form. And then store preference in database. You can raise a separate question for that if you have difficulties - it should be easy.
Quite simple...
You need to generate a twig file for every user in your desired folder, and place "inline" CSS in it.
{% block css %}
<style>
.class {
parameter: {{ entity.value }};
}
</style>
{% endblock css %}
To generate the file, create a service, which you will call when a page is loaded.
It will have to first check if the file exist, if it does, it will read from it (no query to the DB), if not, it will generate the file, and read need data from DB.
Look at answer from me and Gopal on this page to know how to make a service How to use session in Symfony.
You sould be able to use it for your need... ;)
Also look at the Symfony Filesystem Component
file_put_contents() should help you write content of the file... ;)

TWIG variables between templates?

Beeing completely new to TWIG (it's also my first templating language) I have a little problem understanding the variables.
Heres what I need:
I have 2 layouts. One inheriting from the other.
On the first one I need to put an if on a div to add a class if on the second layout a variable is declared.
Thanks in advance.
Say in Symfony you write:
return $this->render('::index.html.twig', array('variable' => $somevar));
And 'index.html.twig' looks like this:
{% extends '::foo.html.twig' %}
{# some contents #}
and 'foo.html.twig' looks like this:
{{ variable }}
It should just work. If it doesn't work, post some code and errors here, and I'll see what I can do to help. Obviously this example is unrealistic, but all templates should have access to all variables passed from Symfony, in addition to the global ones and anything you define as Twig extensions.

Twig: render Symfony2 controllers which extend blocks in the parent template

Say I'm having a base template like this:
// Default/index.html.twig
{% block javascripts %}
<script>//some script</script>
{% endblock %}
<div>
{{ render(controller(MyControllerBundle:Default:header)) }}
</div>
{{ text }}
<div>
{{ render(controller(MyControllerBundle:Default:footer)) }}
</div>
And this renders controllers having these templates:
// Default/header.html.twig
Header content
{% block javascripts %}
<script>//some additional scripts from the header</script>
{% endblock %}
and
// Default/footer.html.twig
Footer content
{% block javascripts %}
<script>//some additional scripts from the footer</script>
{% endblock %}
Is it possible somehow to use the javascripts block from the rendered sub controllers in the parent template?
I want to have all javascripts cumulated in one place.
Rendering from bottom up with extending is no option here because the template consists of
multiple blocks that are rendered by different controllers.
Is this possible somehow? Or is there a better approach to this?
Anything is possible however design-wise it might not be a good idea.
The render tag is really useful when it comes down to scaling and it used as a way to isolate a request. Each render call is considered as a sub-request and a cache strategy can be applied to it.
I'd highly advise you to read this documentation about HTTP caching and especially the part that talks about Edge Side Includes (or ESI).
When you use the render tag, think of it as a module you want to include in multiple pages and eventually cache.
You shouldn't interact with the master request because the sub request is isolated for caching (depending on the place you embed the render tag, the master request will be different which means you might get some unexpected results).
First of all, I'd create a layout template that every other pages extends. The layout template will declare all the basic blocks (javascript, css, footer, header, <head>, <body> - you can abstract in more templates if you want).
If you have logic for your footer or header split them into Twig functions (or filters) and handle the logic in Twig but keep it light (if it's too complicated or too spaghetti that means there is another way).
Avoid having multiple Javascript or CSS files per page. If you have some css or javascript that appears on some pages but not all of them it's still probably a good idea to merge them into one file (less DNS calls on the client side and once it's cached it will be faster to load the page).
If you have a administrator.js kind-of file, then you could include it as a separate file but if most requests come from administrators then you might want to include it with all the other files.
If you didn't know you can combine assets (js or css) into one file: more info in the Symfony documentation.
I didn't answer your "how" question because I'd strongly advise you to not implement such a system however I believe I've shared good guidelines to make an informed decision.
when extending / rendering other content in TWIG you can call the parent block: http://twig.sensiolabs.org/doc/functions/parent.html
this means that you can leave default as it is and inside header / footer define
{% block javascripts %}
{{ parent() }}
{# other scripts #}
{% endblock javascripts %}
I would suggest that you have different block name for the footer - that way you can include scripts outside of the header.
Also, it might be best to keeps scripts in one place - that way you can use assetic rewrite's later down the line : http://symfony.com/doc/current/cookbook/assetic/asset_management.html#including-javascript-files
exactly what #Pazi says in the comment: Do you need a controller? It looks pretty simple to just include the template by itself, without using a controller.
You might use the include tag to include the subtemplates.
{% include 'MyControllerBundle:Default:header.html.twig' %}
For reusing the javascript block from the rendered sub controllers, you could create a base template that contains the javascripts block. Then extend that base template file in your header and footer. Or just including the base template in them should work, too.

How to reference twig for custom field types in dedicated bundle?

I am (still) trying to introduce http://xoxco.com/clickable/jquery-tags-input into a dedicated bundle. As far, I have a type as a child of text and a data transformer that converts comma-separated strings into arrays of Objects and vice versa.
Now I want to decorate the text field with the JQuery code linked above. As far as I understand, I have to define a block like
{% block manytomanycomboselector_widget %}
{% spaceless %}
{{ block('text_widget') }}
<script>
$(function(){
$("#{{ id }}").tagsInput();
});
</script>
{% endspaceless %}
{% endblock manytomanycomboselector_widget %}
in [MyTypeBundle]Resources/views/Form/fields.html.twig
Now, both the documentation and the answers for this question at StackOverflow state that I have to reference fields.html.twig somewhere either in the template that uses the form or in app/, but this doesn't seem to be necessarily for other field-type bundles, though I cannot see in their code why.
What do I have to configure inside the bundle besides this block in this file?
Also I didn't get where I have to put the css and js requirements for the header and how I deal with general requirements like jQuery itself.
I have the same issue & I resolve it by merging my field template in the twig.form.resources parameter.
So, in the DI extension of my bundle (MyBundle/DependencyInjection/MyBundleExtension.php), I add:
$container->setParameter('twig.form.resources', array_merge(
array('MyBundle:Form:field_widget.html.twig'),
$container->getParameter('twig.form.resources')
));
Be aware, your bundle must be registered after the TwigBundle in your AppKernel.
EDIT:
A form field is not linked to any JS or CSS. So, IMO, you have 2 solutions.
Firstly, you directly wrap your JS & CSS in your field template and your bundle stays stand-alone.
Secondly, you instruct final users that they need to include manually some JSS & CSS each time they use your field type.
The IoFormBundle & GenemuFormBundle uses the second solution like explain in their documentation.

Resources