😮‍💨

Vanilla JSでAjax通信する方法(Wp,FetchAPI)

2024/08/17に公開

沼ったので自分用にメモ。

固定ページ用テンプレートに記事を出力する。

ajax.php
<?php
    $post_num = 3;
    $paged = get_query_var("paged") ? get_query_var("paged") : 1; //ページ番号
    $query = new WP_Query(
        array(
            'post_type' => 'post', //カスタム投稿タイプを指定
            'posts_per_page' => $post_num, //記事の表示件数を指定
            'paged' => $paged
            ));
    if ( $query->have_posts() ) : ?>

        <ul class="newsAjaxPage__list" id= "post_list">
            <?php while ( $query->have_posts() ) : $query->the_post();?>
                <li>
                    <a href="<?= get_permalink(); ?>">
                        <h3><?= get_the_title(); ?></h3>
                    </a>
                    <p><?= the_content(); ?></p>
                </li>
                <?php endwhile; ?>
            </ul>
    <?php endif; ?>
    <button id="loadPostsButton" class="newsAjaxPage__btn">VIEW MORE</button>
functions.php
// 投稿データの取得
function get_posts_data_as_array( $posts_per_page = 3) {
    $args = array(
        'post_type'      => 'post',
        'posts_per_page' => $posts_per_page,
		'paged' => $_POST['paged'],
		// 'offset' => 3,
    );
    $query = new WP_Query($args);

    // 連想配列に格納
    $posts_data = array();
    if ($query->have_posts()) {
        while ($query->have_posts()) {
            $query->the_post();
            $posts_data[] = array(
                'title'   => get_the_title(),
                'content' => get_the_content(),
                'link'    => get_permalink(),
            );
        }
        wp_reset_postdata(); // クエリのリセット
    }
    return array(
        'posts' => $posts_data,
        'max_num_pages' => $query->max_num_pages,
        'current_page' => intval($_POST['paged']),
    );
}

// デバッグ用(管理画面のヘッダー部分で出力)
//add_action('admin_head', 'output_posts_data_for_debugging');
//function output_posts_data_for_debugging() {
//  $posts_data = get_posts_data_as_array();
//  echo '<pre>';
//  print_r($posts_data);
//  echo '</pre>';
// }

//core.jsにアクセスするフック
add_action( 'wp_enqueue_scripts', 'core_js_file' );
function core_js_file() {
  wp_enqueue_script( 'core_js', get_theme_file_uri( '/js/core.js'), array(), rand( 1000 ,9999 ) , true );
}

//wp_localize_scriptでcore.jsに値を渡す(urlとnonce-ハッシュ値)
add_action( 'wp_enqueue_scripts', 'core_js_localize_script' );
function core_js_localize_script ( $hook ) {
  $obj = array(
    'url' => admin_url( 'admin-ajax.php' ),
	'nonce' => wp_create_nonce( 'my_nonce' ), // nonce生成時の名前(要メモ!)
	);
	wp_localize_script( 'core_js', 'ajax_obj', $obj );
}

//記事読み込みのフック
add_action( 'wp_ajax_load_more_posts', 'load_more_posts' ); // ログインユーザー
add_action( 'wp_ajax_nopriv_load_more_posts', 'load_more_posts' ); // 一般ユーザー
function load_more_posts() {
  check_ajax_referer( 'my_nonce', 'nonce' );
  $posts_data = get_posts_data_as_array();
  wp_send_json( $posts_data );
}
ajax.js
let paged = 1;

const getPosts = async ( event ) => {
  event.preventDefault();
  paged++;

  const path = ajax_obj.url;
  const nonce = ajax_obj.nonce;
  
  const data = new URLSearchParams();
  data.append( 'action', 'load_more_posts' );
  data.append( 'paged', paged );
  data.append( 'nonce', nonce );

  const options = {
    method: 'POST',
    headers: {
      'Content-Type': 'application/x-www-form-urlencoded',
    },
    body: data.toString(),
  }

  try {
    const response = await fetch( path, options );
    const data = await response.json();
    let post_list = document.getElementById('post_list');
    let postElement;
    if(data.max_num_pages > data.current_page){
      for(let i = 0;i<data.posts.length;i++){
        postElement = htmlPackage(data.posts[i]);
        post_list.appendChild(postElement); // 生成された要素をbodyに追加
      }
    }else if(data.max_num_pages === data.current_page){
      for(let i = 0;i<data.posts.length;i++){
        postElement = htmlPackage(data.posts[i]);
        post_list.appendChild(postElement); // 生成された要素をbodyに追加
      }
      const rmvBtn = document.getElementById('loadPostsButton');
      rmvBtn.remove();
    };
  }
  catch ( error ) {
    console.error( error );
  }
};
document.getElementById('loadPostsButton').addEventListener( 'click', getPosts );

const htmlPackage = (post) =>{
  let li =document.createElement('li');
  let h3 = document.createElement('h3');
  let a_tag = document.createElement('a');
  let p = document.createElement('p');

  h3.textContent = post.title;  // タイトル
  p.textContent = post.content; // リンクのテキストにタイトルを設定
  a_tag.href = post.link; // リンクのURLを設定

  h3.appendChild(a_tag);  // h3タグにリンクを挿入
  li.appendChild(h3);    // liタグにh3を挿入
  li.appendChild(p);     // liタグにpを挿入

  return li; // 生成したHTMLを返す
}

問題点として、はじめに表示する投稿数とajax通信で表示する投稿数が一致しないと投稿がダブって表示されてしまう。そのため、ajaxのwpクエリ呼び出しの段階でオフセットをかけたいが、$pagedと併用ができない。解決案模索中。。

Discussion