最近遇到了这种情况,似乎在传统的“widgets.php”界面中,任何javascript初始化都应该直接为现有的小部件运行(在#widgets-right
div),并通过widget-added
新添加小部件的事件;而在customizer“customize.php”界面中,所有小部件(现有的和新的)都会发送widget-added
事件,所以可以在那里初始化。基于此,以下是WP_Widget
类,通过重写一个函数,可以轻松地将javascript初始化添加到小部件的窗体中,form_javascript_init()
:
class WPSE_JS_Widget extends WP_Widget { // For widgets using javascript in form().
var $js_ns = \'wpse\'; // Javscript namespace.
var $js_init_func = \'\'; // Name of javascript init function to call. Initialized in constructor.
var $is_customizer = false; // Whether in customizer or not. Set on \'load-customize.php\' action (if any).
public function __construct( $id_base, $name, $widget_options = array(), $control_options = array(), $js_ns = \'\' ) {
parent::__construct( $id_base, $name, $widget_options, $control_options );
if ( $js_ns ) {
$this->js_ns = $js_ns;
}
$this->js_init_func = $this->js_ns . \'.\' . $this->id_base . \'_init\';
add_action( \'load-widgets.php\', array( $this, \'load_widgets_php\' ) );
add_action( \'load-customize.php\', array( $this, \'load_customize_php\' ) );
}
// Called on \'load-widgets.php\' action added in constructor.
public function load_widgets_php() {
add_action( \'in_widget_form\', array( $this, \'form_maybe_call_javascript_init\' ) );
add_action( \'admin_print_scripts\', array( $this, \'admin_print_scripts\' ), PHP_INT_MAX );
}
// Called on \'load-customize.php\' action added in constructor.
public function load_customize_php() {
$this->is_customizer = true;
// Don\'t add \'in_widget_form\' action as customizer sends \'widget-added\' event to existing widgets too.
add_action( \'admin_print_scripts\', array( $this, \'admin_print_scripts\' ), PHP_INT_MAX );
}
// Form javascript initialization code here. "widget" and "widget_id" available.
public function form_javascript_init() {
}
// Called on \'in_widget_form\' action (ie directly after form()) when in traditional widgets interface.
// Run init directly unless we\'re newly added.
public function form_maybe_call_javascript_init( $callee_this ) {
if ( $this === $callee_this && \'__i__\' !== $this->number ) {
?>
<script type="text/javascript">
jQuery(function ($) {
<?php echo $this->js_init_func; ?>(null, $(\'#widgets-right [id$="<?php echo $this->id; ?>"]\'));
});
</script>
<?php
}
}
// Called on \'admin_print_scripts\' action added in constructor.
public function admin_print_scripts() {
?>
<script type="text/javascript">
var <?php echo $this->js_ns; ?> = <?php echo $this->js_ns; ?> || {}; // Our namespace.
jQuery(function ($) {
<?php echo $this->js_init_func; ?> = function (e, widget) {
var widget_id = widget.attr(\'id\');
if (widget_id.search(/^widget-[0-9]+_<?php echo $this->id_base; ?>-[0-9]+$/) === -1) { // Check it\'s our widget.
return;
}
<?php $this->form_javascript_init(); ?>
};
$(document).on(\'widget-added\', <?php echo $this->js_init_func; ?>); // Call init on widget add.
});
</script>
<?php
}
}
使用以下内容的示例测试小部件:
class WPSE_Test_Widget extends WPSE_JS_Widget {
var $defaults; // Form defaults. Initialized in constructor.
function __construct() {
parent::__construct( \'wpse_test_widget\', __( \'WPSE: Test Widget\' ), array( \'description\' => __( \'Test init of javascript.\' ) ) );
$this->defaults = array(
\'one\' => false,
\'two\' => false,
\'color\' => \'#123456\',
);
add_action( \'admin_enqueue_scripts\', function ( $hook_suffix ) {
if ( ! in_array( $hook_suffix, array( \'widgets.php\', \'customize.php\' ) ) ) return;
wp_enqueue_script( \'wp-color-picker\' ); wp_enqueue_style( \'wp-color-picker\' );
} );
}
function widget( $args, $instance ) {
extract( $args );
extract( wp_parse_args( $instance, $this->defaults ) );
echo $before_widget, \'<p style="color:\', $color, \';">\', $two ? \'Two\' : ( $one ? \'One\' : \'None\' ), \'</p>\', $after_widget;
}
function update( $new_instance, $old_instance ) {
$new_instance[\'one\'] = isset( $new_instance[\'one\'] ) ? 1 : 0;
$new_instance[\'two\'] = isset( $new_instance[\'two\'] ) ? 1 : 0;
return $new_instance;
}
function form( $instance ) {
extract( wp_parse_args( $instance, $this->defaults ) );
?>
<div class="wpse_test">
<p class="one">
<input class="checkbox" type="checkbox" <?php checked( $one ); disabled( $two ); ?> id="<?php echo $this->get_field_id( \'one\' ); ?>" name="<?php echo $this->get_field_name( \'one\' ); ?>" />
<label for="<?php echo $this->get_field_id( \'one\' ); ?>"><?php _e( \'One?\' ); ?></label>
</p>
<p class="two">
<input class="checkbox" type="checkbox" <?php checked( $two ); disabled( $one ); ?> id="<?php echo $this->get_field_id( \'two\' ); ?>" name="<?php echo $this->get_field_name( \'two\' ); ?>" />
<label for="<?php echo $this->get_field_id( \'two\' ); ?>"><?php _e( \'Two?\' ); ?></label>
</p>
<p class="color">
<input type="text" value="<?php echo htmlspecialchars( $color ); ?>" id="<?php echo $this->get_field_id( \'color\' ); ?>" name="<?php echo $this->get_field_name( \'color\' ); ?>" />
</p>
</div>
<?php
}
// Form javascript initialization code here. "widget" and "widget_id" available.
function form_javascript_init() {
?>
$(\'.one input\', widget).change(function (event) { $(\'.two input\', widget).prop(\'disabled\', this.checked); });
$(\'.two input\', widget).change(function (event) { $(\'.one input\', widget).prop(\'disabled\', this.checked); });
$(\'.color input\', widget).wpColorPicker({
<?php if ( $this->is_customizer ) ?> change: _.throttle( function () { $(this).trigger(\'change\'); }, 1000, {leading: false} )
});
<?php
}
}
add_action( \'widgets_init\', function () {
register_widget( \'WPSE_Test_Widget\' );
} );