• aboutabout
  • servicesservices
  • worksworks
  • mediamedia
  • contactcontact
  • homeサイトトップ
  • about会社概要
  • services業務内容
  • works実績紹介
  • mediaメディア
  • contactお問い合わせ
ja/

media

メディア

  1. サイトトップ
  2. メディア
  3. プログラミングの記事
  4. WordPressでサブループを使った非同期での無限ローディング機能を作成してみる

WordPressでサブループを使った非同期での無限ローディング機能を作成してみる

  • 2020.08.24
  • プログラミング
  • WordPress
Updated: 2020.08.24
先日、WordPress案件で記事一覧ページで無限ローディングの要件があり、いろんな情報記事を参考に作成してみるも上手くいかず、色々と試行錯誤を重ねたものを備忘録としてまとめておきたいと思います。WordPressで無限ローディングを実装するには「Infinite-Scroll」などのプラグインが有名ですが、投稿記事取得の条件が特殊だったり、カスタマイズ性が求められるということでとりあえず自前で実装する方向で進めてみました。   無限ローディングの方法にはスクロールを基準に非同期通信が走るものもありますが、今回はボタンをクリックして記事を取得する方法で作成していきました。投稿記事が無くなった場合にはボタンも非表示になるようにしています。また記事取得の条件はサブループを使用して、いろんなケースに対応できるようになっています。  
非同期で投稿記事を読み込む
通常、WordPressではURLにアクセスすることで、そのURLのルーティングに合わせた情報をデータベースから取得する形になります。もしくはサブクエリという形で、ページ上に書かれた処理を読み込むことで同じくデータベースから取得されます。それに対して非同期通信では、スクロールやボタンクリックなどのイベントで投稿記事をデータベースから取得させることができます。その際にページが読み込まれるといったことはありませんので、より動的な印象で記事を読み込むことができます。   そのため、記事を取得するPHPファイルだけではなく、イベントで非同期通信を実行させるためのJavaScriptファイルも必要になってきます。具体的には下記のような流れで記事が取得されます。 1. JavaScriptでイベントに合わせて取得件数などの情報がPHPファイルへPOSTされる 2. PHP側で取得件数などの情報をもとにサブクエリが実行されて記事情報が取得される 3. 取得した記事情報をPHP側でJSON形式で出力させることでJavaScript側にレスポンスとして渡される 4. JavaScriptでレスポンスで受け取った記事情報をHTML上へ動的に表示させる   上記の流れでどんどん繰り返して記事が存在する限り無限にローディングを行うことができます。それでは次に実際のコードを見ていきます。  
無限ローディング機能の実装
今回の実装には下記の通り最低3つのファイルが必要となります。それぞれのファイル内にあるソースコードと役割を見てきます。 ・ index.php(ページテンプレート) ・ loading.php(ローディング用のループ出力) ・ post.js(非同期でローディング実行)   まずは無限ローディングで記事一覧を表示させるためのページテンプレートです。今回は「index.php」を使っていますが、固定ページなどのページテンプレートでも可能です。ただ、実質は記事一覧ページとなりますのでアーカイブページが好ましいかもしれませんね。ページテンプレートに記述するのはとてもシンプルなHTMLだけになります。記事のアーカイブを表示させるコンテナ要素と、ローディングを実行するためのボタン要素を設置します。JavaScriptでDOM操作をするため適宜Id属性などを設定しておきます。 【index.php】※一部抜粋
..............
<div id="infinite_loading_container">
  <!-- ここに記事のアーカイブが表示されます -->
</div>
<button id="infinite_loading_button">もっと読み込む</button>
..............
  続いて、記事情報を取得するためのサブループが書かれたPHPファイルです。このファイルは基本的にページテンプレートなどでインクルードさせず、JavaScriptからのPOST通信を受けるためのファイルになります。まずはデフォルトであらかじめ表示されている記事件数と、追加で読み込む記事数を変数に入れておきます。カスタム投稿などの投稿タイプといったクエリ条件が通常と異なる場合には変数に入れておくと便利です。そして「wp-load.php」ファイルをインクルードしておきます。こうすることでこのファイル内でWordPressで扱う関数やグローバル変数が使えるようになります。以降、ローディングのための処理が続いていきます。 【loading.php】
<?php
  $default_show_posts = 3;
  $default_loading_posts = 3;
  $target_post_type = 'post';
  require_once(dirname(__FILE__).'/../../../../../wp-load.php');
  $offset_value = isset($_POST['currently_loaded_count']) ? $_POST['currently_loaded_count'] : $default_show_posts;
  $loading_count = isset($_POST['additional_loading_count']) ? $_POST['additional_loading_count'] : $default_loading_posts;
  $all_posts_query = new WP_Query(
    array(
      'post_type' => $target_post_type,
      'posts_per_page' => -1
    )
  );
  $infinite_loading_query = new WP_Query(
    array(
      'post_type' => $target_post_type,
      'posts_per_page' => (int)$loading_count,
      'offset' => (int)$offset_value
    )
  );
  $posts_count = $all_posts_query->found_posts;
  if($infinite_loading_query->have_posts()):
?>
<?php 
  while($infinite_loading_query->have_posts()): 
  $infinite_loading_query->the_post(); 
?>
<?php 
  $posts = $infinite_loading_query->posts;
  $remaining_count = $posts_count - $offset_value - 1;
  $contents = array();
  foreach ($posts as $post) {
    $html = '<div>'.$post->post_title.'</div>';
    $html .= '<a href="'.get_permalink($post->ID).'">'.get_permalink($post->ID).'</a>';
    if(has_post_thumbnail($post->ID)) {
      $html .= '<img src="'.get_the_post_thumbnail_url($post->ID, 'full').'" alt="'.$post->post_title.'">';
    } else {
      $html .= '<img src="********.jpg" alt="'.$post->post_title.'">';
    }
    $html .= '<div>'.get_the_excerpt($post->ID).'</div>';;
    array_push($contents, $html);
  }
?>
<?php endwhile; ?>
<?php 
  $loading_complete = false;
  if($remaining_count < $loading_count) {
    $loading_complete = true;
  }
  echo json_encode(
    array(
      'complete'=>$loading_complete,
      'content'=>$contents
    )
  );
  endif; 
?>
<?php wp_reset_postdata(); ?>
  ローディングのための処理ですが、初めにJavaScriptからPOSTされた値を変数に入れます。$_POST変数に値が入るので、入っている場合には送られてきた値を代入し、POSTされていない場合には先ほど設定した初期値が入るようにしておきます。
$offset_value = isset($_POST['currently_loaded_count']) ? $_POST['currently_loaded_count'] : $default_show_posts;
$loading_count = isset($_POST['additional_loading_count']) ? $_POST['additional_loading_count'] : $default_loading_posts;
  そして、これらの値を使ってサブクエリを作成していきます。その前にまずは対象となる記事の全件数を取得する必要があるので、全件数取得用のサブクエリを作成します。合わせて、サブクエリで取得した記事情報からトータルの記事数を変数に入れておきます。そのあとに、JavaScriptで取得した値を使ったローディング用のサブクエリを作成します。こうすることで、JavaScriptで登録したイベントに合わせてサブクエリが走るという形になります。
$all_posts_query = new WP_Query(
  array(
    'post_type' => $target_post_type,
    'posts_per_page' => -1
  )
);
$infinite_loading_query = new WP_Query(
  array(
    'post_type' => $target_post_type,
    'posts_per_page' => (int)$loading_count,
    'offset' => (int)$offset_value
  )
);
$posts_count = $all_posts_query->found_posts;
if($infinite_loading_query->have_posts()):
  そのあとは先ほどのクエリでサブループを展開してきます。この時にテンプレート上に出力するのではなく、取得した記事情報を変数に入れるようにしておきます。投稿は複数取得する場合もあるので配列の形にしておくことが重要です。記事情報も複数の場合を想定してforeachで取得し、最後に記事情報を格納する配列型の変数に代入していきます。記事情報は必要に応じてHTMLで構成されるように文字列を組んでいきましょう。
<?php 
  while($infinite_loading_query->have_posts()): 
  $infinite_loading_query->the_post(); 
?>
<?php 
  $posts = $infinite_loading_query->posts;
  $remaining_count = $posts_count - $offset_value - 1;
  $contents = array();
  foreach ($posts as $post) {
    $html = '<div>'.$post->post_title.'</div>';
    $html .= '<a href="'.get_permalink($post->ID).'">'.get_permalink($post->ID).'</a>';
    if(has_post_thumbnail($post->ID)) {
      $html .= '<img src="'.get_the_post_thumbnail_url($post->ID, 'full').'" alt="'.$post->post_title.'">';
    } else {
      $html .= '<img src="********.jpg" alt="'.$post->post_title.'">';
    }
    $html .= '<div>'.get_the_excerpt($post->ID).'</div>';;
    array_push($contents, $html);
  }
?>
<?php endwhile; ?>
  続けて読み込みが最終になるかどうかのフラグを用意し、取得した記事情報と合わせてJSON形式で出力するようにします。こうすることでJavaScript側でレスポンスとして受け取ることができます。サブループなので最後に「wp_reset_postdata()」をすることを忘れないようにしましょう。
<?php 
  $loading_complete = false;
  if($remaining_count < $loading_count) {
    $loading_complete = true;
  }
  echo json_encode(
    array(
      'complete'=>$loading_complete,
      'content'=>$contents
    )
  );
  endif; 
?>
<?php wp_reset_postdata(); ?>
  以上でPHPファイルが作成できました。続けてJavaScriptファイルも作成してきます。まずはPOSTする対象となるPHPファイルのパスを絶対パスで変数に入れておきます。そして、初期表示されている数(つまり投稿取得を開始する位置)と、追加読み込みで取得する投稿記事数を変数に入れておきます。あとはトリガーとなるボタン要素と、表示させる先のコンテナ要素もDOMで取得しておきます。 【post.js】
const api_url = 'https://example.com/*******/wp-content/themes/*******/loading.php';   // POST先のPHPファイルパス
let current = 3;   // 初期表示投稿数(投稿取得開始位置)
const add = 3;   // 投稿取得数
const trigger = document.getElementById('infinite_loading_button');   // トリガー要素指定
const container = document.getElementById('infinite_loading_container');   // 表示コンテナ要素指定
trigger.addEventListener('click', () => {
  fetch(api_url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    body: `currently_loaded_count=${current}&additional_loading_count=${add}`
  })
  .then((response) => {
    return response.json();
  })
  .then((json) => {
    json.content.forEach((item) => {
      container.insertAdjacentHTML('beforeEnd', item);
    })
    current = current + add;
    if(json.complete) {
      trigger.remove();
    }
  })
  .catch((error) => {
    return error.message;
  });
});
  そしてイベントでローディングが実行されるように関数を作成していきます。まずはトリガー要素をクリックすると投稿開始位置と追加で取得する投稿数の情報が、対象のPHPファイルにPOST通信で送られるようにします。ここでは「fetch API」のメソッドを使っていますがjQueryのajaxメソッドを使う方法もあるようですね。(fetchを使う場合にはIE対応が別途必要となるので注意)PHP側で$_POST変数として受け取るためには、リクエストヘッダーに「application/x-www-form-urlencoded」を追加するのと、リクエストボディでは「key=value&key=value」の形にしておくことが重要です。
trigger.addEventListener('click', () => {
  fetch(api_url, {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'
    },
    body: `currently_loaded_count=${current}&additional_loading_count=${add}`
  })
  .then((response) => {
    return response.json();
  })
  .then((json) => {
    json.content.forEach((item) => {
      container.insertAdjacentHTML('beforeEnd', item);
    })
    current = current + add;
    if(json.complete) {
      trigger.remove();
    }
  })
  .catch((error) => {
    return error.message;
  });
});
  fetchメソッドでは返り値がPromiseオブジェクトで返ってくるので、then()で続く処理を書いていきます。レスポンスとして投稿記事の情報を受け取ることができるので、それを展開し、HTML上に出力していくという処理を続けていきます。投稿記事データは配列型になっているので、forEach()などで対応しないとうまく記事が表示できないので注意します。そのあとに投稿開始位置の値を更新し、最終のローディングのフラグで条件分岐させてトリガー要素を削除するという処理を追加しておきます。こうすることで、最終の読み込みが終わるとボタンが非表示となります。  
  少し長くなりましたが、今回はWordPressにおいて非同期で投稿記事を読み込む無限ローディング機能の実装についてまとめてみました。色々と方法はあるようなのですが、目的とする要件に合わせて実装するのがいいのではないでしょうか。今回のものはシンプルな形ですのでいろんなカスタマイズにも対応しやすいかと思います。通常のページネーションとは異なるユーザー体験を与えることができますので、ぜひ一度試してみてはいかがでしょうか。   (参考にさせていただいたサイト) WordPressで無限スクロールで記事を読み込む方法!【プラグインなし編】 WordPressの記事をAjaxで追加読み込みしたときの話  
XでシェアLINEで送るはてブに追加

この記事を書いた人オガワ シンヤ

合同会社デザインサプライ代表兼CEO / ディレクター・ウェブデザイナー・フロントエンドエンジニアをやっています。「ウェブとデザインでヒト・モノ・サービスを繋げ新しい価値を生み出す」をコンセプトに日々奮闘中!制作中はダイエットコーラとチョコレートが欠かせないアラフォーWebクリエイター。

Sponsored Link

  • Showcase
  • Startify UI
  • Functional Gradation Generator
  • Coloooors

keyword search

categories

  • WordPress(61)
  • JavaScript(49)
  • Vue.js(48)
  • CSS(46)
  • jQuery(34)
  • Nuxt.js(22)
  • Sass(21)
  • Gulp(17)
  • webpack(16)
  • PHP(14)
  • HTML(14)
  • GSAP(11)
  • React(10)
  • Vite(9)
  • Pug(9)
  • Laravel(8)
  • Cordova(8)
  • Linux(7)
  • Next.js(6)
  • Apache(5)
  • Shopify(4)
  • REST API(4)
  • Node.js(4)
  • Smarty(3)
  • Git(3)
  • JSON(3)
  • その他プログラミング(3)
  • Google Apps API(3)
  • Bootstrap(3)
  • 環境構築・システム(3)
  • TypeScript(2)
  • EJS(2)
  • RMS(2)
  • Docker(2)
  • Instagram API(2)
  • Excel VBA(2)
  • SVG(1)
  • Dart(1)
  • ECカートASP(1)
  • Markdown(1)
  • AMP(1)
  • Nginx(1)
  • XML(1)
  • shellscript(1)
  • Ruby(1)
  • MySQL(1)

recent articles

  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#6:PWA対応とビルド時のエラー
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#6:PWA対応とビルド時のエラー

    2024.12.25/Next.js
  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#5:アナリティクス・アドセンスの導入とサイトマップ作成
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#5:アナリティクス・アドセンスの導入とサイトマップ作成

    2024.08.26/Next.js
  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#4:静的・動的ルーティングとページ作成
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#4:静的・動的ルーティングとページ作成

    2024.07.31/Next.js
  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#3:メタ情報設定・ファイル最適化・ステート管理
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#3:メタ情報設定・ファイル最適化・ステート管理

    2024.06.30/Next.js
  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#2:コーディング環境の構築
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#2:コーディング環境の構築

    2024.05.29/Next.js
  • Next.jsとWordPressでヘッドレスCMSのサイトを作成する#1:インストール・導入
    read more

    Next.jsとWordPressでヘッドレスCMSのサイトを作成する#1:インストール・導入

    2024.04.30/Next.js
  • 次の記事
  • 一覧に戻る
  • 前の記事

まだ依頼内容が決まっていなくても、ご相談ください。

課題の整理や小さな検証、UI/UX・フロントエンドの部分的な支援から始められます。

お問い合わせやご相談はこちらから

Webサイト・プロダクトの企画設計/UI・UXデザイン/フロントエンド開発合同会社デザインサプライ(DesignSupply. LLC)

Office:大阪府大阪市天王寺区清水谷町3-22
Email:info@designsupply-web.com
home
  • サイトトップ
about
  • 3つのポリシー
  • 経営理念
  • 代表・クリエイター紹介
  • 会社概要
services
  • ビジネス・プロダクト支援
  • UI/UX・フロントエンド開発支援
  • プロジェクトの進め方・支援体制
  • エデュケーション事業
works
  • 開発プロジェクト支援
  • クリエイティブ制作
  • 自社プロダクト
media
  • デザイン
  • プログラミング
  • マーケティング
  • Web開発
  • 写真・動画制作
contact
  • お問い合わせ
news
  • インフォメーション
privacy
  • プライバシーポリシー

WE THINK WITH YOU, DESIGN FOR PEOPLE, AND BUILD WHAT WORKS.

WE THINK WITH YOU, DESIGN FOR PEOPLE, AND BUILD WHAT WORKS.

© 2013 - 2026 DesignSupply.LLC
サイトトップへ
contact