搜索全站
数据库 13 分钟阅读

WordPress 文章、页面与自定义文章类型:什么时候该用哪个

把产品、案例、FAQ 全塞进"文章",后期结构和 SEO 都会失控。本文讲清 post、page、CPT 三种内容类型的本质差异,给出 register_post_type 完整代码、CPT 归档与固定链接配置、以及 CPT 在 SEO 上的注意事项。

U
UFO_PF 2024-01-22 · 阅读 13 分钟
Wo 数据库
阅读提示
本文约 4,861 字,预计阅读 13 分钟。文中命令与配置均经过实测,可直接参考执行。

引言:什么都往”文章”里塞的代价

一个企业站,产品、案例、团队、FAQ、下载资料,全部用”文章”发布,靠分类区分。半年后问题来了:

  • 想给产品单独做详情页模板,做不了——所有文章共用 single.php;
  • 想让案例的 URL 是 /case/xxx/ 而不是 /blog/xxx/,做不了;
  • 后台文章列表几千条混在一起,编辑找不到东西;
  • 想让”产品”不出现在 RSS 和站点搜索里,做不了。

这些问题的正确解法是自定义文章类型(Custom Post Type,简称 CPT)。它是 WordPress 从博客系统变成 CMS 的关键能力。

原理分析:三种类型的本质差异

数据库层面,post 和 page 都存在 wp_posts 表,区别只有一个 post_type 字段:

SELECT post_type, COUNT(*) FROM wp_posts
WHERE post_status = 'publish' GROUP BY post_type;

但语义和行为差别很大:

特性 文章 post 页面 page CPT
是否有时间属性 有(发布时间、归档) 无 可配置
是否参与 RSS 是 否 可配置
是否有分类/标签 有 无 可配置
是否有归档页 无独立归档(按分类/日期) 无 可配置 has_archive
层级 无 有(父子页面) 可配置 hierarchical
模板文件 single.php page.php single-{post_type}.php

判断标准其实很简单:

  • 有发布时间、会持续新增、需要按时间倒序和分类聚合 → 文章
  • 静态、不常变、不属于时间序列(关于我们、联系我们、服务介绍) → 页面
  • 内容结构自成一体、需要独立 URL 前缀和独立模板(产品、案例、课程、FAQ、房产、招聘) → CPT

保姆级实操

场景一:用代码注册一个”案例”CPT

推荐写在子主题的 functions.php 或自建的功能插件里,不要写在父主题(更新会被覆盖)。

add_action( 'init', 'mmf_register_case_cpt' );
function mmf_register_case_cpt() {
    $labels = array(
        'name'          => '客户案例',
        'singular_name' => '案例',
        'add_new'       => '添加案例',
        'add_new_item'  => '添加新案例',
        'edit_item'     => '编辑案例',
        'all_items'     => '全部案例',
        'search_items'  => '搜索案例',
        'not_found'     => '暂无案例',
    );

    $args = array(
        'labels'        => $labels,
        'public'        => true,
        'publicly_queryable' => true,
        'show_ui'       => true,
        'show_in_menu'  => true,
        'show_in_rest'  => true,          // 关键:启用 Gutenberg 和 REST API
        'menu_position' => 5,
        'menu_icon'     => 'dashicons-portfolio',
        'supports'      => array( 'title', 'editor', 'thumbnail', 'excerpt', 'custom-fields' ),
        'has_archive'   => true,          // 启用 /case/ 归档页
        'rewrite'       => array( 'slug' => 'case', 'with_front' => false ),
        'hierarchical'  => false,
        'taxonomies'    => array( 'case_cat' ),
        'capability_type' => 'post',
        'map_meta_cap'  => true,
    );

    register_post_type( 'case', $args );
}

配套注册它的分类法:

add_action( 'init', 'mmf_register_case_tax' );
function mmf_register_case_tax() {
    register_taxonomy( 'case_cat', 'case', array(
        'labels'       => array( 'name' => '案例分类', 'singular_name' => '案例分类' ),
        'public'       => true,
        'hierarchical' => true,
        'show_in_rest' => true,
        'rewrite'      => array( 'slug' => 'case-cat' ),
    ) );
}

必须注意:注册完 CPT 后要去 设置 → 固定链接 → 点一次”保存更改”,否则 /case/xxx/ 会 404。这是 CPT 最常见的”注册了打不开”问题。命令行:

wp rewrite flush

场景二:不用代码,用插件

  • Custom Post Type UI(CPT UI):最常用,可视化注册 CPT 和分类法,免费版够用;
  • Pods:除了 CPT 还能加自定义字段,功能更强;
  • ACF + CPT UI 组合:ACF 做字段,CPT UI 做类型,是很多建站公司的标准配置。

CPT UI 注册后同样要刷新固定链接。

场景三:做 CPT 的模板

WordPress 的模板层级(template hierarchy)对 CPT 同样生效:

single-case.php          → 单个案例页
single.php               → 兜底
archive-case.php         → 案例归档页
taxonomy-case_cat.php    → 案例分类页

最省事的做法:复制 single.php 改名 single-case.php,再按需要改。

场景四:让 CPT 出现在首页主循环

默认首页 WP_Query 只包含 post。要包含 CPT:

add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_main_query() && is_home() ) {
        $query->set( 'post_type', array( 'post', 'case' ) );
    }
});

场景五:让 CPT 出现在站点搜索和 RSS

// 搜索包含 CPT
add_action( 'pre_get_posts', function( $query ) {
    if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
        $query->set( 'post_type', array( 'post', 'page', 'case' ) );
    }
});

// RSS 包含 CPT
add_filter( 'request', function( $qv ) {
    if ( isset( $qv['feed'] ) && ! isset( $qv['post_type'] ) ) {
        $qv['post_type'] = array( 'post', 'case' );
    }
    return $qv;
});

场景六:用 WP-CLI 管理 CPT 内容

wp post list --post_type=case --fields=ID,post_title,post_date
wp post create --post_type=case --post_title='某客户案例' --post_status=publish
wp term list case_cat

常见踩坑与失败案例

  1. 案例一:注册了 CPT,前台 /case/xxx/ 404,反复检查代码没问题。99% 是没刷新固定链接。注册代码改动后也要重新 flush。
  2. show_in_rest 没设 true:后台 CPT 编辑页只有经典编辑器,没有 Gutenberg,REST API 也拿不到数据,部分插件(如 RankMath 的编辑器侧栏)无法工作。
  3. with_front 忘了设为 false:如果固定链接结构里带 /blog/,CPT 的 URL 会变成 /blog/case/xxx/,通常不是你想要的。
  4. CPT 别名和页面别名冲突:有个页面别名叫 case,同时 CPT 的 slug 也是 case,归档页打不开。改其中一个。
  5. 案例二:用了 capability_type => 'case' 但没给角色分配能力,编辑完全看不到 CPT 菜单。要么改回 'post',要么用插件(Members)给角色加 edit_cases 等能力。
  6. CPT 归档页 SEO 未配置:has_archive 开启后 /case/ 是个可收录页面,要去 SEO 插件里给它写标题和描述,否则输出的是空的归档标题。
  7. 停用注册插件后 CPT 内容”消失”:CPT 的定义代码没了,后台菜单消失,但数据还在数据库里。重新注册同样的 post_type 就能恢复。删插件前先想清楚,或者把注册代码写进子主题而非插件。

总结

CPT 是 WordPress 从博客走向 CMS 的分水岭。判断什么时候用它的标准很朴素:当某一类内容需要”独立的 URL 前缀 + 独立的模板 + 独立的后台菜单”时,就该用 CPT。注册时三个关键参数不能漏:show_in_rest => true(编辑器与 REST)、has_archive => true(归档页)、rewrite => array('with_front' => false)(干净的 URL)。注册完一定要刷新固定链接。如果不想写代码,CPT UI + ACF 是最稳的组合,但请把注册代码导出到子主题,避免插件停用后内容”消失”。

U
UFO_PF作者

专注 WordPress 生态的实战作者,内容以「可复制、可验证」为第一原则。

留下你的想法

邮箱地址不会被公开。带 * 的为必填项。