WordPress 中的 Blade 模板:使用 Kinsta 上的 Radicle 进行现代模板开发

传统的 WordPress 主题开发依赖于在各个模板文件中重复页眉和页脚标记。每次更新导航菜单或页脚元素时,您都需要找到包含该标记的每个模板文件,并在多个位置进行必要的更改。这增加了维护开销,并增加了网站出现不一致的风险。

Radicle 通过 Acorn 的 基于组件的架构将 Laravel 的 Blade 模板引擎 带入 WordPress。与其将标记分散在各个模板文件中,不如一次性定义可重用的组件,并在整个主题中引用它们。当需要更新 UI 元素时,只需修改单个组件文件,而无需在几十个模板中查找。

为什么 WordPress 模板开发需要基于组件的架构

WordPress 将模板存储在主题目录结构中,其中 header.phpfooter.php 通过 get_header()get_footer() 调用出现在每个页面模板中。这适用于基本站点,但在扩展到复杂项目时会产生问题。

例如,一个包含 自定义文章类型、落地页和营销模板的站点,在每个模板文件中都包含相同的导航标记、页脚结构和侧边栏元素。这要求您必须搜索多个模板文件才能添加新的菜单项或更新页脚中的联系表单。

Radicle 将 Blade 模板组织在 resources/views/ 中,并分别为布局、组件和区块设立单独的目录:

  • components。该目录包含自包含的 UI 元素,例如标题和按钮。
  • layouts。这包含定义页面脚手架的结构模板。
  • blocks。您在这里存储与 WordPress 站点编辑器集成的 区块模板

这种组织方式为每个 UI 元素创建了单一事实来源。x-heading 组件在一个位置定义标题标记和样式。因此,当您在模板中使用此组件时,Blade 会引用该单一定义。推而广之,更新组件即可更新整个站点中的每个实例。

如何构建消除重复代码的主要布局

您可以使用模板继承来创建定义站点外壳的父布局,而不是重复导航和页脚标记。

布局始于 resources/views/components/ 中的 Blade 组件文件。layout.blade.php 文件定义了包裹页面内容的 HTML 结构。这包括 doctype、包含元标记和资源引用的 head 部分、导航结构以及页脚元素。布局中的关键元素是 $slot 变量,Blade 将其用作内容注入点。

<html>
<head>
    <title>{{ $title ?? 'My Site' }}</title>
</head>

<body>
    <nav>
        
    </nav>

    <main>
        {{ $slot }}
    </main>

    <footer>
        
    </footer>

</body>
</html>

子模板使用 Blade 的组件语法扩展此布局。页面模板将其内容包裹在 x-layout 组件标签中。Blade 通过渲染布局组件并将子内容注入到 $slot 变量出现的位置来处理此过程:

<x-layout>
    <h1>Page Title</h1>
    <p>Page content goes here.</p>
</x-layout>

具名插槽为动态内容(例如页面标题)提供了额外的注入点。您可以定义具有特定名称的插槽,而不是接受默认插槽。带有 name 属性的 x-slot 组件将内容传递到这些指定位置:

<x-layout>
    <x-slot name="title">
        Custom Page Title
    </x-slot>

    <h1>Page Heading</h1>
    <p>Page content.</p>
</x-layout>

布局组件通过匹配插槽名称的变量访问具名插槽。这允许你从单个子模板将内容注入到多个布局位置。

创建可复用的 UI 组件以保持一致的设计模式

Blade 组件集中管理常见界面元素的样式和标记。

无需在每个模板中使用 Tailwind 类 编写按钮标记,你可以创建一个封装标记的按钮组件。该组件接受用于定制的“props”(属性),同时保持一致的基础样式。

x-heading 组件与其他排版组件配合使用就是一个很好的例子。它接受一个决定 HTML 元素(h1h2h3)的 level 属性,以及一个控制视觉比例的 size 属性。该组件在内部将这些属性映射到 Tailwind 类,从而将实现细节分离出来。

<x-heading level="h1" size="3xl">
    主页标题
</x-heading>

<x-heading level="h2" size="2xl">
    章节标题
</x-heading>

resources/views/components/heading.blade.php 中的组件文件使用 Blade 的 @props 指令定义接受的属性及其默认值,从而定义标记和样式逻辑。每个组件根据属性值构建带有相应类的适当 HTML 元素。

x-link 组件遵循相同的模式,支持针对不同链接样式的变体,变体属性可以在默认、按钮和无样式表现形式之间切换。

诸如 x-button 之类的 UI 组件允许你通过交互元素实现相同的目标。button 组件支持用于不同按钮样式的大小和变体属性。当你通过 x-modal 组件将其与 Alpine.js 等框架结合使用时,你可以在不将 JavaScript 分散到各个模板中的情况下处理交互:

<x-button variant="primary" @click="showModal = true">
    打开模态框
</x-button>

<x-modal x-show="showModal">
    <p>模态框内容</p>
</x-modal>

Props 非常适合处理字符串、布尔值和其他简单数据。Slots 更适合处理包含标记的复杂内容。例如,modal 组件使用默认插槽来接受完整的模态框内容,而不是通过 prop 传递 HTML。

使用视图组合器将 WordPress 数据连接到 Blade 模板

视图组合器允许你在渲染模板之前聚合来自多个来源的数据。在这里,你创建一个处理数据检索和转换的 composer 类,而不是直接在模板中查询文章。相反,模板接收结构化的数据以供显示。

Radicle 的 Post 模型通过几种不同的方法简化了处理 WordPress 文章数据的工作:

  • title() 返回文章标题。
  • content() 方法检索经过筛选的文章内容。
  • excerpt() 接受字数并生成摘要。
  • permalink() 返回文章 URL。

对于特色图片,hasThumbnail() 检查图片是否存在,而 thumbnail() 检索指定尺寸的图片 HTML:

$post = Post::find(123);
echo $post->title();
echo $post->excerpt(30);
if ($post->hasThumbnail()) {
    echo $post->thumbnail('large');
}

视图组合器类位于 app/View/Composers/ 并继承 Roots\Acorn\View\Composer。该类通过受保护的静态 $views 属性定义其应用于哪些视图,该属性接受模板名称数组。对于首页组合器,指定 'front-page' 即可定位 front-page.blade.php 模板:

namespace App\View\Composers;
use App\Models\Post;
use Roots\Acorn\View\Composer;
class FrontPage extends Composer

{
    protected static $views = ['front-page'];
    public function with()
    {
        return [
            'recentPosts' => Post::recent(6)->get(),
            'totalPosts' => Post::published()->count(),
        ];
    }
}

with() 方法返回一个数组,其中的键会成为模板中的变量名。值可以是 Eloquent 集合、单个模型或任何数据结构。无论如何,此方法在任何模板渲染之前运行并准备数据。

front-page.blade.php 模板直接访问这些变量。Blade 的 @foreach 指令循环遍历文章,每次迭代都会提供对 Post 模型方法的访问:

<div>
    @foreach ($recentPosts as $post)
        <article>
            @if ($post->hasThumbnail())
                <img src="{{ $post->thumbnail('medium') }}" alt="{{ $post->title() }}">
            @endif

            <h2>
                <a href="{{ $post->permalink() }}">{{ $post->title() }}</a>
            </h2>

            <p>{{ $post->excerpt(20) }}</p>
        </article>
    @endforeach
</div>
<p>Total posts: {{ $totalPosts }}</p>

在这种模式中,视图编排器处理查询和数据转换,而模板专注于标记和显示逻辑。当你需要修改数据结构或添加新查询时,你更新视图编排器而无需接触模板文件。

使用 Blade 渲染为 WordPress 站点编辑器构建区块

Radicle 通过 Blade 模板为站点编辑器区块使用服务器端渲染。JavaScript 编辑器组件处理 WordPress 管理后台中的区块界面,而 Blade 模板处理前端输出。

这让你可以使用 React(例如)构建区块界面,同时使用 Blade 渲染生产环境的 HTML。

wp acorn make:block 命令为每个区块生成三个文件:

  • app/Blocks/ 中的 PHP 类管理服务器端逻辑。
  • resources/js/editor/ 中的 JSX 组件定义区块编辑器界面。
  • resources/views/blocks/ 中的 Blade 模板渲染前端输出。

wp acorn make:block latest-posts 命令会创建 LatestPosts.phplatest-posts.block.jsxlatest-posts.blade.php。JSX 文件定义区块的属性和编辑器控件,而动态区块使用 InspectorControls 在区块侧边栏中添加设置。你可以从 @wordpress/components 导入控件并将它们组合成一个设置界面。

import { InspectorControls } from '@wordpress/block-editor';
import { RangeControl, ToggleControl, RadioControl } from '@wordpress/components';
export const attributes = {
    posts: { type: 'number', default: 5 },
    displayFeaturedImage: { type: 'boolean', default: false },
    postLayout: { type: 'string', default: 'list' },
};

export const edit = ({ attributes, setAttributes }) => {
    return (
        <>
            <InspectorControls>
                <RangeControl
                    label="Number of posts"
                    value={attributes.posts}
                    onChange={(value) => setAttributes({ posts: value })}
                    min={1}
                    max={10}
                />
                <ToggleControl
                    label="Display featured image"
                    checked={attributes.displayFeaturedImage}
                    onChange={(value) => setAttributes({ displayFeaturedImage: value })}
                />
                <RadioControl
                    label="Layout"
                    selected={attributes.postLayout}
                    options={[
                        { label: 'List', value: 'list' },
                        { label: 'Grid', value: 'grid' },
                    ]}
                    onChange={(value) => setAttributes({ postLayout: value })}
                />
            </InspectorControls>
        </>
    );
};

BlocksServiceProvider.php 中的 render_block 过滤器拦截区块渲染并将属性传递给 Blade 模板。它还接收区块内容和区块数据。你检查区块名称,查询必要的数据,并返回渲染后的 Blade 视图:

add_filter('render_block', function ($block_content, $block) {
    if ($block['blockName'] === 'radicle/latest-posts') {
        $attributes = $block['attrs'] ?? [];

        $posts = get_posts([
            'numberposts' => $attributes['posts'] ?? 5,
            'post_status' => 'publish',
        ]);

        return view('blocks.latest-posts', [
            'posts' => $posts,
            'displayFeaturedImage' => $attributes['displayFeaturedImage'] ?? false,
            'postLayout' => $attributes['postLayout'] ?? 'list',
        ]);
    }

    return $block_content;
}, 10, 2);

Blade 模板使用 PHP 数组来管理条件布局。在这里,您将布局配置定义为嵌套数组,将布局名称映射到 CSS 类和 HTML 元素。

@php
$layoutConfig = [
    'grid' => [
        'container' => 'grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-6',
        'element' => 'div',
    ],
    'list' => [
        'container' => 'space-y-6',
        'element' => 'div',
    ],
];
$config = $layoutConfig[$postLayout];
@endphp
<div>
    @foreach ($posts as $post)
        <article>
            @if ($displayFeaturedImage && has_post_thumbnail($post))
                {{ get_the_post_thumbnail($post, 'medium') }}
            @endif

            <h3>{{ $post->post_title }}</h3>
        </article>
    @endforeach
</div>

这种模式创建了灵活的区块,编辑器控件可以调整前端输出而无需重复模板逻辑:JavaScript 处理用户界面,PHP 处理数据查询,Blade 处理标记结构。

Kinsta 的缓存如何提升 Blade 编译视图的性能

Blade 编译本质上将 .blade.php 模板转换为纯 PHP 代码。在 Blade 完成对模板和 Blade 语法的完整解析后,它会将编译后的文件存储在 storage/framework/views/ 中。这种编译在每次模板更改时进行一次,而不是在每次页面加载时进行,但随后的请求会跳过编译并执行缓存的 PHP。

该过程将 Blade 指令转换为 PHP 函数。例如,@foreach 指令变为 foreach 循环;{{ $variable }} 语法变为带有转义的 echo 语句。

Kinsta 的服务器级缓存(包括 边缘缓存Redis 对象缓存)与 Blade 的编译缓存协同工作,创建多层性能。Blade 的编译视图位于这些层之间,这些层提供了受益于上游缓存和下游优化的模板执行时间。

在部署期间,当您将模板更改推送到暂存或生产环境时,Blade 会清除缓存。虽然 Blade 在开发过程中会检测模板修改,但您的部署过程应包括通过在部署脚本中运行 php artisan view:clearwp acorn view:clear 来清除视图缓存。

现代 WordPress 主题开发包括 Radicle 和 Kinsta

Radicle 的 Laravel 风格结构与 Kinsta 的托管基础设施 相结合,为您提供了扩展 WordPress 项目的基础。管理多个客户网站的代理机构可以利用跨项目的一致组件模式。对于开发人员,您可以使用熟悉的 Laravel 约定,同时保持与 WordPress 的兼容性。

您的下一步取决于您当前的设置。如果您是重新开始,请先安装 Radicle 并创建您的第一个 Blade 组件。如果您正在迁移现有主题,请识别重复的标记模式并将它们逐部分转换为组件。重点关注高价值区域,如导航、页眉和页脚,在这些区域组件的好处是立竿见影的。

如果您需要支持现代开发工作流的托管 WordPress 主机,Kinsta 提供的功能 可与 Radicle 和 Acorn 等工具配合使用。

分享你的喜爱

留下评论

您的邮箱地址不会被公开。 必填项已用 * 标注