Create New Item
×
Item Type
File
Folder
Item Name
×
Search file in folder and subfolders...
File Manager
/
wp-content
/
plugins
/
advanced-custom-fields
/
includes
/
admin
Advanced Search
Upload
New Item
Settings
Back
Back Up
Advanced Editor
Save
<?php if (!defined('ABSPATH')) { exit; } if (!class_exists('ACF_Admin_Field_Groups')) { class ACF_Admin_Field_Groups { public $sync = array(); public $view = ''; public function __construct() { add_action('load-edit.php', array($this, 'handle_redirection')); add_action('current_screen', array($this, 'current_screen')); add_action('trashed_post', array($this, 'trashed_post')); add_action('untrashed_post', array($this, 'untrashed_post')); add_action('deleted_post', array($this, 'deleted_post')); } public function get_admin_url($params = '') { return admin_url("edit.php?post_type=acf-field-group{$params}"); } public function get_current_admin_url($params = '') { return $this->get_admin_url(($this->view ? '&post_status=' . $this->view : '') . $params); } public function handle_redirection() { if (isset($_GET['post_type']) && $_GET['post_type'] === 'acf') { wp_redirect($this->get_admin_url()); exit; } } public function current_screen() { if (!acf_is_screen('edit-acf-field-group')) { return; } $this->view = isset($_GET['post_status']) ? sanitize_text_field($_GET['post_status']) : ''; $this->setup_sync(); $this->check_sync(); $this->check_duplicate(); global $wp_post_statuses; $wp_post_statuses['publish']->label_count = _n_noop('Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'acf'); $wp_post_statuses['trash'] = acf_extract_var($wp_post_statuses, 'trash'); add_action('admin_enqueue_scripts', array($this, 'admin_enqueue_scripts')); add_action('admin_body_class', array($this, 'admin_body_class')); add_filter('views_edit-acf-field-group', array($this, 'admin_table_views'), 10, 1); add_filter('manage_acf-field-group_posts_columns', array($this, 'admin_table_columns'), 10, 1); add_action('manage_acf-field-group_posts_custom_column', array($this, 'admin_table_columns_html'), 10, 2); add_filter('display_post_states', array($this, 'display_post_states'), 10, 2); add_filter('bulk_actions-edit-acf-field-group', array($this, 'admin_table_bulk_actions'), 10, 1); add_action('admin_footer', array($this, 'admin_footer'), 1); if ($this->view !== 'trash') { add_filter('page_row_actions', array($this, 'page_row_actions'), 10, 2); } if ($this->view === 'sync') { add_action('admin_footer', array($this, 'admin_footer__sync'), 1); } } public function setup_sync() { if (acf_get_local_json_files()) { $all_field_groups = acf_get_field_groups(); foreach ($all_field_groups as $field_group) { $local = acf_maybe_get($field_group, 'local'); $modified = acf_maybe_get($field_group, 'modified'); $private = acf_maybe_get($field_group, 'private'); if ($private) { continue; } elseif ($local !== 'json') { continue; } elseif (!$field_group['ID']) { $this->sync[$field_group['key']] = $field_group; } elseif ($modified && $modified > get_post_modified_time('U', true, $field_group['ID'])) { $this->sync[$field_group['key']] = $field_group; } } } } public function admin_enqueue_scripts() { acf_enqueue_script('acf'); acf_localize_text(array('Review local JSON changes' => __('Review local JSON changes', 'acf'), 'Loading diff' => __('Loading diff', 'acf'), 'Sync changes' => __('Sync changes', 'acf'))); } public function admin_body_class($classes) { $classes .= ' acf-admin-field-groups'; if ($this->view) { $classes .= " view-{$this->view}"; } return $classes; } public function get_disabled_post_state() { return '<span class="dashicons dashicons-hidden"></span> ' . _x('Disabled', 'post status', 'acf'); } public function display_post_states($post_states, $post) { if ($post->post_status === 'acf-disabled') { $post_states['acf-disabled'] = $this->get_disabled_post_state(); } return $post_states; } public function admin_table_columns($_columns) { $columns = array('cb' => $_columns['cb'], 'title' => $_columns['title'], 'acf-description' => __('Description', 'acf'), 'acf-key' => __('Key', 'acf'), 'acf-location' => __('Location', 'acf'), 'acf-count' => __('Fields', 'acf')); if (acf_get_local_json_files()) { $columns['acf-json'] = __('Local JSON', 'acf'); } return $columns; } public function admin_table_columns_html($column_name, $post_id) { $field_group = acf_get_field_group($post_id); if ($field_group) { $this->render_admin_table_column($column_name, $field_group); } } public function render_admin_table_column($column_name, $field_group) { switch ($column_name) { case 'acf-key': echo esc_html($field_group['key']); break; case 'acf-description': if ($field_group['description']) { echo '<span class="acf-description">' . acf_esc_html($field_group['description']) . '</span>'; } break; case 'acf-location': $this->render_admin_table_column_locations($field_group); break; case 'acf-count': echo esc_html(acf_get_field_count($field_group)); break; case 'acf-json': $this->render_admin_table_column_local_status($field_group); break; } } public function render_admin_table_column_locations($field_group) { $objects = array(); if ($field_group['location']) { foreach ($field_group['location'] as $i => $rules) { foreach ($rules as $j => $rule) { $location = acf_get_location_rule($rule['param']); $location_object_type = ''; $location_object_subtype = ''; if ($location) { $location_object_type = $location->get_object_type($rule); $location_object_subtype = $location->get_object_subtype($rule); } $rules[$j]['object_type'] = $location_object_type; $rules[$j]['object_subtype'] = $location_object_subtype; } $object_types = array_column($rules, 'object_type'); $object_types = array_filter($object_types); $object_types = array_values($object_types); if ($object_types) { $object_type = $object_types[0]; } else { continue; } $object_subtypes = array_column($rules, 'object_subtype'); $object_subtypes = array_filter($object_subtypes); $object_subtypes = array_values($object_subtypes); $object_subtypes = array_map('acf_array', $object_subtypes); if (count($object_subtypes) > 1) { $object_subtypes = call_user_func_array('array_intersect', $object_subtypes); $object_subtypes = array_values($object_subtypes); } elseif ($object_subtypes) { $object_subtypes = $object_subtypes[0]; } else { $object_subtypes = array(''); } foreach ($object_subtypes as $object_subtype) { $object = acf_get_object_type($object_type, $object_subtype); if ($object) { $objects[$object->name] = $object; } } } } $objects = array_values($objects); $html = ''; if ($objects) { $limit = 3; $total = count($objects); $html .= '<span class="dashicons ' . $objects[0]->icon . ($total > 1 ? ' acf-multi-dashicon' : '') . '"></span> '; $labels = array_column($objects, 'label'); $labels = array_slice($labels, 0, 3); $html .= implode(', ', $labels); if ($total > $limit) { $html .= ', ...'; } } else { $html = '<span class="dashicons dashicons-businesswoman"></span> ' . __('Various', 'acf'); } echo acf_esc_html($html); } public function get_human_readable_file_location($file) { $theme_path = get_stylesheet_directory(); if (strpos($file, $theme_path) !== false) { $rel_file = str_replace($theme_path, '', $file); $located = sprintf(__('Located in theme: %s', 'acf'), $rel_file); } elseif (strpos($file, WP_PLUGIN_DIR) !== false) { $rel_file = str_replace(WP_PLUGIN_DIR, '', $file); $located = sprintf(__('Located in plugin: %s', 'acf'), $rel_file); } else { $rel_file = str_replace(ABSPATH, '', $file); $located = sprintf(__('Located in: %s', 'acf'), $rel_file); } return $located; } public function render_admin_table_column_local_status($field_group) { $json = acf_get_local_json_files(); if (isset($json[$field_group['key']])) { $file = $json[$field_group['key']]; if (isset($this->sync[$field_group['key']])) { $url = $this->get_admin_url('&acfsync=' . $field_group['key'] . '&_wpnonce=' . wp_create_nonce('bulk-posts')); echo '<strong>' . __('Sync available', 'acf') . '</strong>'; if ($field_group['ID']) { echo '<div class="row-actions"> <span class="sync"><a href="' . esc_url($url) . '">' . __('Sync', 'acf') . '</a> | </span> <span class="review"><a href="#" data-event="review-sync" data-id="' . esc_attr($field_group['ID']) . '" data-href="' . esc_url($url) . '">' . __('Review changes', 'acf') . '</a></span> </div>'; } else { echo '<div class="row-actions"> <span class="sync"><a href="' . esc_url($url) . '">' . __('Import', 'acf') . '</a></span> </div>'; } } else { echo __('Saved', 'acf'); } } else { echo '<span class="acf-secondary-text">' . __('Awaiting save', 'acf') . '</span>'; } } public function page_row_actions($actions, $post) { unset($actions['inline'], $actions['inline hide-if-no-js']); $duplicate_action_url = $this->get_admin_url('&acfduplicate=' . $post->ID . '&_wpnonce=' . wp_create_nonce('bulk-posts')); $actions['acfduplicate'] = '<a href="' . esc_url($duplicate_action_url) . '" aria-label="' . esc_attr__('Duplicate this item', 'acf') . '">' . __('Duplicate', 'acf') . '</a>'; $order = array('edit', 'acfduplicate', 'trash'); return array_merge(array_flip($order), $actions); } public function admin_table_bulk_actions($actions) { if ($this->view !== 'sync') { $actions['acfduplicate'] = __('Duplicate', 'acf'); } if ($this->sync) { if ($this->view === 'sync') { $actions = array(); } $actions['acfsync'] = __('Sync changes', 'acf'); } return $actions; } public function check_duplicate() { if (isset($_GET['acfduplicatecomplete'])) { $ids = array_map('intval', explode(',', $_GET['acfduplicatecomplete'])); $text = sprintf(_n('Field group duplicated.', '%s field groups duplicated.', count($ids), 'acf'), count($ids)); $links = array(); foreach ($ids as $id) { $links[] = '<a href="' . get_edit_post_link($id) . '">' . get_the_title($id) . '</a>'; } $text .= ' ' . implode(', ', $links); acf_add_admin_notice($text, 'success'); return; } $ids = array(); if (isset($_GET['acfduplicate'])) { $ids[] = intval($_GET['acfduplicate']); } elseif (isset($_GET['post'], $_GET['action2']) && $_GET['action2'] === 'acfduplicate') { $ids = array_map('intval', $_GET['post']); } if ($ids) { check_admin_referer('bulk-posts'); $new_ids = array(); foreach ($ids as $id) { $field_group = acf_duplicate_field_group($id); $new_ids[] = $field_group['ID']; } wp_redirect($this->get_admin_url('&acfduplicatecomplete=' . implode(',', $new_ids))); exit; } } public function check_sync() { if (isset($_GET['acfsynccomplete'])) { $ids = array_map('intval', explode(',', $_GET['acfsynccomplete'])); $text = sprintf(_n('Field group synchronised.', '%s field groups synchronised.', count($ids), 'acf'), count($ids)); $links = array(); foreach ($ids as $id) { $links[] = '<a href="' . get_edit_post_link($id) . '">' . get_the_title($id) . '</a>'; } $text .= ' ' . implode(', ', $links); acf_add_admin_notice($text, 'success'); return; } $keys = array(); if (isset($_GET['acfsync'])) { $keys[] = sanitize_text_field($_GET['acfsync']); } elseif (isset($_GET['post'], $_GET['action2']) && $_GET['action2'] === 'acfsync') { $keys = array_map('sanitize_text_field', $_GET['post']); } if ($keys && $this->sync) { check_admin_referer('bulk-posts'); acf_update_setting('json', false); $files = acf_get_local_json_files(); $new_ids = array(); foreach ($this->sync as $key => $field_group) { if ($field_group['key'] && in_array($field_group['key'], $keys)) { } elseif ($field_group['ID'] && in_array($field_group['ID'], $keys)) { } else { continue; } $local_field_group = json_decode(file_get_contents($files[$key]), true); $local_field_group['ID'] = $field_group['ID']; $result = acf_import_field_group($local_field_group); $new_ids[] = $result['ID']; } wp_redirect($this->get_current_admin_url('&acfsynccomplete=' . implode(',', $new_ids))); exit; } } public function admin_table_views($views) { global $wp_list_table, $wp_query; $count = count($this->sync); if ($count) { $views['sync'] = sprintf('<a %s href="%s">%s <span class="count">(%s)</span></a>', $this->view === 'sync' ? 'class="current"' : '', esc_url($this->get_admin_url('&post_status=sync')), esc_html(__('Sync available', 'acf')), $count); } if ($this->view === 'sync') { $wp_list_table->set_pagination_args(array('total_items' => $count, 'total_pages' => 1, 'per_page' => $count)); $wp_query->post_count = 1; } return $views; } function admin_footer() { ?> <script type="text/javascript"> (function($){ // Displays a modal comparing local changes. function reviewSync( props ) { var modal = acf.newModal({ title: acf.__('Review local JSON changes'), content: '<p class="acf-modal-feedback"><i class="acf-loading"></i> ' + acf.__('Loading diff') + '</p>', toolbar: '<a href="' + props.href + '" class="button button-primary button-sync-changes disabled">' + acf.__('Sync changes') + '</a>', }); // Call AJAX. var xhr = $.ajax({ url: acf.get('ajaxurl'), method: 'POST', dataType: 'json', data: acf.prepareForAjax({ action: 'acf/ajax/local_json_diff', id: props.id }) }) .done(function( data, textStatus, jqXHR ) { modal.content( data.html ); modal.$('.button-sync-changes').removeClass('disabled'); }) .fail(function( jqXHR, textStatus, errorThrown ) { if( error = acf.getXhrError(jqXHR) ) { modal.content( '<p class="acf-modal-feedback error">' + error + '</p>' ); } }); } // Add event listener. $(document).on('click', 'a[data-event="review-sync"]', function( e ){ e.preventDefault(); reviewSync( $(this).data() ); }); })(jQuery); </script> <?php } public function admin_footer__sync() { global $wp_list_table; $columns = $wp_list_table->get_columns(); $hidden = get_hidden_columns($wp_list_table->screen); ?> <div style="display: none;"> <table> <tbody id="acf-the-list"> <?php foreach ($this->sync as $k => $field_group) { echo '<tr>'; foreach ($columns as $column_name => $column_label) { $el = 'td'; if ($column_name === 'cb') { $el = 'th'; $classes = 'check-column'; $column_label = ''; } elseif ($column_name === 'title') { $classes = "{$column_name} column-{$column_name} column-primary"; } else { $classes = "{$column_name} column-{$column_name}"; } if (in_array($column_name, $hidden, true)) { $classes .= ' hidden'; } echo "<{$el} class=\"{$classes}\" data-colname=\"{$column_label}\">"; switch ($column_name) { case 'cb': echo '<label for="cb-select-' . esc_attr($k) . '" class="screen-reader-text">' . esc_html(sprintf(__('Select %s', 'acf'), $field_group['title'])) . '</label>'; echo '<input id="cb-select-' . esc_attr($k) . '" type="checkbox" value="' . esc_attr($k) . '" name="post[]">'; break; case 'title': $post_state = ''; if (!$field_group['active']) { $post_state = ' — <span class="post-state">' . $this->get_disabled_post_state() . '</span>'; } echo '<strong><span class="row-title">' . esc_html($field_group['title']) . '</span>' . $post_state . '</strong>'; echo '<div class="row-actions"><span class="file acf-secondary-text">' . $this->get_human_readable_file_location($field_group['local_file']) . '</span></div>'; echo '<button type="button" class="toggle-row"><span class="screen-reader-text">Show more details</span></button>'; break; default: $this->render_admin_table_column($column_name, $field_group); break; } echo "</{$el}>"; } echo '</tr>'; } ?> </tbody> </table> </div> <script type="text/javascript"> (function($){ $('#the-list').html( $('#acf-the-list').children() ); })(jQuery); </script> <?php } public function trashed_post($post_id) { if (get_post_type($post_id) === 'acf-field-group') { acf_trash_field_group($post_id); } } public function untrashed_post($post_id) { if (get_post_type($post_id) === 'acf-field-group') { acf_untrash_field_group($post_id); } } public function deleted_post($post_id) { if (get_post_type($post_id) === 'acf-field-group') { acf_delete_field_group($post_id); } } } acf_new_instance('ACF_Admin_Field_Groups'); }