更新自编写此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
我应该设置的对象。。因此,如果有什么不确定的地方,请告诉我,我会很乐意研究它,并在必要时修改答案。
无论如何