Limit widget to a specific registered sidebar

My jquery knowledge is still almost non existent, so I’m not sure if the solution works that was suggested by @Howdy_McGee in comments.

Anyways, just as matter of proper reference, from the link

just replace 'your_widget' with name of your widget in the code below
(two places).

'sortreceive' event is only called when widget is added to sidebar,
while 'sortstop' gets called whenever you move the widget around
inside sidebar or remove it.

'sortstop' is also called when widget is added, but for some reason
ui.input is not set properly, so i used ‘sortreceive’ to cover that.

jQuery('div.widgets-sortables').bind('sortstop',function(event,ui){
  var id = jQuery(ui.item).attr('id');
  if (id) {
    var widget_type = id.match(/widget-[0-9]+_(.+)-[0-9]+/i)[1];
    if (widget_type == 'your_widget') {
    // do stuff;
    }
  }
})

jQuery('div.widgets-sortables').bind('sortreceive',function(event,ui){
  var id = jQuery(ui.item).attr('id');
  var widget_type = id.match(/widget-[0-9]+_(.+)-__i__/i)[1];
  if (widget_type == 'your_widget') {
    // do stuff;
  }
})

I have recently worked on an answer where a specific widget can be removed from the array of widgets from a specific sidebar. Here we use the sidebars_widgets filter to remove a specific widget from all sidebars except the sidebar where it should be.

So in short, a widget that is incorrectly added to a sidebar will not show up in front end, and it will also not return true with an is_active_sidebar() check if that widget is the only widget added to that specific sidebar.

You can try the following code, just be sure to change the widget and sidebar values accordingly.

add_filter( 'sidebars_widgets', function ( $sidebars_widgets )
{
    // Return our filter when we are on admin screen
    if ( is_admin() )
        return $sidebars_widgets;

    /**
     * Widget we need to target. This should be the name/id we used to register it
     *
     * EXAMPLE
     * parent::__construct(
            'widget_category_posts', 
            _x( 'Category Posts Widget', 'Category Posts Widget' ), 
            [ 'description' => __( 'Display a list of posts from a selected category.' ) ] 
        );
     *
     */
    $custom_widget="widget_category_posts";
    // The sidebar ID we need to run the widget in
    $sidebar_accept="sidebar-2";

    // We have come this far, let us wrap this up
    // See if our custom content widget exists is any sidebar, if so, get the array index
    foreach ( $sidebars_widgets as $sidebars_key=>$sidebars_widget ) {
        // Skip the wp_inactive_widgets set, we do not need them
        if ( $sidebars_key == 'wp_inactive_widgets' )
        continue;

        // Only continue our operation if $sidebars_widget are not an empty array
        if ( $sidebars_widget ) {
            foreach ( $sidebars_widget as $k=>$v ) {

                /**
                 * Look for our custom widget, if found, unset it from the $sidebars_widgets array
                 * @see stripos()
                 */
                if ( stripos( $v, $custom_widget ) !== false ) {
                    // If we are on a single page and the sidebar is $sidebar_accept, do not unset
                    if ( is_single() && $sidebars_key == $sidebar_accept )
                        continue;

                    unset( $sidebars_widgets[$sidebars_key][$k] );
                }
            } // endforeach $sidebars_widget
        } // endif $sidebars_widget
    } // endforeach $sidebars_widgets

    return $sidebars_widgets;
});

In conclusion, this is just a PHP workaround which does work only for the front end, but I would urge you to still look for a proper jquery solution where a widget is only bound to a specific sidebar in the backend. As I said, the jquery solution from the link is untested and I do not know if if really works

Leave a Comment