افزونه روی سایت نصب است، پیشخوان بی‌نقص کار می‌کند، اما روی front-end هیچ‌کدام از دکمه‌ها واکنش نمی‌دهند، فرم‌ها ارسال نمی‌شوند و ویجت‌های تعاملی مرده به‌نظر می‌رسند. اگر با خطای عدم بارگذاری JS افزونه روبرو هستید، این مقاله همان مسیری را طی می‌کند که در سال‌ها کار روی صدها پروژه واقعی وردپرس بارها پیموده‌ام. برخلاف CSS که نبودش را در ظاهر می‌بینید، عدم بارگذاری جاوااسکریپت خودش را ساکت‌تر نشان می‌دهد: عناصر سر جای خودشان هستند ولی رفتارشان از کار افتاده. این خطا در عمل همیشه در یکی از پنج لایه مشخص ریشه دارد: هوک نادرست enqueue، وابستگی نادرست به jQuery یا کتابخانه‌های عمومی، ترتیب اشتباه بارگذاری در برابر inline data، مسیر و نسخه نادرست، و تعارض با افزونه‌های بهینه‌ساز که اسکریپت‌ها را defer یا ترکیب می‌کنند. اگر این پنج لایه را به ترتیب بررسی کنید، تقریباً همیشه به علت دقیق می‌رسید بدون آنکه ساعت‌ها وقت خود را صرف آزمون‌وخطا کنید.

اسکریپت افزونه لود نمی‌شود — تفکیک نشانه‌ها

قبل از هر اقدامی باید دقیقاً مشخص کنید کدام یک از این پنج نشانه را می‌بینید، چون هرکدام مسیر عیب‌یابی متفاوتی را پیش می‌گذارد. نشانه اول: هیچ‌کدام از عناصر افزونه واکنشی ندارند — دکمه‌ها کلیک نمی‌شوند، اسلایدر حرکت نمی‌کند، تب‌ها عوض نمی‌شوند. این حالت تقریباً همیشه به لایه اول (هوک نادرست) یا لایه چهارم (مسیر اشتباه) برمی‌گردد. اگر با پایه‌های معماری افزونه آشنا نیستید، پیش از ادامه نگاهی به افزونه وردپرس چیست بیندازید تا لایه‌بندی و محل بارگذاری اسکریپت‌ها را در ذهن داشته باشید.

نشانه دوم: در کنسول مرورگر خطای Uncaught ReferenceError: jQuery is not defined یا Uncaught TypeError ظاهر می‌شود. این نشانه مستقیماً به لایه دوم (وابستگی نادرست) اشاره دارد. نشانه سوم: در کنسول پیام Uncaught SyntaxError: Unexpected token یا Unexpected end of input می‌بینید — یعنی فایل لود شده ولی محتوایش شکسته یا ناقص است و معمولاً لایه پنجم (minify تهاجمی) مقصر است. نشانه چهارم: هیچ خطایی در کنسول نیست ولی رفتار افزونه کار نمی‌کند. این حالت، دردناک‌ترین حالت است چون هیچ سرنخی به شما نمی‌دهد — و معمولاً به لایه سوم (ترتیب localize) یا بارگذاری شرطی نادرست مربوط می‌شود. نشانه پنجم: در پیشخوان کار می‌کند ولی در front-end لود نمی‌شود یا برعکس، که جهت عیب‌یابی را به لایه هوک محدود می‌کند.

جاوااسکریپت، برخلاف CSS، وقتی نمی‌رسد ساکت است. صفحه به ظاهر سالم به‌نظر می‌رسد ولی رفتار مرده است. اولین ابزاری که باید باز کنید، نه View Source، بلکه Console مرورگر است.

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

وردپرس برای بارگذاری اسکریپت هم همان سیستم صف‌بندی استایل را دارد، ولی با تفاوت‌های مهمی که همین تفاوت‌ها منشأ بسیاری از خطاها هستند. تابع wp_enqueue_script پنج آرگومان می‌گیرد: handle، URL، آرایه وابستگی‌ها، شماره نسخه، و پارامتر in_footer که تعیین می‌کند اسکریپت در head یا پیش از بسته شدن body لود شود. اگر با مفهوم افزونه وردپرس و لایه‌های آن آشنا نیستید، توصیه می‌کنم آن مقاله را مرور کنید چون درک مکانیزم enqueue بدون درک معماری افزونه تقریباً غیرممکن است.

سه نکته کلیدی که درک آن‌ها نیمی از عیب‌یابی است. اول، برخلاف CSS که همیشه در head لود می‌شود، JS می‌تواند در head یا footer لود شود و این انتخاب مستقیماً روی رفتار وابستگی‌ها اثر می‌گذارد. دوم، تابع wp_localize_script داده‌ها را به‌عنوان متغیر JS به اسکریپت شما می‌چسباند و باید دقیقاً بعد از enqueue و قبل از هیچ اسکریپت دیگری که به آن داده وابسته است فراخوانی شود. سوم، هر اسکریپتی که به jQuery وابسته است باید در آرایه وابستگی‌ها jquery را ذکر کند؛ در غیر این صورت وردپرس تضمینی برای لود شدن jQuery قبل از اسکریپت شما نمی‌دهد. برای درک عمیق‌تر جایگاه این هوک‌ها در چرخه اجرای وردپرس، نحوه استفاده صحیح از هوک‌های وردپرس را ببینید.

Contextهوک enqueueنکته ویژه
Front-end سایتwp_enqueue_scriptsپارامتر in_footer معمولاً true
پیشخوان ادمینadmin_enqueue_scriptsjQuery به‌طور پیش‌فرض لود است
صفحه ورودlogin_enqueue_scriptsjQuery لود نیست، وابستگی صریح لازم است
ویرایشگر بلوکیenqueue_block_editor_assetsاز wp-plugins, wp-editor به‌عنوان وابستگی
صفحه سفارشی‌سازیcustomize_controls_enqueue_scriptsjQuery و customize-controls لود است

این جدول سرنخ بسیاری از مشکلات را نشان می‌دهد. مسئله شایع در صفحه ورود، نبود jQuery به‌طور پیش‌فرض است: توسعه‌دهنده استایل و اسکریپت افزونه را در صفحه wp-login.php لود می‌کند و فراموش می‌کند که jQuery در آن صفحه به‌طور خودکار بارگذاری نمی‌شود. نتیجه: اسکریپت خطای undefined می‌دهد و هیچ پیام خطایی روی صفحه ظاهر نمی‌شود مگر آنکه کنسول را باز کنید. برای مرور فهرست کامل این نوع اشتباهات، به اشتباهات رایج هنگام استفاده از هوک‌ها مراجعه کنید.

لایه اول — هوک نادرست و زمان‌بندی enqueue

شایع‌ترین علت عدم بارگذاری JS افزونه، استفاده از هوک اشتباه است. اگر کد را در admin_enqueue_scripts نوشته‌اید ولی انتظار دارید روی front-end لود شود، وردپرس فقط آن را در پیشخوان اجرا می‌کند. اگر از wp_enqueue_scripts استفاده کرده‌اید ولی انتظار دارید در صفحه ورود لود شود، باز هم اجرا نمی‌شود. اگر کد را در wp_head یا wp_footer نوشته‌اید، پس از بسته شدن صف اجرا می‌شود و در خروجی ظاهر نمی‌شود.

الگوی درست برای front-end

الگویی که در همه افزونه‌های خودم به کار می‌برم، با توجه ویژه به پارامتر in_footer:

add_action( 'wp_enqueue_scripts', 'my_plugin_enqueue_frontend_scripts' );

function my_plugin_enqueue_frontend_scripts() {
    wp_enqueue_script(
        'my-plugin-frontend',
        plugins_url( 'assets/js/frontend.js', __FILE__ ),
        array( 'jquery' ),
        '1.0.0',
        true // in_footer
    );
}

سه نکته کلیدی: اول، وابستگی jquery که در لایه دوم توضیح می‌دهم. دوم، پارامتر true که باعث می‌شود اسکریپت در footer لود شود و سرعت رندر صفحه را بهبود دهد. سوم، پارامتر نسخه که از کش ناخواسته مرورگر جلوگیری می‌کند. اگر در بافت فروشگاهی کار می‌کنید و این اسکریپت روی نرخ تبدیل اثر دارد، مطالعه CRO برای فروشگاه‌های ووکامرس دید خوبی درباره اهمیت سرعت JS می‌دهد.

اشتباه رایج: enqueue در template_redirect یا wp

گاهی برای اهداف تشخیصی از هوک‌های دیرهنگام مثل template_redirect یا wp استفاده می‌شود. توجه کنید که wp_enqueue_scripts پیش از این هوک‌ها اجرا می‌شود و پس از آن، صف اسکریپت‌ها بسته می‌شود. اگر پس از این نقطه بخواهید اسکریپت به صف اضافه کنید، وردپرس آن را در خروجی HTML نمی‌آورد. راه‌حل: همیشه enqueue را در wp_enqueue_scripts انجام دهید و از هوک‌های دیگر فقط برای گرفتن اطلاعات استفاده کنید. یک استثنای مهم در این قاعده، اسکریپت‌هایی هستند که به‌عنوان پویا و بر اساس شرایط لحظه‌ای باید اضافه شوند؛ اینها باید با wp_add_inline_script یا از طریق REST API مدیریت شوند.

بارگذاری در صفحه‌های خاص ادمین

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

add_action( 'admin_enqueue_scripts', 'my_plugin_enqueue_admin_scripts' );

function my_plugin_enqueue_admin_scripts( $hook_suffix ) {
    if ( 'settings_page_my-plugin' !== $hook_suffix ) {
        return;
    }
    wp_enqueue_script(
        'my-plugin-admin',
        plugins_url( 'assets/js/admin.js', __FILE__ ),
        array( 'jquery', 'wp-util' ),
        '1.0.0',
        true
    );
}

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

لایه دوم — وابستگی نادرست به jQuery و کتابخانه‌ها

دومین علت شایع عدم بارگذاری JS افزونه، وابستگی نادرست است. اگر اسکریپت شما از jQuery استفاده می‌کند ولی در آرایه وابستگی‌ها ذکر نکرده‌اید، وردپرس تضمینی برای لود شدن jQuery قبل از اسکریپت شما نمی‌دهد. نتیجه: خطای jQuery is not defined در کنسول و مرگ کامل اسکریپت شما.

الگوی درست اعلام وابستگی

برای اسکریپتی که به jQuery وابسته است، الگوی زیر توصیه‌شده است:

wp_enqueue_script(
    'my-plugin-frontend',
    plugins_url( 'assets/js/frontend.js', __FILE__ ),
    array( 'jquery' ), // وابستگی صریح
    '1.0.0',
    true
);

نکته مهم: در وردپرس مدرن، jQuery به‌طور پیش‌فرض در حالت noConflict بارگذاری می‌شود و به‌جای $ باید از jQuery استفاده کنید. اگر در کد خود از $ استفاده می‌کنید، باید آن را داخل یک wrapper قرار دهید:

(function( $ ) {
    // کد شما با استفاده از $
    $( document ).ready( function() {
        // ...
    } );
})( jQuery );

این الگو، کلاسیک‌ترین راه سازگاری با حالت noConflict است. اگر با فایل‌های جاوااسکریپت و ساختار ماژولار آشنایی بیشتری می‌خواهید، آموزش جاوااسکریپت از صفر را ببینید.

وابستگی به کتابخانه‌های عمومی

اگر اسکریپت شما از کتابخانه‌ای مثل React، Vue یا Alpine.js استفاده می‌کند، باید وابستگی را صریح اعلام کنید. در WordPress 5.0 و بالاتر، چند کتابخانه به‌طور رسمی همراه هسته ارائه می‌شوند و می‌توانید از آن‌ها استفاده کنید:

کتابخانهhandle در وردپرسکاربرد
Reactreactبرای بلاک‌های گوتنبرگ
React DOMreact-domرندر React در بستر وردپرس
jQueryjqueryپایه اسکریپت‌های کلاسیک
Underscoreunderscoreتوابع کمکی جاوااسکریپت
Backbonebackboneمدل‌سازی داده در پیشخوان
wp-utilwp-utilتوابع کمکی ajax وردپرس

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

اشتباه رایج: وابستگی به handle که وجود ندارد

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

add_action( 'wp_enqueue_scripts', function() {
    if ( ! wp_script_is( 'my-dependency-handle', 'registered' ) ) {
        error_log( 'Dependency my-dependency-handle is not registered!' );
    }
}, 999 );

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

لایه سوم — ترتیب wp_localize_script و متغیرهای inline

این لایه جایی است که بسیاری از توسعه‌دهندگان حتی نمی‌دانند مسئله وجود دارد. جاوااسکریپت افزونه شما لود می‌شود، درخواست آن در Network موفق است، ولی رفتار افزونه کار نمی‌کند چون متغیرهای داده‌ای که در PHP ساخته و به JS منتقل می‌شوند، پیش از اسکریپت اصلی نوشته نشده‌اند. مکانیزم دقیق این است که wp_localize_script داده‌ها را در HTML به‌صورت یک متغیر JS قبل از اسکریپت هدف تزریق می‌کند. اگر ترتیب اشتباه باشد، اسکریپت شما پیش از آماده شدن داده اجرا می‌شود.

الگوی درست localize

ترتیب صحیح در کد:

wp_enqueue_script(
    'my-plugin-frontend',
    plugins_url( 'assets/js/frontend.js', __FILE__ ),
    array( 'jquery' ),
    '1.0.0',
    true
);

wp_localize_script(
    'my-plugin-frontend',
    'myPluginData',
    array(
        'ajaxUrl' => admin_url( 'admin-ajax.php' ),
        'nonce'   => wp_create_nonce( 'my_plugin_nonce' ),
        'userId'  => get_current_user_id(),
    )
);

نکات مهم: اول، wp_localize_script باید بلافاصله پس از enqueue اسکریپت هدف بیاید. دوم، نام متغیر JS به‌عنوان آرگومان دوم داده می‌شود و در JS با همان نام قابل دسترسی است (myPluginData.ajaxUrl). سوم، داده‌ها به‌صورت امن (escaped) در HTML تزریق می‌شوند، پس نیازی به escape دستی نیست. چهارم، در وردپرس مدرن توصیه می‌شود از wp_add_inline_script به‌جای wp_localize_script استفاده کنید چون کد تولیدشده تمیزتر است، ولی wp_localize_script همچنان برای داده‌های ساده (نه اسکریپت کامل) کاربرد دارد.

ترتیب اشتباه و پیامد آن

اگر ترتیب برعکس باشد — یعنی wp_localize_script قبل از enqueue فراخوانی شود — وردپرس نماد هشدار نمی‌دهد و کاری هم نمی‌کند. نتیجه: در JS، متغیر شما undefined است و در کنسول خطای Cannot read property of undefined می‌بینید. این خطا اغلب توسعه‌دهنده را به سمت اشتباهی می‌فرستد چون فرض می‌کند مشکل در JS است، در حالی که مشکل در ترتیب فراخوانی در PHP است.

wp_add_inline_script و فراخوانی‌های وابسته

الگوی مدرن برای تزریق داده یا کد اجرایی:

wp_add_inline_script(
    'my-plugin-frontend',
    'window.myPluginConfig = ' . wp_json_encode( array( 'ajaxUrl' => admin_url( 'admin-ajax.php' ) ) ) . ';',
    'before'
);

پارامتر سوم (before یا after) تعیین می‌کند اسکریپت inline قبل یا بعد از اسکریپت هدف قرار بگیرد. برای داده‌های پیکربندی، before توصیه می‌شود؛ برای اجرای کد پیگیری، after. اشتباه در این پارامتر منشأ خطاهایی است که در آن‌ها اسکریپت شما داده را نمی‌بیند ولی محتوای داده در HTML وجود دارد.

wp_localize_script و wp_add_inline_script به‌تنهایی کار نمی‌کنند — وابسته به دستور enqueue هستند. اگر دستور enqueue اجرا نشود، داده‌ها هم تزریق نمی‌شوند و در نگاه اول به‌نظر می‌رسد مشکل در JS است، در حالی که ریشه در PHP است.

لایه چهارم — مسیر، نسخه و پارامتر in_footer

لایه چهارم، جایی است که اسکریپت درست enqueue می‌شود ولی به خاطر مسیر یا نسخه اشتباه، درخواست به سرور با خطای ۴۰۴ مواجه می‌شود یا مرورگر نسخه قدیمی را از کش می‌خواند. این لایه در پروژه‌هایی که فایل‌ها جابه‌جا می‌شوند یا محتوای اسکریپت تغییر می‌کند، منشأ سردرگمی زیادی است.

استفاده از توابع صحیح برای ساخت مسیر

همانند CSS، سه تابع استاندارد برای ساخت مسیر اسکریپت استفاده می‌شود:

// برای فایل‌های داخل افزونه
plugins_url( 'assets/js/script.js', __FILE__ );

// برای فایل‌های داخل قالب
get_stylesheet_directory_uri() . '/assets/js/script.js';

// برای فایل‌های داخل parent theme از داخل child theme
get_template_directory_uri() . '/assets/js/script.js';

اشتباه رایج: استفاده از get_template_directory_uri() در child theme و انتظار دسترسی به فایل‌های child. این مسئله در مبحث قالب چایلد وردپرس چیست به تفصیل توضیح داده شده و در بافت بارگذاری اسکریپت‌های اختصاصی بسیار شایع است.

مدیریت نسخه و کش

پارامتر نسخه در wp_enqueue_script باعث می‌شود URL نهایی به‌صورت script.js?ver=1.0.0 ساخته شود. هر بار که نسخه را تغییر دهید، URL تغییر می‌کند و مرورگر مجبور می‌شود فایل جدید را دانلود کند. اگر نسخه را تغییر ندهید، مرورگر نسخه قدیمی را از کش می‌خواند و شما فکر می‌کنید اسکریپت جدید لود نمی‌شود. الگوی توصیه‌شده در پروژه‌های خودم:

define( 'MY_PLUGIN_VERSION', '1.0.0' );

wp_enqueue_script(
    'my-plugin-frontend',
    plugins_url( 'assets/js/frontend.js', __FILE__ ),
    array( 'jquery' ),
    MY_PLUGIN_VERSION,
    true
);

با هر تغییر محتوای JS، مقدار MY_PLUGIN_VERSION را افزایش دهید. بهتر است این مقدار به‌طور خودکار از زمان آخرین تغییر فایل مشتق شود:

$script_path = plugin_dir_path( __FILE__ ) . 'assets/js/frontend.js';
$script_ver  = file_exists( $script_path ) ? filemtime( $script_path ) : '1.0.0';

wp_enqueue_script(
    'my-plugin-frontend',
    plugins_url( 'assets/js/frontend.js', __FILE__ ),
    array( 'jquery' ),
    $script_ver,
    true
);

استفاده از filemtime، در پروژه‌هایی که نسخه افزونه را زیاد تغییر نمی‌دهند اما محتوای JS تغییر می‌کند، بسیار کارساز است. این تکنیک جلوی کش ناخواسته مرورگر را می‌گیرد بدون آنکه نیاز به تغییر دستی نسخه باشد.

پارامتر in_footer و پیامدهای آن

پارامتر پنجم wp_enqueue_script تعیین می‌کند اسکریپت در head یا footer لود شود. اگر true باشد، اسکریپت به footer منتقل می‌شود که برای سرعت بهتر است. اما این پارامتر پیامدهای مهمی دارد که نادیده گرفتن‌شان منشأ خطاهای مبهم است:

  1. اسکریپت‌های وابسته به in_footer: اگر اسکریپت A در footer است و اسکریپت B به A وابسته است ولی خودش در head لود می‌شود، وردپرس B را به footer منتقل می‌کند تا ترتیب حفظ شود. این رفتار گاهی باعث می‌شود اسکریپتی که باید در head لود شود، دیرتر از انتظار بارگذاری شود.
  2. اسکریپت‌های inline وابسته: اگر با wp_add_inline_script کد inline به اسکریپت اضافه کنید، این کد هم به footer منتقل می‌شود. اگر کد inline شما باید در head اجرا شود، باید پارامتر in_footer را false قرار دهید.
  3. اسکریپت‌های header-critical: اسکریپت‌هایی که برای تشخیص device یا بارگذاری قالب استفاده می‌شوند، باید در head لود شوند تا جلوی پرش محتوا (CLS) را بگیرند. این مسئله در بهینه‌سازی Core Web Vitals چیست توضیح داده شده و در بافت اسکریپت‌ها اهمیت بالایی دارد.

Mixed Content و SSL

اگر سایت روی HTTPS است و URL اسکریپت با http:// سخت‌کد شده، مرورگر درخواست را بلاک می‌کند. استفاده از توابع استاندارد (plugins_url، get_stylesheet_directory_uri) این مسئله را به‌طور خودکار حل می‌کند چون پروتکل فعلی سایت را تشخیص می‌دهند. اگر با این وجود مشکل ادامه دارد، احتمالاً URL در دیتابیس ذخیره شده و باید با wp search-replace تبدیل شود.

لایه پنجم — تعارض با defer، minify و افزونه‌های بهینه‌ساز

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

defer و async در برابر وابستگی‌ها

افزونه‌های بهینه‌ساز برای بهبود سرعت، اسکریپت‌ها را به defer یا async تبدیل می‌کنند. این کار در ظاهر مفید است، ولی وابستگی‌های اسکریپت را می‌شکند: اگر jQuery با defer لود شود و اسکریپت شما بدون defer، ترتیب اجرا به‌هم می‌ریزد و اسکریپت شما پیش از jQuery اجرا می‌شود. نتیجه: jQuery is not defined در کنسول.

راه‌حل: در تنظیمات افزونه بهینه‌ساز، اسکریپت خود را از فرآیند defer استثنا کنید، یا در کد افزونه، با استفاده از فیلتر script_loader_tag، خروجی تگ را خودتان مدیریت کنید:

add_filter( 'script_loader_tag', function( $tag, $handle ) {
    if ( 'my-plugin-frontend' !== $handle ) {
        return $tag;
    }
    // اطمینان از اینکه defer اضافه نشود
    return str_replace( ' defer', '', $tag );
}, 10, 2 );

این الگو در پروژه‌هایی که با افزونه‌های تهاجمی مثل Autoptimize یا WP Rocket کار می‌کنند، بسیار کارساز است. برای مطالعه رفتار افزونه‌های بهینه‌ساز و نحوه تعاملشان با اسکریپت‌های افزونه، بهترین افزونه‌های کش وردپرس را ببینید.

minify تهاجمی و شکستن کد مدرن

اگر اسکریپت شما از ویژگی‌های ES6+ مثل arrow functions، template literals یا destructuring استفاده می‌کند، minify کننده‌های قدیمی ممکن است آن‌ها را به‌درستی پردازش نکنند و کد شکسته تولید شود. علامتش Unexpected token در کنسول است. راه‌حل: یا فایل خود را از فرآیند minify استثنا کنید، یا از نسخه‌های جدیدتر افزونه بهینه‌ساز که با ES6+ سازگارند استفاده کنید. راهنماهای عمومی minify و رفتارشان در بافت وردپرس در مقالات افزونه‌های کش توصیه می‌شود.

ترکیب (Combine) و شکستن ترتیب وابستگی

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

پاک کردن کش پس از هر تغییر

اگر محتوای JS تغییر می‌کند ولی رفتار روی سایت عوض نمی‌شود، کش سرور، کش افزونه، کش CDN یا کش مرورگر مسئول است. توالی درست پاک کردن کش مشابه آنچه در بافت CSS توضیح داده شده است:

  1. پاک کردن کش افزونه کش وردپرس.
  2. پاک کردن کش CDN اگر استفاده می‌کنید. برای درک نقش CDN در بافت اسکریپت‌ها، نقش CDN در سرعت سایت را ببینید.
  3. پاک کردن کش مرورگر با Ctrl + Shift + R یا استفاده از پنجره ناشناس.
  4. تست در Network مرورگر که درخواست با کد ۲۰۰ و محتوای جدید برمی‌گردد یا نه.

کنسول مرورگر — ابزار اصلی عیب‌یابی JS

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

  1. فیلتر بر اساس نوع خطا: در کنسول، بین پیام‌های Error، Warning و Info تمایز بگذارید. خطاهای مرتبط با جاوااسکریپت افزونه شما معمولاً در دسته Error هستند ولی خطاهای بارگذاری فایل در دسته Network نمایش داده می‌شوند.
  2. شماره خط در فایل: خطاهای JS معمولاً شماره خط و نام فایل را نشان می‌دهند. این اطلاعات مسیر عیب‌یابی را کوتاه می‌کند. اگر فایل minify شده است، ممکن است شماره خط مفید نباشد ولی نام فایل معمولاً کاملاً واضح است.
  3. Point of failure: خطایی که اول ظاهر می‌شود معمولاً علت است و خطاهای بعدی معلول. اگر خطای اول را بردارید، خطاهای بعدی معمولاً از بین می‌روند.

علاوه بر کنسول، تب Network هم نقش کلیدی دارد: با فیلتر JS می‌توانید ببینید کدام اسکریپت‌ها لود می‌شوند، کدام‌ها ۴۰۴ می‌دهند، و کدام‌ها از کش سرو می‌شوند. ترکیب این دو تب، ۹۰٪ عیب‌یابی JS را پوشش می‌دهد. برای مطالعه رویکرد سیستماتیک‌تر در دیباگ پروژه‌های وردپرس، تست و دیباگ پروژه‌های توسعه وردپرس را ببینید.

کنسول مرورگر، دفترچه خاطرات سایت شماست. هر خطای JS یک اعتراف است؛ اگر آن را نادیده بگیرید، سراغ لایه‌های بی‌ربط می‌روید و ساعت‌ها هدر می‌دهید.

پرسش‌های پرتکرار درباره بارگذاری نشدن JS افزونه

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

چرا اسکریپت افزونه در پیشخوان کار می‌کند ولی در front-end نه؟

شایع‌ترین علت، اتصال کد enqueue به هوک admin_enqueue_scripts است که فقط در پیشخوان اجرا می‌شود. برای رفع، همان تابع را به wp_enqueue_scripts هم وصل کنید یا یک تابع جدا برای front-end بنویسید. مسئله دیگر که در پروژه‌های واقعی دیده‌ام: تفاوت jQuery در دو context. در پیشخوان، jQuery به‌طور پیش‌فرض لود است؛ در front-end، فقط اگر وابستگی صریح اعلام کنید. اگر افزونه شما jQuery لازم دارد و در front-end وابستگی را ذکر نکرده‌اید، خطای undefined می‌گیرید.

چرا خطای jQuery is not defined می‌گیرم؟

دو علت اصلی. اول، وابستگی jquery را در آرایه وابستگی‌های wp_enqueue_script ذکر نکرده‌اید. دوم، افزونه بهینه‌ساز ترتیب لود را با defer یا async به‌هم زده. برای تشخیص، در Network ببینید آیا jQuery لود می‌شود و پیش از اسکریپت شماست یا نه. اگر جواب منفی است، مشکل از لایه دوم یا پنجم است. برای مطالعه مکانیزم دقیق وابستگی‌ها در بافت هوک‌های وردپرس، نحوه استفاده صحیح از هوک‌های وردپرس را ببینید.

چرا اسکریپت لود می‌شود ولی کار نمی‌کند؟

این شایع‌ترین حالت است و سه علت ممکن دارد: اول، داده‌های wp_localize_script قبل از اسکریپت تزریق نشده و در JS به‌صورت undefined ظاهر می‌شوند. دوم، minify تهاجمی کد را شکسته. سوم، یک افزونه دیگر روی همان DOM element رفتار متفاوتی اعمال می‌کند. تشخیص: در کنسول با console.log( window.myPluginData ) ببینید آیا داده‌ها می‌رسند یا نه. اگر داده‌ها درست می‌رسند، به لایه پنجم بروید. اگر نه، به لایه سوم.

چرا اسکریپت در صفحه خاصی لود می‌شود ولی در بقیه نه؟

این نشانه بارگذاری شرطی نادرست است. اگر از توابع تشخیصی مثل is_single، is_page یا has_shortcode استفاده می‌کنید، احتمالاً شرایط در برخی صفحه‌ها برآورده نمی‌شود. برای تشخیص سریع، با error_log مقدار این توابع را در بافت‌های مختلف لاگ کنید. برای مرور دقیق این توابع در بافت post typeهای سفارشی، توابع وردپرس برای ساخت کوئری سفارشی را ببینید.

آیا افزونه‌های بهینه‌ساز می‌توانند باعث بارگذاری نشدن JS شوند؟

بله و در عمل شایع‌ترین علت لایه پنجم است. افزونه‌هایی مثل Autoptimize یا WP Rocket که اسکریپت‌ها را combine، minify یا defer می‌کنند، می‌توانند ترتیب وابستگی‌ها را به‌هم بزنند. راه‌حل: اسکریپت افزونه خود را در تنظیمات افزونه بهینه‌ساز استثنا کنید. اگر با افزونه‌های محبوب کار می‌کنید، برای هرکدام تنظیمات استثنا در مستنداتشان توضیح داده شده و در بهترین افزونه‌های کش وردپرس به آن پرداخته‌ام.

آیا می‌توان اسکریپت را فقط در صفحه‌های دارای شورتکد لود کرد؟

بله، با ترکیب has_shortcode و has_block. الگوی درست:

add_action( 'wp_enqueue_scripts', function() {
    global $post;
    if ( ! is_a( $post, 'WP_Post' ) ) {
        return;
    }
    $has_sc = has_shortcode( $post->post_content, 'my_plugin_form' );
    $has_bl = function_exists( 'has_block' ) && has_block( 'my-plugin/form-block', $post );
    if ( $has_sc || $has_bl ) {
        wp_enqueue_script( 'my-plugin-frontend', /* ... */ );
    }
} );

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

آیا نصب افزونه‌های نال می‌تواند باعث بارگذاری نشدن JS شود؟

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

معماری پایدار برای بارگذاری مطمئن اسکریپت

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

  1. یک فایل مسئول enqueue: همه enqueueها را در یک فایل اختصاصی نگه دارید. این جداسازی، عیب‌یابی و بازبینی کد را بسیار ساده‌تر می‌کند.
  2. پیشوند یکتا برای handleها: همیشه نام افزونه را به‌عنوان پیشوند handle استفاده کنید تا شانس تصادم با افزونه‌های دیگر به‌شدت کاهش یابد.
  3. وابستگی صریح: اگر اسکریپت شما به jQuery، React یا هر کتابخانه دیگری وابسته است، وابستگی را صریح اعلام کنید. هرگز به ترتیب پیش‌فرض وردپرس تکیه نکنید.
  4. ترتیب صحیح localize: wp_localize_script یا wp_add_inline_script را همیشه پس از enqueue قرار دهید تا داده‌ها پیش از اسکریپت شما تزریق شوند.
  5. بارگذاری شرطی: اسکریپت را فقط در بافت‌هایی که لازم است لود کنید. این کار هم بار سایت را کاهش می‌دهد و هم شانس تعارض را کم می‌کند.
  6. استفاده از توابع استاندارد URL: plugins_url برای افزونه، get_stylesheet_directory_uri برای child theme، get_template_directory_uri برای parent theme.
  7. مدیریت نسخه با filemtime: از پارامتر نسخه با مقدار filemtime استفاده کنید تا تغییرات فایل به‌طور خودکار کش را بشکند.
  8. سازگاری با افزونه‌های بهینه‌ساز: در مستندات افزونه، فهرست handleها را ارائه دهید تا کاربران بتوانند از فرآیند defer یا minify استثنا کنند.
  9. تست روی محیط استجینگ: قبل از انتشار نسخه جدید، روی محیط استجینگ با افزونه‌های واقعی کاربران تست کنید. ساخت محیط استجینگ در توسعه وردپرس با محیط لوکال و انتقال امن به زنده در تغییر قالب بدون آسیب به سایت توضیح داده شده است.
  10. رعایت استانداردهای کدنویسی: استانداردهای وردپرس نه فقط برای زیبایی، بلکه برای سازگاری طراحی شده‌اند. مرور آنها در استانداردهای کدنویسی وردپرس چیست و کاربرد عملی در استفاده از WordPress Coding Standards در پروژه‌ها آمده است.

یک نکته از تجربه شخصی در پروژه‌های فروشگاهی: نبود یا شکست یک اسکریپت در صفحه تسویه حساب یا صفحه محصول، مستقیماً روی نرخ تبدیل اثر می‌گذارد. اگر با فروشگاه ووکامرس کار می‌کنید، تست پیش و پس از انتشار نسخه جدید توصیه می‌شود؛ به‌ویژه در بافت CRO برای فروشگاه‌های ووکامرس که به تفصیل به این موضوع پرداخته‌ام.

سخن پایانی

خطای عدم بارگذاری JS افزونه، در نگاه اول یکی از دشوارترین انواع خطا در وردپرس است چون خودش را ساکت نشان می‌دهد: صفحه سالم به‌نظر می‌رسد، استایل‌ها سر جایشان هستند، ولی رفتار از کار افتاده. این خطا در عمل همیشه در یکی از پنج لایه‌ای که در این مقاله بررسی کردیم ریشه دارد: هوک نادرست، وابستگی نادرست، ترتیب اشتباه localize، مسیر و نسخه، و تعارض با defer یا minify. کنسول مرورگر، همان ابزاری است که در ۹۰ درصد موارد سرنخ را در چند ثانیه می‌دهد؛ بدون آن، عیب‌یابی مثل جستجو در تاریکی است. در بلندمدت، انضباط در اعلام وابستگی صریح، ترتیب صحیح localize، و مدیریت نسخه با filemtime، مهم‌تر از هر راه‌حل لحظه‌ای است — چون این انضباط است که اجازه نمی‌دهد این نوع خطا دوباره ظاهر شود و توسعه‌دهنده بعدی را هم به همان سرگردانی گرفتار کند.

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