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 による条件分岐を追加しました。