web-dev-qa-db-ja.com

カスタムの階層型分類法パーマリンクから分類法スラグを削除する

これらの規則を使用して、「フォーラム」分類法を作成しました。

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

Register_taxonomy()に空のslug引数を渡すとうまくいきますが、それはこの分類法に関連するpost型のパーマリンクに問題を引き起こします。

21
onetrickpony

更新

このWordPressコアの記述以降、WPクラスを拡張することなくURLルーティングをエレガントに処理できる'do_parse_request'フックが追加されました。 "ハードコアURLルーティング" ;というタイトルの2014年アトランタWordCampトークで、このトピックについて詳しく説明しました。スライドはリンクから入手できます。

元の回答

URLデザインは10年以上にわたって重要でした。私も それについてブログを書いた 数年前。そしてWordPressは合計が素晴らしいソフトウェアですが、残念なことに URL書き換えシステムは脳死に至っていません(もちろん、IMHO::)とにかく、人々がURLの設計を気にかけているのを見てうれしいです!

私が提供しようとしている答えは、 Tracのこの提案(その提案に注意してくださいWP_Extendedを呼び出すプラグインですあるものとして始まり、別のものに進化したので、それがどこに向かっていたのかを見るために全体を読む必要があります。)

基本的には、WPクラスをサブクラス化し、parse_request()メソッドをオーバーライドし、グローバルな$wp変数にサブクラスのインスタンスを割り当てるという考え方です。次に、parse_request()内で、完全にURLに一致する必要がある正規表現のリストを使用する代わりに、実際にパスを検査しますby path segment.

明示的に述べると、この手法はparse_request()の前にロジックを挿入し、URLとRegExの一致をチェックし、代わりに分類用語の一致を最初に検索しますが、のみparse_request()を置き換えます特に[$query_vars]変数の使用を含むWordPress URLルーティングシステムの残りのすべてをそのまま残します。

この実装のユースケースでは、onlyはURLパスセグメントを分類用語と比較するだけです。この実装は、親子用語の関係を尊重して分類用語を検査し、一致を見つけると、URLパス(先頭と末尾のスラッシュを除く)$wp->query_vars['category_name']$wp->query_vars['tag']または$wp->query_vars['taxonomy']$wp->query_vars['term']に割り当て、バイパスしますWPクラスのparse_request()メソッド。

一方、URLパスが指定した分類法の用語と一致しない場合は、parse_request()メソッドを呼び出してURLルーティングロジックをWordPress書き換えシステムに委任します。 WPクラス。

ユースケースにWP_Extendedを使用するには、次のようにテーマのfunctions.phpファイル内からregister_url_route()関数を呼び出す必要があります。

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();

追伸警告#1

特定のサイトでは、この手法は見事に機能すると思いますが、この手法は、WordPress.orgで他の人が使用できるようにプラグインを配布するために使用しないでください。 WordPressに基づいたソフトウェアパッケージのコアにある場合は、問題ないかもしれません。それ以外の場合、この手法はURLルーティングの改善に限定する必要があります特定のサイト用

どうして? この手法を使用できるプラグインは1つのみであるためです。 2つのプラグインがそれを使用しようとすると、互いに競合します。

余談として、この戦略は、必要になる可能性のあるすべてのユースケースパターンを一般的に処理するように拡張することができ、空き時間または時間を後援できるクライアントを見つけたらすぐに実装するつもりです完全に汎用的な実装を構築するために必要であること。

警告#2

非常に大きな関数であるparse_request()をオーバーライドするためにこれを書きました。設定する必要があるグローバルな$wpオブジェクトのプロパティまたは2つを見逃した可能性があります。調査し、必要に応じて回答を修正してください。

とにかく...

11
MikeSchinkel

本当に簡単です。

ステップ1:書き換えパラメータの使用をまったく中止します。私たちはあなた自身の書き換えを転がすつもりです。

'rewrite'=>false;

手順2:詳細ページルールを設定します。これは通常のPagesがページの一番下でキャッチオールであるのではなく独自のルールを持つことを強制します。

ステップ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を指定すると、システムはルールの先頭から開始し、一致するものが見つかるまでルールを順にたどります。次に、その一致を使用して、クエリをより普通に見える?key = valueセットに書き換えます。それらのキーはWP_Queryオブジェクトに入るものに解析されます。簡単です。

編集: サイドノート、このメソッドはおそらくあなたの通常のカスタム投稿構造が%category%のようなキャッチオールではないもの、あるいはそのようなもので始まっている場合にのみうまくいくでしょう。あなたはそれを静的文字列か%year%のような数値で始める必要があります。これは、それがあなたのルールに到達する前にあなたのURLを捕まえるのを防ぐためです。

7
Otto

WP_Rewriteを単独で使用してこれを実行することはできません。なぜなら、用語スラッグとポストスラッグを区別できないからです。

分類法の代わりにpost query varを設定することで、 'request'にフックして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' );

分類法は before post型で定義する必要があります。

これは、同じクエリvarを持つタクソノミと投稿タイプを持つことが悪い考えであることを指摘するのに良い時期です。

また、用語の1つと同じスラグを持つ投稿に到達することはできません。

4
scribu

これが分類法で機能するかどうかはわかりませんが、カスタム投稿タイプでは機能しました

それは2年間更新されていませんが、以下のプラグインは私のために働きました: http://wordpress.org/plugins/remove-slug-from-custom-post-type/

参考私はWP 3.9.1をWP型1.5.7で実行しています

2
Max

スラッシュ の値として スラッシュ を使用してください。

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

カスタム投稿パーマリンクプラグイン を見てみることをお勧めします。今はテストする時間がありませんが、状況によっては役に立つかもしれません。

2

トップレベルのcatsプラグインのコードを見てみましょう。

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

それを変更することによってあなたのカスタム分類スラグを探しているので、あなたはそれを容易に適応させることができます

$category_base = get_option('category_base');

74行目のようなものに:

$category_base = 'forums';
2
Pabline

私は あなたの他の質問 に精通しているので、私はそれを念頭に置いて答えます。

私はまったくこれをテストしていませんが、あなたが望むすべてのpermastructsを登録した直後に一度これを実行すればうまくいくかもしれません:

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
John P Bloch

このためのプラグインがあります

カスタム投稿タイプページごとに特定のルールを追加して、スラッグを削除します。

2
Adam Bell