当前位置: 首页>>网站问题>>正文


从自定义分层分类法永久链接中删除分类法slug

webfans 网站问题 , , , 去评论

问题描述

我使用以下规则创建了’forum’分类:

register_taxonomy(
  'forum',
  array('topic'),
  array(
    'public' => true,
    'name' => _a('Forums'),
    'singular_name' => _a('Forum'),
    'show_ui' => true,
    'show_in_nav_menus' => true,
    'hierarchical' => true,

    'labels' => array(
      'name' => _a('Forums'),
      'singular_name' => _a('Forum'),
      'search_items' => _a('Search Forums'),
      'popular_items' => _a('Popular Forums'),
      'all_items' => _a('All Forums'),
      'parent_item' => _a('Parent Forum'),
      'parent_item_colon' => _a('Parent Forum:'),
      'edit_item' => _a('Edit Forum'),
      'update_item' => _a('Update Forum'),
      'add_new_item' => _a('Add New Forum'),
      'new_item_name' => _a('New Forum Name'),
    ),
    'query_var' => true,
    'rewrite' => array('slug' => 'forums', 'with_front' => false, 'hierarchical' => true),  
  )
);

在front-end中,URL看起来像:

forums/general-discussion/sub-forum

如何拆下前塞(“forums”)?即,将URL更改为:

general-discussion/sub-forum

如果我将一个空的slug参数传递给 register_taxonomy()它可以工作,但这会导致与此分类法关联的post类型的永久链接出现问题

最佳解决思路

UPDATE

由于编写此WordPress核心已添加'do_parse_request'挂钩,允许优雅地处理URL路由,而无需扩展WP类。我在2014年亚特兰大WordCamp谈话题为“Hardcore URL Routing”的报道中讨论了主题in-depth;幻灯片可在链接中找到。

原始答案

URL设计十分重要,已有十多年了;几年前我甚至还有wrote a blog about it。虽然WordPress总和是一个很棒的软件,但不幸的是它的URL重写系统只是脑死亡(当然是恕我直言。)无论如何,很高兴看到人们关心URL设计!

我要提供的答案是一个插件,我称之为WP_Extended,这是this proposal on Trac的概念证明(请注意,提案始于一件事,并演变为另一件事,所以你必须阅读整个内容,看看它在哪里领导。)

基本上,我们的想法是继承WP类,重写parse_request()方法,然后使用子类的实例分配全局$wp变量。然后在parse_request()中,您实际上按路径段检查路径,而不是使用必须与URL完整匹配的正则表达式列表。

因此,要明确说明,此技术在parse_request()前面插入逻辑,它检查URL-to-RegEx匹配,而不是首先查找分类术语匹配,但它只替换parse_request()并保留WordPress URL路由系统的其余部分,包括特别是使用$query_vars变量。

对于您的use-case,此实现仅将URL路径段与分类术语进行比较,因为这就是您所需要的。此实现检查关于parent-child术语关系的分类术语,当它找到匹配时,它将URL路径(减去前导和尾随斜杠)分配给$wp->query_vars['category_name']$wp->query_vars['tag']$wp->query_vars['taxonomy']& $wp->query_vars['term']和它绕过WP类的parse_request()方法。

另一方面,如果URL路径与您指定的分类法中的术语不匹配,则通过调用WP类的parse_request()方法将URL路由逻辑委派给WordPress重写系统。

要为您的use-case使用WP_Extended,您需要在主题的functions.php文件中调用register_url_route()函数,如下所示:

add_action('init','init_forum_url_route');
function init_forum_url_route() {
  register_url_route(array('taxonomy'=>'forum'));
}

这是什么插件的源代码:

<?php
/*
Filename: wp-extended.php
Plugin Name: WP Extended for Taxonomy URL Routes
Author: Mike Schinkel
*/
function register_url_route($args=array()) {
  if (isset($args['taxonomy']))
    WP_Extended::register_taxonomy_url($args['taxonomy']);
}
class WP_Extended extends WP {
  static $taxonomies = array();
  static function on_load() {
    add_action('setup_theme',array(__CLASS__,'setup_theme'));
  }
  static function register_taxonomy_url($taxonomy) {
    self::$taxonomies[$taxonomy] = get_taxonomy($taxonomy);
  }
  static function setup_theme() { // Setup theme is 1st code run after WP is created.
    global $wp;
    $wp = new WP_Extended();  // Replace the global $wp
  }
  function parse_request($extra_query_vars = '') {
    $path = $_SERVER['REQUEST_URI'];
    $domain = str_replace('.','\.',$_SERVER['SERVER_NAME']);
    //$root_path = preg_replace("#^https?://{$domain}(/.*)$#",'$1',WP_SITEURL);
$root_path = $_SERVER['HTTP_HOST'];

    if (substr($path,0,strlen($root_path))==$root_path)
      $path = substr($path,strlen($root_path));
    list($path) = explode('?',$path);
    $path_segments = explode('/',trim($path,'/'));
    $taxonomy_term = array();
    $parent_id = 0;
    foreach(self::$taxonomies as $taxonomy_slug => $taxonomy) {
      $terms = get_terms($taxonomy_slug);
      foreach($path_segments as $segment_index => $path_segment) {
        foreach($terms as $term_index => $term) {
          if ($term->slug==$path_segments[$segment_index]) {
            if ($term->parent!=$parent_id) { // Make sure we test parents
              $taxonomy_term = array();
            } else {
              $parent_id = $term->term_id; // Capture parent ID for verification
              $taxonomy_term[] = $term->slug; // Collect slug as path segment
              unset($terms[$term_index]); // No need to scan it again
            }
            break;
          }
        }
      }
      if (count($taxonomy_term))
        break;
    }
    if (count($taxonomy_term)) {
      $path = implode('/',$taxonomy_term);
      switch ($taxonomy_slug) {
        case 'category':
          $this->query_vars['category_name'] = $path;
          break;
        case 'post_tag':
          $this->query_vars['tag'] = $path;
          break;
        default:
          $this->query_vars['taxonomy'] = $taxonomy_slug;
          $this->query_vars['term'] = $path;
          break;
      }
    } else {
      parent::parse_request($extra_query_vars); // Delegate to WP class
    }
  }
}
WP_Extended::on_load();

附: CAVEAT#1

虽然对于给定的站点我认为这种技术非常出色,但是这种技术绝不应该用于在WordPress.org上发布的插件供其他人使用。如果它是基于WordPress的软件包的核心,那么这可能没问题。否则,此技术应限于改进特定站点的URL路由。

为什么?因为只有一个插件可以使用这种技术。如果两个插件试图使用它们,它们将相互冲突。

顺便说一下,这个策略可以扩展到一般地处理几乎所有可能需要的use-case模式,这是我打算实现的,只要我找到业余时间或客户谁可以赞助完成构建所需的时间通用实现。

CAVEAT#2

我写这个是为了覆盖parse_request(),这是一个非常大的函数,很可能我错过了一个或两个我应该设置的全局$wp对象..所以如果有什么行为让我知道,我会成为很高兴研究它并在必要时修改答案。

无论如何…

次佳解决思路

简单,真的。

第1步:完全停止使用rewrite参数。我们将推出自己的重写。

'rewrite'=>false;

第2步:设置详细页面规则。这会强制普通的Pages有自己的规则,而不是页面底部的catch-all。

第3步:创建一些重写规则来处理您的用例。

第4步:手动强制执行刷新规则。最简单的方法:转到设置 – >永久链接,然后单击保存按钮。我喜欢这个,而不是我自己使用的插件激活方法,因为每当我改变一些东西时我都可以强制规则刷新。

所以,代码时间:

function test_init() {
    // create a new taxonomy
    register_taxonomy(
        'forum',
        'post',
        array(
            'query_var' => true,
            'public'=>true,
            'label'=>'Forum',
            'rewrite' => false,
        )
    );

    // force verbose rules.. this makes every Page have its own rule instead of being a 
    // catch-all, which we're going to use for the forum taxo instead
    global $wp_rewrite;
    $wp_rewrite->use_verbose_page_rules = true;

    // two rules to handle feeds
    add_rewrite_rule('(.+)/feed/(feed|rdf|rss|rss2|atom)/?$','index.php?forum=$matches[1]&feed=$matches[2]');
    add_rewrite_rule('(.+)/(feed|rdf|rss|rss2|atom)/?$','index.php?forum=$matches[1]&feed=$matches[2]');

    // one rule to handle paging of posts in the taxo
    add_rewrite_rule('(.+)/page/?([0-9]{1,})/?$','index.php?forum=$matches[1]&paged=$matches[2]');

    // one rule to show the forum taxo normally
    add_rewrite_rule('(.+)/?$', 'index.php?forum=$matches[1]');
}

add_action( 'init', 'test_init' );

请记住,添加此代码后,您需要在刷新固定链接规则时将其激活(通过在设置上保存页面 – >固定链接)!

在刷新规则并保存到数据库之后,然后/无论什么应该进入您的论坛=任何分类页面。

如果你理解正则表达式,重写规则确实并不困难。我在调试时使用此代码来帮助我:

function test_foot() {
    global $wp_rewrite;
    echo '<pre>';
    var_dump($wp_rewrite->rules);
    echo '</pre>';
}
add_action('wp_footer','test_foot');

这样,我可以在我的页面上一目了然地看到当前的规则。请记住,给定任何URL,系统从规则的顶部开始,然后通过它们直到找到匹配的规则。然后使用匹配将查询重写为更正常的?key =值集。这些键被解析为进入WP_Query对象的内容。简单。

编辑:侧面注释,这种方法可能只有在你的普通自定义帖子结构以不像cat -ll之类的东西开始时才有效,比如%category%或类似的东西。您需要使用静态字符串或数字启动它,例如%year%。这是为了防止它在达到您的规则之前捕获您的URL。

第三种解决思路

单独使用WP_Rewrite你将无法做到这一点,因为它无法区分术语slug和post slugs。

您还必须挂钩到’request’并通过设置post query var而不是分类法来阻止404。

像这样的东西:

function fix_post_request( $request ) {
    $tax_qv = 'forum';
    $cpt_name = 'post';

    if ( !empty( $request[ $tax_qv ] ) ) {
        $slug = basename( $request[ $tax_qv ] );

        // if this would generate a 404
        if ( !get_term_by( 'slug', $slug, $tax_qv ) ) {
            // set the correct query vars
            $request[ 'name' ] = $slug;
            $request[ 'post_type' ] = $cpt_name;
            unset( $request[$tax_qv] );
        }
    }

    return $request;
}
add_filter( 'request', 'fix_post_request' );

请注意,必须在帖子类型之前定义分类。

这是一个指出具有相同查询var的分类法和帖子类型是一个坏主意的好时机。

此外,您将无法访问与其中一个条款具有相同slug的帖子。

第四种思路

我来看看顶级 cat 插件的代码:

http://fortes.com/projects/wordpress/top-level-cats/

您可以轻松地调整它,以便通过更改它来寻找您的自定义分类标本

$category_base = get_option('category_base');

在第74行到类似的东西:

$category_base = 'forums';

第五种思路

我建议看看Custom Post Permalinks plugin。我现在没有时间进行测试,但它可能对您的情况有所帮助。

第六种思路

由于我熟悉your other question,我会回答这个问题。

我根本没有测试过这个,但是如果你在注册了你想要的所有permastructs之后立即执行了这个,那么它可能会有效:

class RRSwitcher {
  var $rules;
  function RRSwitcher(){
    add_filter( 'topic_rewrite_rules', array( $this, 'topics' ) );
    add_filter( 'rewrite_rules_array', array( $this, 'rules' ) );
  }
  function topics( $array ){
    $this->rules = $array;
    return array();
  }
  function rules( $array ){
    return array_merge( (array)$array, (array)$this->rules );
  }
}
$RRSwitcher = new RRSwitcher();
global $wp_rewrite;
$wp_rewrite->use_verbose_rules = true;
$wp_rewrite->flush_rules();

这样做:它从规则数组的正常流程中删除主题永久链接生成的重写规则,并在数组末尾删除它们的re-merges。这可以防止这些规则干扰任何其他重写规则。接下来,它强制使用详细的重写规则(每个页面都会获得具有特定正则表达式的单个规则)。这可以防止页面干扰您主题的规则。最后,它执行硬刷新(确保你的.htaccess文件是可写的,否则这将无法工作)并保存非常大的非常复杂的重写规则数组。

第七种思路

There is a plugin for this

它通过为每个自定义帖子类型页面添加特定规则来删除类型slug。

第八种思路

不确定这是否适用于分类法,但它适用于自定义帖子类型

虽然它已经更新了2年,但下面的插件对我有用:http://wordpress.org/plugins/remove-slug-from-custom-post-type/

仅供参考我正在使用WP 1.5.7类型的WP 3.9.1

第九种思路

使用斜杠作为slug的值… 100%工作

'rewrite' => array(
    'slug'       => '/', 
    'with_front' => FALSE
 ),

参考资料

本文由朵颐IT整理自网络, 文章地址: https://duoyit.com/article/2718.html,转载请务必附带本地址声明。