Удалить слиток таксономии из пользовательской иерархической постоянной ссылки таксономии


Я создал таксономию "форум", используя следующие правила:

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, связанными с этой таксономией

Author: onetrickpony, 2011-02-15

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, который я должен был установить.. Так что, если что-то пойдет не так, дайте мне знать, и я буду рад изучить это и пересмотреть ответ, если потребуется.

В любом случае...

 11
Author: MikeSchinkel, 2016-07-20 06:59:38

На самом деле все просто.

Шаг 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-адрес до того, как он попадет в ваши правила.

 7
Author: Otto, 2011-02-24 01:39:08

Вы не сможете сделать это, используя только 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 запроса плохая идея.

Кроме того, вы не сможете получить доступ к сообщениям, которые имеют тот же заголовок, что и одно из условий.

 4
Author: scribu, 2011-02-18 01:27:02

Я бы взглянул на код плагина cats верхнего уровня:

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

Вы могли бы легко адаптировать это, чтобы он искал вашу пользовательскую таксономию, изменив

$category_base = get_option('category_base');

В строке 74 что-то вроде:

$category_base = 'forums';
 2
Author: Pabline, 2011-02-15 17:17:21

Я бы предложил взглянуть на Пользовательский плагин постоянных ссылок для сообщений . У меня сейчас нет времени на проверку, но это может помочь в вашей ситуации.

 2
Author: Travis Northcutt, 2011-02-17 22:11:52

Поскольку я знаком с другим вашим вопросом, я отвечу с учетом этого.

Я вообще не тестировал это, но это может сработать, если вы выполните это один раз сразу после регистрации всех пермаструктур, которые вы хотите.:

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
Author: John P Bloch, 2017-04-13 12:37:42

Для этого есть плагин.

Он удаляет блокировку типа, добавляя определенное правило для каждой настраиваемой страницы типа публикации.

 2
Author: Adam Bell, 2011-11-26 16:28:03

Не уверен, сработает ли это для таксономий, но это сработало для пользовательских типов записей

Хотя он не обновлялся в течение 2 лет, приведенный ниже плагин работал для меня: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

К вашему сведению, я запускаю WP 3.9.1 с типами WP 1.5.7

 2
Author: Max, 2014-06-22 15:25:41

Используйте косую черту в качестве значения для слизняка... 100% рабочий

'rewrite' => array(
    'slug'       => '/', 
    'with_front' => FALSE
 ),
 2
Author: Sathish Jayaraman, 2015-04-09 13:46:33