AJAX Debugging در وردپرس چطور کار می‌کند؟ این پرسشی است که هر توسعه‌دهنده‌ای که با درخواست‌های AJAX در وردپرس کار کرده، دیر یا زود با آن روبه‌رو می‌شود. AJAX (Asynchronous JavaScript and XML - جاوااسکریپت و XML ناهمگام) در وردپرس از طریق فایل admin-ajax.php مدیریت می‌شود و مکانیزم آن بر پایه اکشن‌های wp_ajax_* و wp_ajax_nopriv_* بنا شده است. برخلاف درخواست‌های معمولی که پاسخ HTML کامل برمی‌گردانند، درخواست‌های AJAX پاسخ JSON یا متن کوتاه برمی‌گردانند و همین موضوع، دیباگ کردن آن‌ها را چالش‌برانگیز می‌کند. خطاهای رایج در AJAX وردپرس شامل پاسخ 0، پاسخ -1، پاسخ 400 Bad Request، پاسخ 500 Internal Server Error، و خطاهای CORS است. هر کدام از این خطاها ریشه متفاوتی دارند: از عدم ثبت اکشن و شکست بررسی Nonce تا خطای PHP در کد و تداخل افزونه‌ها. در این نوشتار، از مکانیزم فنی AJAX در وردپرس تا ابزارهای دیباگ (کنسول مرورگر، error_log، WP_DEBUG، Query Monitor) و روش‌های سیستماتیک عیب‌یابی را بررسی می‌کنیم. هدف این است که در پایان، بتوانید هر خطای AJAX را با روشی منظم و قابل تکرار، ریشه‌یابی و رفع کنید.

نخستین‌باری که با پاسخ 0 در یک درخواست AJAX وردپرس روبه‌رو شدم، چند ساعت وقت صرف کردم تا بفهمم مشکل از کجاست. بعد از آن تجربه، یک روش سیستماتیک برای دیباگ AJAX طراحی کردم که از آن به بعد، حل هر خطا در چند دقیقه انجام می‌شود. در این نوشتار، آن روش را گام‌به‌گام بررسی می‌کنیم.

AJAX در وردپرس چطور کار می‌کند؟

AJAX (Asynchronous JavaScript and XML - جاوااسکریپت و XML ناهمگام) تکنیکی است که امکان ارسال درخواست به سرور و دریافت پاسخ، بدون بارگذاری مجدد صفحه را فراهم می‌کند. در وردپرس، این مکانیزم از طریق فایل admin-ajax.php و اکشن‌های اختصاصی پیاده‌سازی می‌شود.

جریان یک درخواست AJAX در وردپرس به این شکل است:

  1. JavaScript یک درخواست به admin-ajax.php ارسال می‌کند و پارامتر action را مشخص می‌کند.
  2. وردپرس بر اساس مقدار action، هوک wp_ajax_{action} را فراخوانی می‌کند.
  3. تابع متصل به این هوک اجرا می‌شود و پاسخ را برمی‌گرداند.
  4. پاسخ (معمولاً JSON) به JavaScript برگردانده می‌شود.

برای درک عمیق‌تر ساختار افزونه، افزونه وردپرس چطور نوشته می‌شود؟ را ببینید.

هر درخواست AJAX در وردپرس، دو هوک دارد: یکی برای کاربران لاگین‌شده (wp_ajax_*) و یکی برای کاربران مهمان (wp_ajax_nopriv_*). فراموش کردن هر کدام، یک خطای پنهان است.

نقش admin-ajax.php در معماری وردپرس

فایل admin-ajax.php در پوشه wp-admin قرار دارد و به‌عنوان نقطه ورود همه درخواست‌های AJAX عمل می‌کند. این فایل چند کار انجام می‌دهد:

  • تعریف ثابت DOING_AJAX برای تشخیص زمینه اجرا.
  • بارگذاری وردپرس با wp-load.php.
  • بررسی پارامتر action و فراخوانی هوک مربوطه.
  • خاتمه اجرا با wp_die().

نکته مهم این است که در AJAX، وردپرس پیشخوان را بارگذاری نمی‌کند، اما با wp-load.php همه توابع و هوک‌ها را فعال می‌کند. همین موضوع باعث می‌شود که خطاهای PHP در افزونه‌ها بتوانند پاسخ AJAX را بشکنند. برای درک عمیق‌تر، هوک‌های وردپرس: قلب تپنده توسعه را ببینید.

ساختار یک درخواست AJAX استاندارد

jQuery.post( ajaxurl, {
  action: 'myplugin_get_data',
  nonce: mypluginData.nonce,
  id: 42,
}, function( response ) {
  if ( response.success ) {
    console.log( response.data );
  } else {
    console.error( response.data );
  }
} );

در سمت سرور:

add_action( 'wp_ajax_myplugin_get_data', 'myplugin_handle_get_data' );
function myplugin_handle_get_data() {
  check_ajax_referer( 'myplugin_get_data', 'nonce' );
  
  $id = absint( $_POST['id'] ?? 0 );
  if ( ! $id ) {
    wp_send_json_error( 'شناسه نامعتبر' );
  }
  
  wp_send_json_success( ['id' => $id, 'title' => get_the_title( $id )] );
}

برای درک عمیق‌تر ساختار افزونه، ساختار استاندارد افزونه وردپرس را ببینید.

خطاهای رایج در AJAX وردپرس

در پروژه‌های واقعی، خطاهای AJAX معمولاً به یکی از این دسته‌ها تعلق دارند:

پاسخعلت احتمالی
0عدم ثبت اکشن، شکست بررسی Nonce، یا die() در کد
-1شکست بررسی Nonce یا check_ajax_referer
400 Bad Requestپارامتر نامعتبر یا action نامشخص
500 Internal Server Errorخطای PHP در کد افزونه یا قالب
200 با HTMLخروجی غیرمنتظره قبل از JSON
CORS Errorدرخواست از دامنه متفاوت
Timeoutعملیات طولانی یا حلقه بی‌پایان

هر کدام از این خطاها ریشه متفاوتی دارند و نیازمند رویکرد دیباگ متفاوتی هستند. برای درک عمیق‌تر خطاهای PHP، خطای Fatal error در PHP را ببینید.

فعال‌سازی WP_DEBUG و error_log

اولین گام در دیباگ AJAX، فعال‌سازی حالت دیباگ وردپرس است. در فایل wp-config.php:

define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG', true );

این تنظیمات:

  • WP_DEBUG را فعال می‌کند.
  • خطاها را در فایل wp-content/debug.log ذخیره می‌کند.
  • نمایش خطاها در صفحه را غیرفعال می‌کند (برای جلوگیری از شکستن JSON).
  • نسخه‌های توسعه‌ای JavaScript و CSS را بارگذاری می‌کند.

گام بعدی، افزودن لاگ‌های هدفمند در کد AJAX است:

error_log( 'AJAX myplugin_get_data called with: ' . print_r( $_POST, true ) );

نکته مهم: WP_DEBUG_DISPLAY باید false باشد، زیرا هرگونه خروجی اضافی قبل از JSON، پاسخ را می‌شکند. برای درک عمیق‌تر خطاهای PHP، خطای Warning در PHP را ببینید.

دیباگ با ابزارهای مرورگر

ابزارهای توسعه‌دهنده مرورگر، اولین مکان برای شروع دیباگ AJAX هستند:

تب Network

  1. درخواست AJAX را در تب Network پیدا کنید (فیلتر admin-ajax.php).
  2. وضعیت کد HTTP را بررسی کنید (200، 400، 500).
  3. محتوای درخواست را در تب Payload ببینید.
  4. پاسخ را در تب Response ببینید.

تب Console

خطاهای JavaScript و هشدارهای CORS در تب Console نمایش داده می‌شوند. خطاهایی مانند Uncaught TypeError یا Failed to load resource معمولاً ریشه مشکل را نشان می‌دهند. برای درک عمیق‌تر، چگونه خطاهای جاوااسکریپت را پیدا کنیم را ببینید.

کپی درخواست با cURL

در تب Network، روی درخواست کلیک راست کنید و Copy as cURL را انتخاب کنید. سپس در ترمینال:

curl -X POST https://example.com/wp-admin/admin-ajax.php \
  -d 'action=myplugin_get_data' \
  -d 'nonce=abc123' \
  -d 'id=42'

این روش، امکان تست مستقیم درخواست را بدون مرورگر فراهم می‌کند و خطاهای JavaScript را از معادله حذف می‌کند.

Query Monitor به‌عنوان ابزار حرفه‌ای

Query Monitor یک افزونه محبوب است که امکان مشاهده درخواست‌های AJAX، کوئری‌های دیتابیس، هوک‌های اجراشده و خطاهای PHP را در یک رابط یکپارچه فراهم می‌کند. برای AJAX، این افزونه چند قابلیت کلیدی دارد:

  • نمایش همه درخواست‌های AJAX در پیشخوان.
  • نمایش کوئری‌های اجراشده در هر درخواست.
  • نمایش هوک‌های فراخوانی‌شده و مدت اجرای آن‌ها.
  • نمایش خطاها و هشدارهای PHP.
  • نمایش درخواست‌های HTTP ارسال‌شده.

برای مرور سایر ابزارهای مشابه، ابزارهای اشکال‌زدایی جاوااسکریپت را ببینید.

Query Monitor یک «پرتو ایکس» برای AJAX است: هر چیزی که در سرور اتفاق می‌افتد را قابل مشاهده می‌کند. اگر با AJAX زیاد کار می‌کنید، این افزونه ضروری است.

عیب‌یابی خطاهای Nonce

شایع‌ترین خطای AJAX در وردپرس، شکست بررسی Nonce است که پاسخ -1 یا 0 برمی‌گرداند. دلایل رایج:

  • Nonce اشتباه ارسال شده: نام پارامتر در JavaScript و PHP متفاوت است.
  • Nonce منقضی شده: کاربر فرم را ساعت‌ها باز نگه داشته است.
  • Nonce با اکشن اشتباه ساخته شده: wp_create_nonce( 'action_a' ) اما در سرور check_ajax_referer( 'action_b' ).
  • کاربر لاگین نیست: هوک wp_ajax_nopriv_* ثبت نشده است.
  • Nonce توسط کش شده است: صفحه HTML کش شده و Nonce قدیمی است.

برای عیب‌یابی، ابتدا مطمئن شوید Nonce درست ساخته و ارسال می‌شود:

// در PHP
wp_localize_script( 'myplugin', 'mypluginData', [
  'nonce' => wp_create_nonce( 'myplugin_get_data' ),
  'ajaxurl' => admin_url( 'admin-ajax.php' ),
] );

// در JavaScript
console.log( mypluginData.nonce );

در سرور، Nonce را در error_log ثبت کنید:

error_log( 'Nonce received: ' . ( $_POST['nonce'] ?? 'MISSING' ) );
error_log( 'Nonce verify result: ' . ( wp_verify_nonce( $_POST['nonce'], 'myplugin_get_data' ) ? 'VALID' : 'INVALID' ) );

برای درک عمیق‌تر Nonce، Nonce در وردپرس را ببینید.

عیب‌یابی خطاهای JSON

یکی از چالش‌های AJAX، خطاهای Unexpected token in JSON است که به دلیل خروجی غیرمنتظره قبل از JSON رخ می‌دهد. دلایل رایج:

  • هشدار PHP: یک warning قبل از JSON چاپ شده است.
  • BOM در فایل PHP: کاراکتر نامرئی در ابتدای فایل.
  • فاصله یا خط خالی: بعد از ?> در فایل PHP.
  • خروجی افزونه دیگر: افزونه‌ای که در هوک اجرا می‌شود، چیزی چاپ می‌کند.
  • خطای Deprecated: در PHP 8، هشدارهای بیشتری چاپ می‌شود.

راه‌حل: WP_DEBUG_DISPLAY را false کنید و خطاها را در debug.log ببینید. برای درک عمیق‌تر، خطای Unexpected token in JSON را ببینید.

عیب‌یابی خطاهای CORS

CORS (Cross-Origin Resource Sharing - اشتراک منابع میان‌مبدأ) یک مکانیزم امنیتی مرورگری است که دسترسی JavaScript به منابع دامنه متفاوت را محدود می‌کند. اگر درخواست AJAX از یک دامنه متفاوت ارسال شود، ممکن است با خطای CORS روبه‌رو شوید. دلایل رایج:

  • عدم ارسال هدر Access-Control-Allow-Origin توسط سرور.
  • ارسال Content-Type: application/json در درخواست cross-origin.
  • استفاده از Cookie در درخواست cross-origin بدون credentials: include.
  • عدم تنظیم SameSite=None برای Cookie.

راه‌حل در وردپرس:

add_action( 'init', function() {
  header( 'Access-Control-Allow-Origin: https://trusted.example.com' );
  header( 'Access-Control-Allow-Credentials: true' );
  header( 'Access-Control-Allow-Methods: POST, GET, OPTIONS' );
  header( 'Access-Control-Allow-Headers: Content-Type, X-WP-Nonce' );
} );

نکته مهم: Access-Control-Allow-Origin نباید با * تنظیم شود اگر Credentials ارسال می‌شود. برای درک عمیق‌تر، خطای CORS در جاوااسکریپت را ببینید.

روش سیستماتیک دیباگ AJAX

پس از آشنایی با ابزارها، روش سیستماتیک زیر را پیشنهاد می‌کنم:

  1. تأیید ارسال درخواست: در تب Network، مطمئن شوید درخواست ارسال می‌شود.
  2. بررسی وضعیت HTTP: 200، 400، 500 یا Timeout؟
  3. بررسی Payload: پارامتر action و nonce درست ارسال شده‌اند؟
  4. بررسی Response: پاسخ JSON است یا HTML؟
  5. فعال‌سازی WP_DEBUG: خطاها را در debug.log ببینید.
  6. افزودن error_log در ابتدای handler: آیا هوک فراخوانی می‌شود؟
  7. بررسی Nonce: مقدار ارسالی و نتیجه بررسی.
  8. تست با cURL: مسئله را از JavaScript جدا کنید.
  9. غیرفعال‌سازی افزونه‌ها: یک‌به‌یک، به‌دنبال عامل تداخل بگردید.
  10. تست در قالب پیش‌فرض: عامل تداخل قالب را حذف کنید.

این روش، در ۹۰ درصد موارد به ریشه مشکل می‌رسد. برای درک عمیق‌تر، چگونه افزونه مشکل‌ساز وردپرس را پیدا کنیم را ببینید.

اشتباهات رایج در دیباگ AJAX

  • فعال بودن WP_DEBUG_DISPLAY: هر خروجی، JSON را می‌شکند.
  • نادیده گرفتن خطاهای Console: بسیاری از مشکلات در JavaScript رخ می‌دهند.
  • عدم بررسی Nonce: Nonce یکی از شایع‌ترین دلایل پاسخ 0 یا -1 است.
  • عدم تست با cURL: این روش، مسئله را از JavaScript جدا می‌کند.
  • فراموش کردن wp_ajax_nopriv_*: کاربران مهمان نمی‌توانند درخواست ارسال کنند.
  • نادیده گرفتن BOM: کاراکتر نامرئی در ابتدای فایل PHP.
  • فراموش کردن wp_die() در انتهای handler: ممکن است پاسخ اضافی چاپ شود.
  • عدم ثبت action در هر دو هوک: اگر کاربر لاگین و مهمان هر دو باید دسترسی داشته باشند، هر دو هوک لازم است.
  • نادیده گرفتن کش: صفحه HTML کش شده ممکن است Nonce قدیمی داشته باشد.
  • استفاده از echo به‌جای wp_send_json_*: این توابع، هدرهای مناسب را تنظیم می‌کنند.

برای مرور خطاهای مشابه در کد، اشتباهات رایج در کدنویسی وردپرس را ببینید.

پرسش‌های پرتکرار درباره AJAX Debugging

چرا پاسخ AJAX من 0 است؟ شایع‌ترین دلایل: عدم ثبت اکشن، شکست بررسی Nonce، یا فراخوانی die() در کد. با error_log و فعال‌سازی WP_DEBUG ریشه را پیدا کنید.

چرا پاسخ من -1 است؟ این پاسخ معمولاً نشانه شکست check_ajax_referer است. Nonce را بررسی کنید. برای درک عمیق‌تر، Nonce در وردپرس را ببینید.

چرا خطای CORS دریافت می‌کنم؟ درخواست از دامنه متفاوت ارسال شده و سرور هدرهای مناسب را تنظیم نکرده است. برای مرور، خطای CORS در جاوااسکریپت را ببینید.

چطور بفهمم هوک AJAX فراخوانی می‌شود؟ در ابتدای handler یک error_log اضافه کنید. اگر در debug.log دیده نشد، هوک ثبت نشده است. برای درک عمیق‌تر، هوک‌های وردپرس را ببینید.

چرا پاسخ من به‌جای JSON، HTML است؟ احتمالاً یک خطای PHP یا هشدار قبل از JSON چاپ شده است. WP_DEBUG_DISPLAY را false کنید و در debug.log بررسی کنید.

آیا Query Monitor برای دیباگ AJAX کافی است؟ برای اکثر موارد بله، اما برای خطاهای پیچیده، ترکیب آن با WP_DEBUG و error_log مؤثرتر است.

چرا درخواست AJAX Timeout می‌شود؟ احتمالاً عملیات طولانی یا حلقه بی‌پایان در handler وجود دارد. زمان اجرا را با set_time_limit محدود کنید و عملیات را به پس‌زمینه منتقل کنید.

برای مطالعه بیشتر درباره AJAX، صفحه Ajax در ویکی‌پدیا مفید است.

خط پایان

AJAX Debugging در وردپرس یکی از آن مهارت‌هایی است که پس از یادگیری، بهره‌وری توسعه‌دهنده را چند برابر می‌کند. خطاهای AJAX معمولاً به دلیل پاسخ‌های مبهم مانند 0 و -1، چالش‌برانگیز به‌نظر می‌رسند، اما با یک روش سیستماتیک — بررسی Network، فعال‌سازی WP_DEBUG، افزودن error_log، بررسی Nonce، و تست با cURL — می‌توان هر خطا را در چند دقیقه ریشه‌یابی کرد. Query Monitor این فرآیند را بسیار ساده‌تر می‌کند. اگر با AJAX زیاد کار می‌کنید، این روش و ابزارها را به‌عنوان بخشی از جریان کار خود در نظر بگیرید.

اگر در پروژه‌ای با خطای عجیب AJAX روبه‌رو شده‌اید یا روش متفاوتی برای دیباگ پیاده کرده‌اید، تجربه خود را در دیدگاه‌ها بنویسید؛ به‌خصوص اگر ریشه مشکل چیز غیرمنتظره‌ای بوده، این اطلاعات برای خواننده بعدی بسیار ارزشمند است.