This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
/* | |
Plugin Name: Test select[multiple] sync behavior in Widget Customizer | |
Description: Demonstration of Core issue #31885 via a widget undo/redo feature. | |
Plugin URI: https://core.trac.wordpress.org/ticket/31885 | |
Author: Weston Ruter, David Lonjon, XWP | |
Author URI: https://xwp.co/ | |
GitHub Plugin URI: https://gist.github.com/westonruter/2e56e08881ae296237ca | |
Copyright 2015 XWP.co Pty Ltd | |
This program is free software; you can redistribute it and/or modify | |
it under the terms of the GNU General Public License as published by | |
the Free Software Foundation; version 2 of the License (GPL v2) only. | |
This program is distributed in the hope that it will be useful, | |
but WITHOUT ANY WARRANTY; without even the implied warranty of | |
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
GNU General Public License for more details. | |
You should have received a copy of the GNU General Public License | |
along with this program; if not, write to the Free Software | |
Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA | |
*/ | |
class Test_Select_Multiple_Widget extends WP_Widget { | |
public $select_options = array( | |
'A' => 1, | |
'B' => 2, | |
'C' => 3, | |
'D' => 4, | |
); | |
/** | |
* Register widget with WordPress. | |
*/ | |
function __construct() { | |
parent::__construct( | |
'test_select_multiple', // Base ID | |
__( 'Test select[multiple]' ) // Name | |
); | |
add_action( 'customize_controls_print_footer_scripts', array( $this, 'print_customize_footer_script' ) ); | |
} | |
/** | |
* @param array $instance | |
* @return array | |
*/ | |
function get_instance( $instance = array() ) { | |
return array_merge( | |
array( | |
'title' => '', | |
'select' => array(), | |
), | |
$instance | |
); | |
} | |
/** | |
* Front-end display of widget. | |
* | |
* @see WP_Widget::widget() | |
* | |
* @param array $args Widget arguments. | |
* @param array $instance Saved values from database. | |
*/ | |
public function widget( $args, $instance ) { | |
$instance = $this->get_instance( $instance ); | |
echo $args['before_widget']; | |
echo $args['before_title']; | |
echo esc_html( apply_filters( 'widget_title', $instance['title'] ) ); | |
echo $args['after_title']; | |
var_dump( $instance['select'] ); | |
echo $args['after_widget']; | |
} | |
/** | |
* Back-end widget form. | |
* | |
* @see WP_Widget::form() | |
* | |
* @param array $instance Previously saved values from database. | |
* @return null | |
*/ | |
public function form( $instance ) { | |
$instance = $this->get_instance( $instance ); | |
printf( '<p><label for="%s">Title:</label> <input type="text" id="%s" name="%s" value="%s"></p>', | |
esc_attr( $this->get_field_id( 'title' ) ), | |
esc_attr( $this->get_field_id( 'title' ) ), | |
esc_attr( $this->get_field_name( 'title' ) ), | |
esc_attr( $instance['title'] ) | |
); | |
printf( '<p><label for="%s">Select:</label><br>', esc_attr( $this->get_field_id( 'select' ) ) ); | |
printf( '<select class="widefat" id="%s" name="%s[]" multiple>', esc_attr( $this->get_field_id( 'select' ) ), esc_attr( $this->get_field_name( 'select' ) ) ); | |
foreach ( $this->select_options as $text => $value ) { | |
printf( | |
'<option %s value="%s">%s</option>', | |
selected( in_array( $value, $instance['select'] ), true, false ), | |
esc_attr( $value ), | |
esc_html( $text ) | |
); | |
} | |
echo '</select>'; | |
echo '</p>'; | |
return null; | |
} | |
/** | |
* Sanitize widget form values as they are saved. | |
* | |
* @see WP_Widget::update() | |
* | |
* @param array $new_instance Values just sent to be saved. | |
* @param array $old_instance Previously saved values from database. | |
* | |
* @return array Updated safe values to be saved. | |
*/ | |
public function update( $new_instance, $old_instance ) { | |
$instance = $this->get_instance( $new_instance ); | |
if ( isset( $new_instance['title'] ) ) { | |
$instance['title'] = sanitize_text_field( $new_instance['title'] ); | |
} | |
if ( isset( $new_instance['select'] ) && is_array( $new_instance['select'] ) ) { | |
$instance['select'] = array_intersect( $new_instance['select'], $this->select_options ); | |
} | |
return $instance; | |
} | |
/** | |
* | |
*/ | |
public function print_customize_footer_script() { | |
wp_print_scripts( array( 'customize-controls', 'customize-widgets', 'wp-util' ) ); | |
?> | |
<style> | |
.widget-history-control-actions a { | |
font-size: 16px; | |
} | |
.widget-history-control-actions a.disabled { | |
color: #DDD; | |
cursor: default; | |
} | |
</style> | |
<script type="text/html" id="tmpl-widget-history-control-actions"> | |
<span class="widget-history-control-actions"> | |
| | |
<a class="widget-control-undo dashicons dashicons-undo disabled" href="#undo" title="<?php esc_attr_e( 'Undo' ) ?>"></a> | |
<a class="widget-control-redo dashicons dashicons-redo disabled" href="#redo" title="<?php esc_attr_e( 'Redo' ) ?>"></a> | |
</span> | |
</script> | |
<script type="text/javascript"> | |
var TestSelectMultipleWidget = (function ( $ ) { | |
var self = {}; | |
self.widgetHistoryControlActionsTpl = wp.template( 'widget-history-control-actions' ); | |
/** | |
* @param {jQuery} widget | |
* @return string | |
*/ | |
self.getWidgetControlId = function ( widget ) { | |
var controlId, idBase, widgetNumber; | |
idBase = widget.find( 'input[name=id_base]' ).val(); | |
widgetNumber = widget.find( 'input[name=widget_number]' ).val(); | |
controlId = 'widget_' + idBase + '[' + widgetNumber + ']'; | |
return controlId; | |
}; | |
self.settingHistories = {}; | |
/** | |
* @param {wp.customize.Control} control | |
* @return {object} | |
*/ | |
self.getSettingHistory = function ( control ) { | |
var settingHistory = self.settingHistories[ control.id ]; | |
if ( ! settingHistory ) { | |
throw new Error( 'No settingHistory for ' + control.id ); | |
} | |
return settingHistory; | |
}; | |
/** | |
* | |
* @param {wp.customize.Control} control | |
*/ | |
self.updateUiState = function ( control ) { | |
var settingHistory = self.getSettingHistory( control ); | |
control.container.find( '.widget-control-undo' ).toggleClass( 'disabled', settingHistory.offset >= settingHistory.stack.length - 1 ); | |
control.container.find( '.widget-control-redo' ).toggleClass( 'disabled', settingHistory.offset <= 0 ); | |
}; | |
/** | |
* | |
* @param {wp.customize.Control} control | |
*/ | |
self.undoSettingChange = function ( control ) { | |
var settingHistory = self.getSettingHistory( control ); | |
if ( settingHistory.offset + 1 < settingHistory.stack.length ) { | |
settingHistory.ignoreChanges = true; | |
settingHistory.offset += 1; | |
control.setting( $.extend( {}, settingHistory.stack[ settingHistory.offset ] ) ); | |
settingHistory.ignoreChanges = false; | |
} | |
self.updateUiState( control ); | |
}; | |
/** | |
* | |
* @param {wp.customize.Control} control | |
*/ | |
self.redoSettingChange = function ( control ) { | |
var settingHistory = self.getSettingHistory( control ); | |
if ( settingHistory.offset > 0 ) { | |
settingHistory.ignoreChanges = true; | |
settingHistory.offset -= 1; | |
control.setting( $.extend( {}, settingHistory.stack[ settingHistory.offset ] ) ); | |
settingHistory.ignoreChanges = false; | |
} | |
self.updateUiState( control ); | |
}; | |
/** | |
* @param {wp.customize.Control} control | |
* @param {array} instance | |
*/ | |
self.onChangeSetting = function ( control, instance ) { | |
var settingHistory = self.getSettingHistory( control ); | |
if ( ! settingHistory.ignoreChanges ) { | |
settingHistory.stack.splice( 0, settingHistory.offset, instance ); | |
settingHistory.offset = 0; | |
self.updateUiState( control ); | |
} | |
}; | |
/** | |
* | |
* @param {wp.customize.Control} control | |
*/ | |
self.addWidgetHistory = function ( control ) { | |
var historyControlActions = $( $.trim( self.widgetHistoryControlActionsTpl() ) ), | |
widgetControlActionsLeft = control.container.find( '.widget-control-actions .alignleft' ); | |
self.settingHistories[ control.id ] = { | |
offset: 0, | |
stack: [ control.setting() ] | |
}; | |
control.setting.bind( function ( to ) { | |
self.onChangeSetting( control, to ); | |
} ); | |
historyControlActions.find( '.widget-control-undo' ).on( 'click', function ( e ) { | |
e.preventDefault(); | |
self.undoSettingChange( control ); | |
} ); | |
historyControlActions.find( '.widget-control-redo' ).on( 'click', function ( e ) { | |
e.preventDefault(); | |
self.redoSettingChange( control ); | |
} ); | |
// Add the undo and redo links | |
widgetControlActionsLeft.append( historyControlActions ); | |
// Remove the redundant Close link | |
widgetControlActionsLeft.find( '.widget-control-close' ).each( function () { | |
if ( this.previousSibling && 3 === this.previousSibling.nodeType ) { | |
// Remove the ' | ' | |
this.previousSibling.parentNode.removeChild( this.previousSibling ); | |
} | |
$( this ).hide(); | |
} ); | |
}; | |
/** | |
* | |
* @param {jQuery.Event} e | |
* @param {jQuery} widget | |
*/ | |
self.onWidgetAdded = function ( e, widget ) { | |
var controlId = self.getWidgetControlId( widget ); | |
wp.customize.control( controlId, function ( control ) { | |
self.addWidgetHistory( control ); | |
} ); | |
}; | |
$( document ).on( 'widget-added', _.bind( self.onWidgetAdded, self ) ); | |
return self; | |
}( jQuery )); | |
</script> | |
<?php | |
} | |
} | |
add_action( 'widgets_init', function () { | |
register_widget( 'Test_Select_Multiple_Widget' ); | |
} ); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment