WordPress には、先頭に固定表示の機能もありますが、1ページ目の最初にモリッと差し込まれるので、表示件数が変わってしまったり、ページ送りにも対応できません。
これを、カスタム分類を用いて、
- 該当分類に属するものを、home 表示の際に優先表示
- 1ページの表示投稿数は、設定通りにする
- 先頭固定表示の記事のあとは、それ以外の記事を最新順に
- ページ送り・ページナビに影響がでないこと
を満たすものを作ってみました。
具体的には、news というカスタム分類で、sticky という分類に属する投稿を先頭表示されるようにしています。
また、些細な工夫として、複数箇所から呼ばれる get_custom_sticky_posts で、wp_cache_set と wp_cache_get を使っています。これを使うと、実行結果がメモリ上にキャッシュされるため、複数回呼ばれるような場面においても、パフォーマンスロスを防ぐことができるようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 | /* * 通常表示されるべき投稿を先頭固定の投稿で差し替える */ 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 による条件分岐を追加しました。