SOFTELメモ

Softel Inc.

【WordPress】get_posts(‘category=-3’)がおかしい(MySQLが古い環境で)

問題

「このカテゴリ以外」の一覧を表示したくてget_posts(array('category' => -3))をしたんだけど、順番も取得できている記事も正しくない。

どうなってるのかな?

wordpress答え

そのとき、WordPressはこんなSQLを実行している。

SELECT   wp_posts.ID FROM wp_posts  WHERE 1=1  AND ( wp_posts.ID NOT IN (
					SELECT object_id
					FROM wp_term_relationships
					WHERE term_taxonomy_id IN (3)
				) ) AND wp_posts.post_type = 'post' AND (wp_posts.post_status = 'publish') GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC LIMIT 0, 10;

この辺が怪しい。

GROUP BY wp_posts.ID ORDER BY wp_posts.post_date DESC

MySQLなら文句を言わずに実行するのだろうけど、GROUP BY しているのだから、本来は何らかの集計関数を入れて、例えばこうするべきところ?

GROUP BY wp_posts.ID ORDER BY max(wp_posts.post_date) DESC

MySQL5.0で発生したが、MySQL5.1、5.5では発生しなかったので、あまり古くない環境の人は困っていないのかもしれない。

で、MySQL5.0の人はどうしたらよいのか。

ピンポイントで問題のSQLだけ書き換えてしまおう

今回おかしいのは ORDER BY 句。

posts取得のSQLのORDER BY句の書き換えは posts_orderby というフィルターでできる。add_filter('posts_orderby', '関数名')である。

一時的にフィルターをかけるとこんな感じ。

//どこかで定義しておいて
function hoge($orderby)
{
    return 'max(wp_posts.post_date) DESC';
}

//フィルターを追加
add_filter('posts_orderby', 'hoge', 1000);
//投稿を取得
$posts = get_posts(array('category' => -3, 'suppress_filters' => false));
//フィルターを削除
remove_filter('posts_orderby', 'hoge', 1000);
//以降通常通り
foreach ($posts as $post) {
    //記事一覧のループなど
}

get_posts()で各種フィルターが効かない!という場合は、あわてず suppress_filters を false にすること。デフォルトはtrueとなっており、フィルターが効かない。

関連するメモ

コメント