2011年11月12日土曜日

WordPressのカスタム投稿タイプとパーマリンク

WordPressはブログシステムですが、いろんな拡張ができる。
拡張の1つが、カスタムフィールド と呼ばれるもので、投稿記事に独自の属性を追加できるもの。
さらに、WordPress3.0からは カスタム投稿タイプ/カスタムタグソノミー というものが独自に追加できるようになっています。
WordPressは、[投稿]と[固定ページ]の2つのページの種類がありますが、それを増やすことが出来るのが カスタム投稿タイプ。
それらのページに [Category]という分類を設定できるのですが、[Category]以外の分類を増やす事が出来るのがカスタムタグソノミー。
カスタム投稿タイプ/カスタムタグソノミー を使うと、ブログシステムの枠を超えて、簡単なシステムを作る事ができるようになります。
記事を投稿する画面や、分類毎にページを作成するphpの振り分けはwordpressに任せてあとは自作という感じに。

ここ、3ヶ月ほどWordPressを使ってみて、カスタム投稿タイプ/カスタムタグソノミー も使ってみたりしていたのですが、よくハマったのがパーマリンク。
WEBページでのパーマリンクはREST風にちゃんと設定したくなるので...
WordPressでは、デフォルトの記事のリンクは

http://localhost?post_type={投稿タイプ}&p={投稿のID}

のような感じになっています。これを

http://localhost/sample/test

のようなリンクにするために、URLのRewrite をガシガシ行なって表示します。
WordPressではこのRewriteルールを自動的に設定or管理画面より設定できるようになっています。

たとえば、以下のような設定がWordpressから設定されます。
category/(.+?)/page/?([0-9]{1,})/?$' => string 'index.php?category_name=$matches[1]&paged=$matches[2]

WordPressのデフォルトのRewriteルールの設定は、管理画面のパーマリンクの設定を更新した時に行われると思うので、なんかリンク系を変更した時 とか データを他のサーバーに移行した時 などでは とりあえず更新しておくのが無難。

まぁ、それでも、うまく動かなくなったり、独自のルールにしたくなったり するのでお相手する必要があるのですけども。

ハマったことを中心に。

カスタムタグソノミーもパーマリンクの一部にしたい

デフォルトの投稿タイプ(post)では、カテゴリをパーマリンクの一部にできます。
だが、カスタム投稿タイプのときは...一番いい方法かどうかは不明ですが...以下でできます。

register_post_type で、
'rewrite' => array( 'slug' => CUSTOM_POST_TYPE.'/%'.CUSTOM_TAXONOMY.'%', 'hierarchical' => false ),
と指定しておいて、
add_filter('post_link', 'rating_permalink', 10, 3);
add_filter('post_type_link', 'rating_permalink', 10, 3);

function rating_permalink($permalink, $post_id, $leavename) {
    if (strpos($permalink, '%'.CUSTOM_TAXONOMY.'%') === FALSE) return $permalink;

    $post = get_post($post_id);
    if (!$post) return $permalink;
    if ($post->post_type != CUSTOM_POST_TYPE) return $permalink;

    $terms = wp_get_object_terms($post->ID, CUSTOM_TAXONOMY);
    if (!is_wp_error($terms) && !empty($terms) && is_object($terms[0])) $taxonomy_slug = $terms[0]->slug;
    else $taxonomy_slug = 'not-rated';

    return str_replace('%'.CUSTOM_TAXONOMY.'%', $taxonomy_slug, $permalink);
}
無理やり埋め込んであげている感じですねw
ただし、上記の方法だと、投稿IDをキーにパーマリンクを取得(get_permalink)する時にうまく反応してくれないことがあるので注意。

カスタム投稿タイプのパーマリンクの設定


カスタム投稿タイプの場合、register_post_type という関数を使って登録した後、
flush_rewrite_rules();
を行うと、Rewriteルールを追加してくれます。逆にこれを実行しないと追加されない。

まぁココまではいいのですが、複数のカスタム投稿タイプをつくった場合、登録した後にすぐに上記を複数回実行すると、環境によっては反映が不十分で、パーマリンク設定が未設定のものができてしまう現象に遭遇。
カスタム投稿タイプの登録(register_post_type)は、add_action('init', ***)のアクションフックで処理し、
flush_rewrite_rules は initの後に実行される add_action('wp_loaded', ***)で1回実行することにより解決しました。

あるはずのリンクが404になる

http://localhost?post_type={投稿タイプ}&p={投稿のID}
のような形式ならみれるけど、
http://localhost/sample/test
のような形式だと404になるのであれば、RewriteRuleがうまく設定されていない問題。

あるある。めっちゃよくある。

こういう時は繰り返しになるけど、

- 管理画面のパーマリンクを更新してみる
- カスタム投稿タイプの時には flush_rewrite_rules が実行されているかみる
- global $wp_rewrite を var_dump してルールの中身を確認してみる

な感じでさぐれば解決できるはず。たぶん。

http://localhost/****/****/page/2 のようなURLで2ページ目が表示されないという場合は
他のマッチパターンに引っかかってしまってダメな時もあります。
**** の部分が自由に設定できるような時は、page という名前の投稿名なのか pageの設定なのかが判断つかないよーな感じ。
WordPress.org Using Permalinksを見ると、
http://www.example.com/page/2/
http://www.example.name/category/categoryname/page/2/
http://www.example/year/month/day/page/2/
http://www.example/year/month/page/2/
の例が書かれてますね。

パーマリンクを変えたい

よくあるのが、カテゴリページのURLの category というのを削除したいというパターン
http://localhost/cateogry/fruit

http://localhost/fruit
Top Level Categories ってプラグインを使うと消すことができます。

もっと自由に設定したいんだ! というときには Rewriteルールを書いちゃう手も。
add_filter( 'rewrite_rules_array','my_insert_rewrite_rules' );
function my_insert_rewrite_rules($rules) {
$newrules = array();
$newrules['fruit/?$'] = 'index.php?category_name=fruit';
return $newrules + $rules;
}
とか。



パーマリンクの形式は事前に検討して、
全体的に整合性がとれるか? (=自分で正規表現でマッチパターンがかけるか?)
をしておくのは大事。
これができていれば、最悪なんとか頑張ればできるはず...と思う。
• • •