As a theme developer, I often find myself needing to control the appearance of content on a per-entity basis (for example, assigning a color to a node with a certain category). The easiest way that I've found to accomplish this is by adding a class to the entity based on a field value. Setting this up in Drupal 8 is simple, and will allow content editors (or non-developers) the ability to control the appearance of individual entities without needing to access the code behind the scenes. Here's how it's done:
1. Create the field
Start by creating the field you'd like to use to control the class. If you already have a field in place, skip on ahead to step 2!
Be sure to use a field type that makes sense. I've found that the Text (Plain) type works well for fully-customizable class names, and List (Text) works well for providing a select box with a few curated options for content editors to pick from.
2. Get the value of the field
In a preprocess function in your theme file, you'll start by getting the value of the field. In order to avoid errors, you should also include checks to see if the entity has the field and if the field has a value.
$node = $variables['node'];
// Check if the node has the field and the field has a value.
if ($node->hasField('field_name') && !$node->get('field_name')->isEmpty()) {
// Get the value of the field.
$field_value = $node->get('field_name')->get(0)->getValue();
}
3. Convert the field value to a safe class name
Because class names cannot contain spaces or special characters (among other things), we need to make sure that our field value is formatted correctly. This is especially important when using a freeform text field, where user error is likely. Luckily, Drupal 8 contains a built-in function just for this purpose!
// Convert the field value to a safe class name
$class_name = Html::cleanCssIdentifier($field_value);
Be sure to remember to include the use statement at the top of your theme file.
use Drupal\Component\Utility\Html;
4. Add the class as an attribute
Now that we have our safe class name, all that's left to do is assign that value as a class attribute on our entity.
// Add the class to the entity as an attribute
$variables['attributes']['class'][] = $class_name;
The full code:
use Drupal\Component\Utility\Html;
/**
* Implements hook_preprocess_HOOK() for node.html.twig.
*/
function mytheme_preprocess_node(&$variables) {
$node = $variables['node'];
// Check if the node has the field and the field has a value.
if ($node->hasField('field_name') && !$node->get('field_name')->isEmpty()) {
// Get the value of the field.
$field_value = $node->get('field_name')->get(0)->getValue();
// Convert the field value to a safe class name.
$class_name = Html::cleanCssIdentifier($field_value);
// Add the class to the entity as an attribute.
$variables['attributes']['class'][] = $class_name;
}
}
Need a fresh perspective on a tough project?
Let’s talk about how RDG can help.