PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields (ACF®) / 6.8.7
Advanced Custom Fields (ACF®) v6.8.7
6.8.9 6.8.8 6.8.7 6.8.6 6.8.5 6.8.4 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 / admin / tools / class-acf-admin-tool-export.php
advanced-custom-fields / includes / admin / tools Last commit date
class-acf-admin-tool-export.php 5 months ago class-acf-admin-tool-import.php 5 months ago class-acf-admin-tool.php 5 months ago index.php 2 years ago
class-acf-admin-tool-export.php
539 lines
1 <?php
2 /**
3 * @package ACF
4 * @author WP Engine
5 *
6 * © 2026 Advanced Custom Fields (ACF®). All rights reserved.
7 * "ACF" is a trademark of WP Engine.
8 * Licensed under the GNU General Public License v2 or later.
9 * https://www.gnu.org/licenses/gpl-2.0.html
10 */
11
12 if ( ! defined( 'ABSPATH' ) ) {
13 exit; // Exit if accessed directly
14 }
15
16 if ( ! class_exists( 'ACF_Admin_Tool_Export' ) ) :
17
18 class ACF_Admin_Tool_Export extends ACF_Admin_Tool {
19
20 /** @var string View context */
21 var $view = '';
22
23
24 /** @var array Export data */
25 var $json = '';
26
27
28 /**
29 * initialize
30 *
31 * This function will initialize the admin tool
32 *
33 * @date 10/10/17
34 * @since 5.6.3
35 *
36 * @param n/a
37 * @return n/a
38 */
39 function initialize() {
40
41 // vars
42 $this->name = 'export';
43 $this->title = __( 'Export Field Groups', 'acf' );
44
45 // active
46 if ( $this->is_active() ) {
47 $this->title .= ' - ' . __( 'Generate PHP', 'acf' );
48 }
49 }
50
51
52 /**
53 * submit
54 *
55 * This function will run when the tool's form has been submit
56 *
57 * @date 10/10/17
58 * @since 5.6.3
59 *
60 * @param n/a
61 * @return n/a
62 */
63 function submit() {
64
65 // vars
66 $action = acf_maybe_get_POST( 'action' );
67
68 // download
69 if ( $action === 'download' ) {
70 $this->submit_download();
71
72 // generate
73 } elseif ( $action === 'generate' ) {
74 $this->submit_generate();
75 }
76 }
77
78
79 /**
80 * submit_download
81 *
82 * description
83 *
84 * @date 17/10/17
85 * @since 5.6.3
86 *
87 * @param n/a
88 * @return n/a
89 */
90 function submit_download() {
91
92 // vars
93 $json = $this->get_selected();
94
95 // validate
96 if ( $json === false ) {
97 return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
98 }
99
100 // headers
101 $file_name = 'acf-export-' . date( 'Y-m-d' ) . '.json';
102 header( 'Content-Description: File Transfer' );
103 header( "Content-Disposition: attachment; filename={$file_name}" );
104 header( 'Content-Type: application/json; charset=utf-8' );
105
106 // return
107 echo acf_json_encode( $json ) . "\r\n"; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped as JSON export.
108 die;
109 }
110
111
112 /**
113 * submit_generate
114 *
115 * description
116 *
117 * @date 17/10/17
118 * @since 5.6.3
119 *
120 * @param n/a
121 * @return n/a
122 */
123 function submit_generate() {
124
125 // vars
126 $keys = $this->get_selected_keys();
127
128 // validate
129 if ( ! $keys ) {
130 return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
131 }
132
133 // url
134 $url = add_query_arg( 'keys', implode( '+', $keys ), $this->get_url() );
135
136 // redirect
137 wp_safe_redirect( $url );
138 exit;
139 }
140
141
142 /**
143 * load
144 *
145 * description
146 *
147 * @date 21/10/17
148 * @since 5.6.3
149 *
150 * @param n/a
151 * @return n/a
152 */
153 function load() {
154
155 // active
156 if ( $this->is_active() ) {
157
158 // get selected keys
159 $selected = $this->get_selected_keys();
160
161 // add notice
162 if ( $selected ) {
163 $count = count( $selected );
164 $text = sprintf( _n( 'Exported 1 item.', 'Exported %s items.', $count, 'acf' ), $count );
165 acf_add_admin_notice( $text, 'success' );
166 }
167 }
168 }
169
170
171 /**
172 * html
173 *
174 * This function will output the metabox HTML
175 *
176 * @date 10/10/17
177 * @since 5.6.3
178 *
179 * @param n/a
180 * @return n/a
181 */
182 function html() {
183
184 // single (generate PHP)
185 if ( $this->is_active() ) {
186 $this->html_single();
187
188 // archive
189 } else {
190 $this->html_archive();
191 }
192 }
193
194
195 /**
196 * Renders the checkboxes to select items to export.
197 *
198 * @since 5.6.3
199 */
200 public function html_field_selection() {
201 // Ensure `l10n_var_export` is always false at the point we're outputting the options.
202 acf_update_setting( 'l10n_var_export', false );
203 // Reset the field-groups store which may have been corrupted by export.
204 $store = acf_get_store( 'field-groups' );
205 if ( $store ) {
206 $store->reset();
207 }
208
209 $choices = array();
210 $selected = $this->get_selected_keys();
211 $field_groups = array_filter(
212 acf_get_internal_post_type_posts( 'acf-field-group' ),
213 'acf_internal_post_object_contains_valid_key'
214 );
215
216 if ( $field_groups ) {
217 foreach ( $field_groups as $field_group ) {
218 $choices[ $field_group['key'] ] = esc_html( $field_group['title'] );
219 }
220 }
221
222 acf_render_field_wrap(
223 array(
224 'label' => __( 'Select Field Groups', 'acf' ),
225 'type' => 'checkbox',
226 'name' => 'keys',
227 'prefix' => false,
228 'value' => $selected,
229 'toggle' => true,
230 'choices' => $choices,
231 )
232 );
233
234 $choices = array();
235 $selected = $this->get_selected_keys();
236 $post_types = array_filter(
237 acf_get_internal_post_type_posts( 'acf-post-type' ),
238 'acf_internal_post_object_contains_valid_key'
239 );
240
241 if ( $post_types ) {
242 foreach ( $post_types as $post_type ) {
243 $choices[ $post_type['key'] ] = esc_html( $post_type['title'] );
244 }
245
246 acf_render_field_wrap(
247 array(
248 'label' => __( 'Select Post Types', 'acf' ),
249 'type' => 'checkbox',
250 'name' => 'post_type_keys',
251 'prefix' => false,
252 'value' => $selected,
253 'toggle' => true,
254 'choices' => $choices,
255 )
256 );
257 }
258
259 $choices = array();
260 $selected = $this->get_selected_keys();
261 $taxonomies = array_filter(
262 acf_get_internal_post_type_posts( 'acf-taxonomy' ),
263 'acf_internal_post_object_contains_valid_key'
264 );
265
266 if ( $taxonomies ) {
267 foreach ( $taxonomies as $taxonomy ) {
268 $choices[ $taxonomy['key'] ] = esc_html( $taxonomy['title'] );
269 }
270
271 acf_render_field_wrap(
272 array(
273 'label' => __( 'Select Taxonomies', 'acf' ),
274 'type' => 'checkbox',
275 'name' => 'taxonomy_keys',
276 'prefix' => false,
277 'value' => $selected,
278 'toggle' => true,
279 'choices' => $choices,
280 )
281 );
282 }
283
284 $choices = array();
285 $selected = $this->get_selected_keys();
286 $options_pages = array_filter(
287 acf_get_internal_post_type_posts( 'acf-ui-options-page' ),
288 'acf_internal_post_object_contains_valid_key'
289 );
290
291 if ( $options_pages ) {
292 foreach ( $options_pages as $options_page ) {
293 $choices[ $options_page['key'] ] = esc_html( $options_page['title'] );
294 }
295
296 acf_render_field_wrap(
297 array(
298 'label' => __( 'Select Options Pages', 'acf' ),
299 'type' => 'checkbox',
300 'name' => 'ui_options_page_keys',
301 'prefix' => false,
302 'value' => $selected,
303 'toggle' => true,
304 'choices' => $choices,
305 )
306 );
307 }
308 }
309
310 /**
311 * Renders the side panel for selecting ACF items to export via PHP.
312 *
313 * @since 5.6.3
314 */
315 public function html_panel_selection() {
316 ?>
317 <div class="acf-panel acf-panel-selection">
318 <?php $this->html_field_selection(); ?>
319 </div>
320 <?php
321 }
322
323
324 /**
325 * html_archive
326 *
327 * description
328 *
329 * @date 20/10/17
330 * @since 5.6.3
331 *
332 * @param n/a
333 * @return n/a
334 */
335 function html_archive() {
336
337 ?>
338 <div class="acf-postbox-header">
339 <h2 class="acf-postbox-title"><?php esc_html_e( 'Export', 'acf' ); ?></h2>
340 <div class="acf-tip"><i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Select the items you would like to export and then select your export method. Export As JSON to export to a .json file which you can then import to another ACF installation. Generate PHP to export to PHP code which you can place in your theme.', 'acf' ); ?>">?</i></div>
341 </div>
342 <div class="acf-postbox-inner">
343 <div class="acf-fields">
344 <?php $this->html_field_selection(); ?>
345 </div>
346 <p class="acf-submit acf-actions-strip">
347 <button type="submit" name="action" class="acf-btn acf-button-primary" value="download"><?php esc_html_e( 'Export As JSON', 'acf' ); ?></button>
348 <button type="submit" name="action" class="acf-btn acf-btn-secondary" value="generate"><?php esc_html_e( 'Generate PHP', 'acf' ); ?></button>
349 </p>
350 </div>
351 <?php
352 }
353
354 /**
355 * Renders the PHP export screen.
356 *
357 * @since 5.6.3
358 */
359 public function html_single() {
360 ?>
361 <div class="acf-postbox-header">
362 <h2 class="acf-postbox-title"><?php esc_html_e( 'Export - Generate PHP', 'acf' ); ?></h2>
363 <i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( "The following code can be used to register a local version of the selected items. Storing field groups, post types, or taxonomies locally can provide many benefits such as faster load times, version control & dynamic fields/settings. Simply copy and paste the following code to your theme's functions.php file or include it within an external file, then deactivate or delete the items from the ACF admin.", 'acf' ); ?>">?</i>
364 </div>
365 <div class="acf-postbox-columns">
366 <div class="acf-postbox-main">
367 <?php $this->html_generate(); ?>
368 </div>
369 <div class="acf-postbox-side">
370 <?php $this->html_panel_selection(); ?>
371 <p class="acf-submit">
372 <button type="submit" name="action" class="acf-btn" value="generate"><?php esc_html_e( 'Generate PHP', 'acf' ); ?></button>
373 </p>
374 </div>
375 </div>
376 <?php
377 }
378
379 /**
380 * Generates the HTML for the PHP export functionality.
381 *
382 * @since 5.6.3
383 */
384 public function html_generate() {
385 // Prevent default translation and fake __() within string.
386 acf_update_setting( 'l10n_var_export', true );
387
388 $json = $this->get_selected();
389 $to_export = array();
390
391 // Sort by ACF post type first so we can wrap them in related functions.
392 foreach ( $json as $post ) {
393 $post_type = acf_determine_internal_post_type( $post['key'] );
394
395 if ( $post_type ) {
396 $to_export[ $post_type ][] = $post;
397 }
398 }
399
400 echo '<textarea id="acf-export-textarea" readonly="readonly">';
401
402 foreach ( $to_export as $post_type => $posts ) {
403 if ( 'acf-field-group' === $post_type ) {
404 echo "add_action( 'acf/include_fields', function() {\r\n";
405 echo "\tif ( ! function_exists( 'acf_add_local_field_group' ) ) {\r\n\t\treturn;\r\n\t}\r\n\r\n";
406 } elseif ( 'acf-post-type' === $post_type || 'acf-taxonomy' === $post_type ) {
407 echo "add_action( 'init', function() {\r\n";
408 } elseif ( 'acf-ui-options-page' === $post_type ) {
409 echo "add_action( 'acf/init', function() {\r\n";
410 }
411
412 $count = 0;
413 foreach ( $posts as $post ) {
414 if ( $count !== 0 ) {
415 echo "\r\n";
416 }
417
418 echo "\t" . acf_export_internal_post_type_as_php( $post, $post_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc_textarea() used earlier.
419 ++$count;
420 }
421
422 if ( in_array( $post_type, array( 'acf-post-type', 'acf-taxonomy', 'acf-field-group', 'acf-ui-options-page' ), true ) ) {
423 echo "} );\r\n\r\n";
424 }
425
426 if ( 'acf-post-type' === $post_type ) {
427 echo acf_export_enter_title_here( $posts ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc_textarea() used earlier.
428 }
429 }
430
431 echo '</textarea>';
432 ?>
433 <p class="acf-submit">
434 <a class="button" id="acf-export-copy"><?php esc_html_e( 'Copy to clipboard', 'acf' ); ?></a>
435 </p>
436 <script type="text/javascript">
437 (function($){
438 const $a = $('#acf-export-copy');
439 const $textarea = $('#acf-export-textarea');
440
441 // Remove $a if 'copy' is not supported.
442 if( !document.queryCommandSupported('copy') ) {
443 return $a.remove();
444 }
445
446 $a.on('click', function( e ){
447 e.preventDefault();
448
449 $textarea.get(0).select();
450
451 try {
452 var copy = document.execCommand('copy');
453 if ( ! copy ) {
454 return;
455 }
456
457 acf.newTooltip({
458 text: "<?php esc_html_e( 'Copied', 'acf' ); ?>",
459 timeout: 250,
460 target: $(this),
461 });
462 } catch (err) {
463 // Do nothing.
464 }
465 });
466 })(jQuery);
467 </script>
468 <?php
469 }
470
471 /**
472 * Return an array of keys that have been selected in the export tool.
473 *
474 * @since 5.6.3
475 *
476 * @return array|boolean
477 */
478 public function get_selected_keys() {
479 $key_names = array( 'keys', 'taxonomy_keys', 'post_type_keys', 'ui_options_page_keys' );
480 $all_keys = array();
481
482 foreach ( $key_names as $key_name ) {
483 if ( $keys = acf_maybe_get_POST( $key_name ) ) {
484 $all_keys = array_merge( $all_keys, (array) $keys );
485 } elseif ( $keys = acf_maybe_get_GET( $key_name ) ) {
486 $keys = str_replace( ' ', '+', $keys );
487 $keys = explode( '+', $keys );
488 $all_keys = array_merge( $all_keys, (array) $keys );
489 }
490 }
491
492 if ( ! empty( $all_keys ) ) {
493 return $all_keys;
494 }
495
496 return false;
497 }
498
499 /**
500 * Returns the JSON data for given $_POST args.
501 *
502 * @since 5.6.3
503 *
504 * @return array|boolean
505 */
506 public function get_selected() {
507 $selected = $this->get_selected_keys();
508 $json = array();
509
510 if ( ! $selected ) {
511 return false;
512 }
513
514 foreach ( $selected as $key ) {
515 $post_type = acf_determine_internal_post_type( $key );
516 $post = acf_get_internal_post_type( $key, $post_type );
517
518 if ( empty( $post ) ) {
519 continue;
520 }
521
522 if ( 'acf-field-group' === $post_type ) {
523 $post['fields'] = acf_get_fields( $post );
524 }
525
526 $post = acf_prepare_internal_post_type_for_export( $post, $post_type );
527 $json[] = $post;
528 }
529
530 return $json;
531 }
532 }
533
534 // initialize
535 acf_register_admin_tool( 'ACF_Admin_Tool_Export' );
536 endif; // class_exists check
537
538 ?>
539