You are here

function ds_theme_registry_alter in Display Suite 8.4

Same name and namespace in other branches
  1. 8.2 ds.module \ds_theme_registry_alter()
  2. 8.3 ds.module \ds_theme_registry_alter()
  3. 7.2 ds.module \ds_theme_registry_alter()
  4. 7 ds.module \ds_theme_registry_alter()

Implements hook_theme_registry_alter().

File

./ds.module, line 77
Display Suite core functions.

Code

function ds_theme_registry_alter(&$theme_registry) {
  $layouts = Ds::getLayouts();
  $layout_theme_hooks = [];

  /** @var \Drupal\Core\Layout\LayoutDefinition $info */
  foreach ($layouts as $info) {
    if (is_a($info
      ->getClass(), DsLayout::class, TRUE)) {
      $layout_theme_hooks[$info
        ->getThemeHook()] = 'layout';
    }
  }

  // Only add preprocess functions if entity exposes theme function, and this
  // layout is using the Display Suite layout class.
  foreach ($theme_registry as $theme_hook => $info) {
    if (array_key_exists($theme_hook, $layout_theme_hooks) || !empty($info['base hook']) && array_key_exists($info['base hook'], $layout_theme_hooks)) {
      $theme_registry[$theme_hook]['preprocess functions'][] = 'ds_preprocess_ds_layout';
    }
  }

  // Check preprocess functions for ds fields.
  $field_theme_hooks = [];
  if (\Drupal::config('ds.settings')
    ->get('field_template')) {
    $field_layouts = \Drupal::service('plugin.manager.ds.field.layout')
      ->getDefinitions();
    foreach ($field_layouts as $key => $plugin) {
      if ($key != 'default') {

        // Get the hook name.
        $hook_field_name = 'field__' . $plugin['theme'];
        if (isset($theme_registry[$hook_field_name])) {

          // Store for suggestions later.
          $field_theme_hooks[$hook_field_name] = 'field';

          // Variable holding the preprocess functions to add later.
          $preprocess_functions_to_add = [];

          // Overrides don't get the template_preprocess_field function.
          if (!in_array('template_preprocess_field', $theme_registry[$hook_field_name]['preprocess functions'])) {
            $preprocess_functions_to_add[] = 'template_preprocess_field';
          }

          // Overrides don't get the ds_preprocess_field function.
          if (!in_array('ds_preprocess_field', $theme_registry[$hook_field_name]['preprocess functions'])) {
            $preprocess_functions_to_add[] = 'ds_preprocess_field';
          }

          // We need to make sure the function runs asap as the dedicated field
          // preprocess function might need ds information, e.g.
          // template_preprocess_field__ds_field_expert().
          // template_preprocess() will be available, so put them right after.
          if (!empty($preprocess_functions_to_add)) {
            $preprocess_functions = $theme_registry[$hook_field_name]['preprocess functions'];
            array_splice($preprocess_functions, 1, 0, $preprocess_functions_to_add);
            $theme_registry[$hook_field_name]['preprocess functions'] = $preprocess_functions;
          }
        }
      }
    }
  }

  // ------------------------------------------------------------------------
  // Workaround to get theme suggestions working for templates using the
  // the Display Suite class. It's borderline insane, but gets the job done.
  //
  // Note that this currently only works for Twig, but I assume, there isn't
  // any other engine out there yet for Drupal 8.
  //
  // Code based on drupal_find_theme_templates().
  //
  // @see
  //   - https://www.drupal.org/node/2862683 (core queue)
  //   - https://www.drupal.org/node/2802429 (DS queue)
  //      (and maybe others)
  // ------------------------------------------------------------------------
  // Merge layout and field hooks.
  $all_ds_theme_hooks = $layout_theme_hooks + $field_theme_hooks;
  $engine = \Drupal::theme()
    ->getActiveTheme()
    ->getEngine();
  if ($engine == 'twig') {
    $extension = '.html.twig';
    $theme_path = \Drupal::theme()
      ->getActiveTheme()
      ->getPath();

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

    // Get a listing of all template files in the path to search.
    $files = \Drupal::service('file_system')
      ->scanDirectory($theme_path, $regex, [
      'key' => 'filename',
    ]);
    $patterns = array_keys($files);
    $implementations = [];
    foreach ($all_ds_theme_hooks as $hook => $base_hook) {

      // Ignored if not registered (which would be weird).
      if (!isset($theme_registry[$hook])) {
        continue;
      }
      $pattern = isset($info['pattern']) ? $info['pattern'] : $hook . '__';
      if (!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.
            $info = $theme_registry[$hook];
            $arg_name = isset($info['variables']) ? 'variables' : 'render element';
            $new_hook = strtr($file, '-', '_');
            $implementations[$new_hook] = [
              'template' => $file,
              'path' => dirname($files[$match]->uri),
              $arg_name => $info[$arg_name],
              'base hook' => $base_hook,
              'type' => 'theme_engine',
              'theme path' => $theme_path,
            ];
            if (isset($theme_registry[$hook]['preprocess functions'])) {
              $implementations[$new_hook]['preprocess functions'] = $theme_registry[$hook]['preprocess functions'];
            }
          }
        }
      }
    }
    if (!empty($implementations)) {
      $theme_registry += $implementations;
    }
  }

  // ------------------------------------------------------------------------
  // End of workaround, hopefully we can kill this one day.
  // ------------------------------------------------------------------------
  // Run field group preprocess before ds_entity_view.
  if (function_exists('field_group_build_entity_groups')) {
    array_unshift($theme_registry['ds_entity_view']['preprocess functions'], 'field_group_build_entity_groups');
  }

  // Remove ds_preprocess_field in case field templates is not enabled.
  if (!\Drupal::config('ds.settings')
    ->get('field_template')) {
    $key = array_search('ds_preprocess_field', $theme_registry['field']['preprocess functions']);
    if (!empty($key)) {
      unset($theme_registry['field']['preprocess functions'][$key]);
    }
  }
}