このブログでは、月ごとアーカイブをコンパクトに表示してくれるプラグイン monthchunks を使用していますが、記事がないのに表示されている月があることが判明しました。
問題の月は、2006年の9月。Google ウェブマスターツールのリンクエラー報告によると、76箇所で表示されているとのこと。さすがに数が多いので、本腰を入れて調べてみることにしました。久しぶりのプラグインハックです。
何はともあれ、まずはプラグインのコードを読みます。使用しているバージョンは、最新の2.1。関数が1つ定義してあるだけでコメントを含めても154行と非常に短いので、初めてのハックにはお勧めかもしれません。
大まかな流れは、SQL 文を生成して実行するだけ。オプションによって多少分岐がありますが、上から追いかけていけば大したことはありません。101行目からと114行目(110行目から始まる foreach
の中)からの2箇所でデータベースにアクセスしています。1箇所目は記事のある年度の取得、2箇所目は各年度別に記事のある月の取得をしています。
// get an array of the years in which there are posts
$wpdb->query("SELECT DATE_FORMAT(post_date, '%Y') as post_year
FROM $wpdb->posts
WHERE post_status = 'publish'
GROUP BY post_year
HAVING post_year <> '0000'
ORDER BY post_year $year_order");
$years = $wpdb->get_col();
// get an array of months for the current year without leading zero
// sort by month with leading zero
$months = $wpdb->get_results("SELECT DATE_FORMAT(post_date, '%c') as post_month,
$month_format AS display_month,
DATE_FORMAT(post_date, '%M') as post_month_name
FROM $wpdb->posts
WHERE DATE_FORMAT(post_date, '%Y') = $year
AND post_status = 'publish'
GROUP BY DATE_FORMAT(post_date, '%m')
ORDER BY post_date");
今回問題になっているのは月の情報なので、2箇所目を詳しく見ていきます。PHP のコードと SQL が混在してわかりにくいので、最終的な SQL 文を記述してみます。オプションを特に指定しない場合は、次のようなものが出来上がります。(改行やインデントなどを加えてあります)
SELECT
DATE_FORMAT(`post_date`, '%c') AS `post_month`,
DATE_FORMAT(`post_date`, '%c') AS `display_month`,
DATE_FORMAT(`post_date`, '%M') AS `post_month_name`
FROM `wp_posts`
WHERE
DATE_FORMAT(`post_date`, '%Y') = 2006
AND post_status = 'publish'
GROUP BY DATE_FORMAT(`post_date`, '%m')
ORDER BY `post_date`;
実際にこの SQL 文を手がかりに検索してみると、記事ではなく固定ページが見つかりました。記事と固定ページを区別していないため、固定ページしかない月も表示してしまっていたのです。
ここまでわかればあとは簡単。検索条件に記事であることを加えればいいのです。記事の場合は post_type
というフィールドの値が post
となるので(WordPress 2.1以降)、post_type = 'post'
を加えます。変更後は次のようになります。私は120行目に加えました。
// get an array of months for the current year without leading zero
// sort by month with leading zero
$months = $wpdb->get_results("SELECT DATE_FORMAT(post_date, '%c') as post_month,
$month_format AS display_month,
DATE_FORMAT(post_date, '%M') as post_month_name
FROM $wpdb->posts
WHERE DATE_FORMAT(post_date, '%Y') = $year
AND post_status = 'publish'
AND post_type = 'post'
GROUP BY DATE_FORMAT(post_date, '%m')
ORDER BY post_date");
これにより、その年の公開されている記事という条件で絞り込むことができるようになりました。現在2006年の9月は表示されなくなっています。
2010年6月21日追記
prioさんからコメントをいただきましたので、年度の表示についても追記します。確認はしていませんので、参考程度にどうぞ。
100行目からの年度のコードを見ると、月の取得同様に固定ページも含むようになっています。SQLにしてみるとこんな感じ。
SELECT
DATE_FORMAT(post_date, '%Y') as post_year
FROM `wp_posts`
WHERE
post_status = 'publish'
GROUP BY post_year
HAVING post_year <> '0000'
ORDER BY post_year DESC
記事の投稿に限定する条件を加えると次のようになります。
// get an array of the years in which there are posts
$wpdb->query("SELECT DATE_FORMAT(post_date, '%Y') as post_year
FROM $wpdb->posts
WHERE post_status = 'publish'
AND post_type = 'post'
GROUP BY post_year
HAVING post_year <> '0000'
ORDER BY post_year $year_order");
$years = $wpdb->get_col();
104行目が追加した行です。意味については、月の場合と同じです。