WordPress には、先頭に固定表示の機能もありますが、1ページ目の最初にモリッと差し込まれるので、表示件数が変わってしまったり、ページ送りにも対応できません。
これを、カスタム分類を用いて、
- 該当分類に属するものを、home 表示の際に優先表示
- 1ページの表示投稿数は、設定通りにする
- 先頭固定表示の記事のあとは、それ以外の記事を最新順に
- ページ送り・ページナビに影響がでないこと
を満たすものを作ってみました。
具体的には、news というカスタム分類で、sticky という分類に属する投稿を先頭表示されるようにしています。
また、些細な工夫として、複数箇所から呼ばれる get_custom_sticky_posts で、wp_cache_set と wp_cache_get を使っています。これを使うと、実行結果がメモリ上にキャッシュされるため、複数回呼ばれるような場面においても、パフォーマンスロスを防ぐことができるようになります。
/*
* 通常表示されるべき投稿を先頭固定の投稿で差し替える
*/
function insert_custom_sticky_posts( $posts, $wp_query ) {
if ( ! is_admin() && $wp_query->is_home() ) {
$stickies = get_custom_sticky_posts();
if ( $stickies ) {
$posts_per_page = $wp_query->get( 'posts_per_page' );
$paged = $wp_query->get( 'paged' ) ? $wp_query->get( 'paged' ) : 1;
if ( count( $stickies ) >= $posts_per_page * $paged ) { // 全て差し替え
$posts = array_slice( $stickies, $posts_per_page * ( $paged - 1 ), $posts_per_page );
} elseif ( count( $stickies ) > $posts_per_page * ( $paged - 1 ) ) {
$insert_sickies = array_slice( $stickies, $posts_per_page * ( $paged - 1 ), $posts_per_page );
$posts = array_merge( $insert_sickies, $posts );
$posts = array_slice( $posts, 0, $posts_per_page );
}
}
}
return $posts;
}
add_filter( 'the_posts', 'insert_custom_sticky_posts', 10, 2 );
/*
* 全投稿数に先頭固定の投稿数を足す
*/
function add_custom_sticky_posts_count( $found_posts, $wp_query ) {
if ( ! is_admin() && $wp_query->is_home() && ! $wp_query->get( 'suppress_filters' ) ) {
$found_posts = $found_posts + count( get_custom_sticky_posts() );
}
return $found_posts;
}
add_filter( 'found_posts', 'add_custom_sticky_posts_count', 10, 2 );
/*
* SQL文のLIMIT 句を改変し、先頭固定の投稿数文を差し引いた開始位置にする
*/
function replace_custom_sticky_posts_limit_sql( $limits, $wp_query ) {
if ( ! is_admin() && $wp_query->is_home() ) {
$stickies = get_custom_sticky_posts();
if ( $stickies ) {
$posts_per_page = $wp_query->get( 'posts_per_page' );
$paged = $wp_query->get( 'paged' ) ? $wp_query->get( 'paged' ) : 1;
$start = $posts_per_page * ( $paged - 1 ) - count( $stickies );
if ( $start < 0 ) {
$start = 0;
}
$limits = "LIMIT $start, $posts_per_page";
}
}
return $limits;
}
add_filter( 'post_limits', 'replace_custom_sticky_posts_limit_sql', 10, 2 );
/*
* 通常表示の記事から、先頭固定表示する投稿を除外する
*/
function ignore_custom_stickies( $wp_query ) {
if ( ! is_admin() && $wp_query->is_home() && ! $wp_query->get( 'suppress_filters' ) ) {
$wp_query->set(
'tax_query',
array(
'relation' => 'AND',
array(
'taxonomy' => 'news',
'terms' => array( 'sticky' ),
'field' => 'slug',
'operator' => 'NOT IN',
),
)
);
}
}
add_action( 'pre_get_posts' , 'ignore_custom_stickies' );
/*
* 先頭固定表示する投稿を全て取得する
*/
function get_custom_sticky_posts() {
$cache_key = 'custom-sticky-posts';
$stickies = wp_cache_get( $cache_key );
if ( $stickies === false ) {
$stickies = get_posts(
array(
'posts_per_page' => -1,
'tax_query' => array(
'relation' => 'AND',
array(
'taxonomy' => 'news',
'terms' => array( 'sticky' ),
'field' => 'slug',
'operator' => 'IN',
),
)
)
);
wp_cache_set( $cache_key, $stickies );
}
return $stickies;
}
■ 更新
2013.03.22 suppress_filters による条件分岐を追加しました。