Things I Learned from the DrupalTwig Slack: Volume 2

Things I Learned from the DrupalTwig Slack: Volume 2

Things I Learned from the DrupalTwig Slack: Volume 2

Welcome to Volume 2 of my adventures in learnings from the DrupalTwig Slack, a resource that continues to be the best source of (frontend) knowledge for Drupal. Again, if you haven't joined, do so. (Volume 1 is here.)

And without further ado, here's some things I've learned (or helped others to learn):

1) Check if a user has a permission

@ceaucari wanted to check if a user had permission to do something, and if so certain code would execute. Like everything, it's simple when you know the answer.

{% if user.hasPermission('administer nodes') %}
  ... do something
{% endif %}

Thanks to @hj for providing it.

Check if a user has a permission in Drupal Twig

2) How to print comments separate from fields in a node template

Print comment and comment form fields separately

This one was fun, for no other reason than I was up late having a bottle of beer on a Friday evening when my friend Preston So needed help printing comment fields in nodes (mid-afternoon his time). The specific request was to get the variable for a custom comment type that he wanted to print in a node template. After some late night (by European time zones) investigation, and kinting the hell out of {{ content ... }} I came up with a variable to show the custom comments and another to show the custom comment form.

  {% set custom_comments = content.field_custom_comments.0.comments %}
  {% set custom_comments_form = content.field_custom_comments.0.comment_form %}
  {{ custom_comments }}
  {{ custom_comments_form }}
Print comments and form in Drupal Twig

3) Add body class based on field value

Sometimes you have a field on a content type and you want to take the value of that field and add it as a body class in your HTML. We often do this on our websites so users can choose a background colour for the header on a node-by-node basis, or choose how wide a structured content item should be, for example. This is exactly what @danny_englander needed to do:

Add body class based on field value

Our solution for this was to use THEME_preprocess_html, using code such as this:

function weather_preprocess_html(&$variables) {
  // Get the value of the "Site Section" field and add it as a class on <body>
  // This allows us to have specific colours used within each site section
  // _as long as_ each node is tagged with a site section.
  $node = \Drupal::routeMatch()->getParameter('node');
  if ($node instanceof \Drupal\node\NodeInterface) {
    if ($node->field_site_section) {
      $section_style = $node->field_site_section->value;
      $variables['attributes']['class'][] = $section_style;
    }
  }
}
Print value of node field in body class in Drupal 8

4) Override a twig template from a module using another module

Sometimes modules provide templates with them, such as paragraph.html.twig in the paragraphs module. Sometimes you want to override that template with a custom module (rather than your theme) so the override is available to all themes being used (if you were using themekey for example, or Seven for site editing and your custom theme for the frontend).

This is what Jim Birch needed to do. And after asking the question he found a solution himself and posted it to the Slack. Here's the code:

/**
 * Implements hook_theme_registry_alter().
 */
function bootstrap_paragraphs_theme_registry_alter(&$theme_registry) {
  $module_path = drupal_get_path('module', 'bootstrap_paragraphs');

  // Use the templates in the boostrap_paragraphs module.
  $theme_registry['paragraph__default'] = $theme_registry['paragraph'];
  $theme_registry['paragraph__default']['path'] = $module_path . '/templates/paragraph';
  $theme_registry['paragraph__default']['template'] = 'paragraph--default';
  $theme_registry['paragraph__accordion'] = $theme_registry['paragraph__default'];
  $theme_registry['paragraph__accordion']['template'] = 'paragraph--accordion';
  $theme_registry['paragraph__carousel'] = $theme_registry['paragraph__default'];
  $theme_registry['paragraph__carousel']['template'] = 'paragraph--carousel';
  $theme_registry['paragraph__modal'] = $theme_registry['paragraph__default'];
  $theme_registry['paragraph__modal']['template'] = 'paragraph--modal';
  $theme_registry['field__paragraph__field_column_content'] = $theme_registry['field'];
  $theme_registry['field__paragraph__field_column_content']['path'] = $module_path . '/templates/field';
  $theme_registry['field__paragraph__field_column_content']['template'] = 'field--paragraph--field-column-content';
}
Override a twig template from a module using another module

ADDED BONUS EXTRA FEATURE: In true Drupal fashion, a co-developer of his found an even better solution. Here's that code:

/**
 * Implements hook_theme().
 */
function bootstrap_paragraphs_theme($existing, $type, $theme, $path) {
  return [
    'paragraph__default' => [
      'base hook' => 'paragraph',
    ],
    'paragraph__accordion' => [
      'base hook' => 'paragraph',
    ],
    'paragraph__carousel' => [
      'base hook' => 'paragraph',
    ],
    'paragraph__modal' => [
      'base hook' => 'paragraph',
    ],
    'field__paragraph__field_column_content' => [
      'base hook' => 'paragraph',
    ],
  ];
}
Override a twig template from a module using another module

5) Save render array as variable

This blew my mind. I always thought of saving strings or fields as variables, but as @lauriii pointed out you can save render arrays as variables as well - makes sense when you think about it!

{% set variable_name %}
  {% for item in national_office_address %}
    {{ item.address_line1 }}
    {{ item.postal_code }}
    {{ item.country_code }}
  {% endfor %}
{% endset %}
Save render array as variable

6) Override all CSS from a library except one file

Say you have a library of CSS which contains loads of CSS you don't need and just a little bit you do - maybe you want to override everything in classy except one file, well you can. Of course you can. This is what @mark wanted to do. And @alexbea was to the rescue:

parent/parent-lib: false #removes the whole parent library

parent/parent-lib:
  css:
    css-file.css #allows you to bring back in just the file you want.

 

Override all CSS from a library except one file

 

That's it for Volume 2. Naturally there was loads of more learning and teaching and sharing and helping going on. Join us here.

Comments

Hi mark, thanks for sharing this post. I am looking forward for the next one.

Reading the second point about printing the comment fields I wanted to point out another solution we made in our Open Social distribution. Maybe it is of help to someone. The problem was that we needed to render comments separately as well and also cater for new content types. When a developer creates a new content type with a unique field name for this comment field, he/she shouldn't be bothered with creating template files.

So what we did is to filter the field on type and render it as a new array which can be printed in the node template.

function theme_preprocess_node(&$variables) {
$node = $variables['node'];

// Let's see if we can remove comments from the content and render them in a separate content_below array.
$comment_field_name = '';
$variables['comment_field_name'] = '';

// Check on our node if we have the comment type field somewhere.
$fields_on_node = $node->getFieldDefinitions();
foreach ($fields_on_node as $field) {
if ($field->getType() == 'comment') {
$comment_field_name = $field->getName();
}
}

// Our node has a comment reference. Let's remove it from content array.
$variables['below_content'] = array();
if (!empty($comment_field_name)) {
if (!empty($variables['content'][$comment_field_name])) {
// Add it to our custom comments_section for the template purposes and remove it.
$variables['below_content'][$comment_field_name] = $variables['content'][$comment_field_name];
unset($variables['content'][$comment_field_name]);
}
}

Annertech's default 'Annertechie' profile image.

Thanks Maikel, That looks very nice. I'll send it on to the person who had the original issue.
Mark Conroy - Lead Frontend Developer & Content Strategist

Add new comment

Restricted HTML

  • Allowed HTML tags: <a> <em> <strong> <cite> <blockquote> <code> <ul> <ol> <li> <dl> <dt> <dd> <h4> <h5> <h6>
  • Lines and paragraphs break automatically.
  • Web page addresses and email addresses turn into links automatically.