Color Picker Showing Twice When Widget Added to Sidebar

I’m trying to create a plugin that is basically just a WordPress widget. I’m having great difficulty getting the WordPress color picker to function correctly when my widget is first added to the sidebar. I’ve followed these instructions for integrating the picker. However, this causes two color pickers to show in the sidebar when the widget is first added, only one of which is functional. Once the settings are saved, the second color picker is removed and everything works as expected.

I’ve also tried adding the color picker after the ajaxComplete event fires instead of ready, but that produces the same result – two color pickers.

I then uncovered this WordPress bug that has been marked as being invalid. When I tried the recommended approach of using the sortstop event, I had even worse results – duplicate color pickers, none of which actually functioned.

I’m looking for solutions to this problem as I’ve reached a dead-end and can’t release this plugin with a known bug. Is there perhaps a way to force a save when the widget is first added? Or is there some other way that I haven’t considered in which to address this problem?

Thx!

Update – Here’s the relevant code related to the color picker:

function load_color_picker_style() {
    wp_enqueue_style('wp-color-picker');
}
function load_color_picker_script() {
    wp_enqueue_script('wp-color-picker');
}
add_action('admin_print_scripts-widgets.php', 'load_color_picker_script');
add_action('admin_print_styles-widgets.php', 'load_color_picker_style');

function form( $instance ) {
    $defaults = array(
        'text_color' => '#000',
    );
    $instance = wp_parse_args( (array) $instance, $defaults ); ?>

    <script>
        //This shows two color pickers. So does using ajaxComplete or sortstop.
        jQuery(document).ready(function($) {
            $('.color-picker').wpColorPicker();
        });
    </script>

    <p>
        <label for="<?php echo $this->get_field_id( 'text_color' ); ?>"><?php _e( 'Text Color', 'date-time' ) ?>:</label>
        <input id="<?php echo $this->get_field_id( 'text_color' ); ?>"  name="<?php echo $this->get_field_name( 'text_color' ); ?>" type="text" value="<?php echo esc_attr( $instance[ 'text_color' ] ); ?>" class="color-picker" />
    </p>
<?php
}

Solutions Collecting From Web of "Color Picker Showing Twice When Widget Added to Sidebar"

I added code from this example and it works! (wp 9 still has same issue with color picker)

<script>
( function( $ ){
        function initColorPicker( widget ) {
                widget.find( '.color-picker' ).wpColorPicker( {
                        change: _.throttle( function() { // For Customizer
                                $(this).trigger( 'change' );
                        }, 3000 )
                });
        }
            function onFormUpdate( event, widget ) {
                initColorPicker( widget );
        }
        $( document ).on( 'widget-added widget-updated', onFormUpdate );

        $( document ).ready( function() {
                $( '#widgets-right .widget:has(.color-picker)' ).each( function () {
                        initColorPicker( $( this ) );                                                   
                } );
        } );
}( jQuery ) );

I struggled with this same issue, and found a solution.

The first issue, is that you need to target only the color picker fields that are in the widgets in the sidebars (and also the inactive widgets to make that function properly as well), that is what’s causing the duplicate as it was targeting the class in the available widgets.

$('#widgets-right .color-picker, .inactive-sidebar .color-picker').wpColorPicker();

Second you have to use the ajaxComplete function as this will apply the color picker:

1) When you first add the widget to a sidebar (WP does perform an ajax request when it’s first added).

2) When you click save and it performs that ajax request as well.

This only applies the color picker to newly added widgets and when you save a widget, so if you leave the widgets page and then return again, there is no initial ajax request, so the widgets that you have added will not automatically have the color picker applied.

To handle this you do need to ALSO have the ready function that applies the color picker as well.

You could also put this in a separate js file so it doesn’t get duplicated if you add multiple widgets.

I went a little farther and made it only apply to elements on widget-save and if it’s my widget.

    <script>
        var elems = jQuery('#widgets-right .color-picker, .inactive-sidebar .color-picker');
        var widget_id = 'my-widget-id';
        jQuery(document).ready(function($) {
            elems.wpColorPicker();
        }).ajaxComplete(function(e, xhr, settings) {
            if( settings.data.search('action=save-widget') != -1 && settings.data.search('id_base=' + widget_id) != -1 ) {  
                elems.wpColorPicker();
            }
        });
    </script>

I just wrote this in another post, but it might be useful here too 🙂

Mixing what I had and the solution posted by @skywalker14, I arrived to the following:

jQuery(document).ready(function($) {

    $('#widgets-right .color-picker, .inactive-sidebar .color-picker').wpColorPicker();

    // Executes wpColorPicker function after AJAX is fired on saving the widget
    $(document).ajaxComplete(function() {
        $('#widgets-right .color-picker, .inactive-sidebar .color-picker').wpColorPicker();
    });
});

That did the trick in a much simpler way. I tested it and it seems to be working fine. Hope this can still be helpful to you 🙂

My solution to this problem:

In your custom script add these event listeners:

    $(document).ready(function() {
        $('#widgets-right .color-picker').wpColorPicker();
    });

    $(document).ajaxComplete(function(e, xhr, options) {
        if (xhr.responseText) {
            $('#widgets-right .color-picker').wpColorPicker();
        }
    });

Main points are:

  1. Use ‘#widgets-right .color-picker‘ as a jquery selector instead of just ‘.color-picker’
  2. In ajaxComplete event listener check for xhr.responseText property

The reason why color picker is showing twice is that when widget is added to the appropriate area – 2 ajax requests fire:

  1. Send widget data to be saved. (xhr.responseText = ”)
  2. Send widgets ordering information. (xhr.responseText = ‘1’)