PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields (ACF®) / 6.2.7
Advanced Custom Fields (ACF®) v6.2.7
6.8.3 6.8.2 6.8.1 5.8.5 5.8.6 5.8.7 5.8.8 5.8.9 5.9.0 5.9.1 5.9.2 5.9.3 5.9.4 5.9.5 5.9.6 5.9.7 5.9.8 5.9.9 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.0.6 6.0.7 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.1.5 6.1.6 6.1.7 6.1.8 6.2.0 6.2.1 6.2.2 6.2.3 6.2.4 6.2.5 6.2.6 6.2.6.1 6.2.7 6.2.8 6.2.9 6.3.0 6.3.1 6.3.10.2 6.3.11 6.3.12 6.3.2 6.3.3 6.3.4 6.3.5 6.3.6 6.3.6.1 6.4.0 6.4.0.1 6.4.1 6.4.2 6.4.3 6.5.0 6.5.1 6.6.0 6.6.1 6.6.2 6.7.0 6.7.1 6.7.2 6.8.0 trunk 1.0.0 1.0.2 1.0.3 1.0.5 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 2.0.0 2.0.1 2.0.2 2.0.3 2.0.4 2.0.5 2.1.1 2.1.3 2.1.4 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.6 3.0.7 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 3.3.5 3.3.6 3.3.7 3.3.8 3.3.9 3.4.0 3.4.1 3.4.2 3.4.3 3.5.0 3.5.1 3.5.2 3.5.3 3.5.4 3.5.5 3.5.6 3.5.7 3.5.8 4.0.0 4.0.1 4.0.2 4.0.3 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.1.5 4.1.6 4.1.8 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.3.7 4.3.8 4.3.9 4.4.0 4.4.1 4.4.10 4.4.11 4.4.12 4.4.2 4.4.3 4.4.4 4.4.5 4.4.6 4.4.7 4.4.8 4.4.9 5.10 5.10.1 5.10.2 5.11 5.11.1 5.11.2 5.11.3 5.11.4 5.12 5.12.1 5.12.2 5.12.3 5.12.4 5.12.5 5.12.6 5.6.10 5.6.2 5.6.3 5.6.4 5.6.5 5.6.6 5.6.7 5.6.8 5.6.9 5.7.0 5.7.1 5.7.10 5.7.12 5.7.13 5.7.2 5.7.3 5.7.4 5.7.5 5.7.6 5.7.7 5.7.8 5.7.9 5.8.0 5.8.1 5.8.10 5.8.11 5.8.12 5.8.13 5.8.14 5.8.2 5.8.3 5.8.4
advanced-custom-fields / includes / local-json.php
advanced-custom-fields / includes Last commit date
admin 2 years ago ajax 2 years ago api 2 years ago fields 2 years ago forms 2 years ago legacy 2 years ago locations 2 years ago post-types 2 years ago rest-api 2 years ago walkers 2 years ago acf-bidirectional-functions.php 2 years ago acf-field-functions.php 2 years ago acf-field-group-functions.php 2 years ago acf-form-functions.php 2 years ago acf-helper-functions.php 2 years ago acf-hook-functions.php 2 years ago acf-input-functions.php 2 years ago acf-internal-post-type-functions.php 2 years ago acf-meta-functions.php 2 years ago acf-post-functions.php 4 years ago acf-post-type-functions.php 2 years ago acf-taxonomy-functions.php 2 years ago acf-user-functions.php 2 years ago acf-utility-functions.php 2 years ago acf-value-functions.php 2 years ago acf-wp-functions.php 2 years ago assets.php 2 years ago class-acf-data.php 2 years ago class-acf-internal-post-type.php 2 years ago compatibility.php 2 years ago deprecated.php 2 years ago fields.php 2 years ago l10n.php 2 years ago local-fields.php 2 years ago local-json.php 2 years ago local-meta.php 2 years ago locations.php 2 years ago loop.php 2 years ago media.php 2 years ago rest-api.php 4 years ago revisions.php 2 years ago third-party.php 2 years ago upgrades.php 2 years ago validation.php 2 years ago wpml.php 2 years ago
local-json.php
548 lines
1 <?php
2
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit; // Exit if accessed directly
5 }
6
7 if ( ! class_exists( 'ACF_Local_JSON' ) ) :
8
9 class ACF_Local_JSON {
10
11 /**
12 * The found JSON field group files.
13 *
14 * @since 5.9.0
15 * @var array
16 */
17 private $files = array();
18
19 /**
20 * Constructor.
21 *
22 * @date 14/4/20
23 * @since 5.9.0
24 *
25 * @param void
26 * @return void
27 */
28 public function __construct() {
29
30 // Update settings.
31 acf_update_setting( 'save_json', get_stylesheet_directory() . '/acf-json' );
32 acf_append_setting( 'load_json', get_stylesheet_directory() . '/acf-json' );
33
34 // Add listeners.
35 add_action( 'acf/update_field_group', array( $this, 'update_field_group' ) );
36 add_action( 'acf/untrash_field_group', array( $this, 'update_field_group' ) );
37 add_action( 'acf/trash_field_group', array( $this, 'delete_field_group' ) );
38 add_action( 'acf/delete_field_group', array( $this, 'delete_field_group' ) );
39 add_action( 'acf/update_post_type', array( $this, 'update_internal_post_type' ) );
40 add_action( 'acf/untrash_post_type', array( $this, 'update_internal_post_type' ) );
41 add_action( 'acf/trash_post_type', array( $this, 'delete_internal_post_type' ) );
42 add_action( 'acf/delete_post_type', array( $this, 'delete_internal_post_type' ) );
43 add_action( 'acf/update_taxonomy', array( $this, 'update_internal_post_type' ) );
44 add_action( 'acf/untrash_taxonomy', array( $this, 'update_internal_post_type' ) );
45 add_action( 'acf/trash_taxonomy', array( $this, 'delete_internal_post_type' ) );
46 add_action( 'acf/delete_taxonomy', array( $this, 'delete_internal_post_type' ) );
47
48 // Include fields.
49 add_action( 'acf/include_fields', array( $this, 'include_fields' ) );
50 add_action( 'acf/include_post_types', array( $this, 'include_post_types' ) );
51 add_action( 'acf/include_taxonomies', array( $this, 'include_taxonomies' ) );
52 }
53
54 /**
55 * Returns true if this component is enabled.
56 *
57 * @date 14/4/20
58 * @since 5.9.0
59 *
60 * @param void
61 * @return boolean
62 */
63 public function is_enabled() {
64 return (bool) acf_get_setting( 'json' );
65 }
66
67 /**
68 * Gets the path(s) to load JSON from.
69 *
70 * @since 6.2
71 *
72 * @return array
73 */
74 public function get_load_paths() {
75 $paths = (array) acf_get_setting( 'load_json' );
76
77 /**
78 * Filters the path(s) used to load JSON from.
79 *
80 * @since 6.2
81 *
82 * @param array $paths An array of potential paths to load JSON from.
83 * @return array
84 */
85 return (array) apply_filters( 'acf/json/load_paths', $paths );
86 }
87
88 /**
89 * Gets the path(s) to save JSON to.
90 *
91 * @since 6.2
92 *
93 * @param string $key The key to get paths for (optional).
94 * @param array $post The main ACF post array (optional).
95 * @return array
96 */
97 public function get_save_paths( $key = '', $post = array() ) {
98 $name = ! empty( $post['title'] ) ? (string) $post['title'] : '';
99 $post_type = acf_determine_internal_post_type( $key );
100 $paths = array();
101
102 // Paths are sorted by priority, with key overriding name, etc.
103 $paths[] = acf_get_setting( "save_json/key={$key}" );
104 $paths[] = acf_get_setting( "save_json/name={$name}" );
105 $paths[] = acf_get_setting( "save_json/type={$post_type}" );
106 $paths[] = acf_get_setting( 'save_json' );
107 $paths = array_values( array_filter( $paths ) );
108
109 /**
110 * Filters the paths used to save JSON.
111 *
112 * @since 6.2
113 *
114 * @param array $paths An array of the potential paths to save JSON to.
115 * @param array $post The ACF field group, post type, or taxonomy array.
116 * @return array
117 */
118 return (array) apply_filters( 'acf/json/save_paths', $paths, $post );
119 }
120
121 /**
122 * Writes field group data to JSON file.
123 *
124 * @date 14/4/20
125 * @since 5.9.0
126 *
127 * @param array $field_group The field group.
128 * @return void
129 */
130 public function update_field_group( $field_group ) {
131
132 // Bail early if disabled.
133 if ( ! $this->is_enabled() ) {
134 return false;
135 }
136
137 // Append fields.
138 $field_group['fields'] = acf_get_fields( $field_group );
139
140 // Save to file.
141 $this->save_file( $field_group['key'], $field_group );
142 }
143
144 /**
145 * Writes ACF posts to the JSON file.
146 *
147 * @since 6.1
148 *
149 * @param array $post The main ACF post array.
150 * @return boolean
151 */
152 public function update_internal_post_type( $post ) {
153 if ( ! $this->is_enabled() ) {
154 return false;
155 }
156
157 /**
158 * Filters the ACF post before saving it to the file.
159 *
160 * @since 6.1
161 *
162 * @param array $post The main ACF post array
163 */
164 $post = apply_filters( 'acf/pre_save_json_file', $post );
165
166 return $this->save_file( $post['key'], $post );
167 }
168
169 /**
170 * Deletes a field group JSON file.
171 *
172 * @date 14/4/20
173 * @since 5.9.0
174 *
175 * @param array $field_group The field group.
176 * @return boolean
177 */
178 public function delete_field_group( $field_group ) {
179 return $this->delete_internal_post_type( $field_group );
180 }
181
182 /**
183 * Deletes an ACF JSON file.
184 *
185 * @since 6.1
186 *
187 * @param array $post The main ACF post array.
188 * @return boolean
189 */
190 public function delete_internal_post_type( $post ) {
191 if ( ! $this->is_enabled() ) {
192 return false;
193 }
194
195 // WP appends '__trashed' to the end of 'key' (post_name).
196 $key = str_replace( '__trashed', '', $post['key'] );
197
198 return $this->delete_file( $key, $post );
199 }
200
201 /**
202 * Includes all local JSON fields.
203 *
204 * @date 14/4/20
205 * @since 5.9.0
206 *
207 * @param void
208 * @return void
209 */
210 public function include_fields() {
211
212 // Bail early if disabled.
213 if ( ! $this->is_enabled() ) {
214 return false;
215 }
216
217 // Get load paths.
218 $files = $this->scan_files( 'acf-field-group' );
219 foreach ( $files as $key => $file ) {
220 $json = json_decode( file_get_contents( $file ), true );
221 $json['local'] = 'json';
222 $json['local_file'] = $file;
223 acf_add_local_field_group( $json );
224 }
225 }
226
227 /**
228 * Includes all local JSON post types.
229 *
230 * @since 6.1
231 */
232 public function include_post_types() {
233 // Bail early if disabled.
234 if ( ! $this->is_enabled() ) {
235 return false;
236 }
237
238 // Get load paths.
239 $files = $this->scan_files( 'acf-post-type' );
240 foreach ( $files as $key => $file ) {
241 $json = json_decode( file_get_contents( $file ), true );
242 $json['local'] = 'json';
243 $json['local_file'] = $file;
244 acf_add_local_internal_post_type( $json, 'acf-post-type' );
245 }
246 }
247
248 /**
249 * Includes all local JSON taxonomies.
250 *
251 * @since 6.1
252 */
253 public function include_taxonomies() {
254 // Bail early if disabled.
255 if ( ! $this->is_enabled() ) {
256 return false;
257 }
258
259 // Get load paths.
260 $files = $this->scan_files( 'acf-taxonomy' );
261 foreach ( $files as $key => $file ) {
262 $json = json_decode( file_get_contents( $file ), true );
263 $json['local'] = 'json';
264 $json['local_file'] = $file;
265 acf_add_local_internal_post_type( $json, 'acf-taxonomy' );
266 }
267 }
268
269 /**
270 * Scans for JSON field groups.
271 *
272 * @date 14/4/20
273 * @since 5.9.0
274 *
275 * @return array
276 */
277 function scan_field_groups() {
278 return $this->scan_files( 'acf-field-group' );
279 }
280
281 /**
282 * Scans for JSON files.
283 *
284 * @since 6.1
285 *
286 * @param string $post_type The ACF post type to scan for.
287 * @return array
288 */
289 function scan_files( $post_type = 'acf-field-group' ) {
290 $json_files = array();
291
292 // Loop over "local_json" paths and parse JSON files.
293 foreach ( $this->get_load_paths() as $path ) {
294 if ( is_dir( $path ) ) {
295 $files = scandir( $path );
296 if ( $files ) {
297 foreach ( $files as $filename ) {
298
299 // Ignore hidden files.
300 if ( $filename[0] === '.' ) {
301 continue;
302 }
303
304 // Ignore sub directories.
305 $file = untrailingslashit( $path ) . '/' . $filename;
306 if ( is_dir( $file ) ) {
307 continue;
308 }
309
310 // Ignore non JSON files.
311 $ext = pathinfo( $filename, PATHINFO_EXTENSION );
312 if ( $ext !== 'json' ) {
313 continue;
314 }
315
316 // Read JSON data.
317 $json = json_decode( file_get_contents( $file ), true );
318 if ( ! is_array( $json ) || ! isset( $json['key'] ) ) {
319 continue;
320 }
321
322 // Append data.
323 $json_files[ $json['key'] ] = $file;
324 }
325 }
326 }
327 }
328
329 // Store data and return.
330 $this->files = $json_files;
331 return $this->get_files( $post_type );
332 }
333
334 /**
335 * Returns an array of found JSON files.
336 *
337 * @date 14/4/20
338 * @since 5.9.0
339 *
340 * @param string $post_type The ACF post type to get files for.
341 * @return array
342 */
343 public function get_files( $post_type = 'acf-field-group' ) {
344 $files = array();
345
346 foreach ( $this->files as $key => $path ) {
347 $internal_post_type = acf_determine_internal_post_type( $key );
348
349 if ( $internal_post_type === $post_type ) {
350 $files[ $key ] = $path;
351 } elseif ( 'acf-field-group' === $post_type ) {
352 // If we can't figure out the ACF post type, make an educated guess that it's a field group.
353 $json = json_decode( file_get_contents( $path ), true );
354 if ( ! is_array( $json ) ) {
355 continue;
356 }
357
358 if ( isset( $json['fields'] ) ) {
359 $files[ $key ] = $path;
360 }
361 }
362 }
363
364 return $files;
365 }
366
367 /**
368 * Saves an ACF JSON file.
369 *
370 * @date 17/4/20
371 * @since 5.9.0
372 *
373 * @param string $key The ACF post key.
374 * @param array $post The main ACF post array.
375 * @return boolean
376 */
377 public function save_file( $key, $post ) {
378 $paths = $this->get_save_paths( $key, $post );
379 $file = false;
380 $first_writable = false;
381 $load_path = '';
382
383 if ( is_array( $this->files ) && isset( $this->files[ $key ] ) ) {
384 $load_path = $this->files[ $key ];
385 }
386
387 /**
388 * Filters the filename used when saving JSON.
389 *
390 * @since 6.2
391 *
392 * @param string $filename The default filename.
393 * @param array $post The main post array for the item being saved.
394 * @param string $load_path The path that the item was loaded from.
395 */
396 $filename = apply_filters( 'acf/json/save_file_name', $key . '.json', $post, $load_path );
397
398 if ( ! is_string( $filename ) ) {
399 return false;
400 }
401
402 $filename = sanitize_file_name( $filename );
403
404 // sanitize_file_name() can potentially remove all characters.
405 if ( empty( $filename ) ) {
406 return false;
407 }
408
409 foreach ( $paths as $path ) {
410 if ( ! wp_is_writable( $path ) ) {
411 continue;
412 }
413
414 if ( false === $first_writable ) {
415 $first_writable = $path;
416 }
417
418 $file_to_check = trailingslashit( $path ) . $filename;
419
420 if ( is_file( $file_to_check ) ) {
421 $file = $file_to_check;
422 }
423 }
424
425 if ( ! $file ) {
426 if ( $first_writable ) {
427 $file = trailingslashit( $first_writable ) . $filename;
428 } else {
429 return false;
430 }
431 }
432
433 // Make sure this is a valid ACF post type.
434 $post_type = acf_determine_internal_post_type( $key );
435 if ( ! $post_type ) {
436 return false;
437 }
438
439 // Append modified time.
440 if ( $post['ID'] ) {
441 $post['modified'] = get_post_modified_time( 'U', true, $post['ID'] );
442 } else {
443 $post['modified'] = strtotime( 'now' );
444 }
445
446 // Prepare for export and save the file.
447 $post = acf_prepare_internal_post_type_for_export( $post, $post_type );
448 $result = file_put_contents( $file, acf_json_encode( $post ) . apply_filters( 'acf/json/eof_newline', PHP_EOL ) ); //phpcs:ignore WordPress.WP.AlternativeFunctions.file_system_operations_file_put_contents -- potentially could run outside of admin.
449
450 // Return true if bytes were written.
451 return is_int( $result );
452 }
453
454 /**
455 * Deletes an ACF JSON file.
456 *
457 * @date 17/4/20
458 * @since 5.9.0
459 *
460 * @param string $key The ACF post key.
461 * @param array $post The main ACF post array.
462 * @return boolean
463 */
464 public function delete_file( $key, $post = array() ) {
465 $paths = $this->get_save_paths( $key, $post );
466
467 foreach ( $paths as $path_to_check ) {
468 $file = untrailingslashit( $path_to_check ) . '/' . $key . '.json';
469
470 if ( wp_is_writable( $file ) ) {
471 wp_delete_file( $file );
472 }
473 }
474
475 return true;
476 }
477
478 /**
479 * Includes all local JSON files.
480 *
481 * @date 10/03/2014
482 * @since 5.0.0
483 * @deprecated 5.9.0
484 */
485 public function include_json_folders() {
486 _deprecated_function( __METHOD__, '5.9.0', 'ACF_Local_JSON::include_fields()' );
487 $this->include_fields();
488 }
489
490 /**
491 * Includes local JSON files within a specific folder.
492 *
493 * @date 01/05/2017
494 * @since 5.5.13
495 * @deprecated 5.9.0
496 *
497 * @param string $path The path to a specific JSON folder.
498 * @return void
499 */
500 public function include_json_folder( $path = '' ) {
501 _deprecated_function( __METHOD__, '5.9.0' );
502 // Do nothing.
503 }
504 }
505
506 // Initialize.
507 acf_new_instance( 'ACF_Local_JSON' );
508 endif; // class_exists check
509
510 /**
511 * Returns an array of found JSON field group files.
512 *
513 * @date 14/4/20
514 * @since 5.9.0
515 *
516 * @param string $post_type The ACF post type to get files for.
517 * @return array
518 */
519 function acf_get_local_json_files( $post_type = 'acf-field-group' ) {
520 return acf_get_instance( 'ACF_Local_JSON' )->get_files( $post_type );
521 }
522
523 /**
524 * Saves a field group JSON file.
525 *
526 * @date 5/12/2014
527 * @since 5.1.5
528 *
529 * @param array $field_group The field group.
530 * @return boolean
531 */
532 function acf_write_json_field_group( $field_group ) {
533 return acf_get_instance( 'ACF_Local_JSON' )->save_file( $field_group['key'], $field_group );
534 }
535
536 /**
537 * Deletes a field group JSON file.
538 *
539 * @date 5/12/2014
540 * @since 5.1.5
541 *
542 * @param string $key The field group key.
543 * @return boolean True on success.
544 */
545 function acf_delete_json_field_group( $key ) {
546 return acf_get_instance( 'ACF_Local_JSON' )->delete_file( $key );
547 }
548