从自定义分层分类标准永久链接中删除分类标准条


21

我使用以下规则创建了“论坛”分类法:

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),  
  )
);

在前端,URL如下所示:

forums/general-discussion/sub-forum

我如何卸下前鼻塞(“论坛”)?即,将URL更改为:

general-discussion/sub-forum

如果我将一个空的slug参数传递给register_taxonomy(),它会起作用,但是会导致与此分类法相关的帖子类型的永久链接出现问题


@One Trick Pony-您是否尝试过将'slug' => 'forums'空白完全删除而只留空白'rewrite' => array('with_front' => false, 'hierarchical' => true)?我认为过去对我有用。另外,请确保您冲洗了永久链接。
eileencodes 2011年

尝试过,并且永久链接看起来相同。添加'slug' => ''使它起作用,但是使用此分类法的帖子随后会生成404
onetrickpony

@One Trick Pony-除了“一般性讨论”之外,您还需要其他哪些顶级路径段?
2011年

任何%forum%都应该是顶级细分受众群
onetrickpony

@One Trick Pony-我只是希望您能给我一些其他的上下文顶级路径。
MikeSchinkel 2011年

Answers:


11

更新

自从编写此WordPress核心以来,添加了'do_parse_request'挂钩,该挂钩允许优雅地处理URL路由,而无需扩展WP类。我在2014年亚特兰大WordCamp演讲中深入探讨了该主题,主题为硬核URL路由;可以在链接上找到幻灯片。

原始答案

十多年来,URL设计一直很重要。几年前,我什至写了一个博客。而且,尽管WordPress是一个很棒的软件,但是 不幸的是,它的URL重写系统简直是脑筋急转(当然,恕我直言:)。无论如何,很高兴看到人们关心URL设计!

我要提供的答案是一个我要调用的插件WP_Extended,它是Trac上该提案 的概念证明(请注意,该提案最初是一件事,后来演变为另一件事,因此您必须阅读整个文章才能了解其中的内容。它是前进的。)

基本上,这个想法是对类进行子WP类化,重写parse_request()方法,然后为全局$wp变量分配子类的实例。然后,在其中parse_request()实际检查每个路径的路径而不是使用必须完全匹配URL的正则表达式列表。

因此,要明确指出,该技术会在其前面插入逻辑,parse_request()以检查URL到RegEx匹配项,然后首先查找分类术语匹配项,但替换parse_request()并保留整个WordPress URL路由系统的其余部分,包括和尤其是$query_vars变量的使用。

对于您的用例,此实现将URL路径段与分类术语进行比较,因为这就是您所需要的。此实现检查分类术语尊重父子长期合作关系,并在找到匹配其指定的URL路径(减去开头和结尾的斜杠)$wp->query_vars['category_name']$wp->query_vars['tag']$wp->query_vars['taxonomy']$wp->query_vars['term']它绕过parse_request()的方法WP类。

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

WP_Extended用于用例,您需要register_url_route()从主题functions.php文件中调用该函数,如下所示:

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();

PS CAVEAT#1

尽管对于特定网站我认为该技术效果很好,但是绝不应该使用该技术来将插件分发到WordPress.org上供其他人使用。如果它是基于WordPress的软件包的核心,那么这可能还可以。否则,该技术应仅限于改进特定站点的URL路由。

为什么?因为只有一个插件可以使用此技术。如果两个插件尝试使用它,它们将彼此冲突。

顺便说一句,该策略可以扩展为一般性地处理几乎所有可能需要的用例模式,这就是我打算在找到空闲时间或可以赞助时间的客户后立即实施的目标。构建完全通用的实现。

小穴#2

我写了这个重写来覆盖parse_request()这是一个非常大的函数,很可能我错过了本$wp应设置的一个或两个全局对象的属性。因此,如果发生了一些奇怪的事情,请告诉我,我很乐意研究它并根据需要修改答案。

无论如何...


写完这篇文章后,我意识到我已经测试了类别而不是分类标准术语,因此上述内容不适用于'forum'分类标准,但是我将在今天晚些时候对其进行修改……
MikeSchinkel 2011年

因此,我已经更新了代码以解决前面的评论中提到的问题。
MikeSchinkel

无法完成这项工作...我需要更改重写规则吗?
onetrickpony

@One Trick Pony-多一点诊断信息会有所帮助。:)您尝试了什么?在浏览器中输入URL时会发生什么?您'forums'是不是偶然地称呼您的分类法而不是'forum'?您是否期望链接到这些页面的URL发生更改(如果是,难怪,我的代码将不解决URL的打印问题,而仅解决URL的路由问题。)
MikeSchinkel 2011年

不,我可以更改URL(我想为此需要连接的term_link函数)。site/rootforum/可以,但是site/rootforum/subforum/不能(404错误)...
onetrickpony

7

很简单,真的。

步骤1:完全停止使用rewrite参数。我们将发布您自己的重写。

'rewrite'=>false;

步骤2:设置详细的页面规则。这迫使普通页面具有自己的规则,而不是页面底部的全部内容。

步骤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' );

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

刷新规则并保存到数据库后,/ whatever应该转到您的forum = whatever分类法页面。

如果您了解正则表达式,那么重写规则并不难。在调试它们时,我使用以下代码来帮助我:

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

这样,我可以在页面上一目了然地看到当前规则。只要记住给定任何URL,系统就会从规则的顶部开始,然后遍历所有规则,直到找到匹配的规则。然后使用该匹配将查询重写为外观更正常的?key = value集合。这些键被解析为WP_Query对象中的内容。简单。

编辑:旁注,仅当您的常规自定义帖子结构以不完整的东西(例如%category%或类似的东西)开头时,此方法才可能有效。您需要以静态字符串或数字开头,例如%year%。这是为了防止它在到达规则之前捕获您的URL。


如果您想更轻松地调试重写规则,我(再次)建议使用我的重写分析器插件,该插件可让您试用规则并即时查看查询变量。
Jan Fabry

不幸的是,当前的URL重写系统强制将所有可能的URL模式压平成一个大列表,而不是遵循URL路径的固有树结构。当前设置无法方便地匹配一系列文字,例如类别或论坛名称;如您所知,它会强制首先评估所有“页面” URL。按路径段进行匹配并以多种方式进行匹配(文字,类别,标签,税项,用户名,帖子类型,帖子名称,回调,过滤器挂钩以及最后的RegEx数组)可以更好地扩展复杂性,并且更加容易了解。
MikeSchinkel 2011年

迈克:实际上,这一点根本不容易理解,因为我还没有获得您正在谈论的第一个线索WTF。您对URL路由的想法既混乱又困难,而且您可能知道,我不同意它们。扁平搜索比您通常认为的更有意义和更灵活。大多数人不希望URL拥有所有不必要的复杂性,而且几乎没有人也不需要它。
奥托

谢谢,但我想我已经尝试过在此之前(wordpress.stackexchange.com/questions/9455/...
onetrickpony

幸运的WordPress的答案现在允许人谁自己的网址,想控制,终于有一个声音,它们似乎是许多(100+)。但是,我认为您可能无法在完整实施之前效仿我的榜样。我预计,一旦我倡导的方法在插件中完全实现,并且在大约6到12个月后,它将成为基于WordPress的CMS站点路由其URL的首选方法。因此,让我们在大约9个月内恢复这场辩论。
MikeSchinkel'3

4

您将无法单独使用WP_Rewrite来执行此操作,因为它无法区分术语和后期。

您还必须通过设置后置查询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的分类法和帖子类型是一个坏主意。

另外,您将无法访问与条款之一相同的帖子。


同意具有一个分类法和一个具有相同查询var的帖子类型是一个坏主意,但这可能意味着具有一个分类法和一个具有相同名称的帖子类型的人不是一个好主意,事实并非如此。如果使用相同的名称,则两个中只有一个应具有查询var。
MikeSchinkel 2011年

2

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

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

您可以轻松地对此进行调整,因此它可以通过更改以下内容来查找自定义分类标准:

$category_base = get_option('category_base');

在第74行显示为类似以下内容:

$category_base = 'forums';

可能适用于类别,但不适用于自定义分类法(至少在wp 3.1中)...我设法更改了URL,但出现404错误
onetrickpony


2

由于我熟悉您的其他问题,因此我会在心中回答。

我根本没有测试过,但是如果您在注册了所有所需的永久结构之后立即执行一次,则可能会起作用。

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();

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


尝试了一下,没有任何改变
onetrickpony



2

使用斜杠作为段符的值... 100%工作

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

2
不大,这将导致所有的page职位类型404
米洛
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.