With thanks to the commenters I was able to figure out how to edit the DOM in content pages and menus.
Regarding version: Drupal 10.
Replace "MYTHEME" with the machine name of your theme. Open your MYTHEME.info.yml
file to see the name of your theme. It is case-sensitive.
Within your /themes/MYTHEME/
directory you may have a MYTHEME.theme
file wherein you are able to declare hook functions. These hooks include those that allow you to preprocess data before it gets build into a template. It is here that you are able to adjust the HTML strings to your needs.
These hooks include a $variables
parameter that will eat up all of your available memory if you try to print it via var_dump
.
Editing content
Content includes those that you build in /admin/content
and those you build in /admin/structure/block/block-content
.
The hook used to adjust the HTML of content pages is MYTHEME_preprocess_field(&$variables)
.
Inspect $variables['entity_type']
to determine if you are editing content or block-content.
The HTML string that will be used to build your content is in $variables['items'][0]['content']['#text']
. Adjust that string via string manipulation or DOM manipulation with DOMDocument then overwrite $variables['items'][0]['content']['#text']
with your edited string.
If using DOMDocument you may need to ignore all errors generated by loadHTML() because this feature does not understand HTML5 elements, but it can still work with them.
function MYTHEME_preprocess_field(&$variables): void {
$content = $variables['items'][0]['content'] ?? false;
$type = $content['#type'] ?? '';
// Blocks are the pieces that are not content. These include the sidebar, search, header, and footer.
$block = $variables['entity_type'] === 'block_content';
if ($content && $type === 'processed_text') {
$dom = new DomDocument();
libxml_use_internal_errors(true);
$options = LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD | LIBXML_NOERROR;
$dom->loadHTML('<div>' . $content['#text'] . '</div>', $options);
// Use this variable to inspect the errors when troubleshooting.
// $errors = libxml_get_errors();
libxml_clear_errors();
$parsedHTML = $dom->saveHTML();
// Errors are fine as long as the HTML string was successfully parsed by DOMDocument.
if ($parsedHTML) {
// Your code here to manipulate DOM.
}
}
}
Editing menus
The hook used to adjust the HTML of menus is MYTHEME_preprocess_menu(&$variables)
.
There are various menus in a Drupal page. These include admin
, main
, and account
.
The menu items to adjust are within $variables['items']
. The structure of each element within that array is:
items(array)
- menu_link_content:{unique_id}(array)
- - is_expanded(boolean)
- - is_collapsed(boolean)
- - in_active_trail(boolean)
- - attributes(object)
- - title(string) Sample menu item
- - url(object)
- - below(array)
- - - menu_link_content:{unique_id}(array)
- - - - is_expanded(boolean)
- - - - is_collapsed(boolean)
- - - - in_active_trail(boolean)
- - - - attributes(object)
- - - - title(string) Sample sub-menu item
- - - - url(object)
- - - - below(array)
- - - - original_link(object)
Each menu item may have sub-items. These are saved in the ['below']
key as an array.
If you want to adjust the url the ['url']
element holds a Drupal URL object. Refer to the documentation on how to adjust a Drupal URL object.
Here is an example to get you started:
function adjustMenuItem($item) {
// Your code to adjust the elements of the $item array.
// Handle recursive array elements.
if (isset($item['below']) && is_array($item['below']) && count($item['below']) > 0) {
foreach ($item['below'] as $key => $value) {
$item['below'][$key] = adjustMenuItem($value);
}
}
return $item;
}
function MYTHEME_preprocess_menu(&$variables): void {
$name = $variables['menu_name'] ?? '';
if ($name === 'main' && is_array($variables['items'])) {
foreach ($variables['items'] as $key => $value) {
$variables['items'][$key] = adjustMenuItem($value);
}
}
}