WordPress関数一覧まとめ【Part3】Ajax/REST API・セキュリティ・キャッシュ・外部API連携完全ガイド

WordPress関数大全 WordPress

モダンなWordPressプラグインでは、非同期通信(Ajax/REST API)が欠かせません。「いいね」ボタン、無限スクロール、管理画面での非同期保存、外部サービスとの連携など、ユーザー体験を向上させる多くの機能が非同期通信で実現されています。

しかし、非同期機能が増えるほど、セキュリティ設計がボトルネックになります。外部からリクエストを受け付ける機能は、悪意のある攻撃者にとって格好のターゲットだからです。

この記事では、admin-ajax.php方式とREST API方式の両方について、「どちらを選ぶべきか」から「安全に実装するパターン」まで、関数ベースで徹底的に解説します。

この記事はWordPress関数一覧まとめの3部構成のPart3です。Part1ではテーマ制作、Part2ではプラグインの設定画面を解説しています。

  1. 0. まず結論:admin-ajax と REST API の使い分け
    1. admin-ajax.php を選ぶケース
    2. REST API を選ぶケース
    3. 共通して守るべきこと
  2. 1. Ajax(admin-ajax.php)でよく使う関数
    1. 1-1. add_action( ‘wp_ajax_{action}’, ‘callback’ )
    2. 1-2. add_action( ‘wp_ajax_nopriv_{action}’, ‘callback’ )
    3. 1-3. check_ajax_referer( $action, $query_arg, $die )
    4. 1-4. wp_send_json_success() / wp_send_json_error()
    5. 1-5. wp_localize_script()|JavaScriptへPHPの値を渡す
  3. 2. REST APIでよく使う関数(register_rest_route)
    1. 2-1. add_action( ‘rest_api_init’, function(){ … } )
    2. 2-2. register_rest_route( $namespace, $route, $args )
    3. 2-3. permission_callback(最重要)
    4. 2-4. 返り値:配列 / WP_REST_Response / WP_Error
    5. URLパラメータとルートパターン
  4. 3. セキュリティの型(nonce・権限・サニタイズ)
    1. セキュリティチェックの順序
    2. よく使うサニタイズ関数
    3. nonce生成:wp_create_nonce()
    4. REST APIでのnonce
  5. 4. 外部API通信:HTTP API(wp_remote_*)
    1. wp_remote_get() / wp_remote_post()
    2. is_wp_error()
    3. 外部APIを扱う際の心構え
  6. 5. キャッシュ:Transients と Object Cache
    1. set_transient() / get_transient() / delete_transient()
    2. 時間定数
    3. キャッシュキー戦略
    4. キャッシュの一括無効化
  7. 6. Cron / 重い処理の非同期化
    1. wp_schedule_event() / wp_next_scheduled() / wp_clear_scheduled_hook()
    2. wp_schedule_single_event()
    3. WP-Cronの制限と対策
  8. 7. デバッグとログ(トラブルシューティング)
    1. error_log()
    2. WP_DEBUG / WP_DEBUG_LOG
    3. wp_die()
    4. デバッグのチェックポイント
  9. 8. まとめ:壊れない非同期機能の共通点
    1. 入口の守りが固い
    2. レスポンス形式が統一されている
    3. 重い処理を直接叩かない
    4. 外部APIを信頼しない
    5. ログが残る
    6. 最後に

0. まず結論:admin-ajax と REST API の使い分け

WordPressで非同期通信を実装する方法は、大きく分けて2つあります。どちらを選ぶべきか迷ったときは、以下の基準で判断すると良いでしょう。

admin-ajax.php を選ぶケース

  • 古くからの定番で実装がシンプル
  • ログイン必須の管理系機能
  • 既存のプラグインやテーマとの互換性維持
  • 小規模な機能で、RESTの設計までは不要な場合

REST API を選ぶケース

  • 設計が明確でエンドポイントの構造が綺麗
  • フロントエンド(React、Vue等)との連携
  • 外部アプリケーションやサービスとの連携
  • ブロックエディタ(Gutenberg)との統合
  • 将来的な拡張性を重視する場合

共通して守るべきこと

どちらの方式でも、セキュリティ対策は同じです。違いは「入口(エンドポイント)」が違うだけで、守るべき安全策は共通しています:

  • nonce検証(CSRF対策)
  • 権限チェック
  • 入力値のサニタイズ
  • 出力時のエスケープ

1. Ajax(admin-ajax.php)でよく使う関数

admin-ajax.phpは、WordPressに最初から用意されているAjax処理の仕組みです。フォームデータを/wp-admin/admin-ajax.phpにPOST(またはGET)することで、PHPの処理を非同期に呼び出せます。

1-1. add_action( ‘wp_ajax_{action}’, ‘callback’ )

目的:ログインユーザー向けのAjaxエンドポイントを登録する

このアクションフックは、ログイン済みユーザーからのリクエストのみを処理します。管理画面での設定保存、ユーザー固有のデータ操作など、認証が必要な機能に使用します。

{action}の部分は、JavaScriptから送信するaction名と一致させます。たとえばwp_ajax_myplugin_save_settingsと登録した場合、JavaScript側ではaction: 'myplugin_save_settings'を送信します。

// PHPでエンドポイントを登録
add_action( 'wp_ajax_myplugin_toggle_favorite', 'myplugin_toggle_favorite' );

function myplugin_toggle_favorite() {
  // nonce検証
  check_ajax_referer( 'myplugin_nonce', 'nonce' );
  
  // 権限チェック
  if ( ! current_user_can( 'read' ) ) {
    wp_send_json_error( array( 'message' => '権限がありません' ), 403 );
  }
  
  // 処理を実行
  $post_id = absint( $_POST['post_id'] ?? 0 );
  $result = myplugin_do_toggle_favorite( $post_id, get_current_user_id() );
  
  // 結果を返す
  if ( $result ) {
    wp_send_json_success( array( 'status' => 'favorited' ) );
  } else {
    wp_send_json_error( array( 'message' => '処理に失敗しました' ), 500 );
  }
}

1-2. add_action( ‘wp_ajax_nopriv_{action}’, ‘callback’ )

目的:未ログインユーザーも含めたAjaxエンドポイントを登録する

noprivは「no privileges(権限なし)」の略で、未ログインユーザーからのリクエストも受け付けるエンドポイントです。公開されたフォームの送信処理、投票機能、問い合わせフォームなどに使用します。

重要な注意点:このエンドポイントは「公開API」に近い存在です。誰でもリクエストを送信できるため、入力チェック、レート制限、スパム対策がより重要になります。

// ログインユーザーと未ログインユーザーの両方に対応
add_action( 'wp_ajax_myplugin_submit_form', 'myplugin_submit_form' );
add_action( 'wp_ajax_nopriv_myplugin_submit_form', 'myplugin_submit_form' );

function myplugin_submit_form() {
  // nonce検証は公開フォームでも必須
  check_ajax_referer( 'myplugin_form_nonce', 'nonce' );
  
  // 入力値のサニタイズ
  $name = sanitize_text_field( $_POST['name'] ?? '' );
  $email = sanitize_email( $_POST['email'] ?? '' );
  $message = sanitize_textarea_field( $_POST['message'] ?? '' );
  
  // バリデーション
  if ( empty( $name ) || empty( $email ) || empty( $message ) ) {
    wp_send_json_error( array( 'message' => '必須項目を入力してください' ), 400 );
  }
  
  // 処理を実行
  // ...
  
  wp_send_json_success( array( 'message' => '送信しました' ) );
}

1-3. check_ajax_referer( $action, $query_arg, $die )

目的:Ajaxリクエストのnonce検証を行う(CSRF対策)

CSRF(クロスサイトリクエストフォージェリ)攻撃を防ぐための関数です。第1引数はnonce生成時に使用したアクション名、第2引数はリクエストパラメータ名です。

検証に失敗した場合、デフォルトではwp_die()が実行されてリクエストが終了します。第3引数にfalseを渡すと、戻り値(成功なら12、失敗ならfalse)で判定できます。

// デフォルト:検証失敗時は処理が終了する
check_ajax_referer( 'myplugin_nonce', 'nonce' );

// 戻り値で判定したい場合
$result = check_ajax_referer( 'myplugin_nonce', 'nonce', false );
if ( $result === false ) {
  wp_send_json_error( array( 'message' => 'セキュリティトークンが無効です' ), 403 );
}

1-4. wp_send_json_success() / wp_send_json_error()

目的:JSON形式でレスポンスを返してリクエストを終了する

これらの関数は、適切なHTTPヘッダーを設定し、JSON形式のレスポンスを出力して、スクリプトの実行を終了します。手動でjson_encode()header()を書く必要がなく、統一されたレスポンス形式を提供できます。

// 成功時
wp_send_json_success( array(
  'message' => '保存しました',
  'id' => $new_id,
) );
// 出力: {"success":true,"data":{"message":"保存しました","id":123}}

// 失敗時(第2引数でHTTPステータスコードを指定可能)
wp_send_json_error( array(
  'message' => '入力値が不正です',
  'errors' => $validation_errors,
), 400 );
// 出力: {"success":false,"data":{"message":"入力値が不正です","errors":[...]}}

1-5. wp_localize_script()|JavaScriptへPHPの値を渡す

目的:Ajax URL、nonce、その他の設定値をJavaScriptで使えるようにする

JavaScript側でAjaxリクエストを送信するには、admin-ajax.phpのURLとnonceが必要です。これらの値はPHP側でしか生成できないため、wp_localize_script()を使ってJavaScriptのグローバル変数として渡します。

// PHP側(functions.php またはプラグインファイル)
add_action( 'wp_enqueue_scripts', function() {
  wp_enqueue_script(
    'myplugin-script',
    plugin_dir_url( __FILE__ ) . 'assets/js/app.js',
    array( 'jquery' ),
    '1.0.0',
    true
  );
  
  wp_localize_script( 'myplugin-script', 'MyPluginSettings', array(
    'ajaxUrl' => admin_url( 'admin-ajax.php' ),
    'nonce'   => wp_create_nonce( 'myplugin_nonce' ),
    'postId'  => get_the_ID(),
    'strings' => array(
      'confirm' => 'よろしいですか?',
      'success' => '完了しました',
    ),
  ) );
});
// JavaScript側(app.js)
jQuery(document).ready(function($) {
  $('.favorite-button').on('click', function() {
    $.ajax({
      url: MyPluginSettings.ajaxUrl,
      type: 'POST',
      data: {
        action: 'myplugin_toggle_favorite',
        nonce: MyPluginSettings.nonce,
        post_id: MyPluginSettings.postId
      },
      success: function(response) {
        if (response.success) {
          alert(MyPluginSettings.strings.success);
        } else {
          alert(response.data.message);
        }
      }
    });
  });
});

2. REST APIでよく使う関数(register_rest_route)

WordPress REST APIは、WordPress 4.7から標準搭載された機能です。/wp-json/以下にエンドポイントを定義し、HTTPメソッド(GET、POST、PUT、DELETE等)に応じた処理を行います。

admin-ajax.phpと比較して、以下の特徴があります:

  • RESTfulな設計思想に基づいている
  • HTTPメソッドでアクションを区別する
  • 名前空間でエンドポイントを整理できる
  • ブロックエディタや外部アプリとの連携が容易

2-1. add_action( ‘rest_api_init’, function(){ … } )

目的:REST APIエンドポイントを登録するタイミングを指定する

RESTルートの登録は、rest_api_initアクションフック内で行います。WordPressがREST APIを初期化する適切なタイミングで実行されます。

2-2. register_rest_route( $namespace, $route, $args )

目的:RESTエンドポイントを登録する

第1引数の$namespaceはプラグイン識別子とバージョンを組み合わせた名前空間(例:myplugin/v1)、第2引数の$routeはエンドポイントのパス、第3引数でメソッド、コールバック、権限チェック等を指定します。

add_action( 'rest_api_init', function() {
  
  // GETエンドポイント:ステータス取得
  register_rest_route( 'myplugin/v1', '/status', array(
    'methods'             => 'GET',
    'callback'            => function( WP_REST_Request $request ) {
      return array(
        'ok'   => true,
        'time' => current_time( 'mysql' ),
      );
    },
    'permission_callback' => '__return_true', // 誰でもアクセス可能
  ) );
  
  // POSTエンドポイント:設定保存
  register_rest_route( 'myplugin/v1', '/settings', array(
    'methods'             => 'POST',
    'callback'            => 'myplugin_save_settings',
    'permission_callback' => function() {
      return current_user_can( 'manage_options' );
    },
    'args' => array(
      'enabled' => array(
        'required' => true,
        'type'     => 'boolean',
      ),
      'limit' => array(
        'required'          => false,
        'type'              => 'integer',
        'default'           => 10,
        'sanitize_callback' => 'absint',
      ),
    ),
  ) );
  
});

2-3. permission_callback(最重要)

目的:エンドポイントへのアクセス権限を制御する

permission_callbackは、REST APIのセキュリティにおいて最も重要な設定です。このコールバックがtrueを返した場合のみ、メインのコールバックが実行されます。

絶対に守るべきルール:

  • 権限チェックが不要な公開エンドポイントでも、必ず'permission_callback' => '__return_true'を明示する
  • データを変更するエンドポイント(POST、PUT、DELETE)は、必ず適切な権限チェックを行う
  • permission_callbackを省略すると、デバッグモードで警告が出る
// ログインユーザー限定
'permission_callback' => function() {
  return is_user_logged_in();
}

// 管理者限定
'permission_callback' => function() {
  return current_user_can( 'manage_options' );
}

// 投稿編集権限を持つユーザー限定
'permission_callback' => function( WP_REST_Request $request ) {
  $post_id = $request->get_param( 'id' );
  return current_user_can( 'edit_post', $post_id );
}

// 誰でもアクセス可能(公開エンドポイント)
'permission_callback' => '__return_true'

2-4. 返り値:配列 / WP_REST_Response / WP_Error

目的:レスポンスを適切な形式で返す

コールバック関数からは、以下のいずれかを返すことができます:

  • 配列:自動的にJSONに変換される(最もシンプル)
  • WP_REST_Response:HTTPステータスやヘッダーを細かく制御したい場合
  • WP_Error:エラーを返す場合(適切なHTTPステータスとメッセージが設定される)
// 成功:配列を返す(自動的にJSONに変換)
return array(
  'id' => $new_id,
  'message' => '作成しました',
);

// 成功:ステータスコードを指定
return new WP_REST_Response( array(
  'id' => $new_id,
), 201 ); // 201 Created

// エラー:WP_Errorを返す
if ( empty( $data ) ) {
  return new WP_Error(
    'invalid_data',           // エラーコード
    'データが不正です',         // メッセージ
    array( 'status' => 400 )   // ステータスコード
  );
}

URLパラメータとルートパターン

REST APIでは、URLパスの一部をパラメータとして取得できます。これにより、リソースのID等をURLに含めたRESTfulな設計が可能です。

// /wp-json/myplugin/v1/posts/123 のようなURLに対応
register_rest_route( 'myplugin/v1', '/posts/(?P\d+)', array(
  'methods'             => 'GET',
  'callback'            => function( WP_REST_Request $request ) {
    $post_id = $request->get_param( 'id' );
    $post = get_post( $post_id );
    
    if ( ! $post ) {
      return new WP_Error( 'not_found', '投稿が見つかりません', array( 'status' => 404 ) );
    }
    
    return array(
      'id'    => $post->ID,
      'title' => $post->post_title,
    );
  },
  'permission_callback' => '__return_true',
  'args' => array(
    'id' => array(
      'required' => true,
      'type'     => 'integer',
      'sanitize_callback' => 'absint',
    ),
  ),
) );

3. セキュリティの型(nonce・権限・サニタイズ)

非同期機能は「外部から叩かれる」機能です。だからこそ、入口の守りがすべてです。以下の順序でチェックを行うのが、安全な実装の「型」です。

セキュリティチェックの順序

  1. 権限チェックcurrent_user_can()またはis_user_logged_in()
  2. nonce検証check_ajax_referer()またはwp_verify_nonce()
  3. 入力値の整形sanitize_*関数群
  4. 期待条件の検証:存在確認、所有者確認、範囲チェック等
  5. 出力時のエスケープ:HTMLを返す場合はesc_*関数

よく使うサニタイズ関数

// テキストフィールド(1行)
$title = sanitize_text_field( $_POST['title'] ?? '' );

// テキストエリア(複数行)
$description = sanitize_textarea_field( $_POST['description'] ?? '' );

// メールアドレス
$email = sanitize_email( $_POST['email'] ?? '' );

// 整数(負の数は0になる)
$count = absint( $_POST['count'] ?? 0 );

// キー(英小文字、数字、ハイフン、アンダースコアのみ)
$key = sanitize_key( $_POST['key'] ?? '' );

// $_POST等に含まれる余分なスラッシュを除去
$raw = wp_unslash( $_POST['data'] );

nonce生成:wp_create_nonce()

目的:nonceトークンを生成する

nonceは「Number used ONCE」の略ですが、WordPressでは厳密な意味での使い捨てトークンではなく、一定時間有効なトークンです。CSRF攻撃を防ぐために使用します。

// nonce生成(PHPで生成してJSに渡す)
$nonce = wp_create_nonce( 'myplugin_action' );

// nonce検証(Ajax処理側)
if ( ! wp_verify_nonce( $_POST['nonce'], 'myplugin_action' ) ) {
  wp_send_json_error( array( 'message' => 'セキュリティエラー' ), 403 );
}

REST APIでのnonce

REST APIでも操作系(POST、PUT、DELETE等)のエンドポイントでは、nonceを使用することが推奨されます。WordPressのREST APIは、X-WP-Nonceヘッダーまたは_wpnonceパラメータでnonceを受け付けます。

// JavaScript側
fetch('/wp-json/myplugin/v1/settings', {
  method: 'POST',
  headers: {
    'Content-Type': 'application/json',
    'X-WP-Nonce': wpApiSettings.nonce  // wp_localize_scriptで渡す
  },
  body: JSON.stringify({ enabled: true })
});

4. 外部API通信:HTTP API(wp_remote_*)

外部サービスのAPIと連携する場合、PHPのfile_get_contents()cURLを直接使うのではなく、WordPressのHTTP APIを使用することをお勧めします。WordPress環境に最適化されており、プロキシ設定やSSL証明書の扱いも適切に処理されます。

wp_remote_get() / wp_remote_post()

目的:外部URLにHTTPリクエストを送信する

// GETリクエスト
$response = wp_remote_get( 'https://api.example.com/items', array(
  'timeout' => 10,  // タイムアウト(秒)
  'headers' => array(
    'Authorization' => 'Bearer ' . $api_token,
    'Accept'        => 'application/json',
  ),
) );

// エラーチェック
if ( is_wp_error( $response ) ) {
  error_log( 'API Error: ' . $response->get_error_message() );
  return false;
}

// HTTPステータスコード確認
$code = wp_remote_retrieve_response_code( $response );
if ( $code !== 200 ) {
  error_log( 'API returned status: ' . $code );
  return false;
}

// レスポンスボディを取得
$body = wp_remote_retrieve_body( $response );
$data = json_decode( $body, true );
// POSTリクエスト(JSONを送信)
$response = wp_remote_post( 'https://api.example.com/items', array(
  'timeout' => 15,
  'headers' => array(
    'Content-Type'  => 'application/json',
    'Authorization' => 'Bearer ' . $api_token,
  ),
  'body' => wp_json_encode( array(
    'name'  => $item_name,
    'price' => $price,
  ) ),
) );

is_wp_error()

目的:WP_Errorオブジェクトかどうかを判定する

HTTP APIの関数は、ネットワークエラーやタイムアウト時にWP_Errorオブジェクトを返します。必ずチェックしてから処理を続行してください。

if ( is_wp_error( $response ) ) {
  // エラーメッセージを取得
  $error_message = $response->get_error_message();
  
  // エラーコードを取得
  $error_code = $response->get_error_code();
  
  // ログに記録
  error_log( "HTTP Request failed [{$error_code}]: {$error_message}" );
  
  return false;
}

外部APIを扱う際の心構え

外部APIは「遅い・落ちる・仕様が変わる」ものです。これを前提に設計してください:

  • タイムアウト設定:デフォルトの5秒では短い場合もある。適切な値を設定
  • エラーハンドリング:4xx、5xx、タイムアウト、それぞれに適切な対応を
  • キャッシュ:同じリクエストを繰り返さないよう、Transientsでキャッシュ
  • リトライ:一時的なエラーの場合、リトライロジックを検討

5. キャッシュ:Transients と Object Cache

非同期処理で「毎回外部APIを叩く」「毎回重い集計クエリを実行する」ことを続けると、サイトはすぐに重くなります。WordPressの定番キャッシュ機構がTransients APIです。

set_transient() / get_transient() / delete_transient()

目的:有効期限付きのキャッシュを保存・取得・削除する

Transientsは、データベースのwp_optionsテーブルに保存される一時キャッシュです。有効期限を設定でき、期限切れのデータは自動的に無効になります。Object Cache(Redis、Memcached等)が有効な環境では、自動的にそちらを使用するため、さらに高速になります。

// キャッシュに保存(10分間有効)
set_transient( 'myplugin_api_data', $data, 10 * MINUTE_IN_SECONDS );

// キャッシュから取得
$cached = get_transient( 'myplugin_api_data' );

if ( $cached === false ) {
  // キャッシュがない、または期限切れ
  $data = myplugin_fetch_from_api();
  set_transient( 'myplugin_api_data', $data, 10 * MINUTE_IN_SECONDS );
} else {
  // キャッシュヒット
  $data = $cached;
}

// キャッシュを削除(設定変更時など)
delete_transient( 'myplugin_api_data' );

時間定数

WordPress には有効期限を指定するための便利な定数があります:

  • MINUTE_IN_SECONDS:60
  • HOUR_IN_SECONDS:3600
  • DAY_IN_SECONDS:86400
  • WEEK_IN_SECONDS:604800

キャッシュキー戦略

キャッシュで最も多い事故は、「キーが雑で、異なる条件のデータが混在する」ことです。キーには以下の要素を含めることで、衝突を防ぎます:

  • プラグイン名myplugin_
  • バージョン:仕様変更時に一括無効化するため
  • スコープ:マルチサイトならblog_id、ユーザー別ならuser_id
  • 条件:検索語、ページ番号、ソート順など
// キャッシュキー生成関数の例
function myplugin_cache_key( $prefix, $context = array() ) {
  $version = get_option( 'myplugin_cache_version', 1 );
  $blog_id = get_current_blog_id();
  
  $context = array_merge( array(
    'blog'    => $blog_id,
    'version' => $version,
  ), $context );
  
  return 'myplugin_' . $prefix . '_' . md5( wp_json_encode( $context ) );
}

// 使用例
$key = myplugin_cache_key( 'search_results', array(
  'query' => sanitize_text_field( $_GET['s'] ?? '' ),
  'page'  => max( 1, absint( $_GET['paged'] ?? 1 ) ),
) );

$data = get_transient( $key );
if ( $data === false ) {
  $data = myplugin_perform_search();
  set_transient( $key, $data, 10 * MINUTE_IN_SECONDS );
}

キャッシュの一括無効化

キャッシュキーにバージョン番号を含めておくと、設定変更時や大規模なデータ更新時に、バージョンを上げるだけで全キャッシュを無効化できます。

function myplugin_invalidate_all_cache() {
  $version = get_option( 'myplugin_cache_version', 1 );
  update_option( 'myplugin_cache_version', $version + 1 );
}

6. Cron / 重い処理の非同期化

レスポンスタイムに影響する重い処理は、ユーザーのリクエスト中に実行するのではなく、バックグラウンドで処理することを検討してください。

wp_schedule_event() / wp_next_scheduled() / wp_clear_scheduled_hook()

目的:定期実行するタスクを登録・確認・解除する

// プラグイン有効化時に登録
register_activation_hook( __FILE__, function() {
  if ( ! wp_next_scheduled( 'myplugin_hourly_task' ) ) {
    wp_schedule_event( time(), 'hourly', 'myplugin_hourly_task' );
  }
});

// タスク実行
add_action( 'myplugin_hourly_task', function() {
  // 重い処理をここで実行
  myplugin_sync_external_data();
  myplugin_cleanup_old_records();
});

// プラグイン無効化時に解除
register_deactivation_hook( __FILE__, function() {
  wp_clear_scheduled_hook( 'myplugin_hourly_task' );
});

wp_schedule_single_event()

目的:1回だけ実行するタスクをスケジュールする

即座には実行せず、指定時刻に1回だけ実行したいタスクに使用します。たとえば、データインポート完了後のメール通知などに適しています。

// 5分後に1回だけ実行
wp_schedule_single_event(
  time() + ( 5 * MINUTE_IN_SECONDS ),
  'myplugin_send_notification',
  array( $user_id, $message )  // 引数を渡せる
);

// タスクを受け取る
add_action( 'myplugin_send_notification', function( $user_id, $message ) {
  // 通知処理
}, 10, 2 );

WP-Cronの制限と対策

WP-Cronは「擬似Cron」であり、サーバーの本物のcronとは異なります。WordPressへのアクセスがあったときに初めてチェックが実行されるため、アクセスが少ないサイトではスケジュール通りに実行されないことがあります。

高い精度が求められる場合は、サーバーのcronで直接wp-cron.phpを叩く設定を検討してください:

# サーバーのcrontabに追加
*/5 * * * * wget -q -O - https://example.com/wp-cron.php?doing_wp_cron > /dev/null 2>&1

この場合、wp-config.phpでWP-Cronの自動実行を無効化します:

define( 'DISABLE_WP_CRON', true );

7. デバッグとログ(トラブルシューティング)

非同期処理のバグは発見しにくいものです。「通信が失敗しているのか」「権限で弾かれているのか」「nonceが期限切れなのか」を切り分けるだけで、問題解決の半分は終わります。

error_log()

目的:デバッグ情報をエラーログに出力する

// シンプルなメッセージ
error_log( 'myplugin: Processing started' );

// 変数の内容を出力
error_log( 'myplugin: Data = ' . print_r( $data, true ) );

// エラー情報を記録
if ( is_wp_error( $result ) ) {
  error_log( 'myplugin: Error - ' . $result->get_error_message() );
}

WP_DEBUG / WP_DEBUG_LOG

wp-config.phpで以下を設定すると、エラーがログファイルに記録されます:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );   // wp-content/debug.log に出力
define( 'WP_DEBUG_DISPLAY', false ); // 画面には表示しない(本番環境向け)

wp_die()

目的:処理を中断してメッセージを表示する

Ajax処理のデバッグ時に、途中経過を確認するために一時的に使用することがあります。

wp_die( print_r( $debug_data, true ) );

デバッグのチェックポイント

非同期処理がうまく動かないとき、以下の順序でチェックすると効率的です:

  1. リクエストは届いているか?:ブラウザの開発者ツール(Network)でリクエストを確認
  2. HTTPステータスは何か?:403なら権限、400ならバリデーション、500ならPHPエラー
  3. nonceは有効か?:生成時刻と現在時刻、アクション名の一致を確認
  4. 権限は正しいか?:ログイン状態とcapabilityを確認
  5. PHPエラーは出ていないか?:debug.logを確認

8. まとめ:壊れない非同期機能の共通点

Ajax/RESTを使った機能で「壊れにくい」ものには、共通した特徴があります:

入口の守りが固い

権限チェック、nonce検証、入力値バリデーションの3点セットが必ず存在します。どれか1つでも欠けると、セキュリティホールになります。

レスポンス形式が統一されている

成功時も失敗時も、一貫したJSON構造とHTTPステータスコードを返します。JavaScript側でのエラーハンドリングが容易になります。

重い処理を直接叩かない

Transientsでキャッシュ、Cronでバックグラウンド処理など、ユーザーのリクエストに重い処理を載せない工夫がされています。

外部APIを信頼しない

タイムアウト設定、エラーハンドリング、リトライ、フォールバックが考慮されています。外部サービスが落ちても、サイト全体が止まらない設計になっています。

ログが残る

問題発生時に原因を追跡できるよう、重要な処理には適切なログ出力が仕込まれています。

最後に

この3部構成の記事では、テーマ制作からプラグイン開発、非同期処理まで、WordPress開発に必要な関数を網羅的に解説しました。

重要なのは、これらの関数を「暗記する」ことではありません。「どんな場面で」「何を守りながら」「どう組み合わせるか」というパターンを身につけることです。

次のステップとして、あなたのプラグインやテーマの仕様に合わせて、ここで紹介したパターンを実装してみてください。実際のコードを書くことで、理解が深まるはずです。

コメント

タイトルとURLをコピーしました