Twig add attribute with value in a variable - drupal

Using Drupal 8
I want to print out a field's content into the src attribute. I have the following template for my view:
<div class="videoWrapperHD">
<iframe width="560" height="315" src="{{ rows[0].content | raw }}"
frameborder="0" allowfullscreen>
</iframe>
</div>
But the iframe gets filled with my own site's "Page Not Found" page instead of the Youtube Video because Twig prints out a whole lot of debug comments before and after printing the variable rows[0].content.
Is it possible to disable the debug comments for a specific field? I don't want to have to be disabling/enabling debug to make sure it works as expected.
I also tried using {{ attributes.setAttribute('src', {{ rows[0].content }} ) }} , but no dice.
Another failed attempt was:
{% set iframe_src = rows[0].content %}
<div class="videoWrapperHD">
<iframe width="560" height="315" {{ attributes.setAttribute('src', iframe_src) }}
frameborder="0" allowfullscreen></iframe>
</div>
My last idea was this:
{% set url = rows[0].content | raw %}
{% set iframe_src = 'src=' ~ url %}
<div class="videoWrapperHD">
<iframe {{ iframe_src }} ></iframe>
</div>
But it prints out src=Array

try this
in your .theme
function your_theme_preprocess_field(&$variables, $hook) {
switch ($variables['element']['#field_name']) {
case 'field_iframe_src':
$variables['iframe_src'] = $variables['items'][0]['content']['#context']['value'];
break;
}
}
in your twig
<iframe width="560" height="315" src="{{ iframe_src|raw}}"
frameborder="0" allowfullscreen>
</iframe>

Sounds like something that would have to be done in the preprocessor. If you grab it from the node object, instead of the content array it shouldn't get all that debug nonsense.
You should also make sure that your URL isn't doing something evil... if you only expect youtube videos you should do some checking to make sure that that is what you get from the content.
https://api.drupal.org/api/drupal/core%21modules%21node%21node.module/function/template_preprocess_node/8.2.x
See $node, find the value, sanitize/double check it's value, then set it to $variables['variable_name'] and you should be able to use it in twig with {{variable_name}}

The answer is in another question, I'm pasting it here in case that one gets deleted. The author of the following answer is #4k4
field.content is the rendered field. And in views that means it is no longer a render array, but the finally rendered markup. So this is very problematic to use it as a class name, not only because of twig debug.
Better use the row data, where you find the entity object with the field data from the database. Use clean_class to escape it for using it as a class name:
{{ row._entity.field_myfield.value|clean_class }}

Related

Get the domain name in Twig/Timber to output in WordPress?

When I have an error in my custom WordPress theme I would like to output the webmaster email address which would be webmaster#mydomainname.com but I am a bit baffled on how to do this in Twig/Timber in the most straightforward way: <p class="text-danger fw-bold">PAGE ERROR - Please contact Webmaster at webmaster#{{ #notsure# }}</p>
webmaster#{{ site.url }} just outputs: webmaster#https://mywordpress.local which obviously won't work.
UPDATED: To get by I am using webmaster#{{ site.url[8 :] }} as that strips away the https:// and outputs webmaster#mywordpress.local but seems there should be a cleaner way somehow?
There are two ways to do this:
You can use Advanced custom field. Make a email field and then print that value inside the twig file. Inside advanced custom field, you can add any email you have no need to extract a domain name. For more information follow this reference: https://timber.github.io/docs/guides/acf-cookbook/
Second method is the way you doing is correct but you need to split domain name from site.url using slice method:
{% set website = "https://mywordpress.local" %} //
//calcualting length of string
{% set lengthOfWebsite = website|length %}
//using length here to split the string accordingly. 8is for split "https://" from actual domain name.
{% set domainName = website|slice(8,lengthOfWebsite) %}
webmaster#{{domainName}}
For the first line of code in your case will be:
{% set website = site.url %}
For the last line
webmaster#{{domainName}}
can also be replaced by:
{% set actualDomainName = 'webmaster#' ~ domainName %}
{{actualDomainName}}

Drupal 8 twig multiple images field

I have a content type with a field field_gallery that has multiple images.
I would like to get all these images printed in my twig file: page--front.html.twig. So i want to get these images in my frontpage and not only in their nodes. So far i could get them in their nodes with
{{ file_url(node.field_image.entity.fileuri) }}
but not somewhere else (of course since its using node). Is this possible?
Should i create a preprocessor function for page? Any guidance for this?
Yes, This is possible. This question is have two sub tasks :
1) Creating page--front.html.twig file
For creation of this twig file, you'll have to clone file i.e. page.html.twig and rename it with page--front.html.twig
2) Fetch Raw values of Image fields
You need to update code in my .theme file:
function THEMENAME_preprocess_node(&$variables) {
if ($variables['node']->field_image->entity) {
$variables['image_url'] = $url = entity_load('image_style', 'medium')->buildUrl($variables['node']->field_image->entity->getFileUri());
}
}
Then in page--front.html.twig file I have this:
{% for item in image_url %}
<div class="featured-thumb">
<img src="{{ item }}"/>
</div>
{% endfor %}

Drupal 8 - reach node/content needed variables in view

New user of D8 : my problem is to access to fields in a view or even in general with Drupal 8.
As we could do with ACF in Wordpress.
a {{ kint() }} crash my chrome but works with Firefox to explore the content var.
Unfortunately I do not managed to find and use fields' variables in my view.
I create a new view, which actually display the last three articles. These are well displayed in ugly list but I want to extract fields to put them in a custom html integration.
I create and use a new template for the view :
x node--view--liste-des-actualites--page-2.html.twig
In a custom parent :
x node--page-accueil.html.twig
But when I try to kint() content in my node--view--liste-des-actualites--page-2.html.twig, I have the custom field of the page (Page accueil) and can't find the article's one.
I managed to do it in my custom page but not in this view.
{%
set classes = [
'node',
'node--type-' ~ node.bundle|clean_class,
node.isPromoted() ? 'node--promoted',
node.isSticky() ? 'node--sticky',
not node.isPublished() ? 'node--unpublished',
view_mode ? 'node--view-mode-' ~ view_mode|clean_class,
'clearfix',
]
%}
{{ attach_library('classy/node') }}
<article{{ attributes.addClass(classes) }}>
<div{{ content_attributes.addClass('node__content', 'clearfix') }}>
{{ content }}
<div class="col-lg-4 col-md-4 col-sm-4 col-xs-4">
<a href="{{ LINK_VAR }}" class="bloc-type">
<div class="categ categ_projet">{{ CATEGORY_VAR }}</div>
<div class="img"> <img src="{{ IMAGESRC_VAR }}" alt=""> </div>
<span class="wrapper">
<p class="date">{{ DATE_VAR }}</p>
<h3>{{ TITLE_VAR }}</h3>
</span>
</a>
</div>
</div>
</article>
EDIT
I managed to guess some fields but this is definitely not a good way to find variables..
{{ node.label }} + {{ content.field_tags }} (But I do not want a rendered one, I just want the text/value)
if you use kint(); to debug large arrays can crash your browser.
I would suggest to use the devel module https://www.drupal.org/project/devel. With devel you can debug your arrays inside of the Drupal8 UI for each content type, block or view.
In my case i use the UI of devel (additional tab on each content). in the module settings, you can chose how devel debugs, the error handling and the output.
As the OP commented it is possible to use a preprocess to display the array on your site:
function <themename>_preprocess_page(&$variables) {
dpm($variables);
}

for in twig templates of drupal is behaving strangely

I am trying to show only upcoming events from a list of events. Below is how I have tried to display.
<div class="row">
{% for item in items %}
{% if item.content['#node'].field_event_type.getValue()|first.value == 'upcoming' %}
<div class="col">{{item.content}}</div>
{% endif %}
{% endfor %}
</div>
But the output rendering is, the second event is displaying after the row div like below. I don't understand how this is happening as the for loop is inside the row div
<div class="row">
<div class="col"> content </div>
</div><div class="col"> content </div>
Expected output
<div class="row">
<div class="col"> content </div>
<div class="col"> content </div>
</div>
Twig does lots of things:
loading (open your Twig content)
parsing (create a parse tree from your Twig content)
compiling (browse that tree to create a php file)
caching (store the php file somewhere to avoid recompile it next time)
executing (execute the generated php file)
When a {% for %} is detected during parsing, Twig calls the token parser recursively until it finds {% endfor %} and builds a token tree. In your case, it would look like:
root
|
--- string
|
--- for
| |
| --- if
| |
| --- string
|
--- string
Then, Twig compiler crosses over that tree recursively and generates the corresponding php code. In that way, the following Twig loop:
{% for i in 1..5 %}
Value = {{ i }}
{% endfor %}
Compiles to this in PHP:
// line 1
$context['_parent'] = $context;
$context['_seq'] = twig_ensure_traversable(range(1, 5));
foreach ($context['_seq'] as $context["_key"] => $context["i"]) {
// line 2
echo "Value = ";
echo twig_escape_filter($this->env, $context["i"], "html", null, true);
}
$_parent = $context['_parent'];
unset($context['_seq'], $context['_iterated'], $context['_key'], $context['i'], $context['_parent'], $context['loop']);
$context = array_intersect_key($context, $_parent) + $_parent;
As you can see, a {% for %} is no more than a simple foreach and as Twig tokens are stored into a tree, it is by design not possible to display contents located below a pair of open/close tags.
The only possibility I can see is that one of the tag you're using in Twig is playing with output buffering, and one of the methods you're using in your loop breaks the ob stack (like a ob_get_clean() without any ob_start() for example, that have been open previously).
My advice is to grep your twig file name into your cache directory (eg: grep -Ri 'test.twig' cache/) in order to see that file compiled to PHP, to understand exactly what it does, and debug it.
Instead of filtering your content in twig, filter the results in your Drupal view.
In the "filter criteria" on your view, select the field_event_type field and set it "is equal to" and select/add 'upcoming' as the option.
If you filter in the view, you don't have to mess with the twig template.

Set html id attribute dynamically in Twig

I'm trying to set the id of an element using a variable in a Twig template (not a form) without using JavaScript.
The template code looks like this:
{% set show_id = 'show' ~ entity.id %}
{{ dump(show_id) }}
<div class="event_option" id="show_id">
show
</div>
The show_id variable is dump'ed correctly, but when I try to use it as the html id in id="show_id", the id that gets assigned to the div is the string "show_id", and not the actual value of show_id. I get the same result when no parenthesis are used when assigning the html id, as in id=show_id. How can I access the Twig variable when assigning the html id attribute?
You should enclose with double bracket to tell Twig to print the value of variable
<div class="event_option" id="{{show_id}}">
show
</div>

Resources