2014-03-05 15:41:14 -05:00
< ? php
/**
2015-02-25 03:20:26 -05:00
* WordPress Customize Widgets classes
2014-03-26 18:29:15 -04:00
*
* @ package WordPress
* @ subpackage Customize
2014-03-28 10:07:14 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2015-02-25 03:20:26 -05:00
/**
* Customize Widgets class .
*
* Implements widget management in the Customizer .
*
* @ since 3.9 . 0
*
* @ see WP_Customize_Manager
*/
2014-03-28 10:07:14 -04:00
final class WP_Customize_Widgets {
2014-04-02 01:45:16 -04:00
2014-03-28 10:07:14 -04:00
/**
2014-04-02 01:45:16 -04:00
* WP_Customize_Manager instance .
*
* @ since 3.9 . 0
2014-03-28 10:07:14 -04:00
* @ var WP_Customize_Manager
*/
public $manager ;
2014-03-05 15:41:14 -05:00
/**
2014-04-02 01:45:16 -04:00
* All id_bases for widgets defined in core .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
* @ var array
*/
2014-03-28 10:07:14 -04:00
protected $core_widget_id_bases = array (
2017-07-04 17:01:41 -04:00
'archives' ,
'calendar' ,
'categories' ,
'custom_html' ,
'links' ,
'media_audio' ,
'media_image' ,
'media_video' ,
'meta' ,
'nav_menu' ,
'pages' ,
'recent-comments' ,
'recent-posts' ,
'rss' ,
'search' ,
'tag_cloud' ,
'text' ,
2014-03-05 15:41:14 -05:00
);
2014-03-26 18:29:15 -04:00
/**
* @ since 3.9 . 0
* @ var array
*/
2015-02-08 18:11:25 -05:00
protected $rendered_sidebars = array ();
2014-03-26 18:29:15 -04:00
/**
* @ since 3.9 . 0
* @ var array
*/
2015-02-08 18:11:25 -05:00
protected $rendered_widgets = array ();
2014-03-26 18:29:15 -04:00
/**
* @ since 3.9 . 0
* @ var array
*/
2015-02-08 18:11:25 -05:00
protected $old_sidebars_widgets = array ();
2014-03-26 18:29:15 -04:00
2016-03-21 17:59:29 -04:00
/**
* Mapping of widget ID base to whether it supports selective refresh .
*
* @ since 4.5 . 0
* @ var array
*/
protected $selective_refreshable_widgets ;
2014-04-14 18:46:16 -04:00
/**
2015-02-08 18:11:25 -05:00
* Mapping of setting type to setting ID pattern .
*
* @ since 4.2 . 0
2014-04-14 18:46:16 -04:00
* @ var array
*/
2015-02-08 18:11:25 -05:00
protected $setting_id_patterns = array (
2016-03-21 17:59:29 -04:00
'widget_instance' => '/^widget_(?P<id_base>.+?)(?:\[(?P<widget_number>\d+)\])?$/' ,
'sidebar_widgets' => '/^sidebars_widgets\[(?P<sidebar_id>.+?)\]$/' ,
2015-02-08 18:11:25 -05:00
);
2014-04-14 18:46:16 -04:00
2014-03-05 15:41:14 -05:00
/**
* Initial loader .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-04-02 01:45:16 -04:00
*
* @ param WP_Customize_Manager $manager Customize manager bootstrap instance .
2014-03-05 15:41:14 -05:00
*/
2014-04-06 14:54:14 -04:00
public function __construct ( $manager ) {
2014-03-28 10:07:14 -04:00
$this -> manager = $manager ;
Customize: Implement customized state persistence with changesets.
Includes infrastructure developed in the Customize Snapshots feature plugin.
See https://make.wordpress.org/core/2016/10/12/customize-changesets-technical-design-decisions/
Props westonruter, valendesigns, utkarshpatel, stubgo, lgedeon, ocean90, ryankienstra, mihai2u, dlh, aaroncampbell, jonathanbardo, jorbin.
See #28721.
See #31089.
Fixes #30937.
Fixes #31517.
Fixes #30028.
Fixes #23225.
Fixes #34142.
Fixes #36485.
Built from https://develop.svn.wordpress.org/trunk@38810
git-svn-id: http://core.svn.wordpress.org/trunk@38753 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-10-18 16:05:31 -04:00
// See https://github.com/xwp/wp-customize-snapshots/blob/962586659688a5b1fd9ae93618b7ce2d4e7a421c/php/class-customize-snapshot-manager.php#L420-L449
2017-11-30 18:11:00 -05:00
add_filter ( 'customize_dynamic_setting_args' , array ( $this , 'filter_customize_dynamic_setting_args' ), 10 , 2 );
add_action ( 'widgets_init' , array ( $this , 'register_settings' ), 95 );
add_action ( 'customize_register' , array ( $this , 'schedule_customize_register' ), 1 );
Customize: Implement customized state persistence with changesets.
Includes infrastructure developed in the Customize Snapshots feature plugin.
See https://make.wordpress.org/core/2016/10/12/customize-changesets-technical-design-decisions/
Props westonruter, valendesigns, utkarshpatel, stubgo, lgedeon, ocean90, ryankienstra, mihai2u, dlh, aaroncampbell, jonathanbardo, jorbin.
See #28721.
See #31089.
Fixes #30937.
Fixes #31517.
Fixes #30028.
Fixes #23225.
Fixes #34142.
Fixes #36485.
Built from https://develop.svn.wordpress.org/trunk@38810
git-svn-id: http://core.svn.wordpress.org/trunk@38753 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-10-18 16:05:31 -04:00
// Skip remaining hooks when the user can't manage widgets anyway.
2016-02-22 00:31:27 -05:00
if ( ! current_user_can ( 'edit_theme_options' ) ) {
return ;
}
2017-11-30 18:11:00 -05:00
add_action ( 'wp_loaded' , array ( $this , 'override_sidebars_widgets_for_theme_switch' ) );
add_action ( 'customize_controls_init' , array ( $this , 'customize_controls_init' ) );
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' ) );
2014-04-02 13:04:14 -04:00
add_action ( 'customize_controls_print_footer_scripts' , array ( $this , 'print_footer_scripts' ) );
2014-03-28 10:07:14 -04:00
add_action ( 'customize_controls_print_footer_scripts' , array ( $this , 'output_widget_control_templates' ) );
2017-11-30 18:11:00 -05:00
add_action ( 'customize_preview_init' , array ( $this , 'customize_preview_init' ) );
add_filter ( 'customize_refresh_nonces' , array ( $this , 'refresh_nonces' ) );
2014-03-28 10:07:14 -04:00
2017-11-30 18:11:00 -05: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 13:41:28 -05:00
// Selective Refresh.
2017-11-30 18:11:00 -05:00
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 15:41:14 -05:00
}
2016-03-21 17:59:29 -04:00
/**
* List whether each registered widget can be use selective refresh .
*
* If the theme does not support the customize - selective - refresh - widgets feature ,
* then this will always return an empty array .
*
* @ since 4.5 . 0
*
2017-07-05 04:23:41 -04:00
* @ global WP_Widget_Factory $wp_widget_factory
*
2016-03-21 17:59:29 -04:00
* @ return array Mapping of id_base to support . If theme doesn ' t support
* selective refresh , an empty array is returned .
*/
public function get_selective_refreshable_widgets () {
global $wp_widget_factory ;
if ( ! current_theme_supports ( 'customize-selective-refresh-widgets' ) ) {
return array ();
}
if ( ! isset ( $this -> selective_refreshable_widgets ) ) {
$this -> selective_refreshable_widgets = array ();
foreach ( $wp_widget_factory -> widgets as $wp_widget ) {
$this -> selective_refreshable_widgets [ $wp_widget -> id_base ] = ! empty ( $wp_widget -> widget_options [ 'customize_selective_refresh' ] );
}
}
return $this -> selective_refreshable_widgets ;
}
/**
* Determines if a widget supports selective refresh .
*
* @ since 4.5 . 0
*
* @ param string $id_base Widget ID Base .
* @ return bool Whether the widget can be selective refreshed .
*/
public function is_widget_selective_refreshable ( $id_base ) {
$selective_refreshable_widgets = $this -> get_selective_refreshable_widgets ();
return ! empty ( $selective_refreshable_widgets [ $id_base ] );
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Retrieves the widget setting type given a setting ID .
2014-03-26 18:29:15 -04:00
*
2015-02-08 18:11:25 -05:00
* @ since 4.2 . 0
2014-03-26 18:29:15 -04:00
*
2015-05-29 11:43:29 -04:00
* @ staticvar array $cache
*
2016-03-21 17:59:29 -04:00
* @ param string $setting_id Setting ID .
2015-05-24 01:40:25 -04:00
* @ return string | void Setting type .
2014-03-05 15:41:14 -05:00
*/
2015-02-08 18:11:25 -05:00
protected function get_setting_type ( $setting_id ) {
static $cache = array ();
if ( isset ( $cache [ $setting_id ] ) ) {
return $cache [ $setting_id ];
2014-03-05 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
foreach ( $this -> setting_id_patterns as $type => $pattern ) {
if ( preg_match ( $pattern , $setting_id ) ) {
$cache [ $setting_id ] = $type ;
return $type ;
}
}
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Inspects the incoming customized data for any widget settings , and dynamically adds
* them up - front so widgets will be initialized properly .
2014-03-26 18:29:15 -04:00
*
2015-02-08 18:11:25 -05:00
* @ since 4.2 . 0
2014-03-05 15:41:14 -05:00
*/
2015-02-08 18:11:25 -05:00
public function register_settings () {
2017-11-30 18:11:00 -05:00
$widget_setting_ids = array ();
2015-02-08 18:11:25 -05:00
$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 15:41:14 -05:00
}
}
2015-02-08 18:11:25 -05: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 15:41:14 -05:00
2015-02-08 18:11:25 -05:00
$settings = $this -> manager -> add_dynamic_settings ( array_unique ( $widget_setting_ids ) );
2014-03-05 15:41:14 -05:00
2017-08-02 01:35:41 -04:00
if ( $this -> manager -> settings_previewed () ) {
2015-02-08 18:11:25 -05:00
foreach ( $settings as $setting ) {
$setting -> preview ();
2014-03-05 15:41:14 -05:00
}
}
}
/**
2016-03-03 21:02:26 -05:00
* Determines the arguments for a dynamically - created setting .
2014-04-02 01:45:16 -04:00
*
2015-02-08 18:11:25 -05:00
* @ since 4.2 . 0
2014-03-05 15:41:14 -05:00
*
2015-10-24 10:42:26 -04: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 11:36:26 -04:00
* @ return false | array Setting arguments , false otherwise .
2014-03-05 15:41:14 -05:00
*/
2015-02-08 18:11:25 -05: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 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
return $args ;
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Retrieves an unslashed post value or return a default .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*
2015-02-08 18:11:25 -05:00
* @ param string $name Post value .
* @ param mixed $default Default post value .
* @ return mixed Unslashed post value or default value .
2014-03-05 15:41:14 -05:00
*/
2015-02-08 18:11:25 -05:00
protected function get_post_value ( $name , $default = null ) {
if ( ! isset ( $_POST [ $name ] ) ) {
return $default ;
2014-03-05 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
return wp_unslash ( $_POST [ $name ] );
2014-03-05 15:41:14 -05:00
}
2014-04-14 18:46:16 -04:00
/**
* Override sidebars_widgets for theme switch .
*
2014-10-15 13:21:19 -04:00
* When switching a theme via the Customizer , supply any previously - configured
2014-04-14 18:46:16 -04: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
2015-05-22 01:06:25 -04:00
*
* @ global array $sidebars_widgets
* @ global array $_wp_sidebars_widgets
2014-04-14 18:46:16 -04: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' ) );
Customize: Implement customized state persistence with changesets.
Includes infrastructure developed in the Customize Snapshots feature plugin.
See https://make.wordpress.org/core/2016/10/12/customize-changesets-technical-design-decisions/
Props westonruter, valendesigns, utkarshpatel, stubgo, lgedeon, ocean90, ryankienstra, mihai2u, dlh, aaroncampbell, jonathanbardo, jorbin.
See #28721.
See #31089.
Fixes #30937.
Fixes #31517.
Fixes #30028.
Fixes #23225.
Fixes #34142.
Fixes #36485.
Built from https://develop.svn.wordpress.org/trunk@38810
git-svn-id: http://core.svn.wordpress.org/trunk@38753 1a063a9b-81f0-0310-95a4-ce76da25c4cd
2016-10-18 16:05:31 -04:00
$this -> manager -> set_post_value ( 'old_sidebars_widgets_data' , $this -> old_sidebars_widgets ); // Override any value cached in changeset.
2014-04-14 18:46:16 -04:00
// 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 01:06:25 -04:00
// reset global cache var used by wp_get_sidebars_widgets()
unset ( $GLOBALS [ '_wp_sidebars_widgets' ] );
2014-04-14 18:46:16 -04:00
}
/**
2016-03-03 21:02:26 -05:00
* Filters old_sidebars_widgets_data Customizer setting .
2014-04-14 18:46:16 -04:00
*
2016-03-03 21:02:26 -05: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
2014-04-14 18:46:16 -04:00
* theme_mod .
*
* @ since 3.9 . 0
*
2016-03-03 21:02:26 -05:00
* @ see WP_Customize_Widgets :: handle_theme_switch ()
*
2014-11-30 18:33:23 -05:00
* @ param array $old_sidebars_widgets
2015-05-21 18:05:24 -04:00
* @ return array
2014-04-14 18:46:16 -04:00
*/
public function filter_customize_value_old_sidebars_widgets_data ( $old_sidebars_widgets ) {
return $this -> old_sidebars_widgets ;
}
/**
2016-03-03 21:02:26 -05:00
* Filters sidebars_widgets option for theme switch .
2014-04-14 18:46:16 -04:00
*
2016-03-03 21:02:26 -05:00
* 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 .
2014-04-14 18:46:16 -04:00
*
* @ since 3.9 . 0
*
2016-03-03 21:02:26 -05:00
* @ see WP_Customize_Widgets :: handle_theme_switch ()
2015-05-22 01:06:25 -04:00
* @ global array $sidebars_widgets
*
2014-04-14 18:46:16 -04:00
* @ param array $sidebars_widgets
2015-05-21 18:05:24 -04:00
* @ return array
2014-04-14 18:46:16 -04:00
*/
public function filter_option_sidebars_widgets_for_theme_switch ( $sidebars_widgets ) {
2017-11-30 18:11:00 -05:00
$sidebars_widgets = $GLOBALS [ 'sidebars_widgets' ];
2014-04-14 18:46:16 -04:00
$sidebars_widgets [ 'array_version' ] = 3 ;
return $sidebars_widgets ;
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Ensures all widgets get loaded into the Customizer .
2014-04-02 01:45:16 -04:00
*
* Note : these actions are also fired in wp_ajax_update_widget () .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function customize_controls_init () {
2014-04-02 01:45:16 -04:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2019-07-04 21:45:56 -04:00
do_action ( 'load-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-04-02 01:45:16 -04:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2019-07-04 21:45:56 -04:00
do_action ( 'widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-03-28 15:47:15 -04:00
/** This action is documented in wp-admin/widgets.php */
2014-03-05 15:41:14 -05:00
do_action ( 'sidebar_admin_setup' );
}
/**
2016-03-03 21:02:26 -05:00
* Ensures widgets are available for all types of previews .
2014-04-02 01:45:16 -04:00
*
2016-05-23 14:54:27 -04:00
* When in preview , hook to { @ see 'customize_register' } for settings after WordPress is loaded
2016-03-03 21:02:26 -05:00
* so that all filters have been initialized ( e . g . Widget Visibility ) .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function schedule_customize_register () {
2015-02-08 18:11:25 -05:00
if ( is_admin () ) {
2014-03-28 10:07:14 -04:00
$this -> customize_register ();
2014-03-05 15:41:14 -05:00
} else {
2014-03-28 10:07:14 -04:00
add_action ( 'wp' , array ( $this , 'customize_register' ) );
2014-03-05 15:41:14 -05:00
}
}
/**
2016-03-03 21:02:26 -05:00
* Registers Customizer settings and controls for all sidebars and widgets .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2015-05-22 01:06:25 -04:00
*
* @ global array $wp_registered_widgets
* @ global array $wp_registered_widget_controls
* @ global array $wp_registered_sidebars
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function customize_register () {
2014-03-14 16:01:14 -04:00
global $wp_registered_widgets , $wp_registered_widget_controls , $wp_registered_sidebars ;
2014-03-05 15:41:14 -05:00
2016-04-07 16:59:29 -04:00
add_filter ( 'sidebars_widgets' , array ( $this , 'preview_sidebars_widgets' ), 1 );
2014-03-05 15:41:14 -05:00
$sidebars_widgets = array_merge (
array ( 'wp_inactive_widgets' => array () ),
2015-05-22 01:06:25 -04:00
array_fill_keys ( array_keys ( $wp_registered_sidebars ), array () ),
2014-03-05 15:41:14 -05:00
wp_get_sidebars_widgets ()
);
$new_setting_ids = array ();
2014-03-26 18:29:15 -04:00
/*
2014-04-02 01:45:16 -04: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 15:41:14 -05:00
*/
foreach ( array_keys ( $wp_registered_widgets ) as $widget_id ) {
2014-03-28 10:07:14 -04:00
$setting_id = $this -> get_setting_id ( $widget_id );
$setting_args = $this -> get_setting_args ( $setting_id );
2015-02-08 18:11:25 -05:00
if ( ! $this -> manager -> get_setting ( $setting_id ) ) {
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2014-03-05 15:41:14 -05:00
$new_setting_ids [] = $setting_id ;
}
2014-04-14 18:46:16 -04:00
/*
* Add a setting which will be supplied for the theme ' s sidebars_widgets
2015-12-06 16:23:25 -05:00
* theme_mod when the theme is switched .
2014-04-14 18:46:16 -04:00
*/
if ( ! $this -> manager -> is_theme_active () ) {
2017-11-30 18:11:00 -05:00
$setting_id = 'old_sidebars_widgets_data' ;
$setting_args = $this -> get_setting_args (
2018-08-16 21:51:36 -04:00
$setting_id ,
array (
2017-11-30 18:11:00 -05:00
'type' => 'global_variable' ,
'dirty' => true ,
)
);
2014-04-14 18:46:16 -04:00
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2017-11-30 18:11:00 -05:00
$this -> manager -> add_panel (
2018-08-16 21:51:36 -04:00
'widgets' ,
array (
2017-11-30 18:11:00 -05: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' ),
'auto_expand_sole_section' => true ,
)
);
2014-06-26 16:17:15 -04:00
2014-03-05 15:41:14 -05:00
foreach ( $sidebars_widgets as $sidebar_id => $sidebar_widget_ids ) {
if ( empty ( $sidebar_widget_ids ) ) {
$sidebar_widget_ids = array ();
}
2014-04-02 02:12:16 -04:00
2015-10-12 21:33:25 -04:00
$is_registered_sidebar = is_registered_sidebar ( $sidebar_id );
2014-03-05 15:41:14 -05:00
$is_inactive_widgets = ( 'wp_inactive_widgets' === $sidebar_id );
$is_active_sidebar = ( $is_registered_sidebar && ! $is_inactive_widgets );
2014-04-02 01:45:16 -04:00
// Add setting for managing the sidebar's widgets.
2014-03-05 15:41:14 -05:00
if ( $is_registered_sidebar || $is_inactive_widgets ) {
$setting_id = sprintf ( 'sidebars_widgets[%s]' , $sidebar_id );
2014-03-28 10:07:14 -04:00
$setting_args = $this -> get_setting_args ( $setting_id );
2015-02-08 18:11:25 -05:00
if ( ! $this -> manager -> get_setting ( $setting_id ) ) {
2015-03-10 18:39:28 -04:00
if ( ! $this -> manager -> is_theme_active () ) {
$setting_args [ 'dirty' ] = true ;
}
2015-02-08 18:11:25 -05:00
$this -> manager -> add_setting ( $setting_id , $setting_args );
}
2014-03-05 15:41:14 -05:00
$new_setting_ids [] = $setting_id ;
2014-04-02 01:45:16 -04:00
// Add section to contain controls.
2014-03-05 15:41:14 -05:00
$section_id = sprintf ( 'sidebar-widgets-%s' , $sidebar_id );
if ( $is_active_sidebar ) {
2014-04-02 02:12:16 -04:00
2014-03-05 15:41:14 -05:00
$section_args = array (
2017-11-30 18:11:00 -05:00
'title' => $wp_registered_sidebars [ $sidebar_id ][ 'name' ],
2015-05-22 01:06:25 -04:00
'description' => $wp_registered_sidebars [ $sidebar_id ][ 'description' ],
2017-11-30 18:11:00 -05:00
'priority' => array_search ( $sidebar_id , array_keys ( $wp_registered_sidebars ) ),
'panel' => 'widgets' ,
'sidebar_id' => $sidebar_id ,
2014-03-05 15:41:14 -05:00
);
2014-04-14 14:41:17 -04:00
/**
2016-05-22 14:10:29 -04:00
* Filters Customizer widget section arguments for a given sidebar .
2014-04-14 14:41:17 -04:00
*
* @ 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 15:41:14 -05:00
$section_args = apply_filters ( 'customizer_widgets_section_args' , $section_args , $section_id , $sidebar_id );
2014-04-02 02:12:16 -04:00
2014-11-13 07:19:23 -05:00
$section = new WP_Customize_Sidebar_Section ( $this -> manager , $section_id , $section_args );
$this -> manager -> add_section ( $section );
2014-03-05 15:41:14 -05:00
2017-11-30 18:11:00 -05:00
$control = new WP_Widget_Area_Customize_Control (
2018-08-16 21:51:36 -04:00
$this -> manager ,
$setting_id ,
array (
2017-11-30 18:11:00 -05:00
'section' => $section_id ,
'sidebar_id' => $sidebar_id ,
'priority' => count ( $sidebar_widget_ids ), // place 'Add Widget' and 'Reorder' buttons at end.
)
);
2014-03-05 15:41:14 -05:00
$new_setting_ids [] = $setting_id ;
2014-04-02 02:12:16 -04:00
2014-03-28 10:07:14 -04:00
$this -> manager -> add_control ( $control );
2014-03-05 15:41:14 -05:00
}
}
2014-03-26 18:29:15 -04:00
// Add a control for each active widget (located in a sidebar).
2014-03-05 15:41:14 -05:00
foreach ( $sidebar_widget_ids as $i => $widget_id ) {
2014-03-26 18:29:15 -04:00
// Skip widgets that may have gone away due to a plugin being deactivated.
2017-11-30 18:11:00 -05:00
if ( ! $is_active_sidebar || ! isset ( $wp_registered_widgets [ $widget_id ] ) ) {
2014-03-05 15:41:14 -05:00
continue ;
}
2014-04-02 02:12:16 -04:00
2017-11-30 18:11:00 -05:00
$registered_widget = $wp_registered_widgets [ $widget_id ];
2014-04-02 02:12:16 -04:00
$setting_id = $this -> get_setting_id ( $widget_id );
2017-11-30 18:11:00 -05:00
$id_base = $wp_registered_widget_controls [ $widget_id ][ 'id_base' ];
$control = new WP_Widget_Form_Customize_Control (
2018-08-16 21:51:36 -04:00
$this -> manager ,
$setting_id ,
array (
2017-11-30 18:11:00 -05:00
'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 10:07:14 -04:00
$this -> manager -> add_control ( $control );
2014-03-05 15:41:14 -05:00
}
}
2017-08-02 01:35:41 -04:00
if ( $this -> manager -> settings_previewed () ) {
2014-03-05 15:41:14 -05:00
foreach ( $new_setting_ids as $new_setting_id ) {
2014-03-28 10:07:14 -04:00
$this -> manager -> get_setting ( $new_setting_id ) -> preview ();
2014-03-05 15:41:14 -05:00
}
}
}
2015-10-16 19:48:25 -04:00
/**
2016-03-03 21:02:26 -05:00
* Determines whether the widgets panel is active , based on whether there are sidebars registered .
2015-10-16 19:48:25 -04:00
*
* @ since 4.4 . 0
*
* @ 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 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Converts a widget_id into its corresponding Customizer setting ID ( option name ) .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param string $widget_id Widget ID .
* @ return string Maybe - parsed widget ID .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function get_setting_id ( $widget_id ) {
$parsed_widget_id = $this -> parse_widget_id ( $widget_id );
2014-04-02 02:12:16 -04:00
$setting_id = sprintf ( 'widget_%s' , $parsed_widget_id [ 'id_base' ] );
2014-03-05 15:41:14 -05:00
if ( ! is_null ( $parsed_widget_id [ 'number' ] ) ) {
$setting_id .= sprintf ( '[%d]' , $parsed_widget_id [ 'number' ] );
}
return $setting_id ;
}
/**
2016-03-03 21:02:26 -05:00
* Determines whether the widget is considered " wide " .
*
* Core widgets which may have controls wider than 250 , but can still be shown
* in the narrow Customizer panel . The RSS and Text widgets in Core , for example ,
* have widths of 400 and yet they still render fine in the Customizer panel .
2014-04-02 01:45:16 -04:00
*
2016-03-03 21:02:26 -05:00
* This method will return all Core widgets as being not wide , but this can be
2016-05-23 14:54:27 -04:00
* overridden with the { @ see 'is_wide_widget_in_customizer' } filter .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2015-05-22 01:06:25 -04:00
* @ global $wp_registered_widget_controls
*
2014-03-26 18:29:15 -04:00
* @ param string $widget_id Widget ID .
* @ return bool Whether or not the widget is a " wide " widget .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function is_wide_widget ( $widget_id ) {
2014-03-05 15:41:14 -05:00
global $wp_registered_widget_controls ;
2014-04-02 02:12:16 -04:00
2014-03-28 10:07:14 -04:00
$parsed_widget_id = $this -> parse_widget_id ( $widget_id );
2017-11-30 18:11:00 -05:00
$width = $wp_registered_widget_controls [ $widget_id ][ 'width' ];
2014-04-02 02:12:16 -04:00
$is_core = in_array ( $parsed_widget_id [ 'id_base' ], $this -> core_widget_id_bases );
$is_wide = ( $width > 250 && ! $is_core );
2014-03-26 18:29:15 -04:00
/**
2016-05-22 14:10:29 -04:00
* Filters whether the given widget is considered " wide " .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
*
* @ param bool $is_wide Whether the widget is wide , Default false .
* @ param string $widget_id Widget ID .
*/
2014-04-02 01:45:16 -04:00
return apply_filters ( 'is_wide_widget_in_customizer' , $is_wide , $widget_id );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Converts a widget ID into its id_base and number components .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param string $widget_id Widget ID .
* @ return array Array containing a widget ' s id_base and number components .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function parse_widget_id ( $widget_id ) {
2014-03-05 15:41:14 -05:00
$parsed = array (
2017-11-30 18:11:00 -05:00
'number' => null ,
2014-03-05 15:41:14 -05:00
'id_base' => null ,
);
2014-04-02 02:12:16 -04:00
2014-03-05 15:41:14 -05: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 ;
}
/**
2016-03-03 21:02:26 -05:00
* Converts a widget setting ID ( option path ) to its id_base and number components .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ param string $setting_id Widget setting ID .
2014-04-02 01:45:16 -04:00
* @ return WP_Error | array Array containing a widget ' s id_base and number components ,
2014-03-26 18:29:15 -04:00
* or a WP_Error object .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function parse_widget_setting_id ( $setting_id ) {
2014-03-05 15:41:14 -05:00
if ( ! preg_match ( '/^(widget_(.+?))(?:\[(\d+)\])?$/' , $setting_id , $matches ) ) {
2014-03-29 17:44:14 -04:00
return new WP_Error ( 'widget_setting_invalid_id' );
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
2014-03-05 15:41:14 -05:00
$id_base = $matches [ 2 ];
$number = isset ( $matches [ 3 ] ) ? intval ( $matches [ 3 ] ) : null ;
2014-04-02 02:12:16 -04:00
2014-03-05 15:41:14 -05:00
return compact ( 'id_base' , 'number' );
}
2014-04-02 13:04:14 -04:00
/**
2016-03-03 21:02:26 -05:00
* Calls admin_print_styles - widgets . php and admin_print_styles hooks to
2014-04-02 13:04:14 -04:00
* allow custom styles from plugins .
*
* @ since 3.9 . 0
*/
public function print_styles () {
/** This action is documented in wp-admin/admin-header.php */
2019-07-04 21:45:56 -04:00
do_action ( 'admin_print_styles-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-04-02 13:04:14 -04:00
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_styles' );
}
/**
2016-03-03 21:02:26 -05:00
* Calls admin_print_scripts - widgets . php and admin_print_scripts hooks to
2014-04-02 13:04:14 -04:00
* allow custom scripts from plugins .
*
* @ since 3.9 . 0
*/
public function print_scripts () {
/** This action is documented in wp-admin/admin-header.php */
2019-07-04 21:45:56 -04:00
do_action ( 'admin_print_scripts-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-04-02 13:04:14 -04:00
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_print_scripts' );
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Enqueues scripts and styles for Customizer panel and export data to JavaScript .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2015-05-22 01:06:25 -04:00
*
* @ global WP_Scripts $wp_scripts
* @ global array $wp_registered_sidebars
* @ global array $wp_registered_widgets
2014-03-05 15:41:14 -05:00
*/
2014-04-02 13:04:14 -04:00
public function enqueue_scripts () {
2015-05-22 01:06:25 -04:00
global $wp_scripts , $wp_registered_sidebars , $wp_registered_widgets ;
2014-03-13 15:41:14 -04:00
wp_enqueue_style ( 'customize-widgets' );
wp_enqueue_script ( 'customize-widgets' );
2014-03-05 15:41:14 -05:00
2014-04-02 13:04:14 -04:00
/** This action is documented in wp-admin/admin-header.php */
do_action ( 'admin_enqueue_scripts' , 'widgets.php' );
2014-04-02 01:45:16 -04:00
/*
* Export available widgets with control_tpl removed from model
* since plugins need templates to be in the DOM .
*/
2014-03-05 15:41:14 -05:00
$available_widgets = array ();
2014-04-02 02:12:16 -04:00
2014-03-28 10:07:14 -04:00
foreach ( $this -> get_available_widgets () as $available_widget ) {
2014-03-05 15:41:14 -05:00
unset ( $available_widget [ 'control_tpl' ] );
$available_widgets [] = $available_widget ;
}
$widget_reorder_nav_tpl = sprintf (
2014-03-19 04:18:14 -04: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 15:41:14 -05:00
);
$move_widget_area_tpl = str_replace (
array ( '{description}' , '{btn}' ),
array (
2014-04-07 05:04:14 -04:00
__ ( 'Select an area to move this widget into:' ),
_x ( 'Move' , 'Move widget' ),
2014-03-05 15:41:14 -05:00
),
2014-04-06 16:40:15 -04: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 " >
2016-09-28 15:54:28 -04:00
< button class = " move-widget-btn button " type = " button " > { btn } </ button >
2014-03-05 15:41:14 -05:00
</ div >
2014-04-06 16:40:15 -04:00
</ div > '
2014-03-05 15:41:14 -05:00
);
2017-03-24 18:03:42 -04:00
/*
* Gather all strings in PHP that may be needed by JS on the client .
* Once JS i18n is implemented ( in #20491), this can be removed.
*/
2017-11-30 18:11:00 -05:00
$some_non_rendered_areas_messages = array ();
2017-03-24 18:03:42 -04:00
$some_non_rendered_areas_messages [ 1 ] = html_entity_decode (
__ ( 'Your theme has 1 other widget area, but this particular page doesn’t display it.' ),
ENT_QUOTES ,
get_bloginfo ( 'charset' )
);
2017-11-30 18:11:00 -05:00
$registered_sidebar_count = count ( $wp_registered_sidebars );
2017-03-24 18:03:42 -04:00
for ( $non_rendered_count = 2 ; $non_rendered_count < $registered_sidebar_count ; $non_rendered_count ++ ) {
2017-11-30 18:11:00 -05:00
$some_non_rendered_areas_messages [ $non_rendered_count ] = html_entity_decode (
sprintf (
/* translators: %s: the number of other widget areas registered but not rendered */
_n (
'Your theme has %s other widget area, but this particular page doesn’t display it.' ,
'Your theme has %s other widget areas, but this particular page doesn’t display them.' ,
$non_rendered_count
),
number_format_i18n ( $non_rendered_count )
2018-08-16 21:51:36 -04:00
),
ENT_QUOTES ,
get_bloginfo ( 'charset' )
2017-11-30 18:11:00 -05:00
);
2017-03-24 18:03:42 -04:00
}
if ( 1 === $registered_sidebar_count ) {
2017-11-30 18:11:00 -05:00
$no_areas_shown_message = html_entity_decode (
sprintf (
__ ( 'Your theme has 1 widget area, but this particular page doesn’t display it.' )
2018-08-16 21:51:36 -04:00
),
ENT_QUOTES ,
get_bloginfo ( 'charset' )
2017-11-30 18:11:00 -05:00
);
2017-03-24 18:03:42 -04:00
} else {
2017-11-30 18:11:00 -05:00
$no_areas_shown_message = html_entity_decode (
sprintf (
/* translators: %s: the total number of widget areas registered */
_n (
'Your theme has %s widget area, but this particular page doesn’t display it.' ,
'Your theme has %s widget areas, but this particular page doesn’t display them.' ,
$registered_sidebar_count
),
number_format_i18n ( $registered_sidebar_count )
2018-08-16 21:51:36 -04:00
),
ENT_QUOTES ,
get_bloginfo ( 'charset' )
2017-11-30 18:11:00 -05:00
);
2017-03-24 18:03:42 -04:00
}
2014-04-07 05:04:14 -04:00
$settings = array (
2017-11-30 18:11:00 -05:00
'registeredSidebars' => array_values ( $wp_registered_sidebars ),
'registeredWidgets' => $wp_registered_widgets ,
'availableWidgets' => $available_widgets , // @todo Merge this with registered_widgets
'l10n' => array (
2014-04-07 05:04:14 -04:00
'saveBtnLabel' => __ ( 'Apply' ),
'saveBtnTooltip' => __ ( 'Save and preview changes before publishing them.' ),
'removeBtnLabel' => __ ( 'Remove' ),
2019-03-09 07:56:54 -05:00
'removeBtnTooltip' => __ ( 'Keep widget settings and move it to the inactive widgets' ),
2014-04-07 05:04:14 -04:00
'error' => __ ( 'An error has occurred. Please reload the page and try again.' ),
2014-12-06 19:45:24 -05:00
'widgetMovedUp' => __ ( 'Widget moved up' ),
'widgetMovedDown' => __ ( 'Widget moved down' ),
2017-03-22 15:03:45 -04:00
'navigatePreview' => __ ( 'You can navigate to other pages on your site while using the Customizer to view and edit the widgets displayed on those pages.' ),
2017-03-24 18:03:42 -04:00
'someAreasShown' => $some_non_rendered_areas_messages ,
'noAreasShown' => $no_areas_shown_message ,
2015-10-20 16:15:26 -04:00
'reorderModeOn' => __ ( 'Reorder mode enabled' ),
'reorderModeOff' => __ ( 'Reorder mode closed' ),
'reorderLabelOn' => esc_attr__ ( 'Reorder widgets' ),
2017-09-29 07:42:48 -04:00
/* translators: %d: the number of widgets found */
2016-10-03 12:28:31 -04:00
'widgetsFound' => __ ( 'Number of widgets found: %d' ),
'noWidgetsFound' => __ ( 'No widgets found.' ),
2014-03-05 15:41:14 -05:00
),
2017-11-30 18:11:00 -05:00
'tpl' => array (
2014-04-07 05:04:14 -04:00
'widgetReorderNav' => $widget_reorder_nav_tpl ,
'moveWidgetArea' => $move_widget_area_tpl ,
2014-03-05 15:41:14 -05:00
),
2016-03-21 17:59:29 -04:00
'selectiveRefreshableWidgets' => $this -> get_selective_refreshable_widgets (),
2014-03-05 15:41:14 -05:00
);
2014-04-02 02:12:16 -04:00
2014-04-07 05:04:14 -04:00
foreach ( $settings [ 'registeredWidgets' ] as & $registered_widget ) {
2014-03-05 15:41:14 -05:00
unset ( $registered_widget [ 'callback' ] ); // may not be JSON-serializeable
}
$wp_scripts -> add_data (
2014-03-13 15:41:14 -04:00
'customize-widgets' ,
2014-03-05 15:41:14 -05:00
'data' ,
2014-10-28 14:35:19 -04:00
sprintf ( 'var _wpCustomizeWidgetsSettings = %s;' , wp_json_encode ( $settings ) )
2014-03-05 15:41:14 -05:00
);
}
/**
2016-03-03 21:02:26 -05:00
* Renders the widget form control templates into the DOM .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function output_widget_control_templates () {
2014-03-05 15:41:14 -05:00
?>
< div id = " widgets-left " ><!-- compatibility with JS which looks for widget templates here -->
< div id = " available-widgets " >
2015-05-29 09:57:26 -04:00
< div class = " customize-section-title " >
< button class = " customize-section-back " tabindex = " -1 " >
< span class = " screen-reader-text " >< ? php _e ( 'Back' ); ?> </span>
</ button >
< h3 >
2017-11-30 18:11:00 -05:00
< span class = " customize-action " >
< ? php
2015-05-29 09:57:26 -04:00
/* 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 ) );
2017-11-30 18:11:00 -05:00
?>
</ span >
2015-05-29 09:57:26 -04:00
< ? php _e ( 'Add a Widget' ); ?>
</ h3 >
</ div >
2014-03-05 15:41:14 -05:00
< div id = " available-widgets-filter " >
2014-04-07 05:04:14 -04:00
< label class = " screen-reader-text " for = " widgets-search " >< ? php _e ( 'Search Widgets' ); ?> </label>
2017-11-30 18:11:00 -05:00
< input type = " text " id = " widgets-search " placeholder = " <?php esc_attr_e( 'Search widgets…' ); ?> " aria - describedby = " widgets-search-desc " />
2016-10-03 12:28:31 -04:00
< div class = " search-icon " aria - hidden = " true " ></ div >
< button type = " button " class = " clear-results " >< span class = " screen-reader-text " >< ? php _e ( 'Clear Results' ); ?> </span></button>
< p class = " screen-reader-text " id = " widgets-search-desc " >< ? php _e ( 'The search results will be updated as you type.' ); ?> </p>
2014-03-05 15:41:14 -05:00
</ div >
2015-04-21 10:15:26 -04:00
< div id = " available-widgets-list " >
2017-11-30 18:11:00 -05:00
< ? php foreach ( $this -> get_available_widgets () as $available_widget ) : ?>
< 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 05:04:14 -04:00
< ? php echo $available_widget [ 'control_tpl' ]; ?>
2014-03-05 15:41:14 -05:00
</ div >
< ? php endforeach ; ?>
2016-10-03 12:28:31 -04:00
< p class = " no-widgets-found-message " >< ? php _e ( 'No widgets found.' ); ?> </p>
2015-04-21 10:15:26 -04:00
</ div ><!-- #available-widgets-list -->
2014-03-05 15:41:14 -05:00
</ div ><!-- #available-widgets -->
</ div ><!-- #widgets-left -->
< ? php
}
2014-04-02 13:04:14 -04:00
/**
2016-03-03 21:02:26 -05:00
* Calls admin_print_footer_scripts and admin_print_scripts hooks to
2014-04-02 13:04:14 -04:00
* allow custom scripts from plugins .
*
* @ since 3.9 . 0
*/
public function print_footer_scripts () {
/** This action is documented in wp-admin/admin-footer.php */
2019-07-04 21:45:56 -04:00
do_action ( 'admin_print_footer_scripts-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2016-04-21 11:17:27 -04:00
/** This action is documented in wp-admin/admin-footer.php */
2014-04-02 13:04:14 -04:00
do_action ( 'admin_print_footer_scripts' );
/** This action is documented in wp-admin/admin-footer.php */
2019-07-04 21:45:56 -04:00
do_action ( 'admin_footer-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-04-02 13:04:14 -04:00
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Retrieves common arguments to supply when constructing a Customizer setting .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param string $id Widget setting ID .
* @ param array $overrides Array of setting overrides .
* @ return array Possibly modified setting arguments .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function get_setting_args ( $id , $overrides = array () ) {
2014-03-05 15:41:14 -05:00
$args = array (
2014-04-02 02:12:16 -04:00
'type' => 'option' ,
2014-03-05 15:41:14 -05:00
'capability' => 'edit_theme_options' ,
2014-04-02 02:12:16 -04:00
'default' => array (),
2014-03-05 15:41:14 -05:00
);
2015-02-08 18:11:25 -05:00
if ( preg_match ( $this -> setting_id_patterns [ 'sidebar_widgets' ], $id , $matches ) ) {
2017-11-30 18:11:00 -05:00
$args [ 'sanitize_callback' ] = array ( $this , 'sanitize_sidebar_widgets' );
2015-02-08 18:11:25 -05:00
$args [ 'sanitize_js_callback' ] = array ( $this , 'sanitize_sidebar_widgets_js_instance' );
2017-11-30 18:11:00 -05:00
$args [ 'transport' ] = current_theme_supports ( 'customize-selective-refresh-widgets' ) ? 'postMessage' : 'refresh' ;
2015-06-19 18:01:25 -04:00
} elseif ( preg_match ( $this -> setting_id_patterns [ 'widget_instance' ], $id , $matches ) ) {
2017-11-30 18:11:00 -05:00
$args [ 'sanitize_callback' ] = array ( $this , 'sanitize_widget_instance' );
2015-02-08 18:11:25 -05:00
$args [ 'sanitize_js_callback' ] = array ( $this , 'sanitize_widget_js_instance' );
2017-11-30 18:11:00 -05:00
$args [ 'transport' ] = $this -> is_widget_selective_refreshable ( $matches [ 'id_base' ] ) ? 'postMessage' : 'refresh' ;
2015-02-08 18:11:25 -05:00
}
2014-03-05 15:41:14 -05:00
$args = array_merge ( $args , $overrides );
2014-04-02 01:45:16 -04:00
/**
2016-05-22 14:10:29 -04:00
* Filters the common arguments supplied when constructing a Customizer setting .
2014-04-02 01:45:16 -04:00
*
* @ 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 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Ensures sidebar widget arrays only ever contain widget IDS .
2014-04-02 01:45:16 -04:00
*
* Used as the 'sanitize_callback' for each $sidebars_widgets setting .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2018-03-25 14:10:32 -04:00
* @ param string [] $widget_ids Array of widget IDs .
* @ return string [] Array of sanitized widget IDs .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function sanitize_sidebar_widgets ( $widget_ids ) {
2017-11-30 18:11:00 -05:00
$widget_ids = array_map ( 'strval' , ( array ) $widget_ids );
2014-03-05 15:41:14 -05:00
$sanitized_widget_ids = array ();
foreach ( $widget_ids as $widget_id ) {
2015-02-08 18:11:25 -05:00
$sanitized_widget_ids [] = preg_replace ( '/[^a-z0-9_\-]/' , '' , $widget_id );
2014-03-05 15:41:14 -05:00
}
return $sanitized_widget_ids ;
}
/**
2016-03-03 21:02:26 -05:00
* Builds up an index of all available widgets for use in Backbone models .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*
2015-05-22 01:06:25 -04:00
* @ global array $wp_registered_widgets
* @ global array $wp_registered_widget_controls
* @ staticvar array $available_widgets
*
2014-03-05 15:41:14 -05:00
* @ see wp_list_widgets ()
2014-04-02 01:45:16 -04:00
*
* @ return array List of available widgets .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function get_available_widgets () {
2014-03-05 15:41:14 -05:00
static $available_widgets = array ();
if ( ! empty ( $available_widgets ) ) {
return $available_widgets ;
}
global $wp_registered_widgets , $wp_registered_widget_controls ;
2019-04-13 00:46:52 -04:00
require_once ABSPATH . 'wp-admin/includes/widgets.php' ; // for next_widget_id_number()
2014-03-05 15:41:14 -05:00
$sort = $wp_registered_widgets ;
2014-03-28 10:07:14 -04:00
usort ( $sort , array ( $this , '_sort_name_callback' ) );
2014-03-05 15:41:14 -05: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 02:12:16 -04:00
'widget_id' => $widget [ 'id' ],
2014-03-05 15:41:14 -05:00
'widget_name' => $widget [ 'name' ],
2014-04-02 02:12:16 -04:00
'_display' => 'template' ,
2014-03-05 15:41:14 -05:00
);
$is_disabled = false ;
2017-11-30 18:11:00 -05:00
$is_multi_widget = ( isset ( $wp_registered_widget_controls [ $widget [ 'id' ] ][ 'id_base' ] ) && isset ( $widget [ 'params' ][ 0 ][ 'number' ] ) );
2014-03-05 15:41:14 -05:00
if ( $is_multi_widget ) {
2017-11-30 18:11:00 -05:00
$id_base = $wp_registered_widget_controls [ $widget [ 'id' ] ][ 'id_base' ];
2014-03-05 15:41:14 -05: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 02:12:16 -04:00
2014-03-05 15:41:14 -05:00
if ( $sidebar && 'wp_inactive_widgets' !== $sidebar ) {
$is_disabled = true ;
}
$id_base = $widget [ 'id' ];
}
2017-11-30 18:11:00 -05:00
$list_widget_controls_args = wp_list_widget_controls_dynamic_sidebar (
array (
0 => $args ,
1 => $widget [ 'params' ][ 0 ],
)
);
$control_tpl = $this -> get_widget_control ( $list_widget_controls_args );
2014-03-05 15:41:14 -05:00
2014-04-02 01:45:16 -04:00
// The properties here are mapped to the Backbone Widget model.
2017-11-30 18:11:00 -05:00
$available_widget = array_merge (
2018-08-16 21:51:36 -04:00
$available_widget ,
array (
2017-11-30 18:11:00 -05:00
'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 ,
'transport' => $this -> is_widget_selective_refreshable ( $id_base ) ? 'postMessage' : 'refresh' ,
'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 15:41:14 -05:00
$available_widgets [] = $available_widget ;
}
2014-04-07 05:04:14 -04:00
2014-03-05 15:41:14 -05:00
return $available_widgets ;
}
/**
2016-03-03 21:02:26 -05:00
* Naturally orders available widgets by name .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04: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 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function _sort_name_callback ( $widget_a , $widget_b ) {
2014-03-26 18:29:15 -04:00
return strnatcasecmp ( $widget_a [ 'name' ], $widget_b [ 'name' ] );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Retrieves the widget control markup .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param array $args Widget control arguments .
* @ return string Widget control form HTML markup .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function get_widget_control ( $args ) {
2017-11-30 18:11:00 -05:00
$args [ 0 ][ 'before_form' ] = '<div class="form">' ;
$args [ 0 ][ 'after_form' ] = '</div><!-- .form -->' ;
2015-09-25 17:02:27 -04:00
$args [ 0 ][ 'before_widget_content' ] = '<div class="widget-content">' ;
2017-11-30 18:11:00 -05:00
$args [ 0 ][ 'after_widget_content' ] = '</div><!-- .widget-content -->' ;
2014-03-05 15:41:14 -05:00
ob_start ();
call_user_func_array ( 'wp_widget_control' , $args );
$control_tpl = ob_get_clean ();
2015-09-25 17:02:27 -04:00
return $control_tpl ;
}
2014-04-02 02:12:16 -04:00
2015-09-25 17:02:27 -04:00
/**
2016-03-03 21:02:26 -05:00
* Retrieves the widget control markup parts .
2015-09-25 17:02:27 -04:00
*
* @ since 4.4 . 0
*
* @ param array $args Widget control arguments .
* @ return array {
2016-03-03 21:02:26 -05:00
* @ type string $control Markup for widget control wrapping form .
* @ type string $content The contents of the widget form itself .
2015-09-25 17:02:27 -04:00
* }
*/
public function get_widget_control_parts ( $args ) {
$args [ 0 ][ 'before_widget_content' ] = '<div class="widget-content">' ;
2017-11-30 18:11:00 -05:00
$args [ 0 ][ 'after_widget_content' ] = '</div><!-- .widget-content -->' ;
$control_markup = $this -> get_widget_control ( $args );
2015-09-25 17:02:27 -04:00
$content_start_pos = strpos ( $control_markup , $args [ 0 ][ 'before_widget_content' ] );
2017-11-30 18:11:00 -05:00
$content_end_pos = strrpos ( $control_markup , $args [ 0 ][ 'after_widget_content' ] );
2015-09-25 17:02:27 -04:00
2017-11-30 18:11:00 -05:00
$control = substr ( $control_markup , 0 , $content_start_pos + strlen ( $args [ 0 ][ 'before_widget_content' ] ) );
2015-09-25 17:02:27 -04:00
$control .= substr ( $control_markup , $content_end_pos );
2017-11-30 18:11:00 -05:00
$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 02:12:16 -04:00
2015-09-25 17:02:27 -04:00
return compact ( 'control' , 'content' );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Adds hooks for the Customizer preview .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function customize_preview_init () {
add_action ( 'wp_enqueue_scripts' , array ( $this , 'customize_preview_enqueue' ) );
2017-11-30 18:11:00 -05:00
add_action ( 'wp_print_styles' , array ( $this , 'print_preview_css' ), 1 );
add_action ( 'wp_footer' , array ( $this , 'export_preview_data' ), 20 );
2014-03-05 15:41:14 -05:00
}
2015-04-06 11:10:27 -04:00
/**
2016-03-03 21:02:26 -05:00
* Refreshes the nonce for widget updates .
2015-04-06 11:10:27 -04:00
*
* @ since 4.2 . 0
*
* @ 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 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* When previewing , ensures the proper previewing widgets are used .
2014-03-26 18:29:15 -04:00
*
2016-03-03 21:02:26 -05:00
* Because wp_get_sidebars_widgets () gets called early at { @ see 'init' } ( via
* wp_convert_widget_settings ()) and can set global variable `$_wp_sidebars_widgets`
* to the value of `get_option( 'sidebars_widgets' )` before the Customizer preview
* filter is added , it has to be reset after the filter has been added .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param array $sidebars_widgets List of widgets for the current sidebar .
2015-05-21 18:05:24 -04:00
* @ return array
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function preview_sidebars_widgets ( $sidebars_widgets ) {
2016-05-02 19:42:28 -04:00
$sidebars_widgets = get_option ( 'sidebars_widgets' , array () );
2014-04-02 01:45:16 -04:00
2014-03-05 15:41:14 -05:00
unset ( $sidebars_widgets [ 'array_version' ] );
return $sidebars_widgets ;
}
/**
2016-03-03 21:02:26 -05:00
* Enqueues scripts for the Customizer preview .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function customize_preview_enqueue () {
2014-03-18 11:31:16 -04:00
wp_enqueue_script ( 'customize-preview-widgets' );
2014-03-28 10:07:14 -04:00
}
2014-03-05 15:41:14 -05:00
2014-03-18 11:21:15 -04:00
/**
2016-03-03 21:02:26 -05:00
* Inserts default style for highlighted widget at early point so theme
2014-03-18 11:21:15 -04:00
* stylesheet can override .
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2014-03-18 11:21:15 -04:00
*/
2014-04-06 14:54:14 -04:00
public function print_preview_css () {
2014-03-18 11:21:15 -04:00
?>
< style >
. widget - customizer - highlighted - widget {
outline : none ;
2019-03-04 17:02:52 -05: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 07:48:14 -04:00
position : relative ;
z - index : 1 ;
2014-03-18 11:21:15 -04:00
}
</ style >
< ? php
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Communicates the sidebars that appeared on the page at the very end of the page ,
* and at the very end of the wp_footer ,
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
2017-11-30 18:11:00 -05:00
*
2015-05-22 01:06:25 -04:00
* @ global array $wp_registered_sidebars
* @ global array $wp_registered_widgets
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function export_preview_data () {
2015-05-22 01:06:25 -04:00
global $wp_registered_sidebars , $wp_registered_widgets ;
2016-03-21 17:59:29 -04:00
2016-12-08 14:32:59 -05:00
$switched_locale = switch_to_locale ( get_user_locale () );
2017-11-30 18:11:00 -05:00
$l10n = array (
'widgetTooltip' => __ ( 'Shift-click to edit this widget.' ),
2016-12-08 14:32:59 -05:00
);
if ( $switched_locale ) {
restore_previous_locale ();
}
2014-12-01 19:31:22 -05:00
// Prepare Customizer settings to pass to JavaScript.
2014-03-22 17:04:15 -04:00
$settings = array (
2017-11-30 18:11:00 -05:00
'renderedSidebars' => array_fill_keys ( array_unique ( $this -> rendered_sidebars ), true ),
'renderedWidgets' => array_fill_keys ( array_keys ( $this -> rendered_widgets ), true ),
'registeredSidebars' => array_values ( $wp_registered_sidebars ),
'registeredWidgets' => $wp_registered_widgets ,
'l10n' => $l10n ,
2016-03-21 17:59:29 -04:00
'selectiveRefreshableWidgets' => $this -> get_selective_refreshable_widgets (),
2014-03-22 17:04:15 -04:00
);
foreach ( $settings [ 'registeredWidgets' ] as & $registered_widget ) {
unset ( $registered_widget [ 'callback' ] ); // may not be JSON-serializeable
}
2014-03-05 15:41:14 -05:00
?>
2014-03-22 17:04:15 -04:00
< script type = " text/javascript " >
2014-10-28 14:35:19 -04:00
var _wpWidgetCustomizerPreviewSettings = < ? php echo wp_json_encode ( $settings ); ?> ;
2014-03-05 15:41:14 -05:00
</ script >
< ? php
}
/**
2016-03-03 21:02:26 -05:00
* Tracks the widgets that were rendered .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param array $widget Rendered widget to tally .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function tally_rendered_widgets ( $widget ) {
2014-07-09 19:58:16 -04:00
$this -> rendered_widgets [ $widget [ 'id' ] ] = true ;
}
/**
* Determine if a widget is rendered on the page .
*
* @ since 4.0 . 0
*
2014-07-13 20:42:15 -04:00
* @ param string $widget_id Widget ID to check .
* @ return bool Whether the widget is rendered .
2014-07-09 19:58:16 -04:00
*/
public function is_widget_rendered ( $widget_id ) {
return in_array ( $widget_id , $this -> rendered_widgets );
}
/**
2016-03-03 21:02:26 -05:00
* Determines if a sidebar is rendered on the page .
2014-07-09 19:58:16 -04:00
*
* @ since 4.0 . 0
*
2014-07-13 20:42:15 -04:00
* @ param string $sidebar_id Sidebar ID to check .
* @ return bool Whether the sidebar is rendered .
2014-07-09 19:58:16 -04:00
*/
public function is_sidebar_rendered ( $sidebar_id ) {
return in_array ( $sidebar_id , $this -> rendered_sidebars );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Tallies the sidebars rendered via is_active_sidebar () .
2014-04-02 01:45:16 -04:00
*
2016-03-03 21:02:26 -05:00
* 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 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2014-07-13 20:42:15 -04:00
* @ param bool $is_active Whether the sidebar is active .
* @ param string $sidebar_id Sidebar ID .
2016-03-03 21:02:26 -05:00
* @ return bool Whether the sidebar is active .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function tally_sidebars_via_is_active_sidebar_calls ( $is_active , $sidebar_id ) {
2015-10-12 21:33:25 -04:00
if ( is_registered_sidebar ( $sidebar_id ) ) {
2014-03-28 10:07:14 -04:00
$this -> rendered_sidebars [] = $sidebar_id ;
2014-03-05 15:41:14 -05:00
}
2014-04-02 01:45:16 -04: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 15:41:14 -05:00
return $is_active ;
}
/**
2016-03-03 21:02:26 -05:00
* Tallies the sidebars rendered via dynamic_sidebar () .
2014-04-02 01:45:16 -04:00
*
* 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 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param bool $has_widgets Whether the current sidebar has widgets .
* @ param string $sidebar_id Sidebar ID .
2016-03-03 21:02:26 -05:00
* @ return bool Whether the current sidebar has widgets .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function tally_sidebars_via_dynamic_sidebar_calls ( $has_widgets , $sidebar_id ) {
2015-10-12 21:33:25 -04:00
if ( is_registered_sidebar ( $sidebar_id ) ) {
2014-03-28 10:07:14 -04:00
$this -> rendered_sidebars [] = $sidebar_id ;
2014-03-05 15:41:14 -05:00
}
2014-04-02 01:45:16 -04:00
2014-03-26 18:29:15 -04:00
/*
2014-04-02 01:45:16 -04: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 18:29:15 -04:00
*/
2014-03-05 15:41:14 -05:00
return $has_widgets ;
}
/**
2016-03-03 21:02:26 -05:00
* Retrieves MAC for a serialized widget instance string .
2014-03-26 18:29:15 -04:00
*
2014-08-05 02:50:15 -04:00
* Allows values posted back from JS to be rejected if any tampering of the
* data has occurred .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2014-08-05 02:50:15 -04:00
* @ param string $serialized_instance Widget instance .
* @ return string MAC for serialized widget instance .
2014-03-05 15:41:14 -05:00
*/
2014-08-05 02:50:15 -04:00
protected function get_instance_hash_key ( $serialized_instance ) {
return wp_hash ( $serialized_instance );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Sanitizes a widget instance .
2014-03-26 18:29:15 -04:00
*
2016-03-03 21:02:26 -05: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-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
* @ param array $value Widget instance to sanitize .
2015-05-24 01:40:25 -04:00
* @ return array | void Sanitized widget instance .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function sanitize_widget_instance ( $value ) {
2014-03-05 15:41:14 -05:00
if ( $value === array () ) {
return $value ;
}
2014-04-02 02:12:16 -04:00
if ( empty ( $value [ 'is_widget_customizer_js_value' ] )
|| empty ( $value [ 'instance_hash_key' ] )
2017-11-30 18:11:00 -05:00
|| empty ( $value [ 'encoded_serialized_instance' ] ) ) {
2015-05-21 18:05:24 -04:00
return ;
2014-03-05 15:41:14 -05:00
}
2014-04-02 02:12:16 -04:00
2014-03-05 15:41:14 -05:00
$decoded = base64_decode ( $value [ 'encoded_serialized_instance' ], true );
if ( false === $decoded ) {
2015-05-21 18:05:24 -04:00
return ;
2014-03-05 15:41:14 -05:00
}
2014-04-02 02:12:16 -04:00
2015-08-04 00:51:50 -04:00
if ( ! hash_equals ( $this -> get_instance_hash_key ( $decoded ), $value [ 'instance_hash_key' ] ) ) {
2015-05-21 18:05:24 -04:00
return ;
2014-03-05 15:41:14 -05:00
}
2014-08-05 02:50:15 -04:00
$instance = unserialize ( $decoded );
if ( false === $instance ) {
2015-05-21 18:05:24 -04:00
return ;
2014-03-05 15:41:14 -05:00
}
2014-08-05 02:50:15 -04:00
2014-03-05 15:41:14 -05:00
return $instance ;
}
/**
2016-03-03 21:02:26 -05:00
* Converts a widget instance into JSON - representable format .
2014-03-26 18:29:15 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ param array $value Widget instance to convert to JSON .
* @ return array JSON - converted widget instance .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function sanitize_widget_js_instance ( $value ) {
2014-03-05 15:41:14 -05:00
if ( empty ( $value [ 'is_widget_customizer_js_value' ] ) ) {
$serialized = serialize ( $value );
2014-04-02 02:12:16 -04:00
2014-03-05 15:41:14 -05:00
$value = array (
2014-04-02 02:12:16 -04:00
'encoded_serialized_instance' => base64_encode ( $serialized ),
'title' => empty ( $value [ 'title' ] ) ? '' : $value [ 'title' ],
2014-03-05 15:41:14 -05:00
'is_widget_customizer_js_value' => true ,
2014-08-05 02:50:15 -04:00
'instance_hash_key' => $this -> get_instance_hash_key ( $serialized ),
2014-03-05 15:41:14 -05:00
);
}
return $value ;
}
/**
2016-03-03 21:02:26 -05:00
* Strips out widget IDs for widgets which are no longer registered .
2014-04-02 01:45:16 -04:00
*
* One example where this might happen is when a plugin orphans a widget
* in a sidebar upon deactivation .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2015-05-22 01:06:25 -04:00
* @ global array $wp_registered_widgets
*
2014-03-26 18:29:15 -04:00
* @ param array $widget_ids List of widget IDs .
* @ return array Parsed list of widget IDs .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function sanitize_sidebar_widgets_js_instance ( $widget_ids ) {
2014-03-05 15:41:14 -05:00
global $wp_registered_widgets ;
$widget_ids = array_values ( array_intersect ( $widget_ids , array_keys ( $wp_registered_widgets ) ) );
return $widget_ids ;
}
/**
2016-03-03 21:02:26 -05:00
* Finds and invokes the widget update and control callbacks .
2014-03-26 18:29:15 -04:00
*
2016-03-03 21:02:26 -05:00
* Requires that `$_POST` be populated with the instance data .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2015-05-22 01:06:25 -04:00
* @ global array $wp_registered_widget_updates
* @ global array $wp_registered_widget_controls
*
2014-03-26 18:29:15 -04:00
* @ param string $widget_id Widget ID .
2014-04-02 01:45:16 -04:00
* @ return WP_Error | array Array containing the updated widget information .
* A WP_Error object , otherwise .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function call_widget_update ( $widget_id ) {
2014-03-05 15:41:14 -05:00
global $wp_registered_widget_updates , $wp_registered_widget_controls ;
2015-07-29 12:03:24 -04:00
$setting_id = $this -> get_setting_id ( $widget_id );
/*
* Make sure that other setting changes have previewed since this widget
2017-10-15 18:23:47 -04:00
* may depend on them ( e . g . Menus being present for Navigation Menu widget ) .
2015-07-29 12:03:24 -04:00
*/
if ( ! did_action ( 'customize_preview_init' ) ) {
foreach ( $this -> manager -> settings () as $setting ) {
if ( $setting -> id !== $setting_id ) {
$setting -> preview ();
}
}
}
2014-03-28 10:07:14 -04:00
$this -> start_capturing_option_updates ();
$parsed_id = $this -> parse_widget_id ( $widget_id );
2014-03-22 16:55:18 -04:00
$option_name = 'widget_' . $parsed_id [ 'id_base' ];
2014-03-05 15:41:14 -05:00
2014-03-26 18:29:15 -04:00
/*
2014-03-22 16:55:18 -04: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 10:07:14 -04:00
$sanitized_widget_setting = json_decode ( $this -> get_post_value ( 'sanitized_widget_setting' ), true );
2014-04-08 04:12:15 -04:00
if ( false === $sanitized_widget_setting ) {
2014-03-28 10:07:14 -04:00
$this -> stop_capturing_option_updates ();
2014-03-29 17:44:14 -04:00
return new WP_Error ( 'widget_setting_malformed' );
2014-03-05 15:41:14 -05:00
}
2014-03-28 10:07:14 -04:00
$instance = $this -> sanitize_widget_instance ( $sanitized_widget_setting );
2014-03-22 16:55:18 -04:00
if ( is_null ( $instance ) ) {
2014-03-28 10:07:14 -04:00
$this -> stop_capturing_option_updates ();
2014-03-29 17:44:14 -04:00
return new WP_Error ( 'widget_setting_unsanitized' );
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
if ( ! is_null ( $parsed_id [ 'number' ] ) ) {
2017-11-30 18:11:00 -05:00
$value = array ();
$value [ $parsed_id [ 'number' ] ] = $instance ;
$key = 'widget-' . $parsed_id [ 'id_base' ];
2019-07-02 19:42:58 -04:00
$_REQUEST [ $key ] = wp_slash ( $value );
$_POST [ $key ] = $_REQUEST [ $key ];
2017-11-30 18:11:00 -05:00
$added_input_vars [] = $key ;
2014-03-22 16:55:18 -04:00
} else {
foreach ( $instance as $key => $value ) {
2019-07-02 19:42:58 -04:00
$_REQUEST [ $key ] = wp_slash ( $value );
$_POST [ $key ] = $_REQUEST [ $key ];
2014-03-22 16:55:18 -04:00
$added_input_vars [] = $key ;
}
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
}
2014-03-05 15:41:14 -05:00
2014-03-26 18:29:15 -04:00
// Invoke the widget update callback.
2014-03-22 16:55:18 -04: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 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
}
2014-03-05 15:41:14 -05:00
2014-03-22 16:55:18 -04:00
// Clean up any input vars that were manually added
foreach ( $added_input_vars as $key ) {
2015-02-08 18:11:25 -05:00
unset ( $_POST [ $key ] );
unset ( $_REQUEST [ $key ] );
2014-03-22 16:55:18 -04:00
}
2014-03-26 18:29:15 -04:00
// Make sure the expected option was updated.
2014-03-28 10:07:14 -04:00
if ( 0 !== $this -> count_captured_options () ) {
if ( $this -> count_captured_options () > 1 ) {
$this -> stop_capturing_option_updates ();
2014-03-29 17:44:14 -04:00
return new WP_Error ( 'widget_setting_too_many_options' );
2014-03-05 15:41:14 -05:00
}
2014-03-28 10:07:14 -04:00
$updated_option_name = key ( $this -> get_captured_options () );
2014-03-22 16:55:18 -04:00
if ( $updated_option_name !== $option_name ) {
2014-03-28 10:07:14 -04:00
$this -> stop_capturing_option_updates ();
2014-03-29 17:44:14 -04:00
return new WP_Error ( 'widget_setting_unexpected_option' );
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
}
2014-03-05 15:41:14 -05:00
2015-02-08 18:11:25 -05: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-20 21:52:27 -05:00
$this -> manager -> set_post_value ( $setting_id , $this -> sanitize_widget_js_instance ( $instance ) );
2015-02-08 18:11:25 -05:00
2014-03-26 18:29:15 -04:00
// Obtain the widget control with the updated instance in place.
2014-03-22 16:55:18 -04:00
ob_start ();
2015-02-08 18:11:25 -05:00
$form = $wp_registered_widget_controls [ $widget_id ];
2014-03-22 16:55:18 -04:00
if ( $form ) {
call_user_func_array ( $form [ 'callback' ], $form [ 'params' ] );
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
$form = ob_get_clean ();
2014-03-28 10:07:14 -04:00
$this -> stop_capturing_option_updates ();
2014-04-02 02:12:16 -04:00
2014-03-22 16:55:18 -04:00
return compact ( 'instance' , 'form' );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Updates widget settings asynchronously .
2014-04-02 01:45:16 -04:00
*
* Allows the Customizer to update a widget using its form , but return the new
2014-03-05 15:41:14 -05:00
* instance info via Ajax instead of saving it to the options table .
2014-04-02 01:45:16 -04:00
*
2016-03-03 21:02:26 -05:00
* Most code here copied from wp_ajax_save_widget () .
2014-03-05 15:41:14 -05:00
*
2014-03-26 18:29:15 -04:00
* @ since 3.9 . 0
*
2014-04-02 01:45:16 -04:00
* @ see wp_ajax_save_widget ()
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
public function wp_ajax_update_widget () {
2014-03-05 15:41:14 -05:00
2014-03-22 16:55:18 -04:00
if ( ! is_user_logged_in () ) {
wp_die ( 0 );
}
2014-03-05 15:41:14 -05:00
2014-03-28 11:35:15 -04:00
check_ajax_referer ( 'update-widget' , 'nonce' );
2014-03-22 16:55:18 -04:00
if ( ! current_user_can ( 'edit_theme_options' ) ) {
wp_die ( - 1 );
}
2014-03-05 15:41:14 -05:00
2015-02-08 18:11:25 -05:00
if ( empty ( $_POST [ 'widget-id' ] ) ) {
wp_send_json_error ( 'missing_widget-id' );
2014-03-22 16:55:18 -04:00
}
2014-03-05 15:41:14 -05:00
2014-04-02 01:45:16 -04:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2019-07-04 21:45:56 -04:00
do_action ( 'load-widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-04-02 01:45:16 -04:00
/** This action is documented in wp-admin/includes/ajax-actions.php */
2019-07-04 21:45:56 -04:00
do_action ( 'widgets.php' ); // phpcs:ignore WordPress.NamingConventions.ValidHookName.UseUnderscores
2014-03-28 15:47:15 -04:00
/** This action is documented in wp-admin/widgets.php */
2014-03-22 16:55:18 -04:00
do_action ( 'sidebar_admin_setup' );
2014-03-05 15:41:14 -05:00
2014-03-28 10:07:14 -04:00
$widget_id = $this -> get_post_value ( 'widget-id' );
$parsed_id = $this -> parse_widget_id ( $widget_id );
2017-11-30 18:11:00 -05:00
$id_base = $parsed_id [ 'id_base' ];
2015-02-08 18:11:25 -05:00
$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 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
2014-03-28 10:07:14 -04:00
$updated_widget = $this -> call_widget_update ( $widget_id ); // => {instance,form}
2014-03-22 16:55:18 -04:00
if ( is_wp_error ( $updated_widget ) ) {
2015-05-25 18:09:25 -04:00
wp_send_json_error ( $updated_widget -> get_error_code () );
2014-03-05 15:41:14 -05:00
}
2014-03-22 16:55:18 -04:00
2017-11-30 18:11:00 -05:00
$form = $updated_widget [ 'form' ];
2014-03-28 10:07:14 -04:00
$instance = $this -> sanitize_widget_js_instance ( $updated_widget [ 'instance' ] );
2014-03-22 16:55:18 -04:00
wp_send_json_success ( compact ( 'form' , 'instance' ) );
2014-03-05 15:41:14 -05:00
}
2016-02-19 13:41:28 -05:00
/*
* Selective Refresh Methods
*/
/**
2016-03-03 20:45:26 -05:00
* Filters arguments for dynamic widget partials .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*
2016-03-03 20:45:26 -05:00
* @ param array | false $partial_args Partial arguments .
* @ param string $partial_id Partial ID .
* @ return array ( Maybe ) modified partial arguments .
2016-02-19 13:41:28 -05:00
*/
public function customize_dynamic_partial_args ( $partial_args , $partial_id ) {
2016-03-21 17:59:29 -04:00
if ( ! current_theme_supports ( 'customize-selective-refresh-widgets' ) ) {
return $partial_args ;
}
2016-02-19 13:41:28 -05:00
2016-02-24 13:28:28 -05:00
if ( preg_match ( '/^widget\[(?P<widget_id>.+)\]$/' , $partial_id , $matches ) ) {
2016-02-19 13:41:28 -05:00
if ( false === $partial_args ) {
$partial_args = array ();
}
$partial_args = array_merge (
$partial_args ,
array (
2016-02-24 13:28:28 -05:00
'type' => 'widget' ,
'render_callback' => array ( $this , 'render_widget_partial' ),
2016-02-19 13:41:28 -05:00
'container_inclusive' => true ,
2016-02-24 13:28:28 -05:00
'settings' => array ( $this -> get_setting_id ( $matches [ 'widget_id' ] ) ),
'capability' => 'edit_theme_options' ,
2016-02-19 13:41:28 -05:00
)
);
}
return $partial_args ;
}
/**
2016-03-03 21:02:26 -05:00
* Adds hooks for selective refresh .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*/
public function selective_refresh_init () {
2016-03-21 17:59:29 -04:00
if ( ! current_theme_supports ( 'customize-selective-refresh-widgets' ) ) {
2016-02-19 13:41:28 -05:00
return ;
}
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' ) );
}
/**
* Inject selective refresh data attributes into widget container elements .
*
2017-12-14 19:35:47 -05:00
* @ since 4.5 . 0
*
2016-02-19 13:41:28 -05:00
* @ param array $params {
* Dynamic sidebar params .
*
* @ type array $args Sidebar args .
* @ type array $widget_args Widget args .
* }
2018-01-31 20:20:30 -05:00
* @ see WP_Customize_Nav_Menus :: filter_wp_nav_menu_args ()
2016-02-19 13:41:28 -05:00
*
* @ return array Params .
*/
public function filter_dynamic_sidebar_params ( $params ) {
$sidebar_args = array_merge (
array (
'before_widget' => '' ,
2017-11-30 18:11:00 -05:00
'after_widget' => '' ,
2016-02-19 13:41:28 -05:00
),
$params [ 0 ]
);
// Skip widgets not in a registered sidebar or ones which lack a proper wrapper element to attach the data-* attributes to.
2017-11-30 18:11:00 -05:00
$matches = array ();
2016-02-19 13:41:28 -05:00
$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 ;
2017-11-30 18:11:00 -05:00
} elseif ( isset ( $sidebar_args [ 'id' ] ) && isset ( $this -> sidebar_instance_count [ $sidebar_args [ 'id' ] ] ) ) {
2016-02-19 13:41:28 -05:00
$context [ 'sidebar_instance_number' ] = $this -> sidebar_instance_count [ $sidebar_args [ 'id' ] ];
}
2017-11-30 18:11:00 -05:00
$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' ] ) );
2016-02-19 13:41:28 -05:00
$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 .
*
2016-03-03 21:02:26 -05:00
* This is used in the { @ see 'filter_wp_kses_allowed_html' } filter to ensure that the
2016-02-19 13:41:28 -05:00
* data -* attributes can be whitelisted .
*
* @ since 4.5 . 0
* @ var array
*/
protected $before_widget_tags_seen = array ();
/**
2016-03-03 21:02:26 -05:00
* Ensures the HTML data -* attributes for selective refresh are allowed by kses .
2016-02-19 13:41:28 -05:00
*
2016-03-03 21:02:26 -05:00
* This is needed in case the `$before_widget` is run through wp_kses () when printed .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*
* @ param array $allowed_html Allowed HTML .
2016-03-03 21:02:26 -05:00
* @ return array ( Maybe ) modified allowed HTML .
2016-02-19 13:41:28 -05:00
*/
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 ],
2017-11-30 18:11:00 -05:00
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' ,
2018-08-16 21:51:36 -04:00
),
true
2017-11-30 18:11:00 -05:00
)
2016-02-19 13:41:28 -05:00
);
}
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
* @ var array
*/
protected $sidebar_instance_count = array ();
/**
* The current request ' s sidebar_instance_number context .
*
* @ since 4.5 . 0
2019-05-25 22:16:52 -04:00
* @ var int | null
2016-02-19 13:41:28 -05:00
*/
protected $context_sidebar_instance_number ;
/**
* Current sidebar ID being rendered .
*
* @ since 4.5 . 0
* @ var array
*/
protected $current_dynamic_sidebar_id_stack = array ();
/**
2016-03-03 21:02:26 -05:00
* Begins keeping track of the current sidebar being rendered .
2016-02-19 13:41:28 -05:00
*
* 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 ] ) );
}
}
/**
2016-03-03 21:02:26 -05:00
* Finishes keeping track of the current sidebar being rendered .
2016-02-19 13:41:28 -05:00
*
2016-03-03 21:02:26 -05:00
* Inserts a marker after widgets are rendered in a dynamic sidebar .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*
* @ param int | string $index Index , name , or ID of the dynamic sidebar .
*/
public function end_dynamic_sidebar ( $index ) {
2016-02-22 20:22:26 -05:00
array_shift ( $this -> current_dynamic_sidebar_id_stack );
2016-02-19 13:41:28 -05:00
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
2019-05-25 22:16:52 -04:00
* @ var string | null
2016-02-19 13:41:28 -05:00
*/
protected $rendering_widget_id ;
/**
* Current widget being rendered .
*
* @ since 4.5 . 0
2019-05-25 22:16:52 -04:00
* @ var string | null
2016-02-19 13:41:28 -05:00
*/
protected $rendering_sidebar_id ;
/**
2016-03-03 21:02:26 -05:00
* Filters sidebars_widgets to ensure the currently - rendered widget is the only widget in the current sidebar .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*
* @ param array $sidebars_widgets Sidebars widgets .
2016-03-03 21:02:26 -05:00
* @ return array Filtered sidebars widgets .
2016-02-19 13:41:28 -05:00
*/
public function filter_sidebars_widgets_for_rendering_widget ( $sidebars_widgets ) {
$sidebars_widgets [ $this -> rendering_sidebar_id ] = array ( $this -> rendering_widget_id );
return $sidebars_widgets ;
}
/**
2016-03-03 21:02:26 -05:00
* Renders a specific widget using the supplied sidebar arguments .
2016-02-19 13:41:28 -05:00
*
* @ since 4.5 . 0
*
* @ see dynamic_sidebar ()
*
2016-03-03 21:02:26 -05:00
* @ param WP_Customize_Partial $partial Partial .
2016-02-19 13:41:28 -05:00
* @ param array $context {
* Sidebar args supplied as container context .
*
2016-03-03 21:02:26 -05:00
* @ type string $sidebar_id ID for sidebar for widget to render into .
* @ type int $sidebar_instance_number Disambiguating instance number .
2016-02-19 13:41:28 -05:00
* }
* @ 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 ();
2019-07-02 19:42:58 -04:00
$this -> rendering_sidebar_id = $context [ 'sidebar_id' ];
dynamic_sidebar ( $this -> rendering_sidebar_id );
$container = ob_get_clean ();
2016-02-19 13:41:28 -05:00
// Reset variables for next partial render.
remove_filter ( 'sidebars_widgets' , $filter_callback , 1000 );
$this -> context_sidebar_instance_number = null ;
2017-11-30 18:11:00 -05:00
$this -> rendering_sidebar_id = null ;
$this -> rendering_widget_id = null ;
2016-02-19 13:41:28 -05:00
return $container ;
}
//
// Option Update Capturing
//
2014-03-05 15:41:14 -05:00
/**
2014-04-02 01:45:16 -04:00
* List of captured widget option updates .
*
* @ since 3.9 . 0
* @ var array $_captured_options Values updated while option capture is happening .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected $_captured_options = array ();
2014-03-05 15:41:14 -05:00
/**
2014-04-02 01:45:16 -04:00
* Whether option capture is currently happening .
*
* @ since 3.9 . 0
* @ var bool $_is_current Whether option capture is currently happening or not .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected $_is_capturing_option_updates = false ;
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Determines whether the captured option update should be ignored .
2014-04-02 01:45:16 -04:00
*
* @ since 3.9 . 0
*
* @ param string $option_name Option name .
2015-06-26 21:03:25 -04:00
* @ return bool Whether the option capture is ignored .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function is_option_capture_ignored ( $option_name ) {
return ( 0 === strpos ( $option_name , '_transient_' ) );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Retrieves captured widget option updates .
2014-04-02 01:45:16 -04:00
*
* @ since 3.9 . 0
*
* @ return array Array of captured options .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function get_captured_options () {
return $this -> _captured_options ;
2014-03-05 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
/**
2016-03-03 21:02:26 -05:00
* Retrieves the option that was captured from being saved .
2015-02-08 18:11:25 -05:00
*
* @ since 4.2 . 0
*
* @ param string $option_name Option name .
2016-03-03 21:02:26 -05:00
* @ param mixed $default Optional . Default value to return if the option does not exist . Default false .
2015-02-08 18:11:25 -05:00
* @ 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 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Retrieves the number of captured widget option updates .
2014-04-02 01:45:16 -04:00
*
* @ since 3.9 . 0
*
* @ return int Number of updated options .
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function count_captured_options () {
return count ( $this -> _captured_options );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Begins keeping track of changes to widget options , caching new values .
2014-04-02 01:45:16 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function start_capturing_option_updates () {
if ( $this -> _is_capturing_option_updates ) {
2014-03-05 15:41:14 -05:00
return ;
}
2014-03-28 10:07:14 -04:00
$this -> _is_capturing_option_updates = true ;
2014-04-02 02:12:16 -04:00
2014-04-02 14:31:15 -04:00
add_filter ( 'pre_update_option' , array ( $this , 'capture_filter_pre_update_option' ), 10 , 3 );
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Pre - filters captured option values before updating .
2014-04-02 01:45:16 -04:00
*
2014-04-02 02:12:16 -04:00
* @ since 3.9 . 0
*
2015-02-08 18:11:25 -05: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 15:41:14 -05:00
*/
2014-04-02 14:31:15 -04:00
public function capture_filter_pre_update_option ( $new_value , $option_name , $old_value ) {
2014-03-28 10:07:14 -04:00
if ( $this -> is_option_capture_ignored ( $option_name ) ) {
2019-07-16 17:33:57 -04:00
return $new_value ;
2014-03-05 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
if ( ! isset ( $this -> _captured_options [ $option_name ] ) ) {
2014-04-02 14:31:15 -04:00
add_filter ( " pre_option_ { $option_name } " , array ( $this , 'capture_filter_pre_get_option' ) );
2014-03-28 10:07:14 -04:00
}
2015-02-08 18:11:25 -05:00
$this -> _captured_options [ $option_name ] = $new_value ;
2014-03-28 10:07:14 -04:00
return $old_value ;
}
2014-03-05 15:41:14 -05:00
/**
2016-03-03 21:02:26 -05:00
* Pre - filters captured option values before retrieving .
2014-04-02 01:45:16 -04:00
*
2014-04-02 02:12:16 -04:00
* @ since 3.9 . 0
*
2015-02-08 18:11:25 -05:00
* @ param mixed $value Value to return instead of the option value .
* @ return mixed Filtered option value .
2014-03-05 15:41:14 -05:00
*/
2014-04-02 14:31:15 -04:00
public function capture_filter_pre_get_option ( $value ) {
2014-03-28 10:07:14 -04:00
$option_name = preg_replace ( '/^pre_option_/' , '' , current_filter () );
2014-04-02 02:12:16 -04:00
2015-02-08 18:11:25 -05:00
if ( isset ( $this -> _captured_options [ $option_name ] ) ) {
$value = $this -> _captured_options [ $option_name ];
2014-04-14 14:41:17 -04:00
/** This filter is documented in wp-includes/option.php */
2018-08-11 08:45:26 -04:00
$value = apply_filters ( 'option_' . $option_name , $value , $option_name );
2014-03-05 15:41:14 -05:00
}
2014-03-28 10:07:14 -04:00
return $value ;
2014-03-05 15:41:14 -05:00
}
/**
2016-03-03 21:02:26 -05:00
* Undoes any changes to the options since options capture began .
2014-04-02 01:45:16 -04:00
*
* @ since 3.9 . 0
2014-03-05 15:41:14 -05:00
*/
2014-03-28 10:07:14 -04:00
protected function stop_capturing_option_updates () {
if ( ! $this -> _is_capturing_option_updates ) {
2014-03-05 15:41:14 -05:00
return ;
}
2016-02-19 13:41:28 -05:00
remove_filter ( 'pre_update_option' , array ( $this , 'capture_filter_pre_update_option' ), 10 );
2014-04-02 14:31:15 -04:00
2014-03-28 10:07:14 -04:00
foreach ( array_keys ( $this -> _captured_options ) as $option_name ) {
2014-04-02 14:31:15 -04:00
remove_filter ( " pre_option_ { $option_name } " , array ( $this , 'capture_filter_pre_get_option' ) );
2014-03-05 15:41:14 -05:00
}
2014-03-28 10:07:14 -04:00
2017-11-30 18:11:00 -05:00
$this -> _captured_options = array ();
2014-03-28 10:07:14 -04:00
$this -> _is_capturing_option_updates = false ;
2014-03-05 15:41:14 -05:00
}
2015-02-08 18:11:25 -05:00
/**
2016-05-23 14:54:27 -04:00
* { @ internal Missing Summary }
*
* See the { @ see 'customize_dynamic_setting_args' } filter .
*
2015-02-08 18:11:25 -05:00
* @ since 3.9 . 0
2016-05-23 14:54:27 -04:00
* @ deprecated 4.2 . 0 Deprecated in favor of the { @ see 'customize_dynamic_setting_args' } filter .
2015-02-08 18:11:25 -05:00
*/
public function setup_widget_addition_previews () {
2017-06-24 20:05:44 -04:00
_deprecated_function ( __METHOD__ , '4.2.0' , 'customize_dynamic_setting_args' );
2015-02-08 18:11:25 -05:00
}
/**
2016-05-23 14:54:27 -04:00
* { @ internal Missing Summary }
*
* See the { @ see 'customize_dynamic_setting_args' } filter .
*
2015-02-08 18:11:25 -05:00
* @ since 3.9 . 0
2016-05-23 14:54:27 -04:00
* @ deprecated 4.2 . 0 Deprecated in favor of the { @ see 'customize_dynamic_setting_args' } filter .
2015-02-08 18:11:25 -05:00
*/
public function prepreview_added_sidebars_widgets () {
2017-06-24 20:05:44 -04:00
_deprecated_function ( __METHOD__ , '4.2.0' , 'customize_dynamic_setting_args' );
2015-02-08 18:11:25 -05:00
}
/**
2016-05-23 14:54:27 -04:00
* { @ internal Missing Summary }
*
* See the { @ see 'customize_dynamic_setting_args' } filter .
*
2015-02-08 18:11:25 -05:00
* @ since 3.9 . 0
2016-05-23 14:54:27 -04:00
* @ deprecated 4.2 . 0 Deprecated in favor of the { @ see 'customize_dynamic_setting_args' } filter .
2015-02-08 18:11:25 -05:00
*/
public function prepreview_added_widget_instance () {
2017-06-24 20:05:44 -04:00
_deprecated_function ( __METHOD__ , '4.2.0' , 'customize_dynamic_setting_args' );
2015-02-08 18:11:25 -05:00
}
/**
2016-05-23 14:54:27 -04:00
* { @ internal Missing Summary }
*
* See the { @ see 'customize_dynamic_setting_args' } filter .
*
2015-02-08 18:11:25 -05:00
* @ since 3.9 . 0
2016-05-23 14:54:27 -04:00
* @ deprecated 4.2 . 0 Deprecated in favor of the { @ see 'customize_dynamic_setting_args' } filter .
2015-02-08 18:11:25 -05:00
*/
public function remove_prepreview_filters () {
2017-06-24 20:05:44 -04:00
_deprecated_function ( __METHOD__ , '4.2.0' , 'customize_dynamic_setting_args' );
2015-02-08 18:11:25 -05:00
}
2014-03-05 15:41:14 -05:00
}