Sometimes you need to adjust the DOM in a way you can’t do just via overwriting Twig templates. Thats where preprocessors come in handy.
Lets assume we already have a custom theme called “mytheme” and created a mytheme.theme file in web/themes/custom/mytheme
Even though this file has a .theme extension you can write normal PHP code in there.
Preprocessor functions are usually in the following structure: THEMENAME_preprocess_HOOK()
Our THEMENAME here is mytheme and you can see the available hooks via enabling the Twig Debugging Mode in the frontend HTML comments.
So therefore you can create custom preprocessor function like
- mytheme_preprocess_node()
- All nodes
- mytheme_preprocess_node__article()
- All article nodes
- mytheme_preprocess_menu()
- All menus
What needs to be inside these functions?
Lets say we want to add a class to a specific menu.
/**
* Implements hook_preprocess_HOOK() for menu.html.twig.
*/
function mytheme_preprocess_menu(&$variables) {
if ($variables['menu_name'] == 'main') {
if (!isset($variables['attributes']['class'])) {
$variables['attributes']['class'] = [];
}
$variables['attributes']['class'] = array_merge(
$variables['attributes']['class'],
['my-main-menu']
);
}
}
First of all: $variables is passed through by reference, therefore all the changes we do inside $variables gets passed onto the template side.
Therefore, as you can see above, we check on which menu we currently are and if we are on the ‘main’ menu we add the class ‘my-main-menu’ to the attributes class array.
This results in the following DOM:
The hook “menu__main” here is only a more specific hook as we used above.
We could have also got the same result with the following function:
function mytheme_preprocess_menu__main(&$variables) {
if (!isset($variables['attributes']['class'])) {
$variables['attributes']['class'] = [];
}
$variables['attributes']['class'] = array_merge(
$variables['attributes']['class'],
['my-main-menu']
);
}
As you can see the function name has an appended __main at the end but now we don’t need the outer most if query to check which menu we currently try to preprocess.
One important notice here: The preprocessor mytheme_preprocess_menu only adjusts values for the menu.html.twig, not any other Twig files like page.html.twig or block.html.twig
If you want to adjust values inside the page.html.twig or any other Twig file you should check its hook first and create a separate preprocessor function for this hook.
So therefore you can only adjust values inside a preprocessor for its assigned element connected via the hook. If you want to adjust an element because of another element thats more complicated.