Drupal 10:使用配置页面模块创建可配置的首页

Drupal 10:使用配置页面模块创建首页

在 Drupal 开发中,有许多不同的方法来创建首页。一种常见的做法是创建一个内容类型来存储所需的字段,并添加块以向首页布局中添加额外信息。

不过,添加一个内容类型来处理首页存在一些问题。要为用户正确设置编辑页面的权限可能比较棘手,而且编辑人员很容易不小心删除它,从而破坏整个网站。通常,我们必须以某种方式保护这些内容,以防止意外编辑或删除。

最近,我公司负责为一个 Drupal 网站设置首页,决定使用一个名为 Config Pages 的 Drupal 模块开发来创建一个可配置的首页。事实证明,这种方法相当简单,团队其他成员很快就采用了这种方法来引入额外的配置。

我觉得有必要写一篇文章详细介绍这种方法,因为虽然需要编写一点代码,但却能带来相当大的灵活性。

Config Pages 是一个允许创建一次性使用且可设置字段的实体的模块。这些实体可用于执行多项任务,包括公开配置和创建单例页面。

一、设置配置页面

安装该模块后,我们需要通过访问 /admin/structure/config_pages/types 路径来创建一个配置页面类型,并创建一个新类型。创建这些实体的设置页面包含几个选项,但实际上我们只需要设置标签即可。为了创建首页,可以放心地忽略关于令牌、菜单和上下文设置的字段。

创建完类型后,就可以像配置任何其他可设置字段的实体类型一样对其进行配置。只需向实体中添加所需的字段,以处理所有需要显示的数据。

为了这个示例,我公司创建了一个名为“homepage”的类型,它包含一些用于存储文本信息和一张图片的简单字段。

设置好这些后,我们现在可以访问 /admin/structure/config_pages/homepage/edit 路径,该路径将显示我们刚刚添加的字段的编辑页面。可以在这个表单中输入一些数据并保存,这将在数据库中创建该实体。我们在这里创建的实体是一次性使用的,这意味着它不能被复制或删除,因此非常适合用作首页。

注意,你可以通过在首页配置页面类型配置的“菜单”部分输入路径,使编辑此实体的路径更友好。以下示例将把这个路由改为 /homepage/edit,而不是 /admin/structure/config_pages/homepage/edit

现在我们可以将数据保存到首页实体中,但是如何显示这些数据呢?我们需要添加一点自定义代码来实现这一点。

二、为首页添加代码

为了让我们的配置页面首页正常工作,需要添加一些代码。实际上需要添加的代码并不多,我们只需要向一个模块中添加一个控制器操作来渲染首页即可。

在一个名为 mymodule 的新模块中,我公司创建了一个 mymodule.routing.yml 文件,并添加了以下配置。

mymodule.homepage:
  path: '/homepage'
  defaults:
    _title: 'Homepage'
    _controller: '\Drupal\mymodule\Controller\HomepageController::homepage'
  requirements:
    # 由于这是一个示例,特意将访问权限设置为开放。
    _access: 'TRUE'

这意味着如果用户访问 /homepage 页面,应该调用 HomepageController 类中的 homepage() 方法。homepage() 方法只需要加载首页实体并使用“full”默认视图模式进行渲染即可。

如果首页实体尚未创建,我们将显示一条简单的消息,内容为“未添加内容”。

以下是完整的控制器代码。

<?php

namespace Drupal\mymodule\Controller;

use Drupal\config_pages\Entity\ConfigPages;
use Drupal\Core\Controller\ControllerBase;

class HomepageController extends ControllerBase {

  public function homepage() {
    $configPage = ConfigPages::config('homepage');

    if ($configPage !== NULL) {
      $build = \Drupal::service('entity_type.manager')
        ->getViewBuilder('config_pages')
        ->view($configPage);
      $build['#cache']['tags'][] = 'homepage';
      return $build;
    }

    // 返回一个无缓存的空页面。
    $build = [];
    $build['no_content_added'] = [
      '#markup' => '<p>No content added.</p>',
      '#cache' => [
        'tags' => [
          'homepage',
        ],
        'max-age' => 0,
      ],
    ];
    return $build;

  }

}

在上述代码中需要注意的重要一点是,我们向控制器返回的渲染数组中添加了一个“homepage”缓存标签。这个标签很重要,因为当首页更新时,我们需要正确使缓存失效,以便显示新数据。

为了使这个标签失效,我们需要创建一个 hook_ENTITY_TYPE_update() 钩子,它将监听首页更新并使正确的标签失效。

/**
 * 实现 hook_ENTITY_TYPE_update()。
 */
function mymodule_config_pages_update(EntityInterface $entity) {
  if ($entity->bundle() === 'homepage') {
    // 当首页实体更新时使标签失效。
    $tags = $entity->getCacheTagsToInvalidate();
    $tags[] = 'homepage';
    Cache::invalidateTags($tags);
  }
}

有了这个钩子,对首页所做的任何更改都将立即显示。

如果你的首页上显示有任何视图或其他动态内容,那么你还需要将“homepage”标签注入到它们的缓存标签中,以便它们能正确更新首页缓存。

1. 本地任务

为编辑首页创建连贯的用户体验很重要,因此添加本地任务配置是个好主意。本地任务允许用户查看首页并看到一个编辑链接,通过该链接可以编辑页面。有这个链接比让用户在 Config Pages 模块中寻找正确的界面来编辑首页要好。

为此,我公司创建了一个 mymodule.links.task.yml 文件,并向其中添加了以下配置。

mymodule.homepage:
  title: "Homepage"
  route_name: "mymodule.homepage"
  base_route: "mymodule.homepage"
mymodule.homepage_edit:
  title: "Edit"
  route_name: "config_pages.homepage"
  base_route: "mymodule.homepage"

首页编辑页面的路由是 config_pages.homepage,所以我们只需要将其作为一个编辑链接添加到上面为控制器操作创建的路由之下即可。

就这样,现在我们可以通过 /homepage 路径加载首页,并看到本地任务在起作用时显示的内容。

以下是其实际运行的截图。

这看起来并不惊艳,但我们稍后会对主题进行自定义。

2. Drupal 首页配置

有了这些代码和配置后,我们现在可以更新 Drupal 的默认首页配置,使其指向我们的 /homepage 路径。该路径由我们之前创建的控制器提供服务。

完成这些后,你可以访问你的网站首页,看到通过控制器渲染的配置页面。

三、权限

值得快速查看一下 Config Pages 模块可用的权限。它为你设置的每个实体提供自定义权限,因此对于首页实体,我们只需要确保正确的用户具有编辑权限即可。“编辑首页配置页面实体”权限就是用于此目的的。

查看首页配置页面实体的权限并不是很重要,因为我们是通过控制器来渲染实体的,而控制器通过路由配置有自己的权限。

四、主题

Config Pages 自带的主题只是按照设置的顺序打印出字段。这没问题,但最好能对主题有更多的控制权。

幸运的是,Config Pages 模块通过 Drupal 模板系统来处理其渲染过程,默认模板名为 config-pages.html.twig。由于我们将 Config Pages 实体命名为“homepage”,因此我们只需要在主题中创建一个名为 config-pages--homepage.html.twig 的模板即可。

以下是新模板的内容。

{#
/**
 * @file
 * 显示配置页面的默认主题实现。
 *
 * @see template_preprocess_config_pages()
 *
 * @ingroup 可主题化
 */
#}
{%
  set classes = [
  'config_pages',
  'config_pages--type--' ~ config_pages.bundle|clean_class,
  view_mode ? 'config_pages--view-mode--' ~ view_mode|clean_class,
  view_mode ? 'config_pages--' ~ config_pages.bundle|clean_class ~ '--' ~ view_mode|clean_class,
]
%}
<div{{ attributes.addClass(classes) }}>

  <h1>{{ content.field_home_header_text }}</h1>
  <div>
    {{ content.field_homepage_banner_image }}
    {{ content.field_home_intro_text }}
  </div>

</div>

这只是一个小模板,用于展示如何打印出实体的各个组件,你可以在此基础上进行扩展,以创建所需的主题。

你还可以使用一个名为 template_preprocess_config_pages() 的预处理钩子,向首页主题中添加额外的内容。如果你想向首页内容中注入块或渲染视图,这将很有用。

五、结论

这是一种相当简单的生成首页的方法,你只需更改实体中的字段,就能满足任何需求。实现此功能所需的代码量很少,这使得首页设置具有相当大的灵活性。一旦一切设置完毕,最终效果会非常好。

由于我们用于编辑首页的实体是可配置的,因此我们可以通过配置管理系统快速推出对字段的任何更改。

我公司使用这种方法的项目实际上创建了两个配置页实体来显示首页。这样做是为了将编辑页面分成不同的部分,同时也允许其中一个部分在网站的其他部分重复使用。为了实现这一点,我们使用了 template_preprocess_config_pages() 钩子,将额外的配置页面注入到首页模板中,效果非常好。

如果你在这方面需要帮助,请联系我们。

这种方法的唯一问题是首页没有版本控制。这意味着如果首页被更改,就没有简单的方法恢复到之前的版本。似乎有计划让 Config Pages 支持版本控制,但这依赖于 Drupal 10.1.x 即将推出的新通用版本控制系统,也许在未来的 Drupal11 中会有更好的解决方案。如果你对此感兴趣,可以为该问题做出贡献。

我还应该注意到,Config Pages Viewer 模块可以实现与这里添加的自定义代码几乎相同的功能,但该模块似乎已被弃用。