2

I have a custom made widget that I wrote and I want to display two instances of the same widget in the same widget area. When I drag and drop new widget instance to the widget area inside admin panel and put some new data inside custom fields and save, when I go back to the home page I see both new and old widget with the same content. I think it might be update function problem, but I wrote it following wordpress docs so it looks the same. Here is the code:

functions.php

/**
 * Register new custom wiget
*/

class Sole_Source_Main_Widget extends WP_Widget {
    public function __construct() {
        $widget_options = array(
            'classname' => 'sole_source_main_widget',
            'description' => 'Main content widget'
        );
        parent::__construct('sole_source_main_widget', 'Sole Source Widget', $widget_options);
    }

    //back-end display

    public function update( $new_instance, $old_instance ) {
     $instance = $old_instance;
     $instance['title'] = ( ! empty( $new_instance['title'] ) ) ? strip_tags( $new_instance['title'] ) : '';
     $instance['description'] = ( ! empty( $new_instance['description'] ) ) ? strip_tags( $new_instance['description'] ) : '';
     $instance['image'] = ( ! empty( $new_instance['image'] ) ) ? strip_tags( $new_instance['image'] ) : '';

     return $instance;
}

public function form( $instance ) {
$title = ! empty( $instance['title'] ) ? $instance['title'] : ''; ?>
<?php $description = ! empty( $instance['description'] ) ? $instance['description'] : ''; ?>
<?php $image = ! empty( $instance['image'] ) ? $instance['image'] : ''; ?>
<p>
    <label for="<?php echo $this->get_field_id( 'title' ); ?>">Title:</label>
    <input type="text" id="<?php echo $this->get_field_id( 'title' ); ?>" name="<?php echo $this->get_field_name( 'title' ); ?>" value="<?php echo esc_attr( $title ); ?>" />

    <label for="<?php echo $this->get_field_id( 'description' ); ?>">Description:</label>
    <input type="text" id="<?php echo $this->get_field_id( 'description' ); ?>" name="<?php echo $this->get_field_name( 'description' ); ?>" value="<?php echo esc_attr( $description ); ?>" />

    <label for="<?php echo $this->get_field_id( 'image' ); ?>">Image URL:</label>
    <input type="text" id="<?php echo $this->get_field_id( 'image' ); ?>" name="<?php echo $this->get_field_name( 'image' ); ?>" value="<?php echo esc_attr( $image ); ?>" />
</p><?php
}

    //front-end display
    public function widget( $args, $instance ) {

  $title = apply_filters( 'widget_title', $instance[ 'title' ] );
    $description = apply_filters('widget_title', $instance['description']);
    $image = apply_filters('widget_title', $instance['image']);
    ?>

    <?php echo $args['before_widget'] . $args['before_title']; ?> <img src="<?php echo $image; ?>"></img> <?php $args['after_title']; ?>
  <?php echo $args['before_widget'] . $args['before_title'] . $title . $args['after_title']; ?>
    <?php echo $args['before_widget'] . $args['before_title'] . $description . $args['after_title']; ?>

  <?php echo $args['after_widget'];
    }
}

add_action('widgets_init', function() {
    register_widget('Sole_Source_Main_Widget');
});

sidebar.php

<aside id="secondary" class="widget-area col-sm-12 col-md-12 col-lg-12" role="complementary">
    <div class="col-lg-6 col-md-12">
    <?php dynamic_sidebar( 'main-widget' ); ?>
</div>
    <div class="col-lg-6 col-md-12">
    <?php dynamic_sidebar( 'main-widget' ); ?>
    </div>
</aside><!-- #secondary -->

enter image description here

1 Answer 1

1

I don't see anything wrong with the widget class. The problem you have is that you are displaying the widget area, that contains the widgets, twice in your sidebar.php:

<aside id="secondary" class="widget-area col-sm-12 col-md-12 col-lg-12" role="complementary">
    <div class="col-lg-6 col-md-12">
    <?php dynamic_sidebar( 'main-widget' ); // this will display all the widgets in your main-widget sidebar ?>
</div>
    <div class="col-lg-6 col-md-12">
    <?php dynamic_sidebar( 'main-widget' ); // this will display again all the widgets in your main-widget sidebar ?>
    </div>
</aside><!-- #secondary -->

The second widget in each sidebar display is probably hidden due to some CSS, but I bet it is there, twice, once on the left and one on the right.

So, do not call dynamic_sidebar( 'main-widget' ); twice.

From what I understand you want to wrap the widgets in certain divs so you can put them on two columns. For this you need to filter the before-widget and after-widget params of each widget via the dynamic_sidebar_params filter. Or, better yet you could use some CSS to do the trick.

Here is a starter PHP code that will add wrappers to each widget in your target widget area:

/**
 * @param array $params
 */
function sole_add_widget_columns_wrapper( $params ) {
    // Add the opening wrapper tag
    $params[0]['before_widget'] = PHP_EOL . '<div class="col-lg-6 col-md-12">' . PHP_EOL . $params[0]['before_widget'];

    // Add the closing wrapper tag
    $params[0]['after_widget'] = $params[0]['after_widget'] . PHP_EOL . '</div><!-- close wrapper -->' . PHP_EOL;
}

/**
 * @param string $index
 */
function sole_handle_main_widget_area_columns( $index ) {
    // We only want to deal with the main widget area
    if ( 'main-widget' !== $index ) {
        return;
    }

    // Filter each widget params and add the wrappers
    add_filter( 'dynamic_sidebar_params', 'sole_add_widget_columns_wrapper', 10, 1 );

    // Hook an action to remove the filter above after we are done with this widget area.
    // This way we don't affect other widget area that may come, on the same page, after this one.
    add_action( 'dynamic_sidebar_after', 'sole_remove_main_widget_area_columns_filter', 10 );
}
add_action( 'dynamic_sidebar_before', 'sole_handle_main_widget_area_columns', 10 );

function sole_remove_main_widget_area_columns_filter() {
    remove_filter( 'dynamic_sidebar_params', 'sole_add_widget_columns_wrapper', 10 );
}

This code will wrap each widget, it will not put even and odd widgets into two column wrappers.

2
  • I removed second sidebar call and changed column width to 12 columns. Now it gets displayed full width of the screen in red background. I added a second widget and it works fine but the second widget content gets displayed right under the first widget, not on the right side as I wanted it. Yes that's what I want, left side to be red widget and right side white widget with only some text. Can you explain a little bit more on how to use those filter exactly? I'm not familiar with filters at all. I need to apply it for sidebar register or widget class?
    – Limpuls
    Jan 26, 2018 at 9:14
  • I have updated my answer with the PHP code. I hope it helps, although I believe a CSS solution is more appropriate for your situation.
    – Vlad Olaru
    Jan 26, 2018 at 9:57

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.