Как я могу переопределить поле абзацев и выходные данные пакета с помощью пользовательского шаблона в пользовательском модуле?


Предыстория

Я создал несколько пакетов абзацев. Моя цель - иметь абсолютный контроль над выводом этих пакетов (1), а также выводом содержащего поля (2) масштабируемым способом (для удобства добавления пакетов в будущем - в будущем может быть более 30 пакетов).

Где я нахожусь

Я создал предложение по теме, используя HOOK_theme_suggestions_HOOK_alter, чтобы переопределить вывод пакетов. Это позволило мне создавать пользовательские шаблоны веток для каждый сверток.

/**
 * Implements hook_theme()
 *
 * Register a theme for each paragraph type
 *
 */
function MYMODULE_theme($existing, $type, $theme, $path){
  $theme_templates  = [];
  $paragraph_types  = MYMODULE_get_paragraph_types();

  // Register custom Paragraph bundle templates
  foreach ($paragraph_types as $paragraph_type){
    $theme_templates['paragraph__MYMODULE__' . $paragraph_type] = [
      'base hook' => 'paragraph'
    ];
  }

  // Register custom Paragraph bundle template fallback
  $theme_templates['paragraph__MYMODULE'] = [
    'base hook' => 'paragraph'
  ];

  // Register custom Paragraph field wrapper
  // $module_path = drupal_get_path('module', 'MYMODULE');
  // $theme_templates['paragraph__MYMODULE__field_wrapper'] = [
  //   'base hook' => 'field',
  //   'template' => 'paragraph--MYMODULE--field-wrapper',
  //   'path' => $module_path . '/templates'
  //  ];

  return $theme_templates;
}

/**
 * Implements HOOK_theme_suggestions_HOOK_alter
 */
function MYMODULE_theme_suggestions_field_alter(array &$suggestions, array $variables, $hook) {
  $field = $variables['element']['#field_name'];

  if( $field == 'field_content_modules' ) {
    $suggestions[] = 'paragraph__MYMODULE__field_wrapper';
  }
}


/**
 * Implements HOOK_theme_suggestions_HOOK_alter
 */
function MYMODULE_theme_suggestions_paragraph_alter(&$suggestions, $variables){
  $entity              = $variables['elements']['#paragraph'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
  $type                = $entity->getType();

  $suggestions[] = 'paragraph__MYMODULE';
  $suggestions[] = 'paragraph__MYMODULE__' . $type;
  $suggestions[] = 'paragraph__MYMODULE__' . $type . '__' . $sanitized_view_mode;
}


/**
 * Implements hook_theme_registry_alter()
 */
function MYMODULE_theme_registry_alter(&$theme_registry) {
  $module_path      = drupal_get_path('module', 'MYMODULE');
  $template_objects = drupal_find_theme_templates($theme_registry, '.html.twig', $module_path);
  $paragraph_types  = MYMODULE_get_paragraph_types();

  // 1. Loop through the paragraph types
  // 2. Check if each paragraph exists in the `$template_objects` array
  // 3. If it doesn't exist, remove it from the registry so we don't get any errors
  // 4. If it does exist, set actual path to template
  foreach ($paragraph_types as $type){
    $template = 'paragraph__MYMODULE__' . $type;
    if(!isset($template_objects[$template])){
      unset($theme_registry['paragraph__MYMODULE__' . $type]);
    } else {
      $theme_registry['paragraph__MYMODULE__' . $type]['path'] = $template_objects[$template]['path'];
    }
  }
}


/**
 * Helper function to get a list of paragraph types by machine name
 *
 * @return array
 */
function MYMODULE_get_paragraph_types(){
  $paragraph_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('paragraph');
  return array_keys($paragraph_bundles);
}

Итак, часть 1 завершена.

Часть 2 управляет HTML-контейнером поля абзаца (не пакета). Это должно быть простое переопределение шаблона поля. Я добавил файл:

/modules/custom/MYMODULE/templates/paragraph--MYMODULE--field-wrapper.html.twig

...и опустил содержимое поля.html.twig. Когда я раскомментирую код hook_theme выше ("Зарегистрировать пользовательскую оболочку поля абзаца"), я получаю эту ошибку:

На веб-сайте произошла непредвиденная ошибка. Пожалуйста, повторите попытку позже. Излечимый смертельный ошибка: Аргумент 1 передан Drupal\Core\Render\Элемент::children() должен иметь тип массива, заданный null, вызываемый в /Пользователи/фил/Сайты/поляны/www/модули/контент/абзацы/абзацы. модуль в строке 238 и определен в Drupal\Core\Render\Элемент::дети() (строка 71 из core/lib/Drupal/Core/Render/Element.php).

Есть какие-нибудь мысли относительно того, что я делаю неправильно с переопределением шаблона поля?

Большая часть этого была вдохновлена комментарием Джереми Питера здесь: https://www.drupal.org/node/2499827#comment-12159763

Author: leymannx, 2017-07-23

1 answers

Согласно комментарию 4k4 к исходному сообщению, это была проблема с соглашением об именовании, как показано здесь: https://www.drupal.org/docs/8/theming/twig/twig-template-naming-conventions

В функции hook_theme и hook_theme_suggestions_hook_alter выше я изменил:

paragraph__contentmodules__field_wrapper

Кому:

field__paragraph__contentmodules__field_wrapper

Рабочий код:

<?php


/**
 * Implements hook_theme()
 *
 * Register a theme for each paragraph type
 *
 */
function MYMODULE_theme($existing, $type, $theme, $path){
  $theme_templates  = [];
  $paragraph_types  = MYMODULE_get_paragraph_types();

  // Register custom Paragraph bundle templates
  foreach ($paragraph_types as $paragraph_type){
    $theme_templates['paragraph__MYMODULE__' . $paragraph_type] = [
      'base hook' => 'paragraph'
    ];
  }

  // Register custom Paragraph bundle template fallback
  $theme_templates['paragraph__MYMODULE'] = [
    'base hook' => 'paragraph'
  ];

  // Register custom Paragraph field wrapper
  $theme_templates['field__paragraph__MYMODULE__field_wrapper'] = [
    'base hook' => 'field',
  ];

  return $theme_templates;
}

/**
 * Implements HOOK_theme_suggestions_HOOK_alter
 */
function MYMODULE_theme_suggestions_field_alter(array &$suggestions, array $variables, $hook) {
  $field = $variables['element']['#field_name'];

  if( $field == 'field_content_modules' ) {
    $suggestions[] = 'field__paragraph__MYMODULE__field_wrapper';
  }
}


/**
 * Implements HOOK_theme_suggestions_HOOK_alter
 */
function MYMODULE_theme_suggestions_paragraph_alter(&$suggestions, $variables){
  $entity              = $variables['elements']['#paragraph'];
  $sanitized_view_mode = strtr($variables['elements']['#view_mode'], '.', '_');
  $type                = $entity->getType();

  $suggestions[] = 'paragraph__MYMODULE';
  $suggestions[] = 'paragraph__MYMODULE__' . $type;
  $suggestions[] = 'paragraph__MYMODULE__' . $type . '__' . $sanitized_view_mode;
}


/**
 * Implements hook_theme_registry_alter()
 */
function MYMODULE_theme_registry_alter(&$theme_registry) {
  $module_path      = drupal_get_path('module', 'MYMODULE');
  $template_objects = drupal_find_theme_templates($theme_registry, '.html.twig', $module_path);
  $paragraph_types  = MYMODULE_get_paragraph_types();

  // 1. Loop through the paragraph types
  // 2. Check if each paragraph exists in the `$template_objects` array
  // 3. If it doesn't exist, remove it from the registry so we don't get any errors
  // 4. If it does exist, set actual path to template
  foreach ($paragraph_types as $type){
    $template = 'paragraph__MYMODULE__' . $type;
    if(!isset($template_objects[$template])){
      unset($theme_registry['paragraph__MYMODULE__' . $type]);
    } else {
      $theme_registry['paragraph__MYMODULE__' . $type]['path'] = $template_objects[$template]['path'];
    }
  }
}


/**
 * Helper function to get a list of paragraph types by machine name
 *
 * @return array
 */
function MYMODULE_get_paragraph_types(){
  $paragraph_bundles = \Drupal::service('entity_type.bundle.info')->getBundleInfo('paragraph');
  return array_keys($paragraph_bundles);
}
 2
Author: drupalphil, 2017-07-24 12:14:22