WordPressの管理画面の投稿一覧で、カスタムフィールドの値を表示しつつ、その値でソート可能にするスニペット

# 管理画面上でカスタムフィールドの値でソートしたい！
WordPressの投稿一覧にカスタムフィールドの値を表示させてくれとクライアントに要求される事がよくあるので、そんな時に手軽に機能追加出来るスニペットです。
Admin Columnsのような管理画面にメタ情報を追加出来るプラグインもありますが、無料版ではカスタムフィールドの値でソート出来ません。
下記コードでソート可能にした状態でAdmin Columnsを使って位置を並び替えたりすることも可能です。


```php:functions.php
/**
 * 管理画面の投稿一覧にカスタムフィールドの値を表示、ソート可能にする
 * 既にカスタムフィールドは準備済みとする(ACFでも)
 * $add_custom_columnsは例を参考に追加したい項目を設定
 * typeに使えるのは
 * 'NUMERIC', 'BINARY', 'CHAR', 'DATE', 'DATETIME', 'DECIMAL', 'SIGNED', 'TIME', 'UNSIGNED'
 * meta_typeに引き渡すので正しいソートをするためにちゃんと入力する
 */

// 例
$add_custom_columns = array(
	'post' => array( // 投稿タイプ
		array(
			'name'   => '数値', // 必須: 表示名
			'key'    => 'my_number', // 必須: カスタムフィールド
			'type'   => 'NUMERIC', // 任意: 値のタイプ(default = CHAR)
			'before' => 'date', // 任意: 表示する場所。この値の前(左)に挿入される(title, author, comments, date)
		),
		array(
			'name'   => '数値2',
			'key'    => 'my_number2',
			'type'   => 'NUMERIC',
			'before' => 'date',
		),
	),
	'news' => array( // カスタム投稿タイプもOK
		array(
			'name'     => '値',
			'key'      => 'my_value',
			'sortable' => false, // 任意: ソートは出来なくするときはfalse
		)
	),
);

// 投稿タイプごとにカラムを追加する
foreach ( $add_custom_columns as $post_type => $fields ) {
	add_filter( 'manage_' . $post_type . '_posts_columns', function ( $columns ) use ( $add_custom_columns, $post_type ) {
		$new_columns = $add_columns = array();
		foreach ( $add_custom_columns[ $post_type ] as $v ) {
			if ( isset( $v['before'] ) ) {
				$add_columns[ $v['before'] ][ $v['key'] ] = $v['name'];
			} else {
				$add_columns['last'][ $v['key'] ] = $v['name'];
			}
		}
		foreach ( $columns as $k => $v ) {
			if ( isset( $add_columns[ $k ] ) ) {
				foreach ( $add_columns[ $k ] as $key => $val ) {
					$new_columns[ $key ] = $val;
				}
				$new_columns[ $k ] = $v;
			} else {
				$new_columns[ $k ] = $v;
			}
		}
		if ( isset( $add_columns['last'] ) ) {
			foreach ( $add_columns['last'] as $k => $v ) {
				$new_columns[ $k ] = $v;
			}
		}

		return $new_columns;
	} );
	// ソート可能にする
	add_filter( 'manage_edit-' . $post_type . '_sortable_columns', function ( $sortable_column ) use ( $add_custom_columns, $post_type ) {
		foreach ( $add_custom_columns[ $post_type ] as $v ) {
			if ( isset( $v['sortable'] ) && ! $v['sortable'] ) {
				continue;
			}
			$sortable_column[ $v['key'] ] = $v['key'];
		}

		return $sortable_column;
	} );
}

// ソートの処理
add_filter( 'request', function ( $request ) use ( $add_custom_columns ) {
	foreach ( $add_custom_columns as $postType ) {
		foreach ( $postType as $fields ) {
			if ( isset( $request['orderby'] ) && $request['orderby'] == $fields['key'] ) {
				$type    = isset( $fields['type'] ) ? $fields['type'] : 'CHAR';
				$request = array_merge(
					$request,
					array(
						'meta_key'  => $fields['key'],
						'meta_type' => $type,
						'orderby'   => 'meta_value',
					)
				);
			}
		}
	}

	return $request;
} );

// 表示処理
add_action( 'manage_posts_custom_column', function ( $column, $post_id ) use ( $add_custom_columns ) {
	foreach ( $add_custom_columns as $post_type => $fields ) {
		foreach ( $fields as $v ) {
			if ( $column == $v['key'] ) {
				if ( function_exists( 'get_field' ) ) { // ACFが使える時
					$val = get_field( $v['key'], $post_id, true );
				} else {
					$val = get_post_meta( $post_id, $v['key'], true );
				}
				echo esc_html( $val );
			}
		}
	}
}, 10, 2 );
```