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

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

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

چرا register_widget اهمیت دارد

سیستم ویجت وردپرس از یک Registry سراسری استفاده می‌کند که در آن تمام ویجت‌های ثبت‌شده نگهداری می‌شوند. هر ویجتی که بخواهد در پنل وردپرس ظاهر شود، باید در این Registry ثبت شود. تابع register_widget() این ثبت را انجام می‌دهد.

پس از ثبت، ویجت در چند نقطه وردپرس قابل دسترسی می‌شود:

  • صفحه «ویجت‌ها» در پیشخوان
  • بخش Customizer در Appearance → Customize → Widgets
  • صفحه «بلاک‌ها» در ویرایشگر گوتنبرگ (اگر قالب از Widget Block Area پشتیبانی کند)
  • API برنامه‌نویسی با the_widget()

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

ساختار و امضای تابع register_widget

امضای این تابع به شکل زیر است:

register_widget( string|WP_Widget $widget ): void

پارامتر ورودی می‌تواند نام کلاس ویجت (به‌صورت رشته) یا یک instance از کلاس WP_Widget باشد. در نسخه‌های جدید وردپرس، هر دو روش پشتیبانی می‌شود.

// روش اول: نام کلاس
register_widget( 'My_Text_Widget' );

// روش دوم: instance
register_widget( new My_Text_Widget() );

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

پارامترها و نحوه اتصال به کلاس

پارامتر widget

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

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

// درست
class My_Widget extends WP_Widget { /* ... */ }
register_widget( 'My_Widget' );

// اشتباه، کلاس تعریف نشده
register_widget( 'My_Widget' );
class My_Widget extends WP_Widget { /* ... */ }

نحوه اتصال به کلاس WP_Widget

کلاس شما باید WP_Widget را ارث‌بری کند و متدهای widget، form و update را پیاده‌سازی کند. برای جزئیات کامل، مطلب کلاس WP_Widget را ببینید.

نقش حیاتی hook widgets_init

تابع register_widget باید در hook widgets_init فراخوانی شود. این hook بعد از بارگذاری کل هسته وردپرس و قبل از رندر پنل ویجت‌ها اجرا می‌شود:

add_action( 'widgets_init', function () {
    register_widget( 'My_Text_Widget' );
} );

اگر این تابع را در hook دیگری مثل init یا after_setup_theme فراخوانی کنید، ویجت در پنل ظاهر نمی‌شود. مطلب تابع do_action برای درک hookها مفید است.

ثبت در Customizer

ویجت‌های کلاسیک به‌طور خودکار در Customizer نیز نمایش داده می‌شوند اگر قالب از add_theme_support( 'widgets' ) پشتیبانی کند. برای مطالعه بیشتر، مطلب تابع add_theme_support راهنماست.

نمونه‌های عملی در پروژه واقعی

ثبت ویجت پایه

add_action( 'widgets_init', function () {
    register_widget( 'My_Text_Widget' );
} );

ثبت چند ویجت با یک hook

add_action( 'widgets_init', function () {
    register_widget( 'My_Text_Widget' );
    register_widget( 'My_Recent_Posts_Widget' );
    register_widget( 'My_User_Info_Widget' );
} );

ثبت ویجت با بررسی وجود کلاس

add_action( 'widgets_init', function () {
    if ( class_exists( 'My_Text_Widget' ) ) {
        register_widget( 'My_Text_Widget' );
    }
} );

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

ثبت ویجت با کلاس Namespace

add_action( 'widgets_init', function () {
    register_widget( 'MyPlugin\\Widgets\\Text_Widget' );
} );

در پروژه‌های با namespace، این الگو برای جلوگیری از تداخل نام‌ها ضروری است. برای مطالعه بیشتر، مطلب استانداردهای PSR در PHP راهنماست.

ثبت ویجت با instance برای مقداردهی اولیه

add_action( 'widgets_init', function () {
    $widget = new My_Widget();
    $widget->set_default_option( 'value' );
    register_widget( $widget );
} );

ثبت ویجت در Customizer فقط برای کاربران خاص

add_action( 'widgets_init', function () {
    if ( current_user_can( 'manage_options' ) ) {
        register_widget( 'My_Admin_Widget' );
    }
} );

برای مطالعه کامل نقش‌ها، مطلب Capability و نقش‌های کاربری سفارشی را ببینید.

ثبت ویجت از طریق WP-CLI

wp widget list --sidebar=sidebar-1

مطلب راهنمای WP-CLI الگوهای این کار را پوشش می‌دهد.

حذف ویجت ثبت‌شده

add_action( 'widgets_init', function () {
    unregister_widget( 'My_Text_Widget' );
}, 20 );

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

اشتباهات رایج در استفاده از register_widget

نبود کلاس

شایع‌ترین اشتباه. اگر کلاس قبل از register_widget تعریف نشده باشد، خطای Fatal رخ می‌دهد. همیشه یا کلاس را در همان فایل تعریف کنید یا با class_exists بررسی کنید.

نبود متدهای form و update

اگر کلاس شما این متدها را نداشته باشد، ویجت در پنل ظاهر می‌شود اما تنظیمات کار نمی‌کند. برای مطالعه کامل متدها، مطلب کلاس WP_Widget را ببینید.

فراخوانی در hook اشتباه

اگر register_widget را در hook init یا after_setup_theme فراخوانی کنید، ویجت در پنل ظاهر نمی‌شود. همیشه از widgets_init استفاده کنید.

استفاده از نام تکراری

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

نبود escape در متد widget

در متد widget، مقادیر instance باید escape شوند. عدم escape به XSS منجر می‌شود. مطلب Output Escaping در وردپرس راهنمای کامل است.

نبود sanitize در متد update

در متد update، مقادیر ورودی کاربر باید sanitize شوند. عدم sanitize به ذخیره داده مخرب در دیتابیس منجر می‌شود. مطلب راهنمای Sanitization مرجع است.

نبود تست روی سناریوهای مرزی

تست‌هایی مثل «ثبت ویجت با کلاس ناموجود»، «ثبت دو ویجت با یک کلاس»، «حذف ویجت با unregister_widget» و «ثبت در Customizer» را حتماً بنویسید.

امنیت و عملکرد در register_widget

این تابع به‌تنهایی امنیت را تهدید نمی‌کند، اما کلاس ویجت باید استانداردهای امنیتی را رعایت کند:

  • sanitize در متد update برای ورودی‌ها
  • escape در متد widget برای خروجی‌ها
  • escape در متد form برای مقادیر نمایش‌داده‌شده
  • بررسی capability کاربر در ذخیره تنظیمات (وردپرس به‌طور خودکار انجام می‌دهد)

برای مطالعه جامع مباحث امنیتی، مطلب SQL Injection Prevention در وردپرس مرجع است.

از نظر عملکرد، register_widget فقط یک بار در hook widgets_init اجرا می‌شود و هزینه‌ای در بارگذاری روزانه ندارد. اما کلاس ویجت در هر رندر سایدبار اجرا می‌شود. توصیه می‌شود:

  1. متد widget را سبک نگه دارید
  2. نتیجه کوئری‌های پرتکرار را در cache ذخیره کنید
  3. در ویجت‌های سنگین، از Transient استفاده کنید

برای مطالعه الگوهای بهینه، مطلب تابع get_transient راهنماست.

پرسش‌های پرتکرار درباره register_widget

تفاوت register_widget با add_shortcode چیست؟

register_widget() یک ویجت را برای استفاده در سایدبار ثبت می‌کند، در حالی که add_shortcode() یک شورتکد برای استفاده در محتوا ثبت می‌کند. هرکدام کاربرد متفاوتی دارند.

چرا ویجت من در پیشخوان ظاهر نمی‌شود؟

معمولاً به سه دلیل: فراخوانی register_widget در hook اشتباه، نبود parent::__construct در سازنده کلاس، یا نبود کلاس در زمان فراخوانی.

آیا می‌توان چند ویجت با یک کلاس ثبت کرد؟

بله، می‌توانید کلاس را چند بار با IDهای متفاوت instanceسازی کنید و ثبت کنید. اما هر instance باید ID اختصاصی داشته باشد.

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

در قالب‌های FSE، ویجت‌های کلاسیک به‌طور پیش‌فرض پشتیبانی نمی‌شوند. باید بلاک‌های معادل بسازید یا از Widget Block Area استفاده کنید. مطلب راهنمای Full Site Editing راهنماست.

آیا می‌توان ویجت را در Customizer مخفی کرد؟

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

آیا این تابع روی Multisite رفتار خاصی دارد؟

خیر، در Multisite هر سایت ویجت‌های خودش را دارد و register_widget روی هر سایت جداگانه اجرا می‌شود.

آیا می‌توان ویجت را با WP-CLI مدیریت کرد؟

بله، WP-CLI از دستور wp widget پشتیبانی می‌کند. مطلب راهنمای WP-CLI راهنماست.

نگاه فنی عمیق به register_widget

در سطح معماری، register_widget() یک رکورد در آرایه سراسری $wp_registered_widgets ثبت می‌کند. کلید این آرایه، شناسه ویجت (مثل my_widget-1) است که از ID کلاس و شماره نمونه ساخته می‌شود. وردپرس از این آرایه برای رندر ویجت در frontend و نمایش آن در پیشخوان استفاده می‌کند.

نکته ظریف اول، مسئله تفاوت instance و نام کلاس در پارامتر است. اگر نام کلاس را پاس دهید، وردپرس خودش یک instance می‌سازد و آن را برای همیشه نگه می‌دارد. اگر instance پاس دهید، همان شیء استفاده می‌شود. این تفاوت در سناریوهایی که نیاز به تنظیمات پیش‌فرض دارید، مهم است.

نکته دوم، مسئله Cache و Transient در ویجت‌هاست. نتایج متد widget به‌طور خودکار کش نمی‌شوند. اگر متد کوئری سنگین داشته باشد، هر بار رندر سایدبار یک کوئری انجام می‌شود. راهکار استاندارد استفاده از wp_cache_get و wp_cache_set است. مطلب تابع wp_cache_set راهنماست.

مسئله سوم، تعامل با Widget Block Editor است. از وردپرس 5.8، سیستم ویجت‌ها به سمت بلاک‌ها حرکت کرده است. ویجت‌های کلاسیک همچنان پشتیبانی می‌شوند اما در قالب‌های بلاکی ممکن است در ناحیه Widget Block Area نمایش داده شوند. برای مطالعه این تغییر، مطلب مدیریت ویجت‌ها در قالب‌های مدرن راهنماست.

در نهایت، در پروژه‌های Enterprise توصیه می‌شود به‌جای ساخت ویجت‌های مستقل، یک کلاس Registry مرکزی بسازید که تمام ویجت‌ها را به‌صورت declarative ثبت کند. این کار از پخش شدن منطق جلوگیری می‌کند و تست‌پذیری را بالا می‌برد. برای مطالعه بیشتر، مباحث WordPress Components و استانداردهای PSR مفید هستند. برای مطالعه بیشتر درباره خود وردپرس، WordPress در ویکی‌پدیا نقطه شروع خوبی است.

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