Drupal核心功能覆写、视图优化及无头CMS选型咨询
针对Drupal POC问题的解决方案
1. 控制器层面去除文章内容的多余HTML标签
可以通过自定义控制器直接处理节点内容,绕过默认模板的嵌套HTML结构。核心思路是加载节点后,对字段内容进行HTML清理,再返回纯文本或精简后的HTML。
示例代码(自定义控制器)
假设你创建了一个名为custom_content的模块,在src/Controller/CleanContentController.php中编写:
<?php namespace Drupal\custom_content\Controller; use Drupal\Core\Controller\ControllerBase; use Drupal\node\Entity\Node; /** * 清理文章内容HTML标签的控制器. */ class CleanContentController extends ControllerBase { /** * 获取清理后的文章内容. * * @param int $nid * 节点ID. * * @return array * 渲染数组. */ public function getCleanContent($nid) { // 加载节点 $node = Node::load($nid); if (!$node) { return ['#markup' => $this->t('文章不存在')]; } // 获取body字段原始内容并清理标签 $body_value = $node->get('body')->value; // 保留必要标签,比如<p><h2>,其余全部去除 $cleaned_content = strip_tags($body_value, '<p><h2><h3>'); return [ '#markup' => $cleaned_content, ]; } }
然后在custom_content.routing.yml中配置路由:
custom_content.clean_content: path: '/clean-content/{nid}' defaults: _controller: '\Drupal\custom_content\Controller\CleanContentController::getCleanContent' _title: '清理后的文章内容' requirements: _permission: 'access content' nid: \d+
访问/clean-content/[节点ID]即可看到清理后的内容。如果要替换默认文章页面,可修改节点的视图模式,将其指向这个控制器的输出。
2. 为区块配置独立控制器获取数据
Drupal中可以通过自定义区块插件实现独立数据逻辑,直接在区块的build()方法中编写数据库查询或调用业务逻辑。以下是自定义区块的示例:
示例代码(自定义区块)
在src/Plugin/Block/RecentArticlesBlock.php中编写:
<?php namespace Drupal\custom_content\Plugin\Block; use Drupal\Core\Block\BlockBase; use Drupal\Core\Database\Connection; use Symfony\Component\DependencyInjection\ContainerInterface; /** * 显示最新文章的自定义区块. * * @Block( * id = "recent_articles_block", * admin_label = @Translation("最新文章区块"), * category = @Translation("自定义区块") * ) */ class RecentArticlesBlock extends BlockBase { /** * 数据库连接服务. * * @var \Drupal\Core\Database\Connection */ protected $database; /** * 构造函数. */ public function __construct(array $configuration, $plugin_id, $plugin_definition, Connection $database) { parent::__construct($configuration, $plugin_id, $plugin_definition); $this->database = $database; } /** * 依赖注入. */ public static function create(ContainerInterface $container, array $configuration, $plugin_id, $plugin_definition) { return new static( $configuration, $plugin_id, $plugin_definition, $container->get('database') ); } /** * 构建区块内容. */ public function build() { // 从数据库查询最新5篇已发布文章 $query = $this->database->select('node_field_data', 'n') ->fields('n', ['nid', 'title']) ->condition('type', 'article') ->condition('status', 1) ->orderBy('created', 'DESC') ->range(0, 5); $articles = $query->execute()->fetchAll(); // 构建渲染数组 $items = []; foreach ($articles as $article) { $items[] = [ '#type' => 'link', '#title' => $article->title, '#url' => \Drupal\Core\Url::fromRoute('entity.node.canonical', ['node' => $article->nid]), ]; } return [ '#theme' => 'item_list', '#items' => $items, '#title' => $this->t('最新文章'), ]; } }
启用模块后,在后台「结构」→「区块」中找到「最新文章区块」,将其放置到指定区域即可。这个区块的数据源完全由自定义逻辑控制,无需依赖视图或默认内容展示。
3. 无头Drupal vs Strapi/Ghost的选择建议
选无头Drupal的场景
- POC后续需要扩展复杂内容模型、多角色权限控制、工作流管理(比如审核流程),或者需要整合Drupal成熟的生态模块(电商、会员系统等)。
- 团队已有PHP/Drupal开发经验,能驾驭Drupal的学习曲线。
- 需要与现有Drupal站点共享内容或数据。
选Strapi的场景
- 追求快速搭建、轻量灵活,内容模型相对简单,团队熟悉Node.js技术栈。
- 需要快速生成REST/GraphQL API,且对自定义字段、权限的需求不复杂。
选Ghost的场景
- 核心需求是博客内容发布,需要开箱即用的博客功能(订阅、标签、内容排版等),无需复杂自定义。
总结
如果POC仅验证基础内容展示逻辑,Strapi/Ghost上手更快;如果后续有复杂业务需求,无头Drupal的扩展性更强,适合长期迭代。
内容的提问来源于stack exchange,提问作者Immanuel Thomas
相关产品推荐
相关产品推荐

