WordPress 插件开发教程手册 — 自定义分类方法

分类法是类别和分组的另外一种说法,分类法可以是分级的和扁平的。WordPress 可以让插件开发者注册自定义分类法,分类法存储在 term_taxonomy 数据表中。分类法中有一些分类法项目,这些项目存储在 wp_terms 数据表中。例如,名为 “艺术” 的分类方法有多个分类项目,如 “现在艺术” 和 “18 世纪艺术”。

本章我们来学习怎么注册自定义分类方法,如何从数据库中获取自定义分类方法内容,以及如何显示给用户。

WordPress 3.4 和更早的版本有一个名为“链接”的默认分类方法,在 WordPress 3.5 和以后的版本中不推荐使用。

使用自定义分类法

自定义分类方法

随着分类法系统的推出,WordPress 默认的分类方法 “分类目录” 和 “标签” 很多时候已经不能满足我们的需求,这个时候,我们可以创建自定义分类方法。自定义分类方法通常和自定义文章类型一起使用,为我们自定义的某种内容按照我们自定义的条件分类。

为什么使用自定义分类方法

有些开发者可能会问,为什么要使用分类方法,使用分类方法可以为我们带来什么好处?什么时候使用分类方法来组织内容?下面我们就用一个例子来说明一下使用分类方法的好处。假设有一个客户是厨师,他需要我们帮他使用 WordPress 创建一个网站,用来展示他的食谱。

为了避免 “食谱” 这种类型的内容和其他内容混在一起,引起管理上的混乱,我们需要创建一个自定义文章类型 “食谱” 来存储这个厨师的食谱内容。食谱当然会有分类,我们需要创建一个名为 “课程” 的分类方法来把 “开胃菜” 和 “甜点” 这两种不同的食谱分开,然后创建一个 “原料” 的分类方法来根据原料的不同把食谱分为 “鸡肉” 换 “巧克力”等。

当然,我们也可以使用默认的“分类目录” 和 “标签” 来组织食谱的内容,这种情况下,我们需要创建一个名为 “课程” 的分类,然后创建 “开胃菜” 和 “甜点” 子分类,以及 “原料” 分类和他们的子分类。

使用自定义分类方法的主要优点在于我们可以使用独立于“分类目录” 和 “标签”的分类系统来区分我们的食谱,自定义分类方法在 WordPress 后台有自己独立的菜单,也更方便我们管理。此外,创建自定义分类方法还允许我们创建自定义界面和数据出入流程,来降低用户的学习和使用成本。如果在插件中创建了自定义分类方法,我们还可以在不同的 WordPress 网站上重复使用。

示例:课程分类方法

下面的示例将展示如何创建一个自定义分类方法“课程”,并把这个自定义分类方法添加到默认的“文章”文章类型中。在尝试创建插件之前,请确保阅读了插件开发基础知识章节。

第一步:开始之前

打开:文章>写文章 页面,我们可以看到默认有分类目录和标签这两种分类方法。

第二步:创建一个新插件

使用 init Action 钩子为内容类型 “文章” 注册一个自定义分类方法 “课程”。

/*
* Plugin Name: Course Taxonomy
* Description: A short example showing how to add a taxonomy called Course.
* Version: 1.0
* Author: developer.wordpress.org
* Author URI: https://codex.wordpress.org/User:Aternus
*/

function wporg_register_taxonomy_course() {
   $labels = [
      'name'              => _x( 'Courses', 'taxonomy general name' ),
      'singular_name'     => _x( 'Course', 'taxonomy singular name' ),
      'search_items'      => __( 'Search Courses' ),
      'all_items'         => __( 'All Courses' ),
      'parent_item'       => __( 'Parent Course' ),
      'parent_item_colon' => __( 'Parent Course:' ),
      'edit_item'         => __( 'Edit Course' ),
      'update_item'       => __( 'Update Course' ),
      'add_new_item'      => __( 'Add New Course' ),
      'new_item_name'     => __( 'New Course Name' ),
      'menu_name'         => __( 'Course' ),
   ];
   $args   = [
      'hierarchical'      => true, // make it hierarchical (like categories)
      'labels'            => $labels,
      'show_ui'           => true,
      'show_admin_column' => true,
      'query_var'         => true,
      'rewrite'           => [ 'slug' => 'course' ],
   ];
   register_taxonomy( 'course', [ 'post' ], $args );
}

add_action( 'init', 'wporg_register_taxonomy_course' );

第三步:查看结果

激活我们刚才创建的插件,然后打开文章>写文章 页面,如果一切顺利,我们将看到一个名称为 “课程” 的分类方法。

代码解读

下面我们来逐一了解用于实现上面功能的函数和参数。

函数 wporg_register_taxonomy_course 注册自定义文章类型所需要的所有步骤。

$label 数据中定义了自定义分类方法的标签,也就是我们在后台看到的分类方法的名称、操作等各种信息。

$args 参数包含创建自定义分类方法时使用的配置选项,用来指示 WordPress 怎么设置自定义分类方法。

register_taxonomy() 函数使用 $args 数组为“文章” 这个内容类型配置了课程分类方法。

add_action() 函数把创建分类方法的操作绑定到了 init Action 钩子上。

总结

通过我们创建 “课程” 分类方法的示例代码, WordPress 将自动为 “课程” 分类方法创建存档页面及其子页面。

自定义分类方法存档页面的形式为 (/course/%%term-slug%%/),其中 /course/ 为自定义分类方法的标识符,%%term-slug%% 为自定义分类方法中分类项目别名。

使用自定义分类法

WordPress 中有很多函数可以操作自定义分类法和自定义分类法中的分类项目。如:

  • the_terms:接受分类法参数,在列表中显示分类法项目。
  • wp_tag_cloud:接受分类法参数,以标签云的形式显示分类法项目。
  • is_taxonomy:判断是否为指定的分类方法。

拆分分类法项目(WordPress 4.2+)

WordPress 4.2 以前

在 WordPress 4.2 以前,不同分类方法中使用的相同分类法项目会共享一个分类法项目 ID,例如,具有相同别名 “news” 的分类目录和标签共享一个 ID,其实他们是一个分类法项目。

WordPress 4.2 以后

从 WordPress 4.2 开发,这些共享的分类法项目被更新后,他们会被拆分为单独的项目,每个项目会被分配一个新的 ID。

这意味着什么

绝大多数情况下,这个更新是无缝和平滑的,但是,一些插件和主题会把一些分类法 ID 存储到 options, post_meta, user_meta 或其他数据中,这些情况下,主题或插件可能会受到影响。

处理分类法项目分拆

WordPress 4.2 提供了两个不通的工具来帮助插件和主题开发者进行转换。

split_shared_term 钩子

如果共享的分类法项目被分配了新的 ID,会自动触发挂载到 split_share_term 钩子上的操作。以下是主题和插件开发者使用此钩子确保存储的分类法项目 ID 被更新的示例。

存储在选项中

假如我们的插件存储了一个名为 feartured_tags 的选项,其中包含了一个标签 ID 数组 ( [4,6,10] ),该选项为主页精选文章模块的查询参数。在这个例子中,我们将挂载一个函数到 split_shared_term Action 钩子上,该函数会检查标签 ID 是否在数组中,如果有需要,会更新这个数组。

/**
 * Update featured_tags option when a shared term gets split.
 *
 * @param int    $term_id          ID of the formerly shared term.
 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
 * @param string $taxonomy         Taxonomy for the split term.
 */
function wporg_featured_tags_split( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
   // we only care about tags, so we'll first verify that the taxonomy is post_tag.
   if ( $taxonomy === 'post_tag' ) {

      // get the currently featured tags.
      $featured_tags = get_option( 'featured_tags' );

      // if the updated term is in the array, note the array key.
      $found_term = array_search( $term_id, $featured_tags );
      if ( $found_term !== false ) {

         // the updated term is a featured tag! replace it in the array, save the new array.
         $featured_tags[ $found_term ] = $new_term_id;
         update_option( 'featured_tags', $featured_tags );
      }
   }
}

add_action( 'split_shared_term', 'wporg_featured_tags_split', 10, 4 );

存储在 post_meta 中

假如,插件为页面保存了一个标签 ID,通过这个标签 ID,我们可以在文章页面中显示相关文章。这种情况下,我们先通过 get_psots() 函数来获取 meta_key 和 meta_value 匹配的页面,然后更新 meta_value 为分割后的 ID。

/**
 * Update related posts term ID for pages
 *
 * @param int    $term_id          ID of the formerly shared term.
 * @param int    $new_term_id      ID of the new term created for the $term_taxonomy_id.
 * @param int    $term_taxonomy_id ID for the term_taxonomy row affected by the split.
 * @param string $taxonomy         Taxonomy for the split term.
 */
function wporg_page_related_posts_split( $term_id, $new_term_id, $term_taxonomy_id, $taxonomy ) {
   // find all the pages where meta_value matches the old term ID.
   $page_ids = get_posts( [
      'post_type'  => 'page',
      'fields'     => 'ids',
      'meta_key'   => 'meta_key',
      'meta_value' => $term_id,
   ] );

   // if such pages exist, update the term ID for each page.
   if ( $page_ids ) {
      foreach ( $page_ids as $id ) {
         update_post_meta( $id, 'meta_key', $new_term_id, $term_id );
      }
   }
}

add_action( 'split_shared_term', 'wporg_page_related_posts_split', 10, 4 );

wp_get_split_term 函数

使用 split_shared_term 钩子是处理分类法项目 ID 更改的首选方法。但是可能会出现插件没有机会执行 split_shared_term 钩子的情况。

WordPress 会保存拆分后的分类法项目信息,并提供了 wp_get_split_term() 函数 来帮助开发人员获取此信息。

考虑一下上面的情况,我们的插件存储了一个名为 feartured_tags,值为分类法项目 ID 的数组选项,我们可能需要创建一个函数来检查这些 ID(可以在插件更新的时候)中是否包含已被拆分的 ID,如果包含,我们需要更新被拆分后分类法项目 ID 到这个数组中。

function wporg_featured_tags_check_split() {
   $featured_tag_ids = get_option( 'featured_tags', [] );

   // check to see whether any IDs correspond to post_tag terms that have been split.
   foreach ( $featured_tag_ids as $index => $featured_tag_id ) {
      $new_term_id = wp_get_split_term( $featured_tag_id, 'post_tag' );

      if ( $new_term_id ) {
         $featured_tag_ids[ $index ] = $new_term_id;
      }
   }

   // save
   update_option( 'featured_tags', $featured_tag_ids );
}

注意, wp_get_split_term() 接受两个参数,$old_term_id 和 $taxonomy ,并返回一个整数。

如果我们需要获取所有分类法中与旧分类法 ID 相关的拆分分类法项目列表,我们可以使用 wp_get_split_terms() 函数 。

 

本站提供 WordPress 主题定制开发服务

本站长期承接 WordPress 主题、插件、基于 WooCommerce 的商店商城开发业务。 我们有 8 年 WordPress 开发经验,如果你想 用 WordPress 开发网站, 请联系 QQ: 470266798,或邮箱: 4626395@gmail.com 咨询。

发表评论

电子邮件地址不会被公开。 必填项已用*标注

*