• wp_send_json_success()とwp_send_json_error()はsuccessの真偽とdataを分けて返す

wp_send_json_success()とwp_send_json_error()はsuccessの真偽とdataを分けて返す

公開日: 執筆:佐藤

WordPressのAjax処理からJSONを返すなら、成功時はwp_send_json_success()、失敗時はwp_send_json_error()を使います。JavaScript側は、最初にsuccessの真偽を確認し、その結果に応じてdataを読みます。

この二つの関数は、JSONを出力した後にPHPの処理を終了します。関数を呼んだ後へ別のHTMLや文字列を出力しないでください。返却形式を一つに決めることで、保存、検証、権限不足などの結果を同じ順序で処理できます。

successとdataの役割を分ける

WordPress 4.2.2のcore sourceでは、wp_send_json_success()はsuccessをtrueにし、wp_send_json_error()はfalseにします。引数へ値を渡した場合だけ、dataが追加されます。

PHP側の呼出し JSONの形 用途
wp_send_json_success() {"success":true} dataを返さず成功だけを伝える
wp_send_json_success($data) {"success":true,"data":...} 成功結果をdataへ入れる
wp_send_json_error() {"success":false} dataを返さず失敗だけを伝える
wp_send_json_error($data) {"success":false,"data":...} 理由や入力項目をdataへ入れる

successは処理結果の判定に使い、dataは結果に付随する値に使います。dataがあるかどうかだけで成功を判断すると、失敗理由を入れたresponseを成功と誤認します。

Ajax callbackは一つのresponseで終える

次は、入力したメモを保存する流れを示す説明用の仮例です。hookの登録とJavaScriptからの送信処理は省略しています。

function satolab_save_note() {
    if ( ! check_ajax_referer( 'satolab_save_note', 'nonce', false ) ) {
        wp_send_json_error( array(
            'message' => '送信元を確認できません。',
        ) );
    }

    if ( ! current_user_can( 'edit_posts' ) ) {
        wp_send_json_error( array(
            'message' => '操作権限を確認できません。',
        ) );
    }

    $note = isset( $_POST['note'] )
        ? sanitize_text_field( wp_unslash( $_POST['note'] ) )
        : '';

    if ( '' === $note ) {
        wp_send_json_error( array(
            'field'   => 'note',
            'message' => 'メモを入力してください。',
        ) );
    }

    wp_send_json_success( array(
        'message' => 'メモを受け付けました。',
    ) );
}

例では、nonce、操作権限、入力値を確認してから結果を返しています。実際の保存処理は省略しているため、保存済みの実装例ではありません。

各分岐でreturnを書いていませんが、wp_send_json_success()とwp_send_json_error()がresponseを出力して処理を終えます。関数の後へechoや別のresponseを置くと考えず、一つの分岐を一つのresponseで閉じます。

JavaScriptはsuccessを先に確認する

JavaScript側では、responseを受け取った後、successを先に判定します。次はresponseの読み分けだけを示す仮例です。

function handleSaveResponse(response) {
    if (!response.success) {
        showError(response.data && response.data.message
            ? response.data.message
            : '処理を完了できませんでした。');
        return;
    }

    showNotice(response.data && response.data.message
        ? response.data.message
        : '処理を完了しました。');
}

通信できなかったことと、WordPressがsuccess: falseを返したことは別です。network error、応答形式の破損、PHP errorは通信側の処理で扱い、入力不足や操作不可など、callbackが判定した結果はsuccessで扱います。

同じ画面に複数のAjax機能がある場合も、成功時と失敗時のdata形式を機能ごとに決めます。message、field、更新後の値などを思いつきで混ぜず、JavaScriptが必要とする値だけを返してください。

WP_Errorはcodeとmessageの配列になる

wp_send_json_error()へWP_Errorを渡すと、error codeとmessageの組が配列としてdataへ入ります。

$result = satolab_validate_note();

if ( is_wp_error( $result ) ) {
    wp_send_json_error( $result );
}

一件のerrorなら、responseは次の形になります。

{
  "success": false,
  "data": [
    {
      "code": "empty_note",
      "message": "メモを入力してください。"
    }
  ]
}

通常の配列を渡した場合と、WP_Errorを渡した場合では、dataの形が違います。JavaScript側がdata.messageを読む設計なら、PHP側でも通常の配列へ統一します。複数の検証errorを扱うためWP_Errorを渡すなら、JavaScript側はdataを配列として処理します。

どちらが正しいかではなく、response contractを一つに決めることが重要です。

wp_send_json()が出力と終了を担当する

二つの関数は、内部でwp_send_json()を呼びます。wp_send_json()はJSON用のContent-Typeを送り、値をwp_json_encode()で変換し、出力後に処理を終了します。

そのため、header()、echo json_encode()、die()をcallbackごとに重ねて書く必要はありません。独自の出力処理とWordPressの関数を混ぜると、JSONの前後へ不要な文字が入り、JavaScriptでresponseを読めなくなる原因になります。

開発を外部へ委託する場合は、PHPの関数名だけでなく、成功時と失敗時のJSON例を仕様として残してください。実装作業を任せても、画面が必要とするresponse contractは運用側でも確認できる状態にします。

最初の一手は、一つのAjax callbackについて、成功時と失敗時のJSONを一件ずつ書き出すことです。PHPとJavaScriptが同じsuccessとdataの形を前提にしているかを確認してから、処理を追加してください。

戻る