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(),它可以工作,但是会导致关联的帖子类型的永久链接出现问题使用此分类法
#1 楼
更新自编写此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()
类的WP
方法将URL路由逻辑委托给WordPress重写系统。要在用例中使用
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}(/.*)$#",'',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路由。
为什么?因为只有一个插件可以使用此技术。如果两个插件尝试使用它们,它们将彼此冲突。
此外,该策略可以扩展为通常处理几乎所有可能需要的用例模式,而这正是我打算实现的一旦我找到了业余时间,或者有一位客户可以赞助建立完全通用的实现所需的时间。
CAVEAT#2
我写此代码来重写
parse_request()
,这是一个非常大的函数,很可能我错过了应该设置的全局$wp
对象的一个或两个属性。很高兴研究它,并在需要时修改答案。无论如何...
评论
写完这篇文章后,我意识到我已经测试了类别而不是分类标准术语,因此以上内容不适用于“论坛”分类标准,但是我将对其进行修改以在今天晚些时候工作...
– MikeSchinkel
2011-02-23 12:58
因此,我已经更新了代码以解决在先前的评论中提到的问题。
– MikeSchinkel
2011-2-23在23:55
无法完成这项工作...我需要更改重写规则吗?
–onetrickpony
2011-2-24在10:51
@One Trick Pony-多一点诊断信息会有所帮助。 :)您尝试了什么?在浏览器中输入URL时会发生什么?您是否有机会将分类法称为“论坛”而不是“论坛”?您是否期望链接到这些页面的URL发生更改(如果是的话,难怪我的代码不会解决URL的打印问题,而只会解决URL的路由问题。)
– MikeSchinkel
2011-2-24在19:38
不,我可以更改URL(我想为此需要连接的term_link函数)。 site / rootforum /有效,但site / rootforum / subforum /不起作用(404错误)...
–onetrickpony
2011-2-24在19:56
#2 楼
确实很简单。步骤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' );
请记住,添加此代码后,在刷新永久链接规则时需要将其激活(通过在Settings-> Permalinks上保存页面)!
刷新规则并将其保存到数据库,然后/ 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
2011-2-24在12:28
不幸的是,当前的URL重写系统强制将所有可能的URL模式压平成一个大列表,而不是遵循URL路径固有的树形结构。当前设置无法方便地匹配一系列文字,例如类别或论坛名称;如您所知,它会强制首先评估所有“页面” URL。按路径段进行匹配并以多种方式进行匹配(文字,类别,标签,税项,用户名,帖子类型,帖子名称,回调,过滤器挂钩以及最后的RegEx数组)可以更好地扩展复杂性,并且更加容易了解。
– MikeSchinkel
2011-2-25在4:42
迈克:实际上,这一点根本不容易理解,因为我还没有那里所说的第一个线索WTF。您对URL路由的想法既混乱又困难,您可能知道,我不同意它们。扁平搜索比您通常认为的更有意义,更灵活。大多数人不希望URL拥有所有不必要的复杂性,而且几乎没有人需要它。
–奥托
2011-2-25在17:03
谢谢,但是我想我已经尝试过了(wordpress.stackexchange.com/questions/9455/…)
–onetrickpony
2011-2-25在19:00
幸运的是,WordPress答案现在允许确实想要控制其URL的人最终发出声音,而且他们似乎很多(100+)。但是,我认为您可能无法在完整实施之前效仿我的示例。我预计,一旦我倡导的方法在插件中完全实现,并且在大约6到12个月后,它将成为基于WordPress的CMS网站路由其URL的首选方法。因此,让我们在大约9个月内恢复这场辩论。
– MikeSchinkel
2011年3月1日17:38
#3 楼
您将无法单独使用WP_Rewrite来执行此操作,因为它无法区分术语和后期。您还必须通过设置“发布查询var而不是分类法。
类似这样的事情:
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-02-20 17:51
#4 楼
我看一下顶级cats插件的代码:http://fortes.com/projects/wordpress/top-level-cats/
您可以轻松地对其进行调整,以便通过将第74行上的
$category_base = get_option('category_base');
更改为类似的内容来查找您的自定义分类标准:
$category_base = 'forums';
评论
可能适用于类别,但不适用于自定义分类法(至少在wp 3.1中)...我设法更改了URL,但出现404错误
–onetrickpony
2011-2-15在19:29
#5 楼
我建议您看一下Custom Post Permalinks插件。我现在没有时间进行测试,但这可能会对您的情况有所帮助。评论
不会,它只处理帖子,不处理分类法,即使可以,我也必须在%forum%之前添加某种前缀,这正是我要避免的事情...
–onetrickpony
2011-2-17在22:14
#6 楼
由于我熟悉您的其他问题,因此我会在脑海中回答这个问题。我根本没有测试过,但是如果您在注册后立即执行一次,可能会起作用您想要的所有永久性结构:他们在数组的末尾。这样可以防止这些规则干扰其他任何重写规则。接下来,它强制执行冗长的重写规则(每个页面都有一个带有特定正则表达式的单独规则)。这样可以防止页面干扰您主题的规则。最后,它执行一次硬刷新(确保您的.htaccess文件可写,否则将无法正常工作)并保存非常大且非常复杂的重写规则数组。
评论
尝试过,没有任何变化
–onetrickpony
2011-02-17 23:21
#7 楼
有一个插件。它通过为每个自定义帖子类型页面添加特定规则来删除类型标签。
评论
该链接不再起作用。
– Philipp
20年7月2日,9:16
#8 楼
不知道这是否适用于分类法,但它适用于自定义帖子类型尽管两年未更新,但以下插件对我有用:
http:// wordpress.org/plugins/remove-slug-from-custom-post-type/
FYI我正在使用WP类型
3.9.1
运行WP 1.5.7
#9 楼
使用斜杠作为段符的值... 100%工作'rewrite' => array(
'slug' => '/',
'with_front' => FALSE
),
评论
不完全是,这会使所有页面发布类型变为404。
–米洛
2015年4月9日在15:20
评论
@One Trick Pony-您是否尝试过不将'slug'=>'forums'留空而只是将其完全删除并仅具有'rewrite'=> array('with_front'=> false,'hierarchical'=> true)吗?我认为过去对我有用。另外,请确保您冲洗了永久链接。尝试过,并且永久链接看起来相同。添加'slug'=>''使其起作用,但随后使用此分类法的帖子会生成404s
@One Trick Pony-除了“一般性讨论”之外,您还需要其他哪些顶级路径段?
任何%forum%应该是顶级细分受众群
@One Trick Pony-我只是希望您能给我一些其他的上下文顶级路径段。