Using the custom template pre-process function or trying to mine the theme hook $existing
parameter, or pre-process $variables
parameter, to get data from existing Drupal entities to use in the custom module template, was the wrong approach.
It turns out I needed to use general Drupal methods to pull the desired Drupal entities from within the custom template's theme hook function. Then pass them to the template by adding them to custom template variables array.
So inside the main_sections_theme
function we can do the following:
Getting Config Parameter to Pass to Custom Template
With the Drupal::configFactory() interface, we can use the listAll() method to get a list of the available configuration objects.
$site_config = \Drupal::configFactory()->listAll();
Once we have figured out the name of the config entity we want we can use Drupal::config($name) to get a read only config object.
In this case I wanted the site information configuration which I figured out is contained in system.site
.
Thus, we can get the full set of system.site
configuration parameters using:
$site_info = \Drupal::config('system.site')->get();
Wanting only the site slogan parameter, this can be further refined to pull just the site slogan by using:
$site_slogan = \Drupal::config('system.site')->get('slogan');
Getting Existing Menu Object to Pass to Custom Template
Reviewing the Drupal Menu System API Docs page, Rendering Menus section, we see that we can use the Drupal function menuTree(), to get a MenuLinkTreeInterface that we can use to load an existing menu by name.
// get the menu tree interface object
$menu_tree_interface = \Drupal::menuTree();
// create menu tree parameters object needed to load requested menu
$menu_parameters = new \Drupal\Core\Menu\MenuTreeParameters();
// get menu tree object for the 'main' navigation menu
$main_menu_tree = $menu_tree_interface->load('main', $menu_parameters);
In this case the $main_menu_tree
, at this point, can be built into a renderable array and passed as a template variable, however, from the documentation it seems most proper to also add standard manipulators to ensure access and menu order properties are maintained.
Using the same MenuLinkTreeInterface
we can use the transform()
method to add a couple standard manipulators. Then we can finally prepare our pulled menu data back into a renderable array that can be passed as the template variable, using the MenuLinkTreeInterface
function, build($tree)
:
// create array of desired manipulators to apply to menu tree
$manipulators = array(
// Only show links that are accessible for the current user.
array(
'callable' => 'menu.default_tree_manipulators:checkAccess',
),
// Use the default sorting of menu links.
array(
'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
),
);
// apply manipulators to the menu tree using \Drupal::menuTree()->transform()
$tree = $menu_tree_interface->transform($main_menu_tree, $manipulators);
// convert main menu tree into renderable object for TWIG
$main_menu = $menu_tree_interface->build($tree);
Passing Pulled Existing Site Parameters as Variables to the Custom Template
Finally, we can now pass the discovered Drupal entity parameters, we pulled into the theme hook function above, as variables for our custom TWIG template. We do this by assigning a hook variable name to each variable we want to pass and add them to the template variables array in the theme_HOOK return object.
return [
'pphtml__landing' => [
'variables' => [
'test_var' => 'test text variable',
'theme' => $theme,
'main_menu' => $main_menu,
'main_menu_tree' => $main_menu_tree,
'site_slogan' => $site_slogan,
'site_information' => $site_info,
'site_config' => $site_config,
],
],
];
The final function main_sections_them()
, found in the main_sections.module
file, in full:
/**
* Implements hook_theme()
* Primary module hooks for test_module module.
*/
function main_sections_theme($existing, $type, $theme, $path) {
// get the menu tree interface object
$menu_tree_interface = \Drupal::menuTree();
// create menu tree parameters object
$menu_parameters = new \Drupal\Core\Menu\MenuTreeParameters();
// get menu tree object for the 'main' navigation menu
$main_menu_tree = $menu_tree_interface->load('main', $menu_parameters);
// create array of manipulators to add to menu tree object
$manipulators = array(
// Only show links that are accessible for the current user.
array(
'callable' => 'menu.default_tree_manipulators:checkAccess',
),
// Use the default sorting of menu links.
array(
'callable' => 'menu.default_tree_manipulators:generateIndexAndSort',
),
);
// Transform the menu tree using the manipulators you want.
$tree = $menu_tree_interface->transform($main_menu_tree, $manipulators);
// build transformed menu tree into renderable array object for TWIG
$main_menu = $menu_tree_interface->build($tree);
// get list of site configuration entities
$site_config = \Drupal::configFactory()->listAll();
// get array of all system site information configuration parameters
$site_info = \Drupal::config('system.site')->get();
// get the site slogan the Drupal system site information configuration
$site_slogan = \Drupal::config('system.site')->get('slogan');
return [
'pphtml__landing' => [
'variables' => [
'test_var' => 'test text variable',
'theme' => $theme,
'main_menu' => $main_menu,
'main_menu_tree' => $main_menu_tree,
'site_config' => $site_config,
'site_information' => $site_info,
'site_slogan' => $site_slogan,
],
],
];
}
The final custom TWIG template pphtml--landing.html.twig
using our new variables:
<div class="layout-container">
<header role="banner">
<div>
<p>TESTING HEAD</p>
</div>
</header>
<div>
<p>TESTING BODY</p>
<div>{{ kint(theme) }}</div>
<p>Simple text variable: {{ test_var }}</p>
{{ kint(site_config) }}
{{ kint(site_information) }}
{{ kint(site_slogan) }}
{{ kint(main_menu_tree) }}
{% if site_slogan %}
<div class="d-inline-block align-top site-name-slogan">
{{ site_slogan }}
</div>
{% endif %}
<nav class="navbar navbar-dark bg-primary navbar-expand-lg">
<div class="container contextual-region block block-menu navigation menu--main">
{{ main_menu }}
</div>
</nav>
</div>
<footer role="contentinfo">
<div>
<p>FOOTER TESTING</p>
</div>
</footer>
</div>
Final resulting page showing devel kint variables we used to figure things out and the properly rendered site slogan and main menu inside our custom template.
Expanded kint arrays: