3

I want to add more classes in the div tag of my search widget. My search is located in the sidebar together with other widgets.

My code:

function NT_widgets_init() {
register_sidebar( array(
    'name'          => __( 'Sidebar', 'side' ),
    'id'            => 'sidebar',
    'description'   => __( 'Rechte Spalte', 'rechts' ),
    'before_widget' => '<div id="%1$s" class="widget %2$s">',
    'after_widget'  => '</div>',
    'before_title'  => '<span class="none">',
    'after_title'   => '</span>',
) );

}
add_action( 'widgets_init', 'NT_widgets_init' );

So each widget gets an id and a class. How can I add more classes to only ONE widget, not the rest.

5
  • I'm not sure this would be possible. Could you help us understand why you want to have more classes on a particular widget? Perhaps there is a different way to target the CSS of that widget, instead of adding classes programmatically.
    – WebElaine
    Feb 28, 2017 at 15:47
  • Hello Fayaz, Im using Bootstrap and want to hide the search an handys. So I must to add .hidden-xs only to the search. Copying only the display:none from the css of Bootstrap is not a solution because of the viewport.
    – Peronia
    Mar 2, 2017 at 6:27
  • @Peronia OK, that makes sense. BTW, did you try Option-2 from my answer?
    – Fayaz
    Mar 2, 2017 at 14:09
  • @Fayaz yes I tried your solution. But this dont worked for me. I think I failed with the adaptation
    – Peronia
    Mar 3, 2017 at 6:21
  • What CODE did you try?
    – Fayaz
    Mar 3, 2017 at 11:30

2 Answers 2

2

You have two possible solutions.

1. The widget_display_callback filter hook

This filter hook parameters allows you to target easily the widget instance and override it's arguments.

A possible approach would be: Inside the filter callback, modify the arguments for that instance, display it and then return false to prevent it from being displayed again the normal way by WordPress. See this code in wp-includes/class-wp-widget.php.

2. Register a new widget that extends the search widget

You can extend the search widget --defined in wp-includes/widgets/class-wp-widget-search.php and override the widget() method to add the class you want, something like this (code should be added in some place seen by WordPress, like a custom plugin or in your theme functions.php file):

/**
 * Custom widget search
 *
 * Extends the default search widget and adds a class to classes in `before_title`
 *
 * @author  Nabil Kadimi
 * @link    http://wordpress.stackexchange.com/a/258292/17187
 */
class WP_Widget_Search_Custom extends WP_Widget_Search {

    public function __construct() {
        $widget_ops = array(
            'classname' => 'widget_search widget_search_custom',
            'description' => __( 'A Custom search form for your site.' ),
            'customize_selective_refresh' => true,
        );
        WP_Widget::__construct( 'search_custom', _x( 'Custom Search', 'Custom Search widget' ), $widget_ops );
    }

    public function widget( $args, $instance ) {

        $custom_class = 'wpse-258279';
        $args['before_widget'] = str_replace('class="', "class=\"$custom_class", $args['before_widget']);

        /** This filter is documented in wp-includes/widgets/class-wp-widget-pages.php */
        $title = apply_filters( 'widget_title', empty( $instance['title'] ) ? '' : $instance['title'], $instance, $this->id_base );
        echo $args['before_widget'];
        if ( $title ) {
            echo $args['before_title'] . $title . $args['after_title'];
        }
        // Use current theme search form if it exists
        get_search_form();
        echo $args['after_widget'];
    }
}

/**
 * Register the custom search widget
 */
add_action( 'widgets_init', function() {
    register_widget( 'WP_Widget_Search_Custom' );
} );
6
  • 1
    @NabilKadimi: I'm curious to know how you'd use the widget_display_callback filter hook in this case. I've tried, but it seems it doesn't filter the $args array.
    – Scott
    Mar 2, 2017 at 14:27
  • 1
    @Scott Inside the filter callback, you can modify the arguments for that instance, display it and then return false to prevent it from being displayed again the normal way by WordPress. See this code github.com/WordPress/WordPress/blob/5f4497/wp-includes/…. Mar 2, 2017 at 15:18
  • @NabilKadimi OK understood. But that's a terrible way of applying filter. I'd rather use the dynamic_sidebar_param filter as @fayaz suggested or implement a custom widget as you've suggested.
    – Scott
    Mar 3, 2017 at 17:45
  • @Scott Can you explain more? Mar 3, 2017 at 18:00
  • 1
    I meant, if i use widget_display_callback that way, I'm not actually filtering $args, rather I'm completely short circuiting the widget and printing the output myself. It's better to have just a custom widget as you've suggested, at least that way I'll have more control over the widget. Or, if I just want to filter $args, I'd rather use dynamic_sidebar_param filter, as I'm printing the widgets using dynamic_sidebar() function.
    – Scott
    Mar 3, 2017 at 18:06
3

Option-1: Using CSS class already provided:

Every widget already provides unique id and class to use in CSS rules. So for most styling needs, it's better to use those to generate specific CSS rule that'll only work for that widget (e.g. Search). For example, the default Search widget will have the CSS class widget_search. You may use it to style the search widget differently from other widgets. Like:

.widget {
    background-color: wheat;
}
.widget.widget_search {
    background-color: gold;
}

Option-2: Using dynamic_sidebar_params filter:

Since you are registering the widgets with register_sidebar() function, most likely you've used it with dynamic_sidebar() function in the templates. In that case, you may use the dynamic_sidebar_params filter hook to insert extra CSS classes only to a specific widget.

Use the following CODE in your theme's functions.php file (additional instructions are there in the CODE):

add_filter( 'dynamic_sidebar_params', 'wpse258279_filter_widget' );
function wpse258279_filter_widget( $params ) {
    // avoiding admin panel
    if( ! is_admin() ) {
        if ( is_array( $params ) && is_array( $params[0] ) && $params[0]['widget_name'] === 'Search' ) {
            // Insert your custom CSS class (one or more) in the following array
            $classes = array( 'custom-css-class-for-search' );

            // The following three lines will add $classes
            // (along with the existing CSS classes) using regular expression
            // don't touch it if you don't know RegEx
            $pattern = '/class\s*=\s*(["\'])(?:\s*((?!\1).*?)\s*)?\1/i';
            $replace = 'class=$1$2 ' . implode( ' ', $classes ) . '$1';
            $params[0]['before_widget'] = preg_replace( $pattern, $replace, $params[0]['before_widget'], 1 );
        }
    }
    return $params;
}

With the above CODE, you may add one or more CSS classes in this line: $classes = array( 'custom-css-class-for-search' );. So if you want to add two CSS classes for the search widget, it'll be like:

$classes = array( 'custom-css-class-for-search', 'another-class' );

Option-3: Custom Widget:

If you need more control than the above methods can handle, then you may implement custom Widget for Search like shown in this answer.

However, it may be difficult to maintain custom widgets if you want the same behaviour for multiple widgets. Because then you'll have to implement that widget too (only for extra CSS class)! If that's not an issue for you, then you may follow that path, as with a custom Widget, you'll have far better control over the markups and functionality.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

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