動作
2018 年 4 月に、Google がモバイル検索結果で無限スクロールを導入しました。
Google がモバイル検索結果で導入した無限スクロールは、「もっと見る」ボタンのタップで、ページを移動せず検索結果の続きが表示されます。
この Google 検索に似た無限スクロールを WordPress に実装する方法をご紹介します。
まずは、実際の動作をご覧ください。Google 検索と同じように、「もっと見る」ボタンのクリック・タップで次のページが読み込まれます。
Infinite Scroll を使用
無限スクロールを導入する際は、下記の 2 つを考慮しないといけません。
- クローラーに配慮する
- ユーザーの使い勝手に配慮する
クローラーは無限スクロールが苦手です。そのため、検索エンジンとの相性を考慮した無限スクロールのベストプラクティスに沿う必要があります。
また、自動的に無限スクロールが始まると、サイトの使い勝手が悪くなる恐れがあります。「フッターを見たいのに、見られない!」と私は何度も思ったことがあります。
この 2 つともしっかりと考慮できるのが、JavaScript ライブラリの Infinite Scroll です。設置方法が簡単な魅力もあるため、今回は Infinite Scroll を使用します。
尚、今回は紹介しませんが、Infinite Scroll であれば「もっと見る」ボタンをクリック・タップしない自動的な無限スクロールにも対応できます。
Infinite Scroll の読み込み
最初にすることは、Infinite Scroll の設置と読み込みです。
使用中のテーマフォルダの直下に、infinite-scroll.js ファイルを作成します。
作成した infinite-scroll.js ファイルに、infinite-scroll.pkgd.min.js をそのまま全てコピペをします。
あとは作成した infinite-scroll.js をサイトで読み込みます。下記のコードを使い、</body> タグ直前で読み込みます(<head> タグ内でも可)。
<script src="<?php echo get_stylesheet_directory_uri(); ?>/infinite-scroll.js"></script>
上記のコードは、子テーマの使用を想定しています。
「もっと見る」ボタンを作成
次にすることは、無限スクロールを開始する「もっと見る」ボタンの作成です。
テーマフォルダの直下に、infinite-scroll.php ファイルを作成します。作成した infinite-scroll.php ファイルに、下記のコードを追加します。
<?php
// 現在のページ数
global $paged;
if ( empty( $paged ) ) $paged = 1;
// 総ページ数
global $wp_query;
$pages = $wp_query -> max_num_pages;
if ( ! $pages ) {
$pages = 1;
}
// ページが1ページしかない場合は出力しない・最後のページでも出力しない
if ( $pages != 1 && $paged < $pages ) {
echo '
<button id="more-button" type="button">もっと見る</button>
<div class="scroller-status">
<div class="infinite-scroll-request"></div>
<p class="infinite-scroll-last">これ以上は記事がありません</p>
<p class="infinite-scroll-error">読み込むページがありません</p>
</div>
';
}
ページが 1 ページしかない場合は、ボタンは表示しないようにしています。また、最後のページでもボタンは表示されません。読み込むページがない時は、ボタンは不要です。
18 行目から 22 行目は、Infinite Scroll のオプションの status を使うためのもの。status の使用により、最後の記事の下に「これ以上は記事がありません」と表示されます。
読み込むページがない場合は、「読み込むページがありません」と表示されます。
テンプレートにボタンを設置
作成した infinite-scroll.php ファイルを、記事一覧を呼び出しているテンプレートのお好きな場所に設置します。
設置するためのコードは、下記のとおりです。
<?php get_template_part( 'infinite-scroll' ); ?>
テーマによって、記事一覧を呼び出しているテンプレートは違います。Simplicity であれば list.php 。Cocoon であれば tmp/list.php です。
最適なボタンの設置場所はサイトによって異なりますが、おすすめはページネーションの上。記事一覧の下に広告を設置している場合は、特におすすめです。「もっと見る」ボタンの上に、広告が常に表示されるのは大きいはず。
JavaScript で設定
次は Infinite Scroll の設定です。下記の JavaScript を追加します。コードを追加するファイルは、テーマが用意している JavaScript 用のファイル、または最初に作成した infinite-scroll.js ファイルのどちらでも構いません。
var infScroll = new InfiniteScroll('#list', {
append: '.entry',
path: '.next a',
hideNav: '.pagination',
button: '#more-button',
scrollThreshold: false,
status: '.scroller-status',
history: 'push',
});
1 行ずつ解説します。
まず 1 行目の #list
は、記事一覧を囲む要素を指定します。例えば、記事一覧の HTML が下記のものだとします。
<div id="list">
<article class="entry"></article>
<article class="entry"></article>
<article class="entry"></article>
...
</div>
各記事の <article>
を <div id="list"></div>
が囲んでいます。この囲んでいる要素の id または class を指定します。
2 行目の .entry
は、各記事(上記の HTML では <article> )の class を指定します。この append に指定した要素が、無限スクロールで読み込まれたページに追加されていきます。
3 行目の .next a
は、次のページへの URL を指定します。URL は、ページネーションから拾います。例えば、ページネーションの HTML が下記のものだとします。
<ul class="pagination">
<li><a href="最初のページのURL"></a></li>
<li><a href="現在のページの前のURL"></a></li>
<li>現在のページ数</li>
<li><a href="現在のページの次のURL"></a></li>
<li><a href="現在のページの次の次のURL"></a></li>
...
<li class="next"><a href="次のページのURL"></a></li> ← この a タグを指定します
<li><a href="最後のページのURL"></a></li>
</ul>
.next a
(8 行目)が、次のページの URL です。たいてい「次へ」とか「 > 」で表示されています。この <a> タグの id または class を指定します。
それ以外の部分は、変更する必要はありません。
Infinite Scroll の詳細な設定は、Options にて公式の説明をご覧いただけます。
Safari のバグへの対策
コメントにて、iOS(Safari)でバグがあることを教えていただきました。
各記事に画像があり、その画像に srcset 属性があると、無限スクロールで読み込まれたページで画像が表示されないというものです。
GitHub の Safari not displaying loaded srcset images にて、開発者さんが問題の原因と解決方法をお書きになっています。
Infinite Scroll の設定の JavaScript の後に、下記のどちらかの JavaScript を追加すれば、この問題を解決できます。
jQuery を追加する
2 行目の #list
には、記事一覧を囲む要素を指定します。
jQuery(function($) {
$('#list').on('append.infiniteScroll', function(event, response, path, items) {
$(items).find('img[srcset]').each(function(i, img) {
img.outerHTML = img.outerHTML;
});
});
});
Vanilla JS(素の JavaScript)を追加する
1 行目の .entry
には、各記事の class を指定します。ただし、こちらのコードは実際に検証していません。
var infiniteItem = document.querySelectorAll('.entry');
infScroll.on('append', function(response, path, items) {
for (var i=0; i < items.length; i++) {
reloadSrcsetImgs(infiniteItem[i]);
}
});
function reloadSrcsetImgs(infiniteItem) {
var imgs = infiniteItem.querySelectorAll('img[srcset]');
for (var i=0; i < imgs.length; i++) {
var img = imgs[i];
img.outerHTML = img.outerHTML;
}
}
CSS で装飾
あとは「もっと見る」ボタンなどの CSS を指定すれば終わりです。
CSS の一例は下記のとおり。サイトによって、CSS はだいぶ違うはずです。
#more-button {
background: #eee;
height: 56px;
margin: 40px 0 0;
width: 100%;
}
.scroller-status {
display: none;
margin-top: 40px;
}
.infinite-scroll-request {
animation: scroll-request 1.1s infinite linear;
border: 4px solid #00b8d4;
border-left: 4px solid #fff;
border-radius: 50%;
height: 48px;
margin: auto;
width: 48px;
}
@keyframes scroll-request {
0% {
transform: rotate(0deg);
}
100% {
transform: rotate(360deg);
}
}
.infinite-scroll-last,
.infinite-scroll-error {
color: #757575;
text-align: center;
}
13 行目から 31 行目は、ローディングアイコンの指定です。ローディングアイコンは、「もっと見る」ボタンをクリック・タップした後に表示されます。
ローディングアイコンの CSS は、Single Element CSS Spinners をご参考にするといいかもしれません。
各ローディングアイコンの下にある < View Source > をクリックすると、CSS が出てきます。CSS のセレクタの .loader
を .infinite-scroll-request
に変更するだけで真似ができます。