バックストーリー
複数の段落バンドルを作成しました。私の目標は、これらのバンドルの出力(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
元の投稿に対する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);
}