web-dev-qa-db-ja.com

段落フィールドとバンドル出力をカスタムモジュールのカスタムテンプレートでオーバーライドするにはどうすればよいですか?

バックストーリー

複数の段落バンドルを作成しました。私の目標は、これらのバンドルの出力(1)と包含フィールドの出力(2)をスケーラブルな方法で完全に制御することです(将来のバンドル追加を容易にするため-将来的に30以上のバンドルが存在する可能性があります) )。

今どこにいるか

HOOK_theme_suggestions_HOOK_alterを使用してテーマの提案を作成し、バンドルの出力を上書きしました。これにより、バンドルごとにカスタムのtwigテンプレートを作成できました。

/**
 * 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

...そしてfield.html.twigのコンテンツをドロップしました。上記のhook_themeコード(「カスタム段落フィールドラッパーの登録」)のコメントを外すと、次のエラーが発生します。

Webサイトで予期しないエラーが発生しました。後でもう一度やり直してください。回復可能な致命的なエラー:Drupal\Core\Render\Element :: children()に渡される引数1は、配列型でなければならず、nullが指定され、/ Users/phil/Sites/glades/www/modules/contrib/paragraphs/paragraphsで呼び出されます238行目の.moduleであり、Drupal\Core\Render\Element :: children()で定義されています(core/lib/Drupal/Core/Render/Element.phpの71行目)。

フィールドテンプレートオーバーライドで私が間違っていることについて何か考えはありますか?

これのほとんどは、ここでjeremypeterからのコメントに触発されました: https://www.drupal.org/node/2499827#comment-1215976

1
drupalphil

元の投稿に対する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
drupalphil