uswds_base-8.x-2.0-alpha1/includes/base_themes.inc
includes/base_themes.inc
<?php /** * @file * Utility code related to base themes. * * The concepts/wording in this file are inspired by (ie, stolen from) the D7 * Omega base theme. */ /** * Gets the full theme trail, from active to top-level base. * * @return array * An array of all themes in the trail, ordered from active to top-level base. */ function uswds_base_theme_trail() { $theme = \Drupal::theme()->getActiveTheme(); $all = [$theme->getName() => $theme] + $theme->getBaseThemes(); // This gives us a complete lineage of themes, but we actually only care about // the USWDS Base theme and any child themes. $trail = []; foreach ($all as $key => $value) { $trail[$key] = $value; if ('uswds_base' == $key) { break; } } return $trail; } /** * Finds the first occurrence of a given file in the theme trail. * * @param string $file * The relative path to a file. * * @return string * The path to the file. If the file does not exist at all, it will simply * return the path of the file as it would be if it existed in the given theme * directly. This ensures that the code that uses this function does not break * if a file does not exist anywhere. */ function uswds_base_theme_trail_file($file) { $trail = uswds_base_theme_trail(); foreach ($trail as $name => $theme) { $current = $theme->getPath() . '/' . $file; if (file_exists($current)) { return $current; } } // The default (fallback) path is the path of the active theme, even if it // does not actually have that file. $active = array_shift($trail); return $active->getPath() . '/' . $file; } /** * Implements hook_theme_registry_alter(). */ function uswds_base_theme_registry_alter(&$registry) { $trail = uswds_base_theme_trail(); // For the purpose of this, we want the theme trail in reverse order: from // root base theme to active theme. This way we can let base themes run their // functions before the active theme. $trail = array_reverse($trail); foreach ($trail as $theme) { uswds_base_register_theme_hooks($registry, $theme); } } /** * Helper function to register preprocessor functions for a theme. */ function uswds_base_register_theme_hooks(&$registry, $theme) { // Iterate over all preprocess/process files in the current theme. foreach (['process', 'preprocess'] as $type) { $length = -(strlen($type) + 1); // Only look for files that match the 'something.preprocess.inc' pattern. $mask = '/.' . $type . '.inc$/'; $theme_name = $theme->getName(); // Recursively scan the folder for the current step for (pre-)process // files and write them to the registry. $files = file_scan_directory($theme->getPath() . '/' . $type, $mask); // We sort here because we want to be sure that base hooks (eg, // foo.preprocess.inc) are handled before theme suggestions (eg, // foo__bar.preprocess.inc). ksort($files); foreach ($files as $file) { $hook = strtr(substr($file->name, 0, $length), '-', '_'); $callback = "{$theme_name}_{$type}_{$hook}"; // Is this a base hook or a theme suggestion? $hook_parts = explode('__', $hook); $theme_suggestion = count($hook_parts) > 1; $base_hook = $hook_parts[0]; // If this is a theme suggestion that does not already exist, add it. if ($theme_suggestion && !isset($registry[$hook]) && isset($registry[$base_hook])) { $registry[$hook] = $registry[$base_hook]; $registry[$hook]['base hook'] = $base_hook; } // If this might be a base hook instead, make sure that it's included in // ALL theme suggestions in the registry. if (!$theme_suggestion) { foreach ($registry as &$entry) { if (!empty($entry['base hook'])) { if ($hook == $entry['base hook']) { if (!in_array($callback, $entry["$type functions"])) { $entry["$type functions"][] = $callback; if (empty($entry['includes']) || !in_array($file->uri, $entry['includes'])) { $entry['includes'][] = $file->uri; } } } } } } // If there is no entry in the registry to modify, skip. if (!isset($registry[$hook])) { continue; } // Append the included (pre-)process hook to the array of functions. $registry[$hook]["$type functions"][] = $callback; // By adding this file to the 'includes' array we make sure that it is // available when the hook is executed. $registry[$hook]['includes'][] = $file->uri; } } }