从自定义分层分类固定链接中删除分类插件

时间:2011-02-15 作者:onetrickpony

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

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
我如何删除前面的slug(“论坛”)?Ie,将URL更改为:

general-discussion/sub-forum
如果我将一个空的slug参数传递给register\\u taxonomy(),它会工作,但这会导致与此分类相关联的post类型的永久链接出现问题

9 个回复
最合适的回答,由SO网友:MikeSchinkel 整理而成

更新自编写此WordPress core后,添加了\'do_parse_request\' 钩子,允许优雅地处理URL路由,而无需扩展WP 班我在2014年亚特兰大WordCamp演讲中深入探讨了这个主题,题为"Hardcore URL Routing"; 链接中提供了幻灯片。

十多年来,URL设计的原始答案一直很重要;我甚至wrote a blog about it 几年前。虽然WordPress是sum,但它是一款出色的软件unfortunately 它的URL重写系统还差一点脑子就死了(当然是这样。)不管怎样,很高兴看到人们关心URL设计!

我要提供的答案是我正在调用的插件WP_Extended 这是一个概念证明this proposal on Trac (请注意,提案从一件事开始,然后演变成另一件事,因此您必须阅读整个内容才能看到它的发展方向。)

基本上,我们的想法是将WP 类,重写parse_request() 方法,然后分配全局$wp 具有子类实例的变量。然后在parse_request() 您实际上检查了路径by path segment 而不是使用必须完全匹配URL的正则表达式列表。

因此,为了明确说明这一点,该技术在parse_request() 它检查正则表达式匹配的URL,并首先查找分类术语匹配,但它仅替换parse_request() 并保留WordPress URL路由系统的整个其余部分,包括尤其是$query_vars 变量

对于您的用例,此实现only 将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() 调查方法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();
P.S.注意事项1虽然对于给定的站点,我认为这项技术非常有效,但是this technique should NEVER be used for a plugin to be distributed on WordPress.org for others to use. 如果它是基于WordPress的软件包的核心,那么这可能没问题。否则,此技术应仅限于改进URL路由for a specific site.

为什么?因为only one plugin can use this technique. 如果两个插件试图使用它,它们将相互冲突。

另外,这个策略可以扩展到一般性地处理可能需要的几乎每一个用例模式,这就是我打算在找到空闲时间或一个可以赞助构建完全通用实现所需时间的客户后立即实现的

警告#2

我写这个是为了覆盖parse_request() 这是一个非常大的函数,很可能我遗漏了全局$wp 我应该设置的对象。。因此,如果有什么不确定的地方,请告诉我,我会很乐意研究它,并在必要时修改答案。

无论如何

SO网友:Otto

很简单,真的。

步骤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\' );
请记住,添加此代码后,在刷新永久链接规则时需要将其激活(通过在设置->永久链接上保存页面)!

刷新规则并保存到数据库后,然后/无论什么都应该转到论坛=无论什么分类页面。

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

function test_foot() {
    global $wp_rewrite;
    echo \'<pre>\';
    var_dump($wp_rewrite->rules);
    echo \'</pre>\';
}
add_action(\'wp_footer\',\'test_foot\');
这样,我可以在我的页面上一目了然地看到当前的规则。只要记住,给定任何URL,系统从规则的顶部开始,然后向下遍历,直到找到一个匹配的URL。然后使用匹配将查询重写为外观更正常的查询?键=值集。这些键被解析为进入WP\\u查询对象的内容。易于理解的

Edit: 请注意,只有当您的常规自定义帖子结构以非catchall的内容开始时,此方法才可能有效,例如%category%或类似的内容。您需要以静态字符串或数字开始,如%year%。这是为了防止它在到达您的规则之前捕获您的URL。

SO网友:scribu

单独使用WP\\U重写无法做到这一点,因为它无法区分术语段塞和后期段塞。

您还必须挂接到“request”并通过设置post query var而不是分类法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\' );
请注意,必须在post类型之前定义分类法。

这将是一个很好的时机,可以指出,使用相同的查询var进行分类和发布类型是一个坏主意。

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

SO网友:Pabline

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

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

您可以通过更改

$category_base = get_option(\'category_base\');
在第74行,类似于:

$category_base = \'forums\';

SO网友:Travis Northcutt

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

SO网友:John P Bloch

因为我熟悉your other question, 我会记住这一点。

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

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();
这样做的作用:它从规则数组的正常流中删除从主题permalink生成的重写规则,并在数组末尾重新合并它们。这可以防止这些规则干扰任何其他重写规则。接下来,它强制执行详细的重写规则(每个页面都有一个带有特定正则表达式的单独规则)。这可以防止页面干扰主题的规则。最后,它执行一个硬刷新(确保你的.htaccess文件是可写的,否则这将不起作用),并保存非常大非常复杂的重写规则数组。

SO网友:Adam Gordon Bell

There is a plugin for this.

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

SO网友:Max

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

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

仅供参考,我正在运行WP3.9.1 使用WP类型1.5.7

SO网友:Sathish Jayaraman

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

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

结束

相关推荐

curl problem or permalinks

我刚刚配置了我的VPS,我使用的是Centos,一切都很好,但如果我将永久链接设置为自定义结构,然后接受主页,没有帖子出现,它会显示404页,我想这是因为我没有启用curl,但我不知道我的php在哪里。我的centos中的ini文件?好的,我的卷曲被启用了,我检查过了phpinfo(); 这里是URLhttp://74.117.158.182/info.php但如果我在我的wordpress中设置了永久链接,那么接受主页,所有都会给我404页,你可以在这个URL上查看http://mbas.co.in如果