かもメモ

自分の落ちた落とし穴に何度も落ちる人のメモ帳

Wordpress 固定ページのslug(URL)とカスタム投稿タイプ名が被ってるとどうなるか調べてみた。

既存のプロジェクトに途中参加した際の出来事です。
新しいカテゴリーのページを追加したいということでカスタム投稿タイプを作成したのですが、既存のページのレイアウトが変わってしまっていると連絡をもらってしまいました。調べた所このプロジェクトではwordpressの固定ページをカスタム投稿のトップページの様に使っていて、固定ページのslug(URL)とカスタム投稿タイプ名(URLになる部分)が同じ文字列になっていました。新しくカスタム投稿タイプを追加する前は固定ページで表示されていたものが、機能追加後はカスタム投稿のアーカイブページが表示されてしまっていたのが原因だったようです。
まぁそもそも固定ページのslugと同じカスタム投稿タイプを作成するのどうなの?って感じなのですが、

  • カスタム投稿のトップページをexample.com/hoge
  • カスタム投稿の記事ページをexample.com/hoge/single-page

と表示させたかったのでこのような処置になっていたのだと思います。

折角なので、プレーンなWordpress 固定ページのslug(URL)とカスタム投稿タイプ名がかぶっている時どうなるか調べてみました。

固定ページを作成する

WordPressの固定ページから新規作成を選びslugをworksとしてページを作成します。イェー!!
f:id:kikiki-kiki:20150430120748p:plain

この時local.wordpress/worksは当然ですが固定ページが表示されています。
f:id:kikiki-kiki:20150430121203p:plain
 

カスタム投稿タイプ(works)を作成する

固定ページのslugと同じworksという名前のカスタム投稿タイプを作成します。

<?php // function.php
add_action('init', 'add_my_post_type');
function add_my_post_type() {
  $post_type = 'works';
  $labels = array(
    'name'          => _x('works', 'works'),
    'singular_name' => _x('works', 'works'),
    'add_new'       => __('worksを新規作成'),
    'add_new_item'  => __('worksを作成'),
    'edit_item'     => __('worksを編集'),
    'new_item'      => __('新しいworks'),
    'view_item'     => __('worksを見る'),
    'search_items'  => __('worksを探す'),
    'not_found'     => __('worksはありません'),
    'not_found_in_trash' => __('ゴミ箱にworksはありません'),
  );
  $args = array(
    'labels'             => $labels,
    'public'             => true,
    'publicly_queryable' => true,
    'show_ui'            => true,
    'show_in_menu'       => true,
    'query_var'          => true,
    'capability_type'    => 'post',
    'has_archive'        => true,
    'hierarchical'       => false,
    'menu_position'      => null,
    'menu_icon'          => 'dashicons-art',
    'supports'           => array('title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments')
  );
  register_post_type($post_type, $args);
}

管理画面にworksというメニューが追加されているのでworksの投稿を作成して公開します。いちごちゃん is かわいい。OK?
f:id:kikiki-kiki:20150430122833p:plain
カスタム投稿のURLはhttp://local.wordpress/works/my-work01/となっています。
なのでこのカスタム投稿のアーカイブページはhttp://local.wordpress/works/となるはず。なのですが、固定ページのURLと同じになってしまいます。。。  

worksページを見に行く

http://local.wordpress/works/にアクセスします。
f:id:kikiki-kiki:20150430121203p:plain
固定ページが表示されていました。

カスタム投稿のページ(http://local.wordpress/works/my-work01/)を確認します。 f:id:kikiki-kiki:20150430123809p:plain
404ページが表示されていました。。。

どうやら固定ページを先に作成して固定ページのslugと同じ名前でカスタム投稿タイプを作成しただけでは、カスタム投稿のアーカイブページは先に作成した固定ページが表示され、カスタム投稿のページは404になってしまうようです。
 

パーマリンク設定を更新する

カスタム投稿を作成した時にページが404になってしまう時の解決方法の常套手段が管理画面のパーマリンク設定を更新するだと思います。
そもそもカスタム投稿のページが表示されていないので、ココを更新してみます。
管理画面 > 設定 > パーマリンクにアクセスして何も変更せずに保存ボタンを押します。

再度各ページを確認します。

  • Worksページ ( http://local.wordpress/works/ )
    f:id:kikiki-kiki:20150430143316p:plain
    カスタム投稿のアーカイブページが表示されます
  • カスタム投稿の個別ページ ( http://local.wordpress/works/my-work01/ )
    f:id:kikiki-kiki:20150430143450p:plain
    カスタム投稿の個別ページが表示されます

管理画面のパーマリンク設定を更新すると
新しく作成したカスタム投稿のアーカイブページが優先されるみたいです。
 

flush_rewrite_rules関数を使ってみる。

Wordpressにはリライトルールを変更するflush_rewrite_rulesという関数があるようです。 ざっくりいえば管理画面からパーマリンク設定の更新を行える関数でしょうか。

Function Reference/flush rewrite rules

Description

Remove rewrite rules and then recreate rewrite rules.
This function is useful when used with custom post types as it allows for automatic flushing of the WordPress rewrite rules (usually needs to be done manually for new custom post types). However, this is an expensive operation so it should only be used when absolutely necessary. See Usage section for more details.

<?php flush_rewrite_rules( $hard ); ?>

Parameters

$hard
(boolean) (optional) Whether to update .htaccess (hard flush) or just update rewrite_rules transient (soft flush). Default: true (hard flush)

関数リファレンス/register post type - WordPress Codex 日本語版

参考:プラグインの内部で投稿タイプを登録する場合は、有効化と無効化のフック(下記の「有効化するときリライトルールをフラッシュする」を参照)の中で flush_rewrite_rules() を呼び出すこと。もし flush_rewrite_rules() を使わない場合は、カスタム投稿タイプが正しいパーマリンク構造を表示するために、管理画面の 設定 > パーマリンク設定 を開いてパーマリンク構造を更新(変更を保存)する必要がある。

英語の関数のドキュメントの注意書きのような所に

Flushing the rewrite rules is an expensive operation, there are tutorials and examples that suggest executing it on the 'init' hook. This is bad practice.

と書かれますが、まぁいいや。テストって事でカスタム投稿タイプを追加した時にこの関数をを呼んでリライトルールを変更してみます。

まずは設定を固定ページを作成した段階に戻すしたいので、カスタム投稿タイプの追加を削除して、管理画面のパーマリンク設定を更新してhttp://local.wordpress/works/で固定ページが表示されていた状態に戻します。

続いてflush_rewrite_rules()を追加したカスタム投稿タイプの追加をします。
function.phpを編集します。

<?php // function.php
add_action('init', 'add_my_post_type');
function add_my_post_type() {
  $post_type = 'works';
  $labels = array(
    'name'          => _x('works', 'works'),
    'singular_name' => _x('works', 'works'),
    'add_new'       => __('worksを新規作成'),
    'add_new_item'  => __('worksを作成'),
    'edit_item'     => __('worksを編集'),
    'new_item'      => __('新しいworks'),
    'view_item'     => __('worksを見る'),
    'search_items'  => __('worksを探す'),
    'not_found'     => __('worksはありません'),
    'not_found_in_trash' => __('ゴミ箱にworksはありません'),
  );
  $args = array(
    'labels'             => $labels,
    'public'             => true,
    'publicly_queryable' => true,
    'show_ui'            => true,
    'show_in_menu'       => true,
    'query_var'          => true,
    'capability_type'    => 'post',
    'has_archive'        => true,
    'hierarchical'       => false,
    'menu_position'      => null,
    'menu_icon'          => 'dashicons-art',
    'supports'           => array('title', 'editor', 'author', 'thumbnail', 'excerpt', 'comments')
  );
  register_post_type($post_type, $args);
  // リライトルールを更新する
  flush_rewrite_rules(); // ← 追加
}

function.phpを保存して、管理画面のパーマリンク設定は触らずに各ページを確認してみます。

  • Worksページ ( http://local.wordpress/works/ )
    f:id:kikiki-kiki:20150430143316p:plain
    カスタム投稿のアーカイブページが表示されました
  • カスタム投稿の個別ページ ( http://local.wordpress/works/my-work01/ )
    f:id:kikiki-kiki:20150430143450p:plain
    カスタム投稿の個別ページが表示されました

flush_rewrite_rules() を実行することで管理画面のパーマリンク設定を保存したのと同じ状態になるので、予想通りカスタム投稿のページが表示されていました。

引数で.htaccessの書き換えをするかどうかが変更できますが、trueでもfalseでも同じ挙動になりました。

 

まとめ

固定ページのslug(URl)と同じ名前のカスタム投稿タイプを作成してしまった場合
パーマリンクの設定を保存し直すと、カスタム投稿のアーカイブページが優先されるというのが仕様なようです。

カスタム投稿のトップページは固定ページないでサブクエリを呼び出すのではなく、ちゃんとアーカイブページのテンプレートで作成しましょう。って事ですね!

複数人で開発をしているような場合は、本番環境のWordPressの管理画面から作成したものを各自の開発環境と合わせておかないと、意図せず同じURLを作ってしまい、リリースしたら元の○○が表示できなくなった!みたいな事もあるかもなので注意が必要かなと思いました。


[参考]