Debug در وردپرس یک مهارت است، نه یک ابزار؛ مهارتی که تفاوت میان توسعه‌دهنده‌ای که یک خطا را در چند دقیقه ریشه‌یابی می‌کند و توسعه‌دهنده‌ای که ساعت‌ها در سایت مشتری سرگردان است، همان‌جا مشخص می‌شود. عیب‌یابی حرفه‌ای در وردپرس نیازمند یک روش سیستماتیک است که از لایه هسته شروع می‌شود، به افزونه‌ها و قالب می‌رسد، و در نهایت به کد سفارشی و پایگاه داده ختم می‌شود. ابزارهای بومی وردپرس مانند WP_DEBUG، WP_DEBUG_LOG و WP_DEBUG_DISPLAY پایه این فرآیند را می‌سازند، اما در پروژه‌های واقعی این ابزارها به‌تنهایی کافی نیستند. ترکیب این ابزارها با Query Monitor، بررسی لاگ سرور، تحلیل Backtrace و رویکرد Bisection در افزونه‌ها، یک چارچوب عیب‌یابی کامل می‌سازد. Debugging در وردپرس فقط رفع خطا نیست؛ شناخت ریشه‌ای مشکل، جلوگیری از تکرار و افزایش پایداری سایت در بلندمدت است. این متن مسیر عملی عیب‌یابی حرفه‌ای را از پیکربندی محیط تا ریشه‌یابی خطاهای پیچیده در تولید، با تمرکز بر روش‌شناسی و کد قابل اجرا بررسی می‌کند.

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

Debug در وردپرس دقیقاً چه معنایی دارد؟

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

تفاوت بنیادین عیب‌یابی با «رفع خطا» در همین هدف سوم است. رفع خطا، پاسخ دادن به سؤال «چگونه این خطا الان برطرف شود؟» است، در حالی که عیب‌یابی پاسخ دادن به سؤال «چرا این خطا رخ داد و چه چیزی باید تغییر کند تا دوباره رخ ندهد؟» است. در پروژه‌های واقعی، توسعه‌دهنده‌ای که فقط خطا را رفع می‌کند، در چرخه بی‌پایان تکرار خطا گرفتار می‌شود؛ در حالی که توسعه‌دهنده‌ای که ریشه را می‌یابد، پایداری بلندمدت می‌سازد.

در ادبیات مهندسی نرم‌افزار، مفهوم Debugging نخستین بار در سال ۱۹۴۷ توسط تیم Grace Hopper و به‌واسطه یک شب‌پره که در یک رله کامپیوتر Mark II گیر کرده بود، مطرح شد. توضیح تاریخی این رویداد در دانشنامه آزاد ویکی‌پدیا با عنوان Debugging مستندسازی شده است. اما آنچه در وردپرس عیب‌یابی را از عیب‌یابی در سایر سیستم‌ها متمایز می‌کند، ماهیت پویا و لایه‌ای این CMS است: کد هسته، کد افزونه‌ها، کد قالب و کد سفارشی همه در یک فضای اجرایی مشترک کار می‌کنند و خطا در هر یک می‌تواند از لایه دیگر ناشی شود.

عیب‌یابی حرفه‌ای در وردپرس مبتنی بر یک اصل بنیادین است: خطا هیچ‌گاه تصادفی نیست. هر خطای به‌ظاهر تصادفی، یک زنجیره قطعی از رویدادها دارد که فقط پنهان شده است. وظیفه توسعه‌دهنده، بازسازی این زنجیره است. این بازسازی از طریق ترکیب چهار ابزار انجام می‌شود: گزارش‌گیری دقیق، تکرارپذیری کنترل‌شده، حذف متغیرهای نامرتبط و تحلیل عمیق داده‌ها. برای درک بهتر مفاهیم پایه در بافت وب، مطلب معماری وب چیست؟ دیدگاه مفیدی ارائه می‌دهد.

Debugging در وردپرس، فرآیند بازسازی زنجیره قطعی رویدادهاست، نه حدس‌زدن درباره علت خطا.

چرا عیب‌یابی سیستماتیک از عیب‌یابی تجربی مؤثرتر است؟

عیب‌یابی تجربی، روشی است که در آن توسعه‌دهنده بر پایه حدس و تجربه شخصی، تغییرات متعددی را اعمال می‌کند تا خطا برطرف شود. این روش در خطاهای ساده و آشنای کارآمد است، اما در خطاهای پیچیده یا نادر، می‌تواند به فاجعه منجر شود. سه دلیل بنیادین، عیب‌یابی سیستماتیک را ضروری می‌کند.

دلیل اول: پیچیدگی تعامل لایه‌ها

در یک سایت وردپرسی، حداقل چهار لایه کد در یک فضای اجرایی مشترک کار می‌کنند: کد هسته وردپرس، کد افزونه‌ها، کد قالب و کد سفارشی در functions.php یا افزونه اختصاصی. خطا در یک لایه می‌تواند علائمی در لایه دیگر تولید کند. یک خطای دیتابیس می‌تواند به‌شکل خطای قالب ظاهر شود؛ یک خطای JavaScript می‌تواند به‌شکل خطای امنیتی در REST API دیده شود. بدون رویکرد سیستماتیک، تشخیص لایه واقعی خطا تقریباً غیرممکن است.

دلیل دوم: نبود تکرارپذیری در شرایط تصادفی

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

دلیل سوم: اثرات جانبی پنهان

هر تغییری در سایت، اثرات جانبی دارد. غیرفعال کردن یک افزونه، ممکن است کش را پاک کند یا تنظیمات ذخیره‌شده را حذف کند. تغییر در wp-config.php ممکن است روی رفتار SMTP یا کش شیء اثر بگذارد. بدون مستندسازی تغییرات، تفکیک اثرات مطلوب از اثرات جانبی نامطلوب غیرممکن می‌شود.

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

ثابت‌های WP_DEBUG و پیکربندی محیط

پایه عیب‌یابی در وردپرس، مجموعه‌ای از ثابت‌ها است که رفتار سیستم گزارش خطا را کنترل می‌کنند. این ثابت‌ها در فایل wp-config.php تعریف می‌شوند و رفتار متفاوتی در محیط توسعه و محیط تولید دارند.

ثابت‌های اصلی و رفتار آن‌ها

ثابت WP_DEBUG فعال‌کننده اصلی حالت عیب‌یابی است. با تنظیم آن روی true، وردپرس خطاهای PHP را نمایش می‌دهد و از افزونه‌های قدیمی می‌خواهد که هشدارهای منسوخ‌شدگی تولید کنند. ثابت WP_DEBUG_LOG خطاها را در فایل wp-content/debug.log ذخیره می‌کند. ثابت WP_DEBUG_DISPLAY کنترل می‌کند که خطاها در خروجی HTML نمایش داده شوند یا خیر. ثابت SCRIPT_DEBUG نسخه‌های غیرفشرده فایل‌های JavaScript و CSS هسته را بارگذاری می‌کند. ثابت SAVEQUERIES کوئری‌های دیتابیس را برای تحلیل بعدی ذخیره می‌کند.

// پیکربندی محیط توسعه در wp-config.php
define( 'WP_DEBUG', true );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', true );
define( 'SCRIPT_DEBUG', true );
define( 'SAVEQUERIES', true );
define( 'WP_DISABLE_FATAL_ERROR_HANDLER', true );

@ini_set( 'display_errors', 1 );
@ini_set( 'error_reporting', E_ALL );

// پیکربندی محیط تولید
define( 'WP_DEBUG', false );
define( 'WP_DEBUG_LOG', true );
define( 'WP_DEBUG_DISPLAY', false );
define( 'SCRIPT_DEBUG', false );
define( 'SAVEQUERIES', false );

تفاوت محیط توسعه و محیط تولید

در محیط توسعه، هدف اصلی، شفافیت کامل است: همه خطاها باید دیده شوند، همه هشدارها باید لاگ شوند و همه اعلان‌ها باید بررسی شوند. در محیط تولید، هدف اصلی، پایداری و امنیت است: خطاها نباید به کاربر نمایش داده شوند، اما باید در لاگ ثبت شوند تا توسعه‌دهنده بتواند آن‌ها را بررسی کند.

نکته کلیدی در محیط تولید، تنظیم درست WP_DEBUG_DISPLAY روی false است. اگر این ثابت روی true بماند، خطاهای PHP در خروجی HTML نمایش داده می‌شوند که سه پیامد خطرناک دارد: نخست، اطلاعات حساس مانند مسیر فایل‌ها و ساختار دیتابیس افشا می‌شود. دوم، ظاهر سایت در دید کاربران خراب می‌شود. سوم، در برخی شرایط، خطاهای نمایش‌داده‌شده می‌توانند یک بردار حمله جدید بسازند.

ثابت WP_DISABLE_FATAL_ERROR_HANDLER

از وردپرس نسخه ۵.۲ به بعد، یک مکانیزم بومی برای مدیریت خطاهای Fatal اضافه شده است که به‌طور پیش‌فرض فعال است و در صورت بروز خطای Fatal، یک صفحه «خطای فنی» نمایش می‌دهد و یک ایمیل هشدار به مدیر سایت ارسال می‌کند. این مکانیزم مفید است اما در زمان عیب‌یابی می‌تواند مانع نمایش کامل خطا شود. تنظیم WP_DISABLE_FATAL_ERROR_HANDLER روی true این مکانیزم را غیرفعال می‌کند و امکان مشاهده خطای واقعی را فراهم می‌آورد. برای درک عمیق‌تر این مکانیزم، مطلب خطای 500 وردپرس چیست و چگونه رفع می‌شود راهنمای عملی خوبی است.

لاگ‌گیری حرفه‌ای با WP_DEBUG_LOG

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

مکانیزم کار WP_DEBUG_LOG

با فعال‌سازی WP_DEBUG_LOG، وردپرس همه خطاهای PHP، هشدارها و اعلان‌های منسوخ‌شدگی را در فایل wp-content/debug.log ذخیره می‌کند. این فایل به‌صورت تجمعی رشد می‌کند و می‌تواند در سایت‌های پرترافیک به چندین مگابایت برسد. مدیریت اندازه این فایل، بخشی از فرآیند عیب‌یابی حرفه‌ای است.

لاگ‌گیری سفارشی با error_log

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

function wk_debug_log( $message, $context = [] ) {
    if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
        return;
    }

    $entry = sprintf(
        '[WK-DEBUG] %s | context=%s',
        $message,
        wp_json_encode( $context )
    );

    error_log( $entry );
}

// نمونه استفاده در یک تابع سفارشی
function wk_process_order( $order_id ) {
    wk_debug_log( 'order processing started', [
        'order_id' => $order_id,
        'user_id'  => get_current_user_id(),
    ] );

    $order = wc_get_order( $order_id );
    if ( ! $order ) {
        wk_debug_log( 'order not found', [ 'order_id' => $order_id ] );
        return false;
    }

    wk_debug_log( 'order loaded', [ 'total' => $order->get_total() ] );
    return true;
}

استفاده از تابع wp_debug_backtrace_summary

وردپرس یک تابع بومی به نام wp_debug_backtrace_summary دارد که زنجیره فراخوانی توابع را به‌صورت خوانا ثبت می‌کند. این تابع در ریشه‌یابی خطاهایی که در چند لایه کد رخ می‌دهند، بسیار مفید است.

add_action( 'init', function() {
    if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
        return;
    }

    $backtrace = wp_debug_backtrace_summary( null, 0, false );
    error_log( '[WK-TRACE] init fired: ' . $backtrace );
} );

مدیریت چرخشی لاگ

فایل debug.log می‌تواند در سایت‌های پرترافیک به‌سرعت رشد کند. یک راهکار ساده، تغییر نام فایل لاگ در بازه‌های منظم است تا هر دوره، یک فایل مستقل داشته باشد.

# اسکریپت bash برای چرخش لاگ
#!/bin/bash
LOG_FILE="/var/www/html/wp-content/debug.log"
ARCHIVE_DIR="/var/www/html/wp-content/debug-logs"

mkdir -p "$ARCHIVE_DIR"

if [ -f "$LOG_FILE" ]; then
    TIMESTAMP=$(date +%Y%m%d-%H%M%S)
    mv "$LOG_FILE" "$ARCHIVE_DIR/debug-$TIMESTAMP.log"
    touch "$LOG_FILE"
    chmod 640 "$LOG_FILE"
fi

# حذف لاگ‌های قدیمی‌تر از ۳۰ روز
find "$ARCHIVE_DIR" -name "debug-*.log" -mtime +30 -delete

انواع خطاها و تفکیک آن‌ها

شناخت انواع خطاها، اولین گام در ریشه‌یابی است. در وردپرس، پنج نوع خطای اصلی وجود دارد که هر یک رفتار و مسیر عیب‌یابی متفاوتی دارند.

خطاهای Notice

خطاهای Notice در PHP نشان‌دهنده استفاده از متغیر تعریف‌نشده یا دسترسی به اندیس ناموجود است. این خطاها اجرای اسکریپت را متوقف نمی‌کنند، اما نشانه‌ای از کد ضعیف یا نسخه PHP جدیدتر از زمان نوشتن کد هستند. در سایت‌های وردپرسی، Noticeها اغلب از افزونه‌های قدیمی ناشی می‌شوند.

خطاهای Warning

خطاهای Warning جدی‌تر از Noticeها هستند. این خطاها نشان‌دهنده استفاده نادرست از توابع، آرگومان‌های نادرست یا عملیات نامعتبر هستند. نمونه‌های رایج شامل فراخوانی تابع با تعداد آرگومان نادرست یا تلاش برای دسترسی به فایلی که وجود ندارد. این خطاها نیز اجرای اسکریپت را متوقف نمی‌کنند اما باید جدی گرفته شوند.

خطاهای Deprecated

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

خطاهای Fatal

خطاهای Fatal جدی‌ترین نوع خطا هستند و اجرای اسکریپت را متوقف می‌کنند. در وردپرس، خطای Fatal معمولاً به‌شکل «صفحه سفید مرگ» یا صفحه خطای فنی ظاهر می‌شود. سه علت رایج این خطا در وردپرس: فراخوانی تابع ناموجود، بارگذاری کلاس تکراری و کمبود حافظه.

خطاهای Parse

خطاهای Parse زمانی رخ می‌دهند که کد PHP از نظر نحوی نادرست باشد. این خطاها پیش از اجرای کد شناسایی می‌شوند و باعث توقف کامل اجرا می‌شوند. یک کاراکتر نادرست در یک فایل PHP می‌تواند کل سایت را از دسترس خارج کند.

نوع خطااجرا متوقف می‌شود؟علت رایج در وردپرسمسیر عیب‌یابی
Noticeخیرمتغیر تعریف‌نشده در افزونه قدیمیبه‌روزرسانی افزونه
Warningخیرآرگومان نادرست یا فایل ناموجودبازبینی کد سفارشی
Deprecatedخیراستفاده از تابع منسوخبازنویسی کد با API جدید
Fatalبلهتابع ناموجود یا کمبود حافظهافزایش حافظه یا Bisection
Parseبلهنحوی نادرست در فایل PHPبازبینی فایل با Linter

روش Bisection در ریشه‌یابی تضادها

روش Bisection، یکی از مؤثرترین تکنیک‌های ریشه‌یابی در وردپرس است و بر پایه تقسیم دامنه مشکل به دو نیمه و حذف تدریجی متغیرهای بی‌ربط بنا شده است. این روش در عیب‌یابی تضادهای افزونه و قالب، جایگاه ویژه‌ای دارد.

چرخه عملی Bisection

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

// چکیده‌ای از اسکریپت غیرفعال‌سازی دسته‌ای افزونه‌ها در WP-CLI
# غیرفعال کردن همه افزونه‌ها
wp plugin deactivate --all

# فعال‌سازی دسته اول (نیمی از افزونه‌ها)
wp plugin activate plugin-a plugin-b plugin-c

# بررسی وضعیت سایت
wp option get siteurl
wp plugin list --status=active

# تکرار چرخه تا شناسایی افزونه مشکل‌ساز

پیاده‌سازی Bisection بدون WP-CLI

در محیط‌هایی که WP-CLI در دسترس نیست، می‌توان Bisection را از طریق تغییر نام پوشه افزونه‌ها در سطح فایل سیستم انجام داد. این روش در برابر برخی خطاهای Fatal که مانع بارگذاری پنل مدیریت می‌شوند، تنها راهکار است.

# غیرفعال کردن دسته‌ای افزونه‌ها با تغییر نام پوشه
cd /var/www/html/wp-content/plugins

# ذخیره نام اصلی افزونه‌ها در یک متغیر
PLUGINS=$(ls -d */)

# غیرفعال کردن همه افزونه‌ها با تغییر نام
for plugin in $PLUGINS; do
    mv "$plugin" "${plugin%/}.disabled"
done

# فعال‌سازی تدریجی برای شناسایی افزونه مشکل‌ساز
mv plugin-a.disabled plugin-a
# بررسی سایت، سپس:
mv plugin-b.disabled plugin-b

Bisection در قالب

اگر افزونه‌ها مشکل‌ساز نبودند، Bisection باید در قالب تکرار شود. ابتدا قالب را به یک قالب پیش‌فرض مانند Twenty Twenty-Five تغییر دهید و بررسی کنید خطا برطرف شده است یا خیر. اگر خطا برطرف شد، مشکل در قالب اصلی است. در این حالت، باید قالب را روی یک محیط توسعه فعال کنید و با همین روش Bisection، فایل مشکل‌ساز را شناسایی نمایید.

برای راهنمای کامل این فرآیند، مطلب روش پیدا کردن افزونه یا قالب مشکل‌ساز گام‌به‌گام توضیح داده شده است.

Query Monitor و تحلیل عمیق کوئری‌ها

Query Monitor یکی از ابزارهای ضروری عیب‌یابی وردپرس است که لایه‌ای از شفافیت را به اجرای هر درخواست اضافه می‌کند. این افزونه اطلاعات دقیق کوئری‌های دیتابیس، هوک‌های اجراشده، قالب‌های بارگذاری‌شده و درخواست‌های HTTP خارجی را نمایش می‌دهد.

قابلیت‌های کلیدی Query Monitor

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

تحلیل کوئری‌های کند

پس از نصب Query Monitor، می‌توان کوئری‌های کند را بر پایه زمان اجرا شناسایی کرد. کوئری‌های بالای ۱۰۰ میلی‌ثانیه، به‌عنوان نامزد بهینه‌سازی در نظر گرفته می‌شوند. منبع فراخوانی هر کوئری، مسیر مستقیم به کد مشکل‌ساز را نشان می‌دهد.

// ثبت کوئری‌های کند در لاگ برای تحلیل بعدی
add_action( 'shutdown', function() {
    if ( ! defined( 'SAVEQUERIES' ) || ! SAVEQUERIES ) {
        return;
    }

    global $wpdb;
    if ( empty( $wpdb->queries ) ) {
        return;
    }

    foreach ( $wpdb->queries as $query ) {
        if ( $query[1] > 0.1 ) {
            error_log( sprintf(
                '[WK-SLOW-QUERY] time=%.3fs sql=%s caller=%s',
                $query[1],
                substr( $query[0], 0, 200 ),
                $query[2]
            ) );
        }
    }
} );

تحلیل هوک‌های پرتکرار

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

عیب‌یابی کد سفارشی و Backtrace

عیب‌یابی کد سفارشی، به‌دلیل نبود ابزارهای خودکار، نیازمند تکنیک‌های دستی است. در این بافت، دو ابزار کلیدی وجود دارد: Backtrace و تکنیک‌های ثبت مرحله‌به‌مرحله.

تحلیل Backtrace خطا

PHP به‌طور پیش‌فرض زنجیره فراخوانی توابع را در خطاهای Fatal ثبت می‌کند. این زنجیره، دقیقاً نشان می‌دهد که خطا از کجا آغاز شده و از چه مسیری به نقطه بروز رسیده است. برای خوانایی بیشتر، می‌توان از debug_print_backtrace استفاده کرد.

function wk_trace_error( $message ) {
    if ( ! defined( 'WP_DEBUG' ) || ! WP_DEBUG ) {
        return;
    }

    error_log( '[WK-ERROR] ' . $message );
    error_log( '[WK-BACKTRACE] ' . wp_debug_backtrace_summary( null, 0, false ) );
}

// استفاده در یک نقطه حساس
add_action( 'save_post', function( $post_id, $post, $update ) {
    if ( 'product' !== $post->post_type ) {
        return;
    }

    wk_trace_error( sprintf(
        'save_post fired for product %d update=%s',
        $post_id,
        $update ? 'true' : 'false'
    ) );
}, 10, 3 );

ثبت مرحله‌به‌مرحله در توابع پیچیده

در توابع پیچیده که چند مرحله پردازش دارند، ثبت مرحله‌به‌مرحله امکان شناسایی دقیق نقطه شکست را فراهم می‌کند. این تکنیک در برابر خطاهای سکوت — خطاهایی که اجرا را متوقف نمی‌کنند اما نتیجه نادرست تولید می‌کنند — مؤثر است.

function wk_calculate_discount( $order_total, $customer_id ) {
    $step = 1;
    wk_debug_log( "step {$step}: start", [ 'total' => $order_total ] );

    $step++;
    $tier = get_user_meta( $customer_id, 'wk_tier', true );
    wk_debug_log( "step {$step}: tier loaded", [ 'tier' => $tier ] );

    if ( ! $tier ) {
        wk_debug_log( "step {$step}: tier missing, using default" );
        $tier = 'standard';
    }

    $step++;
    $rates = [ 'standard' => 0, 'silver' => 5, 'gold' => 10 ];
    $rate  = $rates[ $tier ] ?? 0;
    wk_debug_log( "step {$step}: rate determined", [ 'rate' => $rate ] );

    $step++;
    $discount = $order_total * ( $rate / 100 );
    wk_debug_log( "step {$step}: discount computed", [ 'discount' => $discount ] );

    return $discount;
}

اگر با ساختار توابع وردپرس و کاربرد آن‌ها در پروژه‌های واقعی آشنا نیستید، مطلب دیباگ کردن کدهای سفارشی وردپرس راهنمای تکمیلی خوبی است.

تحلیل لاگ سرور در کنار لاگ وردپرس

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

لاگ‌های سرور و منابع آن‌ها

سه لاگ اصلی در سرور وجود دارد. لاگ خطای PHP که در مسیر /var/log/php-fpm/error.log یا /var/log/php/error.log قرار دارد. لاگ وب‌سرور که در /var/log/nginx/error.log یا /var/log/apache2/error.log ثبت می‌شود. لاگ دیتابیس که در /var/log/mysql/error.log قرار دارد.

# پایش زنده لاگ خطا در سرور
tail -f /var/log/php-fpm/error.log
tail -f /var/log/nginx/error.log

# جست‌وجوی خطاهای Fatal در بازه زمانی مشخص
grep -i "fatal" /var/log/php-fpm/error.log | grep "$(date +%Y-%m-%d)"

# شمارش خطاها بر پایه نوع
grep -oP "(PHP )?\w+ error" /var/log/php-fpm/error.log | sort | uniq -c | sort -rn

# شناسایی پرتکرارترین IPهای تولیدکننده خطا
awk '{print $1}' /var/log/nginx/access.log | sort | uniq -c | sort -rn | head -20

همبستگی لاگ سرور با لاگ وردپرس

نکته کلیدی در تحلیل لاگ، همبستگی زمانی است. اگر یک خطای Fatal در لاگ PHP در ساعت ۱۴:۳۲:۱۵ ثبت شده است، باید رویدادهای مشابه در همان زمان در لاگ وردپرس و لاگ وب‌سرور جست‌وجو شوند. این همبستگی، تصویر کاملی از زنجیره رخداد می‌سازد.

برای راهنمای کامل تحلیل لاگ سرور، مطلب چگونه خطاهای سرور را در لاگ‌ها بررسی کنیم؟ گام‌به‌گام توضیح داده شده است. همچنین اگر می‌خواهید با ابزارهای پیشرفته‌تر آشنا شوید، مطلب چگونه خطای افزونه وردپرس را پیدا کنیم؟ راهکارهای مکمل ارائه می‌دهد.

عیب‌یابی در محیط تولید بدون آسیب به کاربران

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

راهکار اول: کلون محیط تولید به محیط استیجینگ

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

# کلون دیتابیس به محیط استیجینگ
mysqldump -u user -p production_db | gzip > production_db.sql.gz
gunzip < production_db.sql.gz | mysql -u user -p staging_db

# جایگزینی URL دامنه در دیتابیس استیجینگ
wp search-replace 'https://example.com' 'https://staging.example.com' \
   --all-tables --precise --skip-columns=guid

# کلون فایل‌ها
rsync -avz --exclude='wp-content/cache/*' \
      /var/www/production/ /var/www/staging/

راهکار دوم: عیب‌یابی روی ترافیک زیرمجموعه

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

// فعال‌سازی WP_DEBUG فقط برای IPهای مشخص
add_action( 'init', function() {
    $allowed_ips = [ '203.0.113.10', '198.51.100.5' ];
    $current_ip  = $_SERVER['REMOTE_ADDR'] ?? '';

    if ( in_array( $current_ip, $allowed_ips, true ) ) {
        if ( ! defined( 'WP_DEBUG' ) ) {
            define( 'WP_DEBUG', true );
        }
    }
}, 1 );

راهکار سوم: استفاده از ابزارهای APM

ابزارهای APM (Application Performance Monitoring) مانند New Relic، Datadog و Sentry امکان رصد رفتار سایت در محیط تولید بدون نیاز به تغییر کد را فراهم می‌کنند. این ابزارها خطاها را در زمان واقعی ثبت می‌کنند و امکان بازسازی رخداد را فراهم می‌آورند.

// نصب Sentry در وردپرس
require_once __DIR__ . '/vendor/autoload.php';

\Sentry\init([
    'dsn' => 'https://examplePublicKey@o0.ingest.sentry.io/0',
    'environment' => 'production',
    'traces_sample_rate' => 0.1,
    'before_send' => function( \Sentry\Event $event ) {
        return $event;
    },
]);

// ثبت خطاهای PHP در Sentry
add_action( 'init', function() {
    if ( function_exists( '\Sentry\captureException' ) ) {
        set_exception_handler( function( $exception ) {
            \Sentry\captureException( $exception );
        } );
    }
} );

اشتباهات رایج در Debug وردپرس

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

  • فعال‌سازی WP_DEBUG_DISPLAY روی محیط تولید که اطلاعات حساس را افشا می‌کند.
  • اعمال تغییرات متعدد به‌صورت هم‌زمان بدون تفکیک اثر هر تغییر.
  • غیرفعال کردن افزونه‌ها بدون تهیه نسخه پشتیبان از تنظیمات آن‌ها.
  • نبود مستندسازی تغییرات، که بازگردانی به حالت اولیه را دشوار می‌کند.
  • اعتماد کامل به لاگ وردپرس و نادیده گرفتن لاگ سرور.
  • استفاده از چاپ مستقیم (var_dump یا print_r) در محیط تولید به‌جای ثبت در لاگ.
  • فرض بر این که خطای مشاهده‌شده در یک لایه، ریشه در همان لایه دارد.
  • نادیده گرفتن Noticeها به بهانه بی‌اهمیت بودن، که در نسخه‌های آینده PHP به Fatal تبدیل می‌شوند.
  • پاک کردن لاگ بدون بررسی آن، که شواهد ارزشمند را از بین می‌برد.
  • نبود فرآیند بررسی دوره‌ای لاگ که باعث پنهان ماندن خطاهای تجمعی می‌شود.
  • اتکا به ابزارهای خودکار بدون درک عمیق از رفتار وردپرس.
  • نادیده گرفتن اثر افزونه‌های کش بر فرآیند عیب‌یابی، که می‌تواند نسخه قدیمی صفحه را نمایش دهد.

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

پرسش‌های پرتکرار درباره Debug در وردپرس

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

آیا باید WP_DEBUG را روی محیط تولید فعال نگه دارم؟

بله، اما با تنظیم صحیح. در محیط تولید، WP_DEBUG باید روی true باشد تا خطاها ثبت شوند، اما WP_DEBUG_DISPLAY باید روی false باشد تا خطاها به کاربران نمایش داده نشوند. این ترکیب، امکان ردیابی خطاها را فراهم می‌کند بدون اینکه امنیت یا تجربه کاربر به خطر بیفتد.

فایل debug.log چقدر می‌تواند بزرگ شود؟

اندازه فایل debug.log به حجم ترافیک و شدت خطاها بستگی دارد. در سایت‌های پرترافیک با خطاهای مکرر، این فایل می‌تواند در چند روز به چند صد مگابایت برسد. توصیه می‌شود یک فرآیند چرخش لاگ با دوره‌های یک هفته‌ای تنظیم شود و لاگ‌های قدیمی‌تر از ۳۰ روز حذف شوند.

آیا می‌توان Debugging را در وردپرس خودکار کرد؟

بخش‌هایی از Debugging قابل خودکارسازی است، اما بخش اصلی آن نیازمند تحلیل انسانی است. ابزارهایی مانند Sentry و New Relic امکان ثبت خودکار خطاها را فراهم می‌کنند، اما تشخیص ریشه و تصمیم‌گیری برای اصلاح، همچنان نیازمند تخصص توسعه‌دهنده است. خودکارسازی فقط می‌تواند مرحله جمع‌آوری داده را تسریع کند.

تفاوت WP_DEBUG با SCRIPT_DEBUG چیست؟

WP_DEBUG رفتار PHP را کنترل می‌کند: نمایش خطاها، لاگ‌گیری و هشدارهای منسوخ‌شدگی. SCRIPT_DEBUG رفتار بارگذاری فایل‌های JavaScript و CSS را کنترل می‌کند: با فعال بودن، نسخه‌های غیرفشرده بارگذاری می‌شوند که خوانایی و قابلیت دیباگ بالاتری دارند. این دو ثابت مکمل یکدیگر هستند و معمولاً در محیط توسعه با هم فعال می‌شوند.

چرا پس از فعال‌سازی WP_DEBUG، سایت کند می‌شود؟

سه دلیل اصلی وجود دارد. نخست، ثبت هر خطا در فایل زمان‌بر است، به‌ویژه اگر تعداد خطاها زیاد باشد. دوم، فعال‌سازی SAVEQUERIES همه کوئری‌ها را در حافظه ذخیره می‌کند که در سایت‌های پرترافیک می‌تواند حافظه را اشباع کند. سوم، نمایش خطاها در خروجی HTML می‌تواند حجم پاسخ را چند برابر کند. راه‌حل، فعال‌سازی این ثابت‌ها فقط در محیط توسعه است.

آیا فعال‌سازی WP_DEBUG روی سئو اثر می‌گذارد؟

بله، اگر در محیط تولید نادرست تنظیم شود. نمایش خطاهای PHP در خروجی HTML، محتوای سایت را آلوده می‌کند و می‌تواند بر رتبه‌بندی اثر منفی بگذارد. همچنین، خطاهای آشکارشده می‌توانند به عنوان سیگنال کیفیت پایین سایت در نظر گرفته شوند. اگر با مسائل سئوی مرتبط مواجه هستید، مطلب اشتباهات رایج سئو که باید کنار بگذارید راهنمای مفیدی است.

چگونه خطاهای JavaScript را در وردپرس عیب‌یابی کنم؟

خطاهای JavaScript در وردپرس از طریق Developer Tools مرورگر قابل مشاهده هستند. کافی است در Chrome یا Firefox، پنل Console را باز کنید و خطاها را مشاهده کنید. ابزارهای پیشرفته‌تر مانند Sentry یا New Relic امکان ثبت خطاهای JavaScript در محیط تولید را فراهم می‌کنند. برای شناخت انواع خطاهای JavaScript، مطلب چگونه خطاهای جاوااسکریپت را در کنسول مرورگر پیدا کنیم؟ راهنمای عملی خوبی است.

آیا می‌توان Debugging را بدون دسترسی به FTP انجام داد؟

بخشی از Debugging بدون دسترسی FTP ممکن است. بررسی لاگ‌ها از طریق پنل هاست، فعال‌سازی WP_DEBUG از طریق wp-config.php (در صورت دسترسی به فایل) و استفاده از افزونه‌هایی مانند Query Monitor، بخشی از فرآیند را ممکن می‌سازد. اما در خطاهای Fatal که مانع بارگذاری پنل می‌شوند، دسترسی FTP ضروری است. در شرایط بحرانی، تماس با پشتیبانی هاست می‌تواند راه‌حل موقت باشد.

نگاهی در سطح معماری هسته و لایه‌های خطا

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

محدودیت اول، نبود مرز واضح میان کد هسته، افزونه‌ها، قالب و کد سفارشی است. همه این لایه‌ها در یک فضای اجرایی مشترک کار می‌کنند و خطا در هر یک می‌تواند علائمی در لایه دیگر تولید کند. این یکپارچگی، شناسایی لایه واقعی خطا را دشوار می‌کند. راه‌حل عملی، استفاده از تکنیک‌های جداسازی است: غیرفعال کردن موقت لایه‌ها، استفاده از محیط‌های ایزوله و ثبت دقیق زنجیره فراخوانی.

محدودیت دوم، ماهیت Stateful وردپرس است. برخلاف برخی سیستم‌ها که در هر درخواست، وضعیت اولیه را از نو می‌سازند، وردپرس از کش، Transient، Option و Session استفاده می‌کند که هر یک می‌تواند وضعیت را در طول زمان تغییر دهد. این ماهیت Stateful، بازسازی دقیق شرایط خطا را دشوار می‌کند. راه‌حل، پاک‌سازی کامل وضعیت در زمان عیب‌یابی است: پاک کردن کش، حذف Transientهای موقت، بازنشانی Sessionها و شروع از وضعیت پایه.

محدودیت سوم، وابستگی به زیرساخت خارجی است. سایت‌های وردپرسی به دیتابیس MySQL، سرور وب، PHP-FPM، کش Redis یا Memcached و در برخی موارد، سرویس‌های خارجی مانند CDN و سرویس ایمیل متکی هستند. خطا در هر یک از این اجزا می‌تواند به‌شکل خطای وردپرس ظاهر شود. عیب‌یابی حرفه‌ای، نیازمند بررسی همه این لایه‌ها به‌صورت هم‌زمان است. اگر با معماری سرور آشنا نیستید، مطلب چگونه امنیت سرور را افزایش دهیم؟ دیدگاه مفیدی ارائه می‌دهد.

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

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

عیب‌یابی حرفه‌ای، پاسخ دادن به سؤال «چرا خطا رخ داد» نیست؛ پاسخ دادن به سؤال «چه چیزی باید تغییر کند تا این خطا دیگر رخ ندهد».

بستن این مسیر

عیب‌یابی حرفه‌ای در وردپرس یک مهارت انباشتی است که با هر پروژه، عمیق‌تر می‌شود. ترکیب ابزارهای بومی مانند WP_DEBUG و WP_DEBUG_LOG با ابزارهای جانبی مانند Query Monitor، تحلیل لاگ سرور و تکنیک Bisection، یک چارچوب کامل عیب‌یابی می‌سازد. نکته کلیدی این است که عیب‌یابی هرگز نباید بر پایه حدس باشد؛ باید بر پایه داده، آزمون فرضیه و مستندسازی منظم بنا شود. اگر امروز تنها یک گام بردارید، بگذارید آن گام پیکربندی صحیح WP_DEBUG و WP_DEBUG_LOG روی محیط تولید با نمایش غیرفعال باشد؛ چون این گام، ارزان‌ترین و مؤثرترین راه برای شروع عیب‌یابی سیستماتیک است. 🐞

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