2026年8月24日

2026年8月24日

WordPressの投稿一覧に独自の列(カスタムカラム)を追加する方法|並べ替え対応まで

管理画面の投稿一覧に独自の列を足すには、列の見出しを登録するフィルター manage_posts_columns(投稿タイプ別なら manage_{投稿タイプ}_posts_columns)と、各行の中身を出力するアクション manage_posts_custom_column(同じく manage_{投稿タイプ}_posts_custom_column)の2つを使います。この記事では、カスタムフィールドの値を列に表示し、見出しクリックで並べ替えられるようにするところまでを、子テーマの functions.php または小さなプラグインに書くコードで解説します。

列の追加は「見出し」と「中身」の2段階

投稿一覧の表は、WordPressコアの WP_Posts_List_Table が描画しています。列を増やすときの流れは次の通りです。

  1. フィルターで列の配列にキーと見出しを追加する
  2. アクションで、そのキーの列に表示する中身を1行ずつ出力する
  3. 並べ替えたい場合は、並べ替え可能な列として登録し、クエリを調整する

列の配列は「列のキー => 見出し」の連想配列で、標準では cb(チェックボックス)、title、author、categories、tags、comments、date などが入っています。ここに独自のキーを追加すると、表に列が増えます。

コードの置き場所は、テーマを替えても管理画面の機能を残したいならプラグイン(またはmu-plugins)、そのテーマ専用でよければ子テーマの functions.php です。親テーマに直接書くと更新で消えます。

投稿一覧にカスタムフィールドの列を追加する

例として、投稿にカスタムフィールド price(価格)が保存されている前提で、「価格」列をタイトルの直後に追加します。

<?php
/**
 * 投稿一覧に「価格」列を追加する(見出し)
 */
function mysite_add_price_column( $columns ) {
	$new_columns = array();
	foreach ( $columns as $key => $label ) {
		$new_columns[ $key ] = $label;
		if ( 'title' === $key ) {
			$new_columns['price'] = __( '価格', 'mysite' );
		}
	}
	return $new_columns;
}
add_filter( 'manage_post_posts_columns', 'mysite_add_price_column' );

/**
 * 「価格」列の中身を出力する
 */
function mysite_render_price_column( $column_name, $post_id ) {
	if ( 'price' !== $column_name ) {
		return;
	}
	$price = get_post_meta( $post_id, 'price', true );
	if ( '' === $price ) {
		echo '&#8212;';
		return;
	}
	echo esc_html( number_format_i18n( (float) $price ) . '円' );
}
add_action( 'manage_post_posts_custom_column', 'mysite_render_price_column', 10, 2 );

ポイントは3つあります。

  • 配列の末尾に足すだけなら $columns['price'] = '価格'; で済みますが、日付列の右に並ぶため見づらくなります。上のようにループで組み直すと好きな位置に差し込めます。
  • アクションは全列分呼ばれるので、最初に列のキーを判定して自分の列以外では何もしないようにします。
  • 出力する値はユーザーが入力したデータなので、esc_html() でエスケープしてから表示します。リンクにするなら esc_url() を使います。

add_action() の第4引数 2 は、コールバックが列名と投稿IDの2つを受け取るための指定です。これを省くと投稿IDが渡らず、値が表示されません。

共通フックと投稿タイプ別フックの違い

manage_posts_columns は固定ページ以外のすべての投稿タイプに効く共通フックで、第2引数で投稿タイプ名を受け取れます。一方、manage_post_posts_columns(投稿)や manage_book_posts_columns(投稿タイプ book)は、その投稿タイプだけに効きます。

中身を出すアクションも同様で、manage_posts_custom_column は階層を持たない投稿タイプ、manage_pages_custom_column は固定ページなど階層型の投稿タイプで呼ばれます。投稿タイプ別の manage_{投稿タイプ}_posts_custom_column は階層の有無にかかわらず呼ばれるため、対象を絞るなら投稿タイプ別フックを使う方が分かりやすく、他の投稿タイプへの影響も避けられます。固定ページの場合は、見出し側が manage_pages_columns、中身側が manage_page_posts_custom_column または manage_pages_custom_column です。

列を並べ替え可能にする

見出しをクリックして並べ替えられるようにするには、manage_edit-{投稿タイプ}_sortable_columns フィルターで列を登録します。投稿なら manage_edit-post_sortable_columns です。値には、URLの orderby パラメーターに入る文字列を指定します。

<?php
function mysite_price_sortable_column( $columns ) {
	$columns['price'] = 'price';
	return $columns;
}
add_filter( 'manage_edit-post_sortable_columns', 'mysite_price_sortable_column' );

これで見出しがリンクになり、クリックすると orderby=price 付きのURLが開きます。ただし、WordPressは price という並べ替え方を知らないため、このままでは並び順が変わりません。pre_get_posts でクエリを書き換えます。

<?php
function mysite_price_orderby( $query ) {
	if ( ! is_admin() || ! $query->is_main_query() ) {
		return;
	}
	if ( 'post' !== $query->get( 'post_type' ) ) {
		return;
	}
	if ( 'price' === $query->get( 'orderby' ) ) {
		$query->set( 'meta_key', 'price' );
		$query->set( 'orderby', 'meta_value_num' );
	}
}
add_action( 'pre_get_posts', 'mysite_price_orderby' );

is_admin() と is_main_query() の判定は省かないでください。外すとフロント側の一覧やウィジェットのクエリまで書き換わります。数値として並べたいなら meta_value_num、文字列のまま並べるなら meta_value を指定します。meta_value のままだと「1000」が「200」より前に来るといった文字列順になるので、価格や点数には向きません。

並べ替え中に記事が減って見える理由

meta_key を指定して並べ替えると、そのカスタムフィールドを持たない投稿は結果から外れます。並べ替えた途端に件数が減ったように見えるのはこのためで、不具合ではありません。全件を並べたい場合は、未入力の投稿にも初期値(例:0)を保存しておく運用にすると扱いやすくなります。

表示を確かめる・不要な列を隠す

コードを保存したら、管理画面の「投稿」→「投稿一覧」を開き、次の点を確認します。

  • 列がタイトルの右に出ているか
  • 値が無い投稿でダッシュが出て、表が崩れていないか
  • 見出しクリックで昇順・降順が切り替わるか
  • 絞り込み(カテゴリーや月)と組み合わせても動くか

追加した列は、画面右上の「表示オプション」(2026年10月現在)でユーザーごとに表示・非表示を切り替えられます。列が見当たらないときは、まずここでチェックが外れていないかを確認してください。逆に標準の列を常に消したい場合は、フィルター内で unset( $columns['comments'] ); のように配列から削除します。

画面幅が狭いと、主要な列以外は折りたたまれて行の下に表示されます。スマートフォンで列が消えたように見えるのはこの仕様です。

パフォーマンスとセキュリティの注意点

各行で get_post_meta() を呼ぶのは問題ありません。一覧のクエリ実行時に、表示する投稿のカスタムフィールドがまとめてキャッシュに読み込まれるためです。避けたいのは、行ごとに WP_Query や get_posts() を実行して関連記事数などを数える処理です。1ページ20件なら20回の追加クエリになり、表示件数を増やすほど遅くなります。集計値が必要なら、保存時に計算してカスタムフィールドに持たせておく方が軽く済みます。

カスタムフィールドでの並べ替えは、データベースのメタ値に索引が効きにくく、投稿数が数万件規模になると一覧表示が重くなることがあります。頻繁に並べ替える列は数を絞り、遅い場合は Query Monitor などで実行時間を確認するとよいでしょう。

列の中に編集用のリンクやボタンを置く場合は、その操作を受け付ける側で current_user_can() による権限チェックとnonceの検証を入れてください。表示しているだけの列でも、値はエスケープしてから出力するのが原則です。

編集前には functions.php のバックアップを取り、構文エラーで管理画面に入れなくなった場合に備えてFTPなどでファイルを戻せる状態にしておきます。

まとめ

  • 列の見出しは manage_{投稿タイプ}_posts_columns フィルター、中身は manage_{投稿タイプ}_posts_custom_column アクションで追加します。共通フックより投稿タイプ別フックの方が影響範囲を絞れます。
  • 中身を出すアクションは列のキーで分岐し、add_action() の引数の数を2にして投稿IDを受け取ります。値はエスケープして出力します。
  • 並べ替えは manage_edit-{投稿タイプ}_sortable_columns で登録し、pre_get_posts で meta_key と orderby を設定します。数値なら meta_value_num です。
  • meta_key で並べ替えると値の無い投稿は外れるため、初期値の保存を検討します。
  • 行ごとの追加クエリは避け、集計値は保存時に計算しておくと一覧が重くなりません。

お気軽にご相談ください

お見積りへ お問い合わせへ
▲