3

Some predefined widgets offer the option to use a select element (dropdown) and/or a counter after each entry. How can I add the CSS classes widget-with-dropdown or widget-with-counters to these widgets?

There are already solutions for custom widgets, known sidebar ids or positions, but I have to inspect the parameters for the current instance, and I want to catch all possible positions or widgets (if they follow the WordPress naming scheme).

  • Why do you want to add classes? to style them or some other purpose? Do you know what these widgets before hand (Your theme or plugin or a site you own) or a generic ones? – Satish Gandham Mar 14 '17 at 4:52
  • @SatishGandham Examples are the built-in widgets like the Archive widget. – fuxia Mar 14 '17 at 8:53
4

The CSS classes are applied in the function dynamic_sidebar(). There is no specific filter for that:

// 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_);

But there is a filter for $params right after this code block:

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

To get the settings for the current widget, we have to search in the global variable $wp_registered_widgets for an entry with the key $params[ 0 ][ 'widget_id' ].
If it exists, it has a class instance as callback, and we can use that object’s method get_settings() to … well … get the settings.
The returned array has probably a key that equals $params[1][ 'number' ].
Associated with this key is an array again, and here we might find another key dropdown (or count) with a value of 0 or 1.
If it is 1, we add the new classes to the string in $params[0]['before_widget'].

I think this easier to read as code:

is_admin() || add_filter( 'dynamic_sidebar_params', 'wpse_widget_classes' );

/**
 * Add classes for widgets with counters or dropdowns.
 *
 * @param  array $params
 * @return array
 */
function wpse_widget_classes( $params ) {

    global $wp_registered_widgets;

    $classes     = array();
    $instance_id = $params[1][ 'number' ];
    $widget_id   = $params[ 0 ][ 'widget_id' ];
    $settings    = $wp_registered_widgets[ $widget_id ][ 'callback' ][ 0 ]->get_settings();

    if ( empty ( $settings[ $instance_id ] ) )
        return $params;

    if ( ! empty ( $settings[ $instance_id ][ 'dropdown' ] ) )
        $classes[] = 'widget-with-dropdown';

    if ( ! empty ( $settings[ $instance_id ][ 'count' ] ) )
        $classes[] = 'widget-with-counters';

    if ( empty ( $classes ) )
        return $params;

    $params[0]['before_widget'] = str_replace(
        'class="',
        'class="' . join( ' ', $classes ) . ' ',
        $params[0]['before_widget']
    );

    return $params;
}
0

Or, you can just use a plugin:

Both plugins are doing pretty much the same as @toscho showed in his answer.

Widget CSS Classes plugin

$this_id    = $params[0]['id']; // Get the id for the current sidebar we're processing
$widget_id  = $params[0]['widget_id'];
$widget_obj = $wp_registered_widgets[$widget_id];
$widget_num = $widget_obj['params'][0]['number'];

Source link to v1.2.1

Custom Widget Classes plugin

global $wp_registered_widgets;
$widget_id    = $params[0]['widget_id'];
$widget_obj    = $wp_registered_widgets[$widget_id];
$widget_opt    = get_option($widget_obj['callback'][0]->option_name);
$widget_num    = $widget_obj['params'][0]['number'];

Source link to v1.1

Just to prove that @toscho is right and there seems to be no other option to go on this.

  • 3
    Plugins might go away eventually, and we want to collect solutions, not links. :) – fuxia Jul 31 '13 at 7:59
  • OK - sorry - my bad. – divydovy Jul 31 '13 at 8:18
0

first add a custom placeholder class in the constructor

<?php
public function __construct() {
   $widget_ops  = array(
      'classname'                   =>; 'widget_text eaa __eaa__', //__eaa__ is my placeholder css class
      'description'                 =>; __( 'AdSense ads, arbitrary text, HTML or JS.','eaa' ),
      'customize_selective_refresh' =>; true,
   );
   $control_ops = array( 'width' =>; 400, 'height' =>; 350 );
   parent::__construct( 'eaa', __( 'Easy AdSense Ads &amp; Scripts', 'eaa' ), $widget_ops, $control_ops );
}
?>

Then replace it with the class/es of your choice based on the widget options like this

<?php
if ( $instance['no_padding'] ) {
   $args['before_widget'] = str_replace( '__eaa__', 'eaa-clean', $args['before_widget'] );
}
?>

We are using the place holder to limit the ways in which the html of before_widget may affect our plugin functionality

You can find the details with example at http://satishgandham.com/2017/03/adding-dynamic-classes-custom-wordpress-widgets/

  • I want to catch all widgets with these properties, not only my own. For those, I can just do anything I want. :) – fuxia Mar 12 '17 at 19:55

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.