wp_get_archives()でのpost_type指定
概要
WordPressには月間アーカイブのリンクを出力するのに使う、wp_get_archives()という関数がある。本関数はVer.4.3.1までは、投稿タイプ(post_type)を指定できず、デフォルトの'post'に対してしか、記事数を取得できなかった。WordPress4.4ではwp_get_archives()関数のパラメータでpost_typeの指定ができるようになった。ただし、一つだけしか指定できない。
WordPress 4.3.1まではどうやって投稿タイプを指定していたか
4.3.1まではwp_get_archives()で投稿タイプを指定するには、getarchives_whereフィルターでSQLのWHERE句を書き換えるのが常套手段とされていた。私も以下のようなフィルタ関数を使ってカスタム投稿タイプの月間アーカイブを作成していた。
post_type指定を可能にするgetarchives_whereフィルタ関数
function custom_post_type_getarchives_where($where, $args){
$post_type = isset($args['post_type']) ? $args['post_type'] : 'post';
if (is_array($post_type)) {
$conds = array();
foreach ($post_type as $type) {
$conds[] = "post_type = '".esc_sql($type)."'";
}
$cond = '('.implode(' OR ', $conds).')';
} else {
$cond = "post_type = '".esc_sql($post_type)."'";
}
return "WHERE $cond AND post_status = 'publish'";
}
add_filter('getarchives_where', 'custom_post_type_getarchives_where', 10, 2);
post_typeを指定しての月間アーカイブHTMLの生成
$args = array('type' => 'monthly',
'limit' => '',
'format' => 'html',
'before' => '',
'after' => '',
'show_post_count' => true,
'echo' => 0,
'order' => 'DESC',
// post_type引数はcustom_post_type_getarchives_where()で参照される
# 'post_type' => 'common', // 投稿タイプの指定
'post_type' => array('common', 'post'), // 複数指定する場合
);
echo wp_get_archives($args);
WordPress 4.4からはどうなるか
WordPress4.4からはwp_get_archives()にpost_typeパラメータが追加になり、投稿タイプを指定できるようになったので、指定したい投稿タイプが一つだけなら、わざわざgetarchives_whereフィルタを書く必要はなくなった。ただし、複数指定したい場合は、相変わらずフィルタに頼ることになる。
ところで、WordPress4.4からはpost_typeパラメータがサポートされたことにより、wp_get_archives()内でpost_typeの値がチェックされるようになったため、上記の例で'post_type'に array('common', 'post')のように複数指定してwp_get_archives()を呼び出した場合、エラー終了してしまうようになった。複数投稿タイプ指定に対応するためgetarchives_whereフィルタを使うなら、フィルタに渡すためのパラメータの名称を'post_type'からなにか別の名称('filter_post_type'とか)に変えてやる必要がある。
wp_get_archives()の不満点
現状のwp_get_archives()には以下の不満がある。
- post_typeが一つしか指定できない。複数指定する場合は相変わらずgetarchives_whereフィルタをいじる必要がある。
- HTMLで返されるので、表示形式をカスタマイズした場合は、正規表現で変換していく必要がある。
ということで、wp_get_archives()の内部から必要な処理を抜き出して、自分にとって扱いやすい関数を作成した。
post_typeを引数で複数指定できるようにしたのが以下の関数。$post_type引数には対象としたい投稿タイプを指定する。複数指定したい場合は、配列で指定する。昇順/降順指定や件数指定はなし。リターン値も年、月、投稿数を格納したオブジェクトが返されるだけなので、出力形式は呼出し側で自由にできる。
月間アーカイブ用のデータを返す関数
function my_get_monthly_archives($post_type = 'post')
{
global $wpdb;
$post_types = is_array($post_type) ? $post_type : array($post_type);
$last_changed = wp_cache_get('last_changed', 'posts');
if (!$last_changed) {
$last_changed = microtime();
wp_cache_set('last_changed', $last_changed, 'posts');
}
$post_type_conds = array();
foreach ($post_types as $type) {
$post_type_conds[] = $wpdb->prepare("post_type = %s", $type);
}
$post_type_condition = '('.implode(' OR ', $post_type_conds).')';
$query = "SELECT YEAR(post_date) AS `year`, MONTH(post_date) AS `month`, count(ID) as posts FROM $wpdb->posts WHERE $post_type_condition AND post_status = 'publish' GROUP BY YEAR(post_date), MONTH(post_date) ORDER BY post_date DESC";
$key = md5($query);
$results = $wpdb->get_results($query);
$key = "my_get_monthly_archives:$key:$last_changed";
if (!$results = wp_cache_get($key, 'posts')) {
$results = $wpdb->get_results($query);
wp_cache_set($key, $results, 'posts');
}
return $results;
}
月間アーカイブのHTML生成
$archives = my_get_monthly_archives(array('common', 'post'));
foreach ($archives as $archive) {
printf('<li><a href="/news/?ym=%04d%02d">%04d年%02d月(%d)</a></li>',
$archive->year,
$archive->month,
$archive->year,
$archive->month,
$archive->posts);
}
