
【WordPress】静的サイト+WordPressで小説サイトを構築する②
2回目です。
前回は構築まで行ったので、今回は具体的な共存方法についてになります。
前回の記事はこちらです。
1. index.htmlとindex.phpを共存させる
index.html と index.php が同時に存在する場合、優先されるのは index.html です。
そのため、index.html と index.php を共存させるためにはまず、 wp-includes/canonical.php を編集していきます。
516行目と592行目あたりにある以下のコードをコメントアウトします。(WordPress ver6.1.1)
バージョンによって行は前後するので、エディタの検索機能を利用してみてください。
// 516行目
$redirect['path'] = preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/?$|', '/', $redirect['path'] );
// 592行目
$redirect['path'] = preg_replace( '|/' . preg_quote( $wp_rewrite->index, '|' ) . '/*?$|', '/', $redirect['path'] );
これでリダイレクトはされなくなり、 http://example.com/index.php にアクセスすれば index.php が表示されるようになります。
更に、index.html ではなく index.php の表示を優先させたい場合は、.htaccess に以下のように追記します。
DirectoryIndex index.php index.html
また、WordPressでホームページの設定を「最新の投稿」ではなく「固定ページ」に設定している場合、index.php にアクセスするとルートディレクトリにリダイレクトされてしまう場合があります。
これを回避したい場合には functions.php に以下のコードを追記します。
remove_filter('template_redirect', 'redirect_canonical');
これらは静的HTMLを移植する際などに、共存した状態で作業を行うのに適していますが、ゼロから構築する場合はあまり気にしなくても大丈夫です。
2. サイト構成
以下は具体的なサイト構成の例です。
public_html / index.html
│ sample.html
├─ novels /
│ ├─ ジャンル1 / index.html
│ │ 作品1-1.html
│ │ 作品1-2.html
│ │
│ ├─ ジャンル2 / index.html
│ │ 作品2-1.html
│ │ 作品2-2.html
│ │
│ └─ ジャンル3 / index.html
│ 作品3-1.html
│ 作品3-2.html
├─ assets /
│ ├─ css /
│ ├─ img /
│ └─ js /
├─ cgi-bin /
└─ wp /* WordPressインストールフォルダ */
├─ novels(カスタム投稿タイプ)
│ ├─ ジャンル1(WordPress) / 作品1-3
│ │ 作品1-4
│ │
│ ├─ ジャンル2(WordPress) / 作品2-3
│ │ 作品2-4
│ │
│ └─ ジャンル3(WordPress) / 作品3-3
│ 作品3-4
│
├─ メールフォーム(固定ページ)
├─ ブログ(カスタム投稿タイプ or 投稿カテゴリー)
└─ 更新情報(カスタム投稿タイプ or 投稿カテゴリー)
実際には、WordPress以下はすべてルートURLで表示されます。
つまり、静的HTMLで作られたページ、
http://example.com/novels/ジャンルn/index.html
http://example.com/novels/ジャンルn/作品n.html
と、WordPressで作られた作品群、
http://example.com/novels/ジャンルn(WordPress)/作品n
は全く同じ階層で表示されます。
WordPressで作られた作品群のURLの内訳は以下のような感じです。
http://example.com/novels(カスタム投稿タイプ)/ジャンルn(親ページ)/作品n(子ページ)
まず、静的ページのフォルダと同じ novels というカスタム投稿タイプをページで作り、親子関係を true にします。
そして親ページとしてジャンル別のフォルダと同じ名前のslugを設定し、これを非公開ページとして作ります。この時、事前に非公開ページを親として選べるように設定する必要がありますが、それは後述します。
そして子ページを作品として公開する、という方法です。
つまり、親である非公開ページはフォルダ相当として扱い、それ以上の意味は持ちません。
これにより基本は静的HTMLで作品を公開しつつ、パスワード保護等の閲覧制限をかけたい場合は全く同じ階層でWordPressによる作品公開を可能とさせるわけです。
作品ページからジャンルINDEXに戻る際も、リンクの指定は一つで大丈夫です。
<a href="./index.html">back</a>
これだけで静的ページからもWordPressのカスタム投稿タイプからも、同じジャンルINDEXページに移れるようになります。
また、パーマリンクに拡張子を付与して静的HTMLのように見せることもできます。(RewriteRuleの書き換え、またはプラグインを使用)
3. 小説用カスタム投稿タイプの設定
今回はプラグインを使わずにカスタム投稿タイプを設定していきます。
プラグインを使用してもいいのですが、何かあったときに対応が面倒なため、個人的にはカスタム投稿タイプ、カスタムタクソノミー、カスタムフィールドはプラグインに依存しない方法を取っています。
以前、使用していたプラグインが有料化となり、メンテナンスができなくなったことがあるのですが、実際にそのような場合になった際でも、プラグインを無効化の後、全く同じカスタム投稿タイプを独自に設定すれば、データは残っているので安心してください。
3-1. functions.php
まず、functions.php に直接書き込んでいる人はそれをやめるところから始めてください。
functions.php に直接書き込んでいくと、どこに何のコードを書いたのか、わからなくなり、メンテナンス効率も可読性も下がります。
そのため、functions.php にはテンプレートパーツを呼び出すためのコードだけを書いていきます。
それぞれのテンプレートファイルはカテゴリーごとに細分化して管理します。
<?php
locate_template('lib/init.php', true); // 初期設定の関数
locate_template('lib/cleanup.php', true); // 不要なモノを削除する関数
locate_template('lib/rewrite_rule.php', true); // RewriteRule
locate_template('lib/scripts.php', true); // CSSやJavascript関連の関数
locate_template('lib/widgets.php', true); // サイドバー、ウィジェットの関数
locate_template('lib/pagination.php', true); // ページネーション出力の関数
locate_template('lib/breadcrumb.php', true); // パンくずリスト
locate_template('lib/profile_img.php', true); // プロフィール画像の設定
locate_template('lib/custom_type.php', true); // カスタム投稿タイプ
locate_template('lib/custom_fields.php', true); // カスタムフィールド
locate_template('lib/post_settings.php', true); // 投稿設定
locate_template('lib/custom.php', true); // その他カスタマイズの関数
?>
今回はテーマフォルダ直下に /lib というフォルダを作り、その中に custom_type.php というファイルを作ってそこに書き込んでいきます。
3-2. カスタム投稿タイプ
今回は novels というカスタム投稿タイプと、novels_cat というカスタムタクソノミーを設定していきます。
また、複数のカスタム投稿タイプを作るためのサンプルも同時に記述していきます。
// カスタム投稿タイプを作成する関数
function create_post_types() {
// 小説カスタム投稿タイプの設定
$novel_labels = array(
'name' => '小説',
'singular_name' => 'novel',
'all_items' => '小説一覧',
'add_new' => '新規追加',
'add_new_item' => '新規追加'
);
$novel_args = array(
'labels' => $novel_labels,
'public' => true,
'has_archive' => true, // アーカイブを有効にする
'menu_position' => 3, // 管理画面のメニューでの表示順
'menu_icon' => 'dashicons-admin-page', // メニューアイコン
'show_in_rest' => true,
'capability_type' => 'page',
'hierarchical' = > true, // 階層化(親子関係を持たせるか)
'taxonomies' => array('novels_cat'), // 使用するタクソノミーの関連付け
'supports' => array(
'title',
'editor',
'revisions',
'custom-fields',
'page-attributes' // hierarchicalと併せて記述
)
);
register_post_type('novels', $novel_args);
// 小説カテゴリーの設定
$novel_cat_args = array(
'label' => '小説カテゴリー',
'public' => true,
'hierarchical' => true,
'show_in_rest' => true
);
register_taxonomy('novels_cat', 'novels', $novel_cat_args);
// サンプル用カスタム投稿タイプの設定
$sample_labels = array(
'name' => 'サンプル',
'singular_name' => 'customtype2',
'all_items' => 'サンプル一覧',
'add_new' => '新規追加',
'add_new_item' => '新規追加'
);
$sample_args = array(
'labels' => $sample_labels,
// 省略
'taxonomies' => array('taxonomy2'),
'supports' => array(
// 省略
)
);
register_post_type('customtypes2', $sample_args);
// サンプルタクソノミーの設定
$sample_cat_args = array(
'label' => 'タグ',
'public' => true,
'hierarchical' => false,
'show_in_rest' => true
);
register_taxonomy('taxonomy2', 'customtypes2', $sample_cat_args);
}
// add_actionで'create_post_types'関数を'init'アクションにフックする
add_action('init', 'create_post_types');
詳しいパラメーターの説明は関数リファレンス/register post type - WordPress Codex 日本語版を参照してください。
変数は必要に応じてわかりやすいものに変更してください。
ただの変数なので、customtypes1 、customtypes2 、taxonomy1 、taxonomy2 などでも大丈夫です。
novels、customtypes2 がカスタム投稿タイプで、novels_cat、taxonomy2 がカスタムタクソノミーです。
それぞれの投稿タイプ、カスタムタクソノミーは register_post_type() と register_taxonomy() で設定します。
'taxonomies' => array('novels_cat') は管理画面でカテゴリーの絞り込みを行う際に、どうしても関連付けができずに他のカスタムタクソノミーを参照してしまったので設定しました。
複数のカスタム投稿タイプ、カスタムタクソノミーを設定したときに起きるようなのですが、多くの記事ではこの問題に関する記述が見つけられなかったので、些か悩みました。
関連付けが上手くいっていないということだけは挙動を見てもわかったのですが、改めて関数リファレンスを確認した際にこのパラメーターを見つけ、追加してみたところ無事、問題が解決しましたので、こちらも設定することをお勧めします。
勿論、配列なので複数指定することが可能です。
'taxonomies' => array('novels_cat','novels_tax'),
3-3. カスタムタクソノミーを管理画面で表示する
ただカスタム投稿タイプ、カスタムタクソノミーを追加しただけでは利便性がよろしくないので、カスタム投稿タイプの管理画面にカスタムタクソノミーを表示するようにしていきます。
// 管理画面への表示
function add_custom_column( $column ){
global $post_type;
if ( $post_type === 'novels' ){
$column['novels_cat'] = '小説カテゴリー';
} else if ( $post_type === 'customtypes2' ){
$column['taxonomy2'] = 'カスタムタクソノミー';
}
return $column;
}
add_filter( 'manage_posts_columns', 'add_custom_column' );
function add_custom_column_id( $column_name, $id ){
if ( $column_name === 'novels_cat' ) {
echo get_the_term_list( $id, 'novels_cat', '', ', ' );
} else if ( $column_name === 'taxonomy2' ) {
echo get_the_term_list( $id, 'taxonomy2', '', ', ' );
}
}
add_action( 'manage_novels_posts_custom_column', 'add_custom_column_id', 10, 2 );
add_action( 'manage_customtypes2_posts_custom_column', 'add_custom_column_id', 10, 2 );
これで管理画面にカスタムタクソノミー用の列が追加されたはずです。
3-4. 管理画面にカスタムタクソノミーを絞り込む
簡単に言えば、投稿にあるようなカテゴリーで絞り込むための機能を追加します。
小説カテゴリーは主にジャンル、短編、シリーズなどで分類します。

コードは以下のとおりです。
// カテゴリーの絞り込みを追加する
add_action( 'restrict_manage_posts', 'add_custom_taxonomies_term_filter' );
function add_custom_taxonomies_term_filter() {
global $post_type;
if ( $post_type == 'novels' ) {
$taxonomy = 'novels_cat';
wp_dropdown_categories( array(
'show_option_all' => 'すべてのカテゴリー',
'orderby' => 'name',
'show_count' => True,
'selected' => get_query_var( $taxonomy ),
'hide_empty' => 0,
'hierarchical' => 1,
'name' => $taxonomy,
'taxonomy' => $taxonomy,
'value_field' => 'slug',
) );
} else if ( $post_type == 'customtypes2' ) {
$taxonomy = 'taxonomy2';
wp_dropdown_categories( array(
'show_option_all' => 'すべてのタグ',
'orderby' => 'name',
'show_count' => True,
'selected' => get_query_var( $taxonomy ),
'hide_empty' => 0,
'hierarchical' => 1,
'name' => $taxonomy,
'taxonomy' => $taxonomy,
'value_field' => 'slug',
) );
}
}
$post_type == 'novels' でカスタム投稿タイプを指定し、$taxonomy = 'novels_cat' でカスタムタクソノミーを指定します。
これに併せ、3-2. で指定した'taxonomies' => array('novels_cat') により、絞り込みは正しく機能するはずです。
3-5. 非公開ページを親ページとして指定できるようにする
通常、非公開ページは親として指定することはできません。
そのため、こちらも functions.php に追加していくのですが、自分は post_settings.php というファイルを作り、その中に記述しています。
// 固定ページを非公開の状態でも階層化選択できるようにする
function my_dropdown_pages($dropdown_pages_args) {
$dropdown_pages_args['post_status'] = array('publish', 'future', 'draft', 'pending', 'private'); //選択を許可する公開ステータス
return $dropdown_pages_args;
}
add_filter('page_attributes_dropdown_pages_args', 'my_dropdown_pages');
add_filter('quick_edit_dropdown_pages_args', 'my_dropdown_pages');
add_filter('quick_edit_dropdown_pages_args', 'my_dropdown_pages'); はクイック編集に追加するためのフィルターです。

4. 非公開ページをフォルダとして設定する
非公開ページを親として指定することができるようになったため、以降はこれをジャンル用のフォルダとして利用します。
名前は何でもいいのですが、わかりやすく [F] ジャンル名 として管理します。必ずカテゴリも設定するようにしてください。

親子階層はあくまで ジャンル > 作品 でのみ管理します。
勿論、シリーズは別階層にて管理することも可能ですが、親子孫階層は必ずシンプルにしてください。
作品の並び順はslugまたは編集画面の ページ属性 > 順序 で対応します。
また、短編、長編、シリーズ等の分類はカテゴリーでのみ対応します。あるいは、カテゴリーは ジャンル > シリーズ のみを分類してください。
カテゴリーは親子階層までを指定。孫階層は使用しません。
またカスタムタクソノミーでタグを追加する場合は、上記以外の特殊な区分(カップリング、年齢制限、ステータス、長編・短編区分等)にのみ使用するようにします。
ここまででも管理はだいぶしやすくなったはずですが、次回は更にカスタムフィールドを追加していこうと思います。
お疲れ様でした!