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

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

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

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

در عیب‌یابی عدم نمایش فرم، اولین سؤال این نیست که «کد من کجاست» بلکه این است «فرم در کدام‌یک از این سه لحظه ناپدید می‌شود؟» — در زمان ثبت شورتکد، در زمان اجرای تابع رندر، یا در زمان نمایش روی مرورگر. هر لحظه، لایه متفاوتی دارد.

فرم‌ها در افزونه‌های وردپرس چطور رندر می‌شوند؟

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

مکانیزم کلی شورتکد این است که وردپرس در زمان رندر محتوا، الگوهایی مثل [my_form] را در متن جستجو می‌کند و هر الگو را با نتیجه فراخوانی تابع ثبت‌شده در add_shortcode جایگزین می‌کند. اگر تابع ثبت‌شده وجود نداشته باشد، وردپرس متن خام را دست‌نخورده رها می‌کند و همان متن روی صفحه نمایش داده می‌شود. اگر تابع وجود داشته باشد ولی مقدار بازنگرداند، وردپرس یک رشته خالی جایگزین می‌کند و به‌جای فرم، یک فضای خالی دیده می‌شود. برای مرور کامل مکانیزم ساخت شورتکد و اصول آن، ساخت شورت‌کد با کدنویسی وردپرس را ببینید — این مقاله بر پیش‌فرض آشنایی با آن بنا شده است.

مکانیزمنقطه ضعف رایجنشانه در فرانت
شورتکدثبت نادرست یا return نشدهمتن خام یا فضای خالی
بلوک گوتنبرگناسازگاری نسخه یا عدم بارگذاری assetبلوک خالی یا خطای کنسول
ویجتثبت نادرست در widgets_initعدم نمایش در سایدبار
تمپلیت تگ در قالبعدم صدا زدن تابع در فایل قالبعدم نمایش در محل مشخص

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

لایه اول — ثبت نادرست شورتکد و hook فرم

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

عدم تطابق نام شورتکد

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

define( 'MY_PLUGIN_FORM_SHORTCODE', 'my_form' );

add_shortcode( MY_PLUGIN_FORM_SHORTCODE, 'my_plugin_render_form' );

function my_plugin_render_form( $atts ) {
    // منطق رندر فرم
    return $html;
}

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

هوک نادرست یا بارگذاری دیرهنگام

شورتکدها باید پیش از آنکه فیلتر the_content اجرا شود، ثبت شده باشند. اگر add_shortcode را داخل یک هوک دیرهنگام مثل wp_footer یا template_redirect بگذارید، وردپرس در لحظه پردازش محتوا هنوز آن را نمی‌شناسد. الگوی درست، ثبت در زمان اجرای فایل افزونه یا در هوک init است:

// روش درست — مستقیم در فایل اصلی افزونه
add_shortcode( 'my_form', 'my_plugin_render_form' );

// یا اگر می‌خواهید درون کلاس باشد
add_action( 'init', array( $this, 'register_shortcodes' ) );
public function register_shortcodes() {
    add_shortcode( 'my_form', array( $this, 'render_form' ) );
}

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

شرط‌گذاری ناخواسته و بارگذاری ناقص

گاهی add_shortcode داخل یک شرط مثل if ( is_admin() ) یا if ( is_singular( 'post' ) ) قرار می‌گیرد که باعث می‌شود شورتکد فقط در بافت خاصی ثبت شود. نتیجه: فرم در برخی صفحه‌ها کار می‌کند و در برخی دیگر متن خام نمایش داده می‌شود. برای درک معماری درست افزونه و پیشگیری از این نوع خطا، ساختار فایل‌های یک افزونه استاندارد وردپرس را ببینید. اگر افزونه را خودتان توسعه می‌دهید و ساختار کلاسی را با هوک‌ها ترکیب می‌کنید، رعایت استانداردهای کدنویسی که در استانداردهای کدنویسی وردپرس چیست توضیح داده شده، این نوع خطاها را به حداقل می‌رساند.

شورتکدی که وجود دارد ولی هیچ‌وقت ثبت نشده، مثل کلیدی است که قفلی برایش ساخته‌ایم. مطمئن شوید add_shortcode دقیقاً در زمانی اجرا می‌شود که وردپرس به آن نیاز دارد — نه زودتر که فراموش شود، نه دیرتر که به کار نیاید.

لایه دوم — بارگذاری شرطی اشتباه

لایه دوم جایی است که شورتکد ثبت شده ولی در برخی صفحه‌ها یا برخی بافت‌ها نمایش داده نمی‌شود. این لایه شایع‌ترین علت «فرم در یک برگه کار می‌کند ولی در برگه دیگر نه» است. سه زیرگروه مهم در این لایه وجود دارد.

شرط‌های is_singular، is_page و has_shortcode

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

add_action( 'wp_enqueue_scripts', function() {
    global $post;
    if ( ! is_a( $post, 'WP_Post' ) ) {
        return;
    }

    $has_sc = has_shortcode( $post->post_content, 'my_form' );
    $has_bl = function_exists( 'has_block' ) && has_block( 'my-plugin/form-block', $post );

    if ( $has_sc || $has_bl ) {
        wp_enqueue_style( 'my-plugin-form' );
        wp_enqueue_script( 'my-plugin-form' );
    }
} );

نکته کلیدی در این کد: بررسی is_a که تضمین می‌کند $post واقعاً یک آبجکت است (در بافت‌هایی مثل آرشیو، ممکن است null باشد). بررسی همزمان has_shortcode و has_block که تضمین می‌کند فرم در هر دو حالت شورتکد سنتی و بلوک گوتنبرگ شناسایی شود. اگر has_block را فراموش کنید و کاربر فرم را از طریق بلوک اضافه کرده باشد، شرط برآورده نمی‌شود و assetهای فرم بارگذاری نمی‌شوند — نتیجه: HTML فرم در صفحه هست ولی CSS و JS آن نیست، و فرم به‌هم‌ریخته یا بی‌واکنش نمایش داده می‌شود. این مسئله دقیقاً به همان مقالات خطای عدم بارگذاری CSS افزونه و خطای عدم بارگذاری JS افزونه مربوط می‌شود که به تفصیل به آن پرداخته‌ام.

بافت‌های خارج از the_content

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

جایگاه شورتکداجرا می‌شود؟راهکار
محتوای نوشته یا برگهبله—
عنوان نوشتهخیرفیلتر the_title
خلاصه (Excerpt)خیرفیلتر get_the_excerpt
ویجت متنوابسته به قالبفیلتر widget_text
آیتم منوخیرفیلتر wp_nav_menu_items
فیلد سفارشیخیرصدا زدن do_shortcode دستی

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

بارگذاری منوط به نقش کاربر

برخی افزونه‌ها فرم را فقط برای کاربران واردشده یا فقط برای نقش‌های خاص نمایش می‌دهند. اگر شرط is_user_logged_in یا current_user_can نادرست تنظیم شده باشد، فرم برای کاربر هدف نمایش داده نمی‌شود. راه تشخیص: با حساب کاربری مختلف (مهمان، مشترک، مدیر) تست کنید. این مسئله در پروژه‌هایی که فرم‌های عضویت یا فرم‌های اختصاصی مشتری دارند شایع است.

لایه سوم — خروجی buffered و بازنگرداندن مقدار

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

اشتباه کلاسیک: echo به‌جای return

شایع‌ترین اشتباه در این لایه، استفاده از echo به‌جای return در تابع رندر است. وردپرس انتظار دارد تابع add_shortcode مقدار بازگشتی بدهد، نه اینکه مستقیم به مرورگر چاپ کند:

// غلط — باعث ناپدید شدن فرم می‌شود
add_shortcode( 'my_form', function( $atts ) {
    echo '<form>...</form>';
} );

// درست
add_shortcode( 'my_form', function( $atts ) {
    return '<form>...</form>';
} );

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

الگوی درست با Output Buffering

الگوی حرفه‌ای که در افزونه‌های خودم استفاده می‌کنم، استفاده از Output Buffering برای تولید HTML پیچیده است:

function my_plugin_render_form( $atts ) {
    $atts = shortcode_atts( array(
        'title' => 'فرم تماس',
        'type'  => 'contact',
    ), $atts, 'my_form' );

    ob_start();
    ?>
    <form class="my-plugin-form" method="post">
        <h3><?php echo esc_html( $atts['title'] ); ?></h3>
        <input type="hidden" name="form_type" value="<?php echo esc_attr( $atts['type'] ); ?>" />
        <?php wp_nonce_field( 'my_plugin_form_submit', 'my_plugin_nonce' ); ?>
        <label>
            نام:
            <input type="text" name="name" required />
        </label>
        <button type="submit">ارسال</button>
    </form>
    <?php
    return ob_get_clean();
}

سه نکته کلیدی در این کد: اول، ob_start() که خروجی را در بافر می‌گیرد. دوم، ob_get_clean() که بافر را می‌خواند و پاک می‌کند و به‌عنوان رشته برمی‌گرداند. سوم، wp_nonce_field برای امنیت فرم که در بافت افزونه‌های فرم بسیار مهم است. اگر این الگو را رعایت کنید، حتی تابع رندر پیچیده هم مقدار درستی برمی‌گرداند و فرم روی صفحه ظاهر می‌شود. برای مطالعه بیشتر درباره escape خروجی و امنیت فرم، پاک‌سازی داده‌ها در کدنویسی وردپرس و نوشتن کد PHP امن برای وردپرس را ببینید.

اشتباه در shortcode_atts و پارامترها

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

$atts = shortcode_atts(
    array( 'title' => 'فرم تماس' ),
    $atts,
    'my_form' // نام شورتکد به‌عنوان آرگومان سوم
);

آرگومان سوم برای فیلتر shortcode_atts_{$tag} استفاده می‌شود و به افزونه‌های دیگر اجازه می‌دهد مقادیر پیش‌فرض را تغییر دهند. فراموش کردن این آرگومان معمولاً خطا نمی‌دهد ولی رفتار غیرقابل پیش‌بینی ایجاد می‌کند.

خطای PHP درون تابع رندر

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

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

این سه خط را در wp-config.php قرار دهید و پس از تلاش برای نمایش صفحه، لاگ را بررسی کنید. خطاهایی مثل Warning: Undefined variable یا Fatal error: Call to undefined function در همین لاگ دیده می‌شوند و مسیر تشخیص را کوتاه می‌کنند. برای رویکرد کامل دیباگ، دیباگ کردن کدهای سفارشی وردپرس و در بافت پروژه‌های بزرگ‌تر تست و دیباگ پروژه‌های توسعه وردپرس را ببینید.

در شورتکدها، echo هرگز جایگزین return نمی‌شود. اگر فرم شما ناپدید می‌شود، پیش از هر چیز تابع رندر را بررسی کنید — احتمالاً echo در جایی وجود دارد که باید return داشته باشد.

لایه چهارم — گوتنبرگ، صفحه‌سازها و بلوک‌های مدرن

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

شورتکد درون بلوک پاراگراف و بلوک Shortcode

گوتنبرگ یک بلوک اختصاصی به نام «Shortcode» دارد که برای همین منظور ساخته شده. اگر شورتکد فرم را داخل بلوک Paragraph به‌عنوان متن خام بنویسید، در پیش‌نمایش ویرایشگر خروجی نشان داده نمی‌شود (چون بلوک Paragraph فقط HTML خالص را نمایش می‌دهد)، ولی روی front-end شورتکد اجرا می‌شود. برای دیدن نتیجه واقعی در ویرایشگر، از «پیش‌نمایش در تب جدید» یا از بلوک Shortcode اختصاصی استفاده کنید که از پنل بلوک‌ها با جستجوی «Shortcode» قابل افزودن است. برای درک کامل معماری گوتنبرگ و آینده آن، گوتنبرگ و آینده ویرایش محتوا در وردپرس را ببینید.

ناسازگاری با بلوک‌های پویا و Query Loop

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

سازگاری با صفحه‌سازها

صفحه‌سازها مثل Elementor، Divi، یا WPBakery، هر بلوک خودشان را مستقل رندر می‌کنند و گاهی محتوا را به‌عنوان HTML خام ذخیره می‌کنند که دیگر از فیلتر the_content عبور نمی‌کند. اگر از صفحه‌ساز استفاده می‌کنید، سه راه دارید: اول، از ویجت/ماژول Shortcode اختصاصی همان صفحه‌ساز استفاده کنید. دوم، در تابع رندر بلوک خود، do_shortcode را صریحاً فراخوانی کنید. سوم، از مکانیزم native صفحه‌ساز برای فرم استفاده کنید. نکته مهم: حتی وقتی شورتکد در صفحه‌ساز کار می‌کند، assetهای CSS و JS آن ممکن است به‌طور خودکار بارگذاری نشوند. اگر فرم شما روی سایت ظاهر می‌شود ولی استایل ندارد، مسئله در بافت بررسی سازگاری قالب با افزونه‌ها قابل ردیابی است.

بلوک‌های Reusable و Block Patterns

اگر شورتکد فرم را در یک Reusable Block (بلوک قابل استفاده مجدد) یا Block Pattern قرار داده‌اید، توجه کنید که در برخی نسخه‌های گوتنبرگ این بلوک‌ها محتوای خود را کش می‌کنند و بعد از ویرایش شورتکد، تغییرات منعکس نمی‌شود. راه‌حل: بلوک را حذف و از نو اضافه کنید، یا از منوی «Reusable Blocks» نسخه ذخیره‌شده را ویرایش کنید.

لایه پنجم — افزونه‌های امنیتی، کش و CSP

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

افزونه‌های امنیتی و مسدودسازی فرم

افزونه‌های امنیتی مثل Wordfence یا Sucuri در حالت خیلی سختگیرانه ممکن است فرم شما را به‌عنوان فرم مشکوک علامت‌گذاری کنند، به‌خصوص اگر فرم شامل فیلدهای حساس یا درخواست‌های AJAX باشد. این مسئله در پروژه‌های واقعی چندین بار دیده‌ام. راه تشخیص: افزونه امنیتی را موقتاً غیرفعال کنید و سایت را تست کنید. اگر مشکل حل شد، در تنظیمات همان افزونه، فرم یا مسیر افزونه خود را استثنا کنید. برای مرور رفتار افزونه‌های امنیتی محبوب، بهترین افزونه‌های امنیتی وردپرس را ببینید.

Content Security Policy و CSP Blocking

اگر سایت شما Content Security Policy (CSP) دارد، ممکن است اسکریپت‌های فرم شما به‌دلیل نقض CSP بلاک شوند و فرم بدون JS باقی بماند. نشانه: در کنسول مرورگر پیام Refused to load the script because it violates the following Content Security Policy directive. راه‌حل: در هدر CSP سایت، دامنه اسکریپت‌های افزونه خود را استثنا کنید یا از nonce-based CSP استفاده کنید. این مسئله در سایت‌هایی که از افزونه‌های امنیتی پیشرفته یا هدرهای امنیتی سختگیرانه استفاده می‌کنند شایع‌تر است.

کش و نسخه‌های قدیمی فرم

افزونه‌های کش، محتوای رندرشده را ذخیره می‌کنند و اگر بعد از ویرایش فرم، کش پاک نشود، بازدیدکنندگان نسخه قدیمی را می‌بینند. اگر فرم شما فقط روی برخی دستگاه‌ها نمایش داده نمی‌شود یا فقط در حالت مهمان، مسئله می‌تواند کش باشد. تفاوت را با پاک کردن کامل کش و رفرش سخت مرورگر تشخیص دهید. برای مطالعه دقیق رفتار افزونه‌های کش با فرم‌های پویا، بهترین افزونه‌های کش وردپرس را ببینید. مسئله مهم دیگر: اگر فرم شما با AJAX کار می‌کند، فرم‌های پویا باید از کش صفحه استثنا شوند یا از fragment cache استفاده کنند. برای سنجش اثر سرعت فرم روی تجربه کاربری، Core Web Vitals چیست را ببینید.

مشکلات ناشی از محدودیت منابع سرور

در موارد نادر، فرم شما ممکن است به‌دلیل محدودیت منابع سرور کار نکند. مثلاً اگر فرم شما یک کوئری سنگین به دیتابیس می‌زند یا فایل بزرگی را پردازش می‌کند، سرور ممکن است درخواست را نیمه‌کاره قطع کند. علامتش معمولاً خطای ۵۰۰ یا timeout است. برای مرور این نوع خطاها، خطای حافظه در وردپرس: علت و راه حل و اصول کاهش مصرف منابع هاست را ببینید.

چک‌لیست دیباگ گام‌به‌گام عدم نمایش فرم

این ترتیبی است که در پروژه‌های واقعی طی می‌کنم. اگر ترتیب را حفظ کنید، از ارزان‌ترین و سریع‌ترین راه به پیچیده‌ترین می‌رسید:

  1. بررسی نمایش متن خام: اگر متن [my_form] روی صفحه نمایش داده می‌شود، شورتکد اصلاً ثبت نشده — به لایه اول بروید. اگر فضای خالی است، تابع رندر مقدار برنمی‌گرداند — به لایه سوم.
  2. فعال‌سازی WP_DEBUG: در wp-config.php مقادیر WP_DEBUG، WP_DEBUG_LOG و WP_DEBUG_DISPLAY را تنظیم کنید و لاگ را در wp-content/debug.log بررسی کنید.
  3. لاگ موقت در تابع رندر: در ابتدای تابع add_shortcode خود یک error_log( 'form render called' ); بگذارید و بررسی کنید آیا اصلاً فراخوانی می‌شود. اگر صدا زده نمی‌شود، شورتکد ثبت نشده یا در بافت اشتباهی است.
  4. بررسی return: اطمینان حاصل کنید تابع رندر شما مقدار return دارد، نه echo. اگر با Output Buffering کار می‌کنید، بررسی کنید ob_get_clean() در انتها با return برمی‌گردد.
  5. تست در بافت‌های مختلف: شورتکد را در نوشته، برگه، ویجت و بلوک Shortcode گوتنبرگ تست کنید. اگر در بافت خاصی کار می‌کند ولی در بقیه نه، مسئله در بافت خاص است.
  6. تست با قالب پیش‌فرض: قالب Twenty Twenty-Five را موقتاً فعال کنید. اگر فرم نمایش داده شد، مسئله در قالب است. اگر نه، در افزونه.
  7. غیرفعال کردن افزونه‌های دیگر: همه افزونه‌ها را غیرفعال کنید و یکی‌یکی فعال کنید تا مقصر پیدا شود. تمرکز ویژه روی افزونه‌های امنیتی، کش و بهینه‌ساز. الگوی کامل در چگونه افزونه مشکل‌ساز وردپرس را پیدا کنیم آمده است.
  8. پاک کردن کش: افزونه کش، کش مرورگر، کش CDN را پاک کنید. اگر با AJAX کار می‌کنید، اطمینان حاصل کنید endpoint فرم از کش مستثنا است.
  9. بررسی کنسول مرورگر: خطاهای جاوااسکریپت و پیام‌های CSP را بررسی کنید. مسئله ممکن است در بارگذاری نادرست assetهای فرم باشد.
  10. مقایسه با نسخه استاندارد: کد شورتکد خود را با یک نمونه استاندارد از ساخت شورت‌کد با کدنویسی وردپرس مقایسه کنید و تفاوت‌ها را بررسی کنید.
  11. بررسی افزونه‌های فرم‌ساز موجود: اگر از یک افزونه فرم‌ساز آماده استفاده می‌کنید، بهترین افزونه‌های فرم‌ساز وردپرس را ببینید و مطمئن شوید تنظیمات همان افزونه به‌درستی پیکربندی شده است.

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

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

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

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

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

چرا متن خام شورتکد فرم روی صفحه نمایش داده می‌شود؟

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

چرا فرم در صفحه‌ای کار می‌کند ولی در صفحه دیگر نه؟

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

چرا فرم در گوتنبرگ نمایش داده نمی‌شود ولی در ویرایشگر کلاسیک بله؟

گوتنبرگ در پیش‌نمایش ویرایشگر، محتوا را به‌طور کامل رندر نمی‌کند و فیلتر the_content را اعمال نمی‌کند. برای دیدن نتیجه واقعی، از «پیش‌نمایش در تب جدید» یا از بلوک Shortcode اختصاصی استفاده کنید. اگر شورتکد شما روی front-end درست کار می‌کند، این رفتار ویرایشگر طبیعی است و نیاز به رفع ندارد. اگر روی front-end هم کار نمی‌کند، به لایه چهارم در همین مقاله برگردید.

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

سه علت اصلی. اول، CSS قالب شما فرم را در اندازه‌های کوچک مخفی می‌کند (مثلاً display: none در مدیاکوئری). دوم، اسکریپت فرم شما روی موبایل به‌دلیل خطای JS یا بارگذاری نادرست asset اجرا نمی‌شود. سوم، افزونه کش نسخه موبایل و دسکتاپ را متفاوت سرو می‌کند. راه تشخیص: در مرورگر دسکتاپ، با Developer Tools به حالت موبایل بروید و ببینید آیا فرم در HTML وجود دارد یا نه. اگر وجود دارد ولی دیده نمی‌شود، مسئله CSS است. اگر وجود ندارد، مسئله سرور است.

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

بله و در پروژه‌های واقعی چندین بار دیده‌ام. افزونه‌های امنیتی مثل Wordfence در حالت سختگیرانه ممکن است فرم شما را به‌عنوان فرم مشکوک بلاک کنند، به‌خصوص اگر فرم شامل فیلدهای حساس یا درخواست‌های AJAX باشد. راه‌حل: افزونه امنیتی را موقتاً غیرفعال کنید و تست کنید. اگر مشکل حل شد، در تنظیمات همان افزونه، فرم یا مسیر افزونه خود را استثنا کنید.

چرا فرم من بعد از آپدیت وردپرس از کار افتاد؟

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

آیا می‌توانم فرم افزونه را در ویجت سایدبار نمایش دهم؟

بله، ولی با شرط. ویجت‌های متن در برخی قالب‌ها شورتکدها را اجرا می‌کنند و در برخی نه. اگر فرم شما در ویجت نمایش داده نمی‌شود، این فیلتر را اضافه کنید:

add_filter( 'widget_text', 'do_shortcode', 11 );
add_filter( 'widget_custom_html_content', 'do_shortcode', 11 );

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

چطور مطمئن شوم که فرم روی همه دستگاه‌ها نمایش داده می‌شود؟

سه تست ساده: اول، در حالت موبایل با DevTools. دوم، در پنجره ناشناس برای حذف اثر کش. سوم، با حساب کاربری مختلف (مهمان، مشترک، مدیر). اگر فرم در همه این حالت‌ها نمایش داده شد، مطمئن هستید که مسئله محیطی نداشته و رندر سمت سرور شما بی‌نقص است.

معماری پایدار برای نمایش مطمئن فرم

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

  1. ثبت شورتکد در یک ثابت: نام شورتکد را در یک ثابت تعریف کنید و همان ثابت را در همه جا استفاده کنید. این کار جلوی اشتباه تایپی را می‌گیرد.
  2. الگوی Output Buffering با return: همیشه از ob_start و ob_get_clean استفاده کنید و در انتها با return مقدار بافر را برگردانید. هرگز به‌جای return از echo استفاده نکنید.
  3. بررسی بافت با توابع تشخیصی: پیش از enqueue assetهای فرم، با has_shortcode و has_block بافت را تشخیص دهید و فقط در صفحه‌های مرتبط assetها را لود کنید.
  4. سازگاری با گوتنبرگ: اگر افزونه شما برای مدت طولانی پشتیبانی می‌شود، بلوک سفارشی فرم خود را با register_block_type ارائه دهید. مسیر کامل در بلوک‌های سفارشی گوتنبرگ را از صفر بسازید آمده است.
  5. escape خروجی: همه خروجی‌های HTML را با esc_html، esc_attr و esc_url escape کنید. امنیت خروجی از اصول پایه است.
  6. nonce و امنیت فرم: برای هر فرم، nonce و CSRF token اضافه کنید. راهنمای دقیق در پاک‌سازی داده‌ها در کدنویسی وردپرس آمده است.
  7. سازگاری با کش: در مستندات افزونه، توضیح دهید که اگر از AJAX استفاده می‌کند، endpoint باید از کش استثنا شود. اگر با افزونه‌های کش کار می‌کنید، رفتارشان را در بهترین افزونه‌های کش وردپرس مرور کنید.
  8. تست روی قالب‌های مختلف: فرم خود را روی حداقل دو قالب متفاوت (پیش‌فرض و یک قالب تجاری) تست کنید تا از سازگاری مطمئن شوید.
  9. رعایت استانداردهای کدنویسی: کد خوانا، امن، بدون هاردکد. مرور اصول در استانداردهای کدنویسی وردپرس چیست.
  10. تست روی محیط استجینگ: هر تغییر در ساختار فرم را روی محیط استجینگ با همان پیکربندی سرور تست کنید. برای مرور ساخت محیط استجینگ، تست و دیباگ پروژه‌های توسعه وردپرس را ببینید.

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

سخن پایانی

خطای عدم نمایش فرم افزونه، در نگاه اول ممکن است یک مسئله پیش‌پاافتاده به‌نظر برسد، ولی در عمل یکی از پرتکرارترین انواع خطا در توسعه افزونه‌هایی است که به تعامل کاربر وابسته‌اند — و در پروژه‌های فروشگاهی، می‌تواند اثر مستقیم روی نرخ تبدیل داشته باشد. این خطا همیشه در یکی از پنج لایه‌ای که در این مقاله بررسی کردیم ریشه دارد: ثبت نادرست شورتکد، بارگذاری شرطی اشتباه، خروجی buffered که return نشده، ناسازگاری با گوتنبرگ و صفحه‌سازها، و تعارض با افزونه‌های امنیتی و کش. ابزار اصلی عیب‌یابی در این بافت، ترکیب سه چیز است: WP_DEBUG برای دیدن خطاهای PHP، error_log در تابع رندر برای تشخیص اجرای واقعی، و View Source برای تفکیک مشکل سمت سرور از مشکل سمت مرورگر. مسیر عیب‌یابی که در چک‌لیست ارائه کردم، همان ترتیبی است که در پروژه‌های واقعی مرا سریع به علت رسانده؛ نکته کلیدی این است که از گام‌های ارزان شروع کنید و به گام‌های گران برسید. در بلندمدت، انضباط در ثبت شورتکد، الگوی درست Output Buffering، بارگذاری شرطی دقیق، و escape خروجی، مهم‌تر از هر راه‌حل لحظه‌ای است — چون این انضباط است که اجازه نمی‌دهد این نوع خطا دوباره ظاهر شود.

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