WP DEVELOP

EP037. “建立 Program 文章类型与关联字段”

首页 WordPress 开发课程 PROGRAM POST TYPE 与关系 · EP037
约 22 分钟· #EP037#PROGRAM POST TYPE 与关系
🔒 登录后可标记已读

新建一个 program 自定义文章类型(math、biology、English 这种专业/学系),做法是直接复制 Section 7 建立 event CPT 时的 register_post_type() 调用来改,省得从头写。同时新建 single-program.phparchive-program.php 两个模板文件(分别从 single-event.phparchive-event.php 复制改造),并且调整了 program 归档页的默认查询:按标题字母排序、posts_per_page 设成 -1 一次性列出所有 program。最后用 ACF 建一个 "Related Program" 关系字段组,让 event 文章可以选择关联一个或多个 program,这一讲只把字段建好,前端怎么显示这个关系留到 EP038。

涉及文件

  • wp-content/mu-plugins/university-post-types.php (修改,新增 program CPT 注册)
  • wp-content/themes/fictional-university-theme/single-program.php (新建,从 single-event.php 复制改造)
  • wp-content/themes/fictional-university-theme/archive-program.php (新建,从 archive-event.php 复制改造)
  • wp-content/themes/fictional-university-theme/functions.php (修改,university_adjust_queries() 里新增 program 归档查询调整)
  • ACF 字段组 "Related Program"(后台 Custom Fields 里配置,不是 PHP 代码)

代码实现


wp-content/mu-plugins/university-post-types.php (修改)

在原本注册 event 的函数里,直接复制那一整段 register_post_type(),改掉几个关键值,加在 event 后面:

function university_post_types() {
  // Event Post Type
  register_post_type('event', array(
    // ...原有 event 参数不变...
  ));

  // 新增:Program Post Type
  register_post_type('program', array(
    'show_in_rest' => true,
    'supports' => array('title', 'editor'), // 不需要 excerpt,比 event 少一项
    'rewrite' => array('slug' => 'programs'),
    'has_archive' => true,
    'public' => true,
    'labels' => array(
      'name' => 'Programs',
      'add_new_item' => 'Add New Program',
      'edit_item' => 'Edit Program',
      'all_items' => 'All Programs',
      'singular_name' => 'Program'
    ),
    'menu_icon' => 'dashicons-awards'
  ));
}

要点:

  • supports 里没有 excerpt(event 有),因为 program 用不上摘要。
  • menu_icon 用的是 dashicons-awards(在 developer.wordpress.org 的 Dashicons 页面能查到图标名)。
  • 保存后台后台侧边栏就会多出 Programs 菜单,但这时候点开新建的 program 文章预览会 404(page not found),因为注册了新 CPT/新的 URL 结构后,WordPress 的 permalink 规则没有自动刷新——要去后台「设置 → 固定链接(Permalinks)」随便点一次「保存更改」,强制 WordPress 重新生成 permalink 规则才会正常。

wp-content/themes/fictional-university-theme/single-program.php (新建)

single-event.php 整份复制过来,只改了 metabox 那行链接的文字和 href(原本是 "Events Home" 链接回 event 归档页,改成 "All Programs" 链接回 program 归档页):

<?php
  get_header();

  while(have_posts()) {
    the_post(); ?>
    <div class="page-banner">
      <div class="page-banner__bg-image" style="background-image: url(<?php echo get_theme_file_uri('/images/ocean.jpg') ?>);"></div>
      <div class="page-banner__content container container--narrow">
        <h1 class="page-banner__title"><?php the_title(); ?></h1>
        <div class="page-banner__intro">
          <p>DONT FORGET TO REPLACE ME LATER</p>
        </div>
      </div>
    </div>

    <div class="container container--narrow page-section">
      <div class="metabox metabox--position-up metabox--with-home-link">
        <p><a class="metabox__blog-home-link" href="<?php echo get_post_type_archive_link('program'); ?>"><i class="fa fa-home" aria-hidden="true"></i> All Programs</a> <span class="metabox__main"><?php the_title(); ?></span></p>
      </div>

      <div class="generic-content"><?php the_content(); ?></div>
    </div>
  <?php }

  get_footer();
?>

wp-content/themes/fictional-university-theme/archive-program.php (新建)

archive-event.php 复制过来,但显示方式完全不一样:event 归档页是卡片式的 event-summary,program 归档页只需要一个纯标题的列表,所以把原本 while 循环里那一大坨 event-summary div 删掉,改成简单的 <li><a>,并且删掉了底部关于「往期活动」的说明文字和分隔线:

<?php
  get_header(); ?>

<div class="page-banner">
  <div class="page-banner__bg-image" style="background-image: url(<?php echo get_theme_file_uri('/images/ocean.jpg') ?>);"></div>
  <div class="page-banner__content container container--narrow">
    <h1 class="page-banner__title">All Programs</h1>
    <div class="page-banner__intro">
      <p>There is something for everyone. Have a look around.</p>
    </div>
  </div>
</div>

<div class="container container--narrow page-section">

<ul class="link-list min-list">

<?php
  while(have_posts()) {
    the_post(); ?>
    <li><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></li>
  <?php }
  echo paginate_links();
?>
</ul>

</div>

<?php get_footer(); ?>

link-list min-list 这两个 class 纯粹是排版用,跟功能无关。


wp-content/themes/fictional-university-theme/functions.php (修改)

university_adjust_queries() 里已经有一段专门调整 event 归档页查询的 if 判断(Section 7 建立的),这一讲在它上面新增一段结构一样、条件换成 program 的判断:

function university_adjust_queries($query) {
  // 新增:调整 program 归档页的默认查询
  if (!is_admin() AND is_post_type_archive('program') AND $query->is_main_query()) {
    $query->set('orderby', 'title');
    $query->set('order', 'ASC');
    $query->set('posts_per_page', -1);
  }

  if (!is_admin() AND is_post_type_archive('event') AND $query->is_main_query()) {
    // ...原有 event 归档查询调整不变...
  }
}

不需要在模板文件里另外写查询,直接在 pre_get_posts 这个已有的调整函数里加条件即可:program 归档页要按标题字母顺序排、而且不分页一次性列出全部(哪怕以后有 80、90 个 program)。


在后台「Custom Fields」新建一个字段组,名字叫 "Related Program":

  • 只加一个字段,字段类型选 Relationship(在 Relational 分类下面,不能选默认的 Text)。
  • Filter by Post Type 勾选 program——这一步很关键,不然这个关系字段会让你选任何文章类型,而不只是 program。
  • Filter by Taxonomy 留空(去掉 Post Type / Taxonomy 筛选框,只留搜索框)。
  • Return Format 保持默认的 Post Object
  • Location 规则设成「Post Type 等于 event」——也就是这个字段只会出现在编辑 event 文章的页面,编辑普通 post/page 时不会出现。
  • 字段一开始起名 "Related Program(s)",后来觉得打字麻烦把括号去掉;实际存进数据库、代码里用来取值的字段名是 related_programs(复数),EP038 会用 get_field('related_programs') 取这个字段。

保存字段组后,去编辑一篇 event(比如 "The Science of Cats"),下面就会多出这个 "Related Programs" 字段,左边是所有 program 文章可选,右边是已选中要关联的。

[截图:ACF Relationship 字段类型的设置画面(Filter by Post Type 选 program、Location 规则设为 Post Type = event)]

[截图:编辑某篇 event 文章时,下方出现的 Related Program(s) 关系字段,左侧可选 program 列表、右侧已选中列表]

Hook / Function 速查

名称类型用途
ACF Relationship 字段类型ACF 字段类型(后台配置,非 PHP 代码)让当前文章类型(这里是 event)可以选择关联一个或多个其他文章类型(program)的文章,返回值是 post object 数组
Filter by Post Type(Relationship 字段设置项)ACF 字段设置限制这个关系字段只能选某个文章类型,不设置的话默认可以选任何类型的文章

register_post_type()initpre_get_posts$query->set() 这些函数用法已经在 Section 7 建 event CPT/调整 event 归档查询时出现过,这里是直接复用同一套模式,不重复列。

常见坑

  • 注册新 CPT 后直接访问文章 permalink 会 404、标签页标题显示 "Page not found"——需要去后台「设置 → 固定链接」点一次「保存更改」强制刷新 permalink 规则。
  • 如果不建 single-program.php,program 文章的详情页会退回用主题的通用 single.php 模板显示(页面上会看到不该出现的博客相关元素,比如返回博客首页的链接)。
  • ACF 关系字段如果没设置 Filter by Post Type = program,会让用户误选到其他文章类型;Location 规则如果没限制成 event,这个字段会出现在编辑普通文章/页面的页面上,造成困扰。

延伸 / 后续讲座会用到

这一讲只是把 related_programs 关系字段建好并在后台测试了赋值,前端怎么显示这个关系(从 event 页面显示关联的 program,以及反过来从 program 页面显示关联的 event)留到 EP038。

Sources

Udemy:

  • Become a WordPress Developer: Unlocking Power With Code — Section 8, EP037