post: Dynamic widgets in horizontal sidebars

Home

Dynamic widgets in horizontal sidebars 3

Working With WordPress

  

Tutorials

Bootstrap CSS WordPress

In the previous part we discussed the alternative method of adding multiple widgets to a horizontal sidebar. Here we streamline this and tweak the traditional method.

Programmatically adding dynamic widgets in a single sidebar: Streamlined

The alternative method of adding multiple widgets to a horizontal sidebar, while attractive, has some convoluted core requiring delving into the widget contents for callback functions and parameters. WordPress normally has some kind of function for everything. It also has in this case. Enter: the_widget().

This function according to the WordPress codex will display a widget: “This template tag displays an arbitrary widget outside of a sidebar. It can be used anywhere in templates”.


<?php the_widget( $widget, $instance, $args ); ?> 

One caveat though. The first parameter is based on the widget class name. This isn’t immediately obvious, or readily available. It is though available in the data stored in the global variables used in the previous method. Let us again dive into some code to get this and display the widgets. Again we’re using the footer sidebar and 4 text widgets.


<?php

global $wp_registered_widgets, $wp_registered_sidebars, $sidebars_widgets;

// Widget limiters
$min_widgets = 2;
$max_widgets = 4;
$overload = 'random'; // random if more than max_widgets or empty to use first max_widgets

// Set param list
$widget_params = array();

// Test sidebar
if ( array_key_exists( 'sidebar-footer', $wp_registered_sidebars ) ) {
    $sidebar = $wp_registered_sidebars['sidebar-footer'];
} else { return; }

// set base widget params
$params = array( 'before_widget'    => '<div id="%1$s" class="widget %2$s">',
                 'after_widget'     => '</div>',
                 'before_title'     => '<h4 class="widget-title widgettitle">',
                 'after_title'      => '</h4>' );
$params = array_merge( $params, $sidebar );

// Retrieve sidebar widgets
$sidebar_widgets = ( array_key_exists('sidebar-footer', $sidebars_widgets ) ) ? $sidebars_widgets['sidebar-footer'] : array();
$widget_count = count( $sidebar_widgets );

// Widget restrictions
if ( $widget_count == 0 || ( $min_widgets > 1 && $widget_count < $min_widgets ) ) { return; }
if ( $widget_count > $max_widgets ) {
    // deal with excess
    if ( $overload  == 'random' ) { shuffle( $sidebar_widgets ); }
    $sidebar_widgets = array_slice( $sidebar_widgets, 0, $max_widgets );
}

// Set up the widget list
$widget_params = array();
foreach ( $sidebar_widgets as $widget_id ) {

    // Default args
    $widget_params[$widget_id]['args'] = $params;
    
    // Search requirements
    $callback   = $wp_registered_widgets[$widget_id]['callback'];
    $number     = $wp_registered_widgets[$widget_id]['params'][0]['number'];
    $class      = $wp_registered_widgets[$widget_id]['classname'];

    // Update params
    $widget_params[$widget_id]['args']['before_widget'] = sprintf($widget_params[$widget_id]['args']['before_widget'], $widget_id, $class );
        
    // Set widget settings
    $settings = $callback[0]->get_settings();
    $widget_params[$widget_id]['instance'] = $settings[$number];

    // Get widget class
    $widget_params[$widget_id]['widget'] = get_class( $callback[0] );
}

// Set column
$widget_col = intval( 12 / count( $widget_params ) );
    
// Display Sidebar
if ( !empty( $widget_params ) ) : ?>
<section id="sidebar-footer" class="container-fluid footer-widgets">
    <div class="row">
    <?php foreach ( $widget_params as $k=>$v ) : ?>
        <div class="col-md-<?php echo $widget_col; ?> <?php echo $k; ?> footer-widget">
            <?php the_widget( $v['widget'], $v['instance'], $v['args'] ); ?>
        </div>
    <?php endforeach; ?>
    </div>
</section>
<?php endif; ?>

Again a fair amount of code. The top sections are the same as the previous method, so we’ll jump to the main section which deals with setting up the widget data.

The key to this is the contents of each widget stored in the wp_registered_widgets array.


Array ( 
    [name] => Text 
    [id] => text-3 
    [callback] => Array ( 
        [0] => WP_Widget_Text Object ( 
            [id_base] => text 
            [name] => Text 
            [widget_options] => Array ( 
                [classname] => widget_text 
                [description] => Arbitrary text or HTML. 
            ) 
            [control_options] => Array ( 
                [id_base] => text 
                [width] => 400 
                [height] => 350 
            ) 
            [number] => 6 
            [id] => text-6 
            [updated] => 
            [option_name] => widget_text 
        ) 
        [1] => display_callback 
    ) 
    [params] => Array ( 
        [0] => Array ( 
            [number] => 3 
        ) 
    ) 
    [classname] => widget_text 
    [description] => Arbitrary text or HTML. 
)

What we need are the callback, classname and params values.


 // Search requirements
    $callback   = $wp_registered_widgets[$widget_id]['callback'];
    $number     = $wp_registered_widgets[$widget_id]['params'][0]['number'];
    $class      = $wp_registered_widgets[$widget_id]['classname'];

The first parameter to the_widget() is the classname which is retrieved from the callback object via get_class(). The second argument is the instance, which is actually the settings for the widget. These are stored in an array related to the number of instances of that particular widget type. In this case 4 text widgets. The one for this instance is in the params setting ‘number’, here 3. We also translate the widget_id and class for the before_widget setting.


<?php the_widget( $v['widget'], $v['instance'], $v['args'] ); ?>

Once done these can be passed to the_widget() which deals with the widget display. We’ve kept the markup the same as the previous example, so you can check that for the html & css.

Tweaking the original

You’ll recall that in the original method that we defined one sidebar for each required widget area, so 4 sidebars for 4 widgets. These were then hardcoded into the template file. Not ideal. Dynamically showing which of these is available is possible using the is_active_sidebar() function. e.g.


<?php if ( is_active_sidebar( 'sidebar-footer-1' ) ) { ?>

With this we can determine which sidebars are active and dynamically display them. We can add a touch of css to set the width. So, with some more code. Replace the contents of the sidebar-footer.php (the one in the main theme folder):


<?php

// Widget limiters
$min_widgets = 2;

// Which sidebars are active?
$footer_sidebars = array( 'sidebar-footer-1', 'sidebar-footer-2', 'sidebar-footer-3', 'sidebar-footer-4' );
$active_sidebars = array();

foreach ( $footer_sidebars as $footer_sidebar ) {
    if ( is_active_sidebar( $footer_sidebar ) ) { $active_sidebars[] = $footer_sidebar; }
}

// Validate
$sidebar_count = count( $active_sidebars );
if ( $sidebar_count < $min_widgets ) { return; }

// Set css width
$footer_width = 'widgets-'.$sidebar_count;

// Display Sidebar
?>
<section id="sidebar-footer" class="footer-widgets <?php echo $footer_width; ?>">
    <?php foreach( $active_sidebars as $active_sidebar ) : ?>
    <div class="footer-widget">
        <?php dynamic_sidebar( $active_sidebar ); ?>
    </div>
    <?php endforeach; ?>
</section>

We do a basic activity check for each of the widget areas and construct an active_sidebars variable. If there are active widget areas, and over the minimum number available, then we display the sidebar and set the width with a defined widgets-xx class. Pretty simple. In the example below we have removed the widget from the 3rd widget area, so only 1,2 & 4 display.

The key css to set the width is, as previously:


.footer-widgets.widgets-2 .footer-widget { float: left; width: 50%; }
.footer-widgets.widgets-3 .footer-widget { float: left; width: 33.3333333333%; }
.footer-widgets.widgets-4 .footer-widget { float: left; width: 25%; }

I hope this has given you an idea of how sidebars and widgets work in WordPress. I’ll post some links to source code and examples when time and update the posts.

comments powered by Disqus