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


21

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

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()に空のスラッグ引数を渡すと動作しますが、この分類法に関連付けられた投稿タイプのパーマリンクに問題が発生します


@One Trick Pony- 'slug' => 'forums'空白のままにして、完全に削除してそのままにしてみました'rewrite' => array('with_front' => false, 'hierarchical' => true)か?それは私にとって過去にうまくいったと思います。また、パーマリンクを必ずフラッシュしてください。
eileencodes

それを試してみたところ、パーマリンクは同じように見えました。追加'slug' => ''それは動作しますが、この分類法を使用したポストは、404エラーを生成します
onetrickpony

@One Trick Pony-'general-discussion'以外に、他にどのようなトップレベルのパスセグメントが必要ですか?
MikeSchinkel

いずれも%forum%トップレベルのセグメントである必要があります
-onetrickpony

@One Trick Pony-コンテキスト用に他のトップレベルのパスセグメントをいくつか提供してほしいと思っていました。
MikeSchinkel

回答:


11

更新

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

元の回答

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

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

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

だから、状態にそれの前に明示的に、この技術のインサートロジックparse_request()たURLツー正規表現マッチをチェックし、タクソノミータームの試合のために代わりに最初に見えるが、それだけ置き換え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}(/.*)$#",'$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();

PS警告#1

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

どうして?そのため一つだけのプラグインは、このテクニックを使用することができます。2つのプラグインが使用しようとすると、互いに競合します。

余談として、この戦略を拡張して、必要となる可能性のある実質的にすべてのユースケースパターンを一般的に処理することができます。完全に汎用的な実装を構築します。

警告#2

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

とにかく...


これを書いた後、一般的に分類用語ではなくカテゴリをテストしたので、上記は'forum'分類には機能しませんが、今日は後で機能するように修正することに
気付きました...-MikeSchinkel

そのため、前のコメントで言及した問題に対処するためにコードを更新しました。
MikeSchinkel

この作業を取得できません...書き換えルールを変更する必要がありますか?
onetrickpony

@One Trick Pony-もう少し診断情報が役立ちます。:)何をしようとしましたか?ブラウザにURLを入力するとどうなりますか?偶然'forums'ではなく、分類法を呼び出しました'forum'か?これらのページにリンクするURLが変更されることを期待していますか(もしそうなら、私のコードはURLの印刷に対処せず、URLのルーティングのみに対処します。)
MikeSchinkel

いいえ、URLを変更できます(そのためにフックする必要があるterm_link関数だと思います)。site/rootforum/動作するが、site/rootforum/subforum/動作しない(404エラー)...
onetrickpony

7

本当にシンプル。

ステップ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' );

このコードを追加した後、パーマリンクルールをフラッシュするときは、(設定->パーマリンクのページを保存して)アクティブにする必要があることに注意してください!

ルールをフラッシュし、データベースに保存したら、forum = whatever taxonomyページに移動する必要があります。

正規表現を理解していれば、書き換えルールはそれほど難しくありません。これらのコードを使用して、デバッグ時に役立ちます。

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をキャッチするのを防ぐためです。


書き換えルールのデバッグを簡単にしたい場合は、(再度)書き換えアナライザープラグインをお勧めします。これにより、ルールを試して、クエリ変数をその場で確認できます。
ヤンファブリー

残念ながら、現在のURL書き換えシステムは、URLパスの固有のツリー構造に従うのではなく、すべての潜在的なURLパターンを大きなリストにフラット化することを強制します。現在の設定は、カテゴリやフォーラム名などのリテラルの配列と簡単には一致しません。ご存知のように、すべての「ページ」 URLが最初に評価されます。パスセグメントによる照合と複数の方法での照合(リテラル、カテゴリ、タグ、課税条件、ユーザー名、投稿タイプ、投稿名、コールバック、フィルターフック、最後にRegExの配列)は、複雑さを改善し、より簡単になります理解する。
MikeSchinkel

マイク:実は、それはまったく簡単なことではありません。あなたが話している最初の手掛かりWTFがまだないからです。URLルーティングのあなたのアイデアは混乱を招き、困難です。おそらくご存知のように、私はそれらに同意しません。フラット検索の方が理にかなっており、あなたが信用する傾向があるよりも柔軟です。ほとんどの人はURLの不必要な複雑さを望んでおらず、ほとんど誰もそれを必要としません。
オットー

おかげで、私は、私はすでに(前にこれを試したと思うwordpress.stackexchange.com/questions/9455/...
onetrickpony

幸いWordPressの回答は今ことができます人々そのURLの制御がしたい最後に声を持っているが、彼らは(100+)多くのように見えます。しかし、完全に実装する前に私の例に従うことができない場合があることを尊重します。私が提唱しているアプローチがプラグインに完全に実装され、約6〜12か月後には、WordPressベースのCMSサイトがURLをルーティングするための好ましい方法になると予測しています。約9か月でこの議論を再開しましょう。
MikeSchinkel

4

用語スラッグと投稿スラッグを区別できないため、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' );

分類は投稿タイプのに定義する必要があることに注意してください。

これは、同じクエリ変数を持つ分類法と投稿タイプを持つことは悪い考えであることを指摘する良い機会です。

また、いずれかの条件と同じスラッグを持つ投稿にアクセスすることはできません。


同じクエリ変数を持つ分類法と投稿タイプを持つことは悪い考えですが、同じ名前を持つ分類法と投稿タイプを持つ人々には悪い考えであることを意味しますが、そうではありません。同じ名前を使用する場合、2つのうち1つだけにクエリ変数を含める必要があります。
MikeSchinkel

2

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

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

あなたはそれを簡単に適応させることができますので、それを変更することでカスタム分類学のナメクジを探しています

$category_base = get_option('category_base');

74行目で次のようにします。

$category_base = 'forums';

カテゴリに対しては機能する可能性がありますが、カスタム分類には対応していません(少なくともwp 3.1では)... URLを変更できましたが、404エラーが発生しました
onetrickpony

2

Custom Post Permalinksプラグインをご覧になることをお勧めします。現在、テストする時間はありませんが、あなたの状況に役立つかもしれません。


それはしません、それは分類法ではなく、投稿のみを処理します、そして、たとえそうであっても、私は前に何らかの種類のプレフィックスを追加する必要があります%forum%、それはまさに私が避けようとしているものです
...-onetrickpony

2

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

私はこれをまったくテストしていませんが、必要なすべてのパーマ構造を登録した直後に1回実行すると動作する可能性があります。

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ファイルが書き込み可能であることを確認します。そうしないと、これは機能しません)、非常に複雑な書き換えルールの配列を保存します。


試してみたが、何も変わらない
onetrickpony



2

スラッシュを使用するスラッグの値としてをます... 100%動作します

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

2
完全ではありません。これにより、すべてのpage投稿タイプが404になります。-
ミロ
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.