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 / post-types / admin-field-group.php
advanced-custom-fields / includes / admin / post-types Last commit date
admin-field-group.php 5 months ago admin-field-groups.php 6 months ago admin-post-type.php 6 months ago admin-post-types.php 6 months ago admin-taxonomies.php 6 months ago admin-taxonomy.php 6 months ago index.php 2 years ago
admin-field-group.php
622 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 ( ! class_exists( 'acf_admin_field_group' ) ) :
13
14 /**
15 * ACF Admin Field Group Class
16 *
17 * All the logic for editing a field group
18 */
19 class acf_admin_field_group extends ACF_Admin_Internal_Post_Type {
20
21 /**
22 * The slug for the internal post type.
23 *
24 * @since 6.1
25 * @var string
26 */
27 public $post_type = 'acf-field-group';
28
29 /**
30 * The admin body class used for the post type.
31 *
32 * @since 6.1
33 * @var string
34 */
35 public $admin_body_class = 'acf-admin-single-field-group';
36
37 /**
38 * Constructs the class.
39 *
40 * @since 5.0.0
41 */
42 public function __construct() {
43 parent::__construct();
44
45 add_action( 'wp_ajax_acf/field_group/render_field_settings', array( $this, 'ajax_render_field_settings' ) );
46 add_action( 'wp_ajax_acf/field_group/render_location_rule', array( $this, 'ajax_render_location_rule' ) );
47 add_action( 'wp_ajax_acf/field_group/move_field', array( $this, 'ajax_move_field' ) );
48 }
49
50 /**
51 * Customizes the messages shown when editing a field group.
52 *
53 * @since 5.0.0
54 *
55 * @param array $messages Post type messages.
56 * @return array
57 */
58 public function post_updated_messages( $messages ) {
59 $messages['acf-field-group'] = array(
60 0 => '', // Unused. Messages start at index 1.
61 1 => __( 'Field group updated.', 'acf' ),
62 2 => __( 'Field group updated.', 'acf' ),
63 3 => __( 'Field group deleted.', 'acf' ),
64 4 => __( 'Field group updated.', 'acf' ),
65 5 => false, // field group does not support revisions.
66 6 => __( 'Field group published.', 'acf' ),
67 7 => __( 'Field group saved.', 'acf' ),
68 8 => __( 'Field group submitted.', 'acf' ),
69 9 => __( 'Field group scheduled for.', 'acf' ),
70 10 => __( 'Field group draft updated.', 'acf' ),
71 );
72
73 return $messages;
74 }
75
76 /**
77 * Enqueues any scripts necessary for internal post type.
78 *
79 * @since 5.0.0
80 */
81 public function admin_enqueue_scripts() {
82 parent::admin_enqueue_scripts();
83
84 acf_localize_text(
85 array(
86 'The string "field_" may not be used at the start of a field name' => esc_html__( 'The string "field_" may not be used at the start of a field name', 'acf' ),
87 'This field cannot be moved until its changes have been saved' => esc_html__( 'This field cannot be moved until its changes have been saved', 'acf' ),
88 'Field group title is required' => esc_html__( 'Field group title is required', 'acf' ),
89 'Move field group to trash?' => esc_html__( 'Move field group to trash?', 'acf' ),
90 'No toggle fields available' => esc_html__( 'No toggle fields available', 'acf' ),
91 'Move Custom Field' => esc_html__( 'Move Custom Field', 'acf' ),
92 'Field moved to other group' => esc_html__( 'Field moved to other group', 'acf' ),
93 'Field groups linked successfully.' => esc_html__( 'Field groups linked successfully.', 'acf' ),
94 'Checked' => esc_html__( 'Checked', 'acf' ),
95 '(no label)' => esc_html__( '(no label)', 'acf' ),
96 '(this field)' => esc_html__( '(this field)', 'acf' ),
97 'copy' => esc_html__( 'copy', 'acf' ),
98 'or' => esc_html__( 'or', 'acf' ),
99 'Show this field group if' => esc_html__( 'Show this field group if', 'acf' ),
100 'Null' => esc_html__( 'Null', 'acf' ),
101 'PRO Only' => esc_html__( 'PRO Only', 'acf' ),
102
103 // Conditions.
104 'Has any value' => esc_html__( 'Has any value', 'acf' ),
105 'Has no value' => esc_html__( 'Has no value', 'acf' ),
106 'Value is equal to' => esc_html__( 'Value is equal to', 'acf' ),
107 'Value is not equal to' => esc_html__( 'Value is not equal to', 'acf' ),
108 'Value matches pattern' => esc_html__( 'Value matches pattern', 'acf' ),
109 'Value contains' => esc_html__( 'Value contains', 'acf' ),
110 'Value is greater than' => esc_html__( 'Value is greater than', 'acf' ),
111 'Value is less than' => esc_html__( 'Value is less than', 'acf' ),
112 'Selection is greater than' => esc_html__( 'Selection is greater than', 'acf' ),
113 'Selection is less than' => esc_html__( 'Selection is less than', 'acf' ),
114 'Relationship is equal to' => esc_html__( 'Relationship is equal to', 'acf' ),
115 'Relationship is not equal to' => esc_html__( 'Relationship is not equal to', 'acf' ),
116 'Relationships contain' => esc_html__( 'Relationships contain', 'acf' ),
117 'Relationships do not contain' => esc_html__( 'Relationships do not contain', 'acf' ),
118 'Post is equal to' => esc_html__( 'Post is equal to', 'acf' ),
119 'Post is not equal to' => esc_html__( 'Post is not equal to', 'acf' ),
120 'Posts contain' => esc_html__( 'Posts contain', 'acf' ),
121 'Posts do not contain' => esc_html__( 'Posts do not contain', 'acf' ),
122 'Has any post selected' => esc_html__( 'Has any post selected', 'acf' ),
123 'Has no post selected' => esc_html__( 'Has no post selected', 'acf' ),
124 'Has any relationship selected' => esc_html__( 'Has any relationship selected', 'acf' ),
125 'Has no relationship selected' => esc_html__( 'Has no relationship selected', 'acf' ),
126 'Page is equal to' => esc_html__( 'Page is equal to', 'acf' ),
127 'Page is not equal to' => esc_html__( 'Page is not equal to', 'acf' ),
128 'Pages contain' => esc_html__( 'Pages contain', 'acf' ),
129 'Pages do not contain' => esc_html__( 'Pages do not contain', 'acf' ),
130 'Has any page selected' => esc_html__( 'Has any page selected', 'acf' ),
131 'Has no page selected' => esc_html__( 'Has no page selected', 'acf' ),
132 'User is equal to' => esc_html__( 'User is equal to', 'acf' ),
133 'User is not equal to' => esc_html__( 'User is not equal to', 'acf' ),
134 'Users contain' => esc_html__( 'Users contain', 'acf' ),
135 'Users do not contain' => esc_html__( 'Users do not contain', 'acf' ),
136 'Has any user selected' => esc_html__( 'Has any user selected', 'acf' ),
137 'Has no user selected' => esc_html__( 'Has no user selected', 'acf' ),
138 'Term is equal to' => esc_html__( 'Term is equal to', 'acf' ),
139 'Term is not equal to' => esc_html__( 'Term is not equal to', 'acf' ),
140 'Terms contain' => esc_html__( 'Terms contain', 'acf' ),
141 'Terms do not contain' => esc_html__( 'Terms do not contain', 'acf' ),
142 'Has any term selected' => esc_html__( 'Has any term selected', 'acf' ),
143 'Has no term selected' => esc_html__( 'Has no term selected', 'acf' ),
144
145 // Custom Select2 templates.
146 'Type to search...' => esc_html__( 'Type to search...', 'acf' ),
147 'This Field' => esc_html__( 'This Field', 'acf' ),
148 )
149 );
150
151 acf_localize_data(
152 array(
153 'fieldTypes' => acf_get_field_types_info(),
154 'fieldCategoriesL10n' => acf_get_field_categories_i18n(),
155 'PROUpgradeURL' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'field-type-selection' ),
156 'PROFieldTypes' => acf_get_pro_field_types(),
157 'PROLocationTypes' => array(
158 'block' => esc_html__( 'Block', 'acf' ),
159 'options_page' => esc_html__( 'Options Page', 'acf' ),
160 ),
161 )
162 );
163
164 do_action( 'acf/field_group/admin_enqueue_scripts' );
165 }
166
167 /**
168 * Set up functionality for the field group edit page.
169 *
170 * @since 3.1.8
171 */
172 public function admin_head() {
173 global $post, $field_group;
174
175 // Set global var.
176 $field_group = acf_get_field_group( $post->ID );
177
178 // metaboxes.
179 add_meta_box( 'acf-field-group-fields', __( 'Fields', 'acf' ), array( $this, 'mb_fields' ), 'acf-field-group', 'normal', 'high' );
180 add_meta_box( 'acf-field-group-options', __( 'Settings', 'acf' ), array( $this, 'mb_options' ), 'acf-field-group', 'normal', 'high' );
181
182 // actions.
183 add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
184 add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
185
186 // filters.
187 add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
188 add_filter( 'get_user_option_screen_layout_acf-field-group', array( $this, 'screen_layout' ), 10, 1 );
189
190 // 3rd party hook.
191 do_action( 'acf/field_group/admin_head' );
192 }
193
194 /**
195 * This action will allow ACF to render metaboxes after the title.
196 */
197 public function edit_form_after_title() {
198 global $post;
199
200 // Render post data.
201 acf_form_data(
202 array(
203 'screen' => 'field_group',
204 'post_id' => $post->ID,
205 'delete_fields' => 0,
206 'validation' => 0,
207 )
208 );
209 }
210
211 /**
212 * This function will add extra HTML to the acf form data element
213 *
214 * @since 5.3.8
215 *
216 * @param array $args Arguments array to pass through to action.
217 * @return void
218 */
219 public function form_data( $args ) {
220 do_action( 'acf/field_group/form_data', $args );
221 }
222
223 /**
224 * This function will append extra l10n strings to the acf JS object
225 *
226 * @since 5.3.8
227 *
228 * @param array $l10n The array of translated strings.
229 * @return array $l10n
230 */
231 public function admin_l10n( $l10n ) {
232 return apply_filters( 'acf/field_group/admin_l10n', $l10n );
233 }
234
235 /**
236 * Admin footer third party hook support
237 *
238 * @since 5.3.2
239 */
240 public function admin_footer() {
241 $this->include_pro_features();
242 do_action( 'acf/field_group/admin_footer' );
243 }
244
245 /**
246 * Renders HTML for the ACF PRO features upgrade notice.
247 */
248 public function include_pro_features() {
249 // Bail if on PRO.
250 if ( acf_is_pro() && acf_pro_is_license_active() ) {
251 return;
252 }
253
254 // Bail if not the edit field group screen.
255 if ( ! acf_is_screen( 'acf-field-group' ) ) {
256 return;
257 }
258
259 acf_get_view( 'acf-field-group/pro-features' );
260 }
261
262 /**
263 * Screen settings html output
264 *
265 * @since 3.6.0
266 *
267 * @param string $html Current screen settings HTML.
268 * @return string $html
269 */
270 public function screen_settings( $html ) {
271 $show_field_keys = acf_get_user_setting( 'show_field_keys' ) ? 'checked="checked"' : '';
272 $show_field_settings_tabs = acf_get_user_setting( 'show_field_settings_tabs', true ) ? 'checked="checked"' : '';
273 $hide_field_settings_tabs = apply_filters( 'acf/field_group/disable_field_settings_tabs', false );
274
275 $html .= '<div id="acf-append-show-on-screen" class="acf-hidden">';
276 $html .= '<label for="acf-field-key-hide"><input id="acf-field-key-hide" type="checkbox" value="1" name="show_field_keys" ' . $show_field_keys . ' /> ' . __( 'Field Keys', 'acf' ) . '</label>';
277
278 if ( ! $hide_field_settings_tabs ) {
279 $html .= '<label for="acf-field-settings-tabs"><input id="acf-field-settings-tabs" type="checkbox" value="1" name="show_field_settings_tabs" ' . $show_field_settings_tabs . ' />' . __( 'Field Settings Tabs', 'acf' ) . '</label>';
280 }
281
282 $html .= '</div>';
283
284 return $html;
285 }
286
287 /**
288 * Sets the "Edit Field Group" screen to use a one-column layout.
289 *
290 * @param integer $columns Number of columns for layout.
291 * @return integer
292 */
293 public function screen_layout( $columns = 0 ) {
294 return 1;
295 }
296
297 /**
298 * This function will customize the publish metabox
299 *
300 * @since 5.2.9
301 */
302 public function post_submitbox_misc_actions() {
303 global $field_group;
304 $status_label = $field_group['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
305
306 ?>
307 <script type="text/javascript">
308 (function($) {
309 $('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
310 })(jQuery);
311 </script>
312 <?php
313 }
314
315 /**
316 * Saves field group data.
317 *
318 * @since 1.0.0
319 *
320 * @param integer $post_id The post ID.
321 * @param WP_Post $post The post object.
322 * @return integer $post_id
323 */
324 public function save_post( $post_id, $post ) {
325 if ( ! $this->verify_save_post( $post_id, $post ) ) {
326 return $post_id;
327 }
328
329 // disable filters to ensure ACF loads raw data from DB.
330 acf_disable_filters();
331
332 // save fields.
333 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated by WordPress.
334 if ( ! empty( $_POST['acf_fields'] ) ) {
335
336 // loop.
337 foreach ( $_POST['acf_fields'] as $field ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
338
339 if ( ! isset( $field['key'] ) ) {
340 continue;
341 }
342
343 // vars.
344 $specific = false;
345 $save = acf_extract_var( $field, 'save' );
346
347 // only saved field if has changed.
348 if ( $save == 'meta' ) {
349 $specific = array(
350 'menu_order',
351 'post_parent',
352 );
353 }
354
355 // set parent.
356 if ( ! $field['parent'] ) {
357 $field['parent'] = $post_id;
358 }
359
360 // save field.
361 acf_update_field( $field, $specific );
362 }
363 }
364
365 // delete fields.
366 if ( acf_maybe_get_POST( '_acf_delete_fields', false ) ) { // phpcs:ignore -- Sanitized below, unslash not needed
367
368 // clean.
369 $ids = explode( '|', $_POST['_acf_delete_fields'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput -- Sanitized below, unslash not required.
370 $ids = array_map( 'intval', $ids );
371
372 // loop.
373 foreach ( $ids as $id ) {
374
375 // bai early if no id.
376 if ( ! $id ) {
377 continue;
378 }
379
380 // delete.
381 acf_delete_field( $id );
382 }
383 }
384
385 $_POST['acf_field_group']['ID'] = $post_id;
386 // phpcs:disable WordPress.Security.ValidatedSanitizedInput
387 $_POST['acf_field_group']['title'] = isset( $_POST['post_title'] ) ? $_POST['post_title'] : ''; // Post title is stored unsafe like WordPress, escaped on output.
388
389 // save field group.
390 acf_update_field_group( $_POST['acf_field_group'] );
391 // phpcs:enable WordPress.Security.ValidatedSanitizedInput
392 // phpcs:enable WordPress.Security.NonceVerification.Missing
393
394 return $post_id;
395 }
396
397 /**
398 * This function will render the HTML for the metabox 'acf-field-group-fields'
399 *
400 * @since 5.0.0
401 */
402 public function mb_fields() {
403 global $field_group;
404
405 $view = array(
406 'fields' => acf_get_fields( $field_group ),
407 'parent' => 0,
408 );
409
410 acf_get_view( $this->post_type . '/fields', $view );
411 }
412
413 /**
414 * This function will render the HTML for the metabox 'acf-field-group-pro-features'
415 *
416 * @since 6.0.0
417 */
418 public function mb_pro_features() {
419 acf_get_view( $this->post_type . '/pro-features' );
420 }
421
422 /**
423 * This function will render the HTML for the metabox 'acf-field-group-options'
424 *
425 * @since 5.0.0
426 */
427 public function mb_options() {
428 global $field_group;
429
430 // Field group key (leave in for compatibility).
431 if ( ! acf_is_field_group_key( $field_group['key'] ) ) {
432 $field_group['key'] = uniqid( 'group_' );
433 }
434
435 acf_get_view( $this->post_type . '/options' );
436 }
437
438 /**
439 * This function can be accessed via an AJAX action and will return the result from the render_location_value function
440 *
441 * @since 5.0.0
442 */
443 public function ajax_render_location_rule() {
444 // validate.
445 if ( ! acf_verify_ajax() ) {
446 die();
447 }
448
449 // verify user capability.
450 if ( ! acf_current_user_can_admin() ) {
451 die();
452 }
453
454 if ( empty( $_POST['rule'] ) ) {
455 die();
456 }
457
458 // validate rule.
459 $rule = acf_validate_location_rule( acf_sanitize_request_args( $_POST['rule'] ) ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- values not saved.
460
461 acf_get_view(
462 'acf-field-group/location-rule',
463 array(
464 'rule' => $rule,
465 )
466 );
467
468 die();
469 }
470
471 /**
472 * This function will return HTML containing the field's settings based on it's new type
473 *
474 * @since 5.0.0
475 */
476 public function ajax_render_field_settings() {
477 // Verify the current request.
478 if ( ! acf_verify_ajax() || ! acf_current_user_can_admin() ) {
479 wp_send_json_error();
480 }
481
482 // Make sure we have a field.
483 $field = acf_maybe_get_POST( 'field' );
484 if ( ! $field ) {
485 wp_send_json_error();
486 }
487
488 $field['prefix'] = acf_maybe_get_POST( 'prefix' );
489 $field = acf_get_valid_field( $field );
490 $tabs = acf_get_combined_field_type_settings_tabs();
491 $tab_keys = array_keys( $tabs );
492 $sections = array();
493
494 foreach ( $tab_keys as $tab ) {
495 ob_start();
496
497 if ( 'general' === $tab ) {
498 // Back-compat for fields not using tab-specific hooks.
499 do_action( "acf/render_field_settings/type={$field['type']}", $field );
500 }
501
502 do_action( "acf/field_group/render_field_settings_tab/{$tab}/type={$field['type']}", $field );
503 do_action( "acf/render_field_{$tab}_settings/type={$field['type']}", $field );
504 do_action( "acf/render_field_{$tab}_settings", $field );
505
506 $sections[ $tab ] = ob_get_clean();
507 }
508
509 wp_send_json_success( $sections );
510 }
511
512 /**
513 * Moves fields between field groups via AJAX.
514 *
515 * @since 5.0.0
516 *
517 * @return void
518 */
519 public function ajax_move_field() {
520 // Disable filters to ensure ACF loads raw data from DB.
521 acf_disable_filters();
522
523 // phpcs:disable WordPress.Security.NonceVerification.Missing
524 $args = acf_parse_args(
525 $_POST,
526 array(
527 'nonce' => '',
528 'post_id' => 0,
529 'field_id' => 0,
530 'field_group_id' => 0,
531 )
532 );
533 // phpcs:enable WordPress.Security.NonceVerification.Missing
534
535 // Verify nonce.
536 if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) ) {
537 die();
538 }
539
540 // Verify user capability.
541 if ( ! acf_current_user_can_admin() ) {
542 die();
543 }
544
545 // Move the field if the user has confirmed.
546 if ( $args['field_id'] && $args['field_group_id'] ) {
547 $field = acf_get_field( $args['field_id'] );
548 $old_field_group = acf_get_field_group( $args['post_id'] );
549 $new_field_group = acf_get_field_group( $args['field_group_id'] );
550
551 // Update the field parent and remove conditional logic.
552 $field['parent'] = $new_field_group['ID'];
553 $field['conditional_logic'] = 0;
554
555 // Update the field in the database.
556 acf_update_field( $field );
557
558 // Fire `acf/update_field_group` action hook so JSON can sync if necessary.
559 do_action( 'acf/update_field_group', $old_field_group );
560 do_action( 'acf/update_field_group', $new_field_group );
561
562 // Output HTML.
563 $link = '<a href="' . admin_url( 'post.php?post=' . $new_field_group['ID'] . '&action=edit' ) . '" target="_blank">' . esc_html( $new_field_group['title'] ) . '</a>';
564
565 echo '' .
566 '<p><strong>' . esc_html__( 'Move Complete.', 'acf' ) . '</strong></p>' .
567 '<p>' . sprintf(
568 /* translators: Confirmation message once a field has been moved to a different field group. */
569 acf_punctify( __( 'The %1$s field can now be found in the %2$s field group', 'acf' ) ),
570 esc_html( $field['label'] ),
571 $link //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
572 ) . '</p>' .
573 '<a href="#" class="button button-primary acf-close-popup">' . esc_html__( 'Close Modal', 'acf' ) . '</a>';
574 die();
575 }
576
577 // Get all field groups.
578 $field_groups = acf_get_field_groups();
579 $choices = array();
580
581 if ( ! empty( $field_groups ) ) {
582 foreach ( $field_groups as $field_group ) {
583 // Bail early if no ID.
584 if ( ! $field_group['ID'] ) {
585 continue;
586 }
587
588 // Bail early if is current.
589 if ( $field_group['ID'] == $args['post_id'] ) {
590 continue;
591 }
592
593 $choices[ $field_group['ID'] ] = $field_group['title'];
594 }
595 }
596
597 // Render options.
598 $field = acf_get_valid_field(
599 array(
600 'type' => 'select',
601 'name' => 'acf_field_group',
602 'choices' => $choices,
603 'aria-label' => __( 'Please select the destination for this field', 'acf' ),
604 )
605 );
606
607 echo '<p>' . esc_html__( 'Please select the destination for this field', 'acf' ) . '</p>';
608 echo '<form id="acf-move-field-form">';
609 acf_render_field_wrap( $field );
610 echo '<button type="submit" class="acf-btn">' . esc_html__( 'Move Field', 'acf' ) . '</button>';
611 echo '</form>';
612
613 die();
614 }
615 }
616
617 // initialize.
618 new acf_admin_field_group();
619 endif; // Class exists check.
620
621 ?>
622