Wordpress – 在永久链接中混合自定义帖子类型和自定义分类术语例如 www.mysite.com/cpt-name/taxonomy-term

问题描述

wordpress 中,我有三种自定义帖子类型:展览、书籍、电影。我有一个包含两个分类术语(store-1 和 store-2)的分类法,可应用于所有 CPT。

我需要实现的是有一个带有永久链接 www.mysite.com/exhibitions页面,其中列出了标记为 store-1 和 store-2 的帖子,这可以通过 CPT 轻松完成。但是,我还希望有永久链接,例如 www.mysite.com/exhibitions/store-1,其中列出了所有来自展览 CPT 的 store-1 分类法的帖子(对于每个 CPT 和每个分类法术语,依此类推)。然而,这会在永久链接中混合使用 CPT 和分类术语,我不知道该怎么做。

我的猜测是反转逻辑并创建三个自定义分类法,分别命名为展览、书籍和电影(当然,我需要将 CPT slug 更改为 cpt-exhibitions、cpt-books 和 cpt-movies),并为每个其中创建术语 store-1 和 store-2。通过这种方式,我将获得诸如 www.mysite.com/exhibitions/store-1 之类的永久链接。关于 www.mysite.com/exhibitions 等永久链接,我正在考虑使用该页面自定义模板创建一个带有 slug“展览”的页面。在模板的 PHP 中,我会添加一个循环来获取所有 cpt-exhibitions 帖子,无论分类术语如何。

这不是一个真正干净的解决方案,因为我在后端基本上有三个空页面,仅用于永久链接目的。所以我想知道:是否有一个特定的功能或重写规则来实现我需要的 CPT 命名展览、书籍、电影和仅适用于所有 CPT 的一个自定义分类法(例如商店)?

感谢您的见解!

解决方法

我曾经有过这样的设置,并通过一些重写规则解决了它。查看此代码,它确实提供了您需要的永久链接,但可能需要您进行一些测试。是的,不要害怕在 WordPress 中重写规则。尽管有些事情可能会付出代价(即性能问题)

add_filter('init','create_movies_taxonomies');
add_filter('init','create_movies_cpt');
add_action('init','movies_rewrite_rules');
add_filter('post_type_link','movies_post_permalinks',10,2);

/**
 * First create Stores taxonomy
 */
function create_movies_taxonomies() {

  register_taxonomy('stores',['movies'],[
      'label'             => __('Stores','textdomain'),'public'            => true,'show_in_nav_menus' => false,'show_ui'           => true,'show_in_menu'      => true,'show_tagcloud'     => false,'show_in_rest'      => true,'hierarchical'      => false,'rewrite'           => ['slug' => 'store','hierarchical' => false,'with_front' => false],'show_admin_column' => true,'query_var'         => true
    ]
  );
}

/**
 * Then create Movies CPT with support for Stores and proper rewrites
 */
function create_movies_cpt() {

  register_post_type('movies',[
      'label'             => __('Movies','public'              => true,'publicly_queryable'  => true,'show_ui'             => true,'show_in_menu'        => true,'exclude_from_search' => false,'capability_type'     => 'post','map_meta_cap'        => true,'show_in_rest'        => true,'hierarchical'        => false,'rewrite'             => [
        'slug'       => '/movies/%stores%','with_front' => false,'feeds'      => false
      ],'query_var'           => true,'supports'            => ['title','tags','editor','comments','custom-fields','thumbnail'],'has_archive'         => 'movies','taxonomies'          => ['stores'],'show_in_nav_menus'   => true,'menu_icon'           => 'dashicons-welcome-learn-more',]
  );
}

/**
 * Add some rewrite rules for our archives (CPT,taxonomy archive)
 */
function movies_rewrite_rules() {

  add_rewrite_rule(
    'movies/([a-z]+)/page/?([0-9]{1,})/?$','index.php?post_type=movies&stores=$matches[1]&paged=$matches[2]','top'
  );

  add_rewrite_rule(
    'movies/([a-z]+)/([a-z0-9_-]+)/?$','index.php?post_type=movies&stores=$matches[1]&movies=$matches[2]','top'
  );

  add_filter('query_vars',function($vars) {
    $vars[] .= 'stores';
    $vars[] .= 'stores-page';

    return $vars;
  });

}


/**
 * Creates beautiful CPT permalinks,like site.com/movies/%term%/%post%/
 *
 * @param $permalink
 * @param $post
 *
 * @return string|string[]
 */
function movies_post_permalinks($permalink,$post) {
  // if it's not our CPT,return regular permalinks
  if (strpos($permalink,'%stores%') === false) {
    return $permalink;
  }

  // Get post taxonomy term
  $terms = get_the_terms($post,'stores');
  // if a post has a term (store),push it into URL
  if ( ! is_wp_error($terms) && ! empty($terms) && is_object($terms[0])) {
    $term_slug = array_pop($terms)->slug;
  } // if it doesn't,push something there,let it be d
  else {
    $term_slug = 'd';
  }

  return str_replace('%stores%',$term_slug,$permalink);
}