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_Control 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_Control, and based on these observations, apply Extract Interface, too.
1 | <?php |
||
15 | class WP_Customize_Control { |
||
16 | |||
17 | /** |
||
18 | * Incremented with each new class instantiation, then stored in $instance_number. |
||
19 | * |
||
20 | * Used when sorting two instances whose priorities are equal. |
||
21 | * |
||
22 | * @since 4.1.0 |
||
23 | * |
||
24 | * @static |
||
25 | * @access protected |
||
26 | * @var int |
||
27 | */ |
||
28 | protected static $instance_count = 0; |
||
29 | |||
30 | /** |
||
31 | * Order in which this instance was created in relation to other instances. |
||
32 | * |
||
33 | * @since 4.1.0 |
||
34 | * @access public |
||
35 | * @var int |
||
36 | */ |
||
37 | public $instance_number; |
||
38 | |||
39 | /** |
||
40 | * @access public |
||
41 | * @var WP_Customize_Manager |
||
42 | */ |
||
43 | public $manager; |
||
44 | |||
45 | /** |
||
46 | * @access public |
||
47 | * @var string |
||
48 | */ |
||
49 | public $id; |
||
50 | |||
51 | /** |
||
52 | * All settings tied to the control. |
||
53 | * |
||
54 | * @access public |
||
55 | * @var array |
||
56 | */ |
||
57 | public $settings; |
||
58 | |||
59 | /** |
||
60 | * The primary setting for the control (if there is one). |
||
61 | * |
||
62 | * @access public |
||
63 | * @var string |
||
64 | */ |
||
65 | public $setting = 'default'; |
||
66 | |||
67 | /** |
||
68 | * Capability required to use this control. |
||
69 | * |
||
70 | * Normally this is empty and the capability is derived from the capabilities |
||
71 | * of the associated `$settings`. |
||
72 | * |
||
73 | * @since 4.5.0 |
||
74 | * @access public |
||
75 | * @var string |
||
76 | */ |
||
77 | public $capability; |
||
78 | |||
79 | /** |
||
80 | * @access public |
||
81 | * @var int |
||
82 | */ |
||
83 | public $priority = 10; |
||
84 | |||
85 | /** |
||
86 | * @access public |
||
87 | * @var string |
||
88 | */ |
||
89 | public $section = ''; |
||
90 | |||
91 | /** |
||
92 | * @access public |
||
93 | * @var string |
||
94 | */ |
||
95 | public $label = ''; |
||
96 | |||
97 | /** |
||
98 | * @access public |
||
99 | * @var string |
||
100 | */ |
||
101 | public $description = ''; |
||
102 | |||
103 | /** |
||
104 | * @todo: Remove choices |
||
105 | * |
||
106 | * @access public |
||
107 | * @var array |
||
108 | */ |
||
109 | public $choices = array(); |
||
110 | |||
111 | /** |
||
112 | * @access public |
||
113 | * @var array |
||
114 | */ |
||
115 | public $input_attrs = array(); |
||
116 | |||
117 | /** |
||
118 | * @deprecated It is better to just call the json() method |
||
119 | * @access public |
||
120 | * @var array |
||
121 | */ |
||
122 | public $json = array(); |
||
123 | |||
124 | /** |
||
125 | * @access public |
||
126 | * @var string |
||
127 | */ |
||
128 | public $type = 'text'; |
||
129 | |||
130 | /** |
||
131 | * Callback. |
||
132 | * |
||
133 | * @since 4.0.0 |
||
134 | * @access public |
||
135 | * |
||
136 | * @see WP_Customize_Control::active() |
||
137 | * |
||
138 | * @var callable Callback is called with one argument, the instance of |
||
139 | * WP_Customize_Control, and returns bool to indicate whether |
||
140 | * the control is active (such as it relates to the URL |
||
141 | * currently being previewed). |
||
142 | */ |
||
143 | public $active_callback = ''; |
||
144 | |||
145 | /** |
||
146 | * Constructor. |
||
147 | * |
||
148 | * Supplied `$args` override class property defaults. |
||
149 | * |
||
150 | * If `$args['settings']` is not defined, use the $id as the setting ID. |
||
151 | * |
||
152 | * @since 3.4.0 |
||
153 | * |
||
154 | * @param WP_Customize_Manager $manager Customizer bootstrap instance. |
||
155 | * @param string $id Control ID. |
||
156 | * @param array $args { |
||
157 | * Optional. Arguments to override class property defaults. |
||
158 | * |
||
159 | * @type int $instance_number Order in which this instance was created in relation |
||
160 | * to other instances. |
||
161 | * @type WP_Customize_Manager $manager Customizer bootstrap instance. |
||
162 | * @type string $id Control ID. |
||
163 | * @type array $settings All settings tied to the control. If undefined, `$id` will |
||
164 | * be used. |
||
165 | * @type string $setting The primary setting for the control (if there is one). |
||
166 | * Default 'default'. |
||
167 | * @type int $priority Order priority to load the control. Default 10. |
||
168 | * @type string $section Section the control belongs to. Default empty. |
||
169 | * @type string $label Label for the control. Default empty. |
||
170 | * @type string $description Description for the control. Default empty. |
||
171 | * @type array $choices List of choices for 'radio' or 'select' type controls, where |
||
172 | * values are the keys, and labels are the values. |
||
173 | * Default empty array. |
||
174 | * @type array $input_attrs List of custom input attributes for control output, where |
||
175 | * attribute names are the keys and values are the values. Not |
||
176 | * used for 'checkbox', 'radio', 'select', 'textarea', or |
||
177 | * 'dropdown-pages' control types. Default empty array. |
||
178 | * @type array $json Deprecated. Use {@see WP_Customize_Control->json()} instead. |
||
179 | * @type string $type Control type. Core controls include 'text', 'checkbox', |
||
180 | * 'textarea', 'radio', 'select', and 'dropdown-pages'. Additional |
||
181 | * input types such as 'email', 'url', 'number', 'hidden', and |
||
182 | * 'date' are supported implicitly. Default 'text'. |
||
183 | * } |
||
184 | */ |
||
185 | public function __construct( $manager, $id, $args = array() ) { |
||
217 | |||
218 | /** |
||
219 | * Enqueue control related scripts/styles. |
||
220 | * |
||
221 | * @since 3.4.0 |
||
222 | */ |
||
223 | public function enqueue() {} |
||
224 | |||
225 | /** |
||
226 | * Check whether control is active to current Customizer preview. |
||
227 | * |
||
228 | * @since 4.0.0 |
||
229 | * @access public |
||
230 | * |
||
231 | * @return bool Whether the control is active to the current preview. |
||
232 | */ |
||
233 | final public function active() { |
||
249 | |||
250 | /** |
||
251 | * Default callback used when invoking WP_Customize_Control::active(). |
||
252 | * |
||
253 | * Subclasses can override this with their specific logic, or they may |
||
254 | * provide an 'active_callback' argument to the constructor. |
||
255 | * |
||
256 | * @since 4.0.0 |
||
257 | * @access public |
||
258 | * |
||
259 | * @return true Always true. |
||
260 | */ |
||
261 | public function active_callback() { |
||
264 | |||
265 | /** |
||
266 | * Fetch a setting's value. |
||
267 | * Grabs the main setting by default. |
||
268 | * |
||
269 | * @since 3.4.0 |
||
270 | * |
||
271 | * @param string $setting_key |
||
272 | * @return mixed The requested setting's value, if the setting exists. |
||
273 | */ |
||
274 | final public function value( $setting_key = 'default' ) { |
||
279 | |||
280 | /** |
||
281 | * Refresh the parameters passed to the JavaScript via JSON. |
||
282 | * |
||
283 | * @since 3.4.0 |
||
284 | */ |
||
285 | public function to_json() { |
||
300 | |||
301 | /** |
||
302 | * Get the data to export to the client via JSON. |
||
303 | * |
||
304 | * @since 4.1.0 |
||
305 | * |
||
306 | * @return array Array of parameters passed to the JavaScript. |
||
307 | */ |
||
308 | public function json() { |
||
312 | |||
313 | /** |
||
314 | * Checks if the user can use this control. |
||
315 | * |
||
316 | * Returns false if the user cannot manipulate one of the associated settings, |
||
317 | * or if one of the associated settings does not exist. Also returns false if |
||
318 | * the associated section does not exist or if its capability check returns |
||
319 | * false. |
||
320 | * |
||
321 | * @since 3.4.0 |
||
322 | * |
||
323 | * @return bool False if theme doesn't support the control or user doesn't have the required permissions, otherwise true. |
||
324 | */ |
||
325 | final public function check_capabilities() { |
||
343 | |||
344 | /** |
||
345 | * Get the control's content for insertion into the Customizer pane. |
||
346 | * |
||
347 | * @since 4.1.0 |
||
348 | * |
||
349 | * @return string Contents of the control. |
||
350 | */ |
||
351 | final public function get_content() { |
||
356 | |||
357 | /** |
||
358 | * Check capabilities and render the control. |
||
359 | * |
||
360 | * @since 3.4.0 |
||
361 | * @uses WP_Customize_Control::render() |
||
362 | */ |
||
363 | final public function maybe_render() { |
||
390 | |||
391 | /** |
||
392 | * Renders the control wrapper and calls $this->render_content() for the internals. |
||
393 | * |
||
394 | * @since 3.4.0 |
||
395 | */ |
||
396 | protected function render() { |
||
404 | |||
405 | /** |
||
406 | * Get the data link attribute for a setting. |
||
407 | * |
||
408 | * @since 3.4.0 |
||
409 | * |
||
410 | * @param string $setting_key |
||
411 | * @return string Data link parameter, if $setting_key is a valid setting, empty string otherwise. |
||
412 | */ |
||
413 | public function get_link( $setting_key = 'default' ) { |
||
419 | |||
420 | /** |
||
421 | * Render the data link attribute for the control's input element. |
||
422 | * |
||
423 | * @since 3.4.0 |
||
424 | * @uses WP_Customize_Control::get_link() |
||
425 | * |
||
426 | * @param string $setting_key |
||
427 | */ |
||
428 | public function link( $setting_key = 'default' ) { |
||
431 | |||
432 | /** |
||
433 | * Render the custom attributes for the control's input element. |
||
434 | * |
||
435 | * @since 4.0.0 |
||
436 | * @access public |
||
437 | */ |
||
438 | public function input_attrs() { |
||
443 | |||
444 | /** |
||
445 | * Render the control's content. |
||
446 | * |
||
447 | * Allows the content to be overriden without having to rewrite the wrapper in $this->render(). |
||
448 | * |
||
449 | * Supports basic input types `text`, `checkbox`, `textarea`, `radio`, `select` and `dropdown-pages`. |
||
450 | * Additional input types such as `email`, `url`, `number`, `hidden` and `date` are supported implicitly. |
||
451 | * |
||
452 | * Control content can alternately be rendered in JS. See {@see WP_Customize_Control::print_template()}. |
||
453 | * |
||
454 | * @since 3.4.0 |
||
455 | */ |
||
456 | protected function render_content() { |
||
568 | |||
569 | /** |
||
570 | * Render the control's JS template. |
||
571 | * |
||
572 | * This function is only run for control types that have been registered with |
||
573 | * {@see WP_Customize_Manager::register_control_type()}. |
||
574 | * |
||
575 | * In the future, this will also print the template for the control's container |
||
576 | * element and be override-able. |
||
577 | * |
||
578 | * @since 4.1.0 |
||
579 | */ |
||
580 | final public function print_template() { |
||
587 | |||
588 | /** |
||
589 | * An Underscore (JS) template for this control's content (but not its container). |
||
590 | * |
||
591 | * Class variables for this control class are available in the `data` JS object; |
||
592 | * export custom variables by overriding {@see WP_Customize_Control::to_json()}. |
||
593 | * |
||
594 | * @see WP_Customize_Control::print_template() |
||
595 | * |
||
596 | * @since 4.1.0 |
||
597 | */ |
||
598 | protected function content_template() {} |
||
599 | |||
600 | } |
||
601 | |||
652 |
Our type inference engine has found an assignment to a property that is incompatible with the declared type of that property.
Either this assignment is in error or the assigned type should be added to the documentation/type hint for that property..