PluginProbe ʕ •ᴥ•ʔ
Advanced Custom Fields (ACF®) / 6.8.8
Advanced Custom Fields (ACF®) v6.8.8
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-groups.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-groups.php
392 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_Field_Groups' ) ) :
17 class ACF_Admin_Field_Groups extends ACF_Admin_Internal_Post_Type_List {
18
19 /**
20 * The slug for the internal post type.
21 *
22 * @var string
23 */
24 public $post_type = 'acf-field-group';
25
26 /**
27 * The admin body class used for the post type.
28 *
29 * @var string
30 */
31 public $admin_body_class = 'acf-admin-field-groups';
32
33 /**
34 * The name of the store used for the post type.
35 *
36 * @var string
37 */
38 public $store = 'field-groups';
39
40 /**
41 * Constructor.
42 *
43 * @since 5.0.0
44 */
45 public function __construct() {
46 add_action( 'admin_menu', array( $this, 'admin_menu' ), 7 );
47 add_action( 'load-edit.php', array( $this, 'handle_redirection' ) );
48 add_action( 'post_class', array( $this, 'get_admin_table_post_classes' ), 10, 3 );
49
50 parent::__construct();
51 }
52
53 /**
54 * Add any menu items required for field groups.
55 *
56 * @since 6.1
57 */
58 public function admin_menu() {
59 $parent_slug = 'edit.php?post_type=acf-field-group';
60 $cap = acf_get_setting( 'capability' );
61 add_submenu_page( $parent_slug, __( 'Field Groups', 'acf' ), __( 'Field Groups', 'acf' ), $cap, $parent_slug );
62 }
63
64 /**
65 * Redirects users from ACF 4.0 admin page.
66 *
67 * @since 5.7.6
68 */
69 public function handle_redirection() {
70 if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'acf' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
71 wp_safe_redirect( $this->get_admin_url() );
72 exit;
73 }
74 }
75
76 /**
77 * Customizes the admin table columns.
78 *
79 * @date 1/4/20
80 * @since 5.9.0
81 *
82 * @param array $_columns The columns array.
83 * @return array
84 */
85 public function admin_table_columns( $_columns ) {
86 // Set the "no found" label to be our custom HTML for no results.
87 if ( empty( acf_request_arg( 's' ) ) ) {
88 global $wp_post_types;
89 $wp_post_types['acf-field-group']->labels->not_found = $this->get_not_found_html();
90 }
91
92 $columns = array(
93 'cb' => $_columns['cb'],
94 'title' => $_columns['title'],
95 'acf-description' => __( 'Description', 'acf' ),
96 'acf-key' => __( 'Key', 'acf' ),
97 'acf-location' => __( 'Location', 'acf' ),
98 'acf-count' => __( 'Fields', 'acf' ),
99 );
100
101 if ( acf_get_local_json_files( $this->post_type ) ) {
102 $columns['acf-json'] = __( 'Local JSON', 'acf' );
103 }
104
105 return $columns;
106 }
107
108 /**
109 * Renders a specific admin table column.
110 *
111 * @date 17/4/20
112 * @since 5.9.0
113 *
114 * @param string $column_name The name of the column to display.
115 * @param array $post The main ACF post array.
116 * @return void
117 */
118 public function render_admin_table_column( $column_name, $post ) {
119 switch ( $column_name ) {
120
121 // Key.
122 case 'acf-key':
123 echo '<i class="acf-icon acf-icon-key-solid"></i>';
124 echo esc_html( $post['key'] );
125 break;
126
127 // Description.
128 case 'acf-description':
129 if ( ( is_string( $post['description'] ) || is_numeric( $post['description'] ) ) && ! empty( $post['description'] ) ) {
130 echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
131 } else {
132 echo '<span class="acf-emdash" aria-hidden="true">—</span>';
133 echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
134 }
135 break;
136
137 // Location.
138 case 'acf-location':
139 $this->render_admin_table_column_locations( $post );
140 break;
141
142 // Count.
143 case 'acf-count':
144 $this->render_admin_table_column_num_fields( $post );
145 break;
146
147 // Local JSON.
148 case 'acf-json':
149 $this->render_admin_table_column_local_status( $post );
150 break;
151 }
152 }
153
154 /**
155 * Displays a visual representation of the field group's locations.
156 *
157 * @date 1/4/20
158 * @since 5.9.0
159 *
160 * @param array $field_group The field group.
161 * @return void
162 */
163 public function render_admin_table_column_locations( $field_group ) {
164 $objects = array();
165
166 // Loop over location rules and determine connected object types.
167 if ( $field_group['location'] ) {
168 foreach ( $field_group['location'] as $i => $rules ) {
169
170 // Determine object types for each rule.
171 foreach ( $rules as $j => $rule ) {
172
173 // Get location type and subtype for the current rule.
174 $location = acf_get_location_rule( $rule['param'] );
175 $location_object_type = '';
176 $location_object_subtype = '';
177 if ( $location ) {
178 $location_object_type = $location->get_object_type( $rule );
179 $location_object_subtype = $location->get_object_subtype( $rule );
180 }
181 $rules[ $j ]['object_type'] = $location_object_type;
182 $rules[ $j ]['object_subtype'] = $location_object_subtype;
183 }
184
185 // Now that each $rule conains object type data...
186 $object_types = array_column( $rules, 'object_type' );
187 $object_types = array_filter( $object_types );
188 $object_types = array_values( $object_types );
189 if ( $object_types ) {
190 $object_type = $object_types[0];
191 } else {
192 continue;
193 }
194
195 $object_subtypes = array_column( $rules, 'object_subtype' );
196 $object_subtypes = array_filter( $object_subtypes );
197 $object_subtypes = array_values( $object_subtypes );
198 $object_subtypes = array_map( 'acf_array', $object_subtypes );
199 if ( count( $object_subtypes ) > 1 ) {
200 $object_subtypes = call_user_func_array( 'array_intersect', $object_subtypes );
201 $object_subtypes = array_values( $object_subtypes );
202 } elseif ( $object_subtypes ) {
203 $object_subtypes = $object_subtypes[0];
204 } else {
205 $object_subtypes = array( '' );
206 }
207
208 // Append to objects.
209 foreach ( $object_subtypes as $object_subtype ) {
210 $object = acf_get_object_type( $object_type, $object_subtype );
211 if ( $object ) {
212 $objects[ $object->name ] = $object;
213 }
214 }
215 }
216 }
217
218 // Reset keys.
219 $objects = array_values( $objects );
220
221 // Display.
222 $html = '';
223 if ( $objects ) {
224 $limit = 3;
225 $total = count( $objects );
226
227 // Icon.
228 $html .= '<span class="dashicons ' . $objects[0]->icon . ( $total > 1 ? ' acf-multi-dashicon' : '' ) . '"></span>';
229
230 // Labels.
231 $labels = array_column( $objects, 'label' );
232 $labels = array_slice( $labels, 0, 3 );
233 $html .= implode( ', ', $labels );
234
235 // More.
236 if ( $total > $limit ) {
237 $html .= ', ...';
238 }
239 } else {
240 $html = '<span class="dashicons dashicons-businesswoman"></span> ' . __( 'Various', 'acf' );
241 }
242
243 // Filter.
244 echo acf_esc_html( $html );
245 }
246
247 /**
248 * Renders the number of fields created for the field group in the list table.
249 *
250 * @since 6.1.5
251 *
252 * @param array $field_group The main field group array.
253 * @return void
254 */
255 public function render_admin_table_column_num_fields( $field_group ) {
256 $field_count = acf_get_field_count( $field_group );
257
258 if ( ! $field_count || ! is_numeric( $field_count ) ) {
259 echo '<span class="acf-emdash" aria-hidden="true">—</span>';
260 echo '<span class="screen-reader-text">' . esc_html__( 'No fields', 'acf' ) . '</span>';
261 return;
262 }
263
264 // If in JSON but not synced or in trash, the link won't work.
265 if ( empty( $field_group['ID'] ) || 'trash' === get_post_status( $field_group['ID'] ) ) {
266 echo esc_html( number_format_i18n( $field_count ) );
267 return;
268 }
269
270 printf(
271 '<a href="%s">%s</a>',
272 esc_url( admin_url( 'post.php?action=edit&post=' . $field_group['ID'] ) ),
273 esc_html( number_format_i18n( $field_count ) )
274 );
275 }
276
277 /**
278 * Gets the class(es) to be used by field groups in the list table.
279 *
280 * @since 6.2.8
281 *
282 * @param array $classes An array of the classes used by the field group.
283 * @param array $css_class An array of additional classes added to the field group.
284 * @param integer $post_id The ID of the field group.
285 * @return array
286 */
287 public function get_admin_table_post_classes( $classes, $css_class, $post_id ) {
288 // Bail early if not in the field group list table.
289 if ( ! is_admin() || $this->post_type !== get_post_type( $post_id ) ) {
290 return $classes;
291 }
292
293 return apply_filters( 'acf/field_group/list_table_classes', $classes, $css_class, $post_id );
294 }
295
296 /**
297 * Fires when trashing a field group.
298 *
299 * @date 8/01/2014
300 * @since 5.0.0
301 *
302 * @param integer $post_id The post ID.
303 * @return void
304 */
305 public function trashed_post( $post_id ) {
306 if ( get_post_type( $post_id ) === $this->post_type ) {
307 acf_trash_field_group( $post_id );
308 }
309 }
310
311 /**
312 * Fires when untrashing a field group.
313 *
314 * @date 8/01/2014
315 * @since 5.0.0
316 *
317 * @param integer $post_id The post ID.
318 * @return void
319 */
320 public function untrashed_post( $post_id ) {
321 if ( get_post_type( $post_id ) === $this->post_type ) {
322 acf_untrash_field_group( $post_id );
323 }
324 }
325
326 /**
327 * Fires when deleting a field group.
328 *
329 * @date 8/01/2014
330 * @since 5.0.0
331 *
332 * @param integer $post_id The post ID.
333 * @return void
334 */
335 public function deleted_post( $post_id ) {
336 if ( get_post_type( $post_id ) === $this->post_type ) {
337 acf_delete_field_group( $post_id );
338 }
339 }
340
341 /**
342 * Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
343 *
344 * @since 6.1
345 *
346 * @param string $action The action being performed.
347 * @param integer $count The number of items the action was performed on.
348 * @return string
349 */
350 public function get_action_notice_text( $action, $count = 1 ) {
351 $text = '';
352 $count = (int) $count;
353
354 switch ( $action ) {
355 case 'acfactivatecomplete':
356 $text = sprintf(
357 /* translators: %s number of field groups activated */
358 _n( 'Field group activated.', '%s field groups activated.', $count, 'acf' ),
359 $count
360 );
361 break;
362 case 'acfdeactivatecomplete':
363 $text = sprintf(
364 /* translators: %s number of field groups deactivated */
365 _n( 'Field group deactivated.', '%s field groups deactivated.', $count, 'acf' ),
366 $count
367 );
368 break;
369 case 'acfduplicatecomplete':
370 $text = sprintf(
371 /* translators: %s number of field groups duplicated */
372 _n( 'Field group duplicated.', '%s field groups duplicated.', $count, 'acf' ),
373 $count
374 );
375 break;
376 case 'acfsynccomplete':
377 $text = sprintf(
378 /* translators: %s number of field groups synchronized */
379 _n( 'Field group synchronized.', '%s field groups synchronized.', $count, 'acf' ),
380 $count
381 );
382 break;
383 }
384
385 return $text;
386 }
387 }
388
389 // Instantiate.
390 acf_new_instance( 'ACF_Admin_Field_Groups' );
391 endif; // Class exists check.
392