2014-03-05 21:41:14 +01:00
< ? php
/**
2015-02-25 09:20:26 +01:00
* WordPress Customize Widgets classes
2014-03-26 23:29:15 +01:00
*
* @ package WordPress
* @ subpackage Customize
2014-03-28 15:07:14 +01:00
* @ since 3.9 . 0
2014-03-05 21:41:14 +01:00
*/
2015-02-25 09:20:26 +01:00
/**
* Customize Widgets class .
*
* Implements widget management in the Customizer .
*
* @ since 3.9 . 0
*
* @ see WP_Customize_Manager
*/
2014-03-28 15:07:14 +01:00
final class WP_Customize_Widgets {
2014-04-02 07:45:16 +02:00
2014-03-28 15:07:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* WP_Customize_Manager instance .
*
* @ since 3.9 . 0
2014-03-28 15:07:14 +01:00
* @ access public
* @ var WP_Customize_Manager
*/
public $manager ;
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* All id_bases for widgets defined in core .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access protected
2014-03-05 21:41:14 +01:00
* @ var array
*/
2014-03-28 15:07:14 +01:00
protected $core_widget_id_bases = array (
2014-04-02 08:12:16 +02:00
'archives' , 'calendar' , 'categories' , 'links' , 'meta' ,
'nav_menu' , 'pages' , 'recent-comments' , 'recent-posts' ,
'rss' , 'search' , 'tag_cloud' , 'text' ,
2014-03-05 21:41:14 +01:00
);
2014-03-26 23:29:15 +01:00
/**
* @ since 3.9 . 0
* @ access protected
* @ var array
*/
2015-02-09 00:11:25 +01:00
protected $rendered_sidebars = array ();
2014-03-26 23:29:15 +01:00
/**
* @ since 3.9 . 0
* @ access protected
* @ var array
*/
2015-02-09 00:11:25 +01:00
protected $rendered_widgets = array ();
2014-03-26 23:29:15 +01:00
/**
* @ since 3.9 . 0
* @ access protected
* @ var array
*/
2015-02-09 00:11:25 +01:00
protected $old_sidebars_widgets = array ();
2014-03-26 23:29:15 +01:00
2014-04-15 00:46:16 +02:00
/**
2015-02-09 00:11:25 +01:00
* Mapping of setting type to setting ID pattern .
*
* @ since 4.2 . 0
2014-04-15 00:46:16 +02:00
* @ access protected
* @ var array
*/
2015-02-09 00:11:25 +01:00
protected $setting_id_patterns = array (
'widget_instance' => '/^(widget_.+?)(?:\[(\d+)\])?$/' ,
'sidebar_widgets' => '/^sidebars_widgets\[(.+?)\]$/' ,
);
2014-04-15 00:46:16 +02:00
2014-03-05 21:41:14 +01:00
/**
* Initial loader .
2014-03-26 23:29:15 +01:00
*
* @ since 3.9 . 0
* @ access public
2014-04-02 07:45:16 +02:00
*
* @ param WP_Customize_Manager $manager Customize manager bootstrap instance .
2014-03-05 21:41:14 +01:00
*/
2014-04-06 20:54:14 +02:00
public function __construct ( $manager ) {
2014-03-28 15:07:14 +01:00
$this -> manager = $manager ;
2016-02-22 06:31:27 +01:00
// Skip useless hooks when the user can't manage widgets anyway.
if ( ! current_user_can ( 'edit_theme_options' ) ) {
return ;
}
2015-02-09 00:11:25 +01:00
add_filter ( 'customize_dynamic_setting_args' , array ( $this , 'filter_customize_dynamic_setting_args' ), 10 , 2 );
add_action ( 'after_setup_theme' , array ( $this , 'register_settings' ) );
2014-04-15 00:46:16 +02:00
add_action ( 'wp_loaded' , array ( $this , 'override_sidebars_widgets_for_theme_switch' ) );
2014-03-28 15:07:14 +01:00
add_action ( 'customize_controls_init' , array ( $this , 'customize_controls_init' ) );
add_action ( 'customize_register' , array ( $this , 'schedule_customize_register' ), 1 );
2014-04-02 19:04:14 +02:00
add_action ( 'customize_controls_enqueue_scripts' , array ( $this , 'enqueue_scripts' ) );
add_action ( 'customize_controls_print_styles' , array ( $this , 'print_styles' ) );
add_action ( 'customize_controls_print_scripts' , array ( $this , 'print_scripts' ) );
add_action ( 'customize_controls_print_footer_scripts' , array ( $this , 'print_footer_scripts' ) );
2014-03-28 15:07:14 +01:00
add_action ( 'customize_controls_print_footer_scripts' , array ( $this , 'output_widget_control_templates' ) );
add_action ( 'customize_preview_init' , array ( $this , 'customize_preview_init' ) );
2015-04-06 17:10:27 +02:00
add_filter ( 'customize_refresh_nonces' , array ( $this , 'refresh_nonces' ) );
2014-03-28 15:07:14 +01:00
add_action ( 'dynamic_sidebar' , array ( $this , 'tally_rendered_widgets' ) );
add_filter ( 'is_active_sidebar' , array ( $this , 'tally_sidebars_via_is_active_sidebar_calls' ), 10 , 2 );
add_filter ( 'dynamic_sidebar_has_widgets' , array ( $this , 'tally_sidebars_via_dynamic_sidebar_calls' ), 10 , 2 );
2016-02-19 19:41:28 +01:00
// Selective Refresh.
add_filter ( 'customize_dynamic_partial_args' , array ( $this , 'customize_dynamic_partial_args' ), 10 , 2 );
add_action ( 'customize_preview_init' , array ( $this , 'selective_refresh_init' ) );
2014-03-05 21:41:14 +01:00
}
/**
2015-02-09 00:11:25 +01:00
* Get the widget setting type given a setting ID .
2014-03-26 23:29:15 +01:00
*
2015-02-09 00:11:25 +01:00
* @ since 4.2 . 0
2015-04-05 17:19:28 +02:00
* @ access protected
2014-03-26 23:29:15 +01:00
*
2015-05-29 17:43:29 +02:00
* @ staticvar array $cache
*
2015-04-05 17:19:28 +02:00
* @ param $setting_id Setting ID .
2015-05-24 07:40:25 +02:00
* @ return string | void Setting type .
2014-03-05 21:41:14 +01:00
*/
2015-02-09 00:11:25 +01:00
protected function get_setting_type ( $setting_id ) {
static $cache = array ();
if ( isset ( $cache [ $setting_id ] ) ) {
return $cache [ $setting_id ];
2014-03-05 21:41:14 +01:00
}
2015-02-09 00:11:25 +01:00
foreach ( $this -> setting_id_patterns as $type => $pattern ) {
if ( preg_match ( $pattern , $setting_id ) ) {
$cache [ $setting_id ] = $type ;
return $type ;
}
}
2014-03-05 21:41:14 +01:00
}
/**
2015-02-09 00:11:25 +01:00
* Inspect the incoming customized data for any widget settings , and dynamically add them up - front so widgets will be initialized properly .
2014-03-26 23:29:15 +01:00
*
2015-02-09 00:11:25 +01:00
* @ since 4.2 . 0
2015-04-05 17:36:26 +02:00
* @ access public
2014-03-05 21:41:14 +01:00
*/
2015-02-09 00:11:25 +01:00
public function register_settings () {
$widget_setting_ids = array ();
$incoming_setting_ids = array_keys ( $this -> manager -> unsanitized_post_values () );
foreach ( $incoming_setting_ids as $setting_id ) {
if ( ! is_null ( $this -> get_setting_type ( $setting_id ) ) ) {
$widget_setting_ids [] = $setting_id ;
2014-03-05 21:41:14 +01:00
}
}
2015-02-09 00:11:25 +01:00
if ( $this -> manager -> doing_ajax ( 'update-widget' ) && isset ( $_REQUEST [ 'widget-id' ] ) ) {
$widget_setting_ids [] = $this -> get_setting_id ( wp_unslash ( $_REQUEST [ 'widget-id' ] ) );
}
2014-03-05 21:41:14 +01:00
2015-02-09 00:11:25 +01:00
$settings = $this -> manager -> add_dynamic_settings ( array_unique ( $widget_setting_ids ) );
2014-03-05 21:41:14 +01:00
2015-02-09 00:11:25 +01:00
/*
* Preview settings right away so that widgets and sidebars will get registered properly .
* But don ' t do this if a customize_save because this will cause WP to think there is nothing
* changed that needs to be saved .
*/
if ( ! $this -> manager -> doing_ajax ( 'customize_save' ) ) {
foreach ( $settings as $setting ) {
$setting -> preview ();
2014-03-05 21:41:14 +01:00
}
}
}
/**
2015-02-09 00:11:25 +01:00
* Determine the arguments for a dynamically - created setting .
2014-04-02 07:45:16 +02:00
*
2015-02-09 00:11:25 +01:00
* @ since 4.2 . 0
2015-04-05 17:36:26 +02:00
* @ access public
2014-03-05 21:41:14 +01:00
*
2015-10-24 16:42:26 +02:00
* @ param false | array $args The arguments to the WP_Customize_Setting constructor .
* @ param string $setting_id ID for dynamic setting , usually coming from `$_POST['customized']` .
2015-04-05 17:36:26 +02:00
* @ return false | array Setting arguments , false otherwise .
2014-03-05 21:41:14 +01:00
*/
2015-02-09 00:11:25 +01:00
public function filter_customize_dynamic_setting_args ( $args , $setting_id ) {
if ( $this -> get_setting_type ( $setting_id ) ) {
$args = $this -> get_setting_args ( $setting_id );
2014-03-05 21:41:14 +01:00
}
2015-02-09 00:11:25 +01:00
return $args ;
2014-03-05 21:41:14 +01:00
}
/**
2015-02-09 00:11:25 +01:00
* Get an unslashed post value or return a default .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
*
2015-02-09 00:11:25 +01:00
* @ access protected
2014-03-05 21:41:14 +01:00
*
2015-02-09 00:11:25 +01:00
* @ param string $name Post value .
* @ param mixed $default Default post value .
* @ return mixed Unslashed post value or default value .
2014-03-05 21:41:14 +01:00
*/
2015-02-09 00:11:25 +01:00
protected function get_post_value ( $name , $default = null ) {
if ( ! isset ( $_POST [ $name ] ) ) {
return $default ;
2014-03-05 21:41:14 +01:00
}
2015-02-09 00:11:25 +01:00
return wp_unslash ( $_POST [ $name ] );
2014-03-05 21:41:14 +01:00
}
2014-04-15 00:46:16 +02:00
/**
* Override sidebars_widgets for theme switch .
*
2014-10-15 19:21:19 +02:00
* When switching a theme via the Customizer , supply any previously - configured
2014-04-15 00:46:16 +02:00
* sidebars_widgets from the target theme as the initial sidebars_widgets
* setting . Also store the old theme ' s existing settings so that they can
* be passed along for storing in the sidebars_widgets theme_mod when the
* theme gets switched .
*
* @ since 3.9 . 0
* @ access public
2015-05-22 07:06:25 +02:00
*
* @ global array $sidebars_widgets
* @ global array $_wp_sidebars_widgets
2014-04-15 00:46:16 +02:00
*/
public function override_sidebars_widgets_for_theme_switch () {
global $sidebars_widgets ;
if ( $this -> manager -> doing_ajax () || $this -> manager -> is_theme_active () ) {
return ;
}
$this -> old_sidebars_widgets = wp_get_sidebars_widgets ();
add_filter ( 'customize_value_old_sidebars_widgets_data' , array ( $this , 'filter_customize_value_old_sidebars_widgets_data' ) );
// retrieve_widgets() looks at the global $sidebars_widgets
$sidebars_widgets = $this -> old_sidebars_widgets ;
$sidebars_widgets = retrieve_widgets ( 'customize' );
add_filter ( 'option_sidebars_widgets' , array ( $this , 'filter_option_sidebars_widgets_for_theme_switch' ), 1 );
2015-05-22 07:06:25 +02:00
// reset global cache var used by wp_get_sidebars_widgets()
unset ( $GLOBALS [ '_wp_sidebars_widgets' ] );
2014-04-15 00:46:16 +02:00
}
/**
2014-10-15 19:21:19 +02:00
* Filter old_sidebars_widgets_data Customizer setting .
2014-04-15 00:46:16 +02:00
*
* When switching themes , filter the Customizer setting
* old_sidebars_widgets_data to supply initial $sidebars_widgets before they
* were overridden by retrieve_widgets () . The value for
* old_sidebars_widgets_data gets set in the old theme ' s sidebars_widgets
* theme_mod .
*
* @ see WP_Customize_Widgets :: handle_theme_switch ()
* @ since 3.9 . 0
* @ access public
*
2014-12-01 00:33:23 +01:00
* @ param array $old_sidebars_widgets
2015-05-22 00:05:24 +02:00
* @ return array
2014-04-15 00:46:16 +02:00
*/
public function filter_customize_value_old_sidebars_widgets_data ( $old_sidebars_widgets ) {
return $this -> old_sidebars_widgets ;
}
/**
* Filter sidebars_widgets option for theme switch .
*
* When switching themes , the retrieve_widgets () function is run when the
* Customizer initializes , and then the new sidebars_widgets here get
* supplied as the default value for the sidebars_widgets option .
*
* @ see WP_Customize_Widgets :: handle_theme_switch ()
* @ since 3.9 . 0
* @ access public
*
2015-05-22 07:06:25 +02:00
* @ global array $sidebars_widgets
*
2014-04-15 00:46:16 +02:00
* @ param array $sidebars_widgets
2015-05-22 00:05:24 +02:00
* @ return array
2014-04-15 00:46:16 +02:00
*/
public function filter_option_sidebars_widgets_for_theme_switch ( $sidebars_widgets ) {
$sidebars_widgets = $GLOBALS [ 'sidebars_widgets' ];
$sidebars_widgets [ 'array_version' ] = 3 ;
return $sidebars_widgets ;
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Make sure all widgets get loaded into the Customizer .
*
* Note : these actions are also fired in wp_ajax_update_widget () .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function customize_controls_init () {
2014-04-02 07:45:16 +02:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2014-03-05 21:41:14 +01:00
do_action ( 'load-widgets.php' );
2014-04-02 07:45:16 +02:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2014-03-05 21:41:14 +01:00
do_action ( 'widgets.php' );
2014-03-28 20:47:15 +01:00
/** This action is documented in wp-admin/widgets.php */
2014-03-05 21:41:14 +01:00
do_action ( 'sidebar_admin_setup' );
}
/**
2014-04-02 07:45:16 +02:00
* Ensure widgets are available for all types of previews .
*
* When in preview , hook to 'customize_register' for settings
* after WordPress is loaded so that all filters have been
* initialized ( e . g . Widget Visibility ) .
2014-03-26 23:29:15 +01:00
*
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function schedule_customize_register () {
2015-02-09 00:11:25 +01:00
if ( is_admin () ) {
2014-03-28 15:07:14 +01:00
$this -> customize_register ();
2014-03-05 21:41:14 +01:00
} else {
2014-03-28 15:07:14 +01:00
add_action ( 'wp' , array ( $this , 'customize_register' ) );
2014-03-05 21:41:14 +01:00
}
}
/**
2014-10-15 19:21:19 +02:00
* Register Customizer settings and controls for all sidebars and widgets .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2015-05-22 07:06:25 +02:00
*
* @ global array $wp_registered_widgets
* @ global array $wp_registered_widget_controls
* @ global array $wp_registered_sidebars
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function customize_register () {
2014-03-14 21:01:14 +01:00
global $wp_registered_widgets , $wp_registered_widget_controls , $wp_registered_sidebars ;
2014-03-05 21:41:14 +01:00
$sidebars_widgets = array_merge (
array ( 'wp_inactive_widgets' => array () ),
2015-05-22 07:06:25 +02:00
array_fill_keys ( array_keys ( $wp_registered_sidebars ), array () ),
2014-03-05 21:41:14 +01:00
wp_get_sidebars_widgets ()
);
$new_setting_ids = array ();
2014-03-26 23:29:15 +01:00
/*
2014-04-02 07:45:16 +02:00
* Register a setting for all widgets , including those which are active ,
* inactive , and orphaned since a widget may get suppressed from a sidebar
* via a plugin ( like Widget Visibility ) .
2014-03-05 21:41:14 +01:00
*/
foreach ( array_keys ( $wp_registered_widgets ) as $widget_id ) {
2014-03-28 15:07:14 +01:00
$setting_id = $this -> get_setting_id ( $widget_id );
$setting_args = $this -> get_setting_args ( $setting_id );
2015-02-09 00:11:25 +01:00
if ( ! $this -> manager -> get_setting ( $setting_id ) ) {
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2014-03-05 21:41:14 +01:00
$new_setting_ids [] = $setting_id ;
}
2014-04-15 00:46:16 +02:00
/*
* Add a setting which will be supplied for the theme ' s sidebars_widgets
2015-12-06 22:23:25 +01:00
* theme_mod when the theme is switched .
2014-04-15 00:46:16 +02:00
*/
if ( ! $this -> manager -> is_theme_active () ) {
$setting_id = 'old_sidebars_widgets_data' ;
$setting_args = $this -> get_setting_args ( $setting_id , array (
'type' => 'global_variable' ,
2015-03-10 23:39:28 +01:00
'dirty' => true ,
2014-04-15 00:46:16 +02:00
) );
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2014-06-26 22:17:15 +02:00
$this -> manager -> add_panel ( 'widgets' , array (
2015-10-17 01:48:25 +02:00
'type' => 'widgets' ,
'title' => __ ( 'Widgets' ),
'description' => __ ( 'Widgets are independent sections of content that can be placed into widgetized areas provided by your theme (commonly called sidebars).' ),
'priority' => 110 ,
'active_callback' => array ( $this , 'is_panel_active' ),
2014-06-26 22:17:15 +02:00
) );
2014-03-05 21:41:14 +01:00
foreach ( $sidebars_widgets as $sidebar_id => $sidebar_widget_ids ) {
if ( empty ( $sidebar_widget_ids ) ) {
$sidebar_widget_ids = array ();
}
2014-04-02 08:12:16 +02:00
2015-10-13 03:33:25 +02:00
$is_registered_sidebar = is_registered_sidebar ( $sidebar_id );
2014-03-05 21:41:14 +01:00
$is_inactive_widgets = ( 'wp_inactive_widgets' === $sidebar_id );
$is_active_sidebar = ( $is_registered_sidebar && ! $is_inactive_widgets );
2014-04-02 07:45:16 +02:00
// Add setting for managing the sidebar's widgets.
2014-03-05 21:41:14 +01:00
if ( $is_registered_sidebar || $is_inactive_widgets ) {
$setting_id = sprintf ( 'sidebars_widgets[%s]' , $sidebar_id );
2014-03-28 15:07:14 +01:00
$setting_args = $this -> get_setting_args ( $setting_id );
2015-02-09 00:11:25 +01:00
if ( ! $this -> manager -> get_setting ( $setting_id ) ) {
2015-03-10 23:39:28 +01:00
if ( ! $this -> manager -> is_theme_active () ) {
$setting_args [ 'dirty' ] = true ;
}
2015-02-09 00:11:25 +01:00
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2014-03-05 21:41:14 +01:00
$new_setting_ids [] = $setting_id ;
2014-04-02 07:45:16 +02:00
// Add section to contain controls.
2014-03-05 21:41:14 +01:00
$section_id = sprintf ( 'sidebar-widgets-%s' , $sidebar_id );
if ( $is_active_sidebar ) {
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
$section_args = array (
2015-05-22 07:06:25 +02:00
'title' => $wp_registered_sidebars [ $sidebar_id ][ 'name' ],
'description' => $wp_registered_sidebars [ $sidebar_id ][ 'description' ],
2014-06-26 22:17:15 +02:00
'priority' => array_search ( $sidebar_id , array_keys ( $wp_registered_sidebars ) ),
'panel' => 'widgets' ,
2014-11-13 13:19:23 +01:00
'sidebar_id' => $sidebar_id ,
2014-03-05 21:41:14 +01:00
);
2014-04-14 20:41:17 +02:00
/**
* Filter Customizer widget section arguments for a given sidebar .
*
* @ since 3.9 . 0
*
* @ param array $section_args Array of Customizer widget section arguments .
* @ param string $section_id Customizer section ID .
* @ param int | string $sidebar_id Sidebar ID .
*/
2014-03-05 21:41:14 +01:00
$section_args = apply_filters ( 'customizer_widgets_section_args' , $section_args , $section_id , $sidebar_id );
2014-04-02 08:12:16 +02:00
2014-11-13 13:19:23 +01:00
$section = new WP_Customize_Sidebar_Section ( $this -> manager , $section_id , $section_args );
$this -> manager -> add_section ( $section );
2014-03-05 21:41:14 +01:00
2014-04-02 08:12:16 +02:00
$control = new WP_Widget_Area_Customize_Control ( $this -> manager , $setting_id , array (
'section' => $section_id ,
'sidebar_id' => $sidebar_id ,
'priority' => count ( $sidebar_widget_ids ), // place 'Add Widget' and 'Reorder' buttons at end.
) );
2014-03-05 21:41:14 +01:00
$new_setting_ids [] = $setting_id ;
2014-04-02 08:12:16 +02:00
2014-03-28 15:07:14 +01:00
$this -> manager -> add_control ( $control );
2014-03-05 21:41:14 +01:00
}
}
2014-03-26 23:29:15 +01:00
// Add a control for each active widget (located in a sidebar).
2014-03-05 21:41:14 +01:00
foreach ( $sidebar_widget_ids as $i => $widget_id ) {
2014-03-26 23:29:15 +01:00
// Skip widgets that may have gone away due to a plugin being deactivated.
2015-05-22 07:06:25 +02:00
if ( ! $is_active_sidebar || ! isset ( $wp_registered_widgets [ $widget_id ] ) ) {
2014-03-05 21:41:14 +01:00
continue ;
}
2014-04-02 08:12:16 +02:00
2015-05-22 07:06:25 +02:00
$registered_widget = $wp_registered_widgets [ $widget_id ];
2014-04-02 08:12:16 +02:00
$setting_id = $this -> get_setting_id ( $widget_id );
2015-05-22 07:06:25 +02:00
$id_base = $wp_registered_widget_controls [ $widget_id ][ 'id_base' ];
2014-04-02 08:12:16 +02:00
$control = new WP_Widget_Form_Customize_Control ( $this -> manager , $setting_id , array (
'label' => $registered_widget [ 'name' ],
'section' => $section_id ,
'sidebar_id' => $sidebar_id ,
'widget_id' => $widget_id ,
'widget_id_base' => $id_base ,
'priority' => $i ,
'width' => $wp_registered_widget_controls [ $widget_id ][ 'width' ],
'height' => $wp_registered_widget_controls [ $widget_id ][ 'height' ],
'is_wide' => $this -> is_wide_widget ( $widget_id ),
) );
2014-03-28 15:07:14 +01:00
$this -> manager -> add_control ( $control );
2014-03-05 21:41:14 +01:00
}
}
2015-02-09 00:11:25 +01:00
if ( ! $this -> manager -> doing_ajax ( 'customize_save' ) ) {
2014-03-05 21:41:14 +01:00
foreach ( $new_setting_ids as $new_setting_id ) {
2014-03-28 15:07:14 +01:00
$this -> manager -> get_setting ( $new_setting_id ) -> preview ();
2014-03-05 21:41:14 +01:00
}
}
2015-02-09 00:11:25 +01:00
add_filter ( 'sidebars_widgets' , array ( $this , 'preview_sidebars_widgets' ), 1 );
2014-03-05 21:41:14 +01:00
}
2015-10-17 01:48:25 +02:00
/**
* Return whether the widgets panel is active , based on whether there are sidebars registered .
*
* @ since 4.4 . 0
* @ access public
*
* @ see WP_Customize_Panel :: $active_callback
*
* @ global array $wp_registered_sidebars
* @ return bool Active .
*/
public function is_panel_active () {
global $wp_registered_sidebars ;
return ! empty ( $wp_registered_sidebars );
}
2014-03-05 21:41:14 +01:00
/**
2014-10-15 19:21:19 +02:00
* Covert a widget_id into its corresponding Customizer setting ID ( option name ) .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param string $widget_id Widget ID .
* @ return string Maybe - parsed widget ID .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function get_setting_id ( $widget_id ) {
$parsed_widget_id = $this -> parse_widget_id ( $widget_id );
2014-04-02 08:12:16 +02:00
$setting_id = sprintf ( 'widget_%s' , $parsed_widget_id [ 'id_base' ] );
2014-03-05 21:41:14 +01:00
if ( ! is_null ( $parsed_widget_id [ 'number' ] ) ) {
$setting_id .= sprintf ( '[%d]' , $parsed_widget_id [ 'number' ] );
}
return $setting_id ;
}
/**
2014-04-02 07:45:16 +02:00
* Determine whether the widget is considered " wide " .
*
* Core widgets which may have controls wider than 250 , but can
2014-10-15 19:21:19 +02:00
* still be shown in the narrow Customizer panel . The RSS and Text
2014-04-02 07:45:16 +02:00
* widgets in Core , for example , have widths of 400 and yet they
2014-10-15 19:21:19 +02:00
* still render fine in the Customizer panel . This method will
2014-04-02 07:45:16 +02:00
* return all Core widgets as being not wide , but this can be
* overridden with the is_wide_widget_in_customizer filter .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2015-05-22 07:06:25 +02:00
* @ global $wp_registered_widget_controls
*
2014-03-26 23:29:15 +01:00
* @ param string $widget_id Widget ID .
* @ return bool Whether or not the widget is a " wide " widget .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function is_wide_widget ( $widget_id ) {
2014-03-05 21:41:14 +01:00
global $wp_registered_widget_controls ;
2014-04-02 08:12:16 +02:00
2014-03-28 15:07:14 +01:00
$parsed_widget_id = $this -> parse_widget_id ( $widget_id );
2014-04-02 08:12:16 +02:00
$width = $wp_registered_widget_controls [ $widget_id ][ 'width' ];
$is_core = in_array ( $parsed_widget_id [ 'id_base' ], $this -> core_widget_id_bases );
$is_wide = ( $width > 250 && ! $is_core );
2014-03-26 23:29:15 +01:00
/**
* Filter whether the given widget is considered " wide " .
*
* @ since 3.9 . 0
*
* @ param bool $is_wide Whether the widget is wide , Default false .
* @ param string $widget_id Widget ID .
*/
2014-04-02 07:45:16 +02:00
return apply_filters ( 'is_wide_widget_in_customizer' , $is_wide , $widget_id );
2014-03-05 21:41:14 +01:00
}
/**
2014-03-26 23:29:15 +01:00
* Covert a widget ID into its id_base and number components .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param string $widget_id Widget ID .
* @ return array Array containing a widget ' s id_base and number components .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function parse_widget_id ( $widget_id ) {
2014-03-05 21:41:14 +01:00
$parsed = array (
'number' => null ,
'id_base' => null ,
);
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
if ( preg_match ( '/^(.+)-(\d+)$/' , $widget_id , $matches ) ) {
$parsed [ 'id_base' ] = $matches [ 1 ];
$parsed [ 'number' ] = intval ( $matches [ 2 ] );
} else {
// likely an old single widget
$parsed [ 'id_base' ] = $widget_id ;
}
return $parsed ;
}
/**
2014-03-26 23:29:15 +01:00
* Convert a widget setting ID ( option path ) to its id_base and number components .
*
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ param string $setting_id Widget setting ID .
2014-04-02 07:45:16 +02:00
* @ return WP_Error | array Array containing a widget ' s id_base and number components ,
2014-03-26 23:29:15 +01:00
* or a WP_Error object .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function parse_widget_setting_id ( $setting_id ) {
2014-03-05 21:41:14 +01:00
if ( ! preg_match ( '/^(widget_(.+?))(?:\[(\d+)\])?$/' , $setting_id , $matches ) ) {
2014-03-29 22:44:14 +01:00
return new WP_Error ( 'widget_setting_invalid_id' );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
2014-03-05 21:41:14 +01:00
$id_base = $matches [ 2 ];
$number = isset ( $matches [ 3 ] ) ? intval ( $matches [ 3 ] ) : null ;
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
return compact ( 'id_base' , 'number' );
}
2014-04-02 19:04:14 +02:00
/**
* Call admin_print_styles - widgets . php and admin_print_styles hooks to
* allow custom styles from plugins .
*
* @ since 3.9 . 0
* @ access public
*/
public function print_styles () {
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_styles-widgets.php' );
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_styles' );
}
/**
* Call admin_print_scripts - widgets . php and admin_print_scripts hooks to
* allow custom scripts from plugins .
*
* @ since 3.9 . 0
* @ access public
*/
public function print_scripts () {
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_scripts-widgets.php' );
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_scripts' );
}
2014-03-05 21:41:14 +01:00
/**
2014-10-15 19:21:19 +02:00
* Enqueue scripts and styles for Customizer panel and export data to JavaScript .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2015-05-22 07:06:25 +02:00
*
* @ global WP_Scripts $wp_scripts
* @ global array $wp_registered_sidebars
* @ global array $wp_registered_widgets
2014-03-05 21:41:14 +01:00
*/
2014-04-02 19:04:14 +02:00
public function enqueue_scripts () {
2015-05-22 07:06:25 +02:00
global $wp_scripts , $wp_registered_sidebars , $wp_registered_widgets ;
2014-03-13 20:41:14 +01:00
wp_enqueue_style ( 'customize-widgets' );
wp_enqueue_script ( 'customize-widgets' );
2014-03-05 21:41:14 +01:00
2014-04-02 19:04:14 +02:00
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_enqueue_scripts' , 'widgets.php' );
2014-04-02 07:45:16 +02:00
/*
* Export available widgets with control_tpl removed from model
* since plugins need templates to be in the DOM .
*/
2014-03-05 21:41:14 +01:00
$available_widgets = array ();
2014-04-02 08:12:16 +02:00
2014-03-28 15:07:14 +01:00
foreach ( $this -> get_available_widgets () as $available_widget ) {
2014-03-05 21:41:14 +01:00
unset ( $available_widget [ 'control_tpl' ] );
$available_widgets [] = $available_widget ;
}
$widget_reorder_nav_tpl = sprintf (
2014-03-19 09:18:14 +01:00
'<div class="widget-reorder-nav"><span class="move-widget" tabindex="0">%1$s</span><span class="move-widget-down" tabindex="0">%2$s</span><span class="move-widget-up" tabindex="0">%3$s</span></div>' ,
__ ( 'Move to another area…' ),
__ ( 'Move down' ),
__ ( 'Move up' )
2014-03-05 21:41:14 +01:00
);
$move_widget_area_tpl = str_replace (
array ( '{description}' , '{btn}' ),
array (
2014-04-07 11:04:14 +02:00
__ ( 'Select an area to move this widget into:' ),
_x ( 'Move' , 'Move widget' ),
2014-03-05 21:41:14 +01:00
),
2014-04-06 22:40:15 +02:00
' < div class = " move-widget-area " >
< p class = " description " > { description } </ p >
< ul class = " widget-area-select " >
<% _ . each ( sidebars , function ( sidebar ){ %>
< li class = " " data - id = " <%- sidebar.id %> " title = " <%- sidebar.description %> " tabindex = " 0 " ><%- sidebar . name %></ li >
<% }); %>
</ ul >
< div class = " move-widget-actions " >
< button class = " move-widget-btn button-secondary " type = " button " > { btn } </ button >
2014-03-05 21:41:14 +01:00
</ div >
2014-04-06 22:40:15 +02:00
</ div > '
2014-03-05 21:41:14 +01:00
);
2014-04-07 11:04:14 +02:00
$settings = array (
2015-05-22 07:06:25 +02:00
'registeredSidebars' => array_values ( $wp_registered_sidebars ),
'registeredWidgets' => $wp_registered_widgets ,
2014-04-07 11:04:14 +02:00
'availableWidgets' => $available_widgets , // @todo Merge this with registered_widgets
'l10n' => array (
'saveBtnLabel' => __ ( 'Apply' ),
'saveBtnTooltip' => __ ( 'Save and preview changes before publishing them.' ),
'removeBtnLabel' => __ ( 'Remove' ),
'removeBtnTooltip' => __ ( 'Trash widget by moving it to the inactive widgets sidebar.' ),
'error' => __ ( 'An error has occurred. Please reload the page and try again.' ),
2014-12-07 01:45:24 +01:00
'widgetMovedUp' => __ ( 'Widget moved up' ),
'widgetMovedDown' => __ ( 'Widget moved down' ),
2015-10-17 01:48:25 +02:00
'noAreasRendered' => __ ( 'There are no widget areas currently rendered in the preview. Navigate in the preview to a template that makes use of a widget area in order to access its widgets here.' ),
2015-10-20 22:15:26 +02:00
'reorderModeOn' => __ ( 'Reorder mode enabled' ),
'reorderModeOff' => __ ( 'Reorder mode closed' ),
'reorderLabelOn' => esc_attr__ ( 'Reorder widgets' ),
'reorderLabelOff' => esc_attr__ ( 'Close reorder mode' ),
2014-03-05 21:41:14 +01:00
),
2014-04-07 11:04:14 +02:00
'tpl' => array (
'widgetReorderNav' => $widget_reorder_nav_tpl ,
'moveWidgetArea' => $move_widget_area_tpl ,
2014-03-05 21:41:14 +01:00
),
2016-02-19 19:41:28 +01:00
'selectiveRefresh' => isset ( $this -> manager -> selective_refresh ),
2014-03-05 21:41:14 +01:00
);
2014-04-02 08:12:16 +02:00
2014-04-07 11:04:14 +02:00
foreach ( $settings [ 'registeredWidgets' ] as & $registered_widget ) {
2014-03-05 21:41:14 +01:00
unset ( $registered_widget [ 'callback' ] ); // may not be JSON-serializeable
}
$wp_scripts -> add_data (
2014-03-13 20:41:14 +01:00
'customize-widgets' ,
2014-03-05 21:41:14 +01:00
'data' ,
2014-10-28 19:35:19 +01:00
sprintf ( 'var _wpCustomizeWidgetsSettings = %s;' , wp_json_encode ( $settings ) )
2014-03-05 21:41:14 +01:00
);
}
/**
2014-04-02 07:45:16 +02:00
* Render the widget form control templates into the DOM .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function output_widget_control_templates () {
2014-03-05 21:41:14 +01:00
?>
< div id = " widgets-left " ><!-- compatibility with JS which looks for widget templates here -->
< div id = " available-widgets " >
2015-05-29 15:57:26 +02:00
< div class = " customize-section-title " >
< button class = " customize-section-back " tabindex = " -1 " >
< span class = " screen-reader-text " >< ? php _e ( 'Back' ); ?> </span>
</ button >
< h3 >
< span class = " customize-action " >< ? php
/* translators: ▸ is the unicode right-pointing triangle, and %s is the section title in the Customizer */
echo sprintf ( __ ( 'Customizing ▸ %s' ), esc_html ( $this -> manager -> get_panel ( 'widgets' ) -> title ) );
?> </span>
< ? php _e ( 'Add a Widget' ); ?>
</ h3 >
</ div >
2014-03-05 21:41:14 +01:00
< div id = " available-widgets-filter " >
2014-04-07 11:04:14 +02:00
< label class = " screen-reader-text " for = " widgets-search " >< ? php _e ( 'Search Widgets' ); ?> </label>
< input type = " search " id = " widgets-search " placeholder = " <?php esc_attr_e( 'Search widgets…' ) ?> " />
2014-03-05 21:41:14 +01:00
</ div >
2015-04-21 16:15:26 +02:00
< div id = " available-widgets-list " >
2014-03-28 15:07:14 +01:00
< ? php foreach ( $this -> get_available_widgets () as $available_widget ) : ?>
2014-03-05 21:41:14 +01:00
< div id = " widget-tpl-<?php echo esc_attr( $available_widget['id'] ) ?> " data - widget - id = " <?php echo esc_attr( $available_widget['id'] ) ?> " class = " widget-tpl <?php echo esc_attr( $available_widget['id'] ) ?> " tabindex = " 0 " >
2014-04-07 11:04:14 +02:00
< ? php echo $available_widget [ 'control_tpl' ]; ?>
2014-03-05 21:41:14 +01:00
</ div >
< ? php endforeach ; ?>
2015-04-21 16:15:26 +02:00
</ div ><!-- #available-widgets-list -->
2014-03-05 21:41:14 +01:00
</ div ><!-- #available-widgets -->
</ div ><!-- #widgets-left -->
< ? php
}
2014-04-02 19:04:14 +02:00
/**
* Call admin_print_footer_scripts and admin_print_scripts hooks to
* allow custom scripts from plugins .
*
* @ since 3.9 . 0
* @ access public
*/
public function print_footer_scripts () {
/** This action is documented in wp-admin/admin-footer.php */
do_action ( 'admin_print_footer_scripts' );
/** This action is documented in wp-admin/admin-footer.php */
do_action ( 'admin_footer-widgets.php' );
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Get common arguments to supply when constructing a Customizer setting .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param string $id Widget setting ID .
* @ param array $overrides Array of setting overrides .
* @ return array Possibly modified setting arguments .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function get_setting_args ( $id , $overrides = array () ) {
2014-03-05 21:41:14 +01:00
$args = array (
2014-04-02 08:12:16 +02:00
'type' => 'option' ,
2014-03-05 21:41:14 +01:00
'capability' => 'edit_theme_options' ,
2016-02-19 19:41:28 +01:00
'transport' => isset ( $this -> manager -> selective_refresh ) ? 'postMessage' : 'refresh' ,
2014-04-02 08:12:16 +02:00
'default' => array (),
2014-03-05 21:41:14 +01:00
);
2015-02-09 00:11:25 +01:00
if ( preg_match ( $this -> setting_id_patterns [ 'sidebar_widgets' ], $id , $matches ) ) {
$args [ 'sanitize_callback' ] = array ( $this , 'sanitize_sidebar_widgets' );
$args [ 'sanitize_js_callback' ] = array ( $this , 'sanitize_sidebar_widgets_js_instance' );
2015-06-20 00:01:25 +02:00
} elseif ( preg_match ( $this -> setting_id_patterns [ 'widget_instance' ], $id , $matches ) ) {
2015-02-09 00:11:25 +01:00
$args [ 'sanitize_callback' ] = array ( $this , 'sanitize_widget_instance' );
$args [ 'sanitize_js_callback' ] = array ( $this , 'sanitize_widget_js_instance' );
}
2014-03-05 21:41:14 +01:00
$args = array_merge ( $args , $overrides );
2014-04-02 07:45:16 +02:00
/**
* Filter the common arguments supplied when constructing a Customizer setting .
*
* @ since 3.9 . 0
*
* @ see WP_Customize_Setting
*
* @ param array $args Array of Customizer setting arguments .
* @ param string $id Widget setting ID .
*/
return apply_filters ( 'widget_customizer_setting_args' , $args , $id );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Make sure that sidebar widget arrays only ever contain widget IDS .
*
* Used as the 'sanitize_callback' for each $sidebars_widgets setting .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param array $widget_ids Array of widget IDs .
* @ return array Array of sanitized widget IDs .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function sanitize_sidebar_widgets ( $widget_ids ) {
2015-02-09 00:11:25 +01:00
$widget_ids = array_map ( 'strval' , ( array ) $widget_ids );
2014-03-05 21:41:14 +01:00
$sanitized_widget_ids = array ();
foreach ( $widget_ids as $widget_id ) {
2015-02-09 00:11:25 +01:00
$sanitized_widget_ids [] = preg_replace ( '/[^a-z0-9_\-]/' , '' , $widget_id );
2014-03-05 21:41:14 +01:00
}
return $sanitized_widget_ids ;
}
/**
2014-03-26 23:29:15 +01:00
* Build up an index of all available widgets for use in Backbone models .
*
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*
2015-05-22 07:06:25 +02:00
* @ global array $wp_registered_widgets
* @ global array $wp_registered_widget_controls
* @ staticvar array $available_widgets
*
2014-03-05 21:41:14 +01:00
* @ see wp_list_widgets ()
2014-04-02 07:45:16 +02:00
*
* @ return array List of available widgets .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function get_available_widgets () {
2014-03-05 21:41:14 +01:00
static $available_widgets = array ();
if ( ! empty ( $available_widgets ) ) {
return $available_widgets ;
}
global $wp_registered_widgets , $wp_registered_widget_controls ;
require_once ABSPATH . '/wp-admin/includes/widgets.php' ; // for next_widget_id_number()
$sort = $wp_registered_widgets ;
2014-03-28 15:07:14 +01:00
usort ( $sort , array ( $this , '_sort_name_callback' ) );
2014-03-05 21:41:14 +01:00
$done = array ();
foreach ( $sort as $widget ) {
if ( in_array ( $widget [ 'callback' ], $done , true ) ) { // We already showed this multi-widget
continue ;
}
$sidebar = is_active_widget ( $widget [ 'callback' ], $widget [ 'id' ], false , false );
$done [] = $widget [ 'callback' ];
if ( ! isset ( $widget [ 'params' ][ 0 ] ) ) {
$widget [ 'params' ][ 0 ] = array ();
}
$available_widget = $widget ;
unset ( $available_widget [ 'callback' ] ); // not serializable to JSON
$args = array (
2014-04-02 08:12:16 +02:00
'widget_id' => $widget [ 'id' ],
2014-03-05 21:41:14 +01:00
'widget_name' => $widget [ 'name' ],
2014-04-02 08:12:16 +02:00
'_display' => 'template' ,
2014-03-05 21:41:14 +01:00
);
$is_disabled = false ;
2014-04-02 08:12:16 +02:00
$is_multi_widget = ( isset ( $wp_registered_widget_controls [ $widget [ 'id' ]][ 'id_base' ] ) && isset ( $widget [ 'params' ][ 0 ][ 'number' ] ) );
2014-03-05 21:41:14 +01:00
if ( $is_multi_widget ) {
2014-04-02 08:12:16 +02:00
$id_base = $wp_registered_widget_controls [ $widget [ 'id' ]][ 'id_base' ];
2014-03-05 21:41:14 +01:00
$args [ '_temp_id' ] = " $id_base -__i__ " ;
$args [ '_multi_num' ] = next_widget_id_number ( $id_base );
$args [ '_add' ] = 'multi' ;
} else {
$args [ '_add' ] = 'single' ;
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
if ( $sidebar && 'wp_inactive_widgets' !== $sidebar ) {
$is_disabled = true ;
}
$id_base = $widget [ 'id' ];
}
$list_widget_controls_args = wp_list_widget_controls_dynamic_sidebar ( array ( 0 => $args , 1 => $widget [ 'params' ][ 0 ] ) );
2014-03-28 15:07:14 +01:00
$control_tpl = $this -> get_widget_control ( $list_widget_controls_args );
2014-03-05 21:41:14 +01:00
2014-04-02 07:45:16 +02:00
// The properties here are mapped to the Backbone Widget model.
2014-04-02 08:12:16 +02:00
$available_widget = array_merge ( $available_widget , array (
'temp_id' => isset ( $args [ '_temp_id' ] ) ? $args [ '_temp_id' ] : null ,
'is_multi' => $is_multi_widget ,
'control_tpl' => $control_tpl ,
'multi_number' => ( $args [ '_add' ] === 'multi' ) ? $args [ '_multi_num' ] : false ,
'is_disabled' => $is_disabled ,
'id_base' => $id_base ,
2016-02-19 19:41:28 +01:00
'transport' => isset ( $this -> manager -> selective_refresh ) ? 'postMessage' : 'refresh' ,
2014-04-02 08:12:16 +02:00
'width' => $wp_registered_widget_controls [ $widget [ 'id' ]][ 'width' ],
'height' => $wp_registered_widget_controls [ $widget [ 'id' ]][ 'height' ],
'is_wide' => $this -> is_wide_widget ( $widget [ 'id' ] ),
) );
2014-03-05 21:41:14 +01:00
$available_widgets [] = $available_widget ;
}
2014-04-07 11:04:14 +02:00
2014-03-05 21:41:14 +01:00
return $available_widgets ;
}
/**
2014-03-26 23:29:15 +01:00
* Naturally order available widgets by name .
*
* @ since 3.9 . 0
2014-03-28 15:07:14 +01:00
* @ access protected
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ param array $widget_a The first widget to compare .
* @ param array $widget_b The second widget to compare .
* @ return int Reorder position for the current widget comparison .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function _sort_name_callback ( $widget_a , $widget_b ) {
2014-03-26 23:29:15 +01:00
return strnatcasecmp ( $widget_a [ 'name' ], $widget_b [ 'name' ] );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Get the widget control markup .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param array $args Widget control arguments .
* @ return string Widget control form HTML markup .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function get_widget_control ( $args ) {
2015-09-25 23:02:27 +02:00
$args [ 0 ][ 'before_form' ] = '<div class="form">' ;
$args [ 0 ][ 'after_form' ] = '</div><!-- .form -->' ;
$args [ 0 ][ 'before_widget_content' ] = '<div class="widget-content">' ;
$args [ 0 ][ 'after_widget_content' ] = '</div><!-- .widget-content -->' ;
2014-03-05 21:41:14 +01:00
ob_start ();
call_user_func_array ( 'wp_widget_control' , $args );
$control_tpl = ob_get_clean ();
2015-09-25 23:02:27 +02:00
return $control_tpl ;
}
2014-04-02 08:12:16 +02:00
2015-09-25 23:02:27 +02:00
/**
* Get the widget control markup parts .
*
* @ since 4.4 . 0
* @ access public
*
* @ param array $args Widget control arguments .
* @ return array {
* @ type string $control Markup for widget control wrapping form .
* @ type string $content The contents of the widget form itself .
* }
*/
public function get_widget_control_parts ( $args ) {
$args [ 0 ][ 'before_widget_content' ] = '<div class="widget-content">' ;
$args [ 0 ][ 'after_widget_content' ] = '</div><!-- .widget-content -->' ;
$control_markup = $this -> get_widget_control ( $args );
$content_start_pos = strpos ( $control_markup , $args [ 0 ][ 'before_widget_content' ] );
$content_end_pos = strrpos ( $control_markup , $args [ 0 ][ 'after_widget_content' ] );
$control = substr ( $control_markup , 0 , $content_start_pos + strlen ( $args [ 0 ][ 'before_widget_content' ] ) );
$control .= substr ( $control_markup , $content_end_pos );
$content = trim ( substr (
$control_markup ,
$content_start_pos + strlen ( $args [ 0 ][ 'before_widget_content' ] ),
$content_end_pos - $content_start_pos - strlen ( $args [ 0 ][ 'before_widget_content' ] )
) );
2014-04-02 08:12:16 +02:00
2015-09-25 23:02:27 +02:00
return compact ( 'control' , 'content' );
2014-03-05 21:41:14 +01:00
}
/**
2014-10-15 19:21:19 +02:00
* Add hooks for the Customizer preview .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function customize_preview_init () {
add_action ( 'wp_enqueue_scripts' , array ( $this , 'customize_preview_enqueue' ) );
2014-04-06 20:54:14 +02:00
add_action ( 'wp_print_styles' , array ( $this , 'print_preview_css' ), 1 );
2014-03-28 15:07:14 +01:00
add_action ( 'wp_footer' , array ( $this , 'export_preview_data' ), 20 );
2014-03-05 21:41:14 +01:00
}
2015-04-06 17:10:27 +02:00
/**
* Refresh nonce for widget updates .
*
* @ since 4.2 . 0
* @ access public
*
* @ param array $nonces Array of nonces .
* @ return array $nonces Array of nonces .
*/
public function refresh_nonces ( $nonces ) {
$nonces [ 'update-widget' ] = wp_create_nonce ( 'update-widget' );
return $nonces ;
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* When previewing , make sure the proper previewing widgets are used .
2014-03-26 23:29:15 +01:00
*
2014-04-02 07:45:16 +02:00
* Because wp_get_sidebars_widgets () gets called early at init
* ( via wp_convert_widget_settings ()) and can set global variable
* $_wp_sidebars_widgets to the value of get_option ( 'sidebars_widgets' )
2014-10-15 19:21:19 +02:00
* before the Customizer preview filter is added , we have to reset
2014-04-02 07:45:16 +02:00
* it after the filter has been added .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param array $sidebars_widgets List of widgets for the current sidebar .
2015-05-22 00:05:24 +02:00
* @ return array
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function preview_sidebars_widgets ( $sidebars_widgets ) {
2014-03-05 21:41:14 +01:00
$sidebars_widgets = get_option ( 'sidebars_widgets' );
2014-04-02 07:45:16 +02:00
2014-03-05 21:41:14 +01:00
unset ( $sidebars_widgets [ 'array_version' ] );
return $sidebars_widgets ;
}
/**
2014-04-02 07:45:16 +02:00
* Enqueue scripts for the Customizer preview .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function customize_preview_enqueue () {
2014-03-18 16:31:16 +01:00
wp_enqueue_script ( 'customize-preview-widgets' );
2014-03-28 15:07:14 +01:00
}
2014-03-05 21:41:14 +01:00
2014-03-18 16:21:15 +01:00
/**
* Insert default style for highlighted widget at early point so theme
* stylesheet can override .
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2014-03-18 16:21:15 +01:00
* @ action wp_print_styles
*/
2014-04-06 20:54:14 +02:00
public function print_preview_css () {
2014-03-18 16:21:15 +01:00
?>
< style >
. widget - customizer - highlighted - widget {
outline : none ;
2014-03-28 14:33:14 +01:00
- webkit - box - shadow : 0 0 2 px rgba ( 30 , 140 , 190 , 0.8 );
box - shadow : 0 0 2 px rgba ( 30 , 140 , 190 , 0.8 );
2014-03-25 12:48:14 +01:00
position : relative ;
z - index : 1 ;
2014-03-18 16:21:15 +01:00
}
</ style >
< ? php
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* At the very end of the page , at the very end of the wp_footer ,
* communicate the sidebars that appeared on the page .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
2015-05-22 07:06:25 +02:00
*
* @ global array $wp_registered_sidebars
* @ global array $wp_registered_widgets
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function export_preview_data () {
2015-05-22 07:06:25 +02:00
global $wp_registered_sidebars , $wp_registered_widgets ;
2014-12-02 01:31:22 +01:00
// Prepare Customizer settings to pass to JavaScript.
2014-03-22 22:04:15 +01:00
$settings = array (
2014-03-28 15:07:14 +01:00
'renderedSidebars' => array_fill_keys ( array_unique ( $this -> rendered_sidebars ), true ),
'renderedWidgets' => array_fill_keys ( array_keys ( $this -> rendered_widgets ), true ),
2015-05-22 07:06:25 +02:00
'registeredSidebars' => array_values ( $wp_registered_sidebars ),
'registeredWidgets' => $wp_registered_widgets ,
2014-03-22 22:04:15 +01:00
'l10n' => array (
2016-02-19 19:41:28 +01:00
'widgetTooltip' => __ ( 'Shift-click to edit this widget.' ),
2014-03-22 22:04:15 +01:00
),
2016-02-19 19:41:28 +01:00
'selectiveRefresh' => isset ( $this -> manager -> selective_refresh ),
2014-03-22 22:04:15 +01:00
);
foreach ( $settings [ 'registeredWidgets' ] as & $registered_widget ) {
unset ( $registered_widget [ 'callback' ] ); // may not be JSON-serializeable
}
2014-03-05 21:41:14 +01:00
?>
2014-03-22 22:04:15 +01:00
< script type = " text/javascript " >
2014-10-28 19:35:19 +01:00
var _wpWidgetCustomizerPreviewSettings = < ? php echo wp_json_encode ( $settings ); ?> ;
2014-03-05 21:41:14 +01:00
</ script >
< ? php
}
/**
2014-04-02 07:45:16 +02:00
* Keep track of the widgets that were rendered .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param array $widget Rendered widget to tally .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function tally_rendered_widgets ( $widget ) {
2014-07-10 01:58:16 +02:00
$this -> rendered_widgets [ $widget [ 'id' ] ] = true ;
}
/**
* Determine if a widget is rendered on the page .
*
* @ since 4.0 . 0
* @ access public
*
2014-07-14 02:42:15 +02:00
* @ param string $widget_id Widget ID to check .
* @ return bool Whether the widget is rendered .
2014-07-10 01:58:16 +02:00
*/
public function is_widget_rendered ( $widget_id ) {
return in_array ( $widget_id , $this -> rendered_widgets );
}
/**
* Determine if a sidebar is rendered on the page .
*
* @ since 4.0 . 0
* @ access public
*
2014-07-14 02:42:15 +02:00
* @ param string $sidebar_id Sidebar ID to check .
* @ return bool Whether the sidebar is rendered .
2014-07-10 01:58:16 +02:00
*/
public function is_sidebar_rendered ( $sidebar_id ) {
return in_array ( $sidebar_id , $this -> rendered_sidebars );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Tally the sidebars rendered via is_active_sidebar () .
*
* Keep track of the times that is_active_sidebar () is called
* in the template , and assume that this means that the sidebar
* would be rendered on the template if there were widgets
* populating it .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2014-07-14 02:42:15 +02:00
* @ param bool $is_active Whether the sidebar is active .
* @ param string $sidebar_id Sidebar ID .
2015-05-22 00:05:24 +02:00
* @ return bool
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function tally_sidebars_via_is_active_sidebar_calls ( $is_active , $sidebar_id ) {
2015-10-13 03:33:25 +02:00
if ( is_registered_sidebar ( $sidebar_id ) ) {
2014-03-28 15:07:14 +01:00
$this -> rendered_sidebars [] = $sidebar_id ;
2014-03-05 21:41:14 +01:00
}
2014-04-02 07:45:16 +02:00
/*
* We may need to force this to true , and also force - true the value
* for 'dynamic_sidebar_has_widgets' if we want to ensure that there
* is an area to drop widgets into , if the sidebar is empty .
*/
2014-03-05 21:41:14 +01:00
return $is_active ;
}
/**
2014-04-02 07:45:16 +02:00
* Tally the sidebars rendered via dynamic_sidebar () .
*
* Keep track of the times that dynamic_sidebar () is called in the template ,
* and assume this means the sidebar would be rendered on the template if
* there were widgets populating it .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param bool $has_widgets Whether the current sidebar has widgets .
* @ param string $sidebar_id Sidebar ID .
2015-05-22 00:05:24 +02:00
* @ return bool
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function tally_sidebars_via_dynamic_sidebar_calls ( $has_widgets , $sidebar_id ) {
2015-10-13 03:33:25 +02:00
if ( is_registered_sidebar ( $sidebar_id ) ) {
2014-03-28 15:07:14 +01:00
$this -> rendered_sidebars [] = $sidebar_id ;
2014-03-05 21:41:14 +01:00
}
2014-04-02 07:45:16 +02:00
2014-03-26 23:29:15 +01:00
/*
2014-04-02 07:45:16 +02:00
* We may need to force this to true , and also force - true the value
* for 'is_active_sidebar' if we want to ensure there is an area to
* drop widgets into , if the sidebar is empty .
2014-03-26 23:29:15 +01:00
*/
2014-03-05 21:41:14 +01:00
return $has_widgets ;
}
/**
2014-08-05 08:50:15 +02:00
* Get MAC for a serialized widget instance string .
2014-03-26 23:29:15 +01:00
*
2014-08-05 08:50:15 +02:00
* Allows values posted back from JS to be rejected if any tampering of the
* data has occurred .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access protected
*
2014-08-05 08:50:15 +02:00
* @ param string $serialized_instance Widget instance .
* @ return string MAC for serialized widget instance .
2014-03-05 21:41:14 +01:00
*/
2014-08-05 08:50:15 +02:00
protected function get_instance_hash_key ( $serialized_instance ) {
return wp_hash ( $serialized_instance );
2014-03-05 21:41:14 +01:00
}
/**
2014-03-26 23:29:15 +01:00
* Sanitize a widget instance .
*
2014-03-05 21:41:14 +01:00
* Unserialize the JS - instance for storing in the options . It ' s important
* that this filter only get applied to an instance once .
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
* @ param array $value Widget instance to sanitize .
2015-05-24 07:40:25 +02:00
* @ return array | void Sanitized widget instance .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function sanitize_widget_instance ( $value ) {
2014-03-05 21:41:14 +01:00
if ( $value === array () ) {
return $value ;
}
2014-04-02 08:12:16 +02:00
if ( empty ( $value [ 'is_widget_customizer_js_value' ] )
|| empty ( $value [ 'instance_hash_key' ] )
|| empty ( $value [ 'encoded_serialized_instance' ] ) )
{
2015-05-22 00:05:24 +02:00
return ;
2014-03-05 21:41:14 +01:00
}
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
$decoded = base64_decode ( $value [ 'encoded_serialized_instance' ], true );
if ( false === $decoded ) {
2015-05-22 00:05:24 +02:00
return ;
2014-03-05 21:41:14 +01:00
}
2014-04-02 08:12:16 +02:00
2015-08-04 06:51:50 +02:00
if ( ! hash_equals ( $this -> get_instance_hash_key ( $decoded ), $value [ 'instance_hash_key' ] ) ) {
2015-05-22 00:05:24 +02:00
return ;
2014-03-05 21:41:14 +01:00
}
2014-08-05 08:50:15 +02:00
$instance = unserialize ( $decoded );
if ( false === $instance ) {
2015-05-22 00:05:24 +02:00
return ;
2014-03-05 21:41:14 +01:00
}
2014-08-05 08:50:15 +02:00
2014-03-05 21:41:14 +01:00
return $instance ;
}
/**
2014-03-26 23:29:15 +01:00
* Convert widget instance into JSON - representable format .
*
* @ since 3.9 . 0
* @ access public
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ param array $value Widget instance to convert to JSON .
* @ return array JSON - converted widget instance .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function sanitize_widget_js_instance ( $value ) {
2014-03-05 21:41:14 +01:00
if ( empty ( $value [ 'is_widget_customizer_js_value' ] ) ) {
$serialized = serialize ( $value );
2014-04-02 08:12:16 +02:00
2014-03-05 21:41:14 +01:00
$value = array (
2014-04-02 08:12:16 +02:00
'encoded_serialized_instance' => base64_encode ( $serialized ),
'title' => empty ( $value [ 'title' ] ) ? '' : $value [ 'title' ],
2014-03-05 21:41:14 +01:00
'is_widget_customizer_js_value' => true ,
2014-08-05 08:50:15 +02:00
'instance_hash_key' => $this -> get_instance_hash_key ( $serialized ),
2014-03-05 21:41:14 +01:00
);
}
return $value ;
}
/**
2014-04-02 07:45:16 +02:00
* Strip out widget IDs for widgets which are no longer registered .
*
* One example where this might happen is when a plugin orphans a widget
* in a sidebar upon deactivation .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2015-05-22 07:06:25 +02:00
* @ global array $wp_registered_widgets
*
2014-03-26 23:29:15 +01:00
* @ param array $widget_ids List of widget IDs .
* @ return array Parsed list of widget IDs .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function sanitize_sidebar_widgets_js_instance ( $widget_ids ) {
2014-03-05 21:41:14 +01:00
global $wp_registered_widgets ;
$widget_ids = array_values ( array_intersect ( $widget_ids , array_keys ( $wp_registered_widgets ) ) );
return $widget_ids ;
}
/**
2014-03-26 23:29:15 +01:00
* Find and invoke the widget update and control callbacks .
*
* Requires that $_POST be populated with the instance data .
2014-03-05 21:41:14 +01:00
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2015-05-22 07:06:25 +02:00
* @ global array $wp_registered_widget_updates
* @ global array $wp_registered_widget_controls
*
2014-03-26 23:29:15 +01:00
* @ param string $widget_id Widget ID .
2014-04-02 07:45:16 +02:00
* @ return WP_Error | array Array containing the updated widget information .
* A WP_Error object , otherwise .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function call_widget_update ( $widget_id ) {
2014-03-05 21:41:14 +01:00
global $wp_registered_widget_updates , $wp_registered_widget_controls ;
2015-07-29 18:03:24 +02:00
$setting_id = $this -> get_setting_id ( $widget_id );
/*
* Make sure that other setting changes have previewed since this widget
* may depend on them ( e . g . Menus being present for Custom Menu widget ) .
*/
if ( ! did_action ( 'customize_preview_init' ) ) {
foreach ( $this -> manager -> settings () as $setting ) {
if ( $setting -> id !== $setting_id ) {
$setting -> preview ();
}
}
}
2014-03-28 15:07:14 +01:00
$this -> start_capturing_option_updates ();
$parsed_id = $this -> parse_widget_id ( $widget_id );
2014-03-22 21:55:18 +01:00
$option_name = 'widget_' . $parsed_id [ 'id_base' ];
2014-03-05 21:41:14 +01:00
2014-03-26 23:29:15 +01:00
/*
2014-03-22 21:55:18 +01:00
* If a previously - sanitized instance is provided , populate the input vars
* with its values so that the widget update callback will read this instance
*/
$added_input_vars = array ();
if ( ! empty ( $_POST [ 'sanitized_widget_setting' ] ) ) {
2014-03-28 15:07:14 +01:00
$sanitized_widget_setting = json_decode ( $this -> get_post_value ( 'sanitized_widget_setting' ), true );
2014-04-08 10:12:15 +02:00
if ( false === $sanitized_widget_setting ) {
2014-03-28 15:07:14 +01:00
$this -> stop_capturing_option_updates ();
2014-03-29 22:44:14 +01:00
return new WP_Error ( 'widget_setting_malformed' );
2014-03-05 21:41:14 +01:00
}
2014-03-28 15:07:14 +01:00
$instance = $this -> sanitize_widget_instance ( $sanitized_widget_setting );
2014-03-22 21:55:18 +01:00
if ( is_null ( $instance ) ) {
2014-03-28 15:07:14 +01:00
$this -> stop_capturing_option_updates ();
2014-03-29 22:44:14 +01:00
return new WP_Error ( 'widget_setting_unsanitized' );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
if ( ! is_null ( $parsed_id [ 'number' ] ) ) {
$value = array ();
$value [ $parsed_id [ 'number' ]] = $instance ;
$key = 'widget-' . $parsed_id [ 'id_base' ];
$_REQUEST [ $key ] = $_POST [ $key ] = wp_slash ( $value );
$added_input_vars [] = $key ;
} else {
foreach ( $instance as $key => $value ) {
$_REQUEST [ $key ] = $_POST [ $key ] = wp_slash ( $value );
$added_input_vars [] = $key ;
}
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
}
2014-03-05 21:41:14 +01:00
2014-03-26 23:29:15 +01:00
// Invoke the widget update callback.
2014-03-22 21:55:18 +01:00
foreach ( ( array ) $wp_registered_widget_updates as $name => $control ) {
if ( $name === $parsed_id [ 'id_base' ] && is_callable ( $control [ 'callback' ] ) ) {
ob_start ();
call_user_func_array ( $control [ 'callback' ], $control [ 'params' ] );
ob_end_clean ();
break ;
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
}
2014-03-05 21:41:14 +01:00
2014-03-22 21:55:18 +01:00
// Clean up any input vars that were manually added
foreach ( $added_input_vars as $key ) {
2015-02-09 00:11:25 +01:00
unset ( $_POST [ $key ] );
unset ( $_REQUEST [ $key ] );
2014-03-22 21:55:18 +01:00
}
2014-03-26 23:29:15 +01:00
// Make sure the expected option was updated.
2014-03-28 15:07:14 +01:00
if ( 0 !== $this -> count_captured_options () ) {
if ( $this -> count_captured_options () > 1 ) {
$this -> stop_capturing_option_updates ();
2014-03-29 22:44:14 +01:00
return new WP_Error ( 'widget_setting_too_many_options' );
2014-03-05 21:41:14 +01:00
}
2014-03-28 15:07:14 +01:00
$updated_option_name = key ( $this -> get_captured_options () );
2014-03-22 21:55:18 +01:00
if ( $updated_option_name !== $option_name ) {
2014-03-28 15:07:14 +01:00
$this -> stop_capturing_option_updates ();
2014-03-29 22:44:14 +01:00
return new WP_Error ( 'widget_setting_unexpected_option' );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
}
2014-03-05 21:41:14 +01:00
2015-02-09 00:11:25 +01:00
// Obtain the widget instance.
$option = $this -> get_captured_option ( $option_name );
if ( null !== $parsed_id [ 'number' ] ) {
$instance = $option [ $parsed_id [ 'number' ] ];
} else {
$instance = $option ;
}
/*
* Override the incoming $_POST [ 'customized' ] for a newly - created widget ' s
* setting with the new $instance so that the preview filter currently
* in place from WP_Customize_Setting :: preview () will use this value
* instead of the default widget instance value ( an empty array ) .
*/
2015-11-21 03:52:27 +01:00
$this -> manager -> set_post_value ( $setting_id , $this -> sanitize_widget_js_instance ( $instance ) );
2015-02-09 00:11:25 +01:00
2014-03-26 23:29:15 +01:00
// Obtain the widget control with the updated instance in place.
2014-03-22 21:55:18 +01:00
ob_start ();
2015-02-09 00:11:25 +01:00
$form = $wp_registered_widget_controls [ $widget_id ];
2014-03-22 21:55:18 +01:00
if ( $form ) {
call_user_func_array ( $form [ 'callback' ], $form [ 'params' ] );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
$form = ob_get_clean ();
2014-03-28 15:07:14 +01:00
$this -> stop_capturing_option_updates ();
2014-04-02 08:12:16 +02:00
2014-03-22 21:55:18 +01:00
return compact ( 'instance' , 'form' );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Update widget settings asynchronously .
*
* Allows the Customizer to update a widget using its form , but return the new
2014-03-05 21:41:14 +01:00
* instance info via Ajax instead of saving it to the options table .
2014-04-02 07:45:16 +02:00
*
2014-03-05 21:41:14 +01:00
* Most code here copied from wp_ajax_save_widget ()
*
2014-03-26 23:29:15 +01:00
* @ since 3.9 . 0
* @ access public
*
2014-04-02 07:45:16 +02:00
* @ see wp_ajax_save_widget ()
*
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
public function wp_ajax_update_widget () {
2014-03-05 21:41:14 +01:00
2014-03-22 21:55:18 +01:00
if ( ! is_user_logged_in () ) {
wp_die ( 0 );
}
2014-03-05 21:41:14 +01:00
2014-03-28 16:35:15 +01:00
check_ajax_referer ( 'update-widget' , 'nonce' );
2014-03-22 21:55:18 +01:00
if ( ! current_user_can ( 'edit_theme_options' ) ) {
wp_die ( - 1 );
}
2014-03-05 21:41:14 +01:00
2015-02-09 00:11:25 +01:00
if ( empty ( $_POST [ 'widget-id' ] ) ) {
wp_send_json_error ( 'missing_widget-id' );
2014-03-22 21:55:18 +01:00
}
2014-03-05 21:41:14 +01:00
2014-04-02 07:45:16 +02:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2014-03-22 21:55:18 +01:00
do_action ( 'load-widgets.php' );
2014-04-02 07:45:16 +02:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2014-03-22 21:55:18 +01:00
do_action ( 'widgets.php' );
2014-03-28 20:47:15 +01:00
/** This action is documented in wp-admin/widgets.php */
2014-03-22 21:55:18 +01:00
do_action ( 'sidebar_admin_setup' );
2014-03-05 21:41:14 +01:00
2014-03-28 15:07:14 +01:00
$widget_id = $this -> get_post_value ( 'widget-id' );
$parsed_id = $this -> parse_widget_id ( $widget_id );
2015-02-09 00:11:25 +01:00
$id_base = $parsed_id [ 'id_base' ];
$is_updating_widget_template = (
isset ( $_POST [ 'widget-' . $id_base ] )
&&
is_array ( $_POST [ 'widget-' . $id_base ] )
&&
preg_match ( '/__i__|%i%/' , key ( $_POST [ 'widget-' . $id_base ] ) )
);
if ( $is_updating_widget_template ) {
wp_send_json_error ( 'template_widget_not_updatable' );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
2014-03-28 15:07:14 +01:00
$updated_widget = $this -> call_widget_update ( $widget_id ); // => {instance,form}
2014-03-22 21:55:18 +01:00
if ( is_wp_error ( $updated_widget ) ) {
2015-05-26 00:09:25 +02:00
wp_send_json_error ( $updated_widget -> get_error_code () );
2014-03-05 21:41:14 +01:00
}
2014-03-22 21:55:18 +01:00
$form = $updated_widget [ 'form' ];
2014-03-28 15:07:14 +01:00
$instance = $this -> sanitize_widget_js_instance ( $updated_widget [ 'instance' ] );
2014-03-22 21:55:18 +01:00
wp_send_json_success ( compact ( 'form' , 'instance' ) );
2014-03-05 21:41:14 +01:00
}
2016-02-19 19:41:28 +01:00
/*
* Selective Refresh Methods
*/
/**
* Filter args for dynamic widget partials .
*
* @ since 4.5 . 0
*
* @ param array | false $partial_args Partial args .
* @ param string $partial_id Partial ID .
* @ return array Partial args
*/
public function customize_dynamic_partial_args ( $partial_args , $partial_id ) {
if ( preg_match ( '/^widget\[.+\]$/' , $partial_id ) ) {
if ( false === $partial_args ) {
$partial_args = array ();
}
$partial_args = array_merge (
$partial_args ,
array (
'type' => 'widget' ,
'render_callback' => array ( $this , 'render_widget_partial' ),
'container_inclusive' => true ,
)
);
}
return $partial_args ;
}
/**
* Add hooks for selective refresh .
*
* @ since 4.5 . 0
* @ access public
*/
public function selective_refresh_init () {
if ( ! isset ( $this -> manager -> selective_refresh ) ) {
return ;
}
add_action ( 'wp_enqueue_scripts' , array ( $this , 'customize_preview_enqueue_deps' ) );
add_filter ( 'dynamic_sidebar_params' , array ( $this , 'filter_dynamic_sidebar_params' ) );
add_filter ( 'wp_kses_allowed_html' , array ( $this , 'filter_wp_kses_allowed_data_attributes' ) );
add_action ( 'dynamic_sidebar_before' , array ( $this , 'start_dynamic_sidebar' ) );
add_action ( 'dynamic_sidebar_after' , array ( $this , 'end_dynamic_sidebar' ) );
}
/**
* Enqueue scripts for the Customizer preview .
*
* @ since 4.5 . 0
* @ access public
*/
public function customize_preview_enqueue_deps () {
if ( isset ( $this -> manager -> selective_refresh ) ) {
$script = wp_scripts () -> registered [ 'customize-preview-widgets' ];
$script -> deps [] = 'customize-selective-refresh' ;
}
wp_enqueue_script ( 'customize-preview-widgets' );
wp_enqueue_style ( 'customize-preview' );
}
/**
* Inject selective refresh data attributes into widget container elements .
*
* @ param array $params {
* Dynamic sidebar params .
*
* @ type array $args Sidebar args .
* @ type array $widget_args Widget args .
* }
* @ see WP_Customize_Nav_Menus_Partial_Refresh :: filter_wp_nav_menu_args ()
*
* @ return array Params .
*/
public function filter_dynamic_sidebar_params ( $params ) {
$sidebar_args = array_merge (
array (
'before_widget' => '' ,
'after_widget' => '' ,
),
$params [ 0 ]
);
// Skip widgets not in a registered sidebar or ones which lack a proper wrapper element to attach the data-* attributes to.
$matches = array ();
$is_valid = (
isset ( $sidebar_args [ 'id' ] )
&&
is_registered_sidebar ( $sidebar_args [ 'id' ] )
&&
( isset ( $this -> current_dynamic_sidebar_id_stack [ 0 ] ) && $this -> current_dynamic_sidebar_id_stack [ 0 ] === $sidebar_args [ 'id' ] )
&&
preg_match ( '#^<(?P<tag_name>\w+)#' , $sidebar_args [ 'before_widget' ], $matches )
);
if ( ! $is_valid ) {
return $params ;
}
$this -> before_widget_tags_seen [ $matches [ 'tag_name' ] ] = true ;
$context = array (
'sidebar_id' => $sidebar_args [ 'id' ],
);
if ( isset ( $this -> context_sidebar_instance_number ) ) {
$context [ 'sidebar_instance_number' ] = $this -> context_sidebar_instance_number ;
} else if ( isset ( $sidebar_args [ 'id' ] ) && isset ( $this -> sidebar_instance_count [ $sidebar_args [ 'id' ] ] ) ) {
$context [ 'sidebar_instance_number' ] = $this -> sidebar_instance_count [ $sidebar_args [ 'id' ] ];
}
$attributes = sprintf ( ' data-customize-partial-id="%s"' , esc_attr ( 'widget[' . $sidebar_args [ 'widget_id' ] . ']' ) );
$attributes .= ' data-customize-partial-type="widget"' ;
$attributes .= sprintf ( ' data-customize-partial-placement-context="%s"' , esc_attr ( wp_json_encode ( $context ) ) );
$attributes .= sprintf ( ' data-customize-widget-id="%s"' , esc_attr ( $sidebar_args [ 'widget_id' ] ) );
$sidebar_args [ 'before_widget' ] = preg_replace ( '#^(<\w+)#' , '$1 ' . $attributes , $sidebar_args [ 'before_widget' ] );
$params [ 0 ] = $sidebar_args ;
return $params ;
}
/**
* List of the tag names seen for before_widget strings .
*
* This is used in the filter_wp_kses_allowed_html filter to ensure that the
* data -* attributes can be whitelisted .
*
* @ since 4.5 . 0
* @ access private
* @ var array
*/
protected $before_widget_tags_seen = array ();
/**
* Ensure that the HTML data -* attributes for selective refresh are allowed by kses .
*
* This is needed in case the $before_widget is run through wp_kses () when printed .
*
* @ since 4.5 . 0
* @ access public
*
* @ param array $allowed_html Allowed HTML .
* @ return array Allowed HTML .
*/
public function filter_wp_kses_allowed_data_attributes ( $allowed_html ) {
foreach ( array_keys ( $this -> before_widget_tags_seen ) as $tag_name ) {
if ( ! isset ( $allowed_html [ $tag_name ] ) ) {
$allowed_html [ $tag_name ] = array ();
}
$allowed_html [ $tag_name ] = array_merge (
$allowed_html [ $tag_name ],
array_fill_keys ( array (
'data-customize-partial-id' ,
'data-customize-partial-type' ,
'data-customize-partial-placement-context' ,
'data-customize-partial-widget-id' ,
'data-customize-partial-options' ,
), true )
);
}
return $allowed_html ;
}
/**
* Keep track of the number of times that dynamic_sidebar () was called for a given sidebar index .
*
* This helps facilitate the uncommon scenario where a single sidebar is rendered multiple times on a template .
*
* @ since 4.5 . 0
* @ access private
* @ var array
*/
protected $sidebar_instance_count = array ();
/**
* The current request ' s sidebar_instance_number context .
*
* @ since 4.5 . 0
* @ access private
* @ var int
*/
protected $context_sidebar_instance_number ;
/**
* Current sidebar ID being rendered .
*
* @ since 4.5 . 0
* @ access private
* @ var array
*/
protected $current_dynamic_sidebar_id_stack = array ();
/**
* Start keeping track of the current sidebar being rendered .
*
* Insert marker before widgets are rendered in a dynamic sidebar .
*
* @ since 4.5 . 0
*
* @ param int | string $index Index , name , or ID of the dynamic sidebar .
*/
public function start_dynamic_sidebar ( $index ) {
array_unshift ( $this -> current_dynamic_sidebar_id_stack , $index );
if ( ! isset ( $this -> sidebar_instance_count [ $index ] ) ) {
$this -> sidebar_instance_count [ $index ] = 0 ;
}
$this -> sidebar_instance_count [ $index ] += 1 ;
if ( ! $this -> manager -> selective_refresh -> is_render_partials_request () ) {
printf ( " \n <!--dynamic_sidebar_before:%s:%d--> \n " , esc_html ( $index ), intval ( $this -> sidebar_instance_count [ $index ] ) );
}
}
/**
* Finish keeping track of the current sidebar being rendered .
*
* Insert marker after widgets are rendered in a dynamic sidebar .
*
* @ since 4.5 . 0
*
* @ param int | string $index Index , name , or ID of the dynamic sidebar .
*/
public function end_dynamic_sidebar ( $index ) {
if ( ! $this -> manager -> selective_refresh -> is_render_partials_request () ) {
printf ( " \n <!--dynamic_sidebar_after:%s:%d--> \n " , esc_html ( $index ), intval ( $this -> sidebar_instance_count [ $index ] ) );
}
}
/**
* Current sidebar being rendered .
*
* @ since 4.5 . 0
* @ access private
* @ var string
*/
protected $rendering_widget_id ;
/**
* Current widget being rendered .
*
* @ since 4.5 . 0
* @ access private
* @ var string
*/
protected $rendering_sidebar_id ;
/**
* Filter sidebars_widgets to ensure the currently - rendered widget is the only widget in the current sidebar .
*
* @ since 4.5 . 0
* @ access private
*
* @ param array $sidebars_widgets Sidebars widgets .
* @ return array Sidebars widgets .
*/
public function filter_sidebars_widgets_for_rendering_widget ( $sidebars_widgets ) {
$sidebars_widgets [ $this -> rendering_sidebar_id ] = array ( $this -> rendering_widget_id );
return $sidebars_widgets ;
}
/**
* Render a specific widget using the supplied sidebar arguments .
*
* @ since 4.5 . 0
* @ access public
*
* @ see dynamic_sidebar ()
*
* @ param WP_Customize_Partial $partial Partial .
* @ param array $context {
* Sidebar args supplied as container context .
*
* @ type string $sidebar_id ID for sidebar for widget to render into .
* @ type int [ $sidebar_instance_number ] Disambiguating instance number .
* }
* @ return string | false
*/
public function render_widget_partial ( $partial , $context ) {
$id_data = $partial -> id_data ();
$widget_id = array_shift ( $id_data [ 'keys' ] );
if ( ! is_array ( $context )
|| empty ( $context [ 'sidebar_id' ] )
|| ! is_registered_sidebar ( $context [ 'sidebar_id' ] )
) {
return false ;
}
$this -> rendering_sidebar_id = $context [ 'sidebar_id' ];
if ( isset ( $context [ 'sidebar_instance_number' ] ) ) {
$this -> context_sidebar_instance_number = intval ( $context [ 'sidebar_instance_number' ] );
}
// Filter sidebars_widgets so that only the queried widget is in the sidebar.
$this -> rendering_widget_id = $widget_id ;
$filter_callback = array ( $this , 'filter_sidebars_widgets_for_rendering_widget' );
add_filter ( 'sidebars_widgets' , $filter_callback , 1000 );
// Render the widget.
ob_start ();
dynamic_sidebar ( $this -> rendering_sidebar_id = $context [ 'sidebar_id' ] );
$container = ob_get_clean ();
// Reset variables for next partial render.
remove_filter ( 'sidebars_widgets' , $filter_callback , 1000 );
$this -> context_sidebar_instance_number = null ;
$this -> rendering_sidebar_id = null ;
$this -> rendering_widget_id = null ;
return $container ;
}
//
// Option Update Capturing
//
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* List of captured widget option updates .
*
* @ since 3.9 . 0
* @ access protected
* @ var array $_captured_options Values updated while option capture is happening .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected $_captured_options = array ();
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Whether option capture is currently happening .
*
* @ since 3.9 . 0
* @ access protected
* @ var bool $_is_current Whether option capture is currently happening or not .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected $_is_capturing_option_updates = false ;
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Determine whether the captured option update should be ignored .
*
* @ since 3.9 . 0
* @ access protected
*
* @ param string $option_name Option name .
2015-06-27 03:03:25 +02:00
* @ return bool Whether the option capture is ignored .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function is_option_capture_ignored ( $option_name ) {
return ( 0 === strpos ( $option_name , '_transient_' ) );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Retrieve captured widget option updates .
*
* @ since 3.9 . 0
* @ access protected
*
* @ return array Array of captured options .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function get_captured_options () {
return $this -> _captured_options ;
2014-03-05 21:41:14 +01:00
}
2015-02-09 00:11:25 +01:00
/**
* Get the option that was captured from being saved .
*
* @ since 4.2 . 0
* @ access protected
*
* @ param string $option_name Option name .
* @ param mixed $default Optional . Default value to return if the option does not exist .
* @ return mixed Value set for the option .
*/
protected function get_captured_option ( $option_name , $default = false ) {
if ( array_key_exists ( $option_name , $this -> _captured_options ) ) {
$value = $this -> _captured_options [ $option_name ];
} else {
$value = $default ;
}
return $value ;
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Get the number of captured widget option updates .
*
* @ since 3.9 . 0
* @ access protected
*
* @ return int Number of updated options .
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function count_captured_options () {
return count ( $this -> _captured_options );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Start keeping track of changes to widget options , caching new values .
*
* @ since 3.9 . 0
* @ access protected
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function start_capturing_option_updates () {
if ( $this -> _is_capturing_option_updates ) {
2014-03-05 21:41:14 +01:00
return ;
}
2014-03-28 15:07:14 +01:00
$this -> _is_capturing_option_updates = true ;
2014-04-02 08:12:16 +02:00
2014-04-02 20:31:15 +02:00
add_filter ( 'pre_update_option' , array ( $this , 'capture_filter_pre_update_option' ), 10 , 3 );
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Pre - filter captured option values before updating .
*
2014-04-02 08:12:16 +02:00
* @ since 3.9 . 0
* @ access public
*
2015-02-09 00:11:25 +01:00
* @ param mixed $new_value The new option value .
* @ param string $option_name Name of the option .
* @ param mixed $old_value The old option value .
* @ return mixed Filtered option value .
2014-03-05 21:41:14 +01:00
*/
2014-04-02 20:31:15 +02:00
public function capture_filter_pre_update_option ( $new_value , $option_name , $old_value ) {
2014-03-28 15:07:14 +01:00
if ( $this -> is_option_capture_ignored ( $option_name ) ) {
2014-03-05 21:41:14 +01:00
return ;
}
2015-02-09 00:11:25 +01:00
if ( ! isset ( $this -> _captured_options [ $option_name ] ) ) {
2014-04-02 20:31:15 +02:00
add_filter ( " pre_option_ { $option_name } " , array ( $this , 'capture_filter_pre_get_option' ) );
2014-03-28 15:07:14 +01:00
}
2015-02-09 00:11:25 +01:00
$this -> _captured_options [ $option_name ] = $new_value ;
2014-03-28 15:07:14 +01:00
return $old_value ;
}
2014-03-05 21:41:14 +01:00
/**
2014-04-02 07:45:16 +02:00
* Pre - filter captured option values before retrieving .
*
2014-04-02 08:12:16 +02:00
* @ since 3.9 . 0
* @ access public
*
2015-02-09 00:11:25 +01:00
* @ param mixed $value Value to return instead of the option value .
* @ return mixed Filtered option value .
2014-03-05 21:41:14 +01:00
*/
2014-04-02 20:31:15 +02:00
public function capture_filter_pre_get_option ( $value ) {
2014-03-28 15:07:14 +01:00
$option_name = preg_replace ( '/^pre_option_/' , '' , current_filter () );
2014-04-02 08:12:16 +02:00
2015-02-09 00:11:25 +01:00
if ( isset ( $this -> _captured_options [ $option_name ] ) ) {
$value = $this -> _captured_options [ $option_name ];
2014-04-14 20:41:17 +02:00
/** This filter is documented in wp-includes/option.php */
2014-03-28 15:07:14 +01:00
$value = apply_filters ( 'option_' . $option_name , $value );
2014-03-05 21:41:14 +01:00
}
2014-03-28 15:07:14 +01:00
return $value ;
2014-03-05 21:41:14 +01:00
}
/**
2014-04-02 07:45:16 +02:00
* Undo any changes to the options since options capture began .
*
* @ since 3.9 . 0
* @ access protected
2014-03-05 21:41:14 +01:00
*/
2014-03-28 15:07:14 +01:00
protected function stop_capturing_option_updates () {
if ( ! $this -> _is_capturing_option_updates ) {
2014-03-05 21:41:14 +01:00
return ;
}
2016-02-19 19:41:28 +01:00
remove_filter ( 'pre_update_option' , array ( $this , 'capture_filter_pre_update_option' ), 10 );
2014-04-02 20:31:15 +02:00
2014-03-28 15:07:14 +01:00
foreach ( array_keys ( $this -> _captured_options ) as $option_name ) {
2014-04-02 20:31:15 +02:00
remove_filter ( " pre_option_ { $option_name } " , array ( $this , 'capture_filter_pre_get_option' ) );
2014-03-05 21:41:14 +01:00
}
2014-03-28 15:07:14 +01:00
$this -> _captured_options = array ();
$this -> _is_capturing_option_updates = false ;
2014-03-05 21:41:14 +01:00
}
2015-02-09 00:11:25 +01:00
/**
* @ since 3.9 . 0
* @ deprecated 4.2 . 0 Deprecated in favor of customize_dynamic_setting_args filter .
*/
public function setup_widget_addition_previews () {
_deprecated_function ( __METHOD__ , '4.2.0' );
}
/**
* @ since 3.9 . 0
* @ deprecated 4.2 . 0 Deprecated in favor of customize_dynamic_setting_args filter .
*/
public function prepreview_added_sidebars_widgets () {
_deprecated_function ( __METHOD__ , '4.2.0' );
}
/**
* @ since 3.9 . 0
* @ deprecated 4.2 . 0 Deprecated in favor of customize_dynamic_setting_args filter .
*/
public function prepreview_added_widget_instance () {
_deprecated_function ( __METHOD__ , '4.2.0' );
}
/**
* @ since 3.9 . 0
* @ deprecated 4.2 . 0 Deprecated in favor of customize_dynamic_setting_args filter .
*/
public function remove_prepreview_filters () {
_deprecated_function ( __METHOD__ , '4.2.0' );
}
2014-03-05 21:41:14 +01:00
}