ページ送りを設置する
目次
1. ページ送りを設置する
今回はページ送りの設置方法について紹介します。ページ送りには、大別して3つの種類があります。
- コメントのページ送り
- 記事一覧のページ送り
- 個別記事のページ送り
#1 コメントのページ送り
コメントが複数ページに渡る場合に、ページを遡って全てのコメントを閲覧できるように、前後のコメントのページへのリンクを表示できるようにします。これについては、以前書いた記事「コメントフォームを設置する」および「コメントフォームをカスタマイズする」を参照してください。
#2 記事一覧のページ送り
カテゴリページを表示したとき、「そのカテゴリの記事数>1ページに表示する記事数」となる場合は、そのカテゴリに属する記事リストを複数ページに分けて表示し、ページ送りを設置して行き来できるようにします。
同様のケースとして、各種アーカイブページ(タグページやカスタム投稿アーカイブページなど)、検索結果ページ、フロントページ(最新の投稿を指定した場合)などがあります。
今回は検索結果ページを例としてとりあげ、次のようなリンクを設置してみます。
#3 個別記事のページ送り
投稿ページを表示したときに、その前後に投稿した投稿ページを辿れるページ送りを設置します。
今回の作成するテーマでは、前後の記事タイトルを表示するようにします。
なお、固定ページ、カスタム投稿ページについても同様のページ送りを設置できます。
query_postsでクエリを変更すると、ページ送りは一筋縄ではいかない
前々回の記事「記事の表示順、表示数を変更する」において、フロントページに表示するの記事リストをquery_posts関数を使ってカスタマイズしました。このようにquery_postsでクエリを変更した場合は、#2の方法だけでは正しくページ送りが機能しません。(ちょっとマニアックで需要があるかわかりませんが)query_postsでクエリをいじった場合にもページ送りを正しく動作させる方法について紹介します。
2. テーマをカスタマイズする
次の順にページ送りを設置していきます。
- 個別投稿ページ(#3)
- 検索結果ページ(#2)
- フロントページ(#2の派生)
なお今回のテーマでは、タイプ#2と#3のページ送りのコードをそれぞれ別のファイルに分けて書く事にします。
index.phpの中でページの種類を判別して、pagination-posts.php、またはpagination-post.phpのどちらかを読み込むようにします。
index.php
<?php get_header(); ?> <div id="content"> <div id="breadcrumb"> <?php get_template_part('breadcrumb'); ?> </div> <?php if ( is_home() ) { query_posts( array('posts_per_page' => 3, 'post_type' => array('websites', 'post'), 'orderby' => 'modified', 'order' => 'DESC')); } while ( have_posts() ) { the_post(); global $post; get_template_part('content'); if( is_singular('post') ) { comments_template(); } } if( is_singular() ) { get_template_part('pagination','post'); } else { get_template_part('pagination','posts'); } ?> </div> <?php get_sidebar(); get_footer();
今回挿入したコードは、次の5行のみです。
if( is_singular() ) { get_template_part('pagination','post'); } else { get_template_part('pagination','posts'); }
個別投稿ページ(投稿、固定ページ、カスタム投稿ページ)を表示する場合は、is_singular()がTRUEとなるので、pagination-post.phpを読み込みます。その他のページを表示する場合は、pagination-posts.phpを読み込みます。
お詫び:今回作成する2ファイルの違いは末尾のsの有無だけです。ファイル命名のセンスが無くてごめんなさい。
2-1. 個別投稿ページにページ送りを設置する
個別投稿ページ用のページ送りテンプレートパーツpagination-post.phpを新規作成して、次のようなコードを書きます。
pagination-post.php
<ul id="pagination" class="post"> <?php // postが無い場合は文字列""が返ってくる $prev_post = get_previous_post(); $next_post = get_next_post(); if ( !empty( $prev_post ) ): ?> <li class="prev"><?php previous_post_link('「%link」前の記事→'); ?></li> <?php endif; if( !empty( $next_post ) ): ?> <li class="next"><?php next_post_link('←次の記事「%link」'); ?></li> <?php endif; ?> </ul>
「前の記事」へのリンクを生成するコードの説明をします。
$prev_post = get_previous_post();
get_previous_postは、1つ前の投稿のオブジェクトを得るWordPress関数です。1つ前の投稿が無い場合は空文字列が返ってきます。そして、
if ( !empty( $prev_post ) ):
によって、$prev_postが空文字列ではない、すなわち1つ前の投稿が存在する場合のみ括弧内{}の処理が実行されます。
補足:エクスクラメーションマーク『!』は否定です。
<?php previous_post_link('「%link」前の記事→'); ?>
previous_post_linkは、1つ前の投稿のリンクHTMLを出力するWordPress関数です。引数で出力形式を指定できます。%linkの部分が、その記事のタイトル&リンクに置換されます。
なお、次の記事へのリンクも、前の記事へのリンクと同様です。
個別投稿ページを表示して、動作を確認してみます。次のようなコードが出力されていればOKです。
ページのソース(該当部分のみ抜粋)
<ul id="pagination class="post"> <li>「<a href="http://..." rel="prev">2件目の投稿</a>」前の記事→</li> <li>←次の記事「<a href="http://..." rel="next">4件目の投稿</a>」</li> </ul>
なお、これらのカスタマイズを行えば、固定ページやカスタム投稿ページを表示したときも同様のページ送りが表示されるはずです。
補足:例えばページ送りを「投稿」だけに出力したいなど、ページ送りを設置するページの種類を限定したい場合は、index.phpの条件文で調整できます。
2-2. 検索結果ページにページ送りを設置する
サイト内検索結果が複数ページに渡る場合に、ページ送りを表示して、ページを行き来できるようにします。ここでは独自にテンプレートパーツpagination-posts.phpを作成します。
pagination-posts.php
<?php // リンクが無い場合はNULLが返ってくる $prev_link = get_previous_posts_link('前のページ'); $next_link = get_next_posts_link('次のページ'); if ( isset( $prev_link ) or isset( $next_link ) ) { echo '<ul id="pagination">', PHP_EOL; if( isset( $prev_link ) ) { echo '<li>',$prev_link,'</li>', PHP_EOL; } if( isset( $next_link ) ) { echo '<li>',$next_link,'</li>', PHP_EOL; } echo '</ul>', PHP_EOL; } ?>
コードの説明をします。
$prev_link = get_previous_posts_link('前のページ'); $next_link = get_next_posts_link('次のページ');
get_previous_posts_linkとget_next_posts_linkで、前後のページへのリンクをゲットして変数に保存します。
if ( isset( $prev_link ) or isset( $next_link ) ) { echo '<ul id="pagination">', PHP_EOL;.... echo '</ul>', PHP_EOL; }
2変数のうち、少なくとも片方がNULLでない場合のみ、リスト構造を出力します。
if( isset( $prev_link ) ) { echo '<li>',$prev_link,'</li>', PHP_EOL; }
前のページが存在するとき、つまり$prev_linkがNULLでない場合は、ページ送りを出力します。$next_linkについても同様です。
これらの編集を終えると、検索結果ページだけでなく各アーカイブページにもページ送りが出力され、正しく機能します。ところが、このテーマのフロントページでは正しく機能しません。
2-3. フロントページにページ送りを設置する
先に書きましたが、このテーマのフロントページはquery_postsを利用しているため、このままではページ送りが正しく機能しません。なぜなら、WordPressのページ送り機能はquery_postsで変更する前のクエリに基づいて動作するからです。例えば20件の記事リストを表示しようとしたとき、仮にダッシュボードにおいて1ページの最大表示件数を10に設定しているとすると、全ページ数は20/10=2ページとなります。これに対してquery_postsで1ページの表示件数を3に変更した場合は、全ページ数は7になって欲しいところです。ところが、ページ送り機能はquery_postsによるクエリ変更前に基づいて動作するため、2ページ目までしか動作しません。
query_postsでクエリを変更した場合もページ送りに対応させるためには、index.phpとfunctions.phpに次のようなコードを挿入します。
index.php(変更箇所のみ抜粋)
... if ( is_home() ) { $paged = (get_query_var('paged')) ? get_query_var('paged') : 1; $args = array('paged'=>$paged,'posts_per_page' => 3, 'post_type' => array('websites', 'post'), 'orderby' => 'modified', 'order' => 'DESC'); query_posts( $args ); } ...
$paged = (get_query_var('paged')) ? get_query_var('paged') : 1;
get_query_varは、引数で指定したクエリの値を得るWordPress関数です。’paged’を指定した場合は、ページ数(1ページ目なら1、2ページ目なら2、…)が出力されます。ただし、表示する記事数が1ページの最大表示件数を超えない場合は0が出力されます。この式全体は3項演算子になっており、get_query_varの出力が0の場合は、$pagedに1を代入します。
$args = array('paged'=>$paged,...
この値$pagedは、query_postsのオプション’paged’として指定します。
このような処理を追加する理由ですが、WordPress CodexのPaginationに関する記事によれば、query_postsでメインループのクエリをいじった場合は、ページ数を示すパラメータpagedに値がセットされないからだそうです。
さらに、次のようなコードをfunctions.phpに追記します。
functions.php(追記)
function include_custom_posts($query) { if ( $query->is_home() && $query->is_main_query() ) { $query->set('post_type', array('post','websites')); $query->set('posts_per_page', 3); } } add_action('pre_get_posts', 'include_custom_posts');
ここでは最新の投稿をフロントページに設定&表示した場合のみ、pre_get_postsフィルターを使ってメインループのクエリを変更するようにしています。ここで指定しなければならないオプションは、query_postsで変更したオプションのうち、ページ数に関与するオプション(全投稿件数と1ページあたりの最大表示数に関与するオプション)です。このテーマでは、post_typeとpost_per_pageが該当します。ページネーションが動作する前に、pre_get_postsフィルターでこれらの値をquery_postsで指定した値に揃えておくことで、正しく動作させることができます。
補足:
しかし・・・、ここでメインクエリを書き換えるのであれば、query_postsを使わずにfunctions.php内でクエリの条件を書き換えちゃえばいいのではないかと思います。2ファイルで値を合わせるとか冗長だし、メンテナンス性も良くないし。実際、Codexには、query_postsを使用するのではなく、pre_get_postsフィルターを使用することを強く推奨します、とあります。
2-4. スタイルを指定する
お好みに合わせて、スタイルを指定します。
style.css(追記)
ul#pagination { list-style-type: none; overflow: hidden; padding: 0 10px; margin: 15px 0; } ul#pagination.posts li { } ul#pagination.posts li a { display: block; padding: 3px 5px; border: 1px solid #aaa; border-radius: 3px; background-color: #556b2f; color: #fff; } ul#pagination.posts li a:hover { background-color: #99C348; } ul#pagination.post li.next, ul#pagination.posts li.prev { float: left; } ul#pagination.post li.prev, ul#pagination.posts li.next { float: right; }
以上で、今回のカスタマイズは終了です。
関連記事
WordPress Codex
「index.phpをカスタマイズする」の記事
- 第20回 ギャラリー表示をカスタマイズする
- 第19回 ページ送りを設置する << この記事です
- 第18回 カテゴリやタグを表示する
- 第17回 記事の表示順、表示数を変更する – 補足
- 第16回 記事の表示順、表示数を変更する
- 第15回 アイキャッチ画像を表示する
- 第14回 抜粋を表示する
- 第13回 パンくずリストを設置する
- 第12回 ページの種類で分岐処理する
- 第11回 カスタム投稿タイプを作成する
- 第10回 カスタム背景を設置する
- 第9回 カスタムヘッダーを設置する
- 第8回 カスタムメニューを設置する
- 第7回 コメントフォームをカスタマイズする
- 第6回 コメントフォームを設置する
- 第5回 サイドバーを設置する
- 第4回 functions.phpとは
- 第3回 テンプレートフォルダ内の画像を使用する
- 第2回 テンプレートパーツ化する
- 第1回 HTMLからWPテーマを作成する