JavaScriptとWordPress(PHP)で通信して値を返すサンプル

広告:ページ内にてアフィリエイト広告を利用しています。

JavaScript から PHP に通信するサンプル

JavaScript だけでは処理が足りずサーバー側(PHP)で処理したい場合があります。しかし、どう作ればよいか、またセキュリティが満たされているか心配ですね。

ポイント

本記事では、

JavaScript と WordPress(PHP)で通信して値を返す(表示する)方法を解説します。

サンプルコードあります。

\自宅でする副業で月に〇万円の収入増があると嬉しすぎる!/

ココナラ副業を始めよう

実際に4か月でプラチナランク(売り上げ10万円以上)を達成した筆者が、ココナラで成功する方法を詳しく解説します。こちら をクリックしてください

目次
PR

サンプルコードで実際に作ってみる!

サンプルコードです。こちらを後述の手順に沿って設置することで実際に動かすことができます。

実際のサンプルコードを紹介します。こちらは、赤と青のボタンを配置して、クリックしたらサーバー側(PHP)に通信して「赤を押したね」「青を押したね」のレスポンスを返して画面上に表示するサンプルです。

上記のようなボタンが出ます(上記はイメージなので動きません)

サンプルコード

サンプルコード

■ PHP 側(サーバー側)

PHP 側のサンプルコードです。WordPress では functions.php などに張り付けて利用します。一般的に必要なセキュリティ対策を入れています。

/* --- [1] ショートコード: [color_press_inline] --- */
add_shortcode('color_press_inline', function () {
    $ajax_url = admin_url('admin-ajax.php');
    $nonce    = wp_create_nonce('color_press'); // CSRF対策

    // 同一ページに複数設置してもOK(個別のnonceとデータ属性を持たせる)
    if (function_exists('wp_unique_id')) {
        $id = wp_unique_id('color-press-');
    } else {
        $id = 'color-press-' . wp_rand();
    }

    ob_start(); ?>
    <div id="<?php echo esc_attr($id); ?>" class="color-press"
         data-ajax-url="<?php echo esc_url($ajax_url); ?>"
         data-nonce="<?php echo esc_attr($nonce); ?>">
      <button type="button" data-color="red"  aria-label="赤ボタン">赤</button>
      <button type="button" data-color="blue" aria-label="青ボタン">青</button>
      <p class="color-press__msg" aria-live="polite"></p>
    </div>

    <style>
      .color-press button{padding:.6rem 1rem;margin-right:.5rem;border:0;border-radius:.5rem;cursor:pointer}
      .color-press [data-color="red"]{background:#e11;color:#fff}
      .color-press [data-color="blue"]{background:#16f;color:#fff}
      .color-press__msg{margin-top:.5rem}
    </style>
    <?php
    return ob_get_clean();
});

/* --- [2] AJAXハンドラ(未ログインOK) --- */
add_action('wp_ajax_color_press',        'fumi_color_press_handle');
add_action('wp_ajax_nopriv_color_press', 'fumi_color_press_handle');

function fumi_color_press_handle(){
    // [a] メソッド制限
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
        wp_send_json_error(['message' => 'method not allowed'], 405);
    }

	// [a1] ペイロードサイズ上限(例:2KB)
    $clen = isset($_SERVER['CONTENT_LENGTH']) ? (int) $_SERVER['CONTENT_LENGTH'] : 0;
    if ($clen > 2048) {
        wp_send_json_error(['message' => 'payload too large'], 413); // 413 Payload Too Large
    }
	
    // [b] ノンス検証(CSRF)
    $nonce = $_POST['nonce'] ?? '';
    if (!wp_verify_nonce($nonce, 'color_press')) {
        wp_send_json_error(['message' => 'invalid nonce'], 403);
    }

    // [c] オリジン/リファラ確認(ヘッダがあれば検証)
    $site_host = wp_parse_url(home_url(), PHP_URL_HOST);
    if (!empty($_SERVER['HTTP_ORIGIN'])) {
        $origin_host = wp_parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
        if ($origin_host !== $site_host) {
            wp_send_json_error(['message' => 'bad origin'], 403);
        }
    } else {
        $ref = wp_get_referer();
        if ($ref) {
            $ref_host = wp_parse_url($ref, PHP_URL_HOST);
            if ($ref_host !== $site_host) {
                wp_send_json_error(['message' => 'bad referer'], 403);
            }
        }
    }

    // [d] 簡易レート制限(IPごと)
    $ip  = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    $key = 'color_press_rl_' . md5($ip);
    $cnt = (int) get_transient($key);
    if ($cnt > 30) { // 1分に31回超ならブロック
        wp_send_json_error(['message' => 'too many requests'], 429);
    }
    set_transient($key, $cnt + 1, 60);

    // [e] 入力ホワイトリスト
    $color = isset($_POST['color']) ? sanitize_key($_POST['color']) : '';
    if ($color === 'red') {
        $code = 1; $label = '赤';
    } elseif ($color === 'blue') {
        $code = 2; $label = '青';
    } else {
        wp_send_json_error(['message' => 'invalid color'], 400);
    }

    // [f] 応答
    wp_send_json_success([
        'code'  => $code,
        'label' => $label,
        'text'  => sprintf('%sを押したね', $label),
    ]);
}

■ JavaScript 側(画面側)

JavaScript 側のサンプルコードです。WordPress では固定ページや投稿ページに「カスタムHTML」ブロックで張り付けて利用できます。

<script>
(function(init){
  if (document.readyState === 'loading') {
    document.addEventListener('DOMContentLoaded', init);
  } else { init(); }
})(function(){
  document.querySelectorAll('.color-press').forEach(function(wrap){
    var msg     = wrap.querySelector('.color-press__msg');
    var ajaxUrl = wrap.getAttribute('data-ajax-url');
    var nonce   = wrap.getAttribute('data-nonce');

    wrap.addEventListener('click', function(e){
      var btn = e.target.closest('[data-color]');
      if (!btn || !wrap.contains(btn)) return;

      var color = btn.getAttribute('data-color');  // "red" | "blue"
      if (msg) msg.textContent = '送信中…';

      // 連打防止(任意)
      var prevDisabled = btn.disabled;
      btn.disabled = true;

      var body = new URLSearchParams();
      body.append('action', 'color_press');
      body.append('nonce',  nonce);
      body.append('color',  color);

      fetch(ajaxUrl, {
        method: 'POST',
        headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
        body: body.toString(),
        credentials: 'same-origin',
        cache: 'no-store'
      })
      .then(function(r){ return r.ok ? r.json() : Promise.reject(new Error('HTTP ' + r.status)); })
      .then(function(json){
        if (json && json.success) {
          if (msg) msg.textContent = json.data.text; // 例:「赤/青を押したね」
          // 数値 (1/2) を使いたい場合: json.data.code
        } else {
          var m = json && json.data && (json.data.message || json.data.text);
          if (msg) msg.textContent = 'エラー:' + (m || 'unknown');
        }
      })
      .catch(function(err){
        if (msg) {
          // ノンス切れ等の案内
          var hint = (err.message.indexOf('403') !== -1) ? '(ページを再読み込みしてください)' : '';
          msg.textContent = '通信エラー:' + err.message + hint;
        }
      })
      .finally(function(){
        btn.disabled = prevDisabled;
      });
    });
  });
});
</script>

実装方法

実装方法

■ PHP 側(サーバー側)

 functions.php などに張り付けて利用

WordPress の functions.php に PHP のコードをそのまま張り付けて保存します。

注意

PHP が古い場合、またはサーバー側の WAF の設定によっては保存時にエラーになる場合があります。

■ JavaScript 側(画面側)

投稿ページ(または固定ページ)側の実装です。

  • ショートコード(今回の場合は PHP 内で作成している「color_press_inline」を貼り付けます。
  • 「カスタムHTML」ブロックを用いて、JavaScript をすべて貼り付けます。

保存して実行すると、サンプルが動きます。

サンプルコードの解説

PHP 側(サーバー側)

PHP 側解説

ショートコード実装

/* --- [1] ショートコード: [color_press_inline] --- */
add_shortcode('color_press_inline', function () {
    $ajax_url = admin_url('admin-ajax.php');
    $nonce    = wp_create_nonce('color_press'); // CSRF対策

    // 同一ページに複数設置してもOK(個別のnonceとデータ属性を持たせる)
    if (function_exists('wp_unique_id')) {
        $id = wp_unique_id('color-press-');
    } else {
        $id = 'color-press-' . wp_rand();
    }

    ob_start(); ?>
    <div id="<?php echo esc_attr($id); ?>" class="color-press"
         data-ajax-url="<?php echo esc_url($ajax_url); ?>"
         data-nonce="<?php echo esc_attr($nonce); ?>">
      <button type="button" data-color="red"  aria-label="赤ボタン">赤</button>
      <button type="button" data-color="blue" aria-label="青ボタン">青</button>
      <p class="color-press__msg" aria-live="polite"></p>
    </div>

    <style>
      .color-press button{padding:.6rem 1rem;margin-right:.5rem;border:0;border-radius:.5rem;cursor:pointer}
      .color-press [data-color="red"]{background:#e11;color:#fff}
      .color-press [data-color="blue"]{background:#16f;color:#fff}
      .color-press__msg{margin-top:.5rem}
    </style>
    <?php
    return ob_get_clean();
});
  • admin-ajax.php の絶対URLを生成しクライアント側へ連携します
  • nonce は CSRF防止の今回限りの時限トークンの発行です。ページを開いたユーザーのブラウザに埋めこみ、送信時に一緒にPOSTすることで、サーバー側で wp_verify_nonce() で送信元の正誤を判定します。
  • wp_unique_id() を用いて、各ブロックをユニークIDで識別できるように実装します(同じページ内に何個でも置ける)
  • HTML(ボタン部分)とCSSもPHPから返しています。時限トークンと重複防止用のコードを埋め込むためPHP側でコードを実装しています(”<?php echo esc_url($ajax_url); ?>”、”<?php echo esc_attr($nonce); ?>”>)

fumi_color_press_handle() にルーティング

/* --- [2] AJAXハンドラ(未ログインOK) --- */
add_action('wp_ajax_color_press',        'fumi_color_press_handle');
add_action('wp_ajax_nopriv_color_press', 'fumi_color_press_handle');

WordPress のログインに関係なく(どちらでも)、admin-ajax に action=color_press で届いたリクエストを fumi_color_press_handle() にルーティングする設定です。

  • admin-ajax:フロント/管理画面からのAJAXを受けるためのWordPress標準エンドポイント(URLは …/wp-admin/admin-ajax.php だが、ログイン不要でも叩ける入口)です。
  • action=color_press:送信パラメータで「どの処理を呼ぶか」を指定する合図。WordPressはこれを見て wp_ajax_color_press(ログイン時)または wp_ajax_nopriv_color_press(未ログイン時)フックを発火し、登録した fumi_color_press_handle() を呼びだします。

リクエストのチェック

    // [a] メソッド制限
    if (($_SERVER['REQUEST_METHOD'] ?? '') !== 'POST') {
        wp_send_json_error(['message' => 'method not allowed'], 405);
    }

	// [a1] ペイロードサイズ上限(例:2KB)
    $clen = isset($_SERVER['CONTENT_LENGTH']) ? (int) $_SERVER['CONTENT_LENGTH'] : 0;
    if ($clen > 2048) {
        wp_send_json_error(['message' => 'payload too large'], 413); // 413 Payload Too Large
    }

「入口で不正リクエストを即切り」してガードしています。

  • $_SERVER[‘REQUEST_METHOD’] を見て POST以外(GET/HEAD/PUT 等)を 405 で拒否し、想定外の叩き方や余計な処理実行を防ぎます。
  • CONTENT_LENGTH から本文サイズを取得し、2KB超は 413(Payload Too Large) を返して遮断します。これにより、JavaScript やリクエストを改ざんして、長文のリクエストを送信する巨大POSTによるリソース消費(DoS)攻撃を防いでいます。

ノンスの検証

    // [b] ノンス検証(CSRF)
    $nonce = $_POST['nonce'] ?? '';
    if (!wp_verify_nonce($nonce, 'color_press')) {
        wp_send_json_error(['message' => 'invalid nonce'], 403);
    }

CSRF対策です。ページ表示時にサーバーが発行した時限トークン(nonce)を、POSTのnonceから取り出して検証しています。wp_verify_nonce($nonce, ‘color_press’)が失敗したら、実際のページ由来でない送信や期限切れと判断し、403 ForbiddenのJSONを返して処理を即終了します。

オリジン/リファラ確認

    // [c] オリジン/リファラ確認(ヘッダがあれば検証)
    $site_host = wp_parse_url(home_url(), PHP_URL_HOST);
    if (!empty($_SERVER['HTTP_ORIGIN'])) {
        $origin_host = wp_parse_url($_SERVER['HTTP_ORIGIN'], PHP_URL_HOST);
        if ($origin_host !== $site_host) {
            wp_send_json_error(['message' => 'bad origin'], 403);
        }
    } else {
        $ref = wp_get_referer();
        if ($ref) {
            $ref_host = wp_parse_url($ref, PHP_URL_HOST);
            if ($ref_host !== $site_host) {
                wp_send_json_error(['message' => 'bad referer'], 403);
            }
        }
    }

リクエストが自サイト(同一ホスト)から来たかをヘッダで確認する防御です。

  • home_url() から自サイトのホスト名を取得。Origin ヘッダがあればそのホストを取り出し、一致しなければ 403(bad origin)を返す。
  • Origin が無い場合は Referer を代替的に確認し、不一致なら 403(bad referer)を返す。

ここでクロスサイトからの不正POST(CSRFや外部ページ経由の叩き)を追加的にブロックします。

簡易レート制限(IPごと)

    // [d] 簡易レート制限(IPごと)
    $ip  = $_SERVER['REMOTE_ADDR'] ?? '0.0.0.0';
    $key = 'color_press_rl_' . md5($ip);
    $cnt = (int) get_transient($key);
    if ($cnt > 30) { // 1分に31回超ならブロック
        wp_send_json_error(['message' => 'too many requests'], 429);
    }
    set_transient($key, $cnt + 1, 60);

1分あたりの呼び出し回数をIP単位で制限している処理です。REMOTE_ADDR をキー(color_press_rl_…)にして Transient にカウントを60秒保持し、毎回+1。読み出し値が >30(=31回目)なら HTTP 429 (Too Many Requests) を返してブロックします。スパム連打やボット負荷を緩和する目的です。

入力ホワイトリスト

    // [e] 入力ホワイトリスト
    $color = isset($_POST['color']) ? sanitize_key($_POST['color']) : '';
    if ($color === 'red') {
        $code = 1; $label = '赤';
    } elseif ($color === 'blue') {
        $code = 2; $label = '青';
    } else {
        wp_send_json_error(['message' => 'invalid color'], 400);
    }

color パラメータを受け取り、まず sanitize_key() で英小文字・数字・-_以外を除去&小文字化します。そのうえで red / blue のみ許可(ホワイトリスト)。一致したら内部用の数値 1 / 2 と表示ラベル(赤/青)を確定し、どれにも当たらなければ 400(invalid color)で即終了。期待しているリクエストのみ許容し、改ざん文字列やスクリプト混入をここで遮断します。

応答

    // [f] 応答
    wp_send_json_success([
        'code'  => $code,
        'label' => $label,
        'text'  => sprintf('%sを押したね', $label),
    ]);

wp_send_json_success() で HTTP 200 + JSON を返し、処理を終了します(Content-Type: application/json となる)。

返却データ

  • code:内部用数値(1 or 2)
  • label:表示ラベル(赤/青)
  • text:ユーザー表示文(例「赤を押したね」)

フロント側の JavaScript は json.success === true を確認し、この text を画面に出します。

JavaScript 側(画面側)

JS 側解説

※コードは上記サンプルを参照

JavaScript 側ではページ読込後に各 「.color-press」 ブロックを初期化し、ボタンクリックを検知しています。

クリック時、data-ajax-url(Ajax のURL) と data-nonce(時短トークン)、押下色(data-color)を取得し、「送信中…」表示した後、念のため連打防止で一時 disabled を入れています。URLSearchParams で action = color_press / nonce / color を組み、admin-ajax へ(同一オリジン Cookie送信・キャッシュ無効にしつつ) POST します。

成功時は返却されたテキストを表示します。失敗時はエラー文を表示し、403なら「再読み込み」ヒントを出しています。

実際に送信している場所

var body = new URLSearchParams();
body.append('action', 'color_press');
body.append('nonce',  nonce);
body.append('color',  color);

fetch(ajaxUrl, {
  method: 'POST',
  headers: {'Content-Type': 'application/x-www-form-urlencoded; charset=UTF-8'},
  body: body.toString(),
  credentials: 'same-origin',
  cache: 'no-store'
})

実際にパラメータを作成し送信している処理は、fetch(ajaxUrl……の部分です。

送信されるリクエスト例

POST https://boonboonblog.com/wp-admin/admin-ajax.php
Content-Type: application/x-www-form-urlencoded; charset=UTF-8
Cookie: (必要なら同一サイトのCookieが付与されます) // credentials:’same-origin’ のため

action=color_press&nonce=18ba35856a&color=red

サーバーからの成功レスポンス例(JSON)

{
“success”: true,
“data”: {
“code”: 1,
“label”: “赤”,
“text”: “赤を押したね”
}
}

まとめ:JavaScriptとWordPress(PHP)で通信して値を返すサンプル

WordPress で 赤 / 青ボタンを押すと、admin-ajax にフォーム POST し、PHPハンドラが色に応じて値(1 / 2)を返し、JavaScript 側がレスポンスを受け取って「○○を押したね」と表示するサンプルです。HTML/CSS+nonce/URLはショートコードにて埋め込み、JavaScript はページに直貼りで動きます。サーバ側はPOST限定・サイズ上限・nonce検証・Origin/Referer 確認・値のホワイトリスト・レート制限で一般的なセキュリティ対策を実装しています。

サンプルの構成

  • ショートコード:UIと data-ajax-url / data-nonce を出力
  • インラインJS:fetch() で admin-ajax へPOSTし、結果を表示
  • PHPハンドラ:検証→数値(1/2)と文言をJSONで返却

導入手順

  • functions.php にショートコード&ハンドラを追加
  • ページ本文にショートコード 「color_press_inline」 を挿入
  • 同ページにJSをべた貼りする

セキュリティ

  • POST以外は 405、サイズ上限(例2KB)で 413 を返す
  • wp_verify_nonce() によるCSRF対策 (403) を実施
  • Origin/Referer一致チェック (403) を実施
  • sanitize_key()+red|blue ホワイトリスト(400) を実施
  • IPあたり1分で30回以内限定(429) を実施
  • 表示は textContent(反射XSS回避)を実施

実装のコツ

  • 対象ページはフルページキャッシュ除外(nonce期限切れ防止)にする必要があります
  • 同一ページ複数配置OK(ユニークID対応)にするほうが想定外のエラー(うっかり重複配置)を防げます

以上で、JavaScriptとWordPress(PHP)で通信して値を返すサンプル完成です。

40代・50代「会社員におすすめ」の在宅でできる副業5選

20代・30代「専業主婦におすすめ」の在宅でできる内職・副業3選

地方がチャンスのおすすめ副業を紹介!

この副業
アフィリエイトスクール
ノートパソコン

ブログの作り方などについてココナラにて「支援作業」を販売しております。

よかったらご利用くださいませ。

もっと WordPress のノウハウを知りたいときは
クリックアイコン
どんどん情報局

本サイトは「どんどん情報局」が運営しています。

著作者:Boon ☆

どんどん情報局はメディア記事の執筆を通して世の中に有益な情報を発信することを心がけています。

「どんどん情報局」の紹介はこちら

PR

広告の設置・収入について

当サイトは Amazonのアソシエイトとして、適格販売により収入を得ています。

当サイトは Google アドセンスを利用し、広告により収入を得ています。

当サイトは ASP が提供するサービスを利用し、広告、適格販売により収入を得ています。

電気通信事業法改正に伴う表記

目次