Duplicate code is one of the most pungent code smells. A rule that is often used is to re-structure code once it is duplicated in three or more places.
Common duplication problems, and corresponding solutions are:
Complex classes like WP_Customize_Widgets often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes. You can also have a look at the cohesion graph to spot any un-connected, or weakly-connected components.
Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.
While breaking up the class, it is a good idea to analyze how other classes use WP_Customize_Widgets, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
19 | final class WP_Customize_Widgets { |
||
20 | |||
21 | /** |
||
22 | * WP_Customize_Manager instance. |
||
23 | * |
||
24 | * @since 3.9.0 |
||
25 | * @access public |
||
26 | * @var WP_Customize_Manager |
||
27 | */ |
||
28 | public $manager; |
||
29 | |||
30 | /** |
||
31 | * All id_bases for widgets defined in core. |
||
32 | * |
||
33 | * @since 3.9.0 |
||
34 | * @access protected |
||
35 | * @var array |
||
36 | */ |
||
37 | protected $core_widget_id_bases = array( |
||
38 | 'archives', 'calendar', 'categories', 'links', 'meta', |
||
39 | 'nav_menu', 'pages', 'recent-comments', 'recent-posts', |
||
40 | 'rss', 'search', 'tag_cloud', 'text', |
||
41 | ); |
||
42 | |||
43 | /** |
||
44 | * @since 3.9.0 |
||
45 | * @access protected |
||
46 | * @var array |
||
47 | */ |
||
48 | protected $rendered_sidebars = array(); |
||
49 | |||
50 | /** |
||
51 | * @since 3.9.0 |
||
52 | * @access protected |
||
53 | * @var array |
||
54 | */ |
||
55 | protected $rendered_widgets = array(); |
||
56 | |||
57 | /** |
||
58 | * @since 3.9.0 |
||
59 | * @access protected |
||
60 | * @var array |
||
61 | */ |
||
62 | protected $old_sidebars_widgets = array(); |
||
63 | |||
64 | /** |
||
65 | * Mapping of widget ID base to whether it supports selective refresh. |
||
66 | * |
||
67 | * @since 4.5.0 |
||
68 | * @access protected |
||
69 | * @var array |
||
70 | */ |
||
71 | protected $selective_refreshable_widgets; |
||
72 | |||
73 | /** |
||
74 | * Mapping of setting type to setting ID pattern. |
||
75 | * |
||
76 | * @since 4.2.0 |
||
77 | * @access protected |
||
78 | * @var array |
||
79 | */ |
||
80 | protected $setting_id_patterns = array( |
||
81 | 'widget_instance' => '/^widget_(?P<id_base>.+?)(?:\[(?P<widget_number>\d+)\])?$/', |
||
82 | 'sidebar_widgets' => '/^sidebars_widgets\[(?P<sidebar_id>.+?)\]$/', |
||
83 | ); |
||
84 | |||
85 | /** |
||
86 | * Initial loader. |
||
87 | * |
||
88 | * @since 3.9.0 |
||
89 | * @access public |
||
90 | * |
||
91 | * @param WP_Customize_Manager $manager Customize manager bootstrap instance. |
||
92 | */ |
||
93 | public function __construct( $manager ) { |
||
122 | |||
123 | /** |
||
124 | * List whether each registered widget can be use selective refresh. |
||
125 | * |
||
126 | * If the theme does not support the customize-selective-refresh-widgets feature, |
||
127 | * then this will always return an empty array. |
||
128 | * |
||
129 | * @since 4.5.0 |
||
130 | * @access public |
||
131 | * |
||
132 | * @return array Mapping of id_base to support. If theme doesn't support |
||
133 | * selective refresh, an empty array is returned. |
||
134 | */ |
||
135 | public function get_selective_refreshable_widgets() { |
||
148 | |||
149 | /** |
||
150 | * Determines if a widget supports selective refresh. |
||
151 | * |
||
152 | * @since 4.5.0 |
||
153 | * @access public |
||
154 | * |
||
155 | * @param string $id_base Widget ID Base. |
||
156 | * @return bool Whether the widget can be selective refreshed. |
||
157 | */ |
||
158 | public function is_widget_selective_refreshable( $id_base ) { |
||
162 | |||
163 | /** |
||
164 | * Retrieves the widget setting type given a setting ID. |
||
165 | * |
||
166 | * @since 4.2.0 |
||
167 | * @access protected |
||
168 | * |
||
169 | * @staticvar array $cache |
||
170 | * |
||
171 | * @param string $setting_id Setting ID. |
||
172 | * @return string|void Setting type. |
||
173 | */ |
||
174 | protected function get_setting_type( $setting_id ) { |
||
186 | |||
187 | /** |
||
188 | * Inspects the incoming customized data for any widget settings, and dynamically adds |
||
189 | * them up-front so widgets will be initialized properly. |
||
190 | * |
||
191 | * @since 4.2.0 |
||
192 | * @access public |
||
193 | */ |
||
194 | public function register_settings() { |
||
219 | |||
220 | /** |
||
221 | * Determines the arguments for a dynamically-created setting. |
||
222 | * |
||
223 | * @since 4.2.0 |
||
224 | * @access public |
||
225 | * |
||
226 | * @param false|array $args The arguments to the WP_Customize_Setting constructor. |
||
227 | * @param string $setting_id ID for dynamic setting, usually coming from `$_POST['customized']`. |
||
228 | * @return false|array Setting arguments, false otherwise. |
||
229 | */ |
||
230 | public function filter_customize_dynamic_setting_args( $args, $setting_id ) { |
||
236 | |||
237 | /** |
||
238 | * Retrieves an unslashed post value or return a default. |
||
239 | * |
||
240 | * @since 3.9.0 |
||
241 | * @access protected |
||
242 | * |
||
243 | * @param string $name Post value. |
||
244 | * @param mixed $default Default post value. |
||
245 | * @return mixed Unslashed post value or default value. |
||
246 | */ |
||
247 | protected function get_post_value( $name, $default = null ) { |
||
254 | |||
255 | /** |
||
256 | * Override sidebars_widgets for theme switch. |
||
257 | * |
||
258 | * When switching a theme via the Customizer, supply any previously-configured |
||
259 | * sidebars_widgets from the target theme as the initial sidebars_widgets |
||
260 | * setting. Also store the old theme's existing settings so that they can |
||
261 | * be passed along for storing in the sidebars_widgets theme_mod when the |
||
262 | * theme gets switched. |
||
263 | * |
||
264 | * @since 3.9.0 |
||
265 | * @access public |
||
266 | * |
||
267 | * @global array $sidebars_widgets |
||
268 | * @global array $_wp_sidebars_widgets |
||
269 | */ |
||
270 | public function override_sidebars_widgets_for_theme_switch() { |
||
287 | |||
288 | /** |
||
289 | * Filters old_sidebars_widgets_data Customizer setting. |
||
290 | * |
||
291 | * When switching themes, filter the Customizer setting old_sidebars_widgets_data |
||
292 | * to supply initial $sidebars_widgets before they were overridden by retrieve_widgets(). |
||
293 | * The value for old_sidebars_widgets_data gets set in the old theme's sidebars_widgets |
||
294 | * theme_mod. |
||
295 | * |
||
296 | * @since 3.9.0 |
||
297 | * @access public |
||
298 | * |
||
299 | * @see WP_Customize_Widgets::handle_theme_switch() |
||
300 | * |
||
301 | * @param array $old_sidebars_widgets |
||
302 | * @return array |
||
303 | */ |
||
304 | public function filter_customize_value_old_sidebars_widgets_data( $old_sidebars_widgets ) { |
||
307 | |||
308 | /** |
||
309 | * Filters sidebars_widgets option for theme switch. |
||
310 | * |
||
311 | * When switching themes, the retrieve_widgets() function is run when the Customizer initializes, |
||
312 | * and then the new sidebars_widgets here get supplied as the default value for the sidebars_widgets |
||
313 | * option. |
||
314 | * |
||
315 | * @since 3.9.0 |
||
316 | * @access public |
||
317 | * |
||
318 | * @see WP_Customize_Widgets::handle_theme_switch() |
||
319 | * @global array $sidebars_widgets |
||
320 | * |
||
321 | * @param array $sidebars_widgets |
||
322 | * @return array |
||
323 | */ |
||
324 | public function filter_option_sidebars_widgets_for_theme_switch( $sidebars_widgets ) { |
||
329 | |||
330 | /** |
||
331 | * Ensures all widgets get loaded into the Customizer. |
||
332 | * |
||
333 | * Note: these actions are also fired in wp_ajax_update_widget(). |
||
334 | * |
||
335 | * @since 3.9.0 |
||
336 | * @access public |
||
337 | */ |
||
338 | public function customize_controls_init() { |
||
348 | |||
349 | /** |
||
350 | * Ensures widgets are available for all types of previews. |
||
351 | * |
||
352 | * When in preview, hook to 'customize_register' for settings after WordPress is loaded |
||
353 | * so that all filters have been initialized (e.g. Widget Visibility). |
||
354 | * |
||
355 | * @since 3.9.0 |
||
356 | * @access public |
||
357 | */ |
||
358 | public function schedule_customize_register() { |
||
365 | |||
366 | /** |
||
367 | * Registers Customizer settings and controls for all sidebars and widgets. |
||
368 | * |
||
369 | * @since 3.9.0 |
||
370 | * @access public |
||
371 | * |
||
372 | * @global array $wp_registered_widgets |
||
373 | * @global array $wp_registered_widget_controls |
||
374 | * @global array $wp_registered_sidebars |
||
375 | */ |
||
376 | public function customize_register() { |
||
515 | |||
516 | /** |
||
517 | * Determines whether the widgets panel is active, based on whether there are sidebars registered. |
||
518 | * |
||
519 | * @since 4.4.0 |
||
520 | * @access public |
||
521 | * |
||
522 | * @see WP_Customize_Panel::$active_callback |
||
523 | * |
||
524 | * @global array $wp_registered_sidebars |
||
525 | * @return bool Active. |
||
526 | */ |
||
527 | public function is_panel_active() { |
||
531 | |||
532 | /** |
||
533 | * Converts a widget_id into its corresponding Customizer setting ID (option name). |
||
534 | * |
||
535 | * @since 3.9.0 |
||
536 | * @access public |
||
537 | * |
||
538 | * @param string $widget_id Widget ID. |
||
539 | * @return string Maybe-parsed widget ID. |
||
540 | */ |
||
541 | public function get_setting_id( $widget_id ) { |
||
550 | |||
551 | /** |
||
552 | * Determines whether the widget is considered "wide". |
||
553 | * |
||
554 | * Core widgets which may have controls wider than 250, but can still be shown |
||
555 | * in the narrow Customizer panel. The RSS and Text widgets in Core, for example, |
||
556 | * have widths of 400 and yet they still render fine in the Customizer panel. |
||
557 | * |
||
558 | * This method will return all Core widgets as being not wide, but this can be |
||
559 | * overridden with the is_wide_widget_in_customizer filter. |
||
560 | * |
||
561 | * @since 3.9.0 |
||
562 | * @access public |
||
563 | * |
||
564 | * @global $wp_registered_widget_controls |
||
565 | * |
||
566 | * @param string $widget_id Widget ID. |
||
567 | * @return bool Whether or not the widget is a "wide" widget. |
||
568 | */ |
||
569 | public function is_wide_widget( $widget_id ) { |
||
587 | |||
588 | /** |
||
589 | * Converts a widget ID into its id_base and number components. |
||
590 | * |
||
591 | * @since 3.9.0 |
||
592 | * @access public |
||
593 | * |
||
594 | * @param string $widget_id Widget ID. |
||
595 | * @return array Array containing a widget's id_base and number components. |
||
596 | */ |
||
597 | public function parse_widget_id( $widget_id ) { |
||
612 | |||
613 | /** |
||
614 | * Converts a widget setting ID (option path) to its id_base and number components. |
||
615 | * |
||
616 | * @since 3.9.0 |
||
617 | * @access public |
||
618 | * |
||
619 | * @param string $setting_id Widget setting ID. |
||
620 | * @return WP_Error|array Array containing a widget's id_base and number components, |
||
621 | * or a WP_Error object. |
||
622 | */ |
||
623 | public function parse_widget_setting_id( $setting_id ) { |
||
633 | |||
634 | /** |
||
635 | * Calls admin_print_styles-widgets.php and admin_print_styles hooks to |
||
636 | * allow custom styles from plugins. |
||
637 | * |
||
638 | * @since 3.9.0 |
||
639 | * @access public |
||
640 | */ |
||
641 | public function print_styles() { |
||
648 | |||
649 | /** |
||
650 | * Calls admin_print_scripts-widgets.php and admin_print_scripts hooks to |
||
651 | * allow custom scripts from plugins. |
||
652 | * |
||
653 | * @since 3.9.0 |
||
654 | * @access public |
||
655 | */ |
||
656 | public function print_scripts() { |
||
663 | |||
664 | /** |
||
665 | * Enqueues scripts and styles for Customizer panel and export data to JavaScript. |
||
666 | * |
||
667 | * @since 3.9.0 |
||
668 | * @access public |
||
669 | * |
||
670 | * @global WP_Scripts $wp_scripts |
||
671 | * @global array $wp_registered_sidebars |
||
672 | * @global array $wp_registered_widgets |
||
673 | */ |
||
674 | public function enqueue_scripts() { |
||
755 | |||
756 | /** |
||
757 | * Renders the widget form control templates into the DOM. |
||
758 | * |
||
759 | * @since 3.9.0 |
||
760 | * @access public |
||
761 | */ |
||
762 | public function output_widget_control_templates() { |
||
793 | |||
794 | /** |
||
795 | * Calls admin_print_footer_scripts and admin_print_scripts hooks to |
||
796 | * allow custom scripts from plugins. |
||
797 | * |
||
798 | * @since 3.9.0 |
||
799 | * @access public |
||
800 | */ |
||
801 | public function print_footer_scripts() { |
||
808 | |||
809 | /** |
||
810 | * Retrieves common arguments to supply when constructing a Customizer setting. |
||
811 | * |
||
812 | * @since 3.9.0 |
||
813 | * @access public |
||
814 | * |
||
815 | * @param string $id Widget setting ID. |
||
816 | * @param array $overrides Array of setting overrides. |
||
817 | * @return array Possibly modified setting arguments. |
||
818 | */ |
||
819 | public function get_setting_args( $id, $overrides = array() ) { |
||
850 | |||
851 | /** |
||
852 | * Ensures sidebar widget arrays only ever contain widget IDS. |
||
853 | * |
||
854 | * Used as the 'sanitize_callback' for each $sidebars_widgets setting. |
||
855 | * |
||
856 | * @since 3.9.0 |
||
857 | * @access public |
||
858 | * |
||
859 | * @param array $widget_ids Array of widget IDs. |
||
860 | * @return array Array of sanitized widget IDs. |
||
861 | */ |
||
862 | public function sanitize_sidebar_widgets( $widget_ids ) { |
||
870 | |||
871 | /** |
||
872 | * Builds up an index of all available widgets for use in Backbone models. |
||
873 | * |
||
874 | * @since 3.9.0 |
||
875 | * @access public |
||
876 | * |
||
877 | * @global array $wp_registered_widgets |
||
878 | * @global array $wp_registered_widget_controls |
||
879 | * @staticvar array $available_widgets |
||
880 | * |
||
881 | * @see wp_list_widgets() |
||
882 | * |
||
883 | * @return array List of available widgets. |
||
884 | */ |
||
885 | public function get_available_widgets() { |
||
957 | |||
958 | /** |
||
959 | * Naturally orders available widgets by name. |
||
960 | * |
||
961 | * @since 3.9.0 |
||
962 | * @access protected |
||
963 | * |
||
964 | * @param array $widget_a The first widget to compare. |
||
965 | * @param array $widget_b The second widget to compare. |
||
966 | * @return int Reorder position for the current widget comparison. |
||
967 | */ |
||
968 | protected function _sort_name_callback( $widget_a, $widget_b ) { |
||
971 | |||
972 | /** |
||
973 | * Retrieves the widget control markup. |
||
974 | * |
||
975 | * @since 3.9.0 |
||
976 | * @access public |
||
977 | * |
||
978 | * @param array $args Widget control arguments. |
||
979 | * @return string Widget control form HTML markup. |
||
980 | */ |
||
981 | public function get_widget_control( $args ) { |
||
991 | |||
992 | /** |
||
993 | * Retrieves the widget control markup parts. |
||
994 | * |
||
995 | * @since 4.4.0 |
||
996 | * @access public |
||
997 | * |
||
998 | * @param array $args Widget control arguments. |
||
999 | * @return array { |
||
1000 | * @type string $control Markup for widget control wrapping form. |
||
1001 | * @type string $content The contents of the widget form itself. |
||
1002 | * } |
||
1003 | */ |
||
1004 | public function get_widget_control_parts( $args ) { |
||
1022 | |||
1023 | /** |
||
1024 | * Adds hooks for the Customizer preview. |
||
1025 | * |
||
1026 | * @since 3.9.0 |
||
1027 | * @access public |
||
1028 | */ |
||
1029 | public function customize_preview_init() { |
||
1034 | |||
1035 | /** |
||
1036 | * Refreshes the nonce for widget updates. |
||
1037 | * |
||
1038 | * @since 4.2.0 |
||
1039 | * @access public |
||
1040 | * |
||
1041 | * @param array $nonces Array of nonces. |
||
1042 | * @return array $nonces Array of nonces. |
||
1043 | */ |
||
1044 | public function refresh_nonces( $nonces ) { |
||
1048 | |||
1049 | /** |
||
1050 | * When previewing, ensures the proper previewing widgets are used. |
||
1051 | * |
||
1052 | * Because wp_get_sidebars_widgets() gets called early at {@see 'init' } (via |
||
1053 | * wp_convert_widget_settings()) and can set global variable `$_wp_sidebars_widgets` |
||
1054 | * to the value of `get_option( 'sidebars_widgets' )` before the Customizer preview |
||
1055 | * filter is added, it has to be reset after the filter has been added. |
||
1056 | * |
||
1057 | * @since 3.9.0 |
||
1058 | * @access public |
||
1059 | * |
||
1060 | * @param array $sidebars_widgets List of widgets for the current sidebar. |
||
1061 | * @return array |
||
1062 | */ |
||
1063 | public function preview_sidebars_widgets( $sidebars_widgets ) { |
||
1069 | |||
1070 | /** |
||
1071 | * Enqueues scripts for the Customizer preview. |
||
1072 | * |
||
1073 | * @since 3.9.0 |
||
1074 | * @access public |
||
1075 | */ |
||
1076 | public function customize_preview_enqueue() { |
||
1080 | |||
1081 | /** |
||
1082 | * Inserts default style for highlighted widget at early point so theme |
||
1083 | * stylesheet can override. |
||
1084 | * |
||
1085 | * @since 3.9.0 |
||
1086 | * @access public |
||
1087 | */ |
||
1088 | public function print_preview_css() { |
||
1101 | |||
1102 | /** |
||
1103 | * Communicates the sidebars that appeared on the page at the very end of the page, |
||
1104 | * and at the very end of the wp_footer, |
||
1105 | * |
||
1106 | * @since 3.9.0 |
||
1107 | * @access public |
||
1108 | * |
||
1109 | * @global array $wp_registered_sidebars |
||
1110 | * @global array $wp_registered_widgets |
||
1111 | */ |
||
1112 | public function export_preview_data() { |
||
1136 | |||
1137 | /** |
||
1138 | * Tracks the widgets that were rendered. |
||
1139 | * |
||
1140 | * @since 3.9.0 |
||
1141 | * @access public |
||
1142 | * |
||
1143 | * @param array $widget Rendered widget to tally. |
||
1144 | */ |
||
1145 | public function tally_rendered_widgets( $widget ) { |
||
1148 | |||
1149 | /** |
||
1150 | * Determine if a widget is rendered on the page. |
||
1151 | * |
||
1152 | * @since 4.0.0 |
||
1153 | * @access public |
||
1154 | * |
||
1155 | * @param string $widget_id Widget ID to check. |
||
1156 | * @return bool Whether the widget is rendered. |
||
1157 | */ |
||
1158 | public function is_widget_rendered( $widget_id ) { |
||
1161 | |||
1162 | /** |
||
1163 | * Determines if a sidebar is rendered on the page. |
||
1164 | * |
||
1165 | * @since 4.0.0 |
||
1166 | * @access public |
||
1167 | * |
||
1168 | * @param string $sidebar_id Sidebar ID to check. |
||
1169 | * @return bool Whether the sidebar is rendered. |
||
1170 | */ |
||
1171 | public function is_sidebar_rendered( $sidebar_id ) { |
||
1174 | |||
1175 | /** |
||
1176 | * Tallies the sidebars rendered via is_active_sidebar(). |
||
1177 | * |
||
1178 | * Keep track of the times that is_active_sidebar() is called in the template, |
||
1179 | * and assume that this means that the sidebar would be rendered on the template |
||
1180 | * if there were widgets populating it. |
||
1181 | * |
||
1182 | * @since 3.9.0 |
||
1183 | * @access public |
||
1184 | * |
||
1185 | * @param bool $is_active Whether the sidebar is active. |
||
1186 | * @param string $sidebar_id Sidebar ID. |
||
1187 | * @return bool Whether the sidebar is active. |
||
1188 | */ |
||
1189 | public function tally_sidebars_via_is_active_sidebar_calls( $is_active, $sidebar_id ) { |
||
1200 | |||
1201 | /** |
||
1202 | * Tallies the sidebars rendered via dynamic_sidebar(). |
||
1203 | * |
||
1204 | * Keep track of the times that dynamic_sidebar() is called in the template, |
||
1205 | * and assume this means the sidebar would be rendered on the template if |
||
1206 | * there were widgets populating it. |
||
1207 | * |
||
1208 | * @since 3.9.0 |
||
1209 | * @access public |
||
1210 | * |
||
1211 | * @param bool $has_widgets Whether the current sidebar has widgets. |
||
1212 | * @param string $sidebar_id Sidebar ID. |
||
1213 | * @return bool Whether the current sidebar has widgets. |
||
1214 | */ |
||
1215 | public function tally_sidebars_via_dynamic_sidebar_calls( $has_widgets, $sidebar_id ) { |
||
1227 | |||
1228 | /** |
||
1229 | * Retrieves MAC for a serialized widget instance string. |
||
1230 | * |
||
1231 | * Allows values posted back from JS to be rejected if any tampering of the |
||
1232 | * data has occurred. |
||
1233 | * |
||
1234 | * @since 3.9.0 |
||
1235 | * @access protected |
||
1236 | * |
||
1237 | * @param string $serialized_instance Widget instance. |
||
1238 | * @return string MAC for serialized widget instance. |
||
1239 | */ |
||
1240 | protected function get_instance_hash_key( $serialized_instance ) { |
||
1243 | |||
1244 | /** |
||
1245 | * Sanitizes a widget instance. |
||
1246 | * |
||
1247 | * Unserialize the JS-instance for storing in the options. It's important that this filter |
||
1248 | * only get applied to an instance *once*. |
||
1249 | * |
||
1250 | * @since 3.9.0 |
||
1251 | * @access public |
||
1252 | * |
||
1253 | * @param array $value Widget instance to sanitize. |
||
1254 | * @return array|void Sanitized widget instance. |
||
1255 | */ |
||
1256 | public function sanitize_widget_instance( $value ) { |
||
1284 | |||
1285 | /** |
||
1286 | * Converts a widget instance into JSON-representable format. |
||
1287 | * |
||
1288 | * @since 3.9.0 |
||
1289 | * @access public |
||
1290 | * |
||
1291 | * @param array $value Widget instance to convert to JSON. |
||
1292 | * @return array JSON-converted widget instance. |
||
1293 | */ |
||
1294 | public function sanitize_widget_js_instance( $value ) { |
||
1307 | |||
1308 | /** |
||
1309 | * Strips out widget IDs for widgets which are no longer registered. |
||
1310 | * |
||
1311 | * One example where this might happen is when a plugin orphans a widget |
||
1312 | * in a sidebar upon deactivation. |
||
1313 | * |
||
1314 | * @since 3.9.0 |
||
1315 | * @access public |
||
1316 | * |
||
1317 | * @global array $wp_registered_widgets |
||
1318 | * |
||
1319 | * @param array $widget_ids List of widget IDs. |
||
1320 | * @return array Parsed list of widget IDs. |
||
1321 | */ |
||
1322 | public function sanitize_sidebar_widgets_js_instance( $widget_ids ) { |
||
1327 | |||
1328 | /** |
||
1329 | * Finds and invokes the widget update and control callbacks. |
||
1330 | * |
||
1331 | * Requires that `$_POST` be populated with the instance data. |
||
1332 | * |
||
1333 | * @since 3.9.0 |
||
1334 | * @access public |
||
1335 | * |
||
1336 | * @global array $wp_registered_widget_updates |
||
1337 | * @global array $wp_registered_widget_controls |
||
1338 | * |
||
1339 | * @param string $widget_id Widget ID. |
||
1340 | * @return WP_Error|array Array containing the updated widget information. |
||
1341 | * A WP_Error object, otherwise. |
||
1342 | */ |
||
1343 | public function call_widget_update( $widget_id ) { |
||
1454 | |||
1455 | /** |
||
1456 | * Updates widget settings asynchronously. |
||
1457 | * |
||
1458 | * Allows the Customizer to update a widget using its form, but return the new |
||
1459 | * instance info via Ajax instead of saving it to the options table. |
||
1460 | * |
||
1461 | * Most code here copied from wp_ajax_save_widget(). |
||
1462 | * |
||
1463 | * @since 3.9.0 |
||
1464 | * @access public |
||
1465 | * |
||
1466 | * @see wp_ajax_save_widget() |
||
1467 | */ |
||
1468 | public function wp_ajax_update_widget() { |
||
1518 | |||
1519 | /* |
||
1520 | * Selective Refresh Methods |
||
1521 | */ |
||
1522 | |||
1523 | /** |
||
1524 | * Filters arguments for dynamic widget partials. |
||
1525 | * |
||
1526 | * @since 4.5.0 |
||
1527 | * @access public |
||
1528 | * |
||
1529 | * @param array|false $partial_args Partial arguments. |
||
1530 | * @param string $partial_id Partial ID. |
||
1531 | * @return array (Maybe) modified partial arguments. |
||
1532 | */ |
||
1533 | public function customize_dynamic_partial_args( $partial_args, $partial_id ) { |
||
1534 | if ( ! current_theme_supports( 'customize-selective-refresh-widgets' ) ) { |
||
1535 | return $partial_args; |
||
1536 | } |
||
1537 | |||
1538 | if ( preg_match( '/^widget\[(?P<widget_id>.+)\]$/', $partial_id, $matches ) ) { |
||
1539 | if ( false === $partial_args ) { |
||
1540 | $partial_args = array(); |
||
1541 | } |
||
1542 | $partial_args = array_merge( |
||
1543 | $partial_args, |
||
1544 | array( |
||
1545 | 'type' => 'widget', |
||
1546 | 'render_callback' => array( $this, 'render_widget_partial' ), |
||
1547 | 'container_inclusive' => true, |
||
1548 | 'settings' => array( $this->get_setting_id( $matches['widget_id'] ) ), |
||
1549 | 'capability' => 'edit_theme_options', |
||
1550 | ) |
||
1551 | ); |
||
1552 | } |
||
1553 | |||
1554 | return $partial_args; |
||
1555 | } |
||
1556 | |||
1557 | /** |
||
1558 | * Adds hooks for selective refresh. |
||
1559 | * |
||
1560 | * @since 4.5.0 |
||
1561 | * @access public |
||
1562 | */ |
||
1563 | public function selective_refresh_init() { |
||
1564 | if ( ! current_theme_supports( 'customize-selective-refresh-widgets' ) ) { |
||
1565 | return; |
||
1566 | } |
||
1567 | add_filter( 'dynamic_sidebar_params', array( $this, 'filter_dynamic_sidebar_params' ) ); |
||
1568 | add_filter( 'wp_kses_allowed_html', array( $this, 'filter_wp_kses_allowed_data_attributes' ) ); |
||
1569 | add_action( 'dynamic_sidebar_before', array( $this, 'start_dynamic_sidebar' ) ); |
||
1570 | add_action( 'dynamic_sidebar_after', array( $this, 'end_dynamic_sidebar' ) ); |
||
1571 | } |
||
1572 | |||
1573 | /** |
||
1574 | * Inject selective refresh data attributes into widget container elements. |
||
1575 | * |
||
1576 | * @param array $params { |
||
1577 | * Dynamic sidebar params. |
||
1578 | * |
||
1579 | * @type array $args Sidebar args. |
||
1580 | * @type array $widget_args Widget args. |
||
1581 | * } |
||
1582 | * @see WP_Customize_Nav_Menus_Partial_Refresh::filter_wp_nav_menu_args() |
||
1583 | * |
||
1584 | * @return array Params. |
||
1585 | */ |
||
1586 | public function filter_dynamic_sidebar_params( $params ) { |
||
1587 | $sidebar_args = array_merge( |
||
1588 | array( |
||
1589 | 'before_widget' => '', |
||
1590 | 'after_widget' => '', |
||
1591 | ), |
||
1592 | $params[0] |
||
1593 | ); |
||
1594 | |||
1595 | // Skip widgets not in a registered sidebar or ones which lack a proper wrapper element to attach the data-* attributes to. |
||
1596 | $matches = array(); |
||
1597 | $is_valid = ( |
||
1598 | isset( $sidebar_args['id'] ) |
||
1599 | && |
||
1600 | is_registered_sidebar( $sidebar_args['id'] ) |
||
1601 | && |
||
1602 | ( isset( $this->current_dynamic_sidebar_id_stack[0] ) && $this->current_dynamic_sidebar_id_stack[0] === $sidebar_args['id'] ) |
||
1603 | && |
||
1604 | preg_match( '#^<(?P<tag_name>\w+)#', $sidebar_args['before_widget'], $matches ) |
||
1605 | ); |
||
1606 | if ( ! $is_valid ) { |
||
1607 | return $params; |
||
1608 | } |
||
1609 | $this->before_widget_tags_seen[ $matches['tag_name'] ] = true; |
||
1610 | |||
1611 | $context = array( |
||
1612 | 'sidebar_id' => $sidebar_args['id'], |
||
1613 | ); |
||
1614 | if ( isset( $this->context_sidebar_instance_number ) ) { |
||
1615 | $context['sidebar_instance_number'] = $this->context_sidebar_instance_number; |
||
1616 | } else if ( isset( $sidebar_args['id'] ) && isset( $this->sidebar_instance_count[ $sidebar_args['id'] ] ) ) { |
||
1617 | $context['sidebar_instance_number'] = $this->sidebar_instance_count[ $sidebar_args['id'] ]; |
||
1618 | } |
||
1619 | |||
1620 | $attributes = sprintf( ' data-customize-partial-id="%s"', esc_attr( 'widget[' . $sidebar_args['widget_id'] . ']' ) ); |
||
1621 | $attributes .= ' data-customize-partial-type="widget"'; |
||
1622 | $attributes .= sprintf( ' data-customize-partial-placement-context="%s"', esc_attr( wp_json_encode( $context ) ) ); |
||
1623 | $attributes .= sprintf( ' data-customize-widget-id="%s"', esc_attr( $sidebar_args['widget_id'] ) ); |
||
1624 | $sidebar_args['before_widget'] = preg_replace( '#^(<\w+)#', '$1 ' . $attributes, $sidebar_args['before_widget'] ); |
||
1625 | |||
1626 | $params[0] = $sidebar_args; |
||
1627 | return $params; |
||
1628 | } |
||
1629 | |||
1630 | /** |
||
1631 | * List of the tag names seen for before_widget strings. |
||
1632 | * |
||
1633 | * This is used in the {@see 'filter_wp_kses_allowed_html'} filter to ensure that the |
||
1634 | * data-* attributes can be whitelisted. |
||
1635 | * |
||
1636 | * @since 4.5.0 |
||
1637 | * @access protected |
||
1638 | * @var array |
||
1639 | */ |
||
1640 | protected $before_widget_tags_seen = array(); |
||
1641 | |||
1642 | /** |
||
1643 | * Ensures the HTML data-* attributes for selective refresh are allowed by kses. |
||
1644 | * |
||
1645 | * This is needed in case the `$before_widget` is run through wp_kses() when printed. |
||
1646 | * |
||
1647 | * @since 4.5.0 |
||
1648 | * @access public |
||
1649 | * |
||
1650 | * @param array $allowed_html Allowed HTML. |
||
1651 | * @return array (Maybe) modified allowed HTML. |
||
1652 | */ |
||
1653 | public function filter_wp_kses_allowed_data_attributes( $allowed_html ) { |
||
1654 | foreach ( array_keys( $this->before_widget_tags_seen ) as $tag_name ) { |
||
1655 | if ( ! isset( $allowed_html[ $tag_name ] ) ) { |
||
1656 | $allowed_html[ $tag_name ] = array(); |
||
1657 | } |
||
1658 | $allowed_html[ $tag_name ] = array_merge( |
||
1659 | $allowed_html[ $tag_name ], |
||
1660 | array_fill_keys( array( |
||
1661 | 'data-customize-partial-id', |
||
1662 | 'data-customize-partial-type', |
||
1663 | 'data-customize-partial-placement-context', |
||
1664 | 'data-customize-partial-widget-id', |
||
1665 | 'data-customize-partial-options', |
||
1666 | ), true ) |
||
1667 | ); |
||
1668 | } |
||
1669 | return $allowed_html; |
||
1670 | } |
||
1671 | |||
1672 | /** |
||
1673 | * Keep track of the number of times that dynamic_sidebar() was called for a given sidebar index. |
||
1674 | * |
||
1675 | * This helps facilitate the uncommon scenario where a single sidebar is rendered multiple times on a template. |
||
1676 | * |
||
1677 | * @since 4.5.0 |
||
1678 | * @access protected |
||
1679 | * @var array |
||
1680 | */ |
||
1681 | protected $sidebar_instance_count = array(); |
||
1682 | |||
1683 | /** |
||
1684 | * The current request's sidebar_instance_number context. |
||
1685 | * |
||
1686 | * @since 4.5.0 |
||
1687 | * @access protected |
||
1688 | * @var int |
||
1689 | */ |
||
1690 | protected $context_sidebar_instance_number; |
||
1691 | |||
1692 | /** |
||
1693 | * Current sidebar ID being rendered. |
||
1694 | * |
||
1695 | * @since 4.5.0 |
||
1696 | * @access protected |
||
1697 | * @var array |
||
1698 | */ |
||
1699 | protected $current_dynamic_sidebar_id_stack = array(); |
||
1700 | |||
1701 | /** |
||
1702 | * Begins keeping track of the current sidebar being rendered. |
||
1703 | * |
||
1704 | * Insert marker before widgets are rendered in a dynamic sidebar. |
||
1705 | * |
||
1706 | * @since 4.5.0 |
||
1707 | * @access public |
||
1708 | * |
||
1709 | * @param int|string $index Index, name, or ID of the dynamic sidebar. |
||
1710 | */ |
||
1711 | public function start_dynamic_sidebar( $index ) { |
||
1712 | array_unshift( $this->current_dynamic_sidebar_id_stack, $index ); |
||
1713 | if ( ! isset( $this->sidebar_instance_count[ $index ] ) ) { |
||
1714 | $this->sidebar_instance_count[ $index ] = 0; |
||
1715 | } |
||
1716 | $this->sidebar_instance_count[ $index ] += 1; |
||
1717 | View Code Duplication | if ( ! $this->manager->selective_refresh->is_render_partials_request() ) { |
|
1718 | printf( "\n<!--dynamic_sidebar_before:%s:%d-->\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) ); |
||
1719 | } |
||
1720 | } |
||
1721 | |||
1722 | /** |
||
1723 | * Finishes keeping track of the current sidebar being rendered. |
||
1724 | * |
||
1725 | * Inserts a marker after widgets are rendered in a dynamic sidebar. |
||
1726 | * |
||
1727 | * @since 4.5.0 |
||
1728 | * @access public |
||
1729 | * |
||
1730 | * @param int|string $index Index, name, or ID of the dynamic sidebar. |
||
1731 | */ |
||
1732 | public function end_dynamic_sidebar( $index ) { |
||
1733 | array_shift( $this->current_dynamic_sidebar_id_stack ); |
||
1734 | View Code Duplication | if ( ! $this->manager->selective_refresh->is_render_partials_request() ) { |
|
1735 | printf( "\n<!--dynamic_sidebar_after:%s:%d-->\n", esc_html( $index ), intval( $this->sidebar_instance_count[ $index ] ) ); |
||
1736 | } |
||
1737 | } |
||
1738 | |||
1739 | /** |
||
1740 | * Current sidebar being rendered. |
||
1741 | * |
||
1742 | * @since 4.5.0 |
||
1743 | * @access protected |
||
1744 | * @var string |
||
1745 | */ |
||
1746 | protected $rendering_widget_id; |
||
1747 | |||
1748 | /** |
||
1749 | * Current widget being rendered. |
||
1750 | * |
||
1751 | * @since 4.5.0 |
||
1752 | * @access protected |
||
1753 | * @var string |
||
1754 | */ |
||
1755 | protected $rendering_sidebar_id; |
||
1756 | |||
1757 | /** |
||
1758 | * Filters sidebars_widgets to ensure the currently-rendered widget is the only widget in the current sidebar. |
||
1759 | * |
||
1760 | * @since 4.5.0 |
||
1761 | * @access protected |
||
1762 | * |
||
1763 | * @param array $sidebars_widgets Sidebars widgets. |
||
1764 | * @return array Filtered sidebars widgets. |
||
1765 | */ |
||
1766 | public function filter_sidebars_widgets_for_rendering_widget( $sidebars_widgets ) { |
||
1767 | $sidebars_widgets[ $this->rendering_sidebar_id ] = array( $this->rendering_widget_id ); |
||
1768 | return $sidebars_widgets; |
||
1769 | } |
||
1770 | |||
1771 | /** |
||
1772 | * Renders a specific widget using the supplied sidebar arguments. |
||
1773 | * |
||
1774 | * @since 4.5.0 |
||
1775 | * @access public |
||
1776 | * |
||
1777 | * @see dynamic_sidebar() |
||
1778 | * |
||
1779 | * @param WP_Customize_Partial $partial Partial. |
||
1780 | * @param array $context { |
||
1781 | * Sidebar args supplied as container context. |
||
1782 | * |
||
1783 | * @type string $sidebar_id ID for sidebar for widget to render into. |
||
1784 | * @type int $sidebar_instance_number Disambiguating instance number. |
||
1785 | * } |
||
1786 | * @return string|false |
||
1787 | */ |
||
1788 | public function render_widget_partial( $partial, $context ) { |
||
1789 | $id_data = $partial->id_data(); |
||
1790 | $widget_id = array_shift( $id_data['keys'] ); |
||
1791 | |||
1792 | if ( ! is_array( $context ) |
||
1793 | || empty( $context['sidebar_id'] ) |
||
1794 | || ! is_registered_sidebar( $context['sidebar_id'] ) |
||
1795 | ) { |
||
1796 | return false; |
||
1797 | } |
||
1798 | |||
1799 | $this->rendering_sidebar_id = $context['sidebar_id']; |
||
1800 | |||
1801 | if ( isset( $context['sidebar_instance_number'] ) ) { |
||
1802 | $this->context_sidebar_instance_number = intval( $context['sidebar_instance_number'] ); |
||
1803 | } |
||
1804 | |||
1805 | // Filter sidebars_widgets so that only the queried widget is in the sidebar. |
||
1806 | $this->rendering_widget_id = $widget_id; |
||
1807 | |||
1808 | $filter_callback = array( $this, 'filter_sidebars_widgets_for_rendering_widget' ); |
||
1809 | add_filter( 'sidebars_widgets', $filter_callback, 1000 ); |
||
1810 | |||
1811 | // Render the widget. |
||
1812 | ob_start(); |
||
1813 | dynamic_sidebar( $this->rendering_sidebar_id = $context['sidebar_id'] ); |
||
1814 | $container = ob_get_clean(); |
||
1815 | |||
1816 | // Reset variables for next partial render. |
||
1817 | remove_filter( 'sidebars_widgets', $filter_callback, 1000 ); |
||
1818 | |||
1819 | $this->context_sidebar_instance_number = null; |
||
1820 | $this->rendering_sidebar_id = null; |
||
1821 | $this->rendering_widget_id = null; |
||
1822 | |||
1823 | return $container; |
||
1824 | } |
||
1825 | |||
1826 | // |
||
1827 | // Option Update Capturing |
||
1828 | // |
||
1829 | |||
1830 | /** |
||
1831 | * List of captured widget option updates. |
||
1832 | * |
||
1833 | * @since 3.9.0 |
||
1834 | * @access protected |
||
1835 | * @var array $_captured_options Values updated while option capture is happening. |
||
1836 | */ |
||
1837 | protected $_captured_options = array(); |
||
1838 | |||
1839 | /** |
||
1840 | * Whether option capture is currently happening. |
||
1841 | * |
||
1842 | * @since 3.9.0 |
||
1843 | * @access protected |
||
1844 | * @var bool $_is_current Whether option capture is currently happening or not. |
||
1845 | */ |
||
1846 | protected $_is_capturing_option_updates = false; |
||
1847 | |||
1848 | /** |
||
1849 | * Determines whether the captured option update should be ignored. |
||
1850 | * |
||
1851 | * @since 3.9.0 |
||
1852 | * @access protected |
||
1853 | * |
||
1854 | * @param string $option_name Option name. |
||
1855 | * @return bool Whether the option capture is ignored. |
||
1856 | */ |
||
1857 | protected function is_option_capture_ignored( $option_name ) { |
||
1860 | |||
1861 | /** |
||
1862 | * Retrieves captured widget option updates. |
||
1863 | * |
||
1864 | * @since 3.9.0 |
||
1865 | * @access protected |
||
1866 | * |
||
1867 | * @return array Array of captured options. |
||
1868 | */ |
||
1869 | protected function get_captured_options() { |
||
1872 | |||
1873 | /** |
||
1874 | * Retrieves the option that was captured from being saved. |
||
1875 | * |
||
1876 | * @since 4.2.0 |
||
1877 | * @access protected |
||
1878 | * |
||
1879 | * @param string $option_name Option name. |
||
1880 | * @param mixed $default Optional. Default value to return if the option does not exist. Default false. |
||
1881 | * @return mixed Value set for the option. |
||
1882 | */ |
||
1883 | protected function get_captured_option( $option_name, $default = false ) { |
||
1891 | |||
1892 | /** |
||
1893 | * Retrieves the number of captured widget option updates. |
||
1894 | * |
||
1895 | * @since 3.9.0 |
||
1896 | * @access protected |
||
1897 | * |
||
1898 | * @return int Number of updated options. |
||
1899 | */ |
||
1900 | protected function count_captured_options() { |
||
1903 | |||
1904 | /** |
||
1905 | * Begins keeping track of changes to widget options, caching new values. |
||
1906 | * |
||
1907 | * @since 3.9.0 |
||
1908 | * @access protected |
||
1909 | */ |
||
1910 | protected function start_capturing_option_updates() { |
||
1919 | |||
1920 | /** |
||
1921 | * Pre-filters captured option values before updating. |
||
1922 | * |
||
1923 | * @since 3.9.0 |
||
1924 | * @access public |
||
1925 | * |
||
1926 | * @param mixed $new_value The new option value. |
||
1927 | * @param string $option_name Name of the option. |
||
1928 | * @param mixed $old_value The old option value. |
||
1929 | * @return mixed Filtered option value. |
||
1930 | */ |
||
1931 | public function capture_filter_pre_update_option( $new_value, $option_name, $old_value ) { |
||
1944 | |||
1945 | /** |
||
1946 | * Pre-filters captured option values before retrieving. |
||
1947 | * |
||
1948 | * @since 3.9.0 |
||
1949 | * @access public |
||
1950 | * |
||
1951 | * @param mixed $value Value to return instead of the option value. |
||
1952 | * @return mixed Filtered option value. |
||
1953 | */ |
||
1954 | public function capture_filter_pre_get_option( $value ) { |
||
1966 | |||
1967 | /** |
||
1968 | * Undoes any changes to the options since options capture began. |
||
1969 | * |
||
1970 | * @since 3.9.0 |
||
1971 | * @access protected |
||
1972 | */ |
||
1973 | protected function stop_capturing_option_updates() { |
||
1987 | |||
1988 | /** |
||
1989 | * @since 3.9.0 |
||
1990 | * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. |
||
1991 | */ |
||
1992 | public function setup_widget_addition_previews() { |
||
1995 | |||
1996 | /** |
||
1997 | * @since 3.9.0 |
||
1998 | * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. |
||
1999 | */ |
||
2000 | public function prepreview_added_sidebars_widgets() { |
||
2003 | |||
2004 | /** |
||
2005 | * @since 3.9.0 |
||
2006 | * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. |
||
2007 | */ |
||
2008 | public function prepreview_added_widget_instance() { |
||
2011 | |||
2012 | /** |
||
2013 | * @since 3.9.0 |
||
2014 | * @deprecated 4.2.0 Deprecated in favor of customize_dynamic_setting_args filter. |
||
2015 | */ |
||
2016 | public function remove_prepreview_filters() { |
||
2019 | } |
||
2020 |
This check looks at variables that are passed out again to other methods.
If the outgoing method call has stricter type requirements than the method itself, an issue is raised.
An additional type check may prevent trouble.