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

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

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

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

در عیب‌یابی ویجت، اولین سؤال این نیست که «کد من کجاست»، بلکه این است «ویجت من در کدام‌یک از این سه لحظه شکست می‌خورد؟» تفاوت میان «در فهرست نیست»، «در فهرست هست ولی روی سایت نیست» و «روی سایت هست ولی ذخیره نمی‌شود» کل مسیر تشخیص را تغییر می‌دهد.

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

سیستم ویجت در وردپرس یکی از قدیمی‌ترین و در عین حال پایدارترین بخش‌های هسته است. مکانیزم کار به این ترتیب است: اول، یک کلاس PHP که از کلاس پایه WP_Widget ارث‌بری می‌کند تعریف می‌شود. دوم، این کلاس در هوک widgets_init با تابع register_widget ثبت می‌شود. سوم، قالب شما با register_sidebar یک یا چند موقعیت (sidebar) تعریف می‌کند. چهارم، وردپرس با اتصال این دو، ویجت‌هایی که کاربر در پیشخوان به سایدبارها اضافه می‌کند را در زمان رندر قالب نمایش می‌دهد. اگر با مفهوم افزونه وردپرس و لایه‌های آن آشنا نیستید، پیش از ادامه آن مقاله را مرور کنید.

کلاس پایه WP_Widget چهار متد مهم دارد که هرکدام در یک لحظه خاص اجرا می‌شود: متد __construct() در زمان ثبت کلاس، متد form() هنگام نمایش فرم تنظیمات در پیشخوان، متد update() هنگام ذخیره تنظیمات از همان فرم، و متد widget() هنگام نمایش خروجی روی سایت. اگر هر یک از این چهار متد به‌درستی پیاده‌سازی نشده باشد، ویجت در همان لحظه شکست می‌خورد و نشانه‌های متفاوتی تولید می‌کند. برای مرور معماری کلی ویجت‌ها و کد نمونه، ساخت ویجت اختصاصی با کدنویسی وردپرس را ببینید — این مقاله همان مفاهیم را به‌عنوان پیش‌نیاز فرض می‌کند.

متد کلاسزمان اجرامسئولیت
__construct()هنگام ثبت کلاستعریف شناسه، نام، توضیحات ویجت
form()نمایش در پیشخوانرندر فرم تنظیمات
update()ذخیره از فرمپاک‌سازی و بازگشت مقادیر جدید
widget()نمایش روی سایتتولید خروجی HTML نهایی

این جدول، نقشه راه عیب‌یابی ویجت است. اگر ویجت شما در فهرست ابزارک‌ها دیده نمی‌شود، به __construct و فراخوانی register_widget نگاه کنید. اگر روی سایت خروجی خالی است، به widget() بروید. اگر تنظیمات ذخیره نمی‌شود، به update() برگردید. این تفکیک ساده، نیمی از عیب‌یابی است.

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

شایع‌ترین علت عدم کارکرد ویجت افزونه، استفاده از هوک نادرست برای ثبت کلاس است. ویجت‌ها باید در هوک widgets_init ثبت شوند. اگر register_widget را در هوک init، wp_loaded یا حتی admin_init صدا بزنید، وردپرس آن را نادیده می‌گیرد و ویجت شما در فهرست ابزارک‌ها ظاهر نمی‌شود. این اشتباه در کدهای تولیدشده توسط ابزارهای هوش مصنوعی و در قالب‌های قدیمی تکرار می‌شود.

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

الگویی که در همه افزونه‌های خودم به کار می‌برم، با جداسازی کلاس ویجت و اتصال آن به هوک درست:

add_action( 'widgets_init', 'my_plugin_register_widgets' );

function my_plugin_register_widgets() {
    register_widget( 'My_Plugin_Recent_Posts_Widget' );
}

class My_Plugin_Recent_Posts_Widget extends WP_Widget {
    public function __construct() {
        parent::__construct(
            'my_plugin_recent_posts',
            __( 'آخرین نوشته‌های من', 'my-plugin' ),
            array( 'description' => __( 'نمایش آخرین نوشته‌ها با استایل سفارشی', 'my-plugin' ) )
        );
    }
    // ... سایر متدها
}

سه نکته کلیدی در این کد: اول، هوک widgets_init که تضمین می‌کند ثبت پیش از رندر ابزارک‌ها انجام می‌شود. دوم، ارث‌بری از کلاس WP_Widget که پایه همه ویجت‌های استاندارد است. سوم، فراخوانی parent::__construct() با سه آرگومان که شناسه یکتا، نام نمایشی، و توضیحات را ثبت می‌کند. اگر این فراخوانی را فراموش کنید یا آرگومان‌ها را نادرست بدهید، ویجت شما نه در فهرست دیده می‌شود و نه روی سایت کار می‌کند.

اشتباه رایج: ثبت در init یا admin_init

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

ثبت چند ویجت با هم

اگر افزونه شما چند ویجت دارد، همه را در یک تابع ثبت کنید تا ترتیب و نگهداری ساده‌تر شود:

add_action( 'widgets_init', 'my_plugin_register_widgets' );

function my_plugin_register_widgets() {
    register_widget( 'My_Plugin_Recent_Posts_Widget' );
    register_widget( 'My_Plugin_Contact_Info_Widget' );
    register_widget( 'My_Plugin_Social_Links_Widget' );
}

نکته مهم: اگر هر کلاس در فایل جداگانه‌ای تعریف شده است، باید قبل از فراخوانی register_widget مطمئن شوید آن فایل بارگذاری شده. اشتباه رایج دیگر: نام کلاس را اشتباه در register_widget بنویسید یا بعد از تغییر نام کلاس، این خط را به‌روز نکنید. نتیجه: خطای Class not found در لاگ و عدم نمایش ویجت در فهرست. برای درک معماری درست فایل‌ها در افزونه، ساختار فایل‌های یک افزونه استاندارد وردپرس را ببینید.

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

لایه دوم — ساختار اشتباه کلاس WP_Widget و متدها

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

متد __construct و شناسه یکتا

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

public function __construct() {
    parent::__construct(
        'myplugin_news_widget', // شناسه یکتا
        'خبرنامه افزونه من',      // نام نمایشی
        array(
            'description' => 'نمایش فرم عضویت در خبرنامه',
            'classname'   => 'myplugin-news-widget', // کلاس CSS
        )
    );
}

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

متد form و نمایش فرم تنظیمات

متد form( $instance ) فرم تنظیمات ویجت را در پیشخوان رندر می‌کند. آرگومان $instance شامل مقادیر ذخیره‌شده فعلی است که در فرم نمایش داده می‌شوند. الگوی درست:

public function form( $instance ) {
    $title   = isset( $instance['title'] ) ? $instance['title'] : 'خبرنامه';
    $count   = isset( $instance['count'] ) ? (int) $instance['count'] : 5;
    ?>
    <p>
        <label for="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>">
            عنوان:
        </label>
        <input
            class="widefat"
            id="<?php echo esc_attr( $this->get_field_id( 'title' ) ); ?>"
            name="<?php echo esc_attr( $this->get_field_name( 'title' ) ); ?>"
            type="text"
            value="<?php echo esc_attr( $title ); ?>"
        />
    </p>
    <p>
        <label for="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>">
            تعداد نوشته‌ها:
        </label>
        <input
            class="tiny-text"
            id="<?php echo esc_attr( $this->get_field_id( 'count' ) ); ?>"
            name="<?php echo esc_attr( $this->get_field_name( 'count' ) ); ?>"
            type="number"
            value="<?php echo esc_attr( $count ); ?>"
        />
    </p>
    <?php
}

سه نکته حیاتی در این کد: اول، استفاده از متدهای $this->get_field_id() و $this->get_field_name() که تضمین می‌کنند شناسه و نام فیلدها یکتا و مطابق استاندارد وردپرس باشند. اگر نام فیلد را دستی بسازید و یک کاراکتر اشتباه بگذارید، تنظیمات ذخیره نمی‌شود. دوم، استفاده از esc_attr برای escape مقادیر — این نکته امنیتی مهمی است که در پاک‌سازی داده‌ها در کدنویسی وردپرس به تفصیل آمده. سوم، استفاده از isset برای مقادیر پیش‌فرض — اگر فیلدی ذخیره نشده باشد، نباید خطای undefined index بدهد.

متد update و ذخیره تنظیمات

متد update( $new_instance, $old_instance ) مسئول ذخیره تنظیمات جدید است. این متد باید مقادیر جدید را پاک‌سازی کند و به‌عنوان آرایه بازگرداند. اگر این متد آرایه بازنگرداند یا مقادیر نادرست برگرداند، تنظیمات شما ذخیره نمی‌شود:

public function update( $new_instance, $old_instance ) {
    $instance          = array();
    $instance['title'] = ! empty( $new_instance['title'] )
        ? sanitize_text_field( $new_instance['title'] )
        : '';
    $instance['count'] = ! empty( $new_instance['count'] )
        ? absint( $new_instance['count'] )
        : 5;
    return $instance;
}

سه اشتباه رایج در این متد: اول، فراموش کردن return که نتیجه آن ذخیره‌نشدن است. دوم، استفاده نکردن از توابع پاک‌سازی مناسب هر فیلد — sanitize_text_field برای متن و absint برای اعداد. سوم، بازگرداندن آرایه‌ای که ساختار فیلدهای موجود را تغییر می‌دهد؛ این کار باعث می‌شود مقادیر قبلی پاک شوند. اصول کامل پاک‌سازی داده در بافت ویجت در همان مقاله اعتبارسنجی داده‌ها در کدنویسی وردپرس آمده است.

متد widget و خروجی روی سایت

متد widget( $args, $instance ) خروجی HTML نهایی را تولید می‌کند. آرگومان $args شامل تنظیمات سایدبار مثل before_widget، after_widget، before_title و after_title است. الگوی درست:

public function widget( $args, $instance ) {
    echo $args['before_widget'];

    if ( ! empty( $instance['title'] ) ) {
        echo $args['before_title']
            . apply_filters( 'widget_title', $instance['title'], $instance, $this->id_base )
            . $args['after_title'];
    }

    $count = ! empty( $instance['count'] ) ? (int) $instance['count'] : 5;

    $posts = get_posts( array(
        'numberposts' => $count,
        'post_status' => 'publish',
    ) );

    echo '<ul class="myplugin-recent-list">';
    foreach ( $posts as $post ) {
        echo '<li><a href="' . esc_url( get_permalink( $post ) ) . '">'
            . esc_html( get_the_title( $post ) )
            . '</a></li>';
    }
    echo '</ul>';

    echo $args['after_widget'];
}

سه نکته مهم: اول، استفاده از echo $args['before_widget'] و after_widget که سازگاری با قالب را تضمین می‌کند. اگر این‌ها را دستی نکنید، ویجت شما بدون قاب و استایل قالب نمایش داده می‌شود. دوم، استفاده از فیلتر widget_title که به افزونه‌های دیگر اجازه می‌دهد عنوان ویجت شما را تغییر دهند — این اصل «گسترش‌پذیری» است که در نحوه استفاده صحیح از هوک‌های وردپرس به تفصیل آمده. سوم، استفاده از esc_html و esc_url برای escape خروجی که امنیت سایت را تضمین می‌کند. مبانی امنیت خروجی در بافت PHP در نوشتن کد PHP امن برای وردپرس توضیح داده شده است.

لایه سوم — ثبت سایدبار و موقعیت‌های قالب

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

الگوی درست ثبت سایدبار

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

add_action( 'widgets_init', 'mytheme_register_sidebars' );

function mytheme_register_sidebars() {
    register_sidebar( array(
        'name'          => 'سایدبار اصلی',
        'id'            => 'mytheme-primary-sidebar',
        'description'   => 'ویجت‌های ستون کنار محتوای اصلی',
        'before_widget' => '<aside id="%1$s" class="widget %2$s">',
        'after_widget'  => '</aside>',
        'before_title'  => '<h3 class="widget-title">',
        'after_title'   => '</h3>',
    ) );
}

نکات کلیدی: اول، شناسه سایدبار (id) باید یکتا باشد. اگر دو سایدبار با شناسه یکسان ثبت کنید، وردپرس یکی را نادیده می‌گیرد. دوم، before_widget و after_widget که ساختار HTML دور هر ویجت را تعریف می‌کنند. این مقادیر در $args به متد widget() منتقل می‌شوند. اگر این‌ها را نادرست تعریف کنید، ویجت‌ها روی سایت به‌هم‌ریخته نمایش داده می‌شوند. مرور کامل پیکربندی سایدبارها و ویجت‌ها در پیکربندی منو و ویجت‌های وردپرس آمده است.

نمایش سایدبار در فایل‌های قالب

ثبت سایدبار کافی نیست؛ قالب باید در فایل‌های خودش آن سایدبار را نمایش دهد. الگوی استاندارد:

<?php if ( is_active_sidebar( 'mytheme-primary-sidebar' ) ) : ?>
    <div class="sidebar-wrapper">
        <?php dynamic_sidebar( 'mytheme-primary-sidebar' ); ?>
    </div>
<?php endif; ?>

سه نکته در این کد: اول، بررسی is_active_sidebar که اگر سایدبار خالی باشد، ظرف دور آن هم نمایش داده نمی‌شود. دوم، استفاده از dynamic_sidebar که خودش ویجت‌ها را با ساختار قبل/بعد رندر می‌کند. سوم، اگر این کد را در child theme قرار می‌دهید، مطمئن شوید که file در جای درست قرار گرفته. بحث جانشینی فایل‌های قالب در بافت قالب فرزند در قالب چایلد وردپرس چیست توضیح داده شده است.

اشتباه رایج: sidebars.php نبودن در قالب

در قالب‌های قدیمی که ساختار فایل‌هایشان نامنظم است، گاهی کد register_sidebar داخل فایلی قرار دارد که در front-end بارگذاری نمی‌شود یا مشروط به شرطی است که برآورده نمی‌شود. راه‌حل: همیشه ثبت سایدبارها را در functions.php قالب یا در یک فایل جداگانه که در hook after_setup_theme یا widgets_init بارگذاری می‌شود قرار دهید. برای مرور معماری فایل‌های یک قالب استاندارد، ساختار فایل‌های یک قالب استاندارد وردپرس را ببینید.

ثبت سایدبار و نمایش آن، دو مرحله جدا هستند. اگر هر یک را انجام دهید و دیگری را فراموش کنید، نتیجه در ظاهر شبیه «ویجت کار نمی‌کند» است — ولی در واقع مسئله این نیست که ویجت کار نمی‌کند، بلکه این است که جایی برای نمایش آن وجود ندارد.

لایه چهارم — ویجت‌های بلوکی گوتنبرگ و مهاجرت

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

سازگاری ویجت کلاسیک با ویرایشگر بلوکی

خبر خوب: وردپرس خودش لایه سازگاری بین ویجت‌های کلاسیک و ویرایشگر بلوکی را ارائه می‌دهد. تا زمانی که ویجت شما از استاندارد WP_Widget پیروی کند، به‌عنوان یک بلوک «Legacy Widget» در ویرایشگر جدید ظاهر می‌شود. اما این لایه دو محدودیت مهم دارد: اول، تنظیمات ویجت کلاسیک در ویرایشگر بلوکی به‌صورت پنل کنار نمایش داده می‌شود (نه به‌صورت فرم درون بلوک). دوم، اگر ویجت شما از فایل‌های جاوااسکریپت اختصاصی برای فرم تنظیمات استفاده می‌کند، ممکن است در ویرایشگر جدید کار نکند. برای مطالعه معماری بلوک‌های گوتنبرگ و آینده ویرایش محتوا، گوتنبرگ و آینده ویرایش محتوا در وردپرس را ببینید.

مهاجرت ویجت کلاسیک به بلوک

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

add_action( 'init', 'my_plugin_register_widget_block' );

function my_plugin_register_widget_block() {
    register_block_type( 'my-plugin/newsletter-widget', array(
        'render_callback' => 'my_plugin_render_newsletter_widget',
        'attributes'      => array(
            'title' => array( 'type' => 'string', 'default' => 'خبرنامه' ),
        ),
    ) );
}

function my_plugin_render_newsletter_widget( $attributes ) {
    // منطق رندر
    return '<div class="myplugin-newsletter">...</div>';
}

نکته مهم: برای اینکه بلوک شما در ویرایشگر ویجت‌ها هم ظاهر شود، باید register_block_type را با درست تعریف کردن render_callback بنویسید تا خروجی روی سرور تولید شود نه در جاوااسکریپت. بلوک‌های پویا (Dynamic Blocks) مناسب این سناریو هستند. راهنمای کامل ساخت بلوک‌های سفارشی گوتنبرگ در بلوک‌های سفارشی گوتنبرگ را از صفر بسازید آمده است.

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

در ویرایشگر ویجت‌های بلوکی، سه مسئله رایج وجود دارد که در پروژه‌های واقعی دیده‌ام. اول، بلوک‌هایی که در پیش‌نمایش ویرایشگر کار می‌کنند ولی روی سایت نه — این مسئله معمولاً به این برمی‌گردد که در ویرایشگر، رندر سمت کلاینت انجام می‌شود و روی سرور نه. راه‌حل: از بلوک‌های پویا (Dynamic Block) با render_callback استفاده کنید. دوم، تنظیمات ویجت کلاسیک در ویرایشگر جدید ذخیره نمی‌شوند — این حالت در ویجت‌هایی که متد update را نادرست پیاده‌سازی کرده‌اند شایع است. سوم، ویجت کلاسیک در ویرایشگر بلوکی به‌عنوان بلوک «قدیمی» شناخته نمی‌شود — این مسئله معمولاً به نبود کامنت استاندارد در کد ویجت برمی‌گردد. اصول کامل ساختار افزونه‌ای که با گوتنبرگ سازگار باشد در اشتباهات رایج هنگام نصب افزونه وردپرس قابل ردیابی است.

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

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

کش صفحه و ویجت‌ها

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

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

افزونه‌های دیگری که روی سیستم ویجت اثر می‌گذارند می‌توانند با ویجت شما تعارض داشته باشند. سه دسته شایع: اول، افزونه‌هایی که مدیریت ویجت‌های شرطی را اضافه می‌کنند (مثل Widget Logic) — این‌ها می‌توانند ویجت شما را بر اساس شرایطی که شما نمی‌دانید غیرفعال کنند. دوم، افزونه‌های بیلدر صفحه‌ای که سایدبارها را بازنویسی می‌کنند (مثل Elementor Pro) — این‌ها سیستم ویجت وردپرس را با سیستم خودشان جانشین می‌کنند. سوم، افزونه‌های چندزبانه که ممکن است ویجت شما را در زبان‌های غیراصلی مخفی کنند. برای تشخیص، ابتدا افزونه‌های مشکوک را غیرفعال کنید و تست بگیرید. الگوی کامل این عیب‌یابی در چگونه افزونه مشکل‌ساز وردپرس را پیدا کنیم توضیح داده شده است.

تعارض با قالب

گاهی قالب شما با CSS اختصاصی، ویجت‌ها را مخفی می‌کند. مثلاً display: none روی کلاس خاص یا مخفی کردن همه ویجت‌ها در اندازه‌های موبایل. برای تشخیص، در مرورگر Inspect Element کنید و ببینید آیا ویجت شما در HTML صفحه وجود دارد. اگر وجود دارد ولی دیده نمی‌شود، مسئله CSS است نه سیستم ویجت. اگر وجود ندارد، مسئله در سطح PHP است. این تفکیک، جهت عیب‌یابی را کوتاه می‌کند.

مشکلات ناشی از PHP و محدودیت‌های منابع

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

چک‌لیست دیباگ گام‌به‌گام خطای ویجت

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

  1. بررسی فهرست ابزارک‌ها: ویجت شما در فهرست «نمایش ← ابزارک‌ها» دیده می‌شود؟ اگر نه، مشکل در لایه اول (هوک) یا لایه دوم (ساختار کلاس) است. اگر بله ولی نمی‌توانید آن را به سایدبار بکشید، به لایه سوم (ثبت سایدبار) بروید.
  2. بررسی View Source: ویجت شما در HTML صفحه وجود دارد؟ با Inspect Element یا View Source بررسی کنید. اگر وجود دارد ولی دیده نمی‌شود، مسئله CSS است. اگر وجود ندارد، به گام بعدی بروید.
  3. فعال‌سازی WP_DEBUG: در wp-config.php مقادیر WP_DEBUG، WP_DEBUG_LOG و WP_DEBUG_DISPLAY را تنظیم کنید. لاگ در wp-content/debug.log نوشته می‌شود.
  4. لاگ موقت در متد widget: در ابتدای متد widget() خود یک error_log( 'widget called' ); بگذارید و بررسی کنید آیا روی سایت فراخوانی می‌شود یا نه. اگر صدا زده نمی‌شود، ویجت به سایدبار وصل نشده یا سایدبار رندر نمی‌شود.
  5. تست با قالب پیش‌فرض: قالب Twenty Twenty-Five را موقتاً فعال کنید و بررسی کنید آیا ویجت کار می‌کند یا نه. اگر کار می‌کند، مسئله در قالب است. اگر نه، در افزونه.
  6. غیرفعال کردن افزونه‌های دیگر: همه افزونه‌های دیگر را غیرفعال کنید و یکی‌یکی فعال کنید تا مقصر پیدا شود. تمرکز ویژه روی افزونه‌های مدیریت ویجت، بیلدر صفحه، و کش.
  7. پاک کردن کش: افزونه کش، کش مرورگر، کش CDN را پاک کنید. اگر مشکل حل شد، به لایه پنجم برگردید.
  8. بررسی console مرورگر: اگر با ویرایشگر ویجت بلوکی کار می‌کنید، کنسول مرورگر را باز کنید و خطاهای جاوااسکریپت را بررسی کنید. مشکل ممکن است در بارگذاری فایل JS مربوط به ویجت باشد که در مقالات خطای عدم بارگذاری JS افزونه به تفصیل توضیح داده شده است.
  9. تست روی محیط استجینگ: اگر روی محیط محلی کار می‌کند ولی روی سرور نه، تفاوت‌های محیطی مسئول است. مطمئن شوید هر دو محیط از یک نسخه PHP و افزونه‌های یکسان استفاده می‌کنند.
  10. مقایسه کد با نسخه استاندارد: کد ویجت خود را با یک نمونه استاندارد از همان مقاله ساخت ویجت اختصاصی مقایسه کنید و تفاوت‌ها را بررسی کنید.

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

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

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

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

چهار علت رایج. اول، هوک ثبت نادرست است — ویجت‌ها فقط در هوک widgets_init قابل ثبت هستند نه در init یا admin_init. دوم، کلاس ویجت شما از WP_Widget ارث‌بری نکرده یا parent::__construct() را فراخوانی نمی‌کند. سوم، فایل کلاس بارگذاری نشده یا نام کلاس در register_widget اشتباه است. چهارم، افزونه‌ای دیگر با همان شناسه ویجت را ثبت کرده و ویجت شما را نادیده می‌گیرد. برای تشخیص، ابتدا با error_log بررسی کنید آیا هوک اجرا می‌شود یا نه.

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

سه علت رایج. اول، سایدبار در فایل‌های قالب با dynamic_sidebar نمایش داده نشده. دوم، افزونه‌ای (مثل Widget Logic) ویجت شما را بر اساس شرطی مخفی کرده. سوم، CSS قالب ویجت را با display: none مخفی کرده. راه تشخیص: View Source و Inspect Element که مشخص می‌کند آیا ویجت در HTML وجود دارد یا نه. اگر وجود ندارد، مسئله PHP است؛ اگر وجود دارد ولی دیده نمی‌شود، مسئله CSS.

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

سه علت. اول، متد update() آرایه برنمی‌گرداند یا ناقص برمی‌گرداند. دوم، فیلدهای فرم با $this->get_field_name() ساخته نشده‌اند و در نتیجه وردپرس آن‌ها را به‌عنوان ورودی ویجت شما تشخیص نمی‌دهد. سوم، افزونه کش، نسخه قدیمی ویجت را سرو می‌کند. راه‌حل: ابتدا متد update() را بازبینی کنید و مطمئن شوید مقادیر را با توابع پاک‌سازی مناسب برگردانده است، سپس کش را پاک کنید.

چرا ویجت من بعد از فعال‌سازی گوتنبرگ کار نمی‌کند؟

این مسئله به مهاجرت سیستم ویجت به بلوک‌های گوتنبرگ مربوط است. اگر ویجت شما کلاسیک است ولی از قالب صفحه‌ساز استفاده می‌کند یا در ویرایشگر جدید ثبت نمی‌شود، مسئله در لایه چهارم است. راه‌حل: یا از لایه سازگاری وردپرس (Legacy Widget Block) استفاده کنید که به‌طور خودکار ویجت کلاسیک را در ویرایشگر بلوکی نمایش می‌دهد، یا نسخه بلوکی ویجت خود را با register_block_type بسازید. برای مطالعه مسیر مهاجرت، بلوک‌های سفارشی گوتنبرگ را از صفر بسازید را ببینید.

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

بله، با استفاده از the_widget() که یک تابع وردپرس برای رندر یک ویجت مشخص در هر جای قالب است. الگوی درست:

<?php the_widget(
    'My_Plugin_Recent_Posts_Widget',
    array( 'title' => 'آخرین مطالب' ),
    array( 'before_widget' => '<div class="custom-widget">' )
); ?>

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

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

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

چطور ویجت را از کش مستثنا کنم؟

روش‌های مختلف بسته به افزونه کش شما متفاوت است. راه‌حل عمومی: از تابع set_transient با زمان کوتاه برای داده‌های پویا استفاده کنید، یا از جریان‌های JavaScript/AJAX برای بارگذاری داده‌های زنده در ویجت بهره ببرید. راه‌حل اختصاصی: در تنظیمات افزونه کش، مسیر یا بخش مربوط به ویجت‌ها را استثنا کنید. برای مطالعه رفتار افزونه‌های کش در بافت ویجت‌های پویا، بهترین افزونه‌های کش وردپرس را ببینید.

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

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

معماری پایدار برای ویجت‌های مطمئن

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

  1. شناسه یکتا و پیشوند اختصاصی: همیشه نام افزونه را به‌عنوان پیشوند شناسه ویجت و نام کلاس استفاده کنید تا شانس تصادم با افزونه‌های دیگر به صفر برسد.
  2. ثبت در widgets_init با فراخوانی parent::__construct: همیشه از هوک widgets_init و فراخوانی سازنده والد استفاده کنید. این دو، پایه‌های ثبت مطمئن هستند.
  3. پیاده‌سازی هر چهار متد به‌طور صریح: __construct، form، update، widget. هر یک را با escape و sanitize مناسب بنویسید.
  4. استفاده از get_field_id و get_field_name: برای تولید نام و شناسه فیلدها، همیشه از این متدها استفاده کنید. هرگز نام فیلد را دستی نسازید.
  5. بازگرداندن مقدار از update: همیشه متد update باید آرایه برگرداند. فراموش کردن این، منشأ شایع‌ترین خطاهای ذخیره است.
  6. سازگاری با بلوک‌های گوتنبرگ: اگر افزونه شما برای مدت طولانی پشتیبانی می‌شود، نسخه بلوکی ویجت خود را با register_block_type ارائه دهید تا در ویرایشگر مدرن هم کار کند.
  7. داده‌های پویا و کش: اگر ویجت شما داده‌های زنده نمایش می‌دهد، از set_transient با زمان کوتاه استفاده کنید یا داده را با AJAX بارگذاری کنید تا کش صفحه آن را منجمد نکند.
  8. escape خروجی: همه خروجی‌های HTML را با esc_html، esc_attr، یا esc_url escape کنید. امنیت خروجی از اصول پایه است که در پاک‌سازی داده‌ها در کدنویسی وردپرس به تفصیل آمده است.
  9. تست روی قالب‌های مختلف: ویجت خود را روی حداقل دو قالب متفاوت (پیش‌فرض و یک قالب تجاری) تست کنید تا از سازگاری مطمئن شوید. تفاوت در ساختار سایدبارها بین قالب‌ها می‌تواند منشأ رفتار غیرمنتظره باشد.
  10. رعایت استانداردهای کدنویسی: کد خوانا، امن، و بدون هاردکد. مرور اصول در استانداردهای کدنویسی وردپرس چیست و کاربرد عملی در استفاده از WordPress Coding Standards در پروژه‌ها آمده است.

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

سخن پایانی

خطای عدم کارکرد ویجت افزونه، در نگاه اول ممکن است یکی از کم‌اهمیت‌ترین خطاهای وردپرس به‌نظر برسد، ولی در عمل یکی از پرتکرارترین انواع خطا در توسعه افزونه‌هایی است که به سایدبار وابسته‌اند — و در پروژه‌های فروشگاهی می‌تواند اثر مستقیم روی تجربه خرید داشته باشد. این خطا همیشه در یکی از پنج لایه‌ای که در این مقاله بررسی کردیم ریشه دارد: هوک نادرست در ثبت ویجت، ساختار اشتباه کلاس WP_Widget، ثبت نادرست سایدبار در قالب، ناسازگاری با ویجت‌های بلوکی گوتنبرگ، و تعارض با کش یا افزونه‌های دیگر. مسیر عیب‌یابی که در چک‌لیست ارائه کردم، همان ترتیبی است که در پروژه‌های واقعی همیشه مرا سریع به علت رسانده؛ نکته کلیدی این است که از گام‌های ارزان (بررسی فهرست ابزارک‌ها، View Source) شروع کنید و به گام‌های گران (غیرفعال کردن افزونه‌ها، تست روی قالب پیش‌فرض) برسید. در بلندمدت، انضباط در نام‌گذاری، پیاده‌سازی صریح چهار متد، escape خروجی، و سازگاری با گوتنبرگ، مهم‌تر از هر راه‌حل لحظه‌ای است — چون این انضباط است که اجازه نمی‌دهد این نوع خطا دوباره ظاهر شود.

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