Same name and namespace in other branches
  1. 7.x includes/theme.inc \drupal_find_theme_templates()
  2. 8.9.x core/includes/theme.inc \drupal_find_theme_templates()
  3. 9 core/includes/theme.inc \drupal_find_theme_templates()

Find overridden theme templates. Called by themes and/or theme engines to easily discover 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.

1 call to drupal_find_theme_templates()
phptemplate_theme in themes/engines/phptemplate/phptemplate.engine
Implementation of hook_theme().

File

includes/theme.inc, line 860
The theme system, which controls the output of Drupal.

Code

function drupal_find_theme_templates($cache, $extension, $path) {
  $templates = array();

  // 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 = array();
  foreach (list_themes() as $theme_info) {
    if (!empty($theme_info->base_theme)) {
      $theme_paths[$theme_info->base_theme][$theme_info->name] = dirname($theme_info->filename);
    }
  }
  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]);
      }
    }
  }
  global $theme;
  $subtheme_paths = isset($theme_paths[$theme]) ? $theme_paths[$theme] : array();

  // Escape the periods in the extension.
  $regex = str_replace('.', '\\.', $extension) . '$';

  // Because drupal_system_listing works the way it does, we check for real
  // templates separately from checking for patterns.
  $files = drupal_system_listing($regex, $path, 'name', 0);
  foreach ($files as $template => $file) {

    // Ignore sub-theme templates for the current theme.
    if (strpos($file->filename, str_replace($subtheme_paths, '', $file->filename)) !== 0) {
      continue;
    }

    // Chop off the remaining extensions if there are any. $template already
    // has the rightmost extension removed, but there might still be more,
    // such as with .tpl.php, which still has .tpl in $template at this point.
    if (($pos = strpos($template, '.')) !== FALSE) {
      $template = substr($template, 0, $pos);
    }

    // Transform - in filenames to _ to match function naming scheme
    // for the purposes of searching.
    $hook = strtr($template, '-', '_');
    if (isset($cache[$hook])) {
      $templates[$hook] = array(
        'template' => $template,
        'path' => dirname($file->filename),
        'include files' => $cache[$hook]['include files'],
      );
    }

    // Ensure that the pattern is maintained from base themes to its sub-themes.
    // Each sub-theme will have their templates scanned so the pattern must be
    // held for subsequent runs.
    if (isset($cache[$hook]['pattern'])) {
      $templates[$hook]['pattern'] = $cache[$hook]['pattern'];
    }
  }
  $patterns = array_keys($files);
  foreach ($cache as $hook => $info) {
    if (!empty($info['pattern'])) {

      // Transform _ in pattern to - to match file naming scheme
      // for the purposes of searching.
      $pattern = strtr($info['pattern'], '_', '-');
      $matches = preg_grep('/^' . $pattern . '/', $patterns);
      if ($matches) {
        foreach ($matches as $match) {
          $file = substr($match, 0, strpos($match, '.'));

          // Put the underscores back in for the hook name and register this pattern.
          $templates[strtr($file, '-', '_')] = array(
            'template' => $file,
            'path' => dirname($files[$match]->filename),
            'arguments' => $info['arguments'],
            'original hook' => $hook,
            'include files' => $info['include files'],
          );
        }
      }
    }
  }
  return $templates;
}