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

شورتکد نمایش داده نمی‌شود — تفکیک حالت‌های مختلف

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

حالت دوم: متن خام نمایش داده نمی‌شود، اما محتوای خروجی هم نمی‌آید — یعنی یک فضای خالی در محل شورتکد دیده می‌شود. این حالت یعنی تابع callback اجرا شده ولی مقدار خروجی نداده یا null بازگردانده است. حالت سوم: به‌جای خروجی، یک پیام خطای PHP مثل Warning یا Fatal error می‌بینید. این حالت یعنی تابع اجرا شده اما داخل بدنه آن خطایی رخ داده است. حالت چهارم: روی پیش‌نمایش ویرایشگر همه‌چیز درست است ولی روی سایت زنده چیزی نمایش داده نمی‌شود. این حالت، شایع‌ترین حالت «شورتکد نمایش داده نمی‌شود» است و تقریباً همیشه به کش، به ویرایشگر بلوکی، یا به تفاوت‌های اجرای context برمی‌گردد.

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

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

شورتکد یک میان‌بُر است: یک برچسب درون‌متنی مثل [contact_form] یا [product id="42"] که در هنگام رندر خروجی، با یک محتوای تولیدشده توسط PHP جایگزین می‌شود. مکانیزم کار ساده است: شما تابعی می‌نویسید، آن را با add_shortcode( 'contact_form', 'my_contact_form_callback' ) به وردپرس معرفی می‌کنید، و از آن لحظه به بعد، هر جای محتوا که این الگوی متنی دیده شود، وردپرس آن را با نتیجه فراخوانی callback جایگزین می‌کند. اگر با ساخت شورت‌کد با کدنویسی وردپرس آشنا نیستید، این مقاله پیش‌نیاز خوبی است.

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

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

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

لایه اول — ثبت نادرست add_shortcode

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

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

نامی که در add_shortcode ثبت می‌کنید باید دقیقاً با نامی که در محتوا استفاده می‌کنید یکسان باشد؛ حتی یک فاصله اضافه یا یک کاراکتر متفاوت، آن را از کار می‌اندازد. مثال: اگر add_shortcode( 'my_form', ... ) نوشته‌اید ولی در محتوا [my-form] گذاشته‌اید (با خط تیره به‌جای زیرخط)، وردپرس آن را نمی‌شناسد. الگوی ساده‌ای که در پروژه‌ها به آن وفادار می‌مانم: نام شورتکد را در یک ثابت تعریف کنید و همان ثابت را در هر دو جا استفاده کنید تا امکان اشتباه تایپی از بین برود:

define( 'MY_PLUGIN_SHORTCODE', 'my_form' );

add_shortcode( MY_PLUGIN_SHORTCODE, 'my_plugin_render_form' );

function my_plugin_render_form( $atts ) {
    // ... logic
    return $html;
}

ثبت شورتکد بعد از اجرای محتوا

شورتکدها باید پیش از آنکه فیلتر the_content اجرا شود، ثبت شده باشند. وردپرس در زمان نمایش یک نوشته، ابتدا تمام افزونه‌ها را لود می‌کند، سپس هوک init را اجرا می‌کند و در انتها فیلتر 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' ) ) قرار می‌گیرد که باعث می‌شود شورتکد فقط در بافت خاصی ثبت شود. مثال دیگر: ثبت داخل کلاسی که در صفحه تنظیمات اجرا می‌شود ولی در front-end بارگذاری نمی‌شود. نشانه این حالت این است که شورتکد روی برخی برگه‌ها کار می‌کند ولی روی برخی دیگر خیر. برای مرور خطاهای مشابه در ساختار افزونه، ساختار فایل‌های یک افزونه استاندارد وردپرس را ببینید — معماری درست، جلوی این نوع باگ‌ها را می‌گیرد. همچنین اگر افزونه را خودتان توسعه داده‌اید و ساختار کلاسی را با هوک‌ها ترکیب می‌کنید، اصول اتصال‌دهی صحیح متدها به هوک‌ها در نحوه استفاده صحیح از هوک‌های وردپرس و در قالب اشتباهات رایج در اشتباهات رایج هنگام استفاده از هوک‌ها آمده است. این دو مقاله را در کنار هم بخوانید تا تصویر کاملی از چرخه اجرای وردپرس داشته باشید.

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

لایه دوم — ترتیب اجرای هوک‌ها و بارگذاری افزونه

وردپرس افزونه‌ها را بر اساس ترتیب الفبایی نام پوشه بارگذاری می‌کند. اگر افزونه‌ای با نام a-custom پوشه‌اش زودتر از افزونه شما با نام z-my-plugin بارگذاری شود، و آن افزونه اولی در هوک init با اولویت پایین، فیلتر یا هوکی ثبت کند که محتوای شورتکد شما را دستکاری می‌کند، می‌تواند دلیل نمایش نشدن باشد. دو مکانیزم دقیقا در همین نقطه وجود دارد که در پروژه‌های واقعی دیده‌ام:

اولویت‌های عددی در add_action و add_filter

هر هوک در وردپرس یک پارامتر اولویت دارد که به‌طور پیش‌فرض 10 است. عدد کمتر یعنی زودتر اجرا می‌شود. اگر یک افزونه امنیتی یا افزونه محتوا در اولویت 1 فیلتر the_content را قلاب کند و خروجی شورتکد را قبل از اجرای شما استخراج کند، ممکن است آن را به‌عنوان متن خام ذخیره کند یا حتی حذف کند. راه‌حل عملی این است که در تنظیمات افزونه، اولویت شورتکد خود را روی یک عدد مشخص مانند 11 یا 20 ثابت کنید:

add_filter( 'the_content', 'do_shortcode', 11 );
// یا برای اجرای زودتر از افزونه‌های دیگر
add_filter( 'the_content', 'my_shortcode_handler', 5 );

احترام به قواعد کدنویسی و نام‌گذاری

یکی دیگر از دلایل پنهان، تعارض نام توابع است. اگر تابع callback شما نام بسیار عمومی مثل render_form داشته باشد و افزونه دیگری هم همین نام را داشته باشد، PHP خطای Cannot redeclare function می‌دهد و به‌جای شورتکد، یک خطای کشنده روی صفحه ظاهر می‌شود. برای جلوگیری از این حالت، همیشه پیشوند اختصاصی افزونه را در نام تابع استفاده کنید. رعایت این اصول، بخشی از استانداردهای کدنویسی وردپرس است که در استانداردهای کدنویسی وردپرس چیست کامل توضیح داده شده. رعایت این استانداردها فقط یک توصیه زیبایی‌شناسانه نیست؛ مستقیماً از باگ‌های واقعی جلوگیری می‌کند.

لایه سوم — بازگشت ندادن مقدار در callback

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

// غلط
add_shortcode( 'my_button', function( $atts ) {
    echo '<a href="#" class="btn">کلیک کنید</a>';
} );

// درست
add_shortcode( 'my_button', function( $atts ) {
    return '<a href="#" class="btn">کلیک کنید</a>';
} );

روش سریع تشخیص این باگ: اگر خروجی شورتکد در بالای صفحه ظاهر می‌شود یا قبل از هر چیز دیگری، این دقیقاً همان نشانه است. همچنین، اگر شورتکد شما درون خودش از توابعی مثل var_dump یا print_r استفاده می‌کند (که در زمان دیباگ کار رایجی است) هم ممکن است همین اتفاق بیفتد؛ چون این توابع خروجی مستقیم دارند نه مقدار بازگشتی. برای بررسی عمیق‌تر رفتار خروجی در PHP، به اصول مطرح‌شده در نوشتن کد PHP امن برای وردپرس مراجعه کنید که هم به امنیت و هم به ساختار صحیح خروجی می‌پردازد.

انتخاب الگوی بازگشتی صحیح

الگوی حرفه‌ای که در افزونه‌های خودم استفاده می‌کنم، این است که همیشه محتوای تولیدشده را در یک متغیر بافر ذخیره کنم و در نهایت با return برگردانم:

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

    ob_start();
    ?>
    <div class="my-form-wrapper">
        <h3><?php echo esc_html( $atts['title'] ); ?></h3>
        <button><?php echo esc_html( $atts['button'] ); ?></button>
    </div>
    <?php
    return ob_get_clean();
}

این الگو دو مزیت دارد: اول اینکه خروجی را در بافر می‌گیرد و در انتها برمی‌گرداند، پس هرگز به‌اشتباه به بالای صفحه نمی‌رود؛ دوم اینکه با escape functions از امنیت خروجی اطمینان می‌دهد.

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

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

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

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

شورتکد درون بلوک‌های Dynamic و Query Loop

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

شورتکد درون Reusable Blocks و Block Patterns

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

شورتکد و گوتنبرگ، به‌ظاهر با هم آشتی دارند ولی در جزئیات نه. اگر شورتکد شما در ویرایشگر کلاسیک کار می‌کرد و در گوتنبرگ نه، پیش از هر چیز به بلوک‌های Dynamic و Reusable نگاه کنید — احتمالاً همان‌جا مسئله پنهان است.

لایه پنجم — تعارض با افزونه‌های دیگر و کش

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

تعارض با افزونه‌های دیگر

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

کش و نسخه‌های قدیمی محتوا

افزونه‌های کش، محتوای رندرشده را ذخیره می‌کنند و اگر بعد از ویرایش شورتکد، کش پاک نشود، بازدیدکنندگان نسخه قدیمی را می‌بینند. این حالت وقتی شبیه باگ به نظر می‌رسد که خود شما هم با همان کش وارد سایت شده‌اید و فکر می‌کنید تغییرات اعمال نشده. تفاوت را با پاک کردن کامل کش و رفرش سخت مرورگر (Ctrl + Shift + R) تشخیص دهید. اثر افزونه‌های کش و اینکه چطور باید با شورتکدها تعامل داشته باشند در بهترین افزونه‌های کش وردپرس بررسی شده است. یک نکته مهم: اگر شورتکد شما محتوای پویا دارد (مثل سبد خرید یا اطلاعات کاربر)، باید آن را از کش مستثنی کنید یا از تکنیک‌های ESI یا Fragment Cache استفاده کنید.

خطاهای بارگذاری CSS و JS افزونه

یکی از سناریوهای کمتر شناخته‌شده: شورتکد در front-end اجرا می‌شود و HTML خروجی درست تولید می‌شود، ولی استایل یا جاوااسکریپت آن بارگذاری نمی‌شود و در نتیجه ظاهر شورتکد به‌هم‌ریخته یا نامرئی است. این حالت را ممکن است اشتباهاً «شورتکد نمایش داده نمی‌شود» تفسیر کنید. برای تشخیص، با ابزار Network در مرورگر بررسی کنید آیا فایل‌های CSS و JS افزونه بارگذاری می‌شوند. اگر بارگذاری نمی‌شوند، باید مطمئن شوید که wp_enqueue_style و wp_enqueue_script در زمان درست اجرا می‌شوند. خطاهای بارگذاری CSS افزونه و همینطور خطاهای بارگذاری JS افزونه به‌طور جداگانه در مقالات دیگر توضیح داده شده‌اند.

شورتکد در بافت‌های مختلف — excerpt، ویجت، منو

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

شورتکد در خلاصه نوشته (Excerpt)

خروجی فیلد excerpt به‌طور پیش‌فرض شورتکدها را اجرا نمی‌کند، چون فیلتر the_excerpt فقط متن را کوتاه می‌کند و فرآیند do_shortcode روی آن اجرا نمی‌شود. اگر می‌خواهید شورتکد در excerpt اجرا شود، این قطعه را در فایل افزونه یا functions.php قرار دهید:

add_filter( 'get_the_excerpt', 'do_shortcode', 11 );

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

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

از وردپرس ۴.۹ به بعد، ویجت‌های متن به‌طور پیش‌فرض از شورتکدها پشتیبانی می‌کنند ولی این وابسته به تنظیمات قالب است. اگر ویجت شما شورتکد را نمایش نمی‌دهد، می‌توانید این فیلتر را اضافه کنید:

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

شورتکد در آیتم‌های منو

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

add_filter( 'wp_nav_menu_items', function( $items, $args ) {
    if ( 'primary' !== $args->theme_location ) {
        return $items;
    }
    $cart_count = do_shortcode( '[cart_count]' );
    return $items . '<li class="menu-cart">' . $cart_count . '</li>';
}, 10, 2 );

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

مشکلات رایج در ویژگی‌ها و پارامترهای شورتکد

گاهی شورتکد اجرا می‌شود ولی با پارامترهای پیش‌فرض، نه با پارامترهایی که شما نوشته‌اید. این حالت معمولاً اشکال در تابع shortcode_atts یا در نحوه نوشتن ویژگی‌ها در محتوا دارد. سه اشتباه رایج در این زمینه وجود دارد:

  • عدم استفاده از shortcode_atts: وقتی ویژگی‌ها را مستقیم از آرایه $atts می‌خوانید، در نبود یک کلید، PHP خطای undefined index می‌دهد. همیشه از shortcode_atts استفاده کنید تا مقادیر پیش‌فرض اعمال شوند.
  • گیومه‌های هوشمند در ویرایشگر: اگر محتوا در ویرایشگر کلاسیک نوشته شده باشد و ویرایشگر به‌طور خودکار گیومه‌های راست‌خط را به گیومه‌های هوشمند («» یا “”) تبدیل کرده باشد، شورتکد پارامترها را نمی‌خواند. از بلوک Shortcode در گوتنبرگ یا از ویرایشگر متن خام استفاده کنید.
  • فاصله‌گذاری اشتباه: شورتکد [my_form id=42] بدون گیومه معتبر است ولی توصیه می‌شود همیشه از [my_form id="42"] با گیومه استفاده کنید، چون در صورت داشتن فاصله در مقدار، مرز پارامترها گم می‌شود.
  • پارامترهای تودرتو: اگر پارامتر شما خودش آرایه است (مثلاً برای انتخاب چند گزینه)، باید از فرمت سریالیزه یا JSON در رشته استفاده کنید و در callback دیکد کنید. این رویکرد در بافت‌های پیچیده مانند نمایش محصولات ووکامرس رایج است.

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

شورتکد تودرتو و مشکلات محتوا

اگر شورتکد شما محتوایی درون خودش دارد — مثلاً [my_box]متن داخلی[/my_box] — باید در تابع callback پارامتر دوم را که $content نام دارد مدیریت کنید. فراموش کردن این پارامتر، یکی از شایع‌ترین اشتباهات در ساخت شورتکدهای جفتی است:

add_shortcode( 'my_box', 'my_plugin_render_box' );

function my_plugin_render_box( $atts, $content = null ) {
    $atts = shortcode_atts(
        array( 'color' => 'blue' ),
        $atts,
        'my_box'
    );

    return '<div class="box box-' . esc_attr( $atts['color'] ) . '">'
         . do_shortcode( $content )
         . '</div>';
}

نکته کلیدی: در شورتکدهای تودرتو، برای اینکه شورتکدهای داخلی هم اجرا شوند، باید صریحاً do_shortcode( $content ) را فراخوانی کنید. اگر فراموش کنید، شورتکدهای داخلی به‌صورت متن خام نمایش داده می‌شوند. این یکی از رایج‌ترین الگوهای باگ در افزونه‌های تازه‌کار است.

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

چک‌لیست دیباگ گام‌به‌گام

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

  1. بررسی ثبت شورتکد: در ابتدای فایل افزونه، یک error_log( 'shortcode registered' ); بعد از add_shortcode بگذارید. اگر در لاگ خطای PHP ندیدید، شورتکد ثبت نشده. علت را در لایه اول جستجو کنید.
  2. بررسی خروجی callback: در داخل تابع callback، ابتدا یک error_log( 'callback executed' ); قرار دهید و مطمئن شوید اجرا می‌شود. اگر اجرا می‌شود ولی خروجی ندارد، مشکل در return است.
  3. بررسی با do_shortcode در قالب: در فایل قالب، مستقیماً echo do_shortcode( '[my_shortcode]' ); بگذارید. اگر اینجا خروجی تولید می‌شود ولی در محتوا نه، مشکل در فیلتر the_content یا در کش است.
  4. فعال‌سازی WP_DEBUG: در wp-config.php، خطوط WP_DEBUG، WP_DEBUG_LOG و WP_DEBUG_DISPLAY را تنظیم کنید و فایل wp-content/debug.log را بررسی کنید.
  5. غیرفعال کردن کش و افزونه‌ها: ابتدا کش را پاک کنید، سپس افزونه‌های دیگر را یکی‌یکی غیرفعال کنید تا مقصر پیدا شود.
  6. تست در بافت‌های مختلف: شورتکد را در نوشته، برگه، ویجت و بلوک Shortcode تست کنید. اگر در بافت خاصی کار می‌کند، مشکل در یک بافت مشخص است نه در خود شورتکد.
  7. بررسی لاگ PHP سرور: اگر به error log سرور دسترسی دارید، لاگ‌های PHP را هم بررسی کنید؛ برخی خطاها به debug.log وردپرس نمی‌رسند.

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

دیباگ کردن شورتکد، مثل باز کردن یک جعبه چینی تو در تو است. اگر از بیرون شروع کنید و لایه به لایه باز کنید، در نهایت به مغز می‌رسید؛ اگر از وسط شروع کنید، همه چیز می‌شکند. ترتیب، همه چیز است.

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

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

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

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

آیا شورتکد می‌تواند به‌طور خودکار توسط افزونه امنیتی حذف شود؟

بله. بعضی افزونه‌های امنیتی مثل Wordfence در حالت آموزش (Learning Mode) یا با قوانین سختگیرانه، الگوهای شورتکد را به‌عنوان کد مشکوک علامت‌گذاری می‌کنند. اگر مطمئن هستید کد شما درست است ولی روی front-end نمایش داده نمی‌شود، افزونه امنیتی را موقتاً غیرفعال کنید و تست بگیرید. در صورت تأیید، در تنظیمات افزونه امنیتی، مسیر یا الگوی شورتکد را استثنا کنید.

چرا شورتکد در ویجت کار می‌کند ولی در محتوا نه؟

احتمالاً به این برمی‌گردد که تابع ثبت شورتکد فقط در context ویجت اجرا می‌شود — مثلاً داخل هوک widgets_init که در front-end برای محتوا اجرا نمی‌شود. تابع add_shortcode را به سطح بالای فایل افزونه منتقل کنید یا داخل هوک init بگذارید. اگر می‌خواهید در همه بافت‌ها ثبت شود، مستقل از هوک‌های admin یا widget ثبت کنید.

آیا استفاده از صفحه‌سازها روی شورتکد اثر می‌گذارد؟

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

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

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

آیا می‌توان شورتکد را در excerpt قالب‌های آماده اجرا کرد؟

بله، با افزودن فیلتر get_the_excerpt که پیش‌تر نشان دادم. توجه کنید که اگر قالب شما excerpt را با تابع سفارشی خودش تولید می‌کند (مثل mytheme_get_excerpt)، فیلتر وردپرس روی آن اثر ندارد و باید آن تابع سفارشی را مستقیماً ویرایش کنید. همیشه مسیر پردازش excerpt را در قالب خود بررسی کنید تا فیلتر شما در نقطه درست قرار گیرد.

جلوگیری از تکرار — معماری پایدار شورتکد

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

  1. نام شورتکد را در یک ثابت تعریف کنید. همان ثابت را در add_shortcode و در همه جاهای دیگر استفاده کنید تا امکان اشتباه تایپی از بین برود.
  2. همیشه از shortcode_atts استفاده کنید. حتی برای پارامترهای تک‌مقداری هم این کار مقادیر پیش‌فرض و امنیت را تضمین می‌کند.
  3. الگوی ob_start و ob_get_clean را برای خروجی پیچیده به کار ببرید. باعث می‌شود تولید HTML پیچیده خوانا باشد و از echo های پراکنده جلوگیری شود.
  4. در انتها همیشه return بگذارید. حتی اگر callback شما فقط یک متغیر ساده برمی‌گرداند، این کار رفتار قابل پیش‌بینی ایجاد می‌کند.
  5. شورتکد را از پیاده‌سازی منطق کسب‌وکار جدا نگه دارید. callback فقط باید HTML تولید کند؛ منطق در کلاس‌های سرویس جدا باشد. این جداسازی تست‌پذیری را چند برابر می‌کند.
  6. برای هر شورتکد، یک تست واحد ساده بنویسید. حتی یک تست ساده که بررسی کند shortcode_exists( 'my_form' ) درست است، جلوی بسیاری از باگ‌های ثبت‌نام را می‌گیرد.
  7. در افزونه‌های فروشگاهی، سازگاری شورتکد با صفحه‌سازها را صریحاً تست کنید. اگر شورتکد قرار است در المنتور، Divi یا Gutenberg استفاده شود، هر سه محیط را جداگانه تست کنید.
  8. یک سیستم لاگ سبک برای شورتکدهای پرمصرف بسازید. اگر شورتکدی در هر بار بارگذاری سنگین است، لاگ اجرای آن به شما نشان می‌دهد که آیا بیش از حد فراخوانی می‌شود یا خیر. این رویکرد در بافت بهینه‌سازی سرعت سایت بسیار مهم است، چون شورتکدهای سنگین می‌توانند مستقیماً روی Core Web Vitals اثر بگذارند و این اثر در بهبود Core Web Vitals در وردپرس توضیح داده شده است.

در نهایت، به‌عنوان یک رویکرد معماری، پیشنهاد می‌کنم شورتکدها را در یک کلاس ثبت‌کننده اختصاصی تعریف کنید که هم registration و هم render را مدیریت می‌کند. این الگو در افزونه‌های بزرگ به‌شدت مقیاس‌پذیر است و روزی که بخواهید شورتکد را به بلوک گوتنبرگ ارتقا دهید، مسیر مهاجرت هموارتری خواهید داشت. تجربه شخصی من این است که پروژه‌هایی که از ابتدا این نظم را رعایت می‌کنند، در بلندمدت بسیار کمتر با باگ‌های شورتکد روبرو می‌شوند.

سخن پایانی

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

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