2
1

More than 3 years have passed since last update.

[WordPress] 投稿をAjaxで読み込む時にプラグインのShortCodeが発動しない時のTips

Last updated at Posted at 2020-04-13

はじめに

WordPressテーマ開発をしている中で、

  • WordPressの投稿をAjaxで取得
  • 何かしらプラグインのショートコードをdo_shortcode()する

っていうことは、それぞれよくやると思う。でもこの2つがかけ合わさった時に色々と手こずったので知見をメモしておきます。せっかく早起きして優雅に始まった朝がめちゃニッチなデバッグに消えたので、この記事で他の誰かの優雅な朝を守りたい。

ちなみに自分が手こずったのはAddToAny Share Buttonsというプラグインで、なぜかAjax経由だとアイコンが表示されない。最終的にはプライグイン独自の仕様の問題だったのでとにかく解決策を知りたい方は最終セクションを見ると良いです。

WordPressでAjaxを使う時のお作法

そもそもWordPressでAjaxを使う時にはお作法が決まっていたので基本としてメモ。

Ajaxリクエストを投げる場所

WordPressにはAjaxリクエストを処理するためにwp-admin/admin-ajax.phpというファイルがあり(Reference)、原則としてリクエストはここに投げるような仕様になっている。もちろん独自にajax用のファイルを用意しても出来るけど、admin-ajax.phpにリクエストすると、functions.phpで登録した関数が使えるようになるので便利。admin-ajax.phpのファイルurlは

functions.php
<?php
function add_my_ajaxurl() {
?>
  <script>
    const ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
  </script>
<?php
}
add_action('wp_head', 'add_my_ajaxurl', 1);

としてヘッダの読み込みにフックしてグローバル変数として登録しておけば、どこのテーマファイルでも使えるようになる。

Ajaxリクエスト時に実行するactionの登録

Ajaxリクエスト時、actionという名称で実行するactionを指定することができる。

my-ajax.js
$.ajax({
    type: 'POST',
    url: ajaxurl,
    data: {
        action: 'my_ajax_action',
    },
    success: function(res) {
        // 成功時の処理
    }
});

ここでのmy_ajax_actionが自分で登録したactionになる。登録はfunctions.phpにて、

functions.php
add_action('wp_ajax_my_ajax_action', 'my_ajax_action');
add_action('wp_ajax_nopriv_my_ajax_action', 'my_ajax_action');

function my_ajax_action() {
    // 任意の処理
}

として記述する。actionが2種類あるがnopriv修飾子がついているのは非ログインユーザーに対する処理(Reference)。ログイン/非ログインで特別に処理を分けたい時以外は両方に同じものを登録しておく。ちなみにaction引数が参照するのは関数名ではなくて、wp_ajax_, wp_ajax_nopriv_の後の文字列なので注意。

Ajaxを用いた投稿読み込みのサンプル

一応サンプルを示しておく。

functions.php
<?php
//---------------------------------
// subscript ajax url
//---------------------------------
function add_my_ajaxurl() {
?>
  <script>
    const ajaxurl = '<?php echo admin_url('admin-ajax.php'); ?>';
  </script>
<?php  
}
add_action('wp_head', 'add_my_ajaxurl', 1);

//---------------------------------
// get post via ajax
//---------------------------------
add_action('wp_ajax_my_get_post_data', 'my_get_post_data');
add_action('wp_ajax_nopriv_my_get_post_data', 'my_get_post_data');

function my_get_post_data() {
  $offset         = isset( $_POST['post_num_now'] ) ? $_POST['post_num_now'] : 1;
  $posts_per_page = isset( $_POST['post_num_add'] ) ? $_POST['post_num_add'] : 0;

  $ajax_query = new WP_Query(
    array(
      'post_type'      => 'post',
      'posts_per_page' => $posts_per_page,
      'offset'         => $offset,
    )
  );

  if ( $ajax_query->have_posts() ) {
    while ( $ajax_query->have_posts() ) {
      $ajax_query->the_post(); ?>
          <div class="post">
            <a href="<?php echo get_the_permalink(); ?>">
                <?php the_post_thumbnail('medium'); ?>
                <p><?php the_time('Y.m.d'); ?></p>
                <h2><?php the_title(); ?></h2>
            </a>
          </div>
    <?php }
  }
  wp_reset_postdata();
  exit;
}
ajax-get-posts.js
let postNumNow = 0;
let postNumAdd = 5; // moreで何件表示するか
let flag = false;

function addPosts() {
    if(!flag) {
        flag = true;
        $.ajax({
            type: "POST",
            url: ajaxurl,
            data: {
                action: 'my_get_post_data',
                post_num_now: postNumNow,
                post_num_add: postNumAdd
            },
            success: function(response) {
                let $postWrap = $('<div class="post_wrap"></div>');
                $('.posts').append($postWrap);
                $postWrap.append(response);
                $postWrap.fadeIn(800);
                postNumNow += postNumAdd;
                flag = false;
            }
        });
    }
}

// 表示の最下部まで到達したら次を読み込む
$(document).ready(function() {
    $(window).on('load', addPosts); // 初期表示
    $(window).scroll(function() {
        let postsBottom = $('.posts').offset().top + $('.posts').innerHeight();
        let scrollTop = $(this).scrollTop();
        if(scrollTop > postsBottom - $(window).innerHeight()) addPosts();
    });
});

Ajax経由でdo_shortcode('hoge')が文字列として表示される時の対処法

さて本題。Ajaxで読み込むリクエスト先にdo_shortcodeを挿入したい時。
例えば

functions.php
function my_ajax_action() {
    if(have_posts()) {
        while(have_posts()) {
            the_post();
            echo do_shortcode('[addtoany]');
        }
    }
}

のように投稿内で呼び出すと、do_shortcodeがそのまま文字列として表示される場合がある。今回はこれとは症状が異なったので解決策にはならなかったが、この場合の解決策がStackExchangeに載っていたので共有する →Why might a plugin's 'do_shortcode' not work in an AJAX request?

簡単にいうと、Ajaxリクエストがadmin-ajax.phpを経由して処理されるので、wp-includesに存在するshortcodes.phpにアクセスできないので、自前でショートコードを登録必要があるとのこと。(今回はこれに関しては大丈夫だったので解決されたのかな??もしくは特定の条件下で起きるのか...要検証)

念のためコードを載せておく。

functions.php
add_action( 'init', function() { 
  ps_register_shortcode_ajax( 'ps_get_survey_form', 'ps_get_survey_form' ); 
} );

function ps_register_shortcode_ajax( $callable, $action ) {

  if ( empty( $_POST['action'] ) || $_POST['action'] != $action )
    return;

  call_user_func( $callable );
}

function ps_get_survey_form() {
    echo do_shortcode( '[contact-form-7 id="397" title="contact form 1"]' );
    die(); 
} 

AddToAnyをAjaxで読み込む時は

そして結局(私の場合の)解決策はこれ。最終的にはAddToAny Share ButtonsのAPI Referenceに答えがありました。やっぱ公式Reference大事です。。本当に

By default, AddToAny's page.js script initializes & renders all AddToAny HTML instances when the document is ready.

AddToAny JavaScript functions can be used to initialize & render new AddToAny HTML instances inserted after the document is ready.

The a2a.init_all() function is often used after content insertion via Ajax.

つまり普通にarchive.phpとかsingle.phpで呼び出せばちゃんと初期化して表示するんだけど、Ajaxみたいに後から読み込む場合は初期化&描画する関数a2a.init_all()用意したから実行してね、とのこと。実行はAjax responce受け取って描画した後に挿入したら行けました。

ajax-get-posts.js
function addPosts() {
    if(!flag) {
        flag = true;
        $.ajax({
            type: "POST",
            url: ajaxurl,
            data: {
                action: 'my_get_post_data',
                post_num_now: postNumNow,
                post_num_add: postNumAdd
            },
            success: function(response) {
                let $postWrap = $('<div class="post_wrap"></div>');
                $('.posts').append($postWrap);
                $postWrap.append(response);
                a2a.init_all();    // ← ここです!!
                $postWrap.fadeIn(800);
                postNumNow += postNumAdd;
                flag = false;
            }
        });
    }
}

終わり

ちょっとニッチな内容でしたが誰かの助けになると良いですね:) ここまで読んでくださってありがとうございます。何かご指摘あったらどしどしお寄せください。

2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1