Adding a div to wrap widget content after the widget title

I’m trying to add a div to a widget’s content in my dynamic sidebar.

Here is the register code;

Read More
register_sidebar(array(
        'name' => "Sidebar1",
        'id' => 'home-sidebar-1',
        'before_widget' => '<div class="sidebar-box">',
        'after_widget' => '</div>',
        'before_title' => '<div class="title">',
        'after_title' => '</div>',
    ));

But this code causes like this;

<div class="sidebar-box">
    <div class="title">{WIDGET TITLE}</div>
     {WIDGET CONTENT}
</div>

Here is what I am trying to do;

<div class="sidebar-box">
    <div class="title">{WIDGET TITLE}</div>
    <div class="content">
           {WIDGET CONTENT}
    </div> 
</div>

How it can be done?

Related posts

Leave a Reply

7 comments

  1. In addition to Toscho’s answer here’s what you need for a robust solution:

    // if no title then add widget content wrapper to before widget
    add_filter( 'dynamic_sidebar_params', 'check_sidebar_params' );
    function check_sidebar_params( $params ) {
        global $wp_registered_widgets;
    
        $settings_getter = $wp_registered_widgets[ $params[0]['widget_id'] ]['callback'][0];
        $settings = $settings_getter->get_settings();
        $settings = $settings[ $params[1]['number'] ];
    
        if ( $params[0][ 'after_widget' ] == '</div></div>' && isset( $settings[ 'title' ] ) && empty( $settings[ 'title' ] ) )
            $params[0][ 'before_widget' ] .= '<div class="content">';
    
        return $params;
    }
    

    From Toscho’s answer:

    register_sidebar(array(
        'name' => "Sidebar1",
        'id' => 'home-sidebar-1',
        'before_widget' => '<div class="sidebar-box">',
        'after_widget' => '</div></div>',
        'before_title' => '<div class="title">',
        'after_title' => '</div><div class="content">',
    ));
    

    What this does is:

    • checks the settings for the registered sidebar for widgets ending in 2 closing <div>s
    • checks if there’s no title
    • if not, it modifies the before_widget output to show the opening widget content div

    You could use this approach to change the sidebar arguments in other ways to based on the widget instance’s settings.

  2. I liked the idea of both @tosco and @sanchothefat answers – however I have struggled with that combination because whilst empty( $settings[ 'title' ] might indeed return true the widget itself might output a default title if none is set. This title is then wrapped in the before_title and after_title markup and again the page breaks. That’s the case with some of the default widgets anyway.

    Easier to just stick to standard widget registration parameters;

    register_sidebar(array(
        'id' => 'sidebar1',
        'name' => __( 'Sidebar 1', 'bonestheme' ),
        'description' => __( 'The first (primary) sidebar.', 'bonestheme' ),
        'before_widget' => '<div class="block">',
        'after_widget' => '</div>',
        'before_title' => '<div class="block-title">',
        'after_title' => '</div>',
    ));
    

    and then add a filter action as per Marventus’ answer here;

    http://wordpress.org/support/topic/add-html-wrapper-around-widget-content

    function widget_content_wrap($content) {
        $content = '<div class="block-content">'.$content.'</div>';
        return $content;
    }
    add_filter('widget_text', 'widget_content_wrap');
    
  3. Add the second div to the title parameter:

    register_sidebar(array(
            'name' => "Sidebar1",
            'id' => 'home-sidebar-1',
            'before_widget' => '<div class="sidebar-box">',
            'after_widget' => '</div></div>',
            'before_title' => '<div class="title">',
            'after_title' => '</div><div class="content">',
        ));
    
  4. Here’s what you do to achieve this:

    register_sidebar(array(
            'name' => "Sidebar1",
            'id' => 'home-sidebar-1',
            'before_widget' => '<div class="sidebar-box"><div class="content">',
            'after_widget' => '</div></div>',
            'before_title' => '</div><div class="title">',
            'after_title' => '</div><div class="content">',
        ))
    

    When there is no title you will get:

    <div class="sidebar-box"><div class="content">
    {CONTENT}
    </div></div>
    

    When there is a title you will get:

    <div class="sidebar-box"><div class="content">
    </div><div class="title">
    {TITLE}
    <div class="content">
    {CONTENT}
    </div></div>
    

    To make sure the first empty content-div doesn’t show in the latter case you add this to your css:

    .sidebar-box .content:empty {display:none !important;}
    
  5. After looking at the previous answers, I think I fixed the problem Cmorales identified with sanchothefat’s answer. Define your widget as follows:

    register_sidebar( array(
        'name' => 'Sidebar',
        'id' => 'sidebar',
        'before_widget' => '<div class="panel panel-default %2$s" id="%1$s">',
        'after_widget' => '</div>',
        'before_title' => '',
        'after_title' => ''
    ) );
    

    It’s important that the before_title and after_title defaults are removed. After some trial and error I noted that the first filter that showed a default title was widget_title. Then use the widget_title filter like so:

    function widget_title( $title ) {
        if ( $title )
            $title = '<div class="panel-heading"><h3 class="panel-title">' . $title . '</h3></div>';
        $title .= '<div class="panel-body">';
        return $title;
    }
    

    Basically, <div class="panel-heading"><h3 class="panel-title"> is my before_title and </h3></div> is my after_title. Finally, use dynamic_sidebar_params to prepend a closing div for our content wrap:

    function dynamic_sidebar_params( $params ) {
        $params[0]['after_widget'] = '</div>' . $params[0]['after_widget'];
        return $params;
    }
    

    It isn’t pretty, but it works.

  6. I just slightly change the code so that don’t need to touch register_sidebar. Register a sidebar with regular way:

    register_sidebar(array(
        'name' => "Sidebar1",
        'id' => 'home-sidebar-1',
        'before_widget' => '<div class="sidebar-box">',
        'after_widget' => '</div>',
        'before_title' => '<div class="title">',
        'after_title' => '</div>',
    ));
    

    And below is modified code From Sanchothefat’s Solution:

    /**
     * If no title given then add widget-content wrapper to before_widget
     * If title given then add content wrapper to before_widget
    */
    add_filter('dynamic_sidebar_params', 'check_widget_template');
    function check_widget_template($params){
        global $wp_registered_widgets;
    
        $settings_obj = $wp_registered_widgets[$params[0]['widget_id']]['callback'][0];
        $the_settings = $settings_obj->get_settings();
        $the_settings = $the_settings[$params[1]['number']];
    
        if (isset($params[0]['id']) && $params[0]['id'] == 'home-sidebar-1') {
            if (!isset($the_settings['title']) && empty($the_settings['title'])) {
                $params[0]['before_widget'] .= '<div class="widget-inner">';
                $params[0]['after_widget']  .= '</div>';
            } else {
                $params[0]['after_widget']  .= '</div>';
                $params[0]['after_title']   .= '<div class="widget-inner">';
            }
        }
    
        return $params;
    }
    
  7. As mentioned in the comments, some core widgets add their own title which then gets wrapped twice with the content div. To remove them, you could simply return an empty string. The only downside is that you have to enter all the titles manually.

    function remove_default_widget_title( $title, $instance = [], $id = '' ) {
        if ( isset($instance['title']) && trim($instance['title']) == '' ) {
            return '';
        }
        return $title;
    };
    add_filter( 'widget_title', 'remove_default_widget_title', 10, 3 );
    

    Correct me if I’m missing something here, but I think that’s quite solid.