I'm having a hell of a time trying to get classes on my body element in D8. I'm using a custom theme and the code I have so far looks like this:
themename.theme
use Drupal\Component\Utility\Html;
/**
* Preprocess variables for html templates.
*/
function HOOK_preprocess_html(&$variables) {
$path_class = !$variables['root_path'] ? 'path-frontpage' : 'path-' . Html::getClass($variables['root_path']);
if (isset($path_class)) {
$variables['attributes']['class'][] = $path_class;
}
}
html.html.twig
{%
set body_classes = [
not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
]
%}
<body{{ attributes.addClass(body_classes) }}>
I get classes on my body element, but the NID is empty, reading, 'page-node' where I need it to read, 'page-node-NID'.
You have to replace HOOK with the name of your theme mytheme_preprocess_html otherwise Drupal will not call the hook.
Related
I'm using Symfony 6.1 with Twig on PHP 8.1. I've already set up my complete layout including fragments/partials/components or whatever we call reusable pieces of the layout at the moment. These fragments include certain kinds of navigations, quotes, tabs and so on which are always supposed to look and work the same and usually only receive a variable with the same name as an array with a few options.
This is how I'm embedding a YouTube-Video for example:
{% set youtube_video = { 'id': 'dQw4w9WgXcQ', 'title': 'Secret Video (unlisted)', 'language': 'en' } %} {% include 'fragment/youtube_video.html.twig' %}
Most of these fragments can be used multiple times on one page (= in the main template of the view or within the base template/s). Some of them however are supposed to be used only once and using them multiple times would create layout issues (e.g. a navigation for mobile devices with a specific CSS id).
For other fragments I would like to have a counter to add a CSS id in addition to a normal class:
<div class="fragment_video" id="fragment_video_{{ counter }}> ... </div>
The question now is how I can count within a fragment template like 'fragment/youtube_video.html.twig' how often this template has been used in that page already. I don't see any Twig functions or anything within the "app" variable for that.
Now I could create a custom Twig function "counter" and call that with with a unique name:
<div class="fragment_video" id="fragment_video_{{ counter('fragment_video') }}> ... </div>
or
{% if counter('fragment_video') == 1 %} ... {% endif %}
BUT how would I store the current count per given name? I don't want to use $GLOBALS in Twig or rather Symfony and storing that information in the session would keep it past the current request. Is there another solution available?
This is how it would look like as a Twig function:
public function getCounter(string $name): int
{
$name = 'twig_counter_'.$name;
if (isset($GLOBALS[$name])) {
++$GLOBALS[$name];
} else {
$GLOBALS[$name] = 1;
}
return $GLOBALS[$name];
}
As suggested by #DarkBee the instance of a TwigExtension object can use properties to keep track of some information:
/**
* #var array<int>
*/
private array $count = [];
...
public function getCounter(string $name): int
{
if (isset($this->count[$name])) {
++$this->count[$name];
} else {
$this->count[$name] = 1;
}
return $this->count[$name];
}
Is it possible to set a series of global properties (such as social media usernames) that are available to all page views in OctoberCMS rather than having them associated to one CMS page or Static Page at a time?
For example, being able to use {{ twitter_username }} in any template, but it wouldn't show up as a field in any page form on the backend.
UPDATE: this can be achieved by registering a Twig function using registerMarkupTags in your plugin:
use System\Classes\PluginBase;
class Plugin extends PluginBase
{
public function registerMarkupTags()
{
return [
'functions' => [
'globals' => function($var) {
switch ($var) {
case 'twitter_username':
return 'mytwitterusername';
}
return null;
},
],
];
}
}
In this case, calling {{ globals('twitter_username') }} from any template prints mytwitterusername.
Hmm yes better you need to add code to life-cycle method in layouts, so now page which are using that layout will have this info already loaded.
In layout code block you can use something like this
use RainLab\Pages\Classes\Page as StaticPage;
function onStart() {
$pageName = 'static-test'; // this will be static page name/filename/title
$staticPage = StaticPage::load($this->controller->getTheme(), $pageName);
$this['my_title'] = $staticPage->viewBag['title'];
$this['twitter_username'] = $staticPage->viewBag['twitter_username'];
}
now inside your cms page you can use this variable
<h1>{{ my_title }} </h1>
<h3>{{ twitter_username }} </h3>
let me know if it you find any issues
You could also use theme config file which gives you more flexibility rather than hardcoding the values in to the code block.
https://octobercms.com/docs/themes/development#customization
does anyone know now to create a custom view type for ez platform? The default 3 have been exhausted and we need a new one for 'link'
Alternatively, does anyone know how to use the render( controller( with a custom template as this would also resolve out block right now.
Basically, we have a multi-relational field in a content object used and we need to print links to all the related contentIds, path works great but we cannot find a way to extract the name of the content object for the link without doing some fairly funky tpl logic of passing in params.
EG: As a hack for now we can pass in "embed_type" as a custom param with the render(controller("ez_content:viewAction" to pull in an alternate view for the content object for a specific content type and view type.
{% if embed_type is defined %}
{% include "embed/#{embed_type}.html.twig" %}
{% else %}
<h1>{{ ez_field_value( content, 'name') }}</h1>
{% endif %}
However, this is very ugly and all we really want to do is use 1 template for all content types, so all we need to do is loop through the relational field and print links (as the only thing available in the content field: "destination ids"). I am sure there used to be this option in the docs but i cannot find it anymore eg:
{% set links = ez_field_value( footer, "first_links_row" ).destinationContentIds%}
{% for id in links %}
{{ render(controller("ez_content:viewAction", {"contentId": id, "template": "link.html.twig"})) }}
{% endfor %}
Where the link.html.twig would simple print the link:
<a href="{{ path( "ez_urlalias", {"contentId": id} ) }}">
{{ ez_field_value( content, "name" ) }}
</a>
If using a custom tpl is not possible with the render (controller ( helper then a new custom view type would also fix this issue, but i cannot find documentation for either.
You can create a twig function that would do that. We have something like this:
Definition:
new Twig_SimpleFunction(
'content_name',
array($this, 'getContentName')
),
Implementation:
public function getContentName($content, $forcedLanguage = null)
{
if (!$content instanceof Content && !$content instanceof ContentInfo) {
$contentInfo = $this->repository->getContentService()->loadContentInfo($content);
} elseif ($content instanceof Content) {
$contentInfo = $content->contentInfo;
} else {
$contentInfo = $content;
}
return $this->translationHelper->getTranslatedContentNameByContentInfo($contentInfo, $forcedLanguage);
}
which enables you to provide either content id, content info or content itself, and it returns translated content name
I import the Bundle AliDatatableBundle on github following the doc step one by one except the part $ bin/vendor install in the installation because with Symfony2.6, there's no need to do this.
When I create the function in my controller, and the rendering in my twig, I have this error:
An exception has been thrown during the rendering of a template ("No
instance found for datatable, you should set a datatable id in your
action with "setDatatableId" using the id from your view ") in
MySpaceGestionPatrimoinesBundle:Batiments:indexBatiments.html.twig at
line 37.
Here's the code for the controller:
/**
* set datatable configs
*
* #return \Ali\DatatableBundle\Util\Datatable
*/
private function _datatable()
{
$controller_instance = $this;
return $this->get('datatable')
->setDatatableId('batiments')
//->setEntity("MySpaceDatabaseBundle:Batiments", "b")
// replace "XXXMyBundle:Entity" by your entity
->setFields(
array(
"Nom" => 'b.nom',
// Declaration for fields:
"Reférence" => 'b.referencebatiment',
// "label" => "alias.field_attribute_for_dql"
"Ensembles" => 'b.ensembles',
"_identifier_" => 'b.id')
// you have to put the identifier field without label. Do not replace the "_identifier_"
)
//->setWhere(
// set your dql where statement
//'x.address = :address',
//array('address' => 'Paris')
//)
//->setOrder("x.created", "desc")
// it's also possible to set the default order
->setHasAction(true);
// you can disable action column from here by setting "false".
}
/**
* Grid action
* #return Response
*/
public function gridAction()
{
return $this->_datatable()->execute();
// call the "execute" method in your grid action
}
/**
* Lists all entities.
* #return Response
*/
public function indexAction()
{
$this->_datatable();
// call the datatable config initializer
return $this->render('MySpaceGestionPatrimoinesBundle:Batiments:indexBatiments.html.twig');
// replace "XXXMyBundle:Module:index.html.twig" by yours
}
And then the code for my twig:
{% extends "MySpaceWelcomeBundle::layout.html.twig" %}
{% block content %}
<div class="jumbotron">
<h4><u>Rechercher un bâtiment et ses affectations spécifiques:</u></h4>
<br>
<div>
{{ datatable({
'id' : 'batiments',
'js' : {
'sAjaxSource' : path('mySpace_formulaire_recherche_batiments')
}
})
}}
</div>
</div>
{% endblock %}
I really don't understand, someone could help me to fix this?
I have already clear the cache, install assets and took over again from the beginning the doc, I do not understand.
Thank you in advance.
It seems like everything was good. I can't see the problem here, if you followed the doc of aliBundle. Try using the Jquery datatable here, the installation is easier I think and better for your project if it's to manage your entities in Symfony.
If you have questions for Jquery DataTables, don't hesitate to ask, I'm using it for a Symfony project too.
I am not very familiar with TWIG templates and I need to add a bit of logic to a template file based on the URL. I know how to do it in PHP, but am sort of lost here.
I can get the full URL using {{ app.request.uri }} but what I am really trying to do is something like this:
$uri = $_SERVER['REQUEST_URI'];
if ($uri == "/page1" ||strpos($uri, "/page1/") !== false) {
echo " id="item1";
}
Is something like this possible? Thanks
you could try it with the in Operator, but routing logic should be outside of the template file
you should do this logic in your Controller and set a variable "true".
controller.php
$uri = $_SERVER['REQUEST_URI'];
$item = null;
if ($uri == "/page1" ||strpos($uri, "/page1/") !== false) {
$item = "id=item1";
}
$this->render('MyBundle:mytwig.html.twig',array("item"=>$item));
mytwig.html.twig
{% if item %}
{{ item }} is only written if item is set
{% endif %}
This kind of logic does not belong in templates. Leave that code outside of your template and assign the result to a variable (instead of directly echoing it). Pass that variable to the Twig template. Output the variable.
Templates are exclusively for presentation, not for containing complicated logic code.