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="https://wordpress.stackexchange.com/questions/292267/<?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 -->
1 Answer
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.