what exactly is haswidgets and widgets in bolt (or twig rather )? - twig

I was just going through the Default theme of bolt CMS, and i came actoss the following lines of code:
{% if haswidgets('aside_top') %}
{{ widgets('aside_top') }}
{% else %}
I googled twig haswidgets and also twig widgets , but i could't find anything.
can somebody explain what these two methods are ? and what exactly do they do ?

They are a feature of Bolt. Extensions can push content to specific places in the backend and also to some places in the frontend, as long as the theme supports that. They are called widgets. the haswidgets() and widgets() twig functions are for checking and displaying them.
You can find more info here https://docs.bolt.cm/3.1/templating/widgets and here https://docs.bolt.cm/3.1/extensions/intermediate/widgets

Related

Which twig template to extend for a custom theme?

I apologise before for a long explanation - I have a hard time explaining it to myself.
I run Shopware 6 locally and using the development template. I needed to remove the product number from the product detail page. So, I override the twig template "buy-widget.html.twig":
{% sw_extends '#Storefront/storefront/page/product-detail/buy-widget.html.twig' %}
{% block page_product_detail_ordernumber_container %}
{% endblock %}
Works as expected - if I have not change the layout template for the product, but using the Shopware default.
But, when I change the layout to a custom layout (the only difference is that the image thumbs is bellow the main image) the product number is back?!
Checking with the Symfony Profiler, I can see that it's now another twig template (from a folder "component/.." responsible for displaying the product number.
Question: Am I correct to assume that I should extend the twig template from this component folder if I'm using a custom layout? I have not find anything in the docs about these "small" details. And if one need to be sure that a custom theme works in every case, you must make the changes (using sw_extends) in two files?
/ Magnus

Grav CMS: how to show/hide parts of the page depending on conditions?

The Grav's documentation clearly describes how a whole page or a folder could be hidden from unregistered users. It also describes how a whole page could be seen only by particular user groups.
But what about pieces of a page, let's say, some links or a private info I want to show on some conditions?
Ok, for registered users I found a snippet at Login plugin docs:
{% if grav.user.authenticated %}
content for registered users goes here
{% endif %}
But going wider - how can I show/hide pieces of a particular page depending on some custom logic in PHP code, i.e. not necessarily user related?
I'm thinking about a twig/shortcode plugin, something like:
{% if some.custom.condition.or.PHP.function %}
hidden content goes here
{% endif %}
or
[hidden_if_something] hidden content goes here [/hidden_if_something]
But not sure how exactly this should be implemented. So working examples would be appreciated. Thanks.
There is a recipe in the Grav documentation here. This provides an example of how to render the output of a PHP code result in a twig template.
In the example they create a plugin, and implement a twig extension providing access to a php function. They can then simply call that php function like in a twig template.
{{ example() }}
Following that example, you can implement whatever logic you would like in php, and call the function in a twig if statement.
{% if example() == true %}
your conditional output
{% endif %

Symfony Server crashes when extending FOSUserBundle's default template layout.html.twig

I am trying to get the basic user login running from the FOSUserBundle.
I am using Symfony 3.0.6.
I followed the description to setup everything from the FOSUserBundle:
https://symfony.com/doc/master/bundles/FOSUserBundle/index.html
DB is up and running everything seems fine except I cant figure out how to override the layout.html.twig from the FOSUserBundle.
I followed this description for achieving that:
https://symfony.com/doc/master/bundles/FOSUserBundle/overriding_templates.html
I now have a file "layout.html.twig" in the folder "Resources/FOSUserBundle/views" with the content being the same as in the last link provided above.
This leads to the following error:
Unable to find template "layout.html.twig" (looked into:
[somePathInfo]) in FOSUserBundle::layout.html.twig at line 1.
Now I changed the first line in the "layout.html.twig" Template to be
{% extends 'FOSUserBundle::layout.html.twig' %}
And this then leads to the symfony server to crash stating
>php bin/console server:run -v
[OK] Server running on http://127.0.0.1:8000
// Quit the server with CONTROL-C.
RUN "C:\xampp\php\php.exe" "-S" "127.0.0.1:8000" "[PATH]\myProject\vendor\symfony\symfony\src\Symfony\Bundle\FrameworkBundle\Resources\config\router_dev.php"
RES -1073741571 Command did not run successfully
[ERROR] Built-in server terminated unexpectedly.
I am stuck here...
Any ideas are very welcome.
EDIT: The FOSUserBundle installed by the composer (which I use through the current PHP-Storm plugin) is installed at the path:
[projectPath]\vendor\friendsofsymfony\user-bundle\Resources\views\layout.html.twig
In the docu however allways "FOSUserBundle" only is mentioned and I don't know how to figure out if that mapping fits to the path in my project.
Any hints for this issue are very wellcome as well.
When you override standart FOSUser layout you need to place your layout into app/Resources/FOSUserBundle/views/layout.html.twig. great, you did this. it's just a layout, it should not extend standart FOSUser layout, so remove line {% extends 'FOSUserBundle::layout.html.twig' %}. But usually developers make one base layout, in my case it is \app\Resources\views\base.html.twig, so if I want to override fosuser layout I will have in app/Resources/FOSUserBundle/views/layout.html.twig something like this
{% extends 'base.html.twig' %}
{% block title %}User Management{% endblock %}
{% block content %}
{% block fos_user_content %}{% endblock %}
{% endblock %}
In first line you extend your base layout not FOSUser. You may not extend something, maybe you have separate complete layout for this template.
The crash does make sense.
When you write:
{% extends 'FOSUserBundle::layout.html.twig' %}
The Symfony will first try to load app/Resources/FOSUserBundle/views/layout.html.twig. Failing to find the file will revert to similar path but inside the vendor directory. And if you are trying to extend FOS's template from within your FOS overriden template, that would create recursive loop:
app/Resource/FOSUserBundle/views/layout.html.twig
^^ extends
app/Resource/FOSUserBundle/views/layout.html.twig
^^ extends
app/Resource/FOSUserBundle/views/layout.html.twig
....
and so on...
So, this is not a way to solve the problem.
Make sure that your template is well placed in your app directory and not your bundle, as Denis Alimov suggested in a comment.

Wrap contextual html around a specific twig variable {{ product.name }}

I want to automatically wrap some html, lets say <span data-id=".."> when I call {{ product.name }} in my twig template.
So when in a twig template, I use {{ product.name }}, I want the output to be: <span data-type="product" data-id="8" data-prop="name">My product name</span>. I cannot use twig filters or macros, since I really need the template syntax to be {{ product.name }}, so the end-user (template designer), does not have to care about it.
The reason I need this is because I am building an on-page editting tool for twig templates, so I need to know the contexts of those variables from within HTML.
I have tried to override the Compiler that the Twig_Environment uses, but I cannot seem to alter the output of the twig variable node.
How can I do this?
EDIT
I wanted to mention that I need this to use the {{ product.name }} syntax, since other designers will work with those templates outside of Symfony 2. I want to make almost all twig variables editable in the front-end, so a solution with filters or macros can indeed work, but it kills the usability and readability of the platform I am writing. There is no public API currently in twig that can achieve what I want, that is why I am fiddling with the twig compiler. I do not have the required knowledge of the Twig internals to achieve this. If someone could point me into a direction that would be great!
UPDATE 2
I have found a place where I can achieve what I want. Every GetAttr node is compiled to $this->getAttribute($someContext, "property"). So if I can change the subclass of compiled twig template, I can achieve what I want. By default all twig templates extend from Twig_Template. I want to extend this method.
How can I change the subclass of all compiled twig templates?
UPDATE 3
I've found a way to use my own base class for all compiled twig templates. I can simply set it as an option on the twig environment, see this link. I hope to get it working tomorrow and I will post a proper answer on how I solved it all together. Not sure how I will handle escaping, since that will happen after the $this->getAttribute() is called.
I think macros are the best candidates for those kind of wrappings.
For example:
main.twig
{% import "macros.twig" as macros %}
{{ macros.display_product(product) }}
macros.twig
{% macro display_product(product) %}
<span data-id="{{ product.id }}" data-prop="name">{{ product.name }}</span>
{% endmacro %}
Context
product:
id: 8
name: My Georgeous Product
Result
<span data-id="8" data-prop="name">My Georgeous Product</span>
See fiddle
I've solved it by wrapping the PrintNode that is created when parsing a VAR_START token (inside the twig parser) with my own EditablePrintNode. In that node I traverse the expression that is compiled by the print node and get the necessary property path and pass that as an argument to a wrapper function around the default twig escape function that is compiled by the PrintNode.
I suggest to write a custom filter. You can find the doc here about how to write and configure in your environment
// an anonymous function
$filter = new Twig_SimpleFilter('my_custom_product_filter', function ($product) {
return '<span data-id="'.$product->getId().'" data-prop="name">'.$product->getName().'</span>';
});
You need to register as described in the doc
then you can use as follow:
{{ myProduct|my_custom_product_filter}}
Hope this help

Yii 2 registerJs in twig templates

In the Yii 2.0 guide it says you can register Javascript code in a twig template like this:
{registerJs key='show' position='POS_LOAD'}
$("span.show").replaceWith('<div class="show">');
{/registerJs}
Tried this but it will simply output the whole snippet {registerJs ... as text on the page without adding it to the page's Javascript Code.
Similar commands like registerJsFile or registerCss aren't working either.
Am I missing something? Thanks!
EDIT:
As Mihai P. noted below, {registerJs} is syntax for Smarty templates. So, the question is: is there a similar way to register inline JS in Twig templates? The documentation only mentions registering assets.
You can use this in your Twig template, which is the current view, to call registerJs.
{% set script %}
var app = new Vue({
el: '#vue-widget',
data: {
message: 'Hello Vue!'
}
})
{% endset %}
{{ this.registerJs(script,4,'vue-widget') }}
The question is 3 years old, I put it here for someone runs into a similar problem.
You can use this in the Twig template with View constant like below:
{{ this.registerJs('$("span.show").replaceWith(\'<div class="show">\');', constant('\\yii\\web\\View::POS_HEAD')) }}
And, you can also call registerJs inside the Yii2 controller, which I think it makes the code cleaner
$this->getView()->registerJs('$("span.show").replaceWith(\'<div class="show">\');', \yii\web\View::POS_HEAD);
Your example is copied from the smarty section not the twig. There are some examples in the twig section that you might want to try.

Resources