تابع add_meta_box ابزار اصلی وردپرس برای افزودن باکس سفارشی به پنل ویرایش نوشته، برگه یا پست تایپ سفارشی است. این تابع امکان تعریف فیلدهای اضافی، تنظیمات ویژه و اطلاعات متادیتای سفارشی را فراهم می‌کند. طراحی درست این تابع با انتخاب screen مناسب، context درست، nonce امنیتی و escape دقیق، پایه پیاده‌سازی حرفه‌ای پنل مدیریت محسوب می‌شود. اشتباهات رایجی مانند نبود nonce، نبود escape، نبود ذخیره‌سازی و نبود تست می‌تواند به ناپدید شدن داده‌ها یا حفره‌های امنیتی منجر شود. تسلط بر این تابع برای افزونه‌نویسی حرفه‌ای ضروری است و در پنل مدیریت کاربرد جدی دارد.

چرا متاباکس سفارشی یک نیاز جدی است؟

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

تابع add_meta_box چیست؟

تابع add_meta_box() یک تابع هسته وردپرس است که در فایل wp-admin/includes/template.php تعریف شده است. این تابع یک باکس جدید به پنل ویرایش اضافه می‌کند. این تابع باید در هوک add_meta_boxes فراخوانی شود. اگر در هوک دیگری فراخوانی شود، ممکن است باکس نمایش داده نشود. نکته مهم این است که این تابع تنها باکس را نمایش می‌دهد و داده را ذخیره نمی‌کند. برای ذخیره‌سازی، باید از هوک save_post استفاده کنید که در صفحه save_post به تفصیل بررسی شده است.

امضای تابع و پارامترها

امضای این تابع به‌شکل زیر است:
function add_meta_box( $id, $title, $callback, $screen = null, $context = 'advanced', $priority = 'default', $callback_args = null ) {
    // ...
}
پارامتر اول (id) شناسه یکتای باکس است. در HTML به‌عنوان id و class استفاده می‌شود. پارامتر دوم (title) عنوان نمایشی باکس است. پارامتر سوم (callback) تابعی است که محتوای باکس را تولید می‌کند. پارامتر چهارم (screen) صفحه‌ای است که باکس در آن نمایش داده می‌شود. پارامتر پنجم (context) موقعیت نمایش باکس است: normal، side یا advanced. پارامتر ششم (priority) اولویت نمایش در موقعیت است: high، core، default یا low. پارامتر هفتم (callback_args) آرایه‌ای از آرگومان‌ها است که به تابع callback پاس داده می‌شود.

هوک add_meta_boxes و زمان فراخوانی

تابع add_meta_box باید در هوک add_meta_boxes فراخوانی شود:
add_action( 'add_meta_boxes', 'myplugin_register_meta_boxes' );
function myplugin_register_meta_boxes() {
    add_meta_box(
        'myplugin_product_details',
        'جزئیات محصول',
        'myplugin_render_product_details_box',
        'product',
        'normal',
        'high'
    );
}
نکته مهم: در هوک add_meta_boxes، پارامتر پست تایپ در دسترس است. می‌توانید بر پایه آن تصمیم بگیرید که باکس ثبت شود یا نه.

پارامتر screen و انتخاب پست تایپ

پارامتر screen تعیین می‌کند که باکس در کدام صفحه نمایش داده شود. مقادیر رایج: - نامک پست تایپ: post، page، product - نام صفحه خاص: link، comment - آرایه از صفحات: array( 'post', 'page' ) - شیء WP_Screen نمونه:
add_meta_box(
    'myplugin_seo_box',
    'تنظیمات سئو',
    'myplugin_render_seo_box',
    array( 'post', 'page' ),
    'normal'
);

پارامتر context و موقعیت نمایش

پارامتر context موقعیت نمایش باکس را تعیین می‌کند. سه مقدار اصلی وجود دارد: - normal: ستون اصلی پنل ویرایش - advanced: مشابه normal اما در بخش پیشرفته - side: ستون کناری پنل ویرایش پارامتر priority ترتیب نمایش در همان context را تنظیم می‌کند: - high: بالاترین ترتیب - core: پس از باکس‌های اصلی - default: پیش‌فرض - low: پایین‌ترین ترتیب

callback و ساخت فرم

تابع callback محتوای باکس را تولید می‌کند. الگوی استاندارد:
function myplugin_render_product_details_box( $post ) {
    wp_nonce_field( 'myplugin_product_details', 'myplugin_product_details_nonce' );

    $price = get_post_meta( $post->ID, '_myplugin_price', true );
    $sku   = get_post_meta( $post->ID, '_myplugin_sku', true );
    ?>
    <div class="myplugin-fields">
        <p>
            <label for="myplugin_price">قیمت:</label>
            <input type="number" id="myplugin_price" name="myplugin_price"
                   value="<?php echo esc_attr( $price ); ?>" step="0.01">
        </p>
        <p>
            <label for="myplugin_sku">شناسه کالا:</label>
            <input type="text" id="myplugin_sku" name="myplugin_sku"
                   value="<?php echo esc_attr( $sku ); ?>">
        </p>
    </div>
    <?php
}
نکته مهم: استفاده از wp_nonce_field برای امنیت و esc_attr برای escape مقادیر. راهنمای escape در صفحه esc_html آمده است.

ذخیره متادیتا با save_post

ذخیره متادیتا در هوک save_post انجام می‌شود. الگوی صحیح:
add_action( 'save_post', 'myplugin_save_product_details', 10, 2 );
function myplugin_save_product_details( $post_id, $post ) {
    if ( ! isset( $_POST['myplugin_product_details_nonce'] ) ) {
        return;
    }

    $nonce = sanitize_text_field( wp_unslash( $_POST['myplugin_product_details_nonce'] ) );

    if ( ! wp_verify_nonce( $nonce, 'myplugin_product_details' ) ) {
        return;
    }

    if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
        return;
    }

    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }

    if ( ! current_user_can( 'edit_post', $post_id ) ) {
        return;
    }

    if ( isset( $_POST['myplugin_price'] ) ) {
        $price = (float) $_POST['myplugin_price'];
        update_post_meta( $post_id, '_myplugin_price', $price );
    }

    if ( isset( $_POST['myplugin_sku'] ) ) {
        $sku = sanitize_text_field( wp_unslash( $_POST['myplugin_sku'] ) );
        update_post_meta( $post_id, '_myplugin_sku', $sku );
    }
}
نکته مهم: پیشوند زیرخط (_) در نام متادیتا باعث می‌شود که این فیلد در فرم سفارشی‌سازی نمایش داده نشود. راهنمای توابع متادیتا در صفحه update_post_meta و صفحه get_post_meta آمده است.

کاربردهای عملی در افزونه

متاباکس برای تنظیمات پیشرفته نوشته:
add_action( 'add_meta_boxes', 'myplugin_add_advanced_settings_box' );
function myplugin_add_advanced_settings_box() {
    add_meta_box(
        'myplugin_advanced',
        'تنظیمات پیشرفته',
        'myplugin_render_advanced_box',
        'post',
        'side',
        'default'
    );
}

function myplugin_render_advanced_box( $post ) {
    wp_nonce_field( 'myplugin_advanced', 'myplugin_advanced_nonce' );

    $featured = get_post_meta( $post->ID, '_myplugin_featured', true );
    $priority = get_post_meta( $post->ID, '_myplugin_priority', true );
    ?>
    <p>
        <label>
            <input type="checkbox" name="myplugin_featured" value="1"
                   <?php checked( $featured, '1' ); ?>>
            نمایش در بخش ویژه
        </label>
    </p>
    <p>
        <label for="myplugin_priority">اولویت:</label>
        <select id="myplugin_priority" name="myplugin_priority">
            <option value="low" <?php selected( $priority, 'low' ); ?>>پایین</option>
            <option value="normal" <?php selected( $priority, 'normal' ); ?>>عادی</option>
            <option value="high" <?php selected( $priority, 'high' ); ?>>بالا</option>
        </select>
    </p>
    <?php
}
راهنمای توابع استفاده‌شده در این بخش: wp_verify_nonce، current_user_can، update_post_meta و esc_html.

نکات امنیتی و اشتباهات رایج

اشتباه اول، نبود nonce است. هر فرم ذخیره‌سازی باید nonce داشته باشد. راهنمای این تابع در صفحه wp_verify_nonce آمده است. اشتباه دوم، نبود escape در خروجی فرم است. هر مقدار که در value یا content چاپ می‌شود، باید با esc_attr یا esc_html عبور کند. اشتباه سوم، نبود بررسی DOING_AUTOSAVE است. در Autosave، ممکن است متادیتا ناخواسته به‌روزرسانی شود. اشتباه چهارم، نبود بررسی wp_is_post_revision است. برای جلوگیری از ذخیره در نسخه‌های قدیمی. اشتباه پنجم، نبود بررسی current_user_can است. اگر کاربر مجاز نباشد، نباید متادیتا ذخیره شود. اشتباه ششم، نبود بررسی نوع فیلد است. اگر فیلد عددی باشد، باید با (int) یا (float) تبدیل شود. اشتباه هفتم، استفاده از نام باکس تکراری است. شناسه باکس باید یکتا باشد. اشتباه هشتم، نبود تست است. باید در سناریوهای ذخیره موفق، ذخیره ناموفق، Autosave و ویرایش سریع تست کنید.

تحلیل فنی پیشرفته

در نگاه مهندسی، تابع add_meta_box() یک نقطه معماری در لایه Admin UI است که بر چند لایه سیستم اثر می‌گذارد. لایه اول لایه Screen Context است. پارامتر screen امکان نمایش باکس در چند پست تایپ یا صفحه را فراهم می‌کند. لایه دوم لایه Hook-based Registration است. هوک add_meta_boxes امکان ثبت داینامیک باکس‌ها را فراهم می‌کند. لایه سوم لایه Form Security است. ترکیب nonce، capability و sanitize، امنیت فرم را تضمین می‌کند. لایه چهارم لایه Serialization است. متادیتا در جدول wp_postmeta ذخیره می‌شود و برای داده‌های پیچیده، سریالایز می‌شود. لایه پنجم لایه REST Integration است. با show_in_rest، می‌توان متادیتا را در REST API نیز قابل دسترسی کرد. لایه ششم لایه Performance است. تعداد زیاد متاباکس‌ها می‌تواند زمان بارگذاری پنل ویرایش را افزایش دهد. لایه هفتم لایه Multisite است. در شبکه‌های Multisite، متاباکس‌ها در هر سایت مستقل کار می‌کنند. لایه هشتم لایه Testing است. تست‌های End-to-End باید همه سناریوها را پوشش دهند. مفاهیم پایه‌ای Metadata در Metadata در ویکی‌پدیا توضیح داده شده است. برای مطالعه بیشتر روی توابع مرتبط، می‌توانید به راهنمای save_post، راهنمای update_post_meta، راهنمای get_post_meta، راهنمای delete_post_meta، راهنمای register_post_type، راهنمای register_taxonomy و راهنمای current_user_can مراجعه کنید.

پرسش‌های پرتکرار

در کدام هوک باید add_meta_box فراخوانی شود؟ در هوک add_meta_boxes. چطور می‌توان باکس را فقط در چند پست تایپ نمایش داد؟ با پاس دادن آرایه به پارامتر screen. آیا می‌توان چند متاباکس در یک پست داشت؟ بله، هر کدام باید شناسه یکتا داشته باشند. آیا متاباکس در ویرایشگر بلوک کار می‌کند؟ بله، اما برای تجربه مدرن‌تر، استفاده از Plugin Sidebar یا بلاک سفارشی توصیه می‌شود. چطور داده متاباکس را در REST API قابل دسترسی کنیم؟ با register_meta و show_in_rest => true.

ادامه مسیر

تابع add_meta_box() ابزار اصلی وردپرس برای افزودن فیلدهای سفارشی به پنل ویرایش است. استفاده درست از آن یعنی انتخاب screen و context مناسب، تعریف nonce، escape مقادیر، بررسی capability و ذخیره‌سازی امن در هوک save_post. اشتباه‌های کوچک در این تابع اغلب به ناپدید شدن داده‌ها یا حفره‌های امنیتی منجر می‌شوند. اگر این تابع را در پروژه‌ای واقعی به کار برده‌اید و رفتار غیرمنتظره‌ای دیده‌اید — به‌خصوص در ویرایشگر بلوک یا در Multisite — تجربه‌تان می‌تواند راهگشای دیگران باشد. کدام بخش بیشترین زمان را از شما گرفت؟ دیدگاه خود را بنویسید.