logo

额外区块类型 (EBT) - 全新的布局构建器体验❗

额外区块类型 (EBT) - 样式化、可定制的区块类型:幻灯片、标签页、卡片、手风琴等更多类型。内置背景、DOM Box、JavaScript 插件的设置。立即体验布局构建的未来。

演示 EBT 模块 下载 EBT 模块

❗额外段落类型 (EPT) - 全新的 Paragraphs 体验

额外段落类型 (EPT) - 类似的基于 Paragraph 的模块集合。

演示 EPT 模块 滚动

滚动

Twig 最佳实践 —— 函数与预处理模板

02/10/2025, by Ivan

为了让 Drupal 8 的主题系统发挥最大性能,并在 Twig 模板中提供更多自定义可能性,请遵循以下建议:

本指南旨在帮助那些有 Drupal 7 开发经验的开发者,他们可能还习惯使用 theme() 或 drupal_render() 这样的函数,但这些函数在 Drupal 8+ 中已经不再推荐使用。文中的「之前」示例通常采用 Drupal 7 风格的代码。

在预处理函数中返回渲染数组

在预处理函数中始终返回渲染数组,而不是调用 theme() 或 drupal_render()。

Twig 会自动渲染所有输出,因此不需要在预处理函数中调用 drupal_render() 或 theme()。相反,应将渲染数组传递给模板,这比传递已经渲染好的 HTML 字符串提供了更多的灵活性。

从预处理函数中移除 theme():

// 之前 - 将渲染好的 HTML 字符串传递到模板。
$variables['table'] = theme('table', ['header' => $header, 'rows' => $rows]);

// 之后 - 将渲染数组传递到模板。
$variables['table'] = [
  '#theme' => 'table',
  '#header' => $header,
  '#rows' => $rows,
];

从预处理函数中移除 drupal_render() 只需删除调用:

// 之前,不必要的 drupal_render() 调用。
$variables['teaser'] = drupal_render($node_teaser);

// 之后,移除了 drupal_render()。
$variables['teaser'] = $node_teaser;

一个常见情况是 drupal_render() 被用在表格数据中:

// 之前,不必要的 drupal_render() 调用。
$row[] = drupal_render($display['title']);

// 之后,移除了 drupal_render()。
$row[]['data'] = $display['title'];

在模板中使用过滤器和工具函数

虽然渲染数组为数据提供了可寻址、可修改的结构,但并非所有变量都需要渲染数组。为了尽可能长时间地保持数据的原始性,主题开发者应该在 Twig 模板中调用 过滤器(如 t),以及工具函数(如 url())。在 Twig 模板而不是预处理函数中调用这些函数,可以减少函数调用次数,因为传入模板的变量可能根本不会被打印出来。

之前:

在预处理函数中:

$variables['no_content_text'] = t('You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.', array('@create-content' => url('admin/structure/types/add')));

在模板中:

<p>{{ no_content_text }}</p>

之后:

在模板中:

<p>{{ 'You have not created any content types yet. Go to the <a href="@create-content">content type creation page</a> to add a new content type.'|t({'@create-content': url('admin/structure/types/add')}) }}</p>

显示 / 隐藏以及移除 drupal_render_children 和 element_children

如果在原始模板中使用了 hide(),并且使用 drupal_render_children 渲染「剩余」的数据,那么我们需要在预处理过程中将这些部分拆分为单独的变量。

之前(PHPTemplate 文件):

<?php
hide($form['advanced']);
hide($form['actions']);
?>
<div class="layout-node-form clearfix">
<div class="layout-region layout-region-node-main">
<?php print drupal_render_children($form); ?>
</div>
<div class="layout-region layout-region-node-secondary">
<?php print render($form['advanced']); ?>
</div>
<div class="layout-region layout-region-node-footer">
<?php print render($form['actions']); ?>
</div>
</div>

请使用 Twig 的「without」过滤器来隐藏特定元素。你可以像平常一样单独打印需要的部分。

之后:(Twig 模板)

<div class="layout-node-form clearfix">
  <div class="layout-region layout-region-node-main">
    {{ form|without('advanced', 'actions') }}
  </div>
  <div class="layout-region layout-region-node-secondary">
    {{ form.advanced }}
  </div>
  <div class="layout-region layout-region-node-footer">
    {{ form.actions }}
  </div>
</div>

替代方法(不再推荐):

将所有部分在预处理中拆分成单独的变量并传递到模板中。在渲染其余内容之前,可能需要将表单中的部分元素赋值给变量。然后在模板中精确地打印这些变量。

之前:(预处理)

function template_preprocess_node_edit_form(&$variables) {
  $form = $variables['form'];
  
  // @todo Update this once drupal.org/node/1920886 is resolved.
  $variables['advanced'] = $form['advanced'];
  $variables['actions'] = $form['actions'];
  unset($form['advanced'], $form['actions']);
  $variables['form'] = drupal_render_children($form);
}

之后:(Twig 模板)

<div class="layout-node-form clearfix">
  <div class="layout-region layout-region-node-main">
    {{ form }}
  </div>
  <div class="layout-region layout-region-node-secondary">
    {{ advanced }}
  </div>
  <div class="layout-region layout-region-node-footer">
    {{ actions }}
  </div>
</div>