Changeset 31370 for trunk/src/wp-includes/class-wp-customize-widgets.php
- Timestamp:
- 02/08/2015 11:10:05 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/wp-includes/class-wp-customize-widgets.php
r31226 r31370 36 36 * @since 3.9.0 37 37 * @access protected 38 * @var 39 */ 40 protected $ _customized;38 * @var array 39 */ 40 protected $rendered_sidebars = array(); 41 41 42 42 /** … … 45 45 * @var array 46 46 */ 47 protected $ _prepreview_added_filters = array();47 protected $rendered_widgets = array(); 48 48 49 49 /** … … 52 52 * @var array 53 53 */ 54 protected $rendered_sidebars = array(); 55 56 /** 57 * @since 3.9.0 54 protected $old_sidebars_widgets = array(); 55 56 /** 57 * Mapping of setting type to setting ID pattern. 58 * 59 * @since 4.2.0 58 60 * @access protected 59 61 * @var array 60 62 */ 61 protected $rendered_widgets = array(); 62 63 /** 64 * @since 3.9.0 65 * @access protected 66 * @var array 67 */ 68 protected $old_sidebars_widgets = array(); 63 protected $setting_id_patterns = array( 64 'widget_instance' => '/^(widget_.+?)(?:\[(\d+)\])?$/', 65 'sidebar_widgets' => '/^sidebars_widgets\[(.+?)\]$/', 66 ); 69 67 70 68 /** … … 79 77 $this->manager = $manager; 80 78 81 add_action( 'after_setup_theme', array( $this, 'setup_widget_addition_previews' ) ); 79 add_filter( 'customize_dynamic_setting_args', array( $this, 'filter_customize_dynamic_setting_args' ), 10, 2 ); 80 add_action( 'after_setup_theme', array( $this, 'register_settings' ) ); 82 81 add_action( 'wp_loaded', array( $this, 'override_sidebars_widgets_for_theme_switch' ) ); 83 82 add_action( 'customize_controls_init', array( $this, 'customize_controls_init' ) ); … … 96 95 97 96 /** 97 * Get the widget setting type given a setting ID. 98 * 99 * @since 4.2.0 100 * 101 * @param $setting_id 102 * 103 * @return string|null 104 */ 105 protected function get_setting_type( $setting_id ) { 106 static $cache = array(); 107 if ( isset( $cache[ $setting_id ] ) ) { 108 return $cache[ $setting_id ]; 109 } 110 foreach ( $this->setting_id_patterns as $type => $pattern ) { 111 if ( preg_match( $pattern, $setting_id ) ) { 112 $cache[ $setting_id ] = $type; 113 return $type; 114 } 115 } 116 return null; 117 } 118 119 /** 120 * Inspect the incoming customized data for any widget settings, and dynamically add them up-front so widgets will be initialized properly. 121 * 122 * @since 4.2.0 123 */ 124 public function register_settings() { 125 $widget_setting_ids = array(); 126 $incoming_setting_ids = array_keys( $this->manager->unsanitized_post_values() ); 127 foreach ( $incoming_setting_ids as $setting_id ) { 128 if ( ! is_null( $this->get_setting_type( $setting_id ) ) ) { 129 $widget_setting_ids[] = $setting_id; 130 } 131 } 132 if ( $this->manager->doing_ajax( 'update-widget' ) && isset( $_REQUEST['widget-id'] ) ) { 133 $widget_setting_ids[] = $this->get_setting_id( wp_unslash( $_REQUEST['widget-id'] ) ); 134 } 135 136 $settings = $this->manager->add_dynamic_settings( array_unique( $widget_setting_ids ) ); 137 138 /* 139 * Preview settings right away so that widgets and sidebars will get registered properly. 140 * But don't do this if a customize_save because this will cause WP to think there is nothing 141 * changed that needs to be saved. 142 */ 143 if ( ! $this->manager->doing_ajax( 'customize_save' ) ) { 144 foreach ( $settings as $setting ) { 145 $setting->preview(); 146 } 147 } 148 } 149 150 /** 151 * Determine the arguments for a dynamically-created setting. 152 * 153 * @since 4.2.0 154 * 155 * @param false|array $args 156 * @param string $setting_id 157 * @return false|array 158 */ 159 public function filter_customize_dynamic_setting_args( $args, $setting_id ) { 160 if ( $this->get_setting_type( $setting_id ) ) { 161 $args = $this->get_setting_args( $setting_id ); 162 } 163 return $args; 164 } 165 166 /** 98 167 * Get an unslashed post value or return a default. 99 168 * … … 111 180 } 112 181 113 return wp_unslash( $_POST[$name] ); 114 } 115 116 /** 117 * Set up widget addition previews. 118 * 119 * Since the widgets get registered on 'widgets_init' before the Customizer 120 * settings are set up on 'customize_register', we have to filter the options 121 * similarly to how the setting previewer will filter the options later. 122 * 123 * @since 3.9.0 124 * 125 * @access public 126 */ 127 public function setup_widget_addition_previews() { 128 $is_customize_preview = false; 129 130 if ( ! empty( $this->manager ) && ! is_admin() && 'on' === $this->get_post_value( 'wp_customize' ) ) { 131 $is_customize_preview = check_ajax_referer( 'preview-customize_' . $this->manager->get_stylesheet(), 'nonce', false ); 132 } 133 134 $is_ajax_widget_update = false; 135 if ( $this->manager->doing_ajax() && 'update-widget' === $this->get_post_value( 'action' ) ) { 136 $is_ajax_widget_update = check_ajax_referer( 'update-widget', 'nonce', false ); 137 } 138 139 $is_ajax_customize_save = false; 140 if ( $this->manager->doing_ajax() && 'customize_save' === $this->get_post_value( 'action' ) ) { 141 $is_ajax_customize_save = check_ajax_referer( 'save-customize_' . $this->manager->get_stylesheet(), 'nonce', false ); 142 } 143 144 $is_valid_request = ( $is_ajax_widget_update || $is_customize_preview || $is_ajax_customize_save ); 145 if ( ! $is_valid_request ) { 146 return; 147 } 148 149 // Input from Customizer preview. 150 if ( isset( $_POST['customized'] ) ) { 151 $this->_customized = json_decode( $this->get_post_value( 'customized' ), true ); 152 } else { // Input from ajax widget update request. 153 $this->_customized = array(); 154 $id_base = $this->get_post_value( 'id_base' ); 155 $widget_number = $this->get_post_value( 'widget_number', false ); 156 $option_name = 'widget_' . $id_base; 157 $this->_customized[ $option_name ] = array(); 158 if ( preg_match( '/^[0-9]+$/', $widget_number ) ) { 159 $option_name .= '[' . $widget_number . ']'; 160 $this->_customized[ $option_name ][ $widget_number ] = array(); 161 } 162 } 163 164 $function = array( $this, 'prepreview_added_sidebars_widgets' ); 165 166 $hook = 'option_sidebars_widgets'; 167 add_filter( $hook, $function ); 168 $this->_prepreview_added_filters[] = compact( 'hook', 'function' ); 169 170 $hook = 'default_option_sidebars_widgets'; 171 add_filter( $hook, $function ); 172 $this->_prepreview_added_filters[] = compact( 'hook', 'function' ); 173 174 $function = array( $this, 'prepreview_added_widget_instance' ); 175 foreach ( $this->_customized as $setting_id => $value ) { 176 if ( preg_match( '/^(widget_.+?)(?:\[(\d+)\])?$/', $setting_id, $matches ) ) { 177 $option = $matches[1]; 178 179 $hook = sprintf( 'option_%s', $option ); 180 if ( ! has_filter( $hook, $function ) ) { 181 add_filter( $hook, $function ); 182 $this->_prepreview_added_filters[] = compact( 'hook', 'function' ); 183 } 184 185 $hook = sprintf( 'default_option_%s', $option ); 186 if ( ! has_filter( $hook, $function ) ) { 187 add_filter( $hook, $function ); 188 $this->_prepreview_added_filters[] = compact( 'hook', 'function' ); 189 } 190 191 /* 192 * Make sure the option is registered so that the update_option() 193 * won't fail due to the filters providing a default value, which 194 * causes the update_option() to get confused. 195 */ 196 add_option( $option, array() ); 197 } 198 } 199 } 200 201 /** 202 * Ensure that newly-added widgets will appear in the widgets_sidebars. 203 * 204 * This is necessary because the Customizer's setting preview filters 205 * are added after the widgets_init action, which is too late for the 206 * widgets to be set up properly. 207 * 208 * @since 3.9.0 209 * @access public 210 * 211 * @param array $sidebars_widgets Associative array of sidebars and their widgets. 212 * @return array Filtered array of sidebars and their widgets. 213 */ 214 public function prepreview_added_sidebars_widgets( $sidebars_widgets ) { 215 foreach ( $this->_customized as $setting_id => $value ) { 216 if ( preg_match( '/^sidebars_widgets\[(.+?)\]$/', $setting_id, $matches ) ) { 217 $sidebar_id = $matches[1]; 218 $sidebars_widgets[ $sidebar_id ] = $value; 219 } 220 } 221 return $sidebars_widgets; 222 } 223 224 /** 225 * Ensure newly-added widgets have empty instances so they 226 * will be recognized. 227 * 228 * This is necessary because the Customizer's setting preview 229 * filters are added after the widgets_init action, which is 230 * too late for the widgets to be set up properly. 231 * 232 * @since 3.9.0 233 * @access public 234 * 235 * @param array|bool|mixed $value Widget instance(s), false if open was empty. 236 * @return array|mixed Widget instance(s) with additions. 237 */ 238 public function prepreview_added_widget_instance( $value = false ) { 239 if ( ! preg_match( '/^(?:default_)?option_(widget_(.+))/', current_filter(), $matches ) ) { 240 return $value; 241 } 242 $id_base = $matches[2]; 243 244 foreach ( $this->_customized as $setting_id => $setting ) { 245 $parsed_setting_id = $this->parse_widget_setting_id( $setting_id ); 246 if ( is_wp_error( $parsed_setting_id ) || $id_base !== $parsed_setting_id['id_base'] ) { 247 continue; 248 } 249 $widget_number = $parsed_setting_id['number']; 250 251 if ( is_null( $widget_number ) ) { 252 // Single widget. 253 if ( false === $value ) { 254 $value = array(); 255 } 256 } else { 257 // Multi widget. 258 if ( empty( $value ) ) { 259 $value = array( '_multiwidget' => 1 ); 260 } 261 if ( ! isset( $value[ $widget_number ] ) ) { 262 $value[ $widget_number ] = array(); 263 } 264 } 265 } 266 267 return $value; 268 } 269 270 /** 271 * Remove pre-preview filters. 272 * 273 * Removes filters added in setup_widget_addition_previews() 274 * to ensure widgets are populating the options during 275 * 'widgets_init'. 276 * 277 * @since 3.9.0 278 * @access public 279 */ 280 public function remove_prepreview_filters() { 281 foreach ( $this->_prepreview_added_filters as $prepreview_added_filter ) { 282 remove_filter( $prepreview_added_filter['hook'], $prepreview_added_filter['function'] ); 283 } 284 $this->_prepreview_added_filters = array(); 182 return wp_unslash( $_POST[ $name ] ); 285 183 } 286 184 … … 381 279 */ 382 280 public function schedule_customize_register() { 383 if ( is_admin() ) { // @todo for some reason, $wp_customize->is_preview() is true here?281 if ( is_admin() ) { 384 282 $this->customize_register(); 385 283 } else { … … 413 311 $setting_id = $this->get_setting_id( $widget_id ); 414 312 $setting_args = $this->get_setting_args( $setting_id ); 415 416 $setting_args['sanitize_callback'] = array( $this, 'sanitize_widget_instance' ); 417 $setting_args['sanitize_js_callback'] = array( $this, 'sanitize_widget_js_instance' ); 418 419 $this->manager->add_setting( $setting_id, $setting_args ); 420 313 if ( ! $this->manager->get_setting( $setting_id ) ) { 314 $this->manager->add_setting( $setting_id, $setting_args ); 315 } 421 316 $new_setting_ids[] = $setting_id; 422 317 } … … 453 348 $setting_id = sprintf( 'sidebars_widgets[%s]', $sidebar_id ); 454 349 $setting_args = $this->get_setting_args( $setting_id ); 455 456 $setting_args['sanitize_callback'] = array( $this, 'sanitize_sidebar_widgets' ); 457 $setting_args['sanitize_js_callback'] = array( $this, 'sanitize_sidebar_widgets_js_instance' ); 458 459 $this->manager->add_setting( $setting_id, $setting_args ); 350 if ( ! $this->manager->get_setting( $setting_id ) ) { 351 $this->manager->add_setting( $setting_id, $setting_args ); 352 } 460 353 $new_setting_ids[] = $setting_id; 461 354 … … 524 417 } 525 418 526 /* 527 * We have to register these settings later than customize_preview_init 528 * so that other filters have had a chance to run. 529 */ 530 if ( did_action( 'customize_preview_init' ) ) { 419 if ( ! $this->manager->doing_ajax( 'customize_save' ) ) { 531 420 foreach ( $new_setting_ids as $new_setting_id ) { 532 421 $this->manager->get_setting( $new_setting_id )->preview(); 533 422 } 534 423 } 535 $this->remove_prepreview_filters(); 424 425 add_filter( 'sidebars_widgets', array( $this, 'preview_sidebars_widgets' ), 1 ); 536 426 } 537 427 … … 805 695 'default' => array(), 806 696 ); 697 698 if ( preg_match( $this->setting_id_patterns['sidebar_widgets'], $id, $matches ) ) { 699 $args['sanitize_callback'] = array( $this, 'sanitize_sidebar_widgets' ); 700 $args['sanitize_js_callback'] = array( $this, 'sanitize_sidebar_widgets_js_instance' ); 701 } else if ( preg_match( $this->setting_id_patterns['widget_instance'], $id, $matches ) ) { 702 $args['sanitize_callback'] = array( $this, 'sanitize_widget_instance' ); 703 $args['sanitize_js_callback'] = array( $this, 'sanitize_widget_js_instance' ); 704 } 705 807 706 $args = array_merge( $args, $overrides ); 808 707 … … 832 731 */ 833 732 public function sanitize_sidebar_widgets( $widget_ids ) { 834 global $wp_registered_widgets; 835 836 $widget_ids = array_map( 'strval', (array) $widget_ids ); 733 $widget_ids = array_map( 'strval', (array) $widget_ids ); 837 734 $sanitized_widget_ids = array(); 838 839 735 foreach ( $widget_ids as $widget_id ) { 840 if ( array_key_exists( $widget_id, $wp_registered_widgets ) ) { 841 $sanitized_widget_ids[] = $widget_id; 842 } 736 $sanitized_widget_ids[] = preg_replace( '/[^a-z0-9_\-]/', '', $widget_id ); 843 737 } 844 738 return $sanitized_widget_ids; … … 975 869 */ 976 870 public function customize_preview_init() { 977 add_filter( 'sidebars_widgets', array( $this, 'preview_sidebars_widgets' ), 1 );978 871 add_action( 'wp_enqueue_scripts', array( $this, 'customize_preview_enqueue' ) ); 979 872 add_action( 'wp_print_styles', array( $this, 'print_preview_css' ), 1 ); … … 1316 1209 // Clean up any input vars that were manually added 1317 1210 foreach ( $added_input_vars as $key ) { 1318 unset( $_POST[ $key] );1319 unset( $_REQUEST[ $key] );1211 unset( $_POST[ $key ] ); 1212 unset( $_REQUEST[ $key ] ); 1320 1213 } 1321 1214 … … 1334 1227 } 1335 1228 1229 // Obtain the widget instance. 1230 $option = $this->get_captured_option( $option_name ); 1231 if ( null !== $parsed_id['number'] ) { 1232 $instance = $option[ $parsed_id['number'] ]; 1233 } else { 1234 $instance = $option; 1235 } 1236 1237 /* 1238 * Override the incoming $_POST['customized'] for a newly-created widget's 1239 * setting with the new $instance so that the preview filter currently 1240 * in place from WP_Customize_Setting::preview() will use this value 1241 * instead of the default widget instance value (an empty array). 1242 */ 1243 $setting_id = $this->get_setting_id( $widget_id ); 1244 $this->manager->set_post_value( $setting_id, $instance ); 1245 1336 1246 // Obtain the widget control with the updated instance in place. 1337 1247 ob_start(); 1338 1339 $form = $wp_registered_widget_controls[$widget_id]; 1248 $form = $wp_registered_widget_controls[ $widget_id ]; 1340 1249 if ( $form ) { 1341 1250 call_user_func_array( $form['callback'], $form['params'] ); 1342 1251 } 1343 1344 1252 $form = ob_get_clean(); 1345 1346 // Obtain the widget instance.1347 $option = get_option( $option_name );1348 1349 if ( null !== $parsed_id['number'] ) {1350 $instance = $option[$parsed_id['number']];1351 } else {1352 $instance = $option;1353 }1354 1253 1355 1254 $this->stop_capturing_option_updates(); … … 1384 1283 } 1385 1284 1386 if ( ! isset( $_POST['widget-id'] ) ) {1387 wp_send_json_error( );1285 if ( empty( $_POST['widget-id'] ) ) { 1286 wp_send_json_error( 'missing_widget-id' ); 1388 1287 } 1389 1288 … … 1399 1298 $widget_id = $this->get_post_value( 'widget-id' ); 1400 1299 $parsed_id = $this->parse_widget_id( $widget_id ); 1401 $id_base = $parsed_id['id_base']; 1402 1403 if ( isset( $_POST['widget-' . $id_base] ) && is_array( $_POST['widget-' . $id_base] ) && preg_match( '/__i__|%i%/', key( $_POST['widget-' . $id_base] ) ) ) { 1404 wp_send_json_error(); 1300 $id_base = $parsed_id['id_base']; 1301 1302 $is_updating_widget_template = ( 1303 isset( $_POST[ 'widget-' . $id_base ] ) 1304 && 1305 is_array( $_POST[ 'widget-' . $id_base ] ) 1306 && 1307 preg_match( '/__i__|%i%/', key( $_POST[ 'widget-' . $id_base ] ) ) 1308 ); 1309 if ( $is_updating_widget_template ) { 1310 wp_send_json_error( 'template_widget_not_updatable' ); 1405 1311 } 1406 1312 1407 1313 $updated_widget = $this->call_widget_update( $widget_id ); // => {instance,form} 1408 1314 if ( is_wp_error( $updated_widget ) ) { 1409 wp_send_json_error( );1315 wp_send_json_error( $updated_widget->get_error_message() ); 1410 1316 } 1411 1317 … … 1464 1370 1465 1371 /** 1372 * Get the option that was captured from being saved. 1373 * 1374 * @since 4.2.0 1375 * @access protected 1376 * 1377 * @param string $option_name Option name. 1378 * @param mixed $default Optional. Default value to return if the option does not exist. 1379 * @return mixed Value set for the option. 1380 */ 1381 protected function get_captured_option( $option_name, $default = false ) { 1382 if ( array_key_exists( $option_name, $this->_captured_options ) ) { 1383 $value = $this->_captured_options[ $option_name ]; 1384 } else { 1385 $value = $default; 1386 } 1387 return $value; 1388 } 1389 1390 /** 1466 1391 * Get the number of captured widget option updates. 1467 1392 * … … 1497 1422 * @access public 1498 1423 * 1499 * @param mixed $new_value1500 * @param string $option_name 1501 * @param mixed $old_value1502 * @return mixed 1424 * @param mixed $new_value The new option value. 1425 * @param string $option_name Name of the option. 1426 * @param mixed $old_value The old option value. 1427 * @return mixed Filtered option value. 1503 1428 */ 1504 1429 public function capture_filter_pre_update_option( $new_value, $option_name, $old_value ) { … … 1507 1432 } 1508 1433 1509 if ( ! isset( $this->_captured_options[ $option_name] ) ) {1434 if ( ! isset( $this->_captured_options[ $option_name ] ) ) { 1510 1435 add_filter( "pre_option_{$option_name}", array( $this, 'capture_filter_pre_get_option' ) ); 1511 1436 } 1512 1437 1513 $this->_captured_options[ $option_name] = $new_value;1438 $this->_captured_options[ $option_name ] = $new_value; 1514 1439 1515 1440 return $old_value; … … 1522 1447 * @access public 1523 1448 * 1524 * @param mixed $value Option1525 * @return mixed 1449 * @param mixed $value Value to return instead of the option value. 1450 * @return mixed Filtered option value. 1526 1451 */ 1527 1452 public function capture_filter_pre_get_option( $value ) { 1528 1453 $option_name = preg_replace( '/^pre_option_/', '', current_filter() ); 1529 1454 1530 if ( isset( $this->_captured_options[ $option_name] ) ) {1531 $value = $this->_captured_options[ $option_name];1455 if ( isset( $this->_captured_options[ $option_name ] ) ) { 1456 $value = $this->_captured_options[ $option_name ]; 1532 1457 1533 1458 /** This filter is documented in wp-includes/option.php */ … … 1558 1483 $this->_is_capturing_option_updates = false; 1559 1484 } 1485 1486 /** 1487 * @since 3.9.0 1488 * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. 1489 */ 1490 public function setup_widget_addition_previews() { 1491 _deprecated_function( __METHOD__, '4.2.0' ); 1492 } 1493 1494 /** 1495 * @since 3.9.0 1496 * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. 1497 */ 1498 public function prepreview_added_sidebars_widgets() { 1499 _deprecated_function( __METHOD__, '4.2.0' ); 1500 } 1501 1502 /** 1503 * @since 3.9.0 1504 * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. 1505 */ 1506 public function prepreview_added_widget_instance() { 1507 _deprecated_function( __METHOD__, '4.2.0' ); 1508 } 1509 1510 /** 1511 * @since 3.9.0 1512 * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. 1513 */ 1514 public function remove_prepreview_filters() { 1515 _deprecated_function( __METHOD__, '4.2.0' ); 1516 } 1560 1517 }
Note: See TracChangeset
for help on using the changeset viewer.