Удалить слиток таксономии из пользовательской иерархической постоянной ссылки таксономии
Я создал таксономию "форум", используя следующие правила:
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(), он работает, но это вызывает проблемы с постоянными ссылками типа post, связанными с этой таксономией
9 answers
ОБНОВЛЕНИЕ
С момента написания этого ядра WordPress был добавлен хук 'do_parse_request'
, который позволяет элегантно обрабатывать маршрутизацию URL-адресов без необходимости расширения класса WP
. Я подробно осветил эту тему в своем выступлении на WordCamp в Атланте в 2014 году под названием " Жесткая маршрутизация URL-адресов"; слайды доступны по ссылке.
ОРИГИНАЛЬНЫЙ ОТВЕТ
Дизайн URL-адресов был важен уже более десяти лет; Я даже написал блог об этом несколько лет назад. И хотя WordPress - это блестящее программное обеспечение , к сожалению, его система перезаписи URL-адресов не дотягивает до мертвого мозга (ИМХО, конечно. :) В любом случае, рад видеть людей, заботящихся о дизайне URL-адресов!
Ответ, который я собираюсь предоставить, - это плагин, который я называю WP_Extended
, который является доказательством концепции для это предложение по Проф ( Обратите внимание, что предложение начиналось как одно и переросло в другое, поэтому вам нужно прочитайте все это, чтобы понять, к чему это привело.)
В основном идея состоит в том, чтобы подкласс класса WP
, переопределить метод parse_request()
, а затем назначить глобальную переменную $wp
экземпляру подкласса. Затем в parse_request()
вы фактически проверяете путь по сегменту пути вместо использования списка регулярных выражений, которые должны полностью соответствовать URL-адресу.
Таким образом, чтобы указать это явно, этот метод вставляет логику перед parse_request()
который проверяет совпадения URL-адресов с регулярным выражением и вместо этого сначала ищет совпадения терминов таксономии, но он ТОЛЬКО заменяет parse_request()
и оставляет всю остальную систему маршрутизации URL WordPress неповрежденной, включая и особенно использование переменной $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-путь не соответствует термину из указанной вами таксономии, он делегирует логику маршрутизации URL-адресов системе перезаписи WordPress, вызывая метод 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
Хотя для данного сайта я думаю, что этот метод работает блестяще, но этот метод НИКОГДА не следует использовать для распространения плагина на WordPress.org для других, чтобы использовать. Если это лежит в основе программного пакета, основанного на WordPress, то это может быть нормально. В противном случае этот метод должен быть ограничен улучшением URL-адреса маршрутизация для определенного сайта .
Почему? Потому что только один плагин может использовать эту технику . Если два плагина попытаются использовать его, они будут конфликтовать друг с другом.
В качестве отступления эта стратегия может быть расширена для общей обработки практически каждого шаблона использования, который может потребоваться, и это то, что я намерен реализовать, как только найду свободное время или клиента, который может спонсировать время, необходимое для создания полностью универсального реализации.
ПРЕДОСТЕРЕЖЕНИЕ № 2
Я написал это, чтобы переопределить parse_request()
, что является очень большой функцией, и вполне возможно, что я пропустил одно или два свойства глобального объекта $wp
, который я должен был установить.. Так что, если что-то пойдет не так, дайте мне знать, и я буду рад изучить это и пересмотреть ответ, если потребуется.
В любом случае...
На самом деле все просто.
Шаг 1: Вообще прекратите использовать параметр перезаписи. Мы собираемся сделать ваши собственные переписывания.
'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-адресе система начинает с верхней части правил и просматривает их, пока не найдет подходящий. Совпадение затем используется для перезаписи запроса в более нормальный вид ?ключ= набор значений. Эти ключи анализируются в то, что входит в объект WP_Query. Простой.
Редактировать: Примечание сбоку, этот метод, вероятно, будет работать только в том случае, если ваша обычная пользовательская структура сообщений начинается с чего-то, что не является общим, например, %категория% или что-то в этом роде. Вам нужно начать его со статической строки или числа, например %year%. Это делается для того, чтобы он не перехватил ваш URL-адрес до того, как он попадет в ваши правила.
Вы не сможете сделать это, используя только WP_Rewrite, так как он не может различать слагаемые терминов и слагаемые сообщений.
Вы также должны подключиться к "запросу" и предотвратить 404, установив var запроса post вместо таксономического.
Что-то вроде этого:
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 запроса плохая идея.
Кроме того, вы не сможете получить доступ к сообщениям, которые имеют тот же заголовок, что и одно из условий.
Я бы взглянул на код плагина cats верхнего уровня:
Http://fortes.com/projects/wordpress/top-level-cats/
Вы могли бы легко адаптировать это, чтобы он искал вашу пользовательскую таксономию, изменив
$category_base = get_option('category_base');
В строке 74 что-то вроде:
$category_base = 'forums';
Я бы предложил взглянуть на Пользовательский плагин постоянных ссылок для сообщений . У меня сейчас нет времени на проверку, но это может помочь в вашей ситуации.
Поскольку я знаком с другим вашим вопросом, я отвечу с учетом этого.
Я вообще не тестировал это, но это может сработать, если вы выполните это один раз сразу после регистрации всех пермаструктур, которые вы хотите.:
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 доступен для записи, иначе это не сработает) и сохраняет очень большой и очень сложный массив правил перезаписи.
Он удаляет блокировку типа, добавляя определенное правило для каждой настраиваемой страницы типа публикации.
Не уверен, сработает ли это для таксономий, но это сработало для пользовательских типов записей
Хотя он не обновлялся в течение 2 лет, приведенный ниже плагин работал для меня: http://wordpress.org/plugins/remove-slug-from-custom-post-type/
К вашему сведению, я запускаю WP 3.9.1
с типами WP 1.5.7
Используйте косую черту в качестве значения для слизняка... 100% рабочий
'rewrite' => array(
'slug' => '/',
'with_front' => FALSE
),