WordPress主题开发:如何基于`Full Site Editing (FSE)`和`block.json`构建无代码主题?

WordPress 无代码主题开发:基于 FSE 和 block.json 的进阶实践

大家好,今天我们来深入探讨如何利用 WordPress 的 Full Site Editing (FSE) 和 block.json 打造一个无需编写 PHP 代码的主题。这并非完全字面意义上的“无代码”,而是指将主题逻辑主要集中在区块配置和模板定制上,最大限度地减少对传统 PHP 主题文件的依赖。

1. FSE 和 block.json 概述

Full Site Editing (FSE) 是 WordPress 5.9 引入的一项重大更新,它允许用户使用区块编辑器来构建整个网站,包括头部、页脚、文章模板等。FSE 的核心思想是将网站的各个部分都视为可编辑的区块,从而实现高度的可定制性和灵活性。

block.json 文件是区块元数据的核心载体。它定义了区块的名称、标题、描述、属性、样式、脚本和样式依赖等信息。通过 block.json,我们可以以声明式的方式定义区块的行为和外观,而无需编写大量的 JavaScript 或 CSS 代码。

2. 准备工作

在开始之前,我们需要确保满足以下条件:

  • WordPress 版本: 确保你的 WordPress 版本为 5.9 或更高。
  • 主题支持: 激活一个支持 FSE 的主题,例如 Twenty Twenty-Two 或 Twenty Twenty-Three。或者,我们可以创建一个基本的主题结构,并声明对 FSE 的支持。
  • 开发环境: 搭建一个本地 WordPress 开发环境,方便测试和调试。

3. 创建一个基本的 FSE 主题

要创建一个最简 FSE 主题,只需包含以下文件:

  • style.css: 包含主题的基本信息。
  • theme.json: 定义主题的全局样式和设置。
  • index.php (可选): 在 FSE 完全接管之前,用于处理一些兼容性问题。

3.1 style.css

/*
 Theme Name:   My FSE Theme
 Theme URI:    https://example.com/my-fse-theme/
 Description:  A basic FSE theme.
 Version:      1.0.0
 Author:       Your Name
 Author URI:   https://example.com/
 License:      GPL v2 or later
 License URI:  https://www.gnu.org/licenses/gpl-2.0.html
 Text Domain:  my-fse-theme
*/

3.2 theme.json

{
    "version": 2,
    "settings": {
        "appearanceTools": true,
        "color": {
            "palette": [
                {
                    "slug": "primary",
                    "color": "#007bff",
                    "name": "Primary"
                },
                {
                    "slug": "secondary",
                    "color": "#6c757d",
                    "name": "Secondary"
                },
                {
                    "slug": "light",
                    "color": "#f8f9fa",
                    "name": "Light"
                },
                {
                    "slug": "dark",
                    "color": "#343a40",
                    "name": "Dark"
                }
            ],
            "gradients": [
                {
                    "slug": "vivid-cyan-blue-to-vivid-purple",
                    "gradient": "linear-gradient(135deg,rgba(6,147,227,1) 0%,rgb(155,81,224) 100%)",
                    "name": "Vivid Cyan Blue to Vivid Purple"
                }
            ],
            "custom": true,
            "link": true
        },
        "typography": {
            "fontFamilies": [
                {
                    "fontFamily": "-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen-Sans, Ubuntu, Cantarell, 'Helvetica Neue', sans-serif",
                    "slug": "system-font",
                    "name": "System Font"
                }
            ],
            "fontSizes": [
                {
                    "slug": "small",
                    "size": "14px",
                    "name": "Small"
                },
                {
                    "slug": "medium",
                    "size": "16px",
                    "name": "Medium"
                },
                {
                    "slug": "large",
                    "size": "18px",
                    "name": "Large"
                }
            ],
            "custom": true
        },
        "layout": {
            "contentSize": "900px",
            "wideSize": "1200px"
        }
    },
    "styles": {
        "elements": {
            "link": {
                "color": {
                    "text": "var(--wp--preset--color--primary)"
                }
            }
        }
    }
}

这个 theme.json 文件定义了主题的颜色方案、字体、布局等全局设置。 appearanceTools: true 开启了许多额外的外观控制选项。

3.3 index.php (可选)

<?php
/**
 * The main template file
 *
 * This is the most generic template file in a WordPress theme
 * and one of the two required files for a theme (the other being style.css).
 * It is used to display a page when nothing more specific matches a query.
 * E.g., it puts together the home page when no home.php file exists.
 *
 * @link https://developer.wordpress.org/themes/basics/template-hierarchy/
 *
 * @package My_FSE_Theme
 */

get_header();
?>

    <main id="primary" class="site-main">

        <?php
        if ( have_posts() ) {

            // Load posts loop.
            while ( have_posts() ) {
                the_post();
                get_template_part( 'template-parts/content/content' );
            }

            // Previous/next page navigation.
            the_posts_navigation();

        } else {

            // If no content, include the "No posts found" template.
            get_template_part( 'template-parts/content/content-none' );

        }
        ?>

    </main><!-- #primary -->

<?php
get_footer();

虽然 FSE 允许我们通过区块编辑器创建模板,但 index.php 仍然可以作为后备方案,或者用于处理一些高级逻辑。

4. 创建区块模板

FSE 的强大之处在于可以通过区块编辑器创建和定制模板。我们可以创建以下类型的模板:

  • index.html: 默认的站点模板。
  • home.html: 用于显示博客首页。
  • single.html: 用于显示单个文章。
  • page.html: 用于显示页面。
  • archive.html: 用于显示文章归档。
  • search.html: 用于显示搜索结果。
  • 404.html: 用于显示 404 错误页面。

4.1 创建 index.html

  1. 在 WordPress 后台,进入“外观” -> “编辑器”。
  2. 点击站点图标,选择“模板” -> “添加新模板”。
  3. 选择 "index" 作为模板类型,并点击 "创建"。
  4. 使用区块编辑器构建你的站点模板。例如,你可以添加一个头部区块、一个文章区块循环、和一个页脚区块。
  5. 保存模板。

一个简单的 index.html 模板可能如下所示:

<!-- wp:template-part {"slug":"header","tagName":"header"} -->
<header id="masthead" class="wp-block-template-part has-no-title">
    <!-- wp:site-title /-->

    <!-- wp:navigation {"isResponsive":true,"openSubmenusOnClick":false,"showSubmenuIcon":true,"useSeparators":true} /-->
</header>
<!-- /wp:template-part -->

<!-- wp:group {"tagName":"main","layout":{"inherit":true}} -->
<main class="wp-block-group">
    <!-- wp:query {"query":{"perPage":10,"pages":0,"offset":0,"postType":"post","inherit":true},"displayLayout":{"columns":3}} -->
        <div class="wp-block-query">
            <!-- wp:post-template -->
                <!-- wp:post-featured-image {"isLink":true} /-->

                <!-- wp:post-title {"isLink":true} /-->

                <!-- wp:post-excerpt /-->
            <!-- /wp:post-template -->

            <!-- wp:query-pagination -->
                <!-- wp:query-pagination-previous /-->
                <!-- wp:query-pagination-numbers /-->
                <!-- wp:query-pagination-next /-->
            <!-- /wp:query-pagination -->
        </div>
    <!-- /wp:query -->
</main>
<!-- /wp:group -->

<!-- wp:template-part {"slug":"footer","tagName":"footer"} -->
<footer class="wp-block-template-part has-no-title">
    <!-- wp:paragraph {"align":"center"} -->
    <p class="has-text-align-center">Powered by WordPress</p>
    <!-- /wp:paragraph -->
</footer>
<!-- /wp:template-part -->

注意:这些模板实际上是以 HTML 注释的形式存储在数据库中的。

4.2 创建模板部件 (Template Parts)

模板部件是可以在多个模板中重复使用的区块集合。常见的模板部件包括头部、页脚、侧边栏等。

  1. 在 WordPress 后台,进入“外观” -> “编辑器”。
  2. 点击站点图标,选择“模板部件” -> “添加新模板部件”。
  3. 为模板部件指定一个名称和区域(例如 "header" 或 "footer"),并点击 "创建"。
  4. 使用区块编辑器构建你的模板部件。
  5. 保存模板部件。

5. 创建自定义区块 (Custom Blocks)

虽然 WordPress 已经提供了大量的内置区块,但有时我们需要创建自定义区块来满足特定的需求。 我们可以使用 block.json 来定义自定义区块,而无需编写复杂的 JavaScript 代码 (对于简单的静态区块)。

5.1 创建区块目录

在你的主题目录下创建一个 blocks 目录,用于存放所有的自定义区块。

5.2 创建区块文件

blocks 目录下,为你的区块创建一个单独的目录,例如 blocks/my-custom-block/。 在这个目录下,创建以下文件:

  • block.json: 区块的元数据定义。
  • index.php: 区块的渲染逻辑(如果需要)。

5.3 block.json 示例

{
    "name": "my-fse-theme/my-custom-block",
    "title": "My Custom Block",
    "description": "A simple block for displaying custom content.",
    "category": "common",
    "icon": "smiley",
    "keywords": [ "custom", "block" ],
    "attributes": {
        "content": {
            "type": "string",
            "default": "Hello, world!"
        },
        "alignment": {
            "type": "string",
            "enum": [ "left", "center", "right" ],
            "default": "center"
        }
    },
    "supports": {
        "align": true,
        "html": false
    },
    "textdomain": "my-fse-theme",
    "editorScript": "file:./index.js",
    "style": "file:./style.css",
    "viewScript": "file:./view.js"
}

这个 block.json 文件定义了一个名为 my-fse-theme/my-custom-block 的区块,它具有以下属性:

  • name: 区块的唯一名称。
  • title: 区块的显示名称。
  • description: 区块的描述。
  • category: 区块所属的类别。
  • icon: 区块的图标。
  • keywords: 区块的关键词。
  • attributes: 区块的属性,例如 contentalignment
  • supports: 区块支持的功能,例如对齐方式和 HTML 编辑。
  • textdomain: 区块的文本域,用于国际化。
    • editorScript: 编辑器环境下的 JS 文件
    • style: 编辑器和前端通用的 CSS 样式文件
    • viewScript: 前端 JS 文件

5.4 index.php 示例

<?php
/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function create_block_my_custom_block_block_init() {
    register_block_type( __DIR__ );
}
add_action( 'init', 'create_block_my_custom_block_block_init' );

这个 index.php 文件注册了区块。 register_block_type( __DIR__ ) 函数会自动加载 block.json 文件,并根据其中的元数据注册区块。

5.5 无需 JavaScript 的静态区块

如果你的区块只是简单地显示一些静态内容,你可以完全省略 editorScriptviewScript,并在 index.php 中使用 render_callback 来定义区块的渲染逻辑。

<?php
/**
 * Registers the block using the metadata loaded from the `block.json` file.
 * Behind the scenes, it registers also all assets so they can be enqueued
 * through the block editor in the corresponding context.
 *
 * @see https://developer.wordpress.org/reference/functions/register_block_type/
 */
function create_block_my_custom_block_block_init() {
    register_block_type( __DIR__, [
        'render_callback' => 'render_my_custom_block'
    ] );
}
add_action( 'init', 'create_block_my_custom_block_block_init' );

function render_my_custom_block( $attributes, $content, $block ) {
    $content = isset( $attributes['content'] ) ? $attributes['content'] : 'Hello, World!';
    $alignment = isset( $attributes['alignment'] ) ? $attributes['alignment'] : 'center';

    return '<div style="text-align: ' . esc_attr( $alignment ) . ';">' . esc_html( $content ) . '</div>';
}

在这个例子中,render_my_custom_block 函数根据区块的属性生成 HTML 代码。 esc_attresc_html 函数用于对属性值进行转义,以防止安全漏洞。

5.6 使用 JavaScript 的动态区块

如果你的区块需要更复杂的交互或动态行为,你需要使用 JavaScript 来定义区块的编辑器界面和前端行为。

  1. 创建 index.js (编辑器脚本): 这个文件包含区块的编辑器逻辑,例如自定义控件、属性处理等。

    import { registerBlockType } from '@wordpress/blocks';
    import { useBlockProps, RichText, AlignmentToolbar, BlockControls } from '@wordpress/block-editor';
    import { __ } from '@wordpress/i18n';
    
    registerBlockType( 'my-fse-theme/my-custom-block', {
        edit: ( props ) => {
            const { attributes, setAttributes } = props;
            const { content, alignment } = attributes;
    
            const onChangeContent = ( newContent ) => {
                setAttributes( { content: newContent } );
            };
    
            const onChangeAlignment = ( newAlignment ) => {
                setAttributes( { alignment: newAlignment === undefined ? 'center' : newAlignment } );
            };
    
            return (
                <div { ...useBlockProps() }>
                    <BlockControls>
                        <AlignmentToolbar
                            value={ alignment }
                            onChange={ onChangeAlignment }
                        />
                    </BlockControls>
                    <RichText
                        tagName="p"
                        className="my-custom-block-text"
                        placeholder={ __( 'Enter your text...', 'my-fse-theme' ) }
                        value={ content }
                        onChange={ onChangeContent }
                        style={ { textAlign: alignment } }
                    />
                </div>
            );
        },
        save: ( props ) => {
            const { attributes } = props;
            const { content, alignment } = attributes;
    
            return (
                <div { ...useBlockProps.save() }>
                    <p style={ { textAlign: alignment } }>{ content }</p>
                </div>
            );
        },
    } );
  2. 创建 view.js (前端脚本): 这个文件包含区块的前端逻辑,例如动画效果、事件处理等。通常来说,对于静态区块,这个文件可以为空。

    // This file can be empty if your block doesn't require any front-end JavaScript.
  3. 配置 block.json:block.json 文件中,指定 editorScriptviewScript 的路径。

    {
        "name": "my-fse-theme/my-custom-block",
        "title": "My Custom Block",
        "description": "A simple block for displaying custom content.",
        "category": "common",
        "icon": "smiley",
        "keywords": [ "custom", "block" ],
        "attributes": {
            "content": {
                "type": "string",
                "default": "Hello, world!"
            },
            "alignment": {
                "type": "string",
                "enum": [ "left", "center", "right" ],
                "default": "center"
            }
        },
        "supports": {
            "align": true,
            "html": false
        },
        "textdomain": "my-fse-theme",
        "editorScript": "file:./index.js",
        "viewScript": "file:./view.js"
    }
  4. 构建 JavaScript 文件: 你需要使用 Webpack 或其他构建工具将 JavaScript 文件打包成浏览器可以识别的格式。WordPress 提供了 @wordpress/scripts 包,可以简化构建过程。

    • 安装 @wordpress/scripts:

      npm install @wordpress/scripts --save-dev
    • package.json 文件中添加构建脚本:

      {
        "name": "my-fse-theme",
        "version": "1.0.0",
        "description": "",
        "main": "index.js",
        "scripts": {
          "build": "wp-scripts build",
          "start": "wp-scripts start"
        },
        "keywords": [],
        "author": "",
        "license": "ISC",
        "devDependencies": {
          "@wordpress/scripts": "^26.7.0"
        },
        "dependencies": {
            "@wordpress/block-editor": "^12.10.0",
            "@wordpress/blocks": "^11.20.0",
            "@wordpress/i18n": "^4.4.0"
        }
      }
    • 运行构建脚本:

      npm run build

      这将在你的区块目录下生成 build 目录,其中包含打包后的 JavaScript 文件。

  5. Enqueue 脚本和样式: 确保在你的主题中 Enqueue 区块的脚本和样式。WordPress 会自动处理这一点,只要 editorScriptstyle 属性在 block.json 中正确设置。

6. 全局样式与 theme.json

theme.json 文件是 FSE 主题的核心配置文件。它允许你定义主题的全局样式、设置和特性。

6.1 全局样式 (Styles)

styles 属性用于定义主题的全局样式,例如颜色、字体、间距等。

{
  "version": 2,
  "styles": {
    "elements": {
      "link": {
        "color": {
          "text": "var(--wp--preset--color--primary)"
        }
      },
      "heading": {
          "color": {
              "text": "var(--wp--preset--color--dark)"
          },
          "typography": {
              "fontFamily": "var(--wp--preset--font-family--system-font)"
          }
      }
    },
    "blocks": {
      "core/heading": {
        "color": {
          "text": "var(--wp--preset--color--secondary)"
        }
      }
    }
  }
}
  • elements: 用于设置 HTML 元素(例如 linkheading)的样式。
  • blocks: 用于设置特定区块的样式。

6.2 全局设置 (Settings)

settings 属性用于定义主题的全局设置,例如颜色调色板、字体大小、布局等。

{
  "version": 2,
  "settings": {
    "appearanceTools": true,
    "color": {
      "palette": [
        {
          "slug": "primary",
          "color": "#007bff",
          "name": "Primary"
        },
        {
          "slug": "secondary",
          "color": "#6c757d",
          "name": "Secondary"
        }
      ],
      "gradients": [],
      "custom": true,
      "link": true
    },
    "typography": {
      "fontFamilies": [],
      "fontSizes": [],
      "custom": true
    },
    "layout": {
      "contentSize": "900px",
      "wideSize": "1200px"
    }
  }
}
  • appearanceTools: 启用或禁用主题外观工具。
  • color: 定义颜色调色板、渐变等。
  • typography: 定义字体系列、字体大小等。
  • layout: 定义内容区域的宽度。

7. 高级技巧

  • 模式 (Patterns): 模式是预定义的区块布局,可以方便用户快速创建复杂的页面结构。你可以使用区块编辑器创建模式,并将它们导出为 JSON 文件,然后将这些文件放置在主题的 patterns 目录下。

  • 模板层叠 (Template Hierarchy): FSE 仍然支持传统的 WordPress 模板层叠。这意味着你可以使用 PHP 文件来覆盖 FSE 模板。例如,你可以创建一个 single.php 文件来覆盖 single.html 模板。

  • 条件逻辑: 虽然 FSE 旨在减少对 PHP 代码的依赖,但在某些情况下,你可能需要使用 PHP 代码来实现条件逻辑。你可以使用 render_callback 函数或创建自定义区块来实现这一点。

  • 主题继承: 你可以创建一个子主题,并继承父主题的 FSE 模板和区块。这可以方便你定制现有主题,而无需从头开始。

8. 常见问题与解决方案

问题 解决方案
区块未显示在编辑器中 检查 block.json 文件是否正确配置,并确保区块已正确注册。 检查 index.php 文件中的注册函数是否被正确调用. 检查 JavaScript 构建过程是否成功完成,并且生成的 JavaScript 文件已正确 Enqueue。
区块样式未生效 检查 style.css 文件是否已正确 Enqueue。 检查 CSS 选择器是否正确。 检查 theme.json 文件中的全局样式是否正确配置。
JavaScript 代码未执行 检查 editorScriptviewScript 是否已正确配置。 检查 JavaScript 代码是否存在错误。 确保 JavaScript 文件已正确 Enqueue。
模板未生效 检查模板文件是否已正确命名。 检查模板文件是否已正确放置在主题目录下。 清除 WordPress 缓存。
theme.json 配置无效 检查 theme.json 文件的语法是否正确。 检查 WordPress 版本是否支持你使用的 theme.json 功能。
模板编辑器无法保存更改 检查服务器的 max_input_vars 设置是否足够大。 一些主机提供商可能会限制允许的输入变量数量,这可能会导致模板编辑器无法保存更改。
模板部件 (Template Parts) 不显示 确保在模板部件中添加了内容。 确保模板部件已正确分配到区域。 检查模板部件是否已正确 Enqueue。

9. 小结

通过 FSE 和 block.json,我们可以构建高度可定制的 WordPress 主题,而无需编写大量的 PHP 代码。 这种方法使主题开发更加灵活和高效,并使更多的人能够参与到 WordPress 主题的定制中来。 当然,要完全实现“无代码”可能仍然有挑战,但我们可以通过充分利用区块配置和模板定制,最大限度地减少对传统 PHP 主题文件的依赖。 拥抱 FSE 和 block.json,将开启 WordPress 主题开发的新纪元。

让主题开发更友好

使用 FSE 和 block.json 可以简化主题开发,降低了技术门槛。

发表回复

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