function drupal_find_theme_templates in Drupal 9
Same name and namespace in other branches
- 8 core/includes/theme.inc \drupal_find_theme_templates()
- 6 includes/theme.inc \drupal_find_theme_templates()
- 7 includes/theme.inc \drupal_find_theme_templates()
Allows themes and/or theme engines to easily discover overridden templates.
Parameters
$cache: The existing cache of theme hooks to test against.
$extension: The extension that these templates will have.
$path: The path to search.
4 calls to drupal_find_theme_templates()
- nyan_cat_theme in core/
modules/ system/ tests/ themes/ engines/ nyan_cat/ nyan_cat.engine - Implements hook_theme().
- ThemeTest::testFindThemeTemplates in core/
modules/ system/ tests/ src/ Kernel/ Theme/ ThemeTest.php - Tests drupal_find_theme_templates().
- TwigDebugMarkupTest::testTwigDebugMarkup in core/
modules/ system/ tests/ src/ Functional/ Theme/ TwigDebugMarkupTest.php - Tests debug markup added to Twig template output.
- twig_theme in core/
themes/ engines/ twig/ twig.engine - Implements hook_theme().
File
- core/
includes/ theme.inc, line 195 - The theme system, which controls the output of Drupal.
Code
function drupal_find_theme_templates($cache, $extension, $path) {
$implementations = [];
// Collect paths to all sub-themes grouped by base themes. These will be
// used for filtering. This allows base themes to have sub-themes in its
// folder hierarchy without affecting the base themes template discovery.
$theme_paths = [];
foreach (\Drupal::service('theme_handler')
->listInfo() as $theme_info) {
if (!empty($theme_info->base_theme)) {
$theme_paths[$theme_info->base_theme][$theme_info
->getName()] = $theme_info
->getPath();
}
}
foreach ($theme_paths as $basetheme => $subthemes) {
foreach ($subthemes as $subtheme => $subtheme_path) {
if (isset($theme_paths[$subtheme])) {
$theme_paths[$basetheme] = array_merge($theme_paths[$basetheme], $theme_paths[$subtheme]);
}
}
}
$theme = \Drupal::theme()
->getActiveTheme()
->getName();
$subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : [];
// Escape the periods in the extension.
$regex = '/' . str_replace('.', '\\.', $extension) . '$/';
// Get a listing of all template files in the path to search.
$files = [];
if (is_dir($path)) {
$files = \Drupal::service('file_system')
->scanDirectory($path, $regex, [
'key' => 'filename',
]);
}
// Find templates that implement registered theme hooks and include that in
// what is returned so that the registry knows that the theme has this
// implementation.
foreach ($files as $template => $file) {
// Ignore sub-theme templates for the current theme.
if (strpos($file->uri, str_replace($subtheme_paths, '', $file->uri)) !== 0) {
continue;
}
// Remove the extension from the filename.
$template = str_replace($extension, '', $template);
// Transform - in filenames to _ to match function naming scheme
// for the purposes of searching.
$hook = strtr($template, '-', '_');
if (isset($cache[$hook])) {
$implementations[$hook] = [
'template' => $template,
'path' => dirname($file->uri),
];
}
// Match templates based on the 'template' filename.
foreach ($cache as $hook => $info) {
if (isset($info['template'])) {
if ($template === $info['template']) {
$implementations[$hook] = [
'template' => $template,
'path' => dirname($file->uri),
];
}
}
}
}
// Find templates that implement possible "suggestion" variants of registered
// theme hooks and add those as new registered theme hooks. See
// drupal_find_theme_functions() for more information about suggestions and
// the use of 'pattern' and 'base hook'.
$patterns = array_keys($files);
foreach ($cache as $hook => $info) {
$pattern = isset($info['pattern']) ? $info['pattern'] : $hook . '__';
if (!isset($info['base hook']) && !empty($pattern)) {
// Transform _ in pattern to - to match file naming scheme
// for the purposes of searching.
$pattern = strtr($pattern, '_', '-');
$matches = preg_grep('/^' . $pattern . '/', $patterns);
if ($matches) {
foreach ($matches as $match) {
$file = $match;
// Remove the extension from the filename.
$file = str_replace($extension, '', $file);
// Put the underscores back in for the hook name and register this
// pattern.
$arg_name = isset($info['variables']) ? 'variables' : 'render element';
$implementations[strtr($file, '-', '_')] = [
'template' => $file,
'path' => dirname($files[$match]->uri),
$arg_name => $info[$arg_name],
'base hook' => $hook,
];
}
}
}
}
return $implementations;
}