تابع wp_send_json_success ابزار استاندارد وردپرس برای ارسال پاسخ موفق JSON در درخواست‌های AJAX و REST API است. این تابع پاسخ را با ساختار مشخص، کد وضعیت مناسب و هدر Content-Type صحیح ارسال می‌کند و پردازش را متوقف می‌سازد. استفاده درست از آن، از نبود پاسخ در سمت JavaScript، خطاهای JSON.parse و رفتار غیرمنتظره جلوگیری می‌کند. اشتباهات رایجی مانند نبود داده، نبود nonce، نبود شرط و نبود تست می‌تواند به خطاهای ظریف و حفره‌های امنیتی منجر شود. تسلط بر این تابع برای AJAX حرفه‌ای ضروری است و در تعامل PHP و JavaScript کاربرد جدی دارد.

چرا پاسخ JSON استاندارد حیاتی است؟

در درخواست‌های AJAX وردپرس، سمت سرور باید پاسخ را با ساختار مشخصی ارسال کند تا سمت کلاینت بتواند آن را پردازش کند. اگر پاسخ ساختار استاندارد نداشته باشد، JavaScript نمی‌تواند تشخیص دهد که عملیات موفق بوده یا خطا رخ داده است. تابع wp_send_json_success() این ساختار را فراهم می‌کند. این تابع پاسخ را با کلید success روی true و داده‌ها را در کلید data ارسال می‌کند. این الگو پایه پردازش AJAX در وردپرس است و توسط افزونه‌های حرفه‌ای رعایت می‌شود.

تابع wp_send_json_success چیست؟

تابع wp_send_json_success() یک تابع هسته وردپرس است که در فایل wp-includes/functions.php تعریف شده است. این تابع یک پاسخ JSON با ساختار موفق ارسال می‌کند و پردازش PHP را متوقف می‌سازد. نکته مهم این است که این تابع در انتهای اجرا فراخوانی wp_die() می‌کند و پردازش را متوقف می‌کند. بنابراین هر کدی که پس از آن نوشته شود، اجرا نمی‌شود. این تابع معمولاً در هندلرهای AJAX و در callbackهای REST API استفاده می‌شود. برای ارسال پاسخ خطا، از تابع wp_send_json_error استفاده کنید که در صفحه wp_send_json_error به تفصیل بررسی شده است.

امضای تابع و پارامترها

امضای این تابع به‌شکل زیر است:
function wp_send_json_success( $data = null, $status_code = null, $options = 0 ) {
    $response = array( 'success' => true );
    if ( null !== $data ) {
        $response['data'] = $data;
    }
    wp_send_json( $response, $status_code, $options );
}
پارامتر اول (data) داده‌ای است که در پاسخ ارسال می‌شود. می‌تواند آرایه، شیء، رشته یا عدد باشد. اگر null باشد، کلید data در پاسخ قرار نمی‌گیرد. پارامتر دوم (status_code) کد وضعیت HTTP است. اگر null باشد، کد پیش‌فرض (۲۰۰) استفاده می‌شود. پارامتر سوم (options) تنظیمات wp_json_encode است که در وردپرس ۵.۶ به بعد اضافه شده است.

سازوکار داخلی تابع

تابع wp_send_json_success ابتدا یک آرایه با کلید success روی true می‌سازد. اگر داده‌ای پاس داده شده باشد، آن را در کلید data قرار می‌دهد. سپس تابع wp_send_json را فراخوانی می‌کند که خودش: - هدر Content-Type: application/json; charset=utf-8 را ارسال می‌کند - داده را با wp_json_encode به JSON تبدیل می‌کند - خروجی را چاپ می‌کند - با wp_die() پردازش را متوقف می‌کند نکته مهم این است که wp_send_json پیش از خروجی، هدرها را ارسال می‌کند. بنابراین هیچ خروجی پیش از این تابع نباید چاپ شود، وگرنه خطای Headers Already Sent رخ می‌دهد.

ساختار پاسخ JSON

خروجی این تابع به‌شکل زیر است:
{
  "success": true,
  "data": {
    "postId": 42,
    "message": "نوشته با موفقیت ذخیره شد",
    "permalink": "https://example.com/post-42/"
  }
}
کلید success همیشه true است. کلید data تنها در صورتی که داده‌ای پاس داده شده باشد، حضور دارد. این ساختار استاندارد توسط jQuery و Fetch API به‌راحتی قابل پردازش است.

استفاده در AJAX

سمت PHP:
add_action( 'wp_ajax_myplugin_save_post', 'myplugin_save_post_handler' );
function myplugin_save_post_handler() {
    check_ajax_referer( 'myplugin_save_post_nonce', 'nonce' );

    if ( ! current_user_can( 'edit_posts' ) ) {
        wp_send_json_error( array( 'message' => 'دسترسی غیرمجاز' ), 403 );
    }

    $post_id = isset( $_POST['post_id'] ) ? absint( $_POST['post_id'] ) : 0;
    if ( ! $post_id ) {
        wp_send_json_error( array( 'message' => 'شناسه نامعتبر' ), 400 );
    }

    wp_update_post( array(
        'ID' => $post_id,
        'post_title' => sanitize_text_field( $_POST['title'] ),
    ) );

    wp_send_json_success( array(
        'postId' => $post_id,
        'message' => 'نوشته با موفقیت ذخیره شد',
    ) );
}
سمت JavaScript:
jQuery.post(
    mypluginData.ajaxUrl,
    {
        action: 'myplugin_save_post',
        nonce: mypluginData.nonce,
        post_id: 42,
        title: 'عنوان جدید'
    },
    function( response ) {
        if ( response.success ) {
            console.log( response.data.message );
        } else {
            console.error( response.data.message );
        }
    }
);
نکته مهم: در سمت JavaScript، حتماً response.success را بررسی کنید تا پاسخ موفق از خطا تفکیک شود.

استفاده در REST API

در REST API، معمولاً از WP_REST_Response استفاده می‌شود اما این تابع نیز کاربرد دارد:
function myplugin_rest_handler( WP_REST_Request $request ) {
    $data = myplugin_process_data( $request );

    if ( is_wp_error( $data ) ) {
        return new WP_Error( 'myplugin_error', $data->get_error_message(), array( 'status' => 400 ) );
    }

    // روش اول: استفاده از WP_REST_Response
    return new WP_REST_Response( array( 'data' => $data ), 200 );

    // روش دوم: استفاده از wp_send_json_success (در permission_callback یا مسیرهای خاص)
    // wp_send_json_success( $data );
}
نکته مهم: در REST API استاندارد، بهتر است از WP_REST_Response استفاده کنید. wp_send_json_success معمولاً در درخواست‌های AJAX و در سناریوهای خاص استفاده می‌شود.

کاربردهای عملی در افزونه

ذخیره تنظیمات افزونه:
add_action( 'wp_ajax_myplugin_save_settings', 'myplugin_save_settings_handler' );
function myplugin_save_settings_handler() {
    check_ajax_referer( 'myplugin_settings_nonce', 'nonce' );

    if ( ! current_user_can( 'manage_options' ) ) {
        wp_send_json_error( array( 'message' => 'دسترسی غیرمجاز' ), 403 );
    }

    $settings = isset( $_POST['settings'] ) ? (array) $_POST['settings'] : array();
    $sanitized = array();
    foreach ( $settings as $key => $value ) {
        $sanitized[ sanitize_key( $key ) ] = sanitize_text_field( $value );
    }

    update_option( 'myplugin_settings', $sanitized );

    wp_send_json_success( array(
        'message'  => 'تنظیمات با موفقیت ذخیره شد',
        'settings' => $sanitized,
    ) );
}
بارگذاری محتوای بیشتر:
add_action( 'wp_ajax_myplugin_load_more', 'myplugin_load_more_handler' );
add_action( 'wp_ajax_nopriv_myplugin_load_more', 'myplugin_load_more_handler' );
function myplugin_load_more_handler() {
    check_ajax_referer( 'myplugin_load_more_nonce', 'nonce' );

    $page = isset( $_POST['page'] ) ? absint( $_POST['page'] ) : 1;

    $query = new WP_Query( array(
        'post_type'      => 'post',
        'posts_per_page' => 10,
        'paged'          => $page,
    ) );

    $posts = array();
    foreach ( $query->posts as $post ) {
        $posts[] = array(
            'id'    => $post->ID,
            'title' => get_the_title( $post ),
            'url'   => get_permalink( $post ),
        );
    }

    wp_send_json_success( array(
        'posts'      => $posts,
        'hasMore'    => $page < $query->max_num_pages,
        'nextPage'   => $page + 1,
    ) );
}
نکته مهم: در سناریوهایی که هم کاربر وارد‌شده و هم مهمان باید پاسخ بگیرند، از هر دو هوک wp_ajax_ و wp_ajax_nopriv_ استفاده کنید. راهنمای این هوک‌ها در راهنمای هوک wp_ajax و راهنمای هوک wp_ajax_nopriv آمده است.

نکات امنیتی و اشتباهات رایج

اشتباه اول، نبود داده است. اگر داده پاس داده نشود، پاسخ شامل کلید data نمی‌شود و سمت کلاینت ممکن است خطا دهد. اشتباه دوم، نبود nonce است. هر درخواست AJAX باید nonce داشته باشد. راهنمای این تابع در صفحه wp_verify_nonce و راهنمای check_ajax_referer آمده است. اشتباه سوم، نبود شرط دسترسی است. برای عملیات حساس، از current_user_can استفاده کنید که در صفحه current_user_can آمده است. اشتباه چهارم، چاپ خروجی پیش از این تابع است. هر خروجی پیش از wp_send_json_success خطای Headers Already Sent ایجاد می‌کند. اشتباه پنجم، نبود escape در داده است. اگر داده شامل HTML است، باید در سمت JavaScript به‌درستی escape شود یا از wp_kses_post در سمت PHP استفاده کنید. اشتباه ششم، نبود تست است. باید در سناریوهای مختلف (موفق، خطا، داده خالی) تست کنید. اشتباه هفتم، استفاده از این تابع در REST API استاندارد است. در REST API بهتر است از WP_REST_Response استفاده کنید.

تحلیل فنی پیشرفته

در نگاه مهندسی، تابع wp_send_json_success() یک نقطه معماری در لایه AJAX Response است که بر چند جنبه از سیستم اثر می‌گذارد. لایه اول لایه Response Contract است. این تابع یک قرارداد مشخص برای پاسخ AJAX ایجاد می‌کند که شامل کلید success و data است. این قرارداد در همه افزونه‌های حرفه‌ای رعایت می‌شود. لایه دوم لایه Header Management است. تابع wp_send_json هدر Content-Type را به‌درستی تنظیم می‌کند. اگر این هدر تنظیم نشود، مرورگر پاسخ را به‌عنوان متن ساده تفسیر می‌کند. لایه سوم لایه Execution Termination است. این تابع با wp_die اجرای PHP را متوقف می‌کند. اگر به‌جای آن از echo استفاده کنید، ممکن است کد اضافی پس از آن اجرا شود و پاسخ را خراب کند. لایه چهارم لایه Security است. این تابع خودش escape اضافی ندارد و به عهده توسعه‌دهنده است که داده را پاک‌سازی کند. لایه پنجم لایه Integration است. ترکیب wp_send_json_success با wp_send_json_error و check_ajax_referer یک الگوی کامل برای پردازش AJAX می‌سازد. لایه ششم لایه Performance است. JSON یک فرمت سبک است و پردازش آن در سمت کلاینت سریع است. لایه هفتم لایه Multisite است. در شبکه‌های Multisite، این تابع در هر سایت مستقل کار می‌کند. لایه هشتم لایه Testing است. تست‌های End-to-End باید همه حالت‌ها (موفق، خطا، داده خالی) را پوشش دهند. مفاهیم پایه‌ای JSON در JSON در ویکی‌پدیا توضیح داده شده است. برای مطالعه بیشتر روی توابع مرتبط، می‌توانید به راهنمای wp_send_json_error، راهنمای wp_send_json، راهنمای هوک wp_ajax، راهنمای هوک wp_ajax_nopriv، راهنمای check_ajax_referer، راهنمای wp_localize_script و راهنمای current_user_can مراجعه کنید.

پرسش‌های پرتکرار

تفاوت wp_send_json_success و wp_send_json_error چیست؟ اولی پاسخ موفق و دومی پاسخ خطا ارسال می‌کند. آیا این تابع پردازش PHP را متوقف می‌کند؟ بله، با wp_die پردازش را متوقف می‌سازد. آیا می‌توان داده را در پاسخ ارسال کرد؟ بله، با پاس دادن پارامتر اول. آیا در REST API نیز می‌توان از این تابع استفاده کرد؟ ممکن است، اما معمولاً WP_REST_Response مناسب‌تر است. چطور خطا را در سمت JavaScript پردازش کنیم؟ با بررسی response.success.

نتیجه و مسیر ادامه

تابع wp_send_json_success() ابزار استاندارد وردپرس برای ارسال پاسخ موفق JSON در AJAX است. استفاده درست از آن یعنی پاس دادن داده معنادار، بررسی nonce و دسترسی، escape داده‌ها و درک دقیق ساختار پاسخ. اشتباه‌های کوچک در این تابع اغلب به نبود پاسخ در سمت JavaScript یا خطاهای پردازش منجر می‌شوند. اگر این تابع را در پروژه‌ای واقعی به کار برده‌اید و رفتار غیرمنتظره‌ای دیده‌اید — به‌خصوص در ترکیب با افزونه‌های کش یا در REST API — تجربه‌تان می‌تواند راهگشای دیگران باشد. کدام بخش بیشترین زمان را از شما گرفت؟ دیدگاه خود را بنویسید.