PluginProbe ʕ •ᴥ•ʔ
Secure Custom Fields / trunk
Secure Custom Fields vtrunk
6.9.1 6.9.0 6.8.9 6.8.7 6.8.8 6.8.6 6.8.4 6.8.5 trunk 6.4.0-beta1 6.4.0-beta2 6.4.1 6.4.1-beta3 6.4.1-beta4 6.4.1-beta5 6.4.1-beta6 6.4.1-beta7 6.4.2 6.5.0 6.5.1 6.5.2 6.5.3 6.5.4 6.5.5 6.5.6 6.5.7 6.6.0 6.7.0 6.7.1 6.8.0 6.8.1 6.8.2 6.8.3
secure-custom-fields / includes / forms / form-customizer.php
secure-custom-fields / includes / forms Last commit date
WC_Order.php 6 hours ago form-attachment.php 1 year ago form-comment.php 7 months ago form-customizer.php 10 months ago form-front.php 3 weeks ago form-gutenberg.php 1 year ago form-nav-menu.php 7 months ago form-post.php 1 month ago form-taxonomy.php 2 weeks ago form-user.php 7 months ago form-widget.php 10 months ago index.php 1 year ago
form-customizer.php
458 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 if ( ! class_exists( 'acf_form_customizer' ) || ! class_exists( 'ACF_Form_Customizer' ) ) :
8 /**
9 * ACF Form Customizer Class
10 *
11 * This class handles the integration of Advanced Custom Fields with the WordPress Customizer.
12 * It manages preview values, fields, and errors for the customizer interface, and handles
13 * saving ACF data when customizer changes are applied.
14 *
15 * @package wordpress/secure-custom-fields
16 * @since ACF 3.6.0
17 */
18 class ACF_Form_Customizer {
19
20
21 /**
22 * Values to be used in the preview.
23 *
24 * @var array
25 */
26 public $preview_values = array();
27
28 /**
29 * Fields to be used in the preview.
30 *
31 * @var array
32 */
33 public $preview_fields = array();
34
35
36 /**
37 * Errors to be used in the preview.
38 *
39 * @var array
40 */
41 public $preview_errors = array();
42
43 /**
44 * This function will setup the class functionality
45 *
46 * @type function
47 * @date 5/03/2014
48 * @since ACF 5.0.0
49 *
50 * @param n/a
51 * @return n/a
52 */
53 public function __construct() {
54
55 // actions
56 add_action( 'customize_controls_init', array( $this, 'customize_controls_init' ) );
57 add_action( 'customize_preview_init', array( $this, 'customize_preview_init' ), 1, 1 );
58 add_action( 'customize_save', array( $this, 'customize_save' ), 1, 1 );
59
60 // save
61 add_filter( 'widget_update_callback', array( $this, 'save_widget' ), 10, 4 );
62 }
63
64
65 /**
66 * This action is run after post query but before any admin script / head actions.
67 * It is a good place to register all actions.
68 *
69 * @type action (admin_enqueue_scripts)
70 * @date 26/01/13
71 * @since ACF 3.6.0
72 * @return void
73 */
74 public function customize_controls_init() {
75
76 // load acf scripts
77 acf_enqueue_scripts(
78 array(
79 'context' => 'customize_controls',
80 )
81 );
82
83 // actions
84 add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ), 1 );
85 }
86
87
88 /**
89 * This function will hook into the widget update filter and save ACF data
90 *
91 * @type function
92 * @date 27/05/2015
93 * @since ACF 5.2.3
94 *
95 * @param array $instance (array) widget settings.
96 * @param array $new_instance (array) widget settings.
97 * @param array $old_instance (array) widget settings.
98 * @param object $widget (object) widget info.
99 * @return array $instance Widget settings.
100 */
101 public function save_widget( $instance, $new_instance, $old_instance, $widget ) {
102 // bail early if not valid (customize + acf values + nonce)
103
104 // phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce is verified in acf_verify_nonce.
105 if ( ! isset( $_POST['wp_customize'] ) || ! isset( $new_instance['acf'] ) || ! acf_verify_nonce( 'widget' ) ) {
106 return $instance;
107 }
108
109 // vars
110 $data = array(
111 'post_id' => "widget_{$widget->id}",
112 'values' => array(),
113 'fields' => array(),
114 );
115
116 // append values
117 $data['values'] = $new_instance['acf'];
118
119 // append fields (name => key relationship) - used later in 'acf/get_field_reference' for customizer previews
120 foreach ( $data['values'] as $k => $v ) {
121
122 // get field
123 $field = acf_get_field( $k );
124
125 // continue if no field
126 if ( ! $field ) {
127 continue;
128 }
129
130 // update
131 $data['fields'][ $field['name'] ] = $field['key'];
132 }
133
134 // append data to instance
135 $instance['acf'] = $data;
136
137 // return
138 return $instance;
139 }
140
141
142 /**
143 * This function will return an array of customizer settings that include ACF data
144 * similar to `$customizer->settings();`
145 *
146 * @type function
147 * @date 22/03/2016
148 * @since ACF 5.3.2
149 *
150 * @param WP_Customize_Manager $customizer Customizer object.
151 * @return Mixed boolean | array. The sCustomizer Settings Object.
152 */
153 public function settings( $customizer ) {
154
155 // vars
156 $data = array();
157 $settings = $customizer->settings();
158
159 // bail early if no settings
160 if ( empty( $settings ) ) {
161 return false;
162 }
163
164 // loop over settings
165 foreach ( $settings as $setting ) {
166
167 // vars
168 $id = $setting->id;
169 // Only process widget and nav_menu settings
170 if ( 'widget' !== substr( $id, 0, 6 ) && 'nav_menu' !== substr( $id, 0, 7 ) ) {
171 continue;
172 }
173
174 // At this point, we're dealing with either a widget or nav_menu setting
175
176 // get value
177 $value = $setting->post_value();
178
179 // bail early if no acf
180 if ( ! is_array( $value ) || ! isset( $value['acf'] ) ) {
181 continue;
182 }
183
184 // set data
185 $setting->acf = $value['acf'];
186
187 // append
188 $data[] = $setting;
189 }
190
191 // bail early if no settings
192 if ( empty( $data ) ) {
193 return false;
194 }
195
196 // return
197 return $data;
198 }
199
200
201 /**
202 * This function is called when customizer preview is initialized
203 *
204 * @type function
205 * @date 22/03/2016
206 * @since ACF 5.3.2
207 *
208 * @param WP_Customize_Manager $customizer Customizer object.
209 * @return void
210 */
211 public function customize_preview_init( $customizer ) {
212
213 // get customizer settings (widgets)
214 $settings = $this->settings( $customizer );
215
216 // bail early if no settings
217 if ( empty( $settings ) ) {
218 return;
219 }
220
221 // append values
222 foreach ( $settings as $setting ) {
223
224 // get acf data
225 $data = $setting->acf;
226
227 // append acf_value to preview_values
228 $this->preview_values[ $data['post_id'] ] = $data['values'];
229 $this->preview_fields[ $data['post_id'] ] = $data['fields'];
230 }
231
232 // bail early if no preview_values
233 if ( empty( $this->preview_values ) ) {
234 return;
235 }
236
237 // add filters
238 add_filter( 'acf/pre_load_value', array( $this, 'pre_load_value' ), 10, 3 );
239 add_filter( 'acf/pre_load_reference', array( $this, 'pre_load_reference' ), 10, 3 );
240 }
241
242 /**
243 * Pre load value function.
244 *
245 * Used to inject preview value.
246 *
247 * @date 2/2/18
248 * @since ACF 5.6.5
249 *
250 * @param mixed $value The value to check.
251 * @param int $post_id The post ID.
252 * @param array $field The field array.
253 * @return mixed The preview value if exists, otherwise the original value.
254 */
255 public function pre_load_value( $value, $post_id, $field ) {
256
257 // check
258 if ( isset( $this->preview_values[ $post_id ][ $field['key'] ] ) ) {
259 return $this->preview_values[ $post_id ][ $field['key'] ];
260 }
261
262 // return
263 return $value;
264 }
265
266 /**
267 * Pre load reference function.
268 *
269 * Used to inject reference value.
270 *
271 * @date 2/2/18
272 * @since ACF 5.6.5
273 *
274 * @param string $field_key The field key.
275 * @param string $field_name The field name.
276 * @param int $post_id The post ID.
277 * @return string The field key if preview field exists, otherwise the original field key.
278 */
279 public function pre_load_reference( $field_key, $field_name, $post_id ) {
280
281 // check
282 if ( isset( $this->preview_fields[ $post_id ][ $field_name ] ) ) {
283 return $this->preview_fields[ $post_id ][ $field_name ];
284 }
285
286 // return
287 return $field_key;
288 }
289
290
291 /**
292 * This function is called when customizer saves a widget.
293 * Normally, the widget_update_callback filter would be used, but the customizer disables this and runs a custom action
294 * class-customizer-settings.php will save the widget data via the function set_root_value which uses update_option
295 *
296 * @type function
297 * @date 22/03/2016
298 * @since ACF 5.3.2
299 *
300 * @param WP_Customize_Manager $customizer The WordPress customizer manager object.
301 * @return void
302 */
303 public function customize_save( $customizer ) {
304
305 // get customizer settings (widgets)
306 $settings = $this->settings( $customizer );
307
308 // bail early if no settings
309 if ( empty( $settings ) ) {
310 return;
311 }
312
313 // append values
314 foreach ( $settings as $setting ) {
315
316 // get acf data
317 $data = $setting->acf;
318
319 // save acf data
320 acf_save_post( $data['post_id'], $data['values'] );
321
322 // remove [acf] data from saved widget array
323 $id_data = $setting->id_data();
324 add_filter( 'pre_update_option_' . $id_data['base'], array( $this, 'pre_update_option' ), 10, 1 );
325 }
326 }
327
328
329 /**
330 * This function will remove the [acf] data from widget instance
331 *
332 * @type function
333 * @date 22/03/2016
334 * @since ACF 5.3.2
335 *
336 * @param mixed $value The new option value.
337 * @return mixed The filtered option value.
338 */
339 public function pre_update_option( $value ) {
340
341 // bail early if no value
342 if ( empty( $value ) ) {
343 return $value;
344 }
345
346 // loop over widgets
347 // WP saves all widgets (of the same type) as an array of widgets
348 foreach ( $value as $i => $widget ) {
349
350 // bail early if no acf
351 if ( ! isset( $widget['acf'] ) ) {
352 continue;
353 }
354
355 // remove widget
356 unset( $value[ $i ]['acf'] );
357 }
358
359 // return
360 return $value;
361 }
362
363
364 /**
365 * This function will add some custom HTML to the footer of the edit page
366 *
367 * @type function
368 * @date 11/06/2014
369 * @since ACF 5.0.0
370 *
371 * @param n/a
372 * @return n/a
373 */
374 public function admin_footer() {
375
376 ?>
377 <script type="text/javascript">
378 (function($) {
379
380 // customizer saves widget on any input change, so unload is not needed
381 acf.unload.active = 0;
382
383
384 // hack customizer function to remove bug caused by WYSIWYG field using a unique ID
385 // customizer compares returned AJAX HTML with the HTML of the widget form.
386 // the _getInputsSignature() function is used to generate a string based of input name + id.
387 // because ACF generates a unique ID on the WYSIWYG field, this string will not match causing the preview function to bail.
388 // an attempt was made to remove the WYSIWYG unique ID, but this caused multiple issues in the wp-admin and ultimately doesn't make sense with the tinymce rule that all editors must have a unique ID.
389 // source: wp-admin/js/customize-widgets.js
390
391 // vars
392 var WidgetControl = wp.customize.Widgets.WidgetControl.prototype;
393
394
395 // backup functions
396 WidgetControl.__getInputsSignature = WidgetControl._getInputsSignature;
397 WidgetControl.__setInputState = WidgetControl._setInputState;
398
399
400 // modify __getInputsSignature
401 WidgetControl._getInputsSignature = function( inputs ) {
402
403 // vars
404 var signature = this.__getInputsSignature( inputs );
405 safe = [];
406
407
408 // split
409 signature = signature.split(';');
410
411
412 // loop
413 for( var i in signature ) {
414
415 // vars
416 var bit = signature[i];
417
418
419 // bail early if acf is found
420 if( bit.indexOf('acf') !== -1 ) continue;
421
422
423 // append
424 safe.push( bit );
425
426 }
427
428
429 // update
430 signature = safe.join(';');
431
432
433 // return
434 return signature;
435
436 };
437
438
439 // modify _setInputState
440 // this function doesn't seem to run on widget title/content, only custom fields
441 // either way, this function is not needed and will break ACF fields
442 WidgetControl._setInputState = function( input, state ) {
443
444 return true;
445
446 };
447
448 })(jQuery);
449 </script>
450 <?php
451 }
452 }
453
454 new ACF_Form_Customizer();
455 endif;
456
457 ?>
458