親ドロップダウンにトップレベルの記事のみ表示されるようにする

必要があって WordPress 標準の「投稿」(post) を階層を持つようにカスタマイズしたのですが、親を設定するドロップダウンから目的の投稿を選ぶのが結構大変になってくることに気づきました。固定ページは大抵それほど大量には存在しませんが、投稿はどんどん増えていくので、どんどん深刻な問題になってきます。そのサイトの運用では親子関係は2階層までなので、ドロップダウンにトップレベルの投稿だけが表示されるようにしようと考えました。

属性メタボックス編

このドロップダウンの1つは編集画面の [属性]メタボックスの中にあり、wp-admin/includes/meta-boxes.php の page_attributes_meta_box() の中で出力されています。ドロップダウン自体はテンプレートタグ wp_dropdown_pages() で表示されていますが、このタグの引数に対して、下記のようにフィルターフックが設定されていました。すばらしい。

$dropdown_args = apply_filters( 'page_attributes_dropdown_pages_args', $dropdown_args, $post );
$pages = wp_dropdown_pages( $dropdown_args );

WordPress Codex の wp_dropdown_pages() の説明を見ると、引数として与えるパラメータの中に depth というのがあり、この値でリストに含める最大階層を指定できることがわかります。デフォルト値は 0 (すべてのページとサブページを表示) ですが、これを 1 にすることで、第 1 階層、つまりトップレベルのページのみ表示することができます。

add_filter( 'page_attributes_dropdown_pages_args', function( $dropdown_args, $post ) {
	if ( $post->post_type == 'post' ) {
		$dropdown_args['depth'] = 1;
	}
	return $dropdown_args;
}, 10, 2 );

上の例では、対象を投稿に限定するために if ( $post->post_type == ‘post’ ) { } で括っています。page_attributes_meta_box() のソースコードを見ると、その先頭付近で $dropdown_args = array( ‘post_type’ => $post->post_type, … とやっているので $dropdown_args[‘post_type’] でも投稿タイプをチェックできます。

クイック編集パネル編

親ドロップダウンはクイック編集パネル内にもあります。どこに書かれているのか探したところ、wp-admin/includes/class-wp-posts-list-table.php の中にありました。ソースの該当箇所は下記のようになっています。

$dropdown_args = apply_filters( 'quick_edit_dropdown_pages_args', $dropdown_args );
wp_dropdown_pages( $dropdown_args );

やはり、wp_dropdown_pages() の引数にフィルターフックが仕込まれているので、前の例と同様、ここにフィルターを追加してやります。

add_filter( 'quick_edit_dropdown_pages_args', function( $dropdown_args ) {
	if ( $dropdown_args['post_type'] == 'post' ) {
		$dropdown_args['depth'] = 1;
	}
	return $dropdown_args;
} );

以上で、属性メタボックスとクイック編集パネルの親ドロップダウンの中身がすっきりしました。