はじめに
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は
<?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を指定することができる。
$.ajax({
type: 'POST',
url: ajaxurl,
data: {
action: 'my_ajax_action',
},
success: function(res) {
// 成功時の処理
}
});
ここでのmy_ajax_action
が自分で登録したactionになる。登録は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を用いた投稿読み込みのサンプル
一応サンプルを示しておく。
<?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;
}
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
を挿入したい時。
例えば
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
にアクセスできないので、自前でショートコードを登録必要があるとのこと。(今回はこれに関しては大丈夫だったので解決されたのかな??もしくは特定の条件下で起きるのか...要検証)
念のためコードを載せておく。
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受け取って描画した後に挿入したら行けました。
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;
}
});
}
}
終わり
ちょっとニッチな内容でしたが誰かの助けになると良いですね:) ここまで読んでくださってありがとうございます。何かご指摘あったらどしどしお寄せください。