WordPress の AMP ページに amp-list の無限スクロールを実装する方法
動作
2019 年 3 月に、amp-list のアップデートがありました。アップデートにより、AMP で動的に表示するリストの無限スクロールが可能になりました。
この amp-list の無限スクロールを WordPress に実装する方法を紹介します。
まずは、amp-list の無限スクロールの動作をご覧ください。最初は 3 件を表示し、ボタンのクリックで 3 件ずつデータを追加しています。
尚、amp-list の無限スクロールには 2 つのタイプがあり、ボタンをクリックせずに自動的にデータを追加するタイプもあります。
特徴と用途
amp-list の無限スクロールは、以下の特徴があります。
- 現在のページに「データ」を追加する
- 「異なるページ」を追加するわけではないため、ページアドレスは変わらない
- データ追加後の状態は、ブラウザの履歴に残らない
この特徴は、異なるページを追加する一般的な無限スクロールとは異なります。一般的な無限スクロールは、このような動作をするのが基本です。
- 現在のページに「異なるページ」を追加する
- 「異なるページ」を追加後、ページアドレスが変わる
- 追加したページのアドレスが、ブラウザの履歴に残る
一般的な無限スクロールはブラウザの履歴に残るため、ブラウザの「戻る」が使えます。一方、amp-list の無限スクロールは、ブラウザの「戻る」が使えません(「戻る」でデータ追加前の状態に戻らない)。
amp-list の無限スクロールの特徴を考慮すると、このようなリストに適しています。
- 「関連記事」や「関連商品」のリスト
- ブログやニュースサイトのコンテンツページで見かける「人気記事」や「最新記事」のリスト
- 検索結果ページなど「絞り込み」や「並び替え」機能が必要なリスト(これらの機能は amp-bind の併用で実装可能)
一方、不適切だと思うのは、ページネーションのある複数のページに分割した記事一覧リスト(記事一覧ページ)。このようなリストに実装すると、ブラウザの戻るが使えないためユーザビリティが悪化する、SEO に悪影響が出る恐れがあります。
尚、AMP の記事一覧ページで無限スクロールを実装するには、amp-next-page を使います。
実装方法
WordPress での amp-list の無限スクロールの実装は、大まかに 3 ステップで終わります。
今回は、投稿ページに「新着記事」を表示する例として説明します。この「新着記事」は、最初は 5 件を表示し、無限スクロールで「現在の投稿ページ」を除く全件を作成日順(新しい記事から表示する降順)で表示するものです。
WP REST API の独自エンドポイントを作成
最初にすることは、WP REST API の独自エンドポイントの作成です。
amp-list は、JSON から動的にデータを取得します。WordPress の JSON と言えば WP REST API です。
しかし、WP REST API には、amp-list の無限スクロールに必要な「JSON の次のページの URL」(1 ページ目をリクエストしている場合は 2 ページ目の URL)が JSON 内に含まれていません。
JSON 内に次のページの URL を含めるために、下記コードを functions.php に追加し独自のエンドポイントを作成します。
add_action( 'rest_api_init', function() {
register_rest_route( 'new', '/id(?P<id>\d+)/page(?P<page>\d+)', [
'callback' => 'get_rest_api_new',
'methods' => WP_REST_Server::READABLE
]);
});
function get_rest_api_new( $request ) {
$request_id = $request['id'];
$request_page = $request['page'];
$the_query = new WP_Query([
'paged' => $request_page,
'post__not_in' => [$request_id],
'posts_per_page' => 5
]);
/**
* 次ページの URL
*/
$max_num_pages = $the_query->max_num_pages;
if ( $request_page < $max_num_pages ) {
$next_page = esc_url( home_url() ) . '/wp-json/new/id' . $request_id . '/page' . ( $request_page + 1 );
}
else {
$next_page = null;
}
/**
* 記事データ
*/
$posts = null;
if ( $the_query->have_posts() ) {
while ( $the_query->have_posts() ) {
$the_query->the_post();
$thumb_id = get_post_thumbnail_id();
$thumb_src = wp_get_attachment_image_src( $thumb_id, 'large' );
$data['permalink'] = get_permalink();
$data['title'] = get_the_title();
$data['cat_name'] = get_the_category()[0]->cat_name;
$data['srcset'] = wp_get_attachment_image_srcset( $thumb_id );
$data['src'] = $thumb_src[0];
$data['img_width'] = $thumb_src[1];
$data['img_height'] = $thumb_src[2];
$data['alt'] = get_post_meta( $thumb_id, '_wp_attachment_image_alt', true );
$posts[] = $data;
}
wp_reset_postdata();
}
/**
* WP REST API へ出力
*/
$json = [
'load-more-src' => $next_page,
'items' => $posts
];
return rest_ensure_response( $json );
}
投稿ページに「アイキャッチ画像がない」「カテゴリーがない」場合の処理はしていません。
参考:Routes and Endpoints | REST API Handbook | WordPress Developer Resources
記事のデータとして、「記事の URL」「記事タイトル」「カテゴリー名」「画像関係」を取得しています。他に必要なデータがあれば、50 行目以降に $data
として追加します。
この独自エンドポイントには、このような URL でリクエストできます。
https://example.com/wp-json/new/id50/page1
id50 は、「新着記事」を表示する「現在の投稿ページ」の id です。この id は、<amp-list>
タグに設定する the_ID()
で取得します。
末尾の page1 は、JSON のページ数です。page1 であれば 1 ページ目、page2 であれば 2 ページ目の JSON をリクエストします。
ブラウザのアドレスバーに打ち込むと、このような JSON が返ってきます。
// https://example.com/wp-json/new/id50/page1
{
"load-more-src": "https://example.com/wp-json/new/id50/page2",
"items": [
{
"permalink": "https://example.com/amp-list/",
"title": "amp-listの無限スクロール",
"cat_name": "AMP",
"srcset": "https://example.com/wp-content/uploads/2019/05/amp-list.png 1920w, 〜(以下、省略)",
"src": "https://example.com/wp-content/uploads/2019/05/amp-list-640x360.png",
"img_width": 640,
"img_height": 360,
"alt": "amp-listの無限スクロール"
},
以下、posts_per_page で指定した件数分の記事データが続く
]
}
JSON は縮小されているため、JSON Viewer のような整形ツールを使うと便利です。
JSON の次のページの URL は、load-more-src
から取得します。また、記事データは、items
に格納しています。
この load-more-src
と items
の名前は、amp-list の仕様に合わせています。異なる名前にできますが、その場合は <amp-list>
タグを作成時に属性の追加が必要です(注意点にて後述します)。
ライブラリの読み込み
次は、amp-list と amp-mustache のライブラリを読み込みます。amp-mustache は、amp-list のテンプレート作成に必要です。
この 2 つのコンポーネントのライブラリを <head>
で読み込みます。
<script
async
custom-element="amp-list"
src="https://cdn.ampproject.org/v0/amp-list-0.1.js"></script>
<script
async
custom-template="amp-mustache"
src="https://cdn.ampproject.org/v0/amp-mustache-0.2.js"></script>
amp-list タグの作成
最後に、<amp-list>
タグを作成します。
作成方法や仕様は、公式ページで詳細に解説されています。
基本的な作り方は、<amp-list>
タグの src
属性に JSON の URL を指定。そして、<template type="amp-mustache">
内で、JSON のデータを {{}}
で囲みテンプレートを作成します。
single.php の「最新記事」を表示したい場所に、このような <amp-list>
タグを設置します。
<amp-list
layout="fixed-height"
height="500"
src="<?php echo esc_url( home_url() ); ?>/wp-json/new/id<?php the_ID(); ?>/page1"
binding="no"
load-more="manual">
<template type="amp-mustache">
<div>
<a href="{{permalink}}">
<div>
<amp-img
src="{{src}}"
srcset="{{srcset}}"
alt="{{alt}}"
width="{{img_width}}"
height="{{img_height}}"
sizes="(max-width: {{img_width}}px) 100vw, {{img_width}}px"></amp-img>
</div>
<div>
<h2>{{title}}</h2>
<p>{{cat_name}}</p>
</div>
</a>
</div>
</template>
</amp-list>
amp-list の無限スクロールに必須の属性は load-more>
です。値は、auto
か manual
のいずれかです。
属性と値 | 動作 |
---|---|
load-more="auto" | 自動的にデータを追加する無限スクロール。 |
load-more="manual" | ボタンのクリックでデータを追加する無限スクロール。デフォルトでは「SEE MORE」ボタンが表示される。 |
注意点
今回「JSON の次のページの URL」は、JSON の load-more-src
から取得しています。この load-more-src
は、amp-list がデフォルトで要求する名前です。
もし、WP REST API の独自エンドポイントの作成時に load-more-src
を異なる名前にした場合は、<amp-list>
タグに load-more-bookmark
属性が必要です。
例えば、名前を next-page
にした場合は、load-more-bookmark="next-page"
を追加します。これで「next-page
から JSON の次のページの URL を取得しなさい」と指示できます。
<amp-list
load-more-bookmark="next-page"
layout="fixed-height"
height="1000"
src="<?php echo esc_url( home_url() ); ?>/wp-json/new/id<?php the_ID(); ?>/page1"
binding="no"
load-more="auto"></amp-list>
また、記事データは、JSON の items
に格納しました。この items
も amp-list がデフォルトで要求する名前です。
もし、items
を異なる名前にした場合は、<amp-list>
タグに items
属性が必要です。
例えば、名前を post-data
にした場合は、items="post-data"
を追加します。
<amp-list
items="post-data"
layout="fixed-height"
height="1000"
src="<?php echo esc_url( home_url() ); ?>/wp-json/new/id<?php the_ID(); ?>/page1"
binding="no"
load-more="auto"></amp-list>
オプション
amp-list の無限スクロールには、<amp-list-load-more>
タグを使用するオプションが用意されています。
このタグは <amp-list>
タグの子要素として配置し、任意の属性を指定します。
公式サイトの amp-list のドキュメントに詳細な説明があるため、ここでは簡単に解説します。
ボタンを変更
load-more="manual"
を指定した場合は、デフォルトで「SEE MORE」ボタンが表示されます。
このボタンを変更できるのが、load-more-button
属性です。
<amp-list>
の子要素として、load-more-button
属性を持つ <amp-list-load-more>
タグを設置します。
<amp-list
layout="fixed-height"
height="1000"
src="<?php echo esc_url( home_url() ); ?>/wp-json/new/id<?php the_ID(); ?>/page1"
load-more="manual">
<template type="amp-mustache">〜省略〜</template>
<amp-list-load-more load-more-button>
<button>もっと見る</button>
</amp-list-load-more>
</amp-list>
amp-mustache を使い、JSON データの反映も可能です。
尚、ボタンの背景色などを変更する場合は、amp-list-load-more タグに対してではなく、button タグに対して CSS を指定します。でなければ、ローディングアニメーションなどにも CSS が適用されてしまいます。
ローディングアニメーション
デフォルトでは、無限スクロール発動時に一般的なローディングアニメーションが適用されます(一部が欠けた円がクルクルと回る)。
独自のローディングアニメーションにしたい時は、load-more-loading
属性を使います。
<amp-list>
の子要素として、load-more-loading
属性を持つ <amp-list-load-more>
タグを設置します。
<amp-list 以下、省略>
...
<amp-list-load-more load-more-loading>
<svg
xmlns="http://www.w3.org/2000/svg"
width="24"
height="24"
viewBox="0 0 24 24">
<path
d="M12 6v3l4-4-4-4v3c-4.42 0-8 3.58-8 8 0 1.57.46 3.03 1.24 4.26L6.7 14.8c-.45-.83-.7-1.79-.7-2.8 0-3.31 2.69-6 6-6zm6.76 1.74L17.3 9.2c.44.84.7 1.79.7 2.8 0 3.31-2.69 6-6 6v-3l-4 4 4 4v-3c4.42 0 8-3.58 8-8 0-1.57-.46-3.03-1.24-4.26z" />
<path d="M0 0h24v24H0z" fill="none" />
</svg>
</amp-list-load-more>
</amp-list>
Material icons の Autorenew の SVG を使っています。
あとは、CSS の @keyframes を使えば、独自のローディングアニメーションの完成です。
尚、「読み込み中」などテキストのみの指定もできます。
読み込み失敗時の再読み込み
JSON の次のページの読み込みに失敗した時に備えられるのが、load-more-failed
属性です。
この属性を持つ <amp-list-load-more>
タグがある場合は、JSON の読み込みの失敗時にボタンを表示できます。このボタンのクリックで、JSON の再読み込みが可能です。
ボタンを表示するだけなら、このように指定します。
<amp-list 以下、省略>
...
<amp-list-load-more load-more-failed>
<button>再読み込み</button>
</amp-list-load-more>
</amp-list>
また、注意文も表示するのならボタン要素に load-more-clickable
属性を指定します(注意文はクリック要素にはならず、ボタンのみがクリック要素となる)。
<amp-list 以下、省略>
...
<amp-list-load-more load-more-failed>
<p>読み込みに失敗しました</p>
<button load-more-clickable>再読み込み</button>
</amp-list-load-more>
</amp-list>
これ以上データがない時の注意文
これ以上読み込む JSON のデータがない時に注意文を表示できるのが、load-more-end
属性です。
「これ以上は記事がありません」などの注意文を表示できます。
<amp-list 以下、省略>
...
<amp-list-load-more load-more-end>
<p>これ以上は記事がありません</p>
</amp-list-load-more>
</amp-list>
複数の指定
異なる属性を持つ複数の <amp-list-load-more>
タグを設置できます。
<amp-list 以下、省略>
...
<amp-list-load-more load-more-button>
<button>もっと見る</button>
</amp-list-load-more>
<amp-list-load-more load-more-end>
<p>これ以上は記事がありません</p>
</amp-list-load-more>
</amp-list>