フリーランス|WEB 制作経験丸7年、制作会社様からのご依頼に丁寧・高クオリティでお手伝いいたします。 IRODORI DESIGN

B L O G

【WordPress】2ページ目以降の記事一覧の該当記事へリンク

array_search
PHP
WordPress

こんにちは、岐阜・名古屋を拠点に全国各地からご依頼いただくWEBサイトを制作しているフリーランスエンジニアの寺井です。

WordPressの投稿ページは大きく分けると「一覧ページ」「詳細ページ」の2ページから構成されます。そのためトップページのバナーなどから特定の記事へリンクさせる場合、この「詳細ページ」へリンクすれば問題ありません。

しかし中には構成や予算の都合上、詳細ページを省略して一覧ページのみ実装という仕様のサイトも存在します。その場合、それなりに更新頻度の多いサイトや古い記事の場合、1ページ目ではなく2ページ目や3ページ目などに追いやられてしまってしまうことがあります。
そんな時、2ページ目や3ページ目になるたびにリンク先を変更するのはかなり手間がかかりますよね。

この記事では一覧ページで2ページ目以降の記事へのリンク方法を解説します。

2ページ目以降の記事一覧の該当記事へリンク設定するサンプルソース

// functions.php
<?php
function my_pre_get_posts( $query ){
	if( is_admin() || ! $query->is_main_query() ){
		return;
	}
	if( $query->is_front_page() || $query->is_home() ){
		$query->set('posts_per_page',-1);
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );
?>
// front-page.php
<?php
	$cnt = 1;
	$post_id_list = array();
	if( have_posts() ):
	    while( have_posts() ):
	        the_post();
	        $post_id_list[++$cnt] = get_the_ID();
?>
<?php
		endwhile;
	endif;
	wp_reset_postdata();
?>
<?php
	$target = 14;	// 投稿記事のIDを指定
	$search_post = array_search( $target,$post_id_list );
	$target_page_no = ceil( $search_post / get_option('posts_per_page') );
	$url = home_url( 'news/page/') . $target_page_no . "#news" . $target;
?>
// archive.php
<?php
	if( have_posts() ):
		while( have_posts() ):
			the_post();
?>
	<div class="news__list" id="#news<?php the_ID(); ?>"><?php echo the_title(); ?></div>
<?php
		endwhile;
	endif;
	wp_reset_postdata();
?>

今回のサンプルソースは以下の条件を想定したものです。

  • 記事IDは14番
  • バナーを設置するのはトップページ、テンプレートファイルはfront-page.php
  • 投稿タイプはpost(デフォルト投稿)
  • 一覧ページはarchive.php

サンプルソースの解説

functions.phpの解説

該当記事が何番目の記事なのかを把握するために一度記事を全件ループする必要があります。そのためfunctions.phpに以下のようなアクションフックを記述をします。

<?php
function my_pre_get_posts( $query ){
	if( is_admin() || ! $query->is_main_query() ){
		return;
	}
	if( $query->is_front_page() || $query->is_home() ){
		$query->set('posts_per_page',-1);
	}
}
add_action( 'pre_get_posts', 'my_pre_get_posts' );
?>

今回はトップページという想定なのでpre_get_postsの内部での分岐指定は

if( $query->is_front_page() || $query->is_home() ){
	$query->set('posts_per_page',-1);
}

ということになります。その他、固定ページや一覧ページなどの分岐方法は以下の記事で解説しています。

全件出力するための指定方法は「-1」になります。

この際、記事が何百件や何千件もあるとこのループ処理に時間がかかったり、処理落ちしてしまう可能性もあります。なのでそのような膨大な記事数のサイトではお勧めできない方法です。そのような規模のサイトであれば一覧・詳細という最もオーソドックスなページ構成になっていると思うのでこの記事のようなプログラムは導入されないかなと思いますね。

front-page.php(トップページ)の解説

ここからテンプレートファイルのソース解説をしたいと思います。今回のサンプルソースはトップページを想定してるのでfront-page.phpとなっています。

<?php
	$cnt = 1;
	$post_id_list = array();
	if( have_posts() ):
	    while( have_posts() ):
	        the_post();
	        $post_id_list[++$cnt] = get_the_ID();
?>

まずはメインループを使い、全件の投稿IDを配列に格納していきます。配列の中身を出力すると以下のようにキーは連番、値には投稿IDが格納された状態になります。この格納されている順番は特に指定していない場合、日付順:dateになっています。サンプルソースでは「orderby」を指定していないので日付順に格納されていることになります。

【配列の中身画像】

$target = 14;	// 投稿記事のIDを指定

該当記事の投稿IDを指定します。今回の解説では投稿ID:14を想定しています。

先ほど全件IDを格納した配列から今指定した$target番号が何番目なのかを取得する必要があります。配列から指定した値が何番目に格納されているか調べるPHP関数はarray_searchです。

array_search関数の基本構文は以下です。

array_search(検索する値, 検索対象の配列, 型の比較を行うか)
第一引数検索したい値
第二引数検索対象する配列
第三引数trueを指定すると型の比較も出来ます。
第三引数は省略可能です。
返り値該当ありの場合、インデックスキー(要素番号)
該当なしの場合、false
$search_post = array_search( $target,$post_id_list );

上の記述のように指定をすると該当する投稿IDがあった場合、変数$search_postに格納されます。ここでは例えばで12番目格納されているとしましょう。そうすると$search_postには「12」が格納されます。

この該当記事が12番目に出力される記事ということが分かりましが、この12番目がページ送りされた一覧の1ページ目なのか2ページ目なのか、はたまた5ページ目なのか割り出す必要があります。

何記事ごとにページ分割されるのかを取得するWordPressの記述は以下です。

get_option('posts_per_page')

この値は管理画面の「設定」>「表示設定」>「1ページに表示する最大投稿数」の値です。

クエリでposts_per_pageを指定していない場合、この値の数でページが分割されます。ここでは「10」で分割されると想定します。

該当記事が何ページ目かを割り出す計算式は以下の通りです。

$target_page_no = ceil( $search_post / get_option('posts_per_page') );

ceilは小数点を切り上げるPHP関数です。「該当記事÷1ページに表示される件数」の計算式で該当記事が何ページ目なのか割り出すことが可能です。小数点を切り上げる理由は例えば計算結果が1.1の場合、該当記事は2ページ目になるため四捨五入をしたり切り捨てをしてしまうと1ページ目と判定されてしまいます。しかし該当記事は2ページ目にあるので見当たりません。

今回の記事の例だと該当記事は12番目にあり、1ページに表示する件数は10件、

12÷10=1.2となり、小数点を切り上げて2となります。つまり2ページ目に該当記事は存在するということになります。

$url = home_url( 'news/page/') . $target_page_no . "#news" . $target;

上記のように該当する記事があるページのURLを変数に格納します。”#news” . $targetで一覧ページで該当記事にidを指定することでページ内の特定箇所へすることが出来ます。

archive.phpの解説

最後に一覧ページの解説です。

<?php
	if( have_posts() ):
		while( have_posts() ):
			the_post();
?>
	<div class="news__list" id="#news<?php the_ID(); ?>"><?php echo the_title(); ?></div>
<?php
		endwhile;
	endif;
	wp_reset_postdata();
?>

メインループの中で記事一覧を出力する際、それぞれの記事ごとのタグにid="news<?php the_ID(); ?>"を指定してあげます。これでリンク元とリンク先でidが一致するのでページ内の特定箇所を表示することが出来ます。

このようにすることで○ページ目の一覧ページの記事へリンク設定をすることが可能です。かなりイレギュラーな処理ですが、もしかしたらWordPressを構築していてこのような場面に遭遇した場合、参考にしていただけると嬉しいです。