Custom dynamic_sidebar Function to Generate Class Definitions Corresponding to a Widget’s Position

In wordpress, if 2 widgets are stacked horizontally, there is no straightforward way of setting the width of the left widget as x and that of the right widget as y through php/css. The only way to accomplish that is by using hardcoded class definitions in the css. I have jotted down an easy solution for this problem in the wordpress ideas forum. However the code that I pasted looks all gibberish because most of the HTML tags in the code are not allowed. Hence this post for anybody who wants to see the code and other details.

The objective of this exercise is to generate class definitions like widget1, widget2 etc depending on the position of the widget in a sidebar. You can see an example right at the bottom of this post where you see the adsense widget and the “most read” widget side by side but with different widths. If you look at the HTML code for this page, you will see that the class definitions that have been generated for these two widgets are:

class="widget Advman_Widget widget-Advman_Widget widget1"
class="widget popular-posts widget-popular-posts widget2"

This lets me write css code like

#divid .widget1 {
width: 350px;
float: left;
}
#divid .widget2 {
width: 300px;
float: right;
}

That is widget independent, position dependent code. With the current implementation of wordpress the classes and code will look like:

class="widget Advman_Widget widget-Advman_Widget"
class="widget popular-posts widget-popular-posts"
#divid .widget {
width: 350px;
float: left;
}
#divid .widget-popular-posts {
width: 300px;
float: right;
}

This means that if I wish to changed the widget from “Popular Posts” to “Related Posts”, I will have to change the css code, which is not very convenient or extensible.

To overcome the above problem right now I’m using a custom dynamic_sidebar function in my theme. (I know using a customized wp core function is far from an ideal situation). However with this customized function, I can call the register_sidebar function with an extra argument to before_widget which in turn generates the widget1, widget2 classes. My register_sidebar call looks like the below code.

register_sidebar(array(
            'name' => 'SidebarID',
            'id' => 'SidebarID',
            'before_widget' => '<div id="%1$s" class="widget %2$s widget-%2$s widget%3$s"><div class="widget-inside">',
            'after_widget' => '</div></div>',
            'before_title' => '<h3 class="widget-title">', 'after_title' => '</h3>'
        ));

The extra widget%3$s argument is what generates the widget1, widget2 classes. The code for the custom dynamic sidebar function is pasted below.

function dynamic_sidebar_custom($index = 1) {
  global $wp_registered_sidebars, $wp_registered_widgets;

  if ( is_int($index) ) {
    $index = "sidebar-$index";
  } else {
    $index = sanitize_title($index);
    foreach ( (array) $wp_registered_sidebars as $key => $value ) {
      if ( sanitize_title($value['name']) == $index ) {
        $index = $key;
        break;
      }
    }
  }

  $sidebars_widgets = wp_get_sidebars_widgets();

  if ( empty($wp_registered_sidebars[$index]) || !array_key_exists($index, $sidebars_widgets) || !is_array($sidebars_widgets[$index]) || empty($sidebars_widgets[$index]) )
    return false;

  $sidebar = $wp_registered_sidebars[$index];

  $did_one = false;
  $widgetnth = 0;
  foreach ( (array) $sidebars_widgets[$index] as $id ) {

    if ( !isset($wp_registered_widgets[$id]) ) continue;
    $widgetnth++;
    $params = array_merge(
      array( array_merge( $sidebar, array('widget_id' => $id, 'widget_name' => $wp_registered_widgets[$id]['name']) ) ),
      (array) $wp_registered_widgets[$id]['params']
    );

    // Substitute HTML id and class attributes into before_widget
    $classname_ = '';
    foreach ( (array) $wp_registered_widgets[$id]['classname'] as $cn ) {
      if ( is_string($cn) )
        $classname_ .= '_' . $cn;
      elseif ( is_object($cn) )
        $classname_ .= '_' . get_class($cn);
    }
    $classname_ = ltrim($classname_, '_');
    $params[0]['before_widget'] = sprintf($params[0]['before_widget'], $id, $classname_, $widgetnth);

    $params = apply_filters( 'dynamic_sidebar_params', $params );

    $callback = $wp_registered_widgets[$id]['callback'];

    do_action( 'dynamic_sidebar', $wp_registered_widgets[$id] );

    if ( is_callable($callback) ) {
      call_user_func_array($callback, $params);
      $did_one = true;
    }
  }

  return $did_one;
}

All it required was two additions and one modification.

Using this function results in a couple of harmless warnings in the admin widgets screen inside the sidebar which uses this custom function. Hence right now I’m using it only for that one sidebar which benifits from this functionality.

Do leave your suggestions and comments.

1 comment

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.