4

I have a widget I want only allowed to be used with the single.php sidebar. When I referenced the codex for register sidebar there isn't a way to limit widgets in the array. I've researched with "WordPress limit widget to post" but they are only plugins returned in my search results. When I change my search parameters to page to see if I can get something returned I am reference to:

Is there a way that I can target a Widget to only be allowed for the id in the register_sidebar? I do not want to use a plugin I want to learn how to properly code it.

EDIT:

Per comments I have a custom widget. that is being called in my singles.php as <?php get_sidebar( 'foobar' );?>. When someone is in admin I want to limit where the widget can be applied to:

enter image description here

So in the image above I want there to only be the option of Post Sidebar. I could hard code all of this in in the sidebar-foobar.php file but I am trying to learn how to utilize widgets more.

  • 2
    Do you want to limit the display of that widget (so it only appears on single.php / single blog posts)? or do you need to disable the ability of admins to drag it into other sidebars in the control panel? There are options for the former but I'm not sure about the latter. – Michelle Sep 24 '15 at 14:58
  • yes I have that widget dedicated to a sidebar which that sidebar is only for single posts – DᴀʀᴛʜVᴀᴅᴇʀ Sep 24 '15 at 15:06
  • 1
    If it's not a custom widget and you can't conditionally display the content using is_singular( 'post' ); maybe you can look into how Widgets are binded - Quora Answer may be of some help. – Howdy_McGee Sep 24 '15 at 15:12
  • I made an edit for clarity. – DᴀʀᴛʜVᴀᴅᴇʀ Sep 24 '15 at 15:31
  • Interesting question. The solution is quite extensive though and something that I might look into during the following week or two, kinda busy the next few days. :-) – Pieter Goosen Sep 24 '15 at 18:18
2

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

1

As an addition to your scripts I wrote the script which hides sidebars from the dropdown list (I couldn't find this anywhere). I made some reverse engineering of the original widgets.js Wordpress code to write this.

The complete solution for allowing to drag & drop only to specified sidebars and to filter the dropdown list (you just need to put this in your document ready jQuery admin script):

function allowedSidebars(allowed)
{
    // this variable will have index of first visible sidebar
    var first = null;
    $('.widgets-chooser-sidebars li').removeClass('widgets-chooser-selected').each(function(index)
    {
        // the data('sidebarId') is set up by wordpress, let's make us of it
        if(-1 === $.inArray($(this).data('sidebarId'), allowed))
        {
            $(this).hide();
        }
        else if(first == null)
        {
            first = index;
        }
    });
    // choose first visible sidebar as default
    if(first != null)
    {
        $('.widgets-chooser-sidebars li').eq(first).addClass('widgets-chooser-selected');
    }
}
$('#available-widgets .widget .widget-title').on('click.widgets-chooser', function()
{
    var widget = $(this).closest('.widget');
    // we want to run our script only on slideDown, not slideUp
    if(!widget.hasClass('widget-in-question'))
    {
        // there is only one sidebar list per all widgets, so we have to show all the sidebars every time
        $('.widgets-chooser-sidebars li').show();
        switch(widget.find('input[name="id_base"]').val())
        {
            // your widgets here
            case 'your_widget_id':
                // allowed sidebars for widget
                allowedSidebars(['your-sidebar-id', 'your-second-sidebar-id']);
            break;
        }
    }
});
// this will make drag and drop working only for specified sidebars
$('.widget').on('dragcreate dragstart', function( event, ui ) {
    var id = $(this).find('input[name="id_base"]').val();
    // probably you may want to change it to switch
    if(id == 'your_widget_id')
    {
        $(this).draggable({
            connectToSortable: '#your-sidebar-id, #your-second-sidebar-id'
        });
    }
});

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.