Back

在 WordPress 中创建自定义文章类型

在 WordPress 中创建自定义文章类型

WordPress 自带文章(Posts)和页面(Pages),但当客户需要房产列表目录、员工名册或食谱档案时,这两种内容类型就显得力不从心了。这时就需要用到 WordPress 自定义文章类型(Custom Post Type)——一种一流的内容结构,它能够完美融入 WordPress 现有的数据模型,而无需对默认设置进行任何破解性修改。

核心要点

  • 自定义文章类型(CPT)扩展的是共享的 wp_posts 数据表,而不是创建单独的表,这使您可以开箱即用地获得管理界面、REST API 端点和模板路由功能。
  • 始终在插件中注册 CPT,而不是在主题中,这样无论主题如何更改,内容都能保持可访问。
  • 必须将 show_in_rest 设置为 true 才能支持区块编辑器和 REST API 访问。
  • 仅在插件激活时刷新重写规则——切勿在每次页面加载时执行。

什么是自定义文章类型?

自定义文章类型(CPT)是您在 WordPress 中注册的一种命名内容类型。尽管名称如此,但它并不是一个独立的数据库表。所有文章类型——无论是内置的还是自定义的——都共享 wp_posts 表,通过 post_type 列进行区分。这是一个重要的概念模型:您是在扩展现有结构,而不是创建一个平行结构。

默认的文章类型包括 postpageattachmentrevisionnav_menu_item。当您注册一个像 propertyrecipe 这样的 CPT 时,WordPress 会以同样一致的方式对待它:管理界面、REST API 端点、URL 路由和模板层级都以相同的方式工作。

自定义文章类型 ≠ 自定义字段。 CPT 定义的是内容的类型。自定义字段(通过 ACF 或元数据 API 添加)存储的是附加到该内容的额外数据。这是两个不同的概念。

使用 register_post_type() 注册自定义文章类型

创建 WordPress 自定义文章类型的标准方法是使用 register_post_type() 函数,在 init 钩子上调用。

以下是一个简洁且可用的示例:

add_action( 'init', 'register_property_post_type' );

function register_property_post_type() {
    $labels = [
        'name'               => 'Properties',
        'singular_name'      => 'Property',
        'add_new_item'       => 'Add New Property',
        'edit_item'          => 'Edit Property',
        'not_found'          => 'No properties found.',
    ];

    $args = [
        'labels'       => $labels,
        'public'       => true,
        'has_archive'  => true,
        'supports'     => [ 'title', 'editor', 'thumbnail', 'excerpt' ],
        'rewrite'      => [ 'slug' => 'properties' ],
        'show_in_rest' => true,
    ];

    register_post_type( 'property', $args );
}

关键参数说明

  • public — 使 CPT 在管理后台和前端可见。对于仅供内部使用的类型,设置为 false
  • labels — 控制管理后台中的所有 UI 文本。值得正确填写,以免编辑人员感到困惑。
  • supports — 声明编辑界面上显示哪些编辑器功能。常用值:titleeditorthumbnailexcerptcustom-fields
  • has_archive — 在 /properties/ 启用归档页面。WordPress 会查找匹配的 archive-property.php 模板(或回退到 archive.php)。
  • rewrite — 设置 URL 别名。单篇文章将显示在 /properties/post-name/
  • show_in_rest将此设置为 true 这会通过 WordPress REST API 公开 CPT,并且是区块编辑器正确处理您的文章类型所必需的。没有它,编辑器会回退到经典界面。

插件 vs. 主题:代码应该放在哪里?

这是一个常见的困惑点。在插件中注册自定义文章类型,而不是在主题中。

如果您的 CPT 注册代码位于 functions.php 中,而客户切换了主题,该类型的所有内容将变得无法访问——不是被删除,而是不可见。一个专用插件(即使是简单的单文件插件)可以使 CPT 在主题更改时保持活动状态。

不要在每次请求时刷新重写规则。 仅调用一次 flush_rewrite_rules() ——通过 register_activation_hook() 在插件激活时调用。在每次 init 时刷新会导致性能问题。

自定义文章类型的模板层级

对于单个 CPT 条目,WordPress 按以下顺序查找模板:

  1. single-{post-type}.php(例如 single-property.php)
  2. single.php
  3. singular.php
  4. index.php

对于归档页面,遵循:archive-{post-type}.phparchive.phpindex.php

总结

通过将 register_post_type() 正确挂载到 init,启用 show_in_rest,并将注册代码放在插件中,您就有了一个坚实、可移植的基础。从这里开始,您可以添加自定义分类法、通过 ACF 或元数据 API 添加元字段,以及自定义管理列——而不会触及任何在 WordPress 或主题更新时会损坏的内容。

常见问题

内容会保留在 wp_posts 表中,不会被删除。但是,WordPress 不再识别该文章类型,因此这些文章在管理后台和前端都会变得不可见。重新激活插件会立即恢复访问。这就是为什么 CPT 注册应该始终位于专用插件中而不是主题中的原因。

可以。您可以在同一个 init 回调中多次调用 register_post_type(),或使用挂载到 init 的单独回调。单个插件可以注册的自定义文章类型数量没有限制,但每个类型必须有一个不超过 20 个字符的唯一文章类型别名。

这几乎总是意味着需要刷新重写规则。在 WordPress 管理后台访问设置,然后访问固定链接,点击保存更改。这会触发重写刷新。对于插件,在 register_activation_hook() 内调用 flush_rewrite_rules(),这样它会在激活时自动运行。切勿在每次页面加载时刷新。

严格来说不需要,但仍然建议这样做。将 show_in_rest 设置为 true 会通过 WordPress REST API 公开您的文章类型,这对于无头设置、外部集成和未来兼容性很有用。如果您将来切换到区块编辑器,它已经可以正常工作了。

Gain Debugging Superpowers

Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers. Check our GitHub repo and join the thousands of developers in our community.

OpenReplay