Drupal 8: How to include the node id and a class in body based on the , depending on the current path

User login

While working on a custom bootstrap subtheme in Drupal, I needed to include specific classes in the body tag.

There are two different cases that I needed to take into consideration, one for nodes and one for custom paths generated by e.g. from Views or Taxonomy.

In the first case, I needed the node id to be included as a class, and on the second I needed a class name that was based on the path.

To achieve this, I needed to edit two different files under my subtheme category. You will need to replace themename with the actual name of your theme.

In themename.theme

<?php
/**
* @file
* Bootstrap sub-theme.
*
* Place your custom PHP code in this file.
*/
function themename_preprocess_html(&$variables) {
  if ($node = \Drupal::request()->attributes->get('node')) {
    $variables['attributes']['class'][] = 'page-node-' . $node->id();
  }
  $current_path = \Drupal::service('path.current')->getPath();
  $variables['current_path'] = \Drupal::service('path.alias_manager')->getAliasByPath($current_path);
}

In html.html.twig:

{#
/**
* @file
* Default theme implementation to display the basic html structure of a single
* Drupal page.
*
* Variables:
* - $css: An array of CSS files for the current page.
* - $language: (object) The language the site is being displayed in.
*   $language->language contains its textual representation.
*   $language->dir contains the language direction. It will either be 'ltr' or
*   'rtl'.
* - $rdf_namespaces: All the RDF namespace prefixes used in the HTML document.
* - $grddl_profile: A GRDDL profile allowing agents to extract the RDF data.
* - $head_title: A modified version of the page title, for use in the TITLE
*   tag.
* - $head_title_array: (array) An associative array containing the string parts
*   that were used to generate the $head_title variable, already prepared to be
*   output as TITLE tag. The key/value pairs may contain one or more of the
*   following, depending on conditions:
*   - title: The title of the current page, if any.
*   - name: The name of the site.
*   - slogan: The slogan of the site, if any, and if there is no title.
* - $head: Markup for the HEAD section (including meta tags, keyword tags, and
*   so on).
* - $styles: Style tags necessary to import all CSS files for the page.
* - $scripts: Script tags necessary to load the JavaScript files and settings
*   for the page.
* - $page_top: Initial markup from any modules that have altered the
*   page. This variable should always be output first, before all other dynamic
*   content.
* - $page: The rendered page content.
* - $page_bottom: Final closing markup from any modules that have altered the
*   page. This variable should always be output last, after all other dynamic
*   content.
* - $classes String of classes that can be used to style contextually through
*   CSS.
*
* @ingroup templates
*
* @see bootstrap_preprocess_html()
* @see template_preprocess()
* @see template_preprocess_html()
* @see template_process()
*/
#}
{%
set body_classes = [
logged_in ? 'user-logged-in',
not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
path_info.args ? 'path-' ~ path_info.args,
node_type ? 'page-node-type-' ~ node_type|clean_class,
db_offline ? 'db-offline',
theme.settings.navbar_position ? 'navbar-is-' ~ theme.settings.navbar_position,
theme.has_glyphicons ? 'has-glyphicons',
current_path ? 'context' ~ current_path|clean_class,
]
%}
<!DOCTYPE html>
<html {{ html_attributes }}>
<head>
  <head-placeholder token="{{ placeholder_token|raw }}">
    <title>{{ head_title|safe_join(' | ') }}</title>
    <css-placeholder token="{{ placeholder_token|raw }}">
      <js-placeholder token="{{ placeholder_token|raw }}">
</head>
<body{{ attributes.addClass(body_classes) }}>
<a href="#main-content" class="visually-hidden focusable skip-link">
  {{ 'Skip to main content'|t }}
</a>
{{ page_top }}
{{ page }}
{{ page_bottom }}
<js-bottom-placeholder token="{{ placeholder_token|raw }}">
</body>
</html>

Don't forget to clear caches. The body tag should look something like the following, for nodes

<body class="page-node-44 user-logged-in path-node page-node-type-page has-glyphicons context-node-44 toolbar-tray-open toolbar-fixed toolbar-horizontal" style="padding-top: 80px;" cz-shortcut-listen="true">

and like

<body class="user-logged-in path-portfolio has-glyphicons context-portfolio-websites">

for view pages.

Tags: 
Drupal 8