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

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

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

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

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

اولین شورتکد سفارشی که ساختم، یک شورتکد ساده برای نمایش آخرین نوشته‌ها بود. در ابتدا به‌نظر می‌رسید کار تمام است، اما بعد از چند هفته، متوجه شدم در بعضی صفحات، محتوای بعد از شورتکد به‌هم می‌ریزد. علت، فراموش کردن wp_reset_postdata() بود. همین تجربه‌ی کوچک، نشان داد که ساخت شورتکد سفارشی، حتی در ساده‌ترین شکل، نیازمند توجه به جزئیات است. در ادامه، این جزئیات را لایه‌به‌لایه باز می‌کنیم.

ساختار پایه‌ی یک شورتکد سفارشی

هر شورتکد سفارشی در وردپرس، از سه بخش اصلی تشکیل می‌شود: یک تابع کالبک (Callback Function) که خروجی HTML را تولید می‌کند، یک فراخوانی add_shortcode() که این تابع را به نام شورتکد متصل می‌کند، و یک استفاده‌ی مشخص در محتوا که با کروشه‌های مربع نوشته می‌شود. این ساختار، ساده به‌نظر می‌رسد اما پایه‌ی همه‌ی شورتکدهای پیچیده‌تر است.

function my_simple_shortcode($atts, $content = null) {
    $atts = shortcode_atts([
        'text' => 'سلام',
        'class' => 'greeting',
    ], $atts, 'my_simple');

    return '<div class="' . esc_attr($atts['class']) . '">'
        . esc_html($atts['text'])
        . '</div>';
}
add_shortcode('my_simple', 'my_simple_shortcode');

در این کد، تابع my_simple_shortcode دو پارامتر می‌گیرد: $atts که ویژگی‌های شورتکد را در خود دارد و $content که محتوای بین تگ باز و بسته را شامل می‌شود. تابع shortcode_atts مقادیر پیش‌فرض را با مقادیر کاربر ادغام می‌کند و سپس خروجی HTML تولید می‌شود. فراخوانی add_shortcode این تابع را به نام my_simple متصل می‌کند.

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

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

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

پارامترها و مقادیر پیش‌فرض در shortcode_atts

پارامترها (Attributes) بخش جدایی‌ناپذیر هر شورتکد حرفه‌ای هستند. آن‌ها به کاربر اجازه می‌دهند بدون تغییر کد، رفتار شورتکد را تنظیم کند. تابع shortcode_atts() ابزار اصلی وردپرس برای مدیریت پارامترهاست؛ این تابع، مقادیر پیش‌فرض را با مقادیر ارائه‌شده توسط کاربر ادغام می‌کند و نتیجه را به‌عنوان آرایه‌ای قابل استفاده برمی‌گرداند.

$atts = shortcode_atts([
    'title' => '',
    'count' => 5,
    'order' => 'DESC',
    'show_date' => false,
], $atts, 'my_recent_posts');

پارامتر سوم shortcode_atts، نام شورتکد است. این پارامتر، به وردپرس می‌گوید که این ویژگی‌ها به کدام شورتکد تعلق دارند و امکان استفاده از فیلتر shortcode_atts_{$shortcode} را فراهم می‌کند. توسعه‌دهندگان دیگر می‌توانند با این فیلتر، مقادیر پیش‌فرض شما را تغییر دهند، بدون اینکه به کد شما دست بزنند.

اعتبارسنجی پارامترها بخش مهمی از ساخت شورتکد حرفه‌ای است. هر مقدار ورودی، قبل از استفاده باید پاک‌سازی و اعتبارسنجی شود. برای اعداد از absint() یا intval()، برای متن از sanitize_text_field()، برای کلاس CSS از sanitize_html_class() و برای URL از esc_url() استفاده کنید.

$atts['count'] = absint($atts['count']);
$atts['title'] = sanitize_text_field($atts['title']);
$atts['show_date'] = filter_var($atts['show_date'], FILTER_VALIDATE_BOOLEAN);
$atts['order'] = in_array(strtoupper($atts['order']), ['ASC', 'DESC'], true)
    ? strtoupper($atts['order'])
    : 'DESC';

نکته‌ی ظریف در اعتبارسنجی این است که برای پارامترهای شمارشی (Enum) مثل order، همیشه مقدار را در برابر لیست مقادیر مجاز بررسی کنید. اگر مقدار نامعتبر بود، به مقدار پیش‌فرض برگردید. این الگو، از بروز رفتار غیرمنتظره جلوگیری می‌کند و امنیت شورتکد را افزایش می‌دهد.

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

مدیریت محتوای درونی شورتکد

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

function my_box_shortcode($atts, $content = null) {
    $atts = shortcode_atts([
        'title' => '',
        'class' => 'info-box',
    ], $atts, 'my_box');

    $output = '<div class="' . esc_attr($atts['class']) . '">';

    if (!empty($atts['title'])) {
        $output .= '<h3>' . esc_html($atts['title']) . '</h3>';
    }

    $output .= '<div class="content">'
        . do_shortcode($content)
        . '</div>';

    $output .= '</div>';

    return $output;
}
add_shortcode('my_box', 'my_box_shortcode');

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

در مدیریت محتوای درونی، سه حالت را باید در نظر بگیرید. حالت اول، محتوای خالی است. در این حالت، باید یک مقدار پیش‌فرض یا پیام مناسب نمایش دهید. حالت دوم، محتوا شامل شورتکدهای دیگر است. در این حالت، باید do_shortcode() را فراخوانی کنید. حالت سوم، محتوا شامل HTML است. در این حالت، باید HTML را با wp_kses_post() پاک‌سازی کنید تا از حملات XSS جلوگیری شود.

if (empty($content)) {
    $content = '<p>' . esc_html__('محتوایی وارد نشده است.', 'textdomain') . '</p>';
} else {
    $content = wp_kses_post($content);
    $content = do_shortcode($content);
}

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

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

شورتکدهای تودرتو و پردازش بازگشتی

شورتکدهای تودرتو (Nested Shortcodes) زمانی رخ می‌دهند که یک شورتکد درون شورتکد دیگری قرار می‌گیرد. این وضعیت، در پروژه‌های واقعی بسیار رایج است، اما پردازش درست آن نیازمند دقت بیشتر است.

[my_wrapper class="container"]
    [my_box title="عنوان"]
        محتوای درونی
    [/my_box]
[/my_wrapper]

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

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

یک راه‌حل جایگزین برای شورتکدهای تودرتو، استفاده از توابع کمکی (Helper Functions) است. در این رویکرد، به‌جای فراخوانی شورتکد درون شورتکد، یک تابع کمکی تعریف می‌کنید که خروجی HTML را برمی‌گرداند. سپس در شورتکد بیرونی، این تابع کمکی را فراخوانی می‌کنید. این رویکرد، از پردازش بازگشتی جلوگیری می‌کند و کارایی را افزایش می‌دهد.

function my_box_render($args = []) {
    $defaults = [
        'title' => '',
        'content' => '',
        'class' => 'info-box',
    ];
    $args = wp_parse_args($args, $defaults);

    $output = '<div class="' . esc_attr($args['class']) . '">';
    if (!empty($args['title'])) {
        $output .= '<h3>' . esc_html($args['title']) . '</h3>';
    }
    $output .= '<div class="content">' . wp_kses_post($args['content']) . '</div>';
    $output .= '</div>';

    return $output;
}

function my_wrapper_shortcode($atts, $content = null) {
    return '<div class="container">'
        . my_box_render(['content' => $content])
        . '</div>';
}

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

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

کار با WP_Query در شورتکد

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

function my_recent_posts_shortcode($atts) {
    $atts = shortcode_atts([
        'count' => 5,
        'category' => '',
        'orderby' => 'date',
        'order' => 'DESC',
    ], $atts, 'recent_posts');

    $args = [
        'post_type' => 'post',
        'posts_per_page' => absint($atts['count']),
        'orderby' => sanitize_key($atts['orderby']),
        'order' => in_array(strtoupper($atts['order']), ['ASC', 'DESC'], true)
            ? strtoupper($atts['order'])
            : 'DESC',
        'no_found_rows' => true,
        'update_post_meta_cache' => false,
        'update_post_term_cache' => false,
    ];

    if (!empty($atts['category'])) {
        $args['category_name'] = sanitize_title($atts['category']);
    }

    $query = new WP_Query($args);

    if (!$query->have_posts()) {
        return '<p>' . esc_html__('نوشته‌ای یافت نشد.', 'textdomain') . '</p>';
    }

    $output = '<ul class="recent-posts">';
    while ($query->have_posts()) {
        $query->the_post();
        $output .= '<li><a href="' . esc_url(get_permalink()) . '">'
            . esc_html(get_the_title()) . '</a></li>';
    }
    $output .= '</ul>';

    wp_reset_postdata();

    return $output;
}
add_shortcode('recent_posts', 'my_recent_posts_shortcode');

نکته‌ی حیاتی در این کد، فراخوانی wp_reset_postdata() بعد از حلقه است. بدون این فراخوانی، متغیر سراسری $post تغییر می‌کند و ممکن است محتوای بعدی صفحه به‌درستی نمایش داده نشود. این اشتباه، یکی از رایج‌ترین باگ‌های شورتکدهای سفارشی است و در پروژه‌های واقعی، ساعت‌ها دیباگ می‌طلبد.

نکته‌ی مهم دیگر، استفاده از پارامترهای بهینه‌سازی در WP_Query است. پارامتر no_found_rows را روی true تنظیم کنید اگر به شمارش کل نتایج نیاز ندارید. پارامترهای update_post_meta_cache و update_post_term_cache را روی false تنظیم کنید اگر به متادیتا یا ترم‌های نوشته‌ها نیاز ندارید. این تنظیمات، کوئری‌های اضافی را حذف می‌کنند و کارایی را بهبود می‌دهند.

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

امنیت در ساخت شورتکد سفارشی

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

حوزه‌ی اول، پاک‌سازی ورودی‌ها. همیشه مقادیر ویژگی‌ها را قبل از استفاده، پاک‌سازی کنید. برای متن از sanitize_text_field()، برای اعداد از absint()، برای URL از esc_url() و برای کلاس‌های CSS از sanitize_html_class() استفاده کنید.

$atts['title'] = sanitize_text_field($atts['title']);
$atts['count'] = absint($atts['count']);
$atts['url'] = esc_url($atts['url']);
$atts['class'] = sanitize_html_class($atts['class']);

حوزه‌ی دوم، فرار دادن خروجی‌ها. هر مقداری که در خروجی HTML قرار می‌گیرد، باید با توابع مناسب فرار داده شود. برای متن از esc_html()، برای ویژگی‌های HTML از esc_attr() و برای URL از esc_url() استفاده کنید.

return '<div class="' . esc_attr($atts['class']) . '">'
    . '<h3>' . esc_html($atts['title']) . '</h3>'
    . '<a href="' . esc_url($atts['url']) . '">'
    . esc_html__('بیشتر', 'textdomain')
    . '</a></div>';

حوزه‌ی سوم، محدود کردن HTML در محتوای درونی. اگر شورتکد شما محتوای HTML را از کاربر دریافت می‌کند، از wp_kses_post() یا wp_kses() برای محدود کردن تگ‌های مجاز استفاده کنید. هرگز محتوای خام کاربر را مستقیماً در خروجی قرار ندهید.

$allowed_html = [
    'a' => ['href' => [], 'title' => [], 'target' => []],
    'strong' => [],
    'em' => [],
    'br' => [],
    'p' => ['class' => []],
];
$safe_content = wp_kses($content, $allowed_html);

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

مفهوم Cross-Site Scripting در ویکی‌پدیا توضیح داده شده است و درک آن برای ساخت شورتکد امن ضروری است. برای مطالعه‌ی عمیق‌تر این نوع حمله، مقاله حملات XSS چیست و چگونه جلوگیری کنیم؟ را مطالعه کنید. همچنین مقاله هوک‌های وردپرس و افزایش امنیت کد نکات تکمیلی دارد.

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

کارایی و کش کردن خروجی شورتکد

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

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

function my_cached_shortcode($atts) {
    $atts = shortcode_atts([
        'count' => 5,
        'category' => '',
    ], $atts, 'cached_posts');

    $cache_key = 'my_cached_shortcode_' . md5(serialize($atts));
    $output = get_transient($cache_key);

    if (false === $output) {
        $output = generate_recent_posts_output($atts);
        set_transient($cache_key, $output, HOUR_IN_SECONDS);
    }

    return $output;
}
add_shortcode('cached_posts', 'my_cached_shortcode');

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

تکنیک دوم، بهینه‌سازی کوئری‌ها. اگر شورتکد شما از WP_Query استفاده می‌کند، از پارامترهای بهینه‌سازی مثل no_found_rows، update_post_meta_cache و update_post_term_cache استفاده کنید. این تنظیمات، کوئری‌های اضافی را حذف می‌کنند.

$args = [
    'posts_per_page' => 5,
    'no_found_rows' => true,
    'update_post_meta_cache' => false,
    'update_post_term_cache' => false,
    'ignore_sticky_posts' => true,
];

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

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

برای درک عمیق‌تر مباحث کارایی، مقاله چگونه سرعت سایت وردپرسی را افزایش دهیم؟ را مطالعه کنید. همچنین مقاله ترنزینت وردپرس چیست و چگونه کش هوشمند بدون افزونه بسازیم؟ برای درک عمیق‌تر Transient API مفید است.

شورتکد یا بلوک گوتنبرگ؟

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

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

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

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

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

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

اشتباهات رایج در ساخت شورتکد سفارشی

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

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

// نادرست
function my_shortcode() {
    echo 'خروجی';
}

// درست
function my_shortcode() {
    return 'خروجی';
}

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

اشتباه سوم، عدم فراخوانی wp_reset_postdata(). اگر شورتکد شما از WP_Query استفاده می‌کند و بعد از حلقه، wp_reset_postdata() را فراخوانی نمی‌کنید، ممکن است محتوای بعدی صفحه به‌درستی نمایش داده نشود. این اشتباه، یکی از رایج‌ترین باگ‌های شورتکدهای سفارشی است.

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

اشتباه پنجم، عدم پردازش شورتکدهای تودرتو. اگر محتوای درونی شورتکد شما شامل شورتکدهای دیگر است، باید do_shortcode() را روی آن فراخوانی کنید. در غیر این صورت، شورتکدهای درونی به‌صورت متن خام نمایش داده می‌شوند.

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

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

اشتباه هشتم، ثبت شورتکد در زمان اشتباه. شورتکد باید بعد از بارگذاری وردپرس ثبت شود. اگر آن را در زمان اشتباه ثبت کنید، ممکن است شناسایی نشود. بهترین زمان، فراخوانی add_shortcode() در فایل اصلی افزونه یا در هوک init است.

اشتباه نهم، عدم استفاده از shortcode_atts. اگر مقادیر پیش‌فرض را به‌صورت دستی مدیریت کنید، کد شما پیچیده‌تر و مستعد خطا می‌شود. همیشه از shortcode_atts() استفاده کنید.

اشتباه دهم، عدم بررسی خالی بودن محتوا. اگر محتوای درونی شورتکد خالی باشد، ممکن است خروجی ناقص یا نامناسب تولید شود. همیشه حالت خالی را مدیریت کنید.

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

دیباگ و عیب‌یابی شورتکد

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

ابزار اول، تابع shortcode_exists(). این تابع بررسی می‌کند که آیا یک شورتکد خاص ثبت شده است یا نه. اگر shortcode_exists('my_shortcode') مقدار false برگرداند، یعنی شورتکد ثبت نشده است.

if (shortcode_exists('my_shortcode')) {
    // شورتکد ثبت شده است
} else {
    // شورتکد ثبت نشده است
}

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

$output = do_shortcode('[my_shortcode]');
var_dump($output);

ابزار سوم، بررسی فیلتر the_content. اگر شورتکد در محتوا پردازش نمی‌شود، ممکن است فیلتر the_content به‌درستی اعمال نشده باشد. بررسی کنید که آیا قالبتان از the_content() استفاده می‌کند یا از get_the_content(). تابع دوم، فیلترها را اعمال نمی‌کند و شورتکدها پردازش نمی‌شوند.

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

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

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

نکته‌ی مهم در دیباگ شورتکدها این است که همیشه از محیط توسعه (Development) استفاده کنید، نه محیط تولید. تغییرات در کد شورتکدها، در محیط تولید می‌تواند سایت را از کار بیندازد. همچنین، قبل از هر تغییر، از سایت بکاپ بگیرید تا در صورت بروز مشکل، بتوانید به حالت قبل برگردید.

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

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

از منظر یک مهندس ارشد، ساخت شورتکد سفارشی فقط نوشتن یک تابع و اتصال آن با add_shortcode() نیست؛ طراحی یک قطعه‌ی نرم‌افزاری است که باید در برابر تغییرات، بار سنگین و تهدیدات امنیتی مقاوم باشد. سه مفهوم بنیادین را باید بازتعریف کنید.

مفهوم اول، جداسازی منطق از نمایش. به‌جای اینکه همه‌ی منطق در تابع شورتکد باشد، آن را به یک کلاس سرویس (Service Class) منتقل کنید. تابع شورتکد فقط نقش اتصال‌دهنده را بازی کند و منطق واقعی در کلاس سرویس باشد. این جداسازی، تست‌پذیری و نگهداری را به‌طور قابل‌توجهی بهبود می‌دهد.

class My_Plugin_Recent_Posts_Service {
    public function get_posts($args) {
        $query = new WP_Query($args);
        $posts = $query->posts;
        wp_reset_postdata();
        return $posts;
    }
}

class My_Plugin_Recent_Posts_Shortcode {
    protected $service;

    public function __construct(My_Plugin_Recent_Posts_Service $service) {
        $this->service = $service;
    }

    public function render($atts) {
        $atts = shortcode_atts([
            'count' => 5,
        ], $atts, 'recent_posts');

        $posts = $this->service->get_posts([
            'posts_per_page' => absint($atts['count']),
            'no_found_rows' => true,
        ]);

        return $this->render_template($posts);
    }

    protected function render_template($posts) {
        // رندر قالب
    }
}

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

$cache_key = 'my_plugin_recent_posts_data_' . md5(serialize($args));
$posts = get_transient($cache_key);

if (false === $posts) {
    $posts = $this->service->get_posts($args);
    set_transient($cache_key, $posts, HOUR_IN_SECONDS);
}

return $this->render_template($posts);

مفهوم سوم، idempotency در پردازش. اگر شورتکد شما عملیات جانبی مثل ثبت داده یا ارسال ایمیل انجام می‌دهد، باید idempotent باشد؛ یعنی اجرای مکرر آن، تأثیر اضافی نداشته باشد. این ویژگی، در سناریوهایی که شورتکد چند بار در یک صفحه فراخوانی می‌شود یا کش غیرفعال است، حیاتی است.

مفهوم چهارم، سازگاری با بسترهای مختلف. یک شورتکد حرفه‌ای باید در ویرایشگر کلاسیک، گوتنبرگ، ویجت‌ها و حتی REST API به‌درستی کار کند. برای دستیابی به این سازگاری، باید از توابع وردپرس که در همه‌ی بسترها کار می‌کنند استفاده کنید و از وابستگی به وضعیت سراسری (Global State) پرهیز کنید.

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

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

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

چرا شورتکد من در محتوا نمایش داده نمی‌شود؟ دلایل متعددی وجود دارد: ممکن است شورتکد ثبت نشده باشد، ممکن است محتوا از فیلتر the_content عبور نکرده باشد، ممکن است تابع کالبک به‌جای return از echo استفاده کند، یا ممکن است نام شورتکد اشتباه نوشته شده باشد.

چگونه یک شورتکد با پارامتر بسازم؟ از تابع shortcode_atts() برای تعریف مقادیر پیش‌فرض استفاده کنید و مقادیر کاربر را با آن‌ها ادغام کنید. سپس پارامترها را در خروجی HTML استفاده کنید.

آیا می‌توانم شورتکد را در ویجت استفاده کنم؟ به‌صورت پیش‌فرض، شورتکدها در ویجت‌ها پردازش نمی‌شوند. اما می‌توانید با فراخوانی do_shortcode() در ویجت، این قابلیت را اضافه کنید.

چگونه شورتکدهای تودرتو را پردازش کنم؟ در تابع کالبک شورتکد بیرونی، روی محتوای درونی do_shortcode() را فراخوانی کنید. این کار، شورتکدهای درونی را نیز پردازش می‌کند.

آیا شورتکدها روی سرعت سایت تأثیر دارند؟ هر شورتکد، یک فراخوانی تابع و یک پردازش عبارت باقاعده است. اگر تعداد شورتکدها زیاد باشد یا هر شورتکد کوئری سنگینی اجرا کند، می‌تواند بر سرعت تأثیر بگذارد. با کش کردن خروجی و بهینه‌سازی کوئری‌ها، می‌توان این تأثیر را کاهش داد.

چگونه شورتکد خود را امن کنم؟ همیشه مقادیر ویژگی‌ها را پاک‌سازی کنید، خروجی‌ها را فرار دهید و محتوای HTML را با wp_kses_post() محدود کنید. برای عملیات حساس، سطح دسترسی کاربر را با current_user_can() بررسی کنید.

آیا می‌توانم شورتکد را در فایل قالب استفاده کنم؟ بله، با فراخوانی do_shortcode() در فایل قالب، می‌توانید شورتکد را اجرا کنید. مثلاً <?php echo do_shortcode('[my_shortcode]'); ?>.

چگونه شورتکد خود را کش کنم؟ از Transient API استفاده کنید. خروجی شورتکد را با set_transient() ذخیره کنید و با get_transient() بازیابی کنید. کلید کش را بر اساس پارامترهای ورودی بسازید تا هر ترکیب، خروجی مخصوص خود را داشته باشد.

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

چگونه شورتکد را از محتوا حذف کنم؟ برای حذف ثبت شورتکد، از remove_shortcode() استفاده کنید. برای حذف استفاده از شورتکد در محتوا، باید کد شورتکد را از محتوا حذف کنید.

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

آیا می‌توانم شورتکد را با کلاس بنویسم؟ بله، می‌توانید شورتکد را به‌صورت یک متد در یک کلاس تعریف کنید و آن را با add_shortcode('my_shortcode', [$instance, 'method_name']) ثبت کنید. این رویکرد، در پروژه‌های بزرگ توصیه می‌شود.

چگونه شورتکد خود را تست کنم؟ از do_shortcode() برای فراخوانی دستی شورتکد استفاده کنید و خروجی را بررسی کنید. همچنین می‌توانید از PHPUnit و WP_UnitTestCase برای نوشتن تست‌های خودکار استفاده کنید.

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

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