In Drupal 8.4, I am trying to add a class to the body (like Drupal 7 had) when the page viewed is a node (or entity for that matter), something like [entity]-[create or edit], so that, when a user is editing or creating a node, a class like page-node-edit gets added to the body classes array.
6 Answers
I couldn't get oknate's solution to work so I modified it. You can add it to your custom module file.
/**
* Implements hook_preprocess_html().
*/
function MYMODULE_preprocess_html(&$variables) {
// Add node ID
if ($node = \Drupal::request()->attributes->get('node')) {
$variables['attributes']['class'][] = 'page-node-' . $node->id();
}
// Get route
$route_name = \Drupal::routeMatch()->getRouteName();
// Add edit class
if ($route_name == 'entity.node.edit_form') {
$variables['attributes']['class'][] = 'entity-edit';
}
// Add create class
if ($route_name == 'node.add') {
$variables['attributes']['class'][] = 'entity-create';
}
}
I combined @Parag's solution with some extra logic to also handle node type along with the operation.
UPDATED: Implemented a switch to allow adding more routes.
function MYTHEME_preprocess_html(&$variables) {
$routeName = \Drupal::routeMatch()->getRouteName();
switch ($routeName) {
case 'entity.node.edit_form':
$entityType = $variables['node_type'];
$op = 'edit';
break;
case 'node.add':
$entityType = \Drupal::routeMatch()->getParameter('node_type')->id();
$op = 'add';
break;
}
if (isset($entityType) && isset($op)) {
$cleanEntityType = Html::cleanCssIdentifier($entityType);
$prefix = 'entity-form';
$cssClasses = [
[$prefix],
[$prefix, $op],
[$prefix, $cleanEntityType],
[$prefix, $cleanEntityType, $op],
];
foreach ($cssClasses as $cssClass) {
$variables['attributes']['class'][] = implode('-', $cssClass);
}
}
}
You can use hook_preprocess_page and check the current route:
function mymodule_preprocess_page(&$vars) {
$route_name = \Drupal::routeMatch()->getRouteName();
// This would add a class based on the route. You'd need the
// pathauto module enabled.
$vars['page_classes'][] = \Drupal::service('pathauto.alias_cleaner')->cleanString($route_name);
// This would add the classes asked for in the question.
if ($route_name == 'entity.node.edit_form') {
$vars['page_classes'][] = 'entity-edit';
}
elseif ($route_name == 'node.add') {
$vars['page_classes'][] = 'entity-create';
}
}
-
Any way to use function THEMENAME_preprocess_html like in d7?– ymdahiCommented Oct 22, 2017 at 0:28
-
Tried this for myself and it didn't work. There should be a way of doing this in the theme, but am unable to discover how. Was easy in D7 when we could use arg with an if statement to target the page via the url... Commented May 6, 2018 at 18:28
After dealing with this for some time, I've found a potential alternative way of approaching this sort of functionality.
For my use case, I was trying to add classes to the body of the node add/edit pages, so I can do things like hide blocks and alter positioning using css.
My new approach to achieve this is to simply override the page.html.twig. So, if I wanted to customize the node edit/add pages for a content type called "Blog Post", I would create two new template files:
- page--node--add--blogpost.html.twig
- page--node--edit--blogpost.html.twig
Note that I can create one set template files to cover all content types like so:
- page--node--add.html.twig
- page--node--edit.html.twig
I can also override html.html.twig, if I really needed to get my classes into the node add/edit pages. For this approach, I would create two new template pages:
- html--node--add.html.twig
- html--node--edit.html.twig
In these template pages, I would simply modify the body_classes array like so:
{%
set body_classes = [
logged_in ? 'user-logged-in',
not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
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',
'my-new-class',
'another-class',
]
%}
function MYTHEME_preprocess_html(&$variables) {
$current_path = \Drupal::service('path.current')->getPath();
$path_alias = \Drupal::service('path.alias_manager')->getAliasByPath($current_path);
$is_edit = strpos($path_alias, '/edit');
if ($is_edit !== false) {
$edit_css_classname = $variables['node_type'].'-edit';
$variables['attributes']['class'][] = \Drupal\Component\Utility\Html::cleanCssIdentifier($edit_css_classname);
}
}
This code snippet adds a MY-NODE-TYPE-edit class to the body tag of a page, if there is "/edit" inside the path.
{%
set body_classes = [
logged_in ? 'user-logged-in',
not root_path ? 'path-frontpage' : 'path-' ~ root_path|clean_class,
node_type ? 'page-node-type-' ~ node_type|clean_class,
db_offline ? 'db-offline',
user.getRoles()|join(' role-'),
'edit' in url('<current>')|render|render ? 'page-edit'
]
%}
-
This code example isn't really helpful. Can you explain what code it is, where it goes, and how it solves the problem for "when a user is editing or creating a node"? Thanks.– mpdonadio ♦Commented Dec 12, 2019 at 13:22
-
This was related to the previous post. You redefine this variable in the html.tml.twig. All the magic happens in this line: 'edit' in url('<current>')|render|render ? 'page-edit' If "edit" is in the URL you edit the page so you add the class Commented Feb 18, 2020 at 21:55