edit pages

This commit is contained in:
razusrest
2024-04-18 17:45:44 +05:45
parent f4e3b7c750
commit 46f1b89d3d
3923 changed files with 1838473 additions and 156 deletions

View File

@ -0,0 +1,940 @@
<?php
/**
* ACF Internal Post Type List class
*
* Base class to add functionality to ACF internal post type list pages.
*
* @package ACF
* @subpackage Admin
* @since 6.1
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Admin_Internal_Post_Type_List' ) ) :
class ACF_Admin_Internal_Post_Type_List {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = '';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = '';
/**
* Array of post objects available for sync.
*
* @since 5.9.0
* @var array
*/
public $sync = array();
/**
* The current view (post_status).
*
* @since 5.9.0
* @var string
*/
public $view = '';
/**
* The name of the store used for the post type.
*
* @var string
*/
public $store = '';
/**
* If this is a pro feature or not.
*
* @var bool
*/
public $is_pro_feature = false;
/**
* Constructs the class.
*/
public function __construct() {
add_action( 'current_screen', array( $this, 'current_screen' ) );
// Handle post status change events.
add_action( 'trashed_post', array( $this, 'trashed_post' ) );
add_action( 'untrashed_post', array( $this, 'untrashed_post' ) );
add_action( 'deleted_post', array( $this, 'deleted_post' ) );
}
/**
* Add any menu items required for post types.
*
* @since 6.1
*/
public function admin_menu() {}
/**
* Returns the admin URL for the current post type edit page.
*
* @date 27/3/20
* @since 5.9.0
*
* @param string $params Extra URL params.
* @return string
*/
public function get_admin_url( $params = '' ) {
return admin_url( "edit.php?post_type={$this->post_type}{$params}" );
}
/**
* Returns the post type admin URL taking into account the current view.
*
* @date 27/3/20
* @since 5.9.0
*
* @param string $params Extra URL params.
* @return string
*/
public function get_current_admin_url( $params = '' ) {
return $this->get_admin_url( ( $this->view ? '&post_status=' . $this->view : '' ) . $params );
}
/**
* Constructor for all ACF internal post type admin list pages.
*
* @date 21/07/2014
* @since 5.0.0
*
* @return void
*/
public function current_screen() {
// Bail early if not the list admin page.
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
return;
}
// Get the current view.
$this->view = acf_request_arg( 'post_status', '' );
// Setup and check for custom actions.
$this->setup_sync();
$this->check_sync();
$this->check_duplicate();
$this->check_activate();
$this->check_deactivate();
// Modify publish post status text and order.
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 hooks.
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
add_filter( "views_edit-{$this->post_type}", array( $this, 'admin_table_views' ), 10, 1 );
add_filter( "manage_{$this->post_type}_posts_columns", array( $this, 'admin_table_columns' ), 10, 1 );
add_action( "manage_{$this->post_type}_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-{$this->post_type}", 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 );
}
// Add hooks for "sync" view.
if ( $this->view === 'sync' ) {
add_action( 'admin_footer', array( $this, 'admin_footer__sync' ), 1 );
}
}
/**
* Sets up the field groups ready for sync.
*
* @date 17/4/20
* @since 5.9.0
*
* @return void
*/
public function setup_sync() {
// Review local json files.
if ( acf_get_local_json_files( $this->post_type ) ) {
// Get all posts in a single cached query to check if sync is available.
$all_posts = acf_get_internal_post_type_posts( $this->post_type );
foreach ( $all_posts as $post ) {
// Extract vars.
$local = acf_maybe_get( $post, 'local' );
$modified = acf_maybe_get( $post, 'modified' );
$private = acf_maybe_get( $post, 'private' );
// Ignore if is private.
if ( $private ) {
continue;
// Ignore not local "json".
} elseif ( $local !== 'json' ) {
continue;
// Append to sync if not yet in database.
} elseif ( ! $post['ID'] ) {
$this->sync[ $post['key'] ] = $post;
// Append to sync if "json" modified time is newer than database.
} elseif ( $modified && $modified > get_post_modified_time( 'U', true, $post['ID'] ) ) {
$this->sync[ $post['key'] ] = $post;
}
}
}
}
/**
* Enqueues admin scripts.
*
* @date 18/4/20
* @since 5.9.0
*
* @return void
*/
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' ),
)
);
}
/**
* Modifies the admin body class.
*
* @date 18/4/20
* @since 5.9.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
$classes .= ' acf-admin-page acf-internal-post-type ' . esc_attr( $this->admin_body_class );
if ( $this->view ) {
$classes .= ' view-' . esc_attr( $this->view );
}
return $classes;
}
/**
* Returns the disabled post state HTML.
*
* @since 5.9.0
*
* @return string
*/
public function get_disabled_post_state() {
return '<span class="dashicons dashicons-hidden"></span> ' . _x( 'Inactive', 'post status', 'acf' );
}
/**
* Returns the registration error state.
*
* @since 6.1
*
* @return string
*/
public function get_registration_error_state() {
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
__( 'This item could not be registered because its key is in use by another item registered by another plugin or theme.', 'acf' ) .
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
}
/**
* Adds the "disabled" post state for the admin table title.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $post_states An array of post display states.
* @param WP_Post $post The current post object.
* @return array
*/
public function display_post_states( $post_states, $post ) {
if ( $post->post_status === 'acf-disabled' ) {
$post_states['acf-disabled'] = $this->get_disabled_post_state();
}
// Check the post store to see if this failed registration.
if ( ! empty( $this->store ) && ! empty( $post->ID ) ) {
$store = acf_get_store( $this->store );
if ( $store ) {
$store_item = $store->get( $post->ID );
if ( ! empty( $store_item ) && ! empty( $store_item['not_registered'] ) ) {
$post_states['acf-registration-warning'] = $this->get_registration_error_state();
}
}
}
return $post_states;
}
/**
* Get the HTML for when there are no post objects found.
*
* @since 6.0.0
*
* @return string
*/
public function get_not_found_html() {
ob_start();
$view = $this->post_type . '/list-empty';
if ( $this->is_pro_feature ) {
$view = ACF_PATH . 'pro/admin/views/' . $view . '.php';
}
acf_get_view( $view );
return ob_get_clean();
}
/**
* Customizes the admin table columns.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $_columns The columns array.
* @return array
*/
public function admin_table_columns( $_columns ) {
return $_columns;
}
/**
* Renders the admin table column HTML
*
* @date 1/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param int $post_id The current post ID.
* @return void
*/
public function admin_table_columns_html( $column_name, $post_id ) {
$post = acf_get_internal_post_type( $post_id, $this->post_type );
if ( $post ) {
$this->render_admin_table_column( $column_name, $post );
}
}
/**
* Renders a specific admin table column.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param array $post The main ACF post array.
* @return void
*/
public function render_admin_table_column( $column_name, $post ) {}
/**
* Returns a human-readable file location.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $file The full file path.
* @return string
*/
public function get_human_readable_file_location( $file ) {
// Generate friendly file path.
$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;
}
/**
* Displays the local JSON status of an ACF post.
*
* @date 14/4/20
* @since 5.9.0
*
* @param array $post The main ACF post array.
* @return void
*/
public function render_admin_table_column_local_status( $post ) {
$json = acf_get_local_json_files( $this->post_type );
if ( isset( $json[ $post['key'] ] ) ) {
if ( isset( $this->sync[ $post['key'] ] ) ) {
$url = $this->get_admin_url( '&acfsync=' . $post['key'] . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
echo '<strong>' . __( 'Sync available', 'acf' ) . '</strong>';
if ( $post['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( $post['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>';
}
}
/**
* Customizes the page row actions visible on hover.
*
* @date 14/4/20
* @since 5.9.0
*
* @param array $actions The array of actions HTML.
* @param WP_Post $post The post.
* @return array
*/
public function page_row_actions( $actions, $post ) {
// Remove "Quick Edit" action.
unset( $actions['inline'], $actions['inline hide-if-no-js'] );
$duplicate_action_url = '';
// Append "Duplicate" action.
if ( 'acf-field-group' === $this->post_type ) {
$duplicate_action_url = $this->get_admin_url( '&acfduplicate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
} elseif ( 'acf-post-type' === $this->post_type ) {
$duplicate_action_url = wp_nonce_url( admin_url( 'post-new.php?post_type=acf-post-type&use_post_type=' . $post->ID ), 'acfduplicate-' . $post->ID );
} elseif ( 'acf-taxonomy' === $this->post_type ) {
$duplicate_action_url = wp_nonce_url( admin_url( 'post-new.php?post_type=acf-taxonomy&use_taxonomy=' . $post->ID ), 'acfduplicate-' . $post->ID );
}
$actions['acfduplicate'] = '<a href="' . esc_url( $duplicate_action_url ) . '" aria-label="' . esc_attr__( 'Duplicate this item', 'acf' ) . '">' . __( 'Duplicate', 'acf' ) . '</a>';
// Append the "Activate" or "Deactivate" actions.
if ( 'acf-disabled' === $post->post_status ) {
$activate_deactivate_action = 'acfactivate';
$activate_action_url = $this->get_admin_url( '&acfactivate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
$actions['acfactivate'] = '<a href="' . esc_url( $activate_action_url ) . '" aria-label="' . esc_attr__( 'Activate this item', 'acf' ) . '">' . __( 'Activate', 'acf' ) . '</a>';
} else {
$activate_deactivate_action = 'acfdeactivate';
$deactivate_action_url = $this->get_admin_url( '&acfdeactivate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
$actions['acfdeactivate'] = '<a href="' . esc_url( $deactivate_action_url ) . '" aria-label="' . esc_attr__( 'Deactivate this item', 'acf' ) . '">' . __( 'Deactivate', 'acf' ) . '</a>';
}
// Return actions in custom order.
$order = array( 'edit', 'acfduplicate', $activate_deactivate_action, 'trash' );
return array_merge( array_flip( $order ), $actions );
}
/**
* Modifies the admin table bulk actions dropdown.
*
* @date 15/4/20
* @since 5.9.0
*
* @param array $actions The actions array.
* @return array
*/
public function admin_table_bulk_actions( $actions ) {
if ( ! in_array( $this->view, array( 'sync', 'trash' ), true ) ) {
// TODO: We'll likely have to add support for CPTs/Taxonomies!
if ( 'acf-field-group' === $this->post_type ) {
$actions['acfduplicate'] = __( 'Duplicate', 'acf' );
}
$actions['acfactivate'] = __( 'Activate', 'acf' );
$actions['acfdeactivate'] = __( 'Deactivate', 'acf' );
}
if ( $this->sync ) {
if ( $this->view === 'sync' ) {
$actions = array();
}
$actions['acfsync'] = __( 'Sync changes', 'acf' );
}
return $actions;
}
/**
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
*
* @since 6.1
*
* @param string $action The action being performed.
* @param int $count The number of items the action was performed on.
* @return string
*/
public function get_action_notice_text( $action, $count = 1 ) {
return '';
}
/**
* Checks for the custom "Activate" bulk action.
*
* @since 6.0
*/
public function check_activate() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
// Display notice on success redirect.
if ( isset( $_GET['acfactivatecomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfactivatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// Generate text.
$text = $this->get_action_notice_text( 'acfactivatecomplete', count( $ids ) );
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to activate.
$ids = array();
if ( isset( $_GET['acfactivate'] ) ) {
$ids[] = intval( $_GET['acfactivate'] );
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfactivate' ) {
$ids = array_map( 'intval', $_GET['post'] );
}
if ( $ids ) {
check_admin_referer( 'bulk-posts' );
// Activate the field groups and return an array of IDs that were activated.
$new_ids = array();
foreach ( $ids as $id ) {
$post_type = get_post_type( $id );
if ( $post_type && acf_update_internal_post_type_active_status( $id, true, $post_type ) ) {
$new_ids[] = $id;
}
}
wp_safe_redirect( $this->get_admin_url( '&acfactivatecomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Checks for the custom "Deactivate" bulk action.
*
* @since 6.0
*/
public function check_deactivate() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
// Display notice on success redirect.
if ( isset( $_GET['acfdeactivatecomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfdeactivatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// Generate text.
$text = $this->get_action_notice_text( 'acfdeactivatecomplete', count( $ids ) );
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to activate.
$ids = array();
if ( isset( $_GET['acfdeactivate'] ) ) {
$ids[] = intval( $_GET['acfdeactivate'] );
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfdeactivate' ) {
$ids = array_map( 'intval', $_GET['post'] );
}
if ( $ids ) {
check_admin_referer( 'bulk-posts' );
// Activate the field groups and return an array of IDs.
$new_ids = array();
foreach ( $ids as $id ) {
$post_type = get_post_type( $id );
if ( $post_type && acf_update_internal_post_type_active_status( $id, false, $post_type ) ) {
$new_ids[] = $id;
}
}
wp_safe_redirect( $this->get_admin_url( '&acfdeactivatecomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Checks for the custom "duplicate" action.
*
* @date 15/4/20
* @since 5.9.0
*
* @return void
*/
public function check_duplicate() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
// Display notice on success redirect.
if ( isset( $_GET['acfduplicatecomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfduplicatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// Generate text.
$text = $this->get_action_notice_text( 'acfduplicatecomplete', count( $ids ) );
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to duplicate.
$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' );
// Duplicate field groups and generate array of new IDs.
$new_ids = array();
foreach ( $ids as $id ) {
$field_group = acf_duplicate_field_group( $id );
$new_ids[] = $field_group['ID'];
}
// Redirect.
wp_safe_redirect( $this->get_admin_url( '&acfduplicatecomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Checks for the custom "acfsync" action.
*
* @date 15/4/20
* @since 5.9.0
*
* @return void
*/
public function check_sync() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
// Display notice on success redirect.
if ( isset( $_GET['acfsynccomplete'] ) ) {
$ids = array_map( 'intval', explode( ',', $_GET['acfsynccomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
// phpcs:enable WordPress.Security.NonceVerification.Recommended
// Generate text.
$text = $this->get_action_notice_text( 'acfsynccomplete', count( $ids ) );
// Append links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
acf_add_admin_notice( $text, 'success' );
return;
}
// Find items to sync.
$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' );
// Disabled "Local JSON" controller to prevent the .json file from being modified during import.
acf_update_setting( 'json', false );
// Sync field groups and generate array of new IDs.
$files = acf_get_local_json_files( $this->post_type );
$new_ids = array();
foreach ( $this->sync as $key => $post ) {
if ( $post['key'] && in_array( $post['key'], $keys ) ) {
// Import.
} elseif ( $post['ID'] && in_array( $post['ID'], $keys ) ) {
// Import.
} else {
// Ignore.
continue;
}
$local_post = json_decode( file_get_contents( $files[ $key ] ), true );
$local_post['ID'] = $post['ID'];
$result = acf_import_internal_post_type( $local_post, $this->post_type );
$new_ids[] = $result['ID'];
}
// Redirect.
wp_safe_redirect( $this->get_current_admin_url( '&acfsynccomplete=' . implode( ',', $new_ids ) ) );
exit;
}
}
/**
* Customizes the admin table subnav.
*
* @date 17/4/20
* @since 5.9.0
*
* @param array $views The available views.
* @return array
*/
public function admin_table_views( $views ) {
global $wp_list_table, $wp_query;
// Count items.
$count = count( $this->sync );
// Append "sync" link to subnav.
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
);
}
// Modify table pagination args to match JSON data.
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; // At least one post is needed to render bulk drop-down.
}
return $views;
}
/**
* Prints scripts into the admin footer.
*
* @date 20/4/20
* @since 5.9.0
*
* @return void
*/
public 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
}
/**
* Customizes the admin table HTML when viewing "sync" post_status.
*
* @date 17/4/20
* @since 5.9.0
*
* @return void
*/
public function admin_footer__sync() {
global $wp_list_table;
// Get table columns.
$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 ) {
// Checkbox.
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;
// Title.
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;
// All other columns.
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
}
/**
* Fires when trashing an internal post type.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function trashed_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_trash_internal_post_type( $post_id, $this->post_type );
}
}
/**
* Fires when untrashing an internal post type.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function untrashed_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_untrash_internal_post_type( $post_id, $this->post_type );
}
}
/**
* Fires when deleting an internal post type.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function deleted_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_delete_internal_post_type( $post_id, $this->post_type );
}
}
}
endif; // Class exists check.

View File

@ -0,0 +1,361 @@
<?php
/**
* ACF Internal Post Type class
*
* Base class to add functionality to ACF internal post types.
*
* @package ACF
* @subpackage Admin
* @since 6.1
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Admin_Internal_Post_Type' ) ) :
/**
* ACF Internal Post Type class.
*
* Adds logic to the edit page for ACF internal post types.
*/
class ACF_Admin_Internal_Post_Type {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = '';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = '';
/**
* Constructs the class.
*/
public function __construct() {
add_action( 'current_screen', array( $this, 'current_screen' ) );
add_action( 'save_post_' . $this->post_type, array( $this, 'save_post' ), 10, 2 );
add_action( 'wp_ajax_acf/link_field_groups', array( $this, 'ajax_link_field_groups' ) );
add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
add_filter( 'use_block_editor_for_post_type', array( $this, 'use_block_editor_for_post_type' ), 10, 2 );
}
/**
* Prevents the block editor from loading when editing an ACF field group.
*
* @since 5.8.0
*
* @param bool $use_block_editor Whether the post type can be edited or not. Default true.
* @param string $post_type The post type being checked.
* @return bool
*/
public function use_block_editor_for_post_type( $use_block_editor, $post_type ) {
if ( $post_type === $this->post_type ) {
return false;
}
return $use_block_editor;
}
/**
* This function will customize the message shown when editing a field group
*
* @since 5.0.0
*
* @param array $messages Post type messages.
* @return array
*/
public function post_updated_messages( $messages ) {
return $messages;
}
/**
* This function is fired when loading the admin page before HTML has been rendered.
*
* @since 5.0.0
*
* @return void
*/
public function current_screen() {
if ( ! acf_is_screen( $this->post_type ) ) {
return;
}
acf_disable_filters();
acf_enqueue_scripts();
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'acf/input/admin_head', array( $this, 'admin_head' ) );
add_action( 'acf/input/form_data', array( $this, 'form_data' ) );
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ) );
add_filter( 'acf/input/admin_l10n', array( $this, 'admin_l10n' ) );
}
/**
* Modifies the admin body class.
*
* @since 6.0.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
return $classes . ' acf-admin-page acf-internal-post-type ' . esc_attr( $this->admin_body_class );
}
/**
* Enqueues any scripts necessary for internal post type.
*
* @since 5.0.0
*
* @return void
*/
public function admin_enqueue_scripts() {
wp_enqueue_script( 'acf-internal-post-type' );
wp_dequeue_script( 'autosave' );
wp_enqueue_style( $this->post_type );
wp_enqueue_script( $this->post_type );
}
/**
* Set up functionality for the field group edit page.
*
* @since 3.1.8
*
* @return void
*/
public function admin_head() {
// Override as necessary.
}
/**
* Adds extra HTML to the acf form data element.
*
* @since 5.3.8
*
* @param array $args Arguments array to pass through to action.
* @return void
*/
public function form_data( $args ) {
// Override as necessary.
}
/**
* Admin footer third party hook support
*
* @since 5.3.2
*
* @return void
*/
public function admin_footer() {
// Override as necessary.
}
/**
* This function will append extra l10n strings to the acf JS object
*
* @since 5.3.8
*
* @param array $l10n The array of translated strings.
* @return array $l10n
*/
public function admin_l10n( $l10n ) {
// Override as necessary.
}
/**
* Ran during the `save_post` hook to verify that the post should be saved.
*
* @since 6.1
*
* @param int $post_id The ID of the post being saved.
* @param WP_Post $post The post object.
*
* @return bool
*/
public function verify_save_post( $post_id, $post ) {
// Do not save if this is an auto save routine.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return false;
}
// Bail early if not an ACF internal post type.
if ( $post->post_type !== $this->post_type ) {
return false;
}
// Only save once! WordPress saves a revision as well.
if ( wp_is_post_revision( $post_id ) ) {
return false;
}
// Verify nonce.
$nonce_name = str_replace(
array( 'acf-', '-' ),
array( '', '_' ),
$this->post_type
);
if ( ! acf_verify_nonce( $nonce_name ) ) {
return false;
}
// Bail early if request came from an unauthorised user.
if ( ! current_user_can( acf_get_setting( 'capability' ) ) ) {
return false;
}
return true;
}
/**
* Powers the modal for linking field groups to newly-created CPTs/taxonomies.
*
* @since 6.1
*
* @return void
*/
public function ajax_link_field_groups() {
// Disable filters to ensure ACF loads raw data from DB.
acf_disable_filters();
// phpcs:disable WordPress.Security.NonceVerification.Missing
$args = acf_parse_args(
$_POST,
array(
'nonce' => '',
'post_id' => 0,
'field_groups' => array(),
)
);
// phpcs:enable WordPress.Security.NonceVerification.Missing
// Verify nonce and user capability.
if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) || ! acf_current_user_can_admin() || ! $args['post_id'] ) {
die();
}
$post_type = get_post_type( $args['post_id'] );
$saved_post = acf_get_internal_post_type( $args['post_id'], $post_type );
// Link the selected field groups.
if ( is_array( $args['field_groups'] ) && ! empty( $args['field_groups'] ) && $saved_post ) {
foreach ( $args['field_groups'] as $field_group_id ) {
$field_group = acf_get_field_group( $field_group_id );
if ( ! is_array( $field_group ) ) {
continue;
}
if ( 'acf-post-type' === $post_type ) {
$param = 'post_type';
$value = $saved_post['post_type'];
} elseif ( 'acf-taxonomy' === $post_type ) {
$param = 'taxonomy';
$value = $saved_post['taxonomy'];
} else {
$param = 'options_page';
$value = $saved_post['menu_slug'];
}
$field_group['location'][] = array(
array(
'param' => $param,
'operator' => '==',
'value' => $value,
),
);
acf_update_field_group( $field_group );
}
ob_start();
?>
<p class="acf-link-successful">
<?php
$link_successful_text = _n(
'Field group linked successfully.',
'Field groups linked successfully.',
count( $args['field_groups'] ),
'acf'
);
echo esc_html( $link_successful_text );
?>
</p>
<div class="acf-actions">
<button type="button" class="acf-btn acf-btn-secondary acf-close-popup"><?php esc_html_e( 'Close Modal', 'acf' ); ?></button>
</div>
<?php
$content = ob_get_clean();
wp_send_json_success( array( 'content' => $content ) );
}
// Render the field group select.
$field_groups = acf_get_field_groups();
$choices = array();
if ( ! empty( $field_groups ) ) {
foreach ( $field_groups as $field_group ) {
if ( ! $field_group['ID'] ) {
continue;
}
$choices[ $field_group['ID'] ] = $field_group['title'];
}
}
$instructions = sprintf(
/* translators: %s - either "post type" or "taxonomy" */
__( 'Add this %s to the location rules of the selected field groups.', 'acf' ),
'acf-post-type' === $post_type ? __( 'post type', 'acf' ) : __( 'taxonomy', 'acf' )
);
$field = acf_get_valid_field(
array(
'type' => 'select',
'name' => 'acf_field_groups',
'choices' => $choices,
'aria-label' => __( 'Please select the field groups to link.', 'acf' ),
'placeholder' => __( 'Select one or many field groups...', 'acf' ),
'label' => __( 'Field Group(s)', 'acf' ),
'instructions' => $instructions,
'ui' => true,
'multiple' => true,
'allow_null' => true,
)
);
ob_start();
?>
<form id="acf-link-field-groups-form">
<?php acf_render_field_wrap( $field, 'div', 'field' ); ?>
<div class="acf-actions">
<button type="button" class="acf-btn acf-btn-secondary acf-close-popup"><?php esc_html_e( 'Cancel', 'acf' ); ?></button>
<button type="submit" class="acf-btn acf-btn-primary"><?php esc_html_e( 'Done', 'acf' ); ?></button>
</div>
</form>
<?php
$content = ob_get_clean();
wp_send_json_success(
array(
'content' => $content,
'title' => esc_html__( 'Link Existing Field Groups', 'acf' ),
)
);
}
}
endif; // Class exists check.

View File

@ -0,0 +1,150 @@
<?php
/**
* ACF Admin Notices
*
* Functions and classes to manage admin notices.
*
* @date 10/1/19
* @since 5.7.10
*/
// Exit if accessed directly.
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
// Register notices store.
acf_register_store( 'notices' );
/**
* ACF_Admin_Notice
*
* Class used to create an admin notice.
*
* @date 10/1/19
* @since 5.7.10
*/
if ( ! class_exists( 'ACF_Admin_Notice' ) ) :
class ACF_Admin_Notice extends ACF_Data {
/** @var array Storage for data. */
var $data = array(
/** @type string Text displayed in notice. */
'text' => '',
/** @type string The type of notice (warning, error, success, info). */
'type' => 'info',
/** @type bool If the notice can be dismissed. */
'dismissible' => true,
/** @type bool If the dismissed state should be persisted to ACF user preferences. */
'persisted' => false,
);
/**
* render
*
* Renders the notice HTML.
*
* @date 27/12/18
* @since 5.8.0
*
* @param void
* @return void
*/
function render() {
$notice_text = $this->get( 'text' );
$notice_type = $this->get( 'type' );
$is_dismissible = $this->get( 'dismissible' );
$is_persisted = $this->get( 'persisted' );
printf(
'<div class="acf-admin-notice notice notice-%s %s" data-persisted="%s" data-persist-id="%s">%s</div>',
esc_attr( $notice_type ),
$is_dismissible ? 'is-dismissible' : '',
$is_persisted ? 'true' : 'false',
esc_attr( md5( $notice_text ) ),
acf_esc_html( wpautop( acf_punctify( $notice_text ) ) )
);
}
}
endif; // class_exists check
/**
* acf_new_admin_notice
*
* Instantiates and returns a new model.
*
* @date 23/12/18
* @since 5.8.0
*
* @param array $data Optional data to set.
* @return ACF_Admin_Notice
*/
function acf_new_admin_notice( $data = false ) {
// Create notice.
$instance = new ACF_Admin_Notice( $data );
// Register notice.
acf_get_store( 'notices' )->set( $instance->cid, $instance );
// Return notice.
return $instance;
}
/**
* acf_render_admin_notices
*
* Renders all admin notices HTML.
*
* @date 10/1/19
* @since 5.7.10
*
* @param void
* @return void
*/
function acf_render_admin_notices() {
// Get notices.
$notices = acf_get_store( 'notices' )->get_data();
// Loop over notices and render.
if ( $notices ) {
foreach ( $notices as $notice ) {
$notice->render();
}
}
}
// Render notices during admin action.
add_action( 'admin_notices', 'acf_render_admin_notices', 99 );
/**
* acf_add_admin_notice
*
* Creates and returns a new notice.
*
* @date 17/10/13
* @since 5.0.0
*
* @param string $text The admin notice text.
* @param string $class The type of notice (warning, error, success, info).
* @param boolean $dismissable Is this notification dismissible (default true) (since 5.11.0)
* @param boolean $persisted Store once a notice has been dismissed per user and prevent showing it again. (since 6.1.0)
* @return ACF_Admin_Notice
*/
function acf_add_admin_notice( $text = '', $type = 'info', $dismissible = true, $persisted = false ) {
return acf_new_admin_notice(
array(
'text' => $text,
'type' => $type,
'dismissible' => $dismissible,
'persisted' => $persisted,
)
);
}

View File

@ -0,0 +1,68 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
if ( ! class_exists( 'ACF_Admin_Options_Preview' ) ) :
class ACF_Admin_Options_Preview {
/**
* Constructor.
*
* @since 6.2.2
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ), 10 );
}
/**
* Adds the Options Pages menu item to the admin menu.
*
* @since 6.2.2
*/
public function admin_menu() {
if ( ! acf_get_setting( 'show_admin' ) ) {
return;
}
$page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Options Pages', 'acf' ), __( 'Options Pages', 'acf' ), acf_get_setting( 'capability' ), 'acf_options_preview', array( $this, 'render' ) );
add_action( 'load-' . $page, array( $this, 'load' ) );
}
/**
* Load the body class and scripts.
*
* @since 6.2.2
*/
public function load() {
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
acf_enqueue_scripts();
}
/**
* Modifies the admin body class.
*
* @since 6.2.2
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
$classes .= ' acf-admin-page acf-internal-post-type acf-options-preview acf-no-options-pages';
return $classes;
}
/**
* The render for the options page preview view.
*
* @since 6.2.2
*/
public function render() {
$screen = get_current_screen();
$view = array( 'screen_id' => $screen->id );
acf_get_view( 'options-page-preview', $view );
}
}
new ACF_Admin_Options_Preview();
endif;

View File

@ -0,0 +1,340 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'acf_admin_tools' ) ) :
#[AllowDynamicProperties]
class acf_admin_tools {
/** @var array Contains an array of admin tool instances */
var $tools = array();
/** @var string The active tool */
var $active = '';
/**
* __construct
*
* This function will setup the class functionality
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function __construct() {
// actions
add_action( 'admin_menu', array( $this, 'admin_menu' ), 15 );
}
/**
* register_tool
*
* This function will store a tool tool class
*
* @date 10/10/17
* @since 5.6.3
*
* @param string $class
* @return n/a
*/
function register_tool( $class ) {
$instance = new $class();
$this->tools[ $instance->name ] = $instance;
}
/**
* get_tool
*
* This function will return a tool tool class
*
* @date 10/10/17
* @since 5.6.3
*
* @param string $name
* @return n/a
*/
function get_tool( $name ) {
return isset( $this->tools[ $name ] ) ? $this->tools[ $name ] : null;
}
/**
* get_tools
*
* This function will return an array of all tools
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return array
*/
function get_tools() {
return $this->tools;
}
/*
* admin_menu
*
* This function will add the ACF menu item to the WP admin
*
* @type action (admin_menu)
* @date 28/09/13
* @since 5.0.0
*
* @param n/a
* @return n/a
*/
function admin_menu() {
// bail early if no show_admin
if ( ! acf_get_setting( 'show_admin' ) ) {
return;
}
// add page
$page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Tools', 'acf' ), __( 'Tools', 'acf' ), acf_get_setting( 'capability' ), 'acf-tools', array( $this, 'html' ) );
// actions
add_action( 'load-' . $page, array( $this, 'load' ) );
}
/**
* load
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
// disable filters (default to raw data)
acf_disable_filters();
// include tools
$this->include_tools();
// check submit
$this->check_submit();
// load acf scripts
acf_enqueue_scripts();
}
/**
* Modifies the admin body class.
*
* @since 6.0.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
$classes .= ' acf-admin-page';
return $classes;
}
/**
* include_tools
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function include_tools() {
// include
acf_include( 'includes/admin/tools/class-acf-admin-tool.php' );
acf_include( 'includes/admin/tools/class-acf-admin-tool-export.php' );
acf_include( 'includes/admin/tools/class-acf-admin-tool-import.php' );
// action
do_action( 'acf/include_admin_tools' );
}
/**
* check_submit
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function check_submit() {
// loop
foreach ( $this->get_tools() as $tool ) {
// load
$tool->load();
// submit
if ( acf_verify_nonce( $tool->name ) ) {
$tool->submit();
}
}
}
/**
* html
*
* description
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
// vars
$screen = get_current_screen();
$active = acf_maybe_get_GET( 'tool' );
// view
$view = array(
'screen_id' => $screen->id,
'active' => $active,
);
// register metaboxes
foreach ( $this->get_tools() as $tool ) {
// check active
if ( $active && $active !== $tool->name ) {
continue;
}
// add metabox
add_meta_box( 'acf-admin-tool-' . $tool->name, acf_esc_html( $tool->title ), array( $this, 'metabox_html' ), $screen->id, 'normal', 'default', array( 'tool' => $tool->name ) );
}
// view
acf_get_view( 'tools/tools', $view );
}
/**
* Output the metabox HTML for specific tools
*
* @since 5.6.3
*
* @param mixed $post The post this metabox is being displayed on, should be an empty string always for us on a tools page.
* @param array $metabox An array of the metabox attributes.
*
* @return void
*/
public function metabox_html( $post, $metabox ) {
$tool = $this->get_tool( $metabox['args']['tool'] );
$form_attrs = array( 'method' => 'post' );
if ( $metabox['args']['tool'] === 'import' ) {
$form_attrs['onsubmit'] = 'acf.disableForm(event)';
}
printf( '<form %s>', acf_esc_attrs( $form_attrs ) );
$tool->html();
acf_nonce_input( $tool->name );
echo '</form>';
}
}
// initialize
acf()->admin_tools = new acf_admin_tools();
endif; // class_exists check
/*
* acf_register_admin_tool
*
* alias of acf()->admin_tools->register_tool()
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_register_admin_tool( $class ) {
return acf()->admin_tools->register_tool( $class );
}
/*
* acf_get_admin_tools_url
*
* This function will return the admin URL to the tools page
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_admin_tools_url() {
return admin_url( 'edit.php?post_type=acf-field-group&page=acf-tools' );
}
/*
* acf_get_admin_tool_url
*
* This function will return the admin URL to the tools page
*
* @type function
* @date 31/5/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function acf_get_admin_tool_url( $tool = '' ) {
return acf_get_admin_tools_url() . '&tool=' . $tool;
}

View File

@ -0,0 +1,296 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Upgrade' ) ) :
class ACF_Admin_Upgrade {
/**
* The name of the transient to store the network update check status.
*
* @var string
*/
public $network_upgrade_needed_transient;
/**
* __construct
*
* Sets up the class functionality.
*
* @date 31/7/18
* @since 5.7.2
*
* @param void
* @return void
*/
function __construct() {
$this->network_upgrade_needed_transient = 'acf_network_upgrade_needed_' . ACF_UPGRADE_VERSION;
add_action( 'admin_menu', array( $this, 'admin_menu' ), 20 );
if ( is_multisite() ) {
add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ), 20 );
}
}
/**
* admin_menu
*
* Setus up logic if DB Upgrade is needed on a single site.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function admin_menu() {
// check if upgrade is avaialble
if ( acf_has_upgrade() ) {
// add notice
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
// add page
$page = add_submenu_page( 'index.php', __( 'Upgrade Database', 'acf' ), __( 'Upgrade Database', 'acf' ), acf_get_setting( 'capability' ), 'acf-upgrade', array( $this, 'admin_html' ) );
// actions
add_action( 'load-' . $page, array( $this, 'admin_load' ) );
}
}
/**
* Displays a “Database Upgrade Required” network admin notice and adds
* the “Upgrade Database” submenu under the “Dashboard” network admin
* menu item if an ACF upgrade needs to run on any network site.
*
* @date 24/8/18
* @since 5.7.4
* @since 6.0.0 Reduce memory usage, cache network upgrade checks.
*
* @return void
*/
function network_admin_menu() {
$network_upgrade_needed = get_site_transient( $this->network_upgrade_needed_transient );
// No transient value exists, so run the upgrade check.
if ( $network_upgrade_needed === false ) {
$network_upgrade_needed = $this->check_for_network_upgrades();
}
if ( $network_upgrade_needed === 'no' ) {
return;
}
add_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
$page = add_submenu_page(
'index.php',
__( 'Upgrade Database', 'acf' ),
__( 'Upgrade Database', 'acf' ),
acf_get_setting( 'capability' ),
'acf-upgrade-network',
array( $this, 'network_admin_html' )
);
add_action( "load-$page", array( $this, 'network_admin_load' ) );
}
/**
* Checks if an ACF database upgrade is required on any site in the
* multisite network.
*
* Stores the result in `$this->network_upgrade_needed_transient`,
* which is version-linked to ACF_UPGRADE_VERSION: the highest ACF
* version that requires an upgrade function to run. Bumping
* ACF_UPGRADE_VERSION will trigger new upgrade checks but incrementing
* ACF_VERSION alone will not.
*
* @since 6.0.0
* @return string 'yes' if any site in the network requires an upgrade,
* otherwise 'no'. String instead of boolean so that
* `false` returned from a get_site_transient check can
* denote that an upgrade check is needed.
*/
public function check_for_network_upgrades() {
$network_upgrade_needed = 'no';
$sites = get_sites(
array(
'number' => 0,
'fields' => 'ids', // Reduces PHP memory usage.
)
);
if ( $sites ) {
// Reduces memory usage (same pattern used in wp-includes/ms-site.php).
remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
foreach ( $sites as $site_id ) {
switch_to_blog( $site_id );
$site_needs_upgrade = acf_has_upgrade();
restore_current_blog(); // Restores global vars.
if ( $site_needs_upgrade ) {
$network_upgrade_needed = 'yes';
break;
}
}
add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
}
set_site_transient(
$this->network_upgrade_needed_transient,
$network_upgrade_needed,
3 * MONTH_IN_SECONDS
);
return $network_upgrade_needed;
}
/**
* admin_load
*
* Runs during the loading of the admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param type $var Description. Default.
* @return type Description.
*/
function admin_load() {
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
// remove prompt
remove_action( 'admin_notices', array( $this, 'admin_notices' ) );
// Enqueue core script.
acf_enqueue_script( 'acf' );
}
/**
* network_admin_load
*
* Runs during the loading of the network admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param type $var Description. Default.
* @return type Description.
*/
function network_admin_load() {
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
// remove prompt
remove_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
// Enqueue core script.
acf_enqueue_script( 'acf' );
}
/**
* Modifies the admin body class.
*
* @since 6.0.0
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
$classes .= ' acf-admin-page';
return $classes;
}
/**
* admin_notices
*
* Displays the DB Upgrade prompt.
*
* @date 23/8/18
* @since 5.7.3
*
* @param void
* @return void
*/
function admin_notices() {
// vars
$view = array(
'button_text' => __( 'Upgrade Database', 'acf' ),
'button_url' => admin_url( 'index.php?page=acf-upgrade' ),
'confirm' => true,
);
// view
acf_get_view( 'upgrade/notice', $view );
}
/**
* network_admin_notices
*
* Displays the DB Upgrade prompt on a multi site.
*
* @date 23/8/18
* @since 5.7.3
*
* @param void
* @return void
*/
function network_admin_notices() {
// vars
$view = array(
'button_text' => __( 'Review sites & upgrade', 'acf' ),
'button_url' => network_admin_url( 'index.php?page=acf-upgrade-network' ),
'confirm' => false,
);
// view
acf_get_view( 'upgrade/notice', $view );
}
/**
* admin_html
*
* Displays the HTML for the admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function admin_html() {
acf_get_view( 'upgrade/upgrade' );
}
/**
* network_admin_html
*
* Displays the HTML for the network upgrade admin page.
*
* @date 24/8/18
* @since 5.7.4
*
* @param void
* @return void
*/
function network_admin_html() {
acf_get_view( 'upgrade/network' );
}
}
// instantiate
acf_new_instance( 'ACF_Admin_Upgrade' );
endif; // class_exists check

View File

@ -0,0 +1,375 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin' ) ) :
class ACF_Admin {
/**
* Constructor.
*
* @since 5.0.0
*
* @return void
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
add_action( 'current_screen', array( $this, 'current_screen' ) );
add_action( 'admin_notices', array( $this, 'maybe_show_escaped_html_notice' ) );
add_action( 'wp_ajax_acf/dismiss_escaped_html_notice', array( $this, 'dismiss_escaped_html_notice' ) );
add_filter( 'parent_file', array( $this, 'ensure_menu_selection' ) );
add_filter( 'submenu_file', array( $this, 'ensure_submenu_selection' ) );
}
/**
* Adds the ACF menu item.
*
* @date 28/09/13
* @since 5.0.0
*/
public function admin_menu() {
// Bail early if ACF is hidden.
if ( ! acf_get_setting( 'show_admin' ) ) {
return;
}
// Vars.
$cap = acf_get_setting( 'capability' );
$parent_slug = 'edit.php?post_type=acf-field-group';
// Add menu items.
add_menu_page( __( 'ACF', 'acf' ), __( 'ACF', 'acf' ), $cap, $parent_slug, false, 'dashicons-welcome-widgets-menus', 80 );
}
/**
* Enqueues global admin styling.
*
* @since 5.0.0
*
* @return void
*/
public function admin_enqueue_scripts() {
wp_enqueue_style( 'acf-global' );
wp_enqueue_script( 'acf-escaped-html-notice' );
wp_localize_script(
'acf-escaped-html-notice',
'acf_escaped_html_notice',
array(
'nonce' => wp_create_nonce( 'acf/dismiss_escaped_html_notice' ),
'show_details' => __( 'Show details', 'acf' ),
'hide_details' => __( 'Hide details', 'acf' ),
)
);
}
/**
* Appends custom admin body classes.
*
* @date 5/11/19
* @since 5.8.7
*
* @param string $classes Space-separated list of CSS classes.
* @return string
*/
public function admin_body_class( $classes ) {
global $wp_version;
// Determine body class version.
$wp_minor_version = floatval( $wp_version );
if ( $wp_minor_version >= 5.3 ) {
$classes .= ' acf-admin-5-3';
} else {
$classes .= ' acf-admin-3-8';
}
// Add browser for specific CSS.
$classes .= ' acf-browser-' . esc_attr( acf_get_browser() );
// Return classes.
return $classes;
}
/**
* Adds custom functionality to "ACF" admin pages.
*
* @date 7/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function current_screen( $screen ) {
// Determine if the current page being viewed is "ACF" related.
if ( isset( $screen->post_type ) && in_array( $screen->post_type, acf_get_internal_post_types(), true ) ) {
add_action( 'in_admin_header', array( $this, 'in_admin_header' ) );
add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
add_filter( 'update_footer', array( $this, 'admin_footer_version_text' ) );
$this->setup_help_tab();
$this->maybe_show_import_from_cptui_notice();
}
}
/**
* Sets up the admin help tab.
*
* @date 20/4/20
* @since 5.9.0
*
* @param void
* @return void
*/
public function setup_help_tab() {
$screen = get_current_screen();
// Overview tab.
$screen->add_help_tab(
array(
'id' => 'overview',
'title' => __( 'Overview', 'acf' ),
'content' =>
'<p><strong>' . __( 'Overview', 'acf' ) . '</strong></p>' .
'<p>' . __( 'The Advanced Custom Fields plugin provides a visual form builder to customize WordPress edit screens with extra fields, and an intuitive API to display custom field values in any theme template file.', 'acf' ) . '</p>' .
'<p>' . sprintf(
__( 'Before creating your first Field Group, we recommend first reading our <a href="%s" target="_blank">Getting started</a> guide to familiarize yourself with the plugin\'s philosophy and best practises.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'help-tab' )
) . '</p>' .
'<p>' . __( 'Please use the Help & Support tab to get in touch should you find yourself requiring assistance.', 'acf' ) . '</p>' .
'',
)
);
// Help tab.
$screen->add_help_tab(
array(
'id' => 'help',
'title' => __( 'Help & Support', 'acf' ),
'content' =>
'<p><strong>' . __( 'Help & Support', 'acf' ) . '</strong></p>' .
'<p>' . __( 'We are fanatical about support, and want you to get the best out of your website with ACF. If you run into any difficulties, there are several places you can find help:', 'acf' ) . '</p>' .
'<ul>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Documentation</a>. Our extensive documentation contains references and guides for most situations you may encounter.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/', 'docs', 'help-tab' )
) . '</li>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Discussions</a>. We have an active and friendly community on our Community Forums who may be able to help you figure out the \'how-tos\' of the ACF world.', 'acf' ),
acf_add_url_utm_tags( 'https://support.advancedcustomfields.com/', 'docs', 'help-tab' )
) . '</li>' .
'<li>' . sprintf(
__( '<a href="%s" target="_blank">Help Desk</a>. The support professionals on our Help Desk will assist with your more in depth, technical challenges.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/support/', 'docs', 'help-tab' )
) . '</li>' .
'</ul>',
)
);
// Sidebar.
$screen->set_help_sidebar(
'<p><strong>' . __( 'Information', 'acf' ) . '</strong></p>' .
'<p><span class="dashicons dashicons-admin-plugins"></span> ' . sprintf( __( 'Version %s', 'acf' ), ACF_VERSION ) . '</p>' .
'<p><span class="dashicons dashicons-wordpress"></span> <a href="https://wordpress.org/plugins/advanced-custom-fields/" target="_blank">' . __( 'View details', 'acf' ) . '</a></p>' .
'<p><span class="dashicons dashicons-admin-home"></span> <a href="' . acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/', 'docs', 'help-tab' ) . '" target="_blank" target="_blank">' . __( 'Visit website', 'acf' ) . '</a></p>' .
''
);
}
/**
* Shows a notice to import post types and taxonomies from CPTUI if that plugin is active.
*
* @since 6.1
*/
public function maybe_show_import_from_cptui_notice() {
global $plugin_page;
// Only show if CPTUI is active and post types are enabled.
if ( ! acf_get_setting( 'enable_post_types' ) || ! is_plugin_active( 'custom-post-type-ui/custom-post-type-ui.php' ) ) {
return;
}
// No need to show on the tools page.
if ( 'acf-tools' === $plugin_page ) {
return;
}
$text = sprintf(
/* translators: %s - URL to ACF tools page. */
__( 'Import Post Types and Taxonomies registered with Custom Post Type UI and manage them with ACF. <a href="%s">Get Started</a>.', 'acf' ),
acf_get_admin_tools_url()
);
acf_add_admin_notice( $text, 'success', true, true );
}
/**
* Notifies the user that fields rendered via shortcode or the_field() have
* had HTML removed/altered due to unsafe HTML being escaped.
*
* @since 6.2.5
*
* @return void
*/
public function maybe_show_escaped_html_notice() {
// Only show to editors and above.
if ( ! current_user_can( 'edit_others_posts' ) ) {
return;
}
// Allow opting-out of the notice.
if ( apply_filters( 'acf/admin/prevent_escaped_html_notice', false ) ) {
return;
}
$escaped = _acf_get_escaped_html_log();
// Notice for when HTML has already been escaped.
if ( ! empty( $escaped ) ) {
acf_get_view( 'escaped-html-notice', array( 'acf_escaped' => $escaped ) );
}
// Throw a separate notice for HTML that will be escaped in future releases.
if ( ! apply_filters( 'acf/the_field/escape_html_optin', false ) ) {
$will_escape = _acf_get_will_escape_html_log();
if ( ! empty( $will_escape ) ) {
acf_get_view( 'escaped-html-notice', array( 'acf_will_escape' => $will_escape ) );
}
}
}
/**
* Dismisses the escaped unsafe HTML notice by clearing the stored log.
*
* @since 6.2.5
*/
public function dismiss_escaped_html_notice() {
if (
! check_admin_referer( 'acf/dismiss_escaped_html_notice', 'nonce' ) ||
! current_user_can( acf_get_setting( 'capability' ) ) ) {
return;
}
$to_dismiss = acf_request_arg( 'notice', 'escaped_html' );
if ( 'escaped_html' === $to_dismiss ) {
_acf_delete_escaped_html_log();
} else {
_acf_delete_will_escape_html_log();
}
}
/**
* Renders the admin navigation element.
*
* @date 27/3/20
* @since 5.9.0
*
* @param void
* @return void
*/
function in_admin_header() {
acf_get_view( 'global/navigation' );
$screen = get_current_screen();
if ( isset( $screen->base ) && 'post' === $screen->base ) {
acf_get_view( 'global/form-top' );
}
do_action( 'acf/in_admin_header' );
}
/**
* Modifies the admin footer text.
*
* @date 7/4/20
* @since 5.9.0
*
* @param string $text The current admin footer text.
* @return string
*/
public function admin_footer_text( $text ) {
$wp_engine_link = acf_add_url_utm_tags( 'https://wpengine.com/', 'bx_prod_referral', acf_is_pro() ? 'acf_pro_plugin_footer_text' : 'acf_free_plugin_footer_text', false, 'acf_plugin', 'referral' );
$acf_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/', 'footer', 'footer' );
return sprintf(
/* translators: This text is prepended by a link to ACF's website, and appended by a link to WP Engine's website. */
'<a href="%1$s" target="_blank">' . ( acf_is_pro() ? 'ACF PRO' : 'ACF' ) . '</a> ' . __( 'is developed and maintained by', 'acf' ) . ' <a href="%2$s" target="_blank">WP Engine</a>.',
$acf_link,
$wp_engine_link
);
}
/**
* Modifies the admin footer version text.
*
* @since 6.2
*
* @param string $text The current admin footer version text.
* @return string
*/
public function admin_footer_version_text( $text ) {
$documentation_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/', 'footer', 'footer' );
$support_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/support/', 'footer', 'footer' );
$feedback_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/feedback/', 'footer', 'footer' );
$version_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/changelog/', 'footer', 'footer' );
return sprintf(
'<a href="%s" target="_blank">%s</a> &#8729; <a href="%s" target="_blank">%s</a> &#8729; <a href="%s" target="_blank">%s</a> &#8729; <a href="%s" target="_blank">%s %s</a>',
$documentation_link,
__( 'Documentation', 'acf' ),
$support_link,
__( 'Support', 'acf' ),
$feedback_link,
__( 'Feedback', 'acf' ),
$version_link,
acf_is_pro() ? __( 'ACF PRO', 'acf' ) : __( 'ACF', 'acf' ),
ACF_VERSION
);
}
/**
* Ensure the ACF parent menu is selected for add-new.php
*
* @since 6.1
* @param string $parent_file The parent file checked against menu activation.
* @return string The modified parent file
*/
public function ensure_menu_selection( $parent_file ) {
if ( ! is_string( $parent_file ) ) {
return $parent_file;
}
if ( strpos( $parent_file, 'edit.php?post_type=acf-' ) === 0 ) {
return 'edit.php?post_type=acf-field-group';
}
return $parent_file;
}
/**
* Ensure the correct ACF submenu item is selected when in post-new versions of edit pages
*
* @since 6.1
* @param string $submenu_file The submenu filename.
* @return string The modified submenu filename
*/
public function ensure_submenu_selection( $submenu_file ) {
if ( ! is_string( $submenu_file ) ) {
return $submenu_file;
}
if ( strpos( $submenu_file, 'post-new.php?post_type=acf-' ) === 0 ) {
return str_replace( 'post-new', 'edit', $submenu_file );
}
return $submenu_file;
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin' );
endif; // class_exists check

View File

@ -0,0 +1,620 @@
<?php
/**
* ACF Admin Field Group Class
*
* @class acf_admin_field_group
*
* @package ACF
* @subpackage Admin
*/
if ( ! class_exists( 'acf_admin_field_group' ) ) :
/**
* ACF Admin Field Group Class
*
* All the logic for editing a field group
*/
class acf_admin_field_group extends ACF_Admin_Internal_Post_Type {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-field-group';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-single-field-group';
/**
* Constructs the class.
*
* @since 5.0.0
*
* @return void
*/
public function __construct() {
parent::__construct();
add_action( 'wp_ajax_acf/field_group/render_field_settings', array( $this, 'ajax_render_field_settings' ) );
add_action( 'wp_ajax_acf/field_group/render_location_rule', array( $this, 'ajax_render_location_rule' ) );
add_action( 'wp_ajax_acf/field_group/move_field', array( $this, 'ajax_move_field' ) );
}
/**
* This function will customize the message shown when editing a field group
*
* @since 5.0.0
*
* @param array $messages Post type messages.
* @return array
*/
public function post_updated_messages( $messages ) {
$messages['acf-field-group'] = array(
0 => '', // Unused. Messages start at index 1.
1 => __( 'Field group updated.', 'acf' ),
2 => __( 'Field group updated.', 'acf' ),
3 => __( 'Field group deleted.', 'acf' ),
4 => __( 'Field group updated.', 'acf' ),
5 => false, // field group does not support revisions.
6 => __( 'Field group published.', 'acf' ),
7 => __( 'Field group saved.', 'acf' ),
8 => __( 'Field group submitted.', 'acf' ),
9 => __( 'Field group scheduled for.', 'acf' ),
10 => __( 'Field group draft updated.', 'acf' ),
);
return $messages;
}
/**
* Enqueues any scripts necessary for internal post type.
*
* @since 5.0.0
*
* @return void
*/
public function admin_enqueue_scripts() {
parent::admin_enqueue_scripts();
acf_localize_text(
array(
'The string "field_" may not be used at the start of a field name' => __( 'The string "field_" may not be used at the start of a field name', 'acf' ),
'This field cannot be moved until its changes have been saved' => __( 'This field cannot be moved until its changes have been saved', 'acf' ),
'Field group title is required' => __( 'Field group title is required', 'acf' ),
'Move field group to trash?' => __( 'Move field group to trash?', 'acf' ),
'No toggle fields available' => __( 'No toggle fields available', 'acf' ),
'Move Custom Field' => __( 'Move Custom Field', 'acf' ),
'Close modal' => __( 'Close modal', 'acf' ),
'Field moved to other group' => __( 'Field moved to other group', 'acf' ),
'Field groups linked successfully.' => __( 'Field groups linked successfully.', 'acf' ),
'Checked' => __( 'Checked', 'acf' ),
'(no label)' => __( '(no label)', 'acf' ),
'(this field)' => __( '(this field)', 'acf' ),
'copy' => __( 'copy', 'acf' ),
'or' => __( 'or', 'acf' ),
'Show this field group if' => __( 'Show this field group if', 'acf' ),
'Null' => __( 'Null', 'acf' ),
'PRO Only' => __( 'PRO Only', 'acf' ),
// Conditions.
'Has any value' => __( 'Has any value', 'acf' ),
'Has no value' => __( 'Has no value', 'acf' ),
'Value is equal to' => __( 'Value is equal to', 'acf' ),
'Value is not equal to' => __( 'Value is not equal to', 'acf' ),
'Value matches pattern' => __( 'Value matches pattern', 'acf' ),
'Value contains' => __( 'Value contains', 'acf' ),
'Value is greater than' => __( 'Value is greater than', 'acf' ),
'Value is less than' => __( 'Value is less than', 'acf' ),
'Selection is greater than' => __( 'Selection is greater than', 'acf' ),
'Selection is less than' => __( 'Selection is less than', 'acf' ),
// Custom Select2 templates.
'Type to search...' => __( 'Type to search...', 'acf' ),
'This Field' => __( 'This Field', 'acf' ),
)
);
acf_localize_data(
array(
'fieldTypes' => acf_get_field_types_info(),
'fieldCategoriesL10n' => acf_get_field_categories_i18n(),
'PROUpgradeURL' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'field-type-selection' ),
'PROFieldTypes' => acf_get_pro_field_types(),
'PROLocationTypes' => array(
'block' => __( 'Block', 'acf' ),
'options_page' => __( 'Options Page', 'acf' ),
),
)
);
do_action( 'acf/field_group/admin_enqueue_scripts' );
}
/**
* Set up functionality for the field group edit page.
*
* @since 3.1.8
*
* @return void
*/
public function admin_head() {
global $post, $field_group;
// Set global var.
$field_group = acf_get_field_group( $post->ID );
// metaboxes.
add_meta_box( 'acf-field-group-fields', __( 'Fields', 'acf' ), array( $this, 'mb_fields' ), 'acf-field-group', 'normal', 'high' );
add_meta_box( 'acf-field-group-options', __( 'Settings', 'acf' ), array( $this, 'mb_options' ), 'acf-field-group', 'normal', 'high' );
// actions.
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
// filters.
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
add_filter( 'get_user_option_screen_layout_acf-field-group', array( $this, 'screen_layout' ), 10, 1 );
// 3rd party hook.
do_action( 'acf/field_group/admin_head' );
}
/**
* This action will allow ACF to render metaboxes after the title.
*
* @return void
*/
public function edit_form_after_title() {
global $post;
// Render post data.
acf_form_data(
array(
'screen' => 'field_group',
'post_id' => $post->ID,
'delete_fields' => 0,
'validation' => 0,
)
);
}
/**
* This function will add extra HTML to the acf form data element
*
* @since 5.3.8
*
* @param array $args Arguments array to pass through to action.
* @return void
*/
public function form_data( $args ) {
do_action( 'acf/field_group/form_data', $args );
}
/**
* This function will append extra l10n strings to the acf JS object
*
* @since 5.3.8
*
* @param array $l10n The array of translated strings.
* @return array $l10n
*/
public function admin_l10n( $l10n ) {
return apply_filters( 'acf/field_group/admin_l10n', $l10n );
}
/**
* Admin footer third party hook support
*
* @since 5.3.2
*
* @return void
*/
public function admin_footer() {
$this->include_pro_features();
do_action( 'acf/field_group/admin_footer' );
}
/**
* Renders HTML for the ACF PRO features upgrade notice.
*
* @return void
*/
public function include_pro_features() {
// Bail if on PRO.
if ( acf_is_pro() && acf_pro_is_license_active() ) {
return;
}
// Bail if not the edit field group screen.
if ( ! acf_is_screen( 'acf-field-group' ) ) {
return;
}
acf_get_view( 'acf-field-group/pro-features' );
}
/**
* Screen settings html output
*
* @since 3.6.0
*
* @param string $html Current screen settings HTML.
* @return string $html
*/
public function screen_settings( $html ) {
$show_field_keys = acf_get_user_setting( 'show_field_keys' ) ? 'checked="checked"' : '';
$show_field_settings_tabs = acf_get_user_setting( 'show_field_settings_tabs', true ) ? 'checked="checked"' : '';
$hide_field_settings_tabs = apply_filters( 'acf/field_group/disable_field_settings_tabs', false );
$html .= '<div id="acf-append-show-on-screen" class="acf-hidden">';
$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>';
if ( ! $hide_field_settings_tabs ) {
$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>';
}
$html .= '</div>';
return $html;
}
/**
* Sets the "Edit Field Group" screen to use a one-column layout.
*
* @param int $columns Number of columns for layout.
*
* @return int
*/
public function screen_layout( $columns = 0 ) {
return 1;
}
/**
* This function will customize the publish metabox
*
* @since 5.2.9
*
* @return void
*/
public function post_submitbox_misc_actions() {
global $field_group;
$status_label = $field_group['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
?>
<script type="text/javascript">
(function($) {
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
})(jQuery);
</script>
<?php
}
/**
* Saves field group data.
*
* @since 1.0.0
*
* @param int $post_id The post ID.
* @param WP_Post $post The post object.
*
* @return int $post_id
*/
public function save_post( $post_id, $post ) {
if ( ! $this->verify_save_post( $post_id, $post ) ) {
return $post_id;
}
// disable filters to ensure ACF loads raw data from DB.
acf_disable_filters();
// save fields.
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated by WordPress.
if ( ! empty( $_POST['acf_fields'] ) ) {
// loop.
foreach ( $_POST['acf_fields'] as $field ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
if ( ! isset( $field['key'] ) ) {
continue;
}
// vars.
$specific = false;
$save = acf_extract_var( $field, 'save' );
// only saved field if has changed.
if ( $save == 'meta' ) {
$specific = array(
'menu_order',
'post_parent',
);
}
// set parent.
if ( ! $field['parent'] ) {
$field['parent'] = $post_id;
}
// save field.
acf_update_field( $field, $specific );
}
}
// delete fields.
if ( $_POST['_acf_delete_fields'] ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below.
// clean.
$ids = explode( '|', $_POST['_acf_delete_fields'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below.
$ids = array_map( 'intval', $ids );
// loop.
foreach ( $ids as $id ) {
// bai early if no id.
if ( ! $id ) {
continue;
}
// delete.
acf_delete_field( $id );
}
}
$_POST['acf_field_group']['ID'] = $post_id;
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
$_POST['acf_field_group']['title'] = $_POST['post_title'];
// save field group.
acf_update_field_group( $_POST['acf_field_group'] );
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// phpcs:enable WordPress.Security.NonceVerification.Missing
return $post_id;
}
/**
* This function will render the HTML for the metabox 'acf-field-group-fields'
*
* @since 5.0.0
*
* @return void
*/
public function mb_fields() {
global $field_group;
$view = array(
'fields' => acf_get_fields( $field_group ),
'parent' => 0,
);
acf_get_view( $this->post_type . '/fields', $view );
}
/**
* This function will render the HTML for the metabox 'acf-field-group-pro-features'
*
* @since 6.0.0
*
* @return void
*/
public function mb_pro_features() {
acf_get_view( $this->post_type . '/pro-features' );
}
/**
* This function will render the HTML for the metabox 'acf-field-group-options'
*
* @since 5.0.0
*
* @return void
*/
public function mb_options() {
global $field_group;
// Field group key (leave in for compatibility).
if ( ! acf_is_field_group_key( $field_group['key'] ) ) {
$field_group['key'] = uniqid( 'group_' );
}
acf_get_view( $this->post_type . '/options' );
}
/**
* This function can be accessed via an AJAX action and will return the result from the render_location_value function
*
* @since 5.0.0
*
* @return void
*/
public function ajax_render_location_rule() {
// validate.
if ( ! acf_verify_ajax() ) {
die();
}
// verify user capability.
if ( ! acf_current_user_can_admin() ) {
die();
}
// validate rule.
$rule = acf_validate_location_rule( acf_sanitize_request_args( $_POST['rule'] ) );
acf_get_view(
'acf-field-group/location-rule',
array(
'rule' => $rule,
)
);
die();
}
/**
* This function will return HTML containing the field's settings based on it's new type
*
* @since 5.0.0
*
* @return void
*/
public function ajax_render_field_settings() {
// Verify the current request.
if ( ! acf_verify_ajax() || ! acf_current_user_can_admin() ) {
wp_send_json_error();
}
// Make sure we have a field.
$field = acf_maybe_get_POST( 'field' );
if ( ! $field ) {
wp_send_json_error();
}
$field['prefix'] = acf_maybe_get_POST( 'prefix' );
$field = acf_get_valid_field( $field );
$tabs = acf_get_combined_field_type_settings_tabs();
$tab_keys = array_keys( $tabs );
$sections = array();
foreach ( $tab_keys as $tab ) {
ob_start();
if ( 'general' === $tab ) {
// Back-compat for fields not using tab-specific hooks.
do_action( "acf/render_field_settings/type={$field['type']}", $field );
}
do_action( "acf/field_group/render_field_settings_tab/{$tab}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab}_settings/type={$field['type']}", $field );
$sections[ $tab ] = ob_get_clean();
}
wp_send_json_success( $sections );
}
/**
* Move field AJAX function
*
* @since 5.0.0
*
* @return void No return, HTML output for AJAX consumption.
*/
public function ajax_move_field() {
// disable filters to ensure ACF loads raw data from DB.
acf_disable_filters();
// phpcs:disable WordPress.Security.NonceVerification.Missing
$args = acf_parse_args(
$_POST,
array(
'nonce' => '',
'post_id' => 0,
'field_id' => 0,
'field_group_id' => 0,
)
);
// phpcs:enable WordPress.Security.NonceVerification.Missing
// verify nonce.
if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) ) {
die();
}
// verify user capability.
if ( ! acf_current_user_can_admin() ) {
die();
}
// confirm?
if ( $args['field_id'] && $args['field_group_id'] ) {
// vars.
$field = acf_get_field( $args['field_id'] );
$field_group = acf_get_field_group( $args['field_group_id'] );
// update parent.
$field['parent'] = $field_group['ID'];
// remove conditional logic.
$field['conditional_logic'] = 0;
// update field.
acf_update_field( $field );
// Output HTML.
$link = '<a href="' . admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' ) . '" target="_blank">' . esc_html( $field_group['title'] ) . '</a>';
echo '' .
'<p><strong>' . __( 'Move Complete.', 'acf' ) . '</strong></p>' .
'<p>' . sprintf(
/* translators: Confirmation message once a field has been moved to a different field group. */
acf_punctify( __( 'The %1$s field can now be found in the %2$s field group', 'acf' ) ),
esc_html( $field['label'] ),
$link //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
) . '</p>' .
'<a href="#" class="button button-primary acf-close-popup">' . __( 'Close Modal', 'acf' ) . '</a>';
die();
}
// get all field groups.
$field_groups = acf_get_field_groups();
$choices = array();
// check.
if ( ! empty( $field_groups ) ) {
// loop.
foreach ( $field_groups as $field_group ) {
// bail early if no ID.
if ( ! $field_group['ID'] ) {
continue;
}
// bail early if is current.
if ( $field_group['ID'] == $args['post_id'] ) {
continue;
}
$choices[ $field_group['ID'] ] = $field_group['title'];
}
}
// render options.
$field = acf_get_valid_field(
array(
'type' => 'select',
'name' => 'acf_field_group',
'choices' => $choices,
'aria-label' => __( 'Please select the destination for this field', 'acf' ),
)
);
echo '<p>' . __( 'Please select the destination for this field', 'acf' ) . '</p>';
echo '<form id="acf-move-field-form">';
// render.
acf_render_field_wrap( $field );
echo '<button type="submit" class="acf-btn">' . __( 'Move Field', 'acf' ) . '</button>';
echo '</form>';
die();
}
}
// initialize.
new acf_admin_field_group();
endif; // Class exists check.
?>

View File

@ -0,0 +1,392 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Field_Groups' ) ) :
#[AllowDynamicProperties]
class ACF_Admin_Field_Groups extends ACF_Admin_Internal_Post_Type_List {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-field-group';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-field-groups';
/**
* The name of the store used for the post type.
*
* @var string
*/
public $store = 'field-groups';
/**
* Constructor.
*
* @date 5/03/2014
* @since 5.0.0
*
* @return void
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ), 7 );
add_action( 'load-edit.php', array( $this, 'handle_redirection' ) );
add_action( 'admin_footer', array( $this, 'include_pro_features' ) );
parent::__construct();
}
/**
* Renders HTML for the ACF PRO features upgrade notice.
*
* @return void
*/
public function include_pro_features() {
// Bail if on PRO.
if ( acf_is_pro() && acf_pro_is_license_active() ) {
return;
}
// Bail if not the edit field groups screen.
if ( ! acf_is_screen( 'edit-acf-field-group' ) ) {
return;
}
acf_get_view( $this->post_type . '/pro-features' );
}
/**
* Add any menu items required for field groups.
*
* @since 6.1
*/
public function admin_menu() {
$parent_slug = 'edit.php?post_type=acf-field-group';
$cap = acf_get_setting( 'capability' );
add_submenu_page( $parent_slug, __( 'Field Groups', 'acf' ), __( 'Field Groups', 'acf' ), $cap, $parent_slug );
}
/**
* Redirects users from ACF 4.0 admin page.
*
* @date 17/9/18
* @since 5.7.6
*
* @return void
*/
public function handle_redirection() {
if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'acf' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
wp_redirect( $this->get_admin_url() );
exit;
}
}
/**
* Customizes the admin table columns.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $_columns The columns array.
* @return array
*/
public function admin_table_columns( $_columns ) {
// Set the "no found" label to be our custom HTML for no results.
if ( empty( acf_request_arg( 's' ) ) ) {
global $wp_post_types;
$this->not_found_label = $wp_post_types['acf-field-group']->labels->not_found;
$wp_post_types['acf-field-group']->labels->not_found = $this->get_not_found_html();
}
$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( $this->post_type ) ) {
$columns['acf-json'] = __( 'Local JSON', 'acf' );
}
return $columns;
}
/**
* Renders a specific admin table column.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param array $post The main ACF post array.
* @return void
*/
public function render_admin_table_column( $column_name, $post ) {
switch ( $column_name ) {
// Key.
case 'acf-key':
echo '<i class="acf-icon acf-icon-key-solid"></i>';
echo esc_html( $post['key'] );
break;
// Description.
case 'acf-description':
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
} else {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
}
break;
// Location.
case 'acf-location':
$this->render_admin_table_column_locations( $post );
break;
// Count.
case 'acf-count':
$this->render_admin_table_column_num_fields( $post );
break;
// Local JSON.
case 'acf-json':
$this->render_admin_table_column_local_status( $post );
break;
}
}
/**
* Displays a visual representation of the field group's locations.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $field_group The field group.
* @return void
*/
public function render_admin_table_column_locations( $field_group ) {
$objects = array();
// Loop over location rules and determine connected object types.
if ( $field_group['location'] ) {
foreach ( $field_group['location'] as $i => $rules ) {
// Determine object types for each rule.
foreach ( $rules as $j => $rule ) {
// Get location type and subtype for the current 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;
}
// Now that each $rule conains object type data...
$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( '' );
}
// Append to objects.
foreach ( $object_subtypes as $object_subtype ) {
$object = acf_get_object_type( $object_type, $object_subtype );
if ( $object ) {
$objects[ $object->name ] = $object;
}
}
}
}
// Reset keys.
$objects = array_values( $objects );
// Display.
$html = '';
if ( $objects ) {
$limit = 3;
$total = count( $objects );
// Icon.
$html .= '<span class="dashicons ' . $objects[0]->icon . ( $total > 1 ? ' acf-multi-dashicon' : '' ) . '"></span>';
// Labels.
$labels = array_column( $objects, 'label' );
$labels = array_slice( $labels, 0, 3 );
$html .= implode( ', ', $labels );
// More.
if ( $total > $limit ) {
$html .= ', ...';
}
} else {
$html = '<span class="dashicons dashicons-businesswoman"></span> ' . __( 'Various', 'acf' );
}
// Filter.
echo acf_esc_html( $html );
}
/**
* Renders the number of fields created for the field group in the list table.
*
* @since 6.1.5
*
* @param array $field_group The main field group array.
* @return void
*/
public function render_admin_table_column_num_fields( $field_group ) {
$field_count = acf_get_field_count( $field_group );
if ( ! $field_count || ! is_numeric( $field_count ) ) {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No fields', 'acf' ) . '</span>';
return;
}
// If in JSON but not synced or in trash, the link won't work.
if ( empty( $field_group['ID'] ) || 'trash' === get_post_status( $field_group['ID'] ) ) {
echo esc_html( number_format_i18n( $field_count ) );
return;
}
printf(
'<a href="%s">%s</a>',
esc_url( admin_url( 'post.php?action=edit&post=' . $field_group['ID'] ) ),
esc_html( number_format_i18n( $field_count ) )
);
}
/**
* Fires when trashing a field group.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function trashed_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_trash_field_group( $post_id );
}
}
/**
* Fires when untrashing a field group.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function untrashed_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_untrash_field_group( $post_id );
}
}
/**
* Fires when deleting a field group.
*
* @date 8/01/2014
* @since 5.0.0
*
* @param int $post_id The post ID.
* @return void
*/
public function deleted_post( $post_id ) {
if ( get_post_type( $post_id ) === $this->post_type ) {
acf_delete_field_group( $post_id );
}
}
/**
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
*
* @since 6.1
*
* @param string $action The action being performed.
* @param int $count The number of items the action was performed on.
* @return string
*/
public function get_action_notice_text( $action, $count = 1 ) {
$text = '';
$count = (int) $count;
switch ( $action ) {
case 'acfactivatecomplete':
$text = sprintf(
/* translators: %s number of field groups activated */
_n( 'Field group activated.', '%s field groups activated.', $count, 'acf' ),
$count
);
break;
case 'acfdeactivatecomplete':
$text = sprintf(
/* translators: %s number of field groups deactivated */
_n( 'Field group deactivated.', '%s field groups deactivated.', $count, 'acf' ),
$count
);
break;
case 'acfduplicatecomplete':
$text = sprintf(
/* translators: %s number of field groups duplicated */
_n( 'Field group duplicated.', '%s field groups duplicated.', $count, 'acf' ),
$count
);
break;
case 'acfsynccomplete':
$text = sprintf(
/* translators: %s number of field groups synchronized */
_n( 'Field group synchronized.', '%s field groups synchronized.', $count, 'acf' ),
$count
);
break;
}
return $text;
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin_Field_Groups' );
endif; // Class exists check.

View File

@ -0,0 +1,370 @@
<?php
/**
* ACF Admin Post Type Class
*
* @class ACF_Admin_Post_Type
*
* @package ACF
* @subpackage Admin
*/
if ( ! class_exists( 'ACF_Admin_Post_Type' ) ) :
/**
* ACF Admin Post Type Class
*
* All the logic for editing a post type.
*/
class ACF_Admin_Post_type extends ACF_Admin_Internal_Post_Type {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-post-type';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-single-post-type';
/**
* This function will customize the message shown when editing a post type.
*
* @since 5.0.0
*
* @param array $messages Post type messages.
* @return array
*/
public function post_updated_messages( $messages ) {
$messages['acf-post-type'] = array(
0 => '', // Unused. Messages start at index 1.
1 => $this->post_type_created_message(), // Updated.
2 => $this->post_type_created_message(),
3 => __( 'Post type deleted.', 'acf' ),
4 => __( 'Post type updated.', 'acf' ),
5 => false, // Post type does not support revisions.
6 => $this->post_type_created_message( true ), // Created.
7 => __( 'Post type saved.', 'acf' ),
8 => __( 'Post type submitted.', 'acf' ),
9 => __( 'Post type scheduled for.', 'acf' ),
10 => __( 'Post type draft updated.', 'acf' ),
);
return $messages;
}
/**
* Renders the post type created message.
*
* @since 6.1
*
* @param bool $created True if the post was just created.
* @return string
*/
public function post_type_created_message( $created = false ) {
global $post_id;
$title = get_the_title( $post_id );
/* translators: %s post type name */
$item_saved_text = sprintf( __( '%s post type updated', 'acf' ), $title );
if ( $created ) {
/* translators: %s post type name */
$item_saved_text = sprintf( __( '%s post type created', 'acf' ), $title );
}
$add_fields_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-field-group&use_post_type=' . $post_id ),
'add-fields-' . $post_id
);
$create_post_type_link = admin_url( 'post-new.php?post_type=acf-post-type' );
$duplicate_post_type_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-post-type&use_post_type=' . $post_id ),
'acfduplicate-' . $post_id
);
$create_taxonomy_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-taxonomy&use_post_type=' . $post_id ),
'create-taxonomy-' . $post_id
);
ob_start(); ?>
<p class="acf-item-saved-text"><?php echo esc_html( $item_saved_text ); ?></p>
<div class="acf-item-saved-links">
<a href="<?php echo esc_url( $add_fields_link ); ?>"><?php esc_html_e( 'Add fields', 'acf' ); ?></a>
<a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link field groups', 'acf' ); ?></a>
<a href="<?php echo esc_url( $create_post_type_link ); ?>"><?php esc_html_e( 'Create post type', 'acf' ); ?></a>
<a href="<?php echo esc_url( $duplicate_post_type_link ); ?>"><?php esc_html_e( 'Duplicate post type', 'acf' ); ?></a>
<a href="<?php echo esc_url( $create_taxonomy_link ); ?>"><?php esc_html_e( 'Create taxonomy', 'acf' ); ?></a>
</div>
<?php
return ob_get_clean();
}
/**
* Enqueues any scripts necessary for internal post type.
*
* @since 5.0.0
*
* @return void
*/
public function admin_enqueue_scripts() {
wp_enqueue_style( 'acf-field-group' );
acf_localize_text(
array(
'Post' => __( 'Post', 'acf' ),
'Posts' => __( 'Posts', 'acf' ),
'Page' => __( 'Page', 'acf' ),
'Pages' => __( 'Pages', 'acf' ),
'Default' => __( 'Default', 'acf' ),
)
);
parent::admin_enqueue_scripts();
do_action( 'acf/post_type/admin_enqueue_scripts' );
}
/**
* Sets up all functionality for the post type edit page to work.
*
* @since 3.1.8
*
* @return void
*/
public function admin_head() {
// global.
global $post, $acf_post_type;
// set global var.
$acf_post_type = acf_get_internal_post_type( $post->ID, $this->post_type );
if ( ! empty( $acf_post_type['not_registered'] ) ) {
acf_add_admin_notice(
__( 'This post type could not be registered because its key is in use by another post type registered by another plugin or theme.', 'acf' ),
'error'
);
}
// metaboxes.
add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'acf' ), array( $this, 'mb_basic_settings' ), 'acf-post-type', 'normal', 'high' );
add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'acf' ), array( $this, 'mb_advanced_settings' ), 'acf-post-type', 'normal', 'high' );
// actions.
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
// filters.
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
add_filter( 'get_user_option_screen_layout_acf-post-type', array( $this, 'screen_layout' ), 10, 1 );
add_filter( 'get_user_option_metaboxhidden_acf-post-type', array( $this, 'force_basic_settings' ), 10, 1 );
add_filter( 'get_user_option_closedpostboxes_acf-post-type', array( $this, 'force_basic_settings' ), 10, 1 );
add_filter( 'get_user_option_closedpostboxes_acf-post-type', array( $this, 'force_advanced_settings' ), 10, 1 );
// 3rd party hook.
do_action( 'acf/post_type/admin_head' );
}
/**
* This action will allow ACF to render metaboxes after the title.
*
* @return void
*/
public function edit_form_after_title() {
// globals.
global $post;
// render post data.
acf_form_data(
array(
'screen' => 'post_type',
'post_id' => $post->ID,
'delete_fields' => 0,
'validation' => 1,
)
);
}
/**
* This function will add extra HTML to the acf form data element
*
* @since 5.3.8
*
* @param array $args Arguments array to pass through to action.
* @return void
*/
public function form_data( $args ) {
do_action( 'acf/post_type/form_data', $args );
}
/**
* This function will append extra l10n strings to the acf JS object
*
* @since 5.3.8
*
* @param array $l10n The array of translated strings.
* @return array $l10n
*/
public function admin_l10n( $l10n ) {
return apply_filters( 'acf/post_type/admin_l10n', $l10n );
}
/**
* Admin footer third party hook support
*
* @since 5.3.2
*
* @return void
*/
public function admin_footer() {
do_action( 'acf/post_type/admin_footer' );
}
/**
* Screen settings html output
*
* @since 3.6.0
*
* @param string $html Current screen settings HTML.
* @return string $html
*/
public function screen_settings( $html ) {
return $html;
}
/**
* Sets the "Edit Post Type" screen to use a one-column layout.
*
* @param int $columns Number of columns for layout.
*
* @return int
*/
public function screen_layout( $columns = 0 ) {
return 1;
}
/**
* Force basic settings to always be visible
*
* @param array $hidden_metaboxes The metaboxes hidden on this page.
*
* @return array
*/
public function force_basic_settings( $hidden_metaboxes ) {
if ( ! is_array( $hidden_metaboxes ) ) {
return $hidden_metaboxes;
}
return array_diff( $hidden_metaboxes, array( 'acf-basic-settings' ) );
}
/**
* Force advanced settings to be visible
*
* @param array $hidden_metaboxes The metaboxes hidden on this page.
*
* @return array
*/
public function force_advanced_settings( $hidden_metaboxes ) {
if ( ! is_array( $hidden_metaboxes ) ) {
return $hidden_metaboxes;
}
return array_diff( $hidden_metaboxes, array( 'acf-advanced-settings' ) );
}
/**
* This function will customize the publish metabox
*
* @since 5.2.9
*
* @return void
*/
public function post_submitbox_misc_actions() {
global $acf_post_type;
$status_label = $acf_post_type['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
?>
<script type="text/javascript">
(function($) {
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
})(jQuery);
</script>
<?php
}
/**
* Saves post type data.
*
* @since 1.0.0
*
* @param int $post_id The post ID.
* @param WP_Post $post The post object.
*
* @return int $post_id
*/
public function save_post( $post_id, $post ) {
if ( ! $this->verify_save_post( $post_id, $post ) ) {
return $post_id;
}
// Disable filters to ensure ACF loads raw data from DB.
acf_disable_filters();
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated in $this->verify_save_post() above.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
$_POST['acf_post_type']['ID'] = $post_id;
$_POST['acf_post_type']['title'] = isset( $_POST['acf_post_type']['labels']['name'] ) ? $_POST['acf_post_type']['labels']['name'] : '';
// Save the post type.
acf_update_internal_post_type( $_POST['acf_post_type'], $this->post_type ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Validated in verify_save_post
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// phpcs:enable WordPress.Security.NonceVerification.Missing
return $post_id;
}
/**
* Renders HTML for the basic settings metabox.
*
* @since 5.0.0
*
* @return void
*/
public function mb_basic_settings() {
global $acf_post_type;
if ( ! acf_is_internal_post_type_key( $acf_post_type['key'], 'acf-post-type' ) ) {
$acf_post_type['key'] = uniqid( 'post_type_' );
}
acf_get_view( $this->post_type . '/basic-settings' );
}
/**
* Renders the HTML for the advanced settings metabox.
*
* @since 5.0.0
*
* @return void
*/
public function mb_advanced_settings() {
acf_get_view( $this->post_type . '/advanced-settings' );
}
}
new ACF_Admin_Post_Type();
endif; // Class exists check.
?>

View File

@ -0,0 +1,377 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Admin_Post_Types' ) ) :
/**
* The ACF Post Types admin controller class
*/
#[AllowDynamicProperties]
class ACF_Admin_Post_Types extends ACF_Admin_Internal_Post_Type_List {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-post-type';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-post-types';
/**
* The name of the store used for the post type.
*
* @var string
*/
public $store = 'post-types';
/**
* Constructor.
*
* @date 5/03/2014
* @since 6.2
*
* @return void
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ), 8 );
add_action( 'admin_footer', array( $this, 'include_pro_features' ) );
parent::__construct();
}
/**
* Renders HTML for the ACF PRO features upgrade notice.
*
* @return void
*/
public function include_pro_features() {
// Bail if on PRO.
if ( acf_is_pro() && acf_pro_is_license_active() ) {
return;
}
// Bail if not the edit post types screen.
if ( ! acf_is_screen( 'edit-acf-post-type' ) ) {
return;
}
acf_get_view( 'acf-field-group/pro-features' );
}
/**
* Current screen actions for the post types list admin page.
*
* @since 6.1
*
* @return void
*/
public function current_screen() {
// Bail early if not post types admin page.
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
return;
}
parent::current_screen();
// Run a first-run routine to set some defaults which are stored in user preferences.
if ( ! acf_get_user_setting( 'post-type-first-run', false ) ) {
$option_key = 'manageedit-' . $this->post_type . 'columnshidden';
$hidden_items = get_user_option( $option_key );
if ( ! is_array( $hidden_items ) ) {
$hidden_items = array();
}
if ( ! in_array( 'acf-key', $hidden_items ) ) {
$hidden_items[] = 'acf-key';
}
update_user_option( get_current_user_id(), $option_key, $hidden_items, true );
acf_update_user_setting( 'post-type-first-run', true );
}
}
/**
* Add any menu items required for post types.
*
* @since 6.1
*/
public function admin_menu() {
$parent_slug = 'edit.php?post_type=acf-field-group';
$cap = acf_get_setting( 'capability' );
add_submenu_page( $parent_slug, __( 'Post Types', 'acf' ), __( 'Post Types', 'acf' ), $cap, 'edit.php?post_type=acf-post-type' );
}
/**
* Customizes the admin table columns.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $_columns The columns array.
* @return array
*/
public function admin_table_columns( $_columns ) {
// Set the "no found" label to be our custom HTML for no results.
if ( empty( acf_request_arg( 's' ) ) ) {
global $wp_post_types;
$this->not_found_label = $wp_post_types[ $this->post_type ]->labels->not_found;
$wp_post_types[ $this->post_type ]->labels->not_found = $this->get_not_found_html();
}
$columns = array(
'cb' => $_columns['cb'],
'title' => $_columns['title'],
'acf-description' => __( 'Description', 'acf' ),
'acf-key' => __( 'Key', 'acf' ),
'acf-taxonomies' => __( 'Taxonomies', 'acf' ),
'acf-field-groups' => __( 'Field Groups', 'acf' ),
'acf-count' => __( 'Posts', 'acf' ),
);
if ( acf_get_local_json_files( $this->post_type ) ) {
$columns['acf-json'] = __( 'Local JSON', 'acf' );
}
return $columns;
}
/**
* Renders a specific admin table column.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param array $post The main ACF post array.
* @return void
*/
public function render_admin_table_column( $column_name, $post ) {
switch ( $column_name ) {
case 'acf-key':
echo '<i class="acf-icon acf-icon-key-solid"></i>';
echo esc_html( $post['key'] );
break;
// Description.
case 'acf-description':
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
} else {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
}
break;
case 'acf-taxonomies':
$this->render_admin_table_column_taxonomies( $post );
break;
case 'acf-field-groups':
$this->render_admin_table_column_field_groups( $post );
break;
case 'acf-count':
$this->render_admin_table_column_num_posts( $post );
break;
// Local JSON.
case 'acf-json':
$this->render_admin_table_column_local_status( $post );
break;
}
}
/**
* Renders the field groups attached to the post type in the list table.
*
* @since 6.1
*
* @param array $post_type The main post type array.
* @return void
*/
public function render_admin_table_column_field_groups( $post_type ) {
$field_groups = acf_get_field_groups( array( 'post_type' => $post_type['post_type'] ) );
if ( empty( $field_groups ) ) {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No field groups', 'acf' ) . '</span>';
return;
}
$labels = wp_list_pluck( $field_groups, 'title' );
$limit = 3;
$shown_labels = array_slice( $labels, 0, $limit );
$hidden_labels = array_slice( $labels, $limit );
$text = implode( ', ', $shown_labels );
if ( ! empty( $hidden_labels ) ) {
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
}
echo acf_esc_html( $text );
}
/**
* Renders the taxonomies attached to the post type in the list table.
*
* @since 6.1
*
* @param array $post_type The main post type array.
* @return void
*/
public function render_admin_table_column_taxonomies( $post_type ) {
$taxonomies = array();
$labels = array();
if ( is_array( $post_type['taxonomies'] ) ) {
$taxonomies = $post_type['taxonomies'];
}
$acf_taxonomies = acf_get_internal_post_type_posts( 'acf-taxonomy' );
foreach ( $acf_taxonomies as $acf_taxonomy ) {
if ( is_array( $acf_taxonomy['object_type'] ) && in_array( $post_type['post_type'], $acf_taxonomy['object_type'], true ) ) {
$taxonomies[] = $acf_taxonomy['taxonomy'];
}
}
$taxonomies = array_unique( $taxonomies );
foreach ( $taxonomies as $tax_slug ) {
$taxonomy = get_taxonomy( $tax_slug );
if ( ! is_object( $taxonomy ) || empty( $taxonomy->label ) ) {
continue;
}
$labels[] = $taxonomy->label;
}
if ( empty( $labels ) ) {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No taxonomies', 'acf' ) . '</span>';
return;
}
$limit = 3;
$shown_labels = array_slice( $labels, 0, $limit );
$hidden_labels = array_slice( $labels, $limit );
$text = implode( ', ', $shown_labels );
if ( ! empty( $hidden_labels ) ) {
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
}
echo acf_esc_html( $text );
}
/**
* Renders the number of posts created for the post type in the list table.
*
* @since 6.1
*
* @param array $post_type The main post type array.
* @return void
*/
public function render_admin_table_column_num_posts( $post_type ) {
$no_posts = '<span class="acf-emdash" aria-hidden="true">—</span>';
$no_posts .= '<span class="screen-reader-text">' . esc_html__( 'No posts', 'acf' ) . '</span>';
// WP doesn't count posts for post types that don't exist.
if ( empty( $post_type['active'] ) || 'trash' === get_post_status( $post_type['ID'] ) ) {
echo acf_esc_html( $no_posts );
return;
}
$num_posts = wp_count_posts( $post_type['post_type'] );
if ( is_object( $num_posts ) && property_exists( $num_posts, 'publish' ) ) {
$num_posts = $num_posts->publish;
}
if ( ! $num_posts || ! is_numeric( $num_posts ) ) {
echo acf_esc_html( $no_posts );
return;
}
printf(
'<a href="%s">%s</a>',
esc_url( admin_url( 'edit.php?post_type=' . $post_type['post_type'] ) ),
esc_html( number_format_i18n( $num_posts ) )
);
}
/**
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
*
* @since 6.1
*
* @param string $action The action being performed.
* @param int $count The number of items the action was performed on.
* @return string
*/
public function get_action_notice_text( $action, $count = 1 ) {
$text = '';
$count = (int) $count;
switch ( $action ) {
case 'acfactivatecomplete':
$text = sprintf(
/* translators: %s number of post types activated */
_n( 'Post type activated.', '%s post types activated.', $count, 'acf' ),
$count
);
break;
case 'acfdeactivatecomplete':
$text = sprintf(
/* translators: %s number of post types deactivated */
_n( 'Post type deactivated.', '%s post types deactivated.', $count, 'acf' ),
$count
);
break;
case 'acfduplicatecomplete':
$text = sprintf(
/* translators: %s number of post types duplicated */
_n( 'Post type duplicated.', '%s post types duplicated.', $count, 'acf' ),
$count
);
break;
case 'acfsynccomplete':
$text = sprintf(
/* translators: %s number of post types synchronized */
_n( 'Post type synchronized.', '%s post types synchronized.', $count, 'acf' ),
$count
);
break;
}
return $text;
}
/**
* Returns the registration error state.
*
* @since 6.1
*
* @return string
*/
public function get_registration_error_state() {
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
__( 'This post type could not be registered because its key is in use by another post type registered by another plugin or theme.', 'acf' ) .
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin_Post_Types' );
endif; // Class exists check.

View File

@ -0,0 +1,384 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly.
}
if ( ! class_exists( 'ACF_Admin_Taxonomies' ) ) :
/**
* The ACF Post Types admin controller class
*/
#[AllowDynamicProperties]
class ACF_Admin_Taxonomies extends ACF_Admin_Internal_Post_Type_List {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-taxonomy';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-taxonomies';
/**
* The name of the store used for the post type.
*
* @var string
*/
public $store = 'taxonomies';
/**
* Constructor.
*
* @date 5/03/2014
* @since 6.2
*
* @return void
*/
public function __construct() {
add_action( 'admin_menu', array( $this, 'admin_menu' ), 9 );
add_action( 'admin_footer', array( $this, 'include_pro_features' ) );
parent::__construct();
}
/**
* Renders HTML for the ACF PRO features upgrade notice.
*
* @return void
*/
public function include_pro_features() {
// Bail if on PRO.
if ( acf_is_pro() && acf_pro_is_license_active() ) {
return;
}
// Bail if not the edit taxonomies screen.
if ( ! acf_is_screen( 'edit-acf-taxonomy' ) ) {
return;
}
acf_get_view( 'acf-field-group/pro-features' );
}
/**
* Current screen actions for the taxonomies list admin page.
*
* @since 6.1
*
* @return void
*/
public function current_screen() {
// Bail early if not post types admin page.
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
return;
}
parent::current_screen();
// Run a first-run routine to set some defaults which are stored in user preferences.
if ( ! acf_get_user_setting( 'taxonomies-first-run', false ) ) {
$option_key = 'manageedit-' . $this->post_type . 'columnshidden';
$hidden_items = get_user_option( $option_key );
if ( ! is_array( $hidden_items ) ) {
$hidden_items = array();
}
if ( ! in_array( 'acf-key', $hidden_items ) ) {
$hidden_items[] = 'acf-key';
}
update_user_option( get_current_user_id(), $option_key, $hidden_items, true );
acf_update_user_setting( 'taxonomies-first-run', true );
}
}
/**
* Add any menu items required for taxonomies.
*
* @since 6.1
*/
public function admin_menu() {
$parent_slug = 'edit.php?post_type=acf-field-group';
$cap = acf_get_setting( 'capability' );
add_submenu_page( $parent_slug, __( 'Taxonomies', 'acf' ), __( 'Taxonomies', 'acf' ), $cap, 'edit.php?post_type=acf-taxonomy' );
}
/**
* Customizes the admin table columns.
*
* @date 1/4/20
* @since 5.9.0
*
* @param array $_columns The columns array.
* @return array
*/
public function admin_table_columns( $_columns ) {
// Set the "no found" label to be our custom HTML for no results.
if ( empty( acf_request_arg( 's' ) ) ) {
global $wp_post_types;
$this->not_found_label = $wp_post_types[ $this->post_type ]->labels->not_found;
$wp_post_types[ $this->post_type ]->labels->not_found = $this->get_not_found_html();
}
$columns = array(
'cb' => $_columns['cb'],
'title' => $_columns['title'],
'acf-description' => __( 'Description', 'acf' ),
'acf-key' => __( 'Key', 'acf' ),
'acf-post-types' => __( 'Post Types', 'acf' ),
'acf-field-groups' => __( 'Field Groups', 'acf' ),
'acf-count' => __( 'Terms', 'acf' ),
);
if ( acf_get_local_json_files( $this->post_type ) ) {
$columns['acf-json'] = __( 'Local JSON', 'acf' );
}
return $columns;
}
/**
* Renders a specific admin table column.
*
* @date 17/4/20
* @since 5.9.0
*
* @param string $column_name The name of the column to display.
* @param array $post The main ACF post array.
* @return void
*/
public function render_admin_table_column( $column_name, $post ) {
switch ( $column_name ) {
case 'acf-key':
echo '<i class="acf-icon acf-icon-key-solid"></i>';
echo esc_html( $post['key'] );
break;
// Description.
case 'acf-description':
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
} else {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
}
break;
case 'acf-field-groups':
$this->render_admin_table_column_field_groups( $post );
break;
case 'acf-post-types':
$this->render_admin_table_column_post_types( $post );
break;
case 'acf-count':
$this->render_admin_table_column_num_terms( $post );
break;
// Local JSON.
case 'acf-json':
$this->render_admin_table_column_local_status( $post );
break;
}
}
/**
* Renders the field groups attached to the taxonomy in the list table.
*
* @since 6.1
*
* @param array $taxonomy The main taxonomy array.
* @return void
*/
public function render_admin_table_column_field_groups( $taxonomy ) {
$field_groups = acf_get_field_groups( array( 'taxonomy' => $taxonomy['taxonomy'] ) );
if ( empty( $field_groups ) ) {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No field groups', 'acf' ) . '</span>';
return;
}
$labels = wp_list_pluck( $field_groups, 'title' );
$limit = 3;
$shown_labels = array_slice( $labels, 0, $limit );
$hidden_labels = array_slice( $labels, $limit );
$text = implode( ', ', $shown_labels );
if ( ! empty( $hidden_labels ) ) {
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
}
echo acf_esc_html( $text );
}
/**
* Renders the post types attached to the taxonomy in the list table.
*
* @since 6.1
*
* @param array $taxonomy The main taxonomy array.
* @return void
*/
public function render_admin_table_column_post_types( $taxonomy ) {
$post_types = get_post_types( array(), 'objects' );
$labels = array();
$object_types = array();
if ( ! empty( $taxonomy['object_type'] ) ) {
$object_types = (array) $taxonomy['object_type'];
}
foreach ( $object_types as $post_type_slug ) {
if ( ! isset( $post_types[ $post_type_slug ] ) ) {
continue;
}
$post_type = $post_types[ $post_type_slug ];
if ( empty( $post_type->label ) ) {
continue;
}
$labels[] = $post_type->label;
}
$acf_post_types = acf_get_internal_post_type_posts( 'acf-post-type' );
foreach ( $acf_post_types as $acf_post_type ) {
if ( is_array( $acf_post_type['taxonomies'] ) && in_array( $taxonomy['taxonomy'], $acf_post_type['taxonomies'], true ) ) {
$labels[] = $acf_post_type['title'];
}
}
if ( empty( $labels ) ) {
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
echo '<span class="screen-reader-text">' . esc_html__( 'No post types', 'acf' ) . '</span>';
return;
}
$labels = array_unique( $labels );
$limit = 3;
$shown_labels = array_slice( $labels, 0, $limit );
$hidden_labels = array_slice( $labels, $limit );
$text = implode( ', ', $shown_labels );
if ( ! empty( $hidden_labels ) ) {
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
}
echo acf_esc_html( $text );
}
/**
* Renders the number of terms created for the taxonomy in the list table.
*
* @since 6.1
*
* @param array $taxonomy The main taxonomy array.
* @return void
*/
public function render_admin_table_column_num_terms( $taxonomy ) {
$no_terms = '<span class="acf-emdash" aria-hidden="true">—</span>';
$no_terms .= '<span class="screen-reader-text">' . esc_html__( 'No terms', 'acf' ) . '</span>';
// WP doesn't count terms for taxonomies that don't exist and instead returns WP_Error.
if ( empty( $taxonomy['active'] ) || 'trash' === get_post_status( $taxonomy['ID'] ) ) {
echo acf_esc_html( $no_terms );
return;
}
$num_terms = wp_count_terms(
array(
'taxonomy' => $taxonomy['taxonomy'],
'hide_empty' => false,
'parent' => 0,
)
);
if ( ! $num_terms || ! is_numeric( $num_terms ) ) {
echo acf_esc_html( $no_terms );
return;
}
printf(
'<a href="%s">%s</a>',
esc_url( admin_url( 'edit-tags.php?taxonomy=' . $taxonomy['taxonomy'] ) ),
esc_html( number_format_i18n( $num_terms ) )
);
}
/**
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
*
* @since 6.1
*
* @param string $action The action being performed.
* @param int $count The number of items the action was performed on.
* @return string
*/
public function get_action_notice_text( $action, $count = 1 ) {
$text = '';
$count = (int) $count;
switch ( $action ) {
case 'acfactivatecomplete':
$text = sprintf(
/* translators: %s number of taxonomies activated */
_n( 'Taxonomy activated.', '%s taxonomies activated.', $count, 'acf' ),
$count
);
break;
case 'acfdeactivatecomplete':
$text = sprintf(
/* translators: %s number of taxonomies deactivated */
_n( 'Taxonomy deactivated.', '%s taxonomies deactivated.', $count, 'acf' ),
$count
);
break;
case 'acfduplicatecomplete':
$text = sprintf(
/* translators: %s number of taxonomies duplicated */
_n( 'Taxonomy duplicated.', '%s taxonomies duplicated.', $count, 'acf' ),
$count
);
break;
case 'acfsynccomplete':
$text = sprintf(
/* translators: %s number of taxonomies synchronized */
_n( 'Taxonomy synchronized.', '%s taxonomies synchronized.', $count, 'acf' ),
$count
);
break;
}
return $text;
}
/**
* Returns the registration error state.
*
* @since 6.1
*
* @return string
*/
public function get_registration_error_state() {
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
__( 'This taxonomy could not be registered because its key is in use by another taxonomy registered by another plugin or theme.', 'acf' ) .
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
}
}
// Instantiate.
acf_new_instance( 'ACF_Admin_Taxonomies' );
endif; // Class exists check.

View File

@ -0,0 +1,372 @@
<?php
/**
* ACF Admin Taxonomy Class
*
* @class ACF_Admin_Taxonomiy
*
* @package ACF
* @subpackage Admin
*/
if ( ! class_exists( 'ACF_Admin_Taxonomy' ) ) :
/**
* ACF Admin Field Group Class
*
* All the logic for editing a taxonomy.
*/
class ACF_Admin_Taxonomy extends ACF_Admin_Internal_Post_Type {
/**
* The slug for the internal post type.
*
* @since 6.1
* @var string
*/
public $post_type = 'acf-taxonomy';
/**
* The admin body class used for the post type.
*
* @since 6.1
* @var string
*/
public $admin_body_class = 'acf-admin-single-taxonomy';
/**
* This function will customize the message shown when editing a field group
*
* @since 5.0.0
*
* @param array $messages Post type messages.
* @return array
*/
public function post_updated_messages( $messages ) {
$messages['acf-taxonomy'] = array(
0 => '', // Unused. Messages start at index 1.
1 => $this->taxonomy_saved_message(),
2 => __( 'Taxonomy updated.', 'acf' ),
3 => __( 'Taxonomy deleted.', 'acf' ),
4 => $this->taxonomy_saved_message(),
5 => false, // taxonomy does not support revisions.
6 => $this->taxonomy_saved_message( true ),
7 => __( 'Taxonomy saved.', 'acf' ),
8 => __( 'Taxonomy submitted.', 'acf' ),
9 => __( 'Taxonomy scheduled for.', 'acf' ),
10 => __( 'Taxonomy draft updated.', 'acf' ),
);
return $messages;
}
/**
* Renders the post type created message.
*
* @since 6.1
*
* @param bool $created True if the post was just created.
* @return string
*/
public function taxonomy_saved_message( $created = false ) {
global $post_id;
$title = get_the_title( $post_id );
/* translators: %s taxonomy name */
$item_saved_text = sprintf( __( '%s taxonomy updated', 'acf' ), $title );
/* translators: %s taxonomy name */
$add_fields_text = sprintf( __( 'Add fields to %s', 'acf' ), $title );
if ( $created ) {
/* translators: %s taxonomy name */
$item_saved_text = sprintf( __( '%s taxonomy created', 'acf' ), $title );
}
$add_fields_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-field-group&use_taxonomy=' . $post_id ),
'add-fields-' . $post_id
);
$create_taxonomy_link = admin_url( 'post-new.php?post_type=acf-taxonomy' );
$duplicate_taxonomy_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-taxonomy&use_taxonomy=' . $post_id ),
'acfduplicate-' . $post_id
);
$create_post_type_link = wp_nonce_url(
admin_url( 'post-new.php?post_type=acf-post-type&use_taxonomy=' . $post_id ),
'create-post-type-' . $post_id
);
ob_start(); ?>
<p class="acf-item-saved-text"><?php echo esc_html( $item_saved_text ); ?></p>
<div class="acf-item-saved-links">
<a href="<?php echo esc_url( $add_fields_link ); ?>"><?php esc_html_e( 'Add fields', 'acf' ); ?></a>
<a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link field groups', 'acf' ); ?></a>
<a href="<?php echo esc_url( $create_taxonomy_link ); ?>"><?php esc_html_e( 'Create taxonomy', 'acf' ); ?></a>
<a href="<?php echo esc_url( $duplicate_taxonomy_link ); ?>"><?php esc_html_e( 'Duplicate taxonomy', 'acf' ); ?></a>
<a href="<?php echo esc_url( $create_post_type_link ); ?>"><?php esc_html_e( 'Create post type', 'acf' ); ?></a>
</div>
<?php
return ob_get_clean();
}
/**
* Enqueues any scripts necessary for internal post type.
*
* @since 5.0.0
*
* @return void
*/
public function admin_enqueue_scripts() {
wp_enqueue_style( 'acf-field-group' );
acf_localize_text(
array(
'Tag' => __( 'Tag', 'acf' ),
'Tags' => __( 'Tags', 'acf' ),
'Category' => __( 'Category', 'acf' ),
'Categories' => __( 'Categories', 'acf' ),
'Default' => __( 'Default', 'acf' ),
)
);
parent::admin_enqueue_scripts();
do_action( 'acf/taxonomy/admin_enqueue_scripts' );
}
/**
* Sets up all functionality for the taxonomy edit page to work.
*
* @since 3.1.8
*
* @return void
*/
public function admin_head() {
// global.
global $post, $acf_taxonomy;
// set global var.
$acf_taxonomy = acf_get_internal_post_type( $post->ID, $this->post_type );
if ( ! empty( $acf_taxonomy['not_registered'] ) ) {
acf_add_admin_notice(
__( 'This taxonomy could not be registered because its key is in use by another taxonomy registered by another plugin or theme.', 'acf' ),
'error'
);
}
// metaboxes.
add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'acf' ), array( $this, 'mb_basic_settings' ), 'acf-taxonomy', 'normal', 'high' );
add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'acf' ), array( $this, 'mb_advanced_settings' ), 'acf-taxonomy', 'normal', 'high' );
// actions.
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
// filters.
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
add_filter( 'get_user_option_screen_layout_acf-taxonomy', array( $this, 'screen_layout' ), 10, 1 );
add_filter( 'get_user_option_metaboxhidden_acf-taxonomy', array( $this, 'force_basic_settings' ), 10, 1 );
add_filter( 'get_user_option_closedpostboxes_acf-taxonomy', array( $this, 'force_basic_settings' ), 10, 1 );
add_filter( 'get_user_option_closedpostboxes_acf-taxonomy', array( $this, 'force_advanced_settings' ), 10, 1 );
// 3rd party hook.
do_action( 'acf/taxonomy/admin_head' );
}
/**
* This action will allow ACF to render metaboxes after the title.
*
* @return void
*/
public function edit_form_after_title() {
// globals.
global $post;
// render post data.
acf_form_data(
array(
'screen' => 'taxonomy',
'post_id' => $post->ID,
'delete_fields' => 0,
'validation' => 1,
)
);
}
/**
* This function will add extra HTML to the acf form data element
*
* @since 5.3.8
*
* @param array $args Arguments array to pass through to action.
* @return void
*/
public function form_data( $args ) {
do_action( 'acf/taxonomy/form_data', $args );
}
/**
* This function will append extra l10n strings to the acf JS object
*
* @since 5.3.8
*
* @param array $l10n The array of translated strings.
* @return array $l10n
*/
public function admin_l10n( $l10n ) {
return apply_filters( 'acf/taxonomy/admin_l10n', $l10n );
}
/**
* Admin footer third party hook support
*
* @since 5.3.2
*
* @return void
*/
public function admin_footer() {
do_action( 'acf/taxonomy/admin_footer' );
}
/**
* Screen settings html output
*
* @since 3.6.0
*
* @param string $html Current screen settings HTML.
* @return string $html
*/
public function screen_settings( $html ) {
return $html;
}
/**
* Sets the "Edit Field Group" screen to use a one-column layout.
*
* @param int $columns Number of columns for layout.
*
* @return int
*/
public function screen_layout( $columns = 0 ) {
return 1;
}
/**
* Force basic settings to always be visible
*
* @param array $hidden_metaboxes The metaboxes hidden on this page.
*
* @return array
*/
public function force_basic_settings( $hidden_metaboxes ) {
if ( ! is_array( $hidden_metaboxes ) ) {
return $hidden_metaboxes;
}
return array_diff( $hidden_metaboxes, array( 'acf-basic-settings' ) );
}
/**
* Force advanced settings to be visible
*
* @param array $hidden_metaboxes The metaboxes hidden on this page.
*
* @return array
*/
public function force_advanced_settings( $hidden_metaboxes ) {
if ( ! is_array( $hidden_metaboxes ) ) {
return $hidden_metaboxes;
}
return array_diff( $hidden_metaboxes, array( 'acf-advanced-settings' ) );
}
/**
* This function will customize the publish metabox
*
* @since 5.2.9
*
* @return void
*/
public function post_submitbox_misc_actions() {
global $acf_taxonomy;
$status_label = $acf_taxonomy['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
?>
<script type="text/javascript">
(function($) {
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
})(jQuery);
</script>
<?php
}
/**
* Saves taxonomy data.
*
* @since 1.0.0
*
* @param int $post_id The post ID.
* @param WP_Post $post The post object.
*
* @return int $post_id
*/
public function save_post( $post_id, $post ) {
if ( ! $this->verify_save_post( $post_id, $post ) ) {
return $post_id;
}
// Disable filters to ensure ACF loads raw data from DB.
acf_disable_filters();
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated in $this->verify_save_post() above.
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
$_POST['acf_taxonomy']['ID'] = $post_id;
$_POST['acf_taxonomy']['title'] = isset( $_POST['acf_taxonomy']['labels']['name'] ) ? $_POST['acf_taxonomy']['labels']['name'] : '';
// Save the taxonomy.
acf_update_internal_post_type( $_POST['acf_taxonomy'], $this->post_type ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Validated in verify_save_post
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
// phpcs:enable WordPress.Security.NonceVerification.Missing
return $post_id;
}
/**
* Renders HTML for the 'acf-taxonomy-fields' metabox.
*
* @since 5.0.0
*
* @return void
*/
public function mb_basic_settings() {
global $acf_taxonomy;
if ( ! acf_is_internal_post_type_key( $acf_taxonomy['key'], 'acf-taxonomy' ) ) {
$acf_taxonomy['key'] = uniqid( 'taxonomy_' );
}
acf_get_view( $this->post_type . '/basic-settings' );
}
/**
* Renders the HTML for the 'acf-taxonomy-options' metabox.
*
* @since 5.0.0
*
* @return void
*/
public function mb_advanced_settings() {
acf_get_view( $this->post_type . '/advanced-settings' );
}
}
new ACF_Admin_Taxonomy();
endif; // Class exists check.
?>

View File

@ -0,0 +1,578 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool_Export' ) ) :
class ACF_Admin_Tool_Export extends ACF_Admin_Tool {
/** @var string View context */
var $view = '';
/** @var array Export data */
var $json = '';
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
// vars
$this->name = 'export';
$this->title = __( 'Export Field Groups', 'acf' );
// active
if ( $this->is_active() ) {
$this->title .= ' - ' . __( 'Generate PHP', 'acf' );
}
}
/**
* submit
*
* This function will run when the tool's form has been submit
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit() {
// vars
$action = acf_maybe_get_POST( 'action' );
// download
if ( $action === 'download' ) {
$this->submit_download();
// generate
} elseif ( $action === 'generate' ) {
$this->submit_generate();
}
}
/**
* submit_download
*
* description
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit_download() {
// vars
$json = $this->get_selected();
// validate
if ( $json === false ) {
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
}
// headers
$file_name = 'acf-export-' . date( 'Y-m-d' ) . '.json';
header( 'Content-Description: File Transfer' );
header( "Content-Disposition: attachment; filename={$file_name}" );
header( 'Content-Type: application/json; charset=utf-8' );
// return
echo acf_json_encode( $json ) . "\r\n";
die;
}
/**
* submit_generate
*
* description
*
* @date 17/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit_generate() {
// vars
$keys = $this->get_selected_keys();
// validate
if ( ! $keys ) {
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
}
// url
$url = add_query_arg( 'keys', implode( '+', $keys ), $this->get_url() );
// redirect
wp_redirect( $url );
exit;
}
/**
* load
*
* description
*
* @date 21/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
// active
if ( $this->is_active() ) {
// get selected keys
$selected = $this->get_selected_keys();
// add notice
if ( $selected ) {
$count = count( $selected );
$text = sprintf( _n( 'Exported 1 item.', 'Exported %s items.', $count, 'acf' ), $count );
acf_add_admin_notice( $text, 'success' );
}
}
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
// single (generate PHP)
if ( $this->is_active() ) {
$this->html_single();
// archive
} else {
$this->html_archive();
}
}
/**
* Renders the checkboxes to select items to export.
*
* @date 24/10/17
* @since 5.6.3
*
* @return void
*/
public function html_field_selection() {
// Ensure `l10n_var_export` is always false at the point we're outputting the options.
acf_update_setting( 'l10n_var_export', false );
// Reset the field-groups store which may have been corrupted by export.
$store = acf_get_store( 'field-groups' );
if ( $store ) {
$store->reset();
}
$choices = array();
$selected = $this->get_selected_keys();
$field_groups = acf_get_internal_post_type_posts( 'acf-field-group' );
if ( $field_groups ) {
foreach ( $field_groups as $field_group ) {
$choices[ $field_group['key'] ] = esc_html( $field_group['title'] );
}
}
acf_render_field_wrap(
array(
'label' => __( 'Select Field Groups', 'acf' ),
'type' => 'checkbox',
'name' => 'keys',
'prefix' => false,
'value' => $selected,
'toggle' => true,
'choices' => $choices,
)
);
$choices = array();
$selected = $this->get_selected_keys();
$post_types = acf_get_internal_post_type_posts( 'acf-post-type' );
if ( $post_types ) {
foreach ( $post_types as $post_type ) {
$choices[ $post_type['key'] ] = esc_html( $post_type['title'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Select Post Types', 'acf' ),
'type' => 'checkbox',
'name' => 'post_type_keys',
'prefix' => false,
'value' => $selected,
'toggle' => true,
'choices' => $choices,
)
);
}
$choices = array();
$selected = $this->get_selected_keys();
$taxonomies = acf_get_internal_post_type_posts( 'acf-taxonomy' );
if ( $taxonomies ) {
foreach ( $taxonomies as $taxonomy ) {
$choices[ $taxonomy['key'] ] = esc_html( $taxonomy['title'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Select Taxonomies', 'acf' ),
'type' => 'checkbox',
'name' => 'taxonomy_keys',
'prefix' => false,
'value' => $selected,
'toggle' => true,
'choices' => $choices,
)
);
}
$choices = array();
$selected = $this->get_selected_keys();
$options_pages = acf_get_internal_post_type_posts( 'acf-ui-options-page' );
if ( $options_pages ) {
foreach ( $options_pages as $options_page ) {
$choices[ $options_page['key'] ] = esc_html( $options_page['title'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Select Options Pages', 'acf' ),
'type' => 'checkbox',
'name' => 'ui_options_page_keys',
'prefix' => false,
'value' => $selected,
'toggle' => true,
'choices' => $choices,
)
);
}
}
/**
* Renders the side panel for selecting ACF items to export via PHP.
*
* @date 21/10/17
* @since 5.6.3
*
* @return void
*/
public function html_panel_selection() {
?>
<div class="acf-panel acf-panel-selection">
<?php $this->html_field_selection(); ?>
</div>
<?php
}
/**
* html_panel_settings
*
* description
*
* @date 21/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_panel_settings() {
?>
<div class="acf-panel acf-panel-settings">
<h3 class="acf-panel-title"><?php _e( 'Settings', 'acf' ); ?> <i class="dashicons dashicons-arrow-right"></i></h3>
<div class="acf-panel-inside">
<?php
/*
acf_render_field_wrap(array(
'label' => __('Empty settings', 'acf'),
'type' => 'select',
'name' => 'minimal',
'prefix' => false,
'value' => '',
'choices' => array(
'all' => __('Include all settings', 'acf'),
'minimal' => __('Ignore empty settings', 'acf'),
)
));
*/
?>
</div>
</div>
<?php
}
/**
* html_archive
*
* description
*
* @date 20/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html_archive() {
?>
<div class="acf-postbox-header">
<h2 class="acf-postbox-title"><?php esc_html_e( 'Export', 'acf' ); ?></h2>
<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>
</div>
<div class="acf-postbox-inner">
<div class="acf-fields">
<?php $this->html_field_selection(); ?>
</div>
<p class="acf-submit acf-actions-strip">
<button type="submit" name="action" class="acf-btn acf-button-primary" value="download"><?php _e( 'Export As JSON', 'acf' ); ?></button>
<button type="submit" name="action" class="acf-btn acf-btn-secondary" value="generate"><?php _e( 'Generate PHP', 'acf' ); ?></button>
</p>
</div>
<?php
}
/**
* Renders the PHP export screen.
*
* @date 20/10/17
* @since 5.6.3
*
* @return void
*/
public function html_single() {
?>
<div class="acf-postbox-header">
<h2 class="acf-postbox-title"><?php esc_html_e( 'Export - Generate PHP', 'acf' ); ?></h2>
<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>
</div>
<div class="acf-postbox-columns">
<div class="acf-postbox-main">
<?php $this->html_generate(); ?>
</div>
<div class="acf-postbox-side">
<?php $this->html_panel_selection(); ?>
<p class="acf-submit">
<button type="submit" name="action" class="acf-btn" value="generate"><?php esc_html_e( 'Generate PHP', 'acf' ); ?></button>
</p>
</div>
</div>
<?php
}
/**
* Generates the HTML for the PHP export functionality.
*
* @date 17/10/17
* @since 5.6.3
*
* @return void
*/
public function html_generate() {
// Prevent default translation and fake __() within string.
acf_update_setting( 'l10n_var_export', true );
$json = $this->get_selected();
$to_export = array();
// Sort by ACF post type first so we can wrap them in related functions.
foreach ( $json as $post ) {
$post_type = acf_determine_internal_post_type( $post['key'] );
if ( $post_type ) {
$to_export[ $post_type ][] = $post;
}
}
echo '<textarea id="acf-export-textarea" readonly="readonly">';
foreach ( $to_export as $post_type => $posts ) {
if ( 'acf-field-group' === $post_type ) {
echo "add_action( 'acf/include_fields', function() {\r\n";
echo "\tif ( ! function_exists( 'acf_add_local_field_group' ) ) {\r\n\t\treturn;\r\n\t}\r\n\r\n";
} elseif ( 'acf-post-type' === $post_type || 'acf-taxonomy' === $post_type ) {
echo "add_action( 'init', function() {\r\n";
} elseif ( 'acf-ui-options-page' === $post_type ) {
echo "add_action( 'acf/init', function() {\r\n";
}
$count = 0;
foreach ( $posts as $post ) {
if ( $count !== 0 ) {
echo "\r\n";
}
echo "\t" . acf_export_internal_post_type_as_php( $post, $post_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc_textarea() used earlier.
++$count;
}
if ( in_array( $post_type, array( 'acf-post-type', 'acf-taxonomy', 'acf-field-group', 'acf-ui-options-page' ), true ) ) {
echo "} );\r\n\r\n";
}
if ( 'acf-post-type' === $post_type ) {
echo acf_export_enter_title_here( $posts ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc_textarea() used earlier.
}
}
echo '</textarea>';
?>
<p class="acf-submit">
<a class="button" id="acf-export-copy"><?php _e( 'Copy to clipboard', 'acf' ); ?></a>
</p>
<script type="text/javascript">
(function($){
const $a = $('#acf-export-copy');
const $textarea = $('#acf-export-textarea');
// Remove $a if 'copy' is not supported.
if( !document.queryCommandSupported('copy') ) {
return $a.remove();
}
$a.on('click', function( e ){
e.preventDefault();
$textarea.get(0).select();
try {
var copy = document.execCommand('copy');
if ( ! copy ) {
return;
}
acf.newTooltip({
text: "<?php esc_html_e( 'Copied', 'acf' ); ?>",
timeout: 250,
target: $(this),
});
} catch (err) {
// Do nothing.
}
});
})(jQuery);
</script>
<?php
}
/**
* Return an array of keys that have been selected in the export tool.
*
* @date 20/10/17
* @since 5.6.3
*
* @return array|bool
*/
public function get_selected_keys() {
$key_names = array( 'keys', 'taxonomy_keys', 'post_type_keys', 'ui_options_page_keys' );
$all_keys = array();
foreach ( $key_names as $key_name ) {
if ( $keys = acf_maybe_get_POST( $key_name ) ) {
$all_keys = array_merge( $all_keys, (array) $keys );
} elseif ( $keys = acf_maybe_get_GET( $key_name ) ) {
$keys = str_replace( ' ', '+', $keys );
$keys = explode( '+', $keys );
$all_keys = array_merge( $all_keys, (array) $keys );
}
}
if ( ! empty( $all_keys ) ) {
return $all_keys;
}
return false;
}
/**
* Returns the JSON data for given $_POST args.
*
* @date 17/10/17
* @since 5.6.3
*
* @return array|bool
*/
public function get_selected() {
$selected = $this->get_selected_keys();
$json = array();
if ( ! $selected ) {
return false;
}
foreach ( $selected as $key ) {
$post_type = acf_determine_internal_post_type( $key );
$post = acf_get_internal_post_type( $key, $post_type );
if ( empty( $post ) ) {
continue;
}
if ( 'acf-field-group' === $post_type ) {
$post['fields'] = acf_get_fields( $post );
}
$post = acf_prepare_internal_post_type_for_export( $post, $post_type );
$json[] = $post;
}
return $json;
}
}
// initialize
acf_register_admin_tool( 'ACF_Admin_Tool_Export' );
endif; // class_exists check
?>

View File

@ -0,0 +1,298 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool_Import' ) ) :
class ACF_Admin_Tool_Import extends ACF_Admin_Tool {
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
// vars
$this->name = 'import';
$this->title = __( 'Import Field Groups', 'acf' );
$this->icon = 'dashicons-upload';
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
?>
<div class="acf-postbox-header">
<h2 class="acf-postbox-title"><?php esc_html_e( 'Import', 'acf' ); ?></h2>
<div class="acf-tip"><i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Select the Advanced Custom Fields JSON file you would like to import. When you click the import button below, ACF will import the items in that file.', 'acf' ); ?>">?</i></div>
</div>
<div class="acf-postbox-inner">
<div class="acf-fields">
<?php
acf_render_field_wrap(
array(
'label' => __( 'Select File', 'acf' ),
'type' => 'file',
'name' => 'acf_import_file',
'value' => false,
'uploader' => 'basic',
)
);
?>
</div>
<p class="acf-submit">
<button type="submit" class="acf-btn" name="import_type" value="json">
<?php esc_html_e( 'Import JSON', 'acf' ); ?>
</button>
</p>
<?php
if ( is_plugin_active( 'custom-post-type-ui/custom-post-type-ui.php' ) && acf_get_setting( 'enable_post_types' ) ) {
$cptui_post_types = get_option( 'cptui_post_types' );
$cptui_taxonomies = get_option( 'cptui_taxonomies' );
$choices = array();
$overwrite_warning = false;
if ( $cptui_post_types ) {
$choices['post_types'] = __( 'Post Types', 'acf' );
$existing_post_types = acf_get_acf_post_types();
foreach ( $existing_post_types as $existing_post_type ) {
if ( isset( $cptui_post_types[ $existing_post_type['post_type'] ] ) ) {
$overwrite_warning = true;
}
}
}
if ( $cptui_taxonomies ) {
$choices['taxonomies'] = __( 'Taxonomies', 'acf' );
if ( ! $overwrite_warning ) {
$existing_taxonomies = acf_get_acf_taxonomies();
foreach ( $existing_taxonomies as $existing_taxonomy ) {
if ( isset( $cptui_taxonomies[ $existing_taxonomy['taxonomy'] ] ) ) {
$overwrite_warning = true;
}
}
}
}
if ( ! empty( $choices ) ) :
?>
<div class="acf-fields import-cptui">
<?php
acf_render_field_wrap(
array(
'label' => __( 'Import from Custom Post Type UI', 'acf' ),
'type' => 'checkbox',
'name' => 'acf_import_cptui',
'choices' => $choices,
'toggle' => true,
)
);
?>
</div>
<?php
if ( $overwrite_warning ) {
echo '<p class="acf-inline-notice notice notice-info">' . esc_html__( 'Importing a Post Type or Taxonomy with the same key as one that already exists will overwrite the settings for the existing Post Type or Taxonomy with those of the import.', 'acf' ) . '</p>';
}
?>
<p class="acf-submit">
<button type="submit" class="acf-btn" name="import_type" value="cptui">
<?php esc_html_e( 'Import from Custom Post Type UI', 'acf' ); ?>
</button>
</p>
<?php
endif;
}
?>
</div>
<?php
}
/**
* Imports the selected ACF posts and returns an admin notice on completion.
*
* @date 10/10/17
* @since 5.6.3
*
* @return ACF_Admin_Notice
*/
public function submit() {
//phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce verified before this function is called.
if ( 'cptui' === acf_request_arg( 'import_type', '' ) ) {
$import = acf_sanitize_request_args( $_POST['acf_import_cptui'] );
return $this->import_cpt_ui( $import );
}
// Check file size.
if ( empty( $_FILES['acf_import_file']['size'] ) ) {
return acf_add_admin_notice( __( 'No file selected', 'acf' ), 'warning' );
}
$file = acf_sanitize_files_array( $_FILES['acf_import_file'] );
// Check errors.
if ( $file['error'] ) {
return acf_add_admin_notice( __( 'Error uploading file. Please try again', 'acf' ), 'warning' );
}
// Check file type.
if ( pathinfo( $file['name'], PATHINFO_EXTENSION ) !== 'json' ) {
return acf_add_admin_notice( __( 'Incorrect file type', 'acf' ), 'warning' );
}
// Read JSON.
$json = file_get_contents( $file['tmp_name'] );
$json = json_decode( $json, true );
// Check if empty.
if ( ! $json || ! is_array( $json ) ) {
return acf_add_admin_notice( __( 'Import file empty', 'acf' ), 'warning' );
}
// Ensure $json is an array of posts.
if ( isset( $json['key'] ) ) {
$json = array( $json );
}
// Remember imported post ids.
$ids = array();
// Loop over json.
foreach ( $json as $to_import ) {
// Search database for existing post.
$post_type = acf_determine_internal_post_type( $to_import['key'] );
$post = acf_get_internal_post_type_post( $to_import['key'], $post_type );
if ( $post ) {
$to_import['ID'] = $post->ID;
}
// Import the post.
$to_import = acf_import_internal_post_type( $to_import, $post_type );
// Append message.
$ids[] = $to_import['ID'];
}
// Count number of imported posts.
$total = count( $ids );
// Generate text.
$text = sprintf( _n( 'Imported 1 item', 'Imported %s items', $total, 'acf' ), $total );
// Add links to text.
$links = array();
foreach ( $ids as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
// Add notice.
return acf_add_admin_notice( $text, 'success' );
//phpcs:enable WordPress.Security.NonceVerification.Missing
}
/**
* Handles the import of CPTUI post types and taxonomies.
*
* @since 6.1
*
* @param array $import_args What to import.
* @return ACF_Admin_Notice
*/
public function import_cpt_ui( $import_args ) {
if ( ! is_array( $import_args ) ) {
return acf_add_admin_notice( __( 'Nothing from Custom Post Type UI plugin selected for import.', 'acf' ), 'warning' );
}
$imported = array();
// Import any post types.
if ( in_array( 'post_types', $import_args, true ) ) {
$cptui_post_types = get_option( 'cptui_post_types' );
$instance = acf_get_internal_post_type_instance( 'acf-post-type' );
if ( ! is_array( $cptui_post_types ) || ! $instance ) {
return acf_add_admin_notice( __( 'Failed to import post types.', 'acf' ), 'warning' );
}
foreach ( $cptui_post_types as $post_type ) {
$result = $instance->import_cptui_post_type( $post_type );
if ( is_array( $result ) && isset( $result['ID'] ) ) {
$imported[] = (int) $result['ID'];
}
}
}
// Import any taxonomies.
if ( in_array( 'taxonomies', $import_args, true ) ) {
$cptui_taxonomies = get_option( 'cptui_taxonomies' );
$instance = acf_get_internal_post_type_instance( 'acf-taxonomy' );
if ( ! is_array( $cptui_taxonomies ) || ! $instance ) {
return acf_add_admin_notice( __( 'Failed to import taxonomies.', 'acf' ), 'warning' );
}
foreach ( $cptui_taxonomies as $taxonomy ) {
$result = $instance->import_cptui_taxonomy( $taxonomy );
if ( is_array( $result ) && isset( $result['ID'] ) ) {
$imported[] = (int) $result['ID'];
}
}
}
if ( ! empty( $imported ) ) {
// Generate text.
$total = count( $imported );
/* translators: %d - number of items imported from CPTUI */
$text = sprintf( _n( 'Imported %d item from Custom Post Type UI -', 'Imported %d items from Custom Post Type UI -', $total, 'acf' ), $total );
// Add links to text.
$links = array();
foreach ( $imported as $id ) {
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
}
$text .= ' ' . implode( ', ', $links );
$text .= __( '. The Custom Post Type UI plugin can be deactivated.', 'acf' );
return acf_add_admin_notice( $text, 'success' );
}
return acf_add_admin_notice( __( 'Nothing to import', 'acf' ), 'warning' );
}
}
// Initialize.
acf_register_admin_tool( 'ACF_Admin_Tool_Import' );
endif; // class_exists check.
?>

View File

@ -0,0 +1,185 @@
<?php
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
if ( ! class_exists( 'ACF_Admin_Tool' ) ) :
class ACF_Admin_Tool {
/** @var string Tool name */
var $name = '';
/** @var string Tool title */
var $title = '';
/** @var string Dashicon slug */
var $icon = '';
/** @var boolean Redirect form to single */
// var $redirect = false;
/**
* get_name
*
* This function will return the Tool's name
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_name() {
return $this->name;
}
/**
* get_title
*
* This function will return the Tool's title
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_title() {
return $this->title;
}
/**
* get_url
*
* This function will return the Tool's title
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function get_url() {
return acf_get_admin_tool_url( $this->name );
}
/**
* is_active
*
* This function will return true if the tool is active
*
* @date 19/10/17
* @since 5.6.3
*
* @param n/a
* @return bool
*/
function is_active() {
return acf_maybe_get_GET( 'tool' ) === $this->name;
}
/*
* __construct
*
* This function will setup the class functionality
*
* @type function
* @date 27/6/17
* @since 5.6.0
*
* @param n/a
* @return n/a
*/
function __construct() {
// initialize
$this->initialize();
}
/**
* initialize
*
* This function will initialize the admin tool
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function initialize() {
/* do nothing */
}
/**
* load
*
* This function is called during the admin page load
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function load() {
/* do nothing */
}
/**
* html
*
* This function will output the metabox HTML
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function html() {
}
/**
* submit
*
* This function will run when the tool's form has been submit
*
* @date 10/10/17
* @since 5.6.3
*
* @param n/a
* @return n/a
*/
function submit() {
}
}
endif; // class_exists check

View File

@ -0,0 +1,178 @@
<?php
// vars
$disabled = false;
// empty
if ( empty( $field['conditional_logic'] ) ) {
$disabled = true;
$field['conditional_logic'] = array(
// group 0
array(
// rule 0
array(),
),
);
}
?>
<div class="acf-field acf-field-true-false acf-field-setting-conditional_logic" data-type="true_false" data-name="conditional_logic">
<div class="acf-conditional-toggle">
<div class="acf-label">
<?php $acf_label_for = acf_idify( $field['prefix'] . '[conditional_logic]' ); ?>
<label for="<?php echo esc_attr( $acf_label_for ); ?>"><?php _e( 'Conditional Logic', 'acf' ); ?></label>
</div>
<div class="acf-input">
<?php
acf_render_field(
array(
'type' => 'true_false',
'name' => 'conditional_logic',
'prefix' => $field['prefix'],
'value' => $disabled ? 0 : 1,
'ui' => 1,
'class' => 'conditions-toggle',
)
);
?>
</div>
</div>
<div class="rule-groups"
<?php
if ( $disabled ) {
echo ' style="display:none"';
}
?>
>
<?php
foreach ( $field['conditional_logic'] as $group_id => $group ) :
// validate
if ( empty( $group ) ) {
continue;
}
// vars
// $group_id must be completely different to $rule_id to avoid JS issues
$group_id = "group_{$group_id}";
$h4 = ( $group_id == 'group_0' ) ? __( 'Show this field if', 'acf' ) : __( 'or', 'acf' );
?>
<div class="rule-group" data-id="<?php echo $group_id; ?>">
<h4><?php echo $h4; ?></h4>
<table class="acf-table -clear">
<tbody>
<?php
foreach ( $group as $rule_id => $rule ) :
// valid rule
$rule = wp_parse_args(
$rule,
array(
'field' => '',
'operator' => '',
'value' => '',
)
);
// vars
// $group_id must be completely different to $rule_id to avoid JS issues
$rule_id = "rule_{$rule_id}";
$prefix = "{$field['prefix']}[conditional_logic][{$group_id}][{$rule_id}]";
// data attributes
$attributes = array(
'data-id' => $rule_id,
'data-field' => $rule['field'],
'data-operator' => $rule['operator'],
'data-value' => $rule['value'],
);
?>
<tr class="rule" <?php echo acf_esc_attrs( $attributes ); ?>>
<td class="param">
<?php
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'field',
'class' => 'condition-rule-field',
'disabled' => $disabled,
'value' => $rule['field'],
'choices' => array(
$rule['field'] => $rule['field'],
),
)
);
?>
</td>
<td class="operator">
<?php
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'operator',
'class' => 'condition-rule-operator',
'disabled' => $disabled,
'value' => $rule['operator'],
'choices' => array(
$rule['operator'] => $rule['operator'],
),
)
);
?>
</td>
<td class="value">
<?php
// create field
acf_render_field(
array(
'type' => 'select',
'prefix' => $prefix,
'name' => 'value',
'class' => 'condition-rule-value',
'disabled' => $disabled,
'value' => $rule['value'],
'choices' => array(
$rule['value'] => $rule['value'],
),
)
);
?>
</td>
<td class="add">
<a href="#" class="button add-conditional-rule"><?php _e( 'and', 'acf' ); ?></a>
</td>
<td class="remove">
<a href="#" class="acf-icon -minus remove-conditional-rule"></a>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<?php endforeach; ?>
<h4><?php _e( 'or', 'acf' ); ?></h4>
<a href="#" class="button add-conditional-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
</div>
</div>

View File

@ -0,0 +1,328 @@
<?php
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
// Define input name prefix using unique identifier.
$input_prefix = 'acf_fields[' . $field['ID'] . ']';
$input_id = acf_idify( $input_prefix );
// Update field props.
$field['prefix'] = $input_prefix;
// Elements.
$div_attrs = array(
'class' => 'acf-field-object acf-field-object-' . acf_slugify( $field['type'] ),
'data-id' => $field['ID'],
'data-key' => $field['key'],
'data-type' => $field['type'],
);
// Add additional class if the field is an endpoint.
if ( isset( $field['endpoint'] ) && $field['endpoint'] ) {
$div_attrs['class'] .= ' acf-field-is-endpoint';
}
// Misc template vars.
$field_label = acf_get_field_label( $field, 'admin' );
$field_type_label = acf_get_field_type_label( $field['type'] );
if ( acf_is_pro() && acf_get_field_type_prop( $field['type'], 'pro' ) && ! acf_pro_is_license_active() ) {
$field_type_label .= '<span class="acf-pro-label acf-pro-label-field-type">PRO</span>';
}
if ( ! isset( $num_field_groups ) ) {
$num_field_groups = 0;
}
$conditional_logic_class = $conditional_logic_text = '';
if ( isset( $field['conditional_logic'] ) && is_array( $field['conditional_logic'] ) && count( $field['conditional_logic'] ) > 0 ) {
$conditional_logic_class = ' is-enabled';
$conditional_logic_text = __( 'Active', 'acf' );
}
?>
<div <?php echo acf_esc_attrs( $div_attrs ); ?>>
<div class="meta">
<?php
$meta_inputs = array(
'ID' => $field['ID'],
'key' => $field['key'],
'parent' => $field['parent'],
'menu_order' => $i,
'save' => '',
);
foreach ( $meta_inputs as $k => $v ) :
acf_hidden_input(
array(
'name' => $input_prefix . '[' . $k . ']',
'value' => $v,
'id' => $input_id . '-' . $k,
)
);
endforeach;
?>
</div>
<div class="handle">
<ul class="acf-hl acf-tbody">
<li class="li-field-order">
<span class="acf-icon acf-sortable-handle" title="<?php _e( 'Drag to reorder', 'acf' ); ?>"><?php echo ( $i + 1 ); ?></span>
</li>
<li class="li-field-label">
<strong>
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php echo acf_esc_html( $field_label ); ?></a>
</strong>
<div class="row-options">
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php _e( 'Edit', 'acf' ); ?></a>
<a class="duplicate-field" title="<?php _e( 'Duplicate field', 'acf' ); ?>" href="#"><?php _e( 'Duplicate', 'acf' ); ?></a>
<?php if ( $num_field_groups > 1 ) : ?>
<a class="move-field" title="<?php _e( 'Move field to another group', 'acf' ); ?>" href="#"><?php _e( 'Move', 'acf' ); ?></a>
<?php endif; ?>
<a class="delete-field" title="<?php _e( 'Delete field', 'acf' ); ?>" href="#"><?php _e( 'Delete', 'acf' ); ?></a>
</div>
</li>
<li class="li-field-name"><span class="copyable"><?php echo esc_html( $field['name'] ); ?></span></li>
<li class="li-field-key"><span class="copyable"><?php echo esc_html( $field['key'] ); ?></span></li>
<li class="li-field-type">
<i class="field-type-icon field-type-icon-<?php echo acf_slugify( $field['type'] ); ?>"></i>
<span class="field-type-label">
<?php echo acf_esc_html( $field_type_label ); ?>
</span>
</li>
</ul>
</div>
<div class="settings">
<div class="acf-field-editor">
<div class="acf-field-settings acf-fields">
<?php
foreach ( acf_get_combined_field_type_settings_tabs() as $tab_key => $tab_label ) {
$field_to_render = array(
'type' => 'tab',
'label' => $tab_label,
'key' => 'acf_field_settings_tabs',
'settings-type' => $tab_key,
);
if ( $tab_key === 'conditional_logic' ) {
$field_to_render['label'] = __( 'Conditional Logic', 'acf' ) . '<i class="conditional-logic-badge' . $conditional_logic_class . '">' . $conditional_logic_text . '</i>';
}
acf_render_field_wrap( $field_to_render );
?>
<?php
$wrapper_class = str_replace( '_', '-', $tab_key );
?>
<div class="acf-field-settings-main acf-field-settings-main-<?php echo esc_attr( $wrapper_class ); ?>">
<?php
switch ( $tab_key ) {
case 'general':
$field_type_select_class = 'field-type';
if ( ! apply_filters( 'acf/field_group/enable_field_type_select2', true ) ) {
$field_type_select_class .= ' disable-select2';
}
// type
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Type', 'acf' ),
'instructions' => '',
'type' => 'select',
'name' => 'type',
'choices' => acf_get_grouped_field_types(),
'class' => $field_type_select_class,
),
true
);
if ( apply_filters( 'acf/field_group/enable_field_browser', true ) ) {
?>
<div class="acf-field acf-field-setting-browse-fields" data-append="type">
<div class="acf-input">
<button class="acf-btn browse-fields">
<i class="acf-icon acf-icon-dots-grid"></i>
<?php _e( 'Browse Fields', 'acf' ); ?>
</button>
</div>
</div>
<?php
}
// label
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Label', 'acf' ),
'instructions' => __( 'This is the name which will appear on the EDIT page', 'acf' ),
'name' => 'label',
'type' => 'text',
'class' => 'field-label',
),
true
);
// name
acf_render_field_setting(
$field,
array(
'label' => __( 'Field Name', 'acf' ),
'instructions' => __( 'Single word, no spaces. Underscores and dashes allowed', 'acf' ),
'name' => 'name',
'type' => 'text',
'class' => 'field-name',
),
true
);
// 3rd party settings
do_action( 'acf/render_field_settings', $field );
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
?>
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
<?php
do_action( "acf/render_field_settings/type={$field['type']}", $field );
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
?>
</div>
<?php
break;
case 'validation':
// required
acf_render_field_setting(
$field,
array(
'label' => __( 'Required', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'required',
'ui' => 1,
'class' => 'field-required',
),
true
);
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
?>
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
<?php
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
?>
</div>
<?php
break;
case 'presentation':
acf_render_field_setting(
$field,
array(
'label' => __( 'Instructions', 'acf' ),
'instructions' => __( 'Instructions for authors. Shown when submitting data', 'acf' ),
'type' => 'textarea',
'name' => 'instructions',
'rows' => 5,
),
true
);
acf_render_field_wrap(
array(
'label' => '',
'instructions' => '',
'type' => 'text',
'name' => 'class',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['class'],
'prepend' => __( 'class', 'acf' ),
'wrapper' => array(
'data-append' => 'wrapper',
),
),
'div'
);
acf_render_field_wrap(
array(
'label' => '',
'instructions' => '',
'type' => 'text',
'name' => 'id',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['id'],
'prepend' => __( 'id', 'acf' ),
'wrapper' => array(
'data-append' => 'wrapper',
),
),
'div'
);
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
?>
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
<?php
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
?>
</div>
<?php
acf_render_field_wrap(
array(
'label' => __( 'Wrapper Attributes', 'acf' ),
'instructions' => '',
'type' => 'number',
'name' => 'width',
'prefix' => $field['prefix'] . '[wrapper]',
'value' => $field['wrapper']['width'],
'prepend' => __( 'width', 'acf' ),
'append' => '%',
'wrapper' => array(
'data-name' => 'wrapper',
'class' => 'acf-field-setting-wrapper',
),
),
'div'
);
break;
case 'conditional_logic':
acf_get_view( 'acf-field-group/conditional-logic', array( 'field' => $field ) );
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
?>
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
<?php
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
?>
</div>
<?php
break;
default:
// Global action hook for custom tabs.
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
?>
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
<?php
// Type-specific action hook for custom tabs.
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
?>
</div>
<?php
}
?>
</div>
<?php
}
?>
<div class="acf-field-settings-footer">
<a class="button close-field edit-field" title="<?php _e( 'Close Field', 'acf' ); ?>" href="#"><?php _e( 'Close Field', 'acf' ); ?></a>
</div>
</div>
</div>
</div>
</div>

View File

@ -0,0 +1,135 @@
<?php
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- template include file
$field_groups = acf_get_field_groups();
$num_field_groups = 0;
if ( is_array( $field_groups ) ) {
$num_field_groups = count( $field_groups );
}
$is_subfield = ! empty( $is_subfield );
$wrapper_class = '';
if ( $is_subfield ) {
$wrapper_class = ' acf-is-subfields';
if ( ! $fields ) {
$wrapper_class .= ' -empty';
}
} elseif ( ! $fields && ! $parent ) {
/**
* Filter for determining if a new field group should render with a text field automatically
*
* @since 6.2
*
* @param bool $bool If an empty field group should render with a new field auto appended.
*/
if ( apply_filters( 'acf/field_group/auto_add_first_field', true ) ) {
$wrapper_class = ' acf-auto-add-field';
} else {
$wrapper_class = ' -empty';
}
}
?>
<?php if ( $parent || $is_subfield ) { ?>
<div class="acf-sub-field-list-header">
<h3 class="acf-sub-field-list-title"><?php _e( 'Fields', 'acf' ); ?></h3>
<a href="#" class="acf-btn acf-btn-secondary add-field"><i class="acf-icon acf-icon-plus"></i><?php _e( 'Add Field', 'acf' ); ?></a>
</div>
<?php } ?>
<?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- fixed string output ?>
<div class="acf-field-list-wrap<?php echo $wrapper_class; ?>">
<ul class="acf-hl acf-thead">
<li class="li-field-order">
<?php
/* translators: A symbol (or text, if not available in your locale) meaning "Order Number", in terms of positional placement. */
_e( '#', 'acf' );
?>
<span class="acf-hidden">
<?php
/* translators: Hidden accessibility text for the positional order number of the field. */
_e( 'Order', 'acf' );
?>
</span>
</li>
<li class="li-field-label"><?php _e( 'Label', 'acf' ); ?></li>
<li class="li-field-name"><?php _e( 'Name', 'acf' ); ?></li>
<li class="li-field-key"><?php _e( 'Key', 'acf' ); ?></li>
<li class="li-field-type"><?php _e( 'Type', 'acf' ); ?></li>
</ul>
<?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- fixed string output ?>
<div class="acf-field-list<?php echo $wrapper_class; ?>">
<div class="no-fields-message">
<div class="no-fields-message-inner">
<img src="<?php echo acf_get_url( 'assets/images/empty-group.svg' ); ?>" />
<h2><?php _e( 'Add Your First Field', 'acf' ); ?></h2>
<p><?php _e( 'Get started creating new custom fields for your posts, pages, custom post types and other WordPress content.', 'acf' ); ?></p>
<a href="#" class="acf-btn acf-btn-primary add-field add-first-field
"><i class="acf-icon acf-icon-plus"></i> <?php _e( 'Add Field', 'acf' ); ?></a>
<p class="acf-small">
<?php
printf(
/* translators: %s url to field types list */
__( 'Choose from over 30 field types. <a href="%s" target="_blank">Learn more</a>.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/', 'docs', 'empty-field-group', 'field-types' )
);
?>
</p>
</div>
</div>
<?php
if ( $fields ) :
foreach ( $fields as $i => $field ) :
acf_get_view(
'acf-field-group/field',
array(
'field' => $field,
'i' => $i,
'num_field_groups' => $num_field_groups,
)
);
endforeach;
endif;
?>
</div>
<ul class="acf-hl acf-tfoot">
<li class="acf-fr">
<a href="#" class="acf-btn acf-btn-secondary add-field"><i class="acf-icon acf-icon-plus"></i><?php _e( 'Add Field', 'acf' ); ?></a>
</li>
</ul>
<?php
if ( ! $parent ) :
// get clone
$clone = acf_get_valid_field(
array(
'ID' => 'acfcloneindex',
'key' => 'acfcloneindex',
'label' => __( 'New Field', 'acf' ),
'name' => 'new_field',
'type' => 'text',
)
);
?>
<script type="text/html" id="tmpl-acf-field">
<?php
acf_get_view(
'acf-field-group/field',
array(
'field' => $clone,
'i' => 0,
'num_field_groups' => $num_field_groups,
)
);
?>
</script>
<script type="text/html" id="tmpl-acf-browse-fields-modal">
<?php acf_get_view( 'browse-fields-modal' ); ?>
</script>
<?php endif; ?>
</div>

View File

@ -0,0 +1,26 @@
<script>document.body.classList.add('acf-no-field-groups');</script>
<div class="acf-no-field-groups-wrapper">
<div class="acf-no-field-groups-inner">
<img src="<?php echo acf_get_url( 'assets/images/empty-group.svg' ); ?>" />
<h2><?php _e( 'Add Your First Field Group', 'acf' ); ?></h2>
<p>
<?php
printf(
/* translators: %s url to creating a field group page */
__( 'ACF uses <a href="%s" target="_blank">field groups</a> to group custom fields together, and then attach those fields to edit screens.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/creating-a-field-group/', 'docs', 'no-field-groups' )
);
?>
</p>
<a href="<?php echo admin_url( 'post-new.php?post_type=acf-field-group' ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php _e( 'Add Field Group', 'acf' ); ?></a>
<p class="acf-small">
<?php
printf(
/* translators: %s url to getting started guide */
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-field-groups' )
);
?>
</p>
</div>
</div>

View File

@ -0,0 +1,29 @@
<div class="rule-group" data-id="<?php echo $group_id; ?>">
<h4><?php echo ( $group_id == 'group_0' ) ? __( 'Show this field group if', 'acf' ) : __( 'or', 'acf' ); ?></h4>
<table class="acf-table -clear">
<tbody>
<?php
foreach ( $group as $i => $rule ) :
// validate rule
$rule = acf_validate_location_rule( $rule );
// append id and group
$rule['id'] = "rule_{$i}";
$rule['group'] = $group_id;
// view
acf_get_view(
'acf-field-group/location-rule',
array(
'rule' => $rule,
)
);
endforeach;
?>
</tbody>
</table>
</div>

View File

@ -0,0 +1,89 @@
<?php
// vars
$prefix = 'acf_field_group[location][' . $rule['group'] . '][' . $rule['id'] . ']';
?>
<tr data-id="<?php echo $rule['id']; ?>">
<td class="param">
<?php
// vars
$choices = acf_get_location_rule_types();
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'param',
'prefix' => $prefix,
'value' => $rule['param'],
'choices' => $choices,
'class' => 'refresh-location-rule',
)
);
}
?>
</td>
<td class="operator">
<?php
// vars
$choices = acf_get_location_rule_operators( $rule );
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'operator',
'prefix' => $prefix,
'value' => $rule['operator'],
'choices' => $choices,
)
);
// custom
} else {
echo $choices;
}
?>
</td>
<td class="value">
<?php
// vars
$choices = acf_get_location_rule_values( $rule );
// array
if ( is_array( $choices ) ) {
acf_render_field(
array(
'type' => 'select',
'name' => 'value',
'class' => 'location-rule-value',
'prefix' => $prefix,
'value' => $rule['value'],
'choices' => $choices,
)
);
// custom
} else {
echo $choices;
}
?>
</td>
<td class="add">
<a href="#" class="button add-location-rule"><?php _e( 'and', 'acf' ); ?></a>
</td>
<td class="remove">
<a href="#" class="acf-icon -minus remove-location-rule"></a>
</td>
</tr>

View File

@ -0,0 +1,51 @@
<?php
// global
global $field_group;
?>
<div class="acf-field">
<div class="acf-label">
<label><?php _e( 'Rules', 'acf' ); ?></label>
<i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Create a set of rules to determine which edit screens will use these advanced custom fields', 'acf' ); ?>">?</i>
</div>
<div class="acf-input">
<div class="rule-groups">
<?php
foreach ( $field_group['location'] as $i => $group ) :
// bail early if no group
if ( empty( $group ) ) {
return;
}
// view
acf_get_view(
'acf-field-group/location-group',
array(
'group' => $group,
'group_id' => "group_{$i}",
)
);
endforeach;
?>
<h4><?php _e( 'or', 'acf' ); ?></h4>
<a href="#" class="button add-location-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
</div>
</div>
</div>
<script type="text/javascript">
if( typeof acf !== 'undefined' ) {
acf.newPostbox({
'id': 'acf-field-group-locations',
'label': 'left'
});
}
</script>

View File

@ -0,0 +1,297 @@
<?php
// global
global $field_group;
// UI needs at lease 1 location rule
if ( empty( $field_group['location'] ) ) {
$field_group['location'] = array(
// Group 0.
array(
// Rule 0.
array(
'param' => 'post_type',
'operator' => '==',
'value' => 'post',
),
),
);
$acf_use_post_type = acf_get_post_type_from_request_args( 'add-fields' );
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'add-fields' );
$acf_use_options_page = acf_get_ui_options_page_from_request_args( 'add-fields' );
if ( $acf_use_post_type && ! empty( $acf_use_post_type['post_type'] ) ) {
$field_group['location'] = array(
array(
array(
'param' => 'post_type',
'operator' => '==',
'value' => $acf_use_post_type['post_type'],
),
),
);
}
if ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['taxonomy'] ) ) {
$field_group['location'] = array(
array(
array(
'param' => 'taxonomy',
'operator' => '==',
'value' => $acf_use_taxonomy['taxonomy'],
),
),
);
}
if ( $acf_use_options_page && ! empty( $acf_use_options_page['menu_slug'] ) ) {
$field_group['location'] = array(
array(
array(
'param' => 'options_page',
'operator' => '==',
'value' => $acf_use_options_page['menu_slug'],
),
),
);
}
}
foreach ( acf_get_combined_field_group_settings_tabs() as $tab_key => $tab_label ) {
acf_render_field_wrap(
array(
'type' => 'tab',
'label' => $tab_label,
'key' => 'acf_field_group_settings_tabs',
'settings-type' => $tab_key,
)
);
switch ( $tab_key ) {
case 'location_rules':
echo '<div class="field-group-locations field-group-settings-tab">';
acf_get_view( 'acf-field-group/locations' );
echo '</div>';
break;
case 'presentation':
echo '<div class="field-group-setting-split-container field-group-settings-tab">';
echo '<div class="field-group-setting-split">';
// style
acf_render_field_wrap(
array(
'label' => __( 'Style', 'acf' ),
'instructions' => '',
'type' => 'button_group',
'name' => 'style',
'prefix' => 'acf_field_group',
'value' => $field_group['style'],
'choices' => array(
'default' => __( 'Standard (WP metabox)', 'acf' ),
'seamless' => __( 'Seamless (no metabox)', 'acf' ),
),
)
);
// position
acf_render_field_wrap(
array(
'label' => __( 'Position', 'acf' ),
'instructions' => __( "'High' position not supported in the Block Editor", 'acf' ),
'type' => 'button_group',
'name' => 'position',
'prefix' => 'acf_field_group',
'value' => $field_group['position'],
'choices' => array(
'acf_after_title' => __( 'High (after title)', 'acf' ),
'normal' => __( 'Normal (after content)', 'acf' ),
'side' => __( 'Side', 'acf' ),
),
'default_value' => 'normal',
),
'div',
'field'
);
// label_placement
acf_render_field_wrap(
array(
'label' => __( 'Label Placement', 'acf' ),
'instructions' => '',
'type' => 'button_group',
'name' => 'label_placement',
'prefix' => 'acf_field_group',
'value' => $field_group['label_placement'],
'choices' => array(
'top' => __( 'Top aligned', 'acf' ),
'left' => __( 'Left aligned', 'acf' ),
),
)
);
// instruction_placement
acf_render_field_wrap(
array(
'label' => __( 'Instruction Placement', 'acf' ),
'instructions' => '',
'type' => 'button_group',
'name' => 'instruction_placement',
'prefix' => 'acf_field_group',
'value' => $field_group['instruction_placement'],
'choices' => array(
'label' => __( 'Below labels', 'acf' ),
'field' => __( 'Below fields', 'acf' ),
),
)
);
// menu_order
acf_render_field_wrap(
array(
'label' => __( 'Order No.', 'acf' ),
'instructions' => __( 'Field groups with a lower order will appear first', 'acf' ),
'type' => 'number',
'name' => 'menu_order',
'prefix' => 'acf_field_group',
'value' => $field_group['menu_order'],
),
'div',
'field'
);
echo '</div>';
echo '<div class="field-group-setting-split">';
// hide on screen
$choices = array(
'permalink' => __( 'Permalink', 'acf' ),
'the_content' => __( 'Content Editor', 'acf' ),
'excerpt' => __( 'Excerpt', 'acf' ),
'custom_fields' => __( 'Custom Fields', 'acf' ),
'discussion' => __( 'Discussion', 'acf' ),
'comments' => __( 'Comments', 'acf' ),
'revisions' => __( 'Revisions', 'acf' ),
'slug' => __( 'Slug', 'acf' ),
'author' => __( 'Author', 'acf' ),
'format' => __( 'Format', 'acf' ),
'page_attributes' => __( 'Page Attributes', 'acf' ),
'featured_image' => __( 'Featured Image', 'acf' ),
'categories' => __( 'Categories', 'acf' ),
'tags' => __( 'Tags', 'acf' ),
'send-trackbacks' => __( 'Send Trackbacks', 'acf' ),
);
if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
unset( $choices['custom_fields'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Hide on screen', 'acf' ),
'instructions' => __( '<b>Select</b> items to <b>hide</b> them from the edit screen.', 'acf' ) . '<br /><br />' . __( "If multiple field groups appear on an edit screen, the first field group's options will be used (the one with the lowest order number)", 'acf' ),
'type' => 'checkbox',
'name' => 'hide_on_screen',
'prefix' => 'acf_field_group',
'value' => $field_group['hide_on_screen'],
'toggle' => true,
'choices' => $choices,
),
'div',
'label',
true
);
echo '</div>';
echo '</div>';
break;
case 'group_settings':
echo '<div class="field-group-settings field-group-settings-tab">';
// active
acf_render_field_wrap(
array(
'label' => __( 'Active', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'active',
'prefix' => 'acf_field_group',
'value' => $field_group['active'],
'ui' => 1,
// 'ui_on_text' => __('Active', 'acf'),
// 'ui_off_text' => __('Inactive', 'acf'),
)
);
// Show fields in REST API.
if ( acf_get_setting( 'rest_api_enabled' ) ) {
acf_render_field_wrap(
array(
'label' => __( 'Show in REST API', 'acf' ),
'instructions' => '',
'type' => 'true_false',
'name' => 'show_in_rest',
'prefix' => 'acf_field_group',
'value' => $field_group['show_in_rest'],
'ui' => 1,
// 'ui_on_text' => __('Active', 'acf'),
// 'ui_off_text' => __('Inactive', 'acf'),
)
);
}
// description
acf_render_field_wrap(
array(
'label' => __( 'Description', 'acf' ),
'instructions' => __( 'Shown in field group list', 'acf' ),
'type' => 'text',
'name' => 'description',
'prefix' => 'acf_field_group',
'value' => $field_group['description'],
),
'div',
'field'
);
/* translators: 1: Post creation date 2: Post creation time */
$acf_created_on = sprintf( __( 'Created on %1$s at %2$s', 'acf' ), get_the_date(), get_the_time() );
?>
<div class="acf-field-group-settings-footer">
<span class="acf-created-on"><?php echo esc_html( $acf_created_on ); ?></span>
<a href="<?php echo get_delete_post_link(); ?>" class="acf-btn acf-btn-tertiary acf-delete-field-group">
<i class="acf-icon acf-icon-trash"></i>
<?php esc_html_e( 'Delete Field Group', 'acf' ); ?>
</a>
</div>
<?php
echo '</div>';
break;
default:
echo '<div class="field-group-' . esc_attr( $tab_key ) . ' field-group-settings-tab">';
do_action( 'acf/field_group/render_group_settings_tab/' . $tab_key, $field_group );
echo '</div>';
break;
}
}
// 3rd party settings
do_action( 'acf/render_field_group_settings', $field_group );
?>
<div class="acf-hidden">
<input type="hidden" name="acf_field_group[key]" value="<?php echo $field_group['key']; ?>" />
</div>
<script type="text/javascript">
if( typeof acf !== 'undefined' ) {
acf.newPostbox({
'id': 'acf-field-group-options',
'label': 'top'
});
}
</script>

View File

@ -0,0 +1,90 @@
<?php
$acf_field_group_pro_features_title = __( 'Unlock Advanced Features and Build Even More with ACF PRO', 'acf' );
$acf_learn_more_text = __( 'Learn More', 'acf' );
$acf_learn_more_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'metabox' );
$acf_learn_more_target = '_blank';
$acf_pricing_text = __( 'View Pricing & Upgrade', 'acf' );
$acf_pricing_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'metabox_pricing', 'pricing-table' );
$acf_more_tools_link = acf_add_url_utm_tags( 'https://wpengine.com/developer/', 'bx_prod_referral', 'acf_free_plugin_cta_panel_logo', false, 'acf_plugin', 'referral' );
$acf_wpengine_logo_link = acf_add_url_utm_tags( 'https://wpengine.com/', 'bx_prod_referral', 'acf_free_plugin_cta_panel_logo', false, 'acf_plugin', 'referral' );
if ( acf_is_pro() ) {
if ( ! acf_pro_get_license_key() && acf_is_updates_page_visible() ) {
$acf_learn_more_target = '';
$acf_learn_more_text = __( 'Manage License', 'acf' );
$acf_learn_more_link = esc_url( admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates#acf_pro_license' ) );
} elseif ( acf_pro_is_license_expired() ) {
$acf_pricing_text = __( 'Renew License', 'acf' );
$acf_pricing_link = acf_add_url_utm_tags( acf_pro_get_manage_license_url(), 'ACF renewal', 'metabox' );
}
}
?>
<div id="tmpl-acf-field-group-pro-features">
<div class="acf-field-group-pro-features-wrapper">
<h1 class="acf-field-group-pro-features-title-sm"><?php echo esc_html( $acf_field_group_pro_features_title ); ?> <div class="acf-pro-label">PRO</div></h1>
<div class="acf-field-group-pro-features-content">
<h1 class="acf-field-group-pro-features-title"><?php echo esc_html( $acf_field_group_pro_features_title ); ?> <div class="acf-pro-label">PRO</div></h1>
<p class="acf-field-group-pro-features-desc"><?php esc_html_e( 'Speed up your workflow and develop better websites with features like ACF Blocks and Options Pages, and sophisticated field types like Repeater, Flexible Content, Clone, and Gallery.', 'acf' ); ?></p>
<div class="acf-field-group-pro-features-actions">
<a target="<?php echo $acf_learn_more_target; ?>" href="<?php echo $acf_learn_more_link; ?>" class="acf-btn acf-btn-muted acf-pro-features-learn-more"><?php echo esc_html( $acf_learn_more_text ); ?> <i class="acf-icon acf-icon-arrow-up-right"></i></a>
<a target="_blank" href="<?php echo $acf_pricing_link; ?>" class="acf-btn acf-pro-features-upgrade"><?php echo esc_html( $acf_pricing_text ); ?> <i class="acf-icon acf-icon-arrow-up-right"></i></a>
</div>
</div>
<div class="acf-field-group-pro-features-grid">
<div class="acf-field-group-pro-feature">
<i class="field-type-icon field-type-icon-flexible-content"></i>
<span class="field-type-label"><?php esc_html_e( 'Flexible Content Field', 'acf' ); ?></span>
</div>
<div class="acf-field-group-pro-feature">
<i class="field-type-icon field-type-icon-repeater"></i>
<span class="field-type-label"><?php esc_html_e( 'Repeater Field', 'acf' ); ?></span>
</div>
<div class="acf-field-group-pro-feature">
<i class="field-type-icon field-type-icon-clone"></i>
<span class="field-type-label"><?php esc_html_e( 'Clone Field', 'acf' ); ?></span>
</div>
<div class="acf-field-group-pro-feature">
<i class="field-type-icon pro-feature-blocks"></i>
<span class="field-type-label"><?php esc_html_e( 'ACF Blocks', 'acf' ); ?></span>
</div>
<div class="acf-field-group-pro-feature">
<i class="field-type-icon pro-feature-options-pages"></i>
<span class="field-type-label"><?php esc_html_e( 'Options Pages', 'acf' ); ?></span>
</div>
<div class="acf-field-group-pro-feature">
<i class="field-type-icon field-type-icon-gallery"></i>
<span class="field-type-label"><?php esc_html_e( 'Gallery Field', 'acf' ); ?></span>
</div>
</div>
</div>
<div class="acf-field-group-pro-features-footer-wrap">
<div class="acf-field-group-pro-features-footer">
<div class="acf-for-the-builders">
<?php
$acf_wpengine_logo = acf_get_url( 'assets/images/wp-engine-horizontal-white.svg' );
$acf_wpengine_logo = sprintf( '<a href="%s" target="_blank"><img class="acf-field-group-pro-features-wpengine-logo" src="%s" alt="WP Engine" /></a>', $acf_wpengine_logo_link, $acf_wpengine_logo );
/* translators: %s - WP Engine logo */
$acf_made_for_text = sprintf( __( 'Built for those that build with WordPress, by the team at %s', 'acf' ), $acf_wpengine_logo );
echo acf_esc_html( $acf_made_for_text );
?>
</div>
<div class="acf-more-tools-from-wpengine">
<a href="<?php echo $acf_more_tools_link; ?>" target="_blank"><?php esc_html_e( 'More Tools from WP Engine', 'acf' ); ?> <i class="acf-icon acf-icon-arrow-up-right"></i></a>
</div>
</div>
</div>
</div>
<script type="text/javascript">
( function ( $, undefined ) {
$( document ).ready( function() {
if ( 'field_group' === acf.get( 'screen' ) ) {
$( '#acf-field-group-options' ).after( $( '#tmpl-acf-field-group-pro-features' ).css( 'display', 'block' ) );
} else {
$( '#tmpl-acf-field-group-pro-features' ).appendTo( '#wpbody-content .wrap' ).css( 'display', 'block' );
}
} );
} )( jQuery );
</script>

View File

@ -0,0 +1,153 @@
<?php
global $acf_post_type;
$acf_duplicate_post_type = acf_get_post_type_from_request_args( 'acfduplicate' );
if ( acf_is_post_type( $acf_duplicate_post_type ) ) {
// Reset vars that likely have to be changed.
$acf_duplicate_post_type['key'] = uniqid( 'post_type_' );
$acf_duplicate_post_type['title'] = '';
$acf_duplicate_post_type['labels'] = array_map( '__return_empty_string', $acf_duplicate_post_type['labels'] );
$acf_duplicate_post_type['post_type'] = '';
$acf_duplicate_post_type['rest_base'] = '';
$acf_duplicate_post_type['query_var_name'] = '';
$acf_duplicate_post_type['rewrite']['slug'] = '';
// Rest of the vars can be reused.
$acf_post_type = $acf_duplicate_post_type;
}
acf_render_field_wrap(
array(
'label' => __( 'Plural Label', 'acf' ),
/* translators: example post type */
'placeholder' => __( 'Movies', 'acf' ),
'type' => 'text',
'name' => 'name',
'key' => 'name',
'class' => 'acf_plural_label',
'prefix' => 'acf_post_type[labels]',
'value' => $acf_post_type['labels']['name'],
'required' => true,
),
'div',
'field'
);
acf_render_field_wrap(
array(
'label' => __( 'Singular Label', 'acf' ),
/* translators: example post type */
'placeholder' => __( 'Movie', 'acf' ),
'type' => 'text',
'name' => 'singular_name',
'key' => 'singular_name',
'class' => 'acf_slugify_to_key acf_singular_label',
'prefix' => 'acf_post_type[labels]',
'value' => $acf_post_type['labels']['singular_name'],
'required' => true,
),
'div',
'field'
);
acf_render_field_wrap(
array(
'label' => __( 'Post Type Key', 'acf' ),
'instructions' => __( 'Lower case letters, underscores and dashes only, Max 20 characters.', 'acf' ),
/* translators: example post type */
'placeholder' => __( 'movie', 'acf' ),
'type' => 'text',
'name' => 'post_type',
'key' => 'post_type',
'maxlength' => 20,
'class' => 'acf_slugified_key',
'prefix' => 'acf_post_type',
'value' => $acf_post_type['post_type'],
'required' => true,
),
'div',
'field'
);
// Allow preselecting the linked taxonomies based on previously created taxonomy.
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'create-post-type' );
if ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['taxonomy'] ) ) {
$acf_post_type['taxonomies'] = array( $acf_use_taxonomy['taxonomy'] );
}
acf_render_field_wrap(
array(
'type' => 'select',
'name' => 'taxonomies',
'key' => 'taxonomies',
'prefix' => 'acf_post_type',
'value' => $acf_post_type['taxonomies'],
'label' => __( 'Taxonomies', 'acf' ),
'instructions' => __( 'Select existing taxonomies to classify items of the post type.', 'acf' ),
'choices' => acf_get_taxonomy_labels(),
'ui' => true,
'allow_null' => true,
'multiple' => true,
),
'div',
'field'
);
acf_render_field_wrap( array( 'type' => 'seperator' ) );
acf_render_field_wrap(
array(
'type' => 'true_false',
'name' => 'public',
'key' => 'public',
'prefix' => 'acf_post_type',
'value' => $acf_post_type['public'],
'label' => __( 'Public', 'acf' ),
'instructions' => __( 'Visible on the frontend and in the admin dashboard.', 'acf' ),
'ui' => true,
'default' => 1,
),
'div'
);
acf_render_field_wrap(
array(
'type' => 'true_false',
'name' => 'hierarchical',
'key' => 'hierarchical',
'class' => 'acf_hierarchical_switch',
'prefix' => 'acf_post_type',
'value' => $acf_post_type['hierarchical'],
'label' => __( 'Hierarchical', 'acf' ),
'instructions' => __( 'Hierarchical post types can have descendants (like pages).', 'acf' ),
'ui' => true,
),
'div'
);
do_action( 'acf/post_type/basic_settings', $acf_post_type );
acf_render_field_wrap( array( 'type' => 'seperator' ) );
acf_render_field_wrap(
array(
'label' => __( 'Advanced Configuration', 'acf' ),
'instructions' => __( 'I know what I\'m doing, show me all the options.', 'acf' ),
'type' => 'true_false',
'name' => 'advanced_configuration',
'key' => 'advanced_configuration',
'prefix' => 'acf_post_type',
'value' => $acf_post_type['advanced_configuration'],
'ui' => 1,
'class' => 'acf-advanced-settings-toggle',
)
);
?>
<div class="acf-hidden">
<input type="hidden" name="acf_post_type[key]" value="<?php echo esc_attr( $acf_post_type['key'] ); ?>" />
<input type="hidden" name="acf_post_type[import_source]" value="<?php echo esc_attr( $acf_post_type['import_source'] ); ?>" />
<input type="hidden" name="acf_post_type[import_date]" value="<?php echo esc_attr( $acf_post_type['import_date'] ); ?>" />
</div>
<?php

View File

@ -0,0 +1,18 @@
<script>document.body.classList.add('acf-no-post-types');</script>
<div class="acf-no-post-types-wrapper">
<div class="acf-no-post-types-inner">
<img src="<?php echo esc_url( acf_get_url( 'assets/images/empty-post-types.svg' ) ); ?>" />
<h2><?php esc_html_e( 'Add Your First Post Type', 'acf' ); ?></h2>
<p><?php esc_html_e( 'Expand the functionality of WordPress beyond standard posts and pages with custom post types.', 'acf' ); ?></p>
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=acf-post-type' ) ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php esc_html_e( 'Add Post Type', 'acf' ); ?></a>
<p class="acf-small">
<?php
printf(
/* translators: %s url to getting started guide */
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-post-types' )
);
?>
</p>
</div>
</div>

View File

@ -0,0 +1,152 @@
<?php
global $acf_taxonomy;
$acf_duplicate_taxonomy = acf_get_taxonomy_from_request_args( 'acfduplicate' );
if ( acf_is_taxonomy( $acf_duplicate_taxonomy ) ) {
// Reset vars that likely have to be changed.
$acf_duplicate_taxonomy['key'] = uniqid( 'taxonomy_' );
$acf_duplicate_taxonomy['title'] = '';
$acf_duplicate_taxonomy['labels'] = array_map( '__return_empty_string', $acf_duplicate_taxonomy['labels'] );
$acf_duplicate_taxonomy['taxonomy'] = '';
$acf_duplicate_taxonomy['rewrite']['slug'] = '';
$acf_duplicate_taxonomy['query_var_name'] = '';
$acf_duplicate_taxonomy['rest_base'] = '';
// Rest of the vars can be reused.
$acf_taxonomy = $acf_duplicate_taxonomy;
}
acf_render_field_wrap(
array(
'label' => __( 'Plural Label', 'acf' ),
/* translators: example taxonomy */
'placeholder' => __( 'Genres', 'acf' ),
'type' => 'text',
'key' => 'name',
'name' => 'name',
'class' => 'acf_plural_label',
'prefix' => 'acf_taxonomy[labels]',
'value' => $acf_taxonomy['labels']['name'],
'required' => 1,
),
'div',
'field'
);
acf_render_field_wrap(
array(
'label' => __( 'Singular Label', 'acf' ),
/* translators: example taxonomy */
'placeholder' => __( 'Genre', 'acf' ),
'type' => 'text',
'key' => 'singular_name',
'name' => 'singular_name',
'class' => 'acf_slugify_to_key acf_singular_label',
'prefix' => 'acf_taxonomy[labels]',
'value' => $acf_taxonomy['labels']['singular_name'],
'required' => 1,
),
'div',
'field'
);
acf_render_field_wrap(
array(
'label' => __( 'Taxonomy Key', 'acf' ),
'instructions' => __( 'Lower case letters, underscores and dashes only, Max 32 characters.', 'acf' ),
/* translators: example taxonomy */
'placeholder' => __( 'genre', 'acf' ),
'type' => 'text',
'key' => 'taxonomy',
'name' => 'taxonomy',
'maxlength' => 32,
'class' => 'acf_slugified_key',
'prefix' => 'acf_taxonomy',
'value' => $acf_taxonomy['taxonomy'],
'required' => 1,
),
'div',
'field'
);
// Allow preselecting the linked post types based on previously created post type.
$acf_use_post_type = acf_get_post_type_from_request_args( 'create-taxonomy' );
if ( $acf_use_post_type && ! empty( $acf_use_post_type['post_type'] ) ) {
$acf_taxonomy['object_type'] = array( $acf_use_post_type['post_type'] );
}
acf_render_field_wrap(
array(
'label' => __( 'Post Types', 'acf' ),
'type' => 'select',
'name' => 'object_type',
'prefix' => 'acf_taxonomy',
'value' => $acf_taxonomy['object_type'],
'choices' => acf_get_pretty_post_types(),
'multiple' => 1,
'ui' => 1,
'allow_null' => 1,
'instructions' => __( 'One or many post types that can be classified with this taxonomy.', 'acf' ),
),
'div',
'field'
);
acf_render_field_wrap( array( 'type' => 'seperator' ) );
acf_render_field_wrap(
array(
'type' => 'true_false',
'key' => 'public',
'name' => 'public',
'prefix' => 'acf_taxonomy',
'value' => $acf_taxonomy['public'],
'label' => __( 'Public', 'acf' ),
'instructions' => __( 'Makes a taxonomy visible on the frontend and in the admin dashboard.', 'acf' ),
'ui' => true,
'default' => 1,
)
);
acf_render_field_wrap(
array(
'type' => 'true_false',
'key' => 'hierarchical',
'name' => 'hierarchical',
'class' => 'acf_hierarchical_switch',
'prefix' => 'acf_taxonomy',
'value' => $acf_taxonomy['hierarchical'],
'label' => __( 'Hierarchical', 'acf' ),
'instructions' => __( 'Hierarchical taxonomies can have descendants (like categories).', 'acf' ),
'ui' => true,
),
'div'
);
do_action( 'acf/taxonomy/basic_settings', $acf_taxonomy );
acf_render_field_wrap( array( 'type' => 'seperator' ) );
acf_render_field_wrap(
array(
'label' => __( 'Advanced Configuration', 'acf' ),
'instructions' => __( 'I know what I\'m doing, show me all the options.', 'acf' ),
'type' => 'true_false',
'key' => 'advanced_configuration',
'name' => 'advanced_configuration',
'prefix' => 'acf_taxonomy',
'value' => $acf_taxonomy['advanced_configuration'],
'ui' => 1,
'class' => 'acf-advanced-settings-toggle',
)
);
?>
<div class="acf-hidden">
<input type="hidden" name="acf_taxonomy[key]" value="<?php echo esc_attr( $acf_taxonomy['key'] ); ?>" />
<input type="hidden" name="acf_taxonomy[import_source]" value="<?php echo esc_attr( $acf_taxonomy['import_source'] ); ?>" />
<input type="hidden" name="acf_taxonomy[import_date]" value="<?php echo esc_attr( $acf_taxonomy['import_date'] ); ?>" />
</div>
<?php

View File

@ -0,0 +1,18 @@
<script>document.body.classList.add('acf-no-taxonomies');</script>
<div class="acf-no-taxonomies-wrapper">
<div class="acf-no-taxonomies-inner">
<img src="<?php echo esc_url( acf_get_url( 'assets/images/empty-taxonomies.svg' ) ); ?>" />
<h2><?php esc_html_e( 'Add Your First Taxonomy', 'acf' ); ?></h2>
<p><?php esc_html_e( 'Create custom taxonomies to classify post type content', 'acf' ); ?></p>
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=acf-taxonomy' ) ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php esc_html_e( 'Add Taxonomy', 'acf' ); ?></a>
<p class="acf-small">
<?php
printf(
/* translators: %s url to getting started guide */
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-taxonomies' )
);
?>
</p>
</div>
</div>

View File

@ -0,0 +1,99 @@
<?php
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
$browse_fields_tabs = array( 'popular' => __( 'Popular', 'acf' ) );
$browse_fields_tabs = $browse_fields_tabs + acf_get_field_categories_i18n();
?>
<div class="acf-browse-fields-modal-wrap">
<div class="acf-modal acf-browse-fields-modal">
<div class="acf-field-picker">
<div class="acf-modal-title">
<h1><?php esc_html_e( 'Select Field Type', 'acf' ); ?></h1>
<span class="acf-search-field-types-wrap">
<input class="acf-search-field-types" type="search" placeholder="<?php esc_attr_e( 'Search fields...', 'acf' ); ?>" />
</span>
</div>
<div class="acf-modal-content">
<?php
foreach ( $browse_fields_tabs as $name => $label ) {
acf_render_field_wrap(
array(
'type' => 'tab',
'label' => $label,
'key' => 'acf_browse_fields_tabs',
)
);
printf(
'<div class="acf-field-types-tab" data-category="%s"></div>',
esc_attr( $name )
);
}
?>
<div class="acf-field-type-search-results"></div>
<div class="acf-field-type-search-no-results">
<img src="<?php echo esc_url( acf_get_url( 'assets/images/face-sad.svg' ) ); ?>" />
<p class="acf-no-results-text">
<?php
printf(
/* translators: %s: The invalid search term */
acf_esc_html( __( "No search results for '%s'", 'acf' ) ),
'<span class="acf-invalid-search-term"></span>'
);
?>
</p>
<p>
<?php
$browse_popular_link = '<a href="#" class="acf-browse-popular-fields">' . esc_html( __( 'Popular fields', 'acf' ) ) . '</a>';
printf(
/* translators: %s: A link to the popular fields used in ACF */
acf_esc_html( __( 'Try a different search term or browse %s', 'acf' ) ),
$browse_popular_link //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
);
?>
</p>
</div>
</div>
<div class="acf-modal-toolbar acf-field-picker-toolbar">
<div class="acf-field-picker-label">
<input class="acf-insert-field-label" type="text" placeholder="<?php esc_attr_e( 'Field Label', 'acf' ); ?>" />
</div>
<div class="acf-field-picker-actions">
<button class="button acf-cancel acf-modal-close"><?php esc_html_e( 'Cancel', 'acf' ); ?></button>
<button class="acf-btn acf-select-field"><?php esc_html_e( 'Select Field', 'acf' ); ?></button>
<a target="_blank" data-url-base="<?php echo esc_attr( acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'field-type-modal', '' ) ); ?>" class="acf-btn acf-btn-pro">
<?php _e( 'Upgrade to PRO', 'acf' ); ?>
</a>
</div>
</div>
</div>
<div class="acf-field-type-preview">
<div class="field-type-info">
<h2 class="field-type-name"></h2>
<a target="_blank" data-url-base="<?php echo esc_attr( acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'field-type-modal', '' ) ); ?>" class="field-type-upgrade-to-unlock">
<i class="acf-icon acf-icon-lock"></i>
<?php _e( 'Available with ACF PRO', 'acf' ); ?>
</a>
<p class="field-type-desc"></p>
<div class="field-type-preview-container">
<img class="field-type-image" />
</div>
</div>
<ul class="acf-hl field-type-links">
<li>
<a class="field-type-tutorial" href="#" target="_blank">
<i class="acf-icon acf-icon-play"></i>
<?php esc_html_e( 'Tutorial', 'acf' ); ?>
</a>
</li>
<li>
<a class="field-type-doc" href="#" target="_blank">
<i class="acf-icon acf-icon-document"></i>
<?php esc_html_e( 'Documentation', 'acf' ); ?>
</a>
</li>
</ul>
</div>
</div>
<div class="acf-modal-backdrop acf-modal-close"></div>
</div>

View File

@ -0,0 +1,70 @@
<?php
$acf_plugin_name = acf_is_pro() ? 'ACF PRO' : 'ACF';
$acf_plugin_name = '<strong>' . $acf_plugin_name . ' &mdash;</strong>';
$acf_learn_how_to_fix = '<a href="' . acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/escaping-the-field/', 'docs', '6-2-5-security-changes' ) . '" target="_blank">' . __( 'Learn how to fix', 'acf' ) . '</a>';
$acf_class = '';
$acf_user_can_acf = false;
if ( current_user_can( acf_get_setting( 'capability' ) ) ) {
$acf_user_can_acf = true;
$acf_show_details = ' <a class="acf-show-more-details" href="#">' . __( 'Show details', 'acf' ) . '</a>';
$acf_class = ' is-dismissible';
} else {
$acf_show_details = __( 'Please contact your site admin for more details.', 'acf' );
}
if ( ! empty( $acf_will_escape ) ) {
$acf_escaped = $acf_will_escape;
$acf_class .= ' notice-warning acf-will-escape';
$acf_error_msg = sprintf(
/* translators: %1$s - name of the ACF plugin. %2$s - Link to documentation. %3$s - Link to show more details about the error */
__( '%1$s ACF will soon escape unsafe HTML that is rendered by <code>the_field()</code>. We\'ve detected the output of some of your fields will be modified by this change. %2$s. %3$s', 'acf' ),
$acf_plugin_name,
$acf_learn_how_to_fix,
$acf_show_details
);
} else {
$acf_class .= ' notice-error';
if ( apply_filters( 'acf/the_field/escape_html_optin', false ) ) {
$acf_error_msg = sprintf(
/* translators: %1$s - name of the ACF plugin. %2$s - Link to documentation. %3$s - Link to show more details about the error */
__( '%1$s ACF now automatically escapes unsafe HTML when rendered by <code>the_field</code> or the ACF shortcode. We\'ve detected the output of some of your fields will be modified by this change. %2$s. %3$s', 'acf' ),
$acf_plugin_name,
$acf_learn_how_to_fix,
$acf_show_details
);
} else {
$acf_error_msg = sprintf(
/* translators: %1$s - name of the ACF plugin. %2$s - Link to documentation. %3$s - Link to show more details about the error */
__( '%1$s ACF now automatically escapes unsafe HTML when rendered by the ACF shortcode. We\'ve detected the output of some of your fields will be modified by this change. %2$s. %3$s', 'acf' ),
$acf_plugin_name,
$acf_learn_how_to_fix,
$acf_show_details
);
}
}
?>
<div class="acf-admin-notice notice acf-escaped-html-notice<?php echo esc_attr( $acf_class ); ?>">
<p><?php echo acf_esc_html( $acf_error_msg ); ?></p>
<?php if ( $acf_user_can_acf && ! empty( $acf_escaped ) ) : ?>
<ul class="acf-error-details" style="display: none; list-style: disc; margin-left: 14px;">
<?php
foreach ( $acf_escaped as $acf_field_key => $acf_data ) {
$acf_error = sprintf(
/* translators: %1$s - The selector used %2$s The field name 3%$s The parent function name */
__( '%1$s (%2$s) - rendered via %3$s', 'acf' ),
$acf_data['selector'],
$acf_data['field'],
$acf_data['function']
);
echo '<li>' . esc_html( $acf_error ) . '</li>';
}
?>
</ul>
<?php endif; ?>
</div>

View File

@ -0,0 +1,94 @@
<?php
global $title, $post_new_file, $post_type_object, $post;
$acf_title_placeholder = apply_filters( 'enter_title_here', __( 'Add title' ), $post );
$acf_title = $post->post_title;
$acf_post_type = is_object( $post_type_object ) ? $post_type_object->name : '';
$acf_publish_btn_name = 'save';
$acf_duplicated_from = '';
if ( 'publish' !== $post->post_status ) {
$acf_publish_btn_name = 'publish';
}
if ( 'acf-field-group' === $acf_post_type ) {
$acf_use_post_type = acf_get_post_type_from_request_args( 'add-fields' );
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'add-fields' );
$acf_use_options_page = acf_get_ui_options_page_from_request_args( 'add-fields' );
/* translators: %s - singular label of post type/taxonomy, i.e. "Movie"/"Genre" */
$acf_prefilled_title = __( '%s fields', 'acf' );
/**
* Sets a default title to be prefilled (e.g. "Movies Fields") for a post type or taxonomy.
*
* @since 6.1.5
*
* @param string $acf_prefilled_title A string to define the prefilled title for a post type or taxonomy.
*/
$acf_prefilled_title = (string) apply_filters( 'acf/field_group/prefill_title', $acf_prefilled_title );
if ( $acf_use_post_type && ! empty( $acf_use_post_type['labels']['singular_name'] ) ) {
$acf_prefilled_title = sprintf( $acf_prefilled_title, $acf_use_post_type['labels']['singular_name'] );
} elseif ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['labels']['singular_name'] ) ) {
$acf_prefilled_title = sprintf( $acf_prefilled_title, $acf_use_taxonomy['labels']['singular_name'] );
} elseif ( $acf_use_options_page && ! empty( $acf_use_options_page['page_title'] ) ) {
$acf_prefilled_title = sprintf( $acf_prefilled_title, $acf_use_options_page['page_title'] );
} else {
$acf_prefilled_title = false;
}
if ( empty( $acf_title ) && $acf_prefilled_title ) {
$acf_title = $acf_prefilled_title;
}
} elseif ( in_array( $acf_post_type, array( 'acf-post-type', 'acf-taxonomy' ) ) ) {
$acf_duplicate_post_type = acf_get_post_type_from_request_args( 'acfduplicate' );
$acf_duplicate_taxonomy = acf_get_taxonomy_from_request_args( 'acfduplicate' );
$acf_duplicated_from_label = '';
if ( $acf_duplicate_post_type && ! empty( $acf_duplicate_post_type['labels']['singular_name'] ) ) {
$acf_duplicated_from_label = $acf_duplicate_post_type['labels']['singular_name'];
} elseif ( $acf_duplicate_taxonomy && ! empty( $acf_duplicate_taxonomy['labels']['singular_name'] ) ) {
$acf_duplicated_from_label = $acf_duplicate_taxonomy['labels']['singular_name'];
}
if ( ! empty( $acf_duplicated_from_label ) ) {
/* translators: %s - A singular label for a post type or taxonomy. */
$acf_duplicated_from = sprintf( __( ' (Duplicated from %s)', 'acf' ), $acf_duplicated_from_label );
}
}
?>
<div class="acf-headerbar acf-headerbar-field-editor">
<div class="acf-headerbar-inner">
<div class="acf-headerbar-content">
<h1 class="acf-page-title">
<?php
echo esc_html( $title );
if ( ! empty( $acf_duplicated_from ) ) {
echo '<span class="acf-duplicated-from">' . esc_html( $acf_duplicated_from ) . '</span>';
}
?>
</h1>
<?php if ( 'acf-field-group' === $acf_post_type ) : ?>
<div class="acf-title-wrap">
<label class="screen-reader-text" id="title-prompt-text" for="title"><?php echo esc_html( $acf_title_placeholder ); ?></label>
<input form="post" type="text" name="post_title" size="30" value="<?php echo esc_attr( $acf_title ); ?>" id="title" class="acf-headerbar-title-field" spellcheck="true" autocomplete="off" placeholder="<?php esc_attr_e( 'Field Group Title', 'acf' ); ?>" />
</div>
<?php endif; ?>
</div>
<div class="acf-headerbar-actions" id="submitpost">
<?php if ( 'acf-field-group' === $acf_post_type ) : ?>
<a href="#" class="acf-btn acf-btn-secondary add-field">
<i class="acf-icon acf-icon-plus"></i>
<?php esc_html_e( 'Add Field', 'acf' ); ?>
</a>
<?php endif; ?>
<button form="post" class="acf-btn acf-publish" name="<?php echo esc_attr( $acf_publish_btn_name ); ?>" type="submit">
<?php esc_html_e( 'Save Changes', 'acf' ); ?>
</button>
</div>
</div>
</div>

View File

@ -0,0 +1,45 @@
<?php
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
global $post_type, $post_type_object, $acf_page_title;
$post_new_file = sprintf(
'post-new.php?post_type=%s',
is_string( $post_type ) ? $post_type : 'acf-field-group'
);
$acf_is_options_page_preview = acf_request_arg( 'page' ) === 'acf_options_preview';
$page_title = false;
if ( isset( $acf_page_title ) ) {
$page_title = $acf_page_title;
} elseif ( is_object( $post_type_object ) ) {
$page_title = $post_type_object->labels->name;
}
if ( $page_title ) {
?>
<div class="acf-headerbar">
<h1 class="acf-page-title">
<?php
echo esc_html( $page_title );
?>
<?php if ( $acf_is_options_page_preview ) { ?>
<div class="acf-pro-label">PRO</div>
<?php
}
?>
</h1>
<?php if ( $acf_is_options_page_preview ) { ?>
<a href="#" class="acf-btn acf-btn-sm disabled">
<i class="acf-icon acf-icon-plus"></i>
<?php esc_html_e( 'Add Options Page', 'acf' ); ?>
</a>
<?php } ?>
<?php
if ( ! empty( $post_type_object ) && current_user_can( $post_type_object->cap->create_posts ) ) {
echo ' <a href="' . esc_url( admin_url( $post_new_file ) ) . '" class="acf-btn acf-btn-sm"><i class="acf-icon acf-icon-plus"></i>' . esc_html( $post_type_object->labels->add_new ) . '</a>';
}
?>
</div>
<?php } ?>

View File

@ -0,0 +1,256 @@
<?php
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
/**
* The template for displaying admin navigation.
*
* @date 27/3/20
* @since 5.9.0
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
global $submenu, $submenu_file, $plugin_page, $acf_page_title;
// Setup default vars and generate array of navigation items.
$parent_slug = 'edit.php?post_type=acf-field-group';
$core_tabs = array();
$acf_more_items = array();
$more_items = array();
$wpengine_more_items = array();
// Hardcoded since future ACF post types will likely live in the "More" menu.
$core_tabs_classes = array( 'acf-field-group', 'acf-post-type', 'acf-taxonomy' );
$acf_more_items_classes = array( 'acf-ui-options-page', 'acf-tools', 'acf-settings-updates' );
if ( isset( $submenu[ $parent_slug ] ) ) {
foreach ( $submenu[ $parent_slug ] as $i => $sub_item ) {
// Check user can access page.
if ( ! current_user_can( $sub_item[1] ) ) {
continue;
}
// Define tab.
$menu_item = array(
'text' => $sub_item[0],
'url' => $sub_item[2],
);
// Convert submenu slug "test" to "$parent_slug&page=test".
if ( ! strpos( $sub_item[2], '.php' ) ) {
$menu_item['url'] = add_query_arg( array( 'page' => $sub_item[2] ), $parent_slug );
$menu_item['class'] = $sub_item[2];
} else {
// Build class from URL.
$menu_item['class'] = str_replace( 'edit.php?post_type=', '', $sub_item[2] );
}
// Detect active state.
if ( $submenu_file === $sub_item[2] || $plugin_page === $sub_item[2] ) {
$menu_item['is_active'] = true;
}
// Handle "Add New" versions of edit page.
if ( str_replace( 'edit', 'post-new', $sub_item[2] ) === $submenu_file ) {
$menu_item['is_active'] = true;
}
// Organize the menu items.
if ( in_array( $menu_item['class'], $core_tabs_classes, true ) ) {
// Main ACF tabs.
$core_tabs[] = $menu_item;
// Add post types & taxonomies to the more menu as well so we can show them there on smaller screens.
if ( in_array( $menu_item['class'], array( 'acf-post-type', 'acf-taxonomy' ), true ) ) {
$acf_more_items[] = $menu_item;
}
} elseif ( in_array( $menu_item['class'], $acf_more_items_classes, true ) ) {
// ACF tabs moved to the "More" menu.
$acf_more_items[] = $menu_item;
} else {
// Third party tabs placed into the "More" menu.
if ( 'acf_options_preview' === $menu_item['class'] ) {
continue;
}
$more_items[] = $menu_item;
}
}
}
if ( ! acf_get_setting( 'pro' ) ) {
$acf_more_items[] = array(
'url' => 'edit.php?post_type=acf-field-group&page=acf_options_preview',
'text' => __( 'Options Pages', 'acf' ) . '<span class="acf-requires-pro">' . __( 'PRO', 'acf' ) . '</span>',
'target' => '_self',
);
}
if ( ! defined( 'PWP_NAME' ) ) {
$acf_wpengine_logo = acf_get_url( 'assets/images/wp-engine-horizontal-black.svg' );
$acf_wpengine_logo = sprintf( '<span><img class="acf-wp-engine-pro" src="%s" alt="WP Engine" /></span>', $acf_wpengine_logo );
$utm_content = acf_is_pro() ? 'acf_pro_plugin_topbar_dropdown_cta' : 'acf_free_plugin_topbar_dropdown_cta';
$wpengine_more_items[] = array(
'url' => acf_add_url_utm_tags( 'https://wpengine.com/plans/?coupon=freedomtocreate', 'bx_prod_referral', $utm_content, false, 'acf_plugin', 'referral' ),
'text' => $acf_wpengine_logo . '<span class="acf-wp-engine-upsell-pill">' . __( '4 Months Free', 'acf' ) . '</span>',
'target' => '_blank',
'li_class' => 'acf-wp-engine',
);
}
/**
* Filters the admin navigation more items.
*
* @since 5.9.0
*
* @param array $more_items The array of navigation tabs.
*/
$more_items = apply_filters( 'acf/admin/toolbar', $more_items );
// Bail early if set to false.
if ( $core_tabs === false ) {
return;
}
$acf_wpengine_logo_link = acf_add_url_utm_tags(
'https://wpengine.com/',
'bx_prod_referral',
acf_is_pro() ? 'acf_pro_plugin_topbar_logo' : 'acf_free_plugin_topbar_logo',
false,
'acf_plugin',
'referral'
);
/**
* Helper function for looping over the provided menu items
* and echoing out the necessary markup.
*
* @since 6.2
*
* @param array $menu_items An array of menu items to print.
* @param string $section The section being printed.
* @return void
*/
function acf_print_menu_section( $menu_items, $section = '' ) {
// Bail if no menu items.
if ( ! is_array( $menu_items ) || empty( $menu_items ) ) {
return;
}
$section_html = '';
foreach ( $menu_items as $menu_item ) {
$class = ! empty( $menu_item['class'] ) ? $menu_item['class'] : $menu_item['text'];
$target = ! empty( $menu_item['target'] ) ? ' target="' . esc_attr( $menu_item['target'] ) . '"' : '';
$li_class = ! empty( $menu_item['li_class'] ) ? $menu_item['li_class'] : '';
$html = sprintf(
'<a class="acf-tab%s %s" href="%s"%s><i class="acf-icon"></i>%s</a>',
! empty( $menu_item['is_active'] ) ? ' is-active' : '',
'acf-header-tab-' . acf_slugify( $class ),
esc_url( $menu_item['url'] ),
$target,
acf_esc_html( $menu_item['text'] )
);
if ( 'core' !== $section ) {
if ( $li_class === '' ) {
$html = '<li>' . $html . '</li>';
} else {
$html = sprintf( '<li class="%s">', $li_class ) . $html . '</li>';
}
}
$section_html .= $html;
}
echo $section_html;
}
?>
<div class="acf-admin-toolbar">
<div class="acf-admin-toolbar-inner">
<div class="acf-nav-wrap">
<a href="<?php echo admin_url( 'edit.php?post_type=acf-field-group' ); ?>" class="acf-logo">
<img src="<?php echo acf_get_url( 'assets/images/acf-logo.svg' ); ?>" alt="<?php esc_attr_e( 'Advanced Custom Fields logo', 'acf' ); ?>">
<?php if ( acf_is_pro() && acf_pro_is_license_active() ) { ?>
<div class="acf-pro-label">PRO</div>
<?php } ?>
</a>
<h2><?php echo acf_get_setting( 'name' ); ?></h2>
<?php acf_print_menu_section( $core_tabs, 'core' ); ?>
<?php if ( $acf_more_items || $more_items ) { ?>
<div class="acf-more acf-header-tab-acf-more" tabindex="0">
<span class="acf-tab acf-more-tab"><i class="acf-icon acf-icon-more"></i><?php esc_html_e( 'More', 'acf' ); ?> <i class="acf-icon acf-icon-dropdown"></i></span>
<ul>
<?php
if ( $acf_more_items ) {
if ( $more_items ) {
echo '<li class="acf-more-section-header"><span class="acf-tab acf-tab-header">ACF</span></li>';
}
acf_print_menu_section( $acf_more_items, 'acf' );
}
if ( $more_items ) {
echo '<li class="acf-more-section-header"><span class="acf-tab acf-tab-header">' . esc_html__( 'Other', 'acf' ) . ' </span></li>';
acf_print_menu_section( $more_items );
}
if ( $wpengine_more_items ) {
acf_print_menu_section( $wpengine_more_items );
}
?>
</ul>
</div>
<?php } ?>
</div>
<div class="acf-nav-upgrade-wrap">
<?php
if ( ! acf_is_pro() || ! acf_pro_is_license_active() ) {
$unlock_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'header' );
$unlock_target = '_blank';
$unlock_text = __( 'Unlock Extra Features with ACF PRO', 'acf' );
if ( acf_is_pro() ) {
if ( acf_is_updates_page_visible() ) {
$unlock_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates#acf_pro_license' );
$unlock_target = '';
}
if ( acf_pro_is_license_expired() ) {
$unlock_url = acf_add_url_utm_tags( acf_pro_get_manage_license_url(), 'ACF renewal', 'header' );
$unlock_target = '_blank';
$unlock_text = __( 'Renew ACF PRO License', 'acf' );
}
}
?>
<a target="<?php echo esc_attr( $unlock_target ); ?>" href="<?php echo esc_url( $unlock_url ); ?>" class="btn-upgrade acf-admin-toolbar-upgrade-btn">
<i class="acf-icon acf-icon-stars"></i>
<p><?php echo esc_html( $unlock_text ); ?></p>
</a>
<?php
}
?>
<a href="<?php echo $acf_wpengine_logo_link; ?>" target="_blank" class="acf-nav-wpengine-logo">
<img src="<?php echo esc_url( acf_get_url( 'assets/images/wp-engine-horizontal-white.svg' ) ); ?>" alt="<?php esc_html_e( 'WP Engine logo', 'acf' ); ?>" />
</a>
</div>
</div>
</div>
<?php
global $plugin_page;
$screen = get_current_screen();
if ( ! in_array( $screen->id, acf_get_internal_post_types(), true ) ) {
if ( $plugin_page == 'acf-tools' ) {
$acf_page_title = __( 'Tools', 'acf' );
} elseif ( $plugin_page == 'acf-settings-updates' ) {
$acf_page_title = __( 'Updates', 'acf' );
} elseif ( $plugin_page == 'acf_options_preview' && ! acf_is_pro() ) {
$acf_page_title = __( 'Options Pages', 'acf' );
}
acf_get_view( 'global/header' );
}
?>

View File

@ -0,0 +1,39 @@
<?php
$acf_learn_more_link = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'no-options-pages' );
$acf_upgrade_button = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'no-options-pages-pricing', 'pricing-table' );
$acf_options_pages_desc = sprintf(
/* translators: %s URL to ACF options pages documentation */
__( 'ACF <a href="%s" target="_blank">options pages</a> are custom admin pages for managing global settings via fields. You can create multiple pages and sub-pages.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/options-page/', 'docs', 'no-options-pages' )
);
$acf_getting_started = sprintf(
/* translators: %s url to getting started guide */
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-options-pages' )
);
?>
<div class="wrap acf_options_preview_wrap">
<table class="wp-list-table widefat fixed striped">
<tbody id="the-list">
<tr class="no-items">
<td class="colspanchange" colspan="6">
<div class="acf-no-field-groups-wrapper">
<div class="acf-no-field-groups-inner acf-field-group-pro-features-content">
<img src="<?php echo acf_get_url( 'assets/images/empty-post-types.svg' ); ?>" />
<h2><?php echo acf_esc_html( 'Upgrade to ACF PRO to create options pages in just a few clicks', 'acf' ); ?></h2>
<p><?php echo acf_esc_html( $acf_options_pages_desc ); ?></p>
<div class="acf-field-group-pro-features-actions">
<a target="_blank" href="<?php echo $acf_learn_more_link; ?>" class="acf-btn acf-btn-muted"><?php esc_html_e( 'Learn More', 'acf' ); ?> <i class="acf-icon acf-icon-arrow-up-right"></i></a>
<a target="_blank" href="<?php echo $acf_upgrade_button; ?>" class="acf-btn acf-options-pages-preview-upgrade-button"> <?php esc_html_e( 'Upgrade to ACF PRO', 'acf' ); ?> <i class="acf-icon acf-icon-arrow-up-right"></i></a>
</div>
<p class="acf-small"><?php echo acf_esc_html( $acf_getting_started ); ?></p>
</div>
</div>
</td>
</tr>
</tbody>
</table>
</div>

View File

@ -0,0 +1,35 @@
<?php
/**
* html-admin-tools
*
* View to output admin tools for both archive and single
*
* @date 20/10/17
* @since 5.6.3
*
* @param string $screen_id The screen ID used to display metaboxes
* @param string $active The active Tool
* @return n/a
*/
$class = $active ? 'single' : 'grid';
$tool = $active ? ' tool-' . $active : '';
?>
<div id="acf-admin-tools" class="wrap<?php echo esc_attr( $tool ); ?>">
<h1><?php _e( 'Tools', 'acf' ); ?> <?php
if ( $active ) :
?>
<a class="page-title-action" href="<?php echo acf_get_admin_tools_url(); ?>"><?php _e( 'Back to all tools', 'acf' ); ?></a><?php endif; ?></h1>
<div class="acf-meta-box-wrap -<?php echo $class; ?>">
<?php do_meta_boxes( $screen_id, 'normal', '' ); ?>
</div>
<?php
if ( ! acf_is_pro() ) {
acf_get_view( 'acf-field-group/pro-features' );
}
?>
</div>

View File

@ -0,0 +1,195 @@
<?php
/**
* Network Admin Database Upgrade
*
* Shows the databse upgrade process.
*
* @date 24/8/18
* @since 5.7.4
* @param void
*/
?>
<style type="text/css">
/* hide steps */
.show-on-complete {
display: none;
}
</style>
<div id="acf-upgrade-wrap" class="wrap">
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
<p><?php printf( __( 'The following sites require a DB upgrade. Check the ones you want to update and then click %s.', 'acf' ), '"' . __( 'Upgrade Sites', 'acf' ) . '"' ); ?></p>
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites"></p>
<table class="wp-list-table widefat">
<thead>
<tr>
<td class="manage-column check-column" scope="col">
<input type="checkbox" id="sites-select-all">
</td>
<th class="manage-column" scope="col" style="width:33%;">
<label for="sites-select-all"><?php _e( 'Site', 'acf' ); ?></label>
</th>
<th><?php _e( 'Description', 'acf' ); ?></th>
</tr>
</thead>
<tfoot>
<tr>
<td class="manage-column check-column" scope="col">
<input type="checkbox" id="sites-select-all-2">
</td>
<th class="manage-column" scope="col">
<label for="sites-select-all-2"><?php _e( 'Site', 'acf' ); ?></label>
</th>
<th><?php _e( 'Description', 'acf' ); ?></th>
</tr>
</tfoot>
<tbody id="the-list">
<?php
$sites = acf_get_sites();
if ( $sites ) :
foreach ( $sites as $i => $site ) :
// switch blog
switch_to_blog( $site['blog_id'] );
?>
<tr
<?php
if ( $i % 2 == 0 ) :
?>
class="alternate"<?php endif; ?>>
<th class="check-column" scope="row">
<?php if ( acf_has_upgrade() ) : ?>
<input type="checkbox" value="<?php echo $site['blog_id']; ?>" name="checked[]">
<?php endif; ?>
</th>
<td>
<strong><?php echo get_bloginfo( 'name' ); ?></strong><br /><?php echo home_url(); ?>
</td>
<td>
<?php if ( acf_has_upgrade() ) : ?>
<span class="response"><?php printf( __( 'Site requires database upgrade from %1$s to %2$s', 'acf' ), acf_get_db_version(), ACF_VERSION ); ?></span>
<?php else : ?>
<?php _e( 'Site is up to date', 'acf' ); ?>
<?php endif; ?>
</td>
</tr>
<?php
// restore
restore_current_blog();
endforeach;
endif;
?>
</tbody>
</table>
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites-2"></p>
<p class="show-on-complete"><?php printf( __( 'Database Upgrade complete. <a href="%s">Return to network dashboard</a>', 'acf' ), network_admin_url() ); ?></p>
<script type="text/javascript">
(function($) {
var upgrader = new acf.Model({
events: {
'click #upgrade-sites': 'onClick',
'click #upgrade-sites-2': 'onClick'
},
$inputs: function(){
return $('#the-list input:checked');
},
onClick: function( e, $el ){
// prevent default
e.preventDefault();
// bail early if no selection
if( !this.$inputs().length ) {
return alert('<?php _e( 'Please select at least one site to upgrade.', 'acf' ); ?>');
}
// confirm action
if( !confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>") ) {
return;
}
// upgrade
this.upgrade();
},
upgrade: function(){
// vars
var $inputs = this.$inputs();
// bail early if no sites selected
if( !$inputs.length ) {
return this.complete();
}
// disable buttons
$('.button').prop('disabled', true);
// vars
var $input = $inputs.first();
var $row = $input.closest('tr');
var text = '';
var success = false;
// show loading
$row.find('.response').html('<i class="acf-loading"></i></span> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?>');
// send ajax request to upgrade DB
$.ajax({
url: acf.get('ajaxurl'),
dataType: 'json',
type: 'post',
data: acf.prepareForAjax({
action: 'acf/ajax/upgrade',
blog_id: $input.val()
}),
success: function( json ){
success = true;
$input.remove();
text = '<?php _e( 'Upgrade complete.', 'acf' ); ?>';
},
error: function( jqXHR, textStatus, errorThrown ){
text = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
if( error = acf.getXhrError(jqXHR) ) {
text += ' <code>' + error + '</code>';
}
},
complete: this.proxy(function(){
// display text
$row.find('.response').html( text );
// if successful upgrade, proceed to next site. Otherwise, skip to complete.
if( success ) {
this.upgrade();
} else {
this.complete();
}
})
});
},
complete: function(){
// enable buttons
$('.button').prop('disabled', false);
// show message
$('.show-on-complete').show();
}
});
})(jQuery);
</script>
</div>

View File

@ -0,0 +1,48 @@
<?php
// calculate add-ons (non pro only)
$plugins = array();
if ( ! acf_get_setting( 'pro' ) ) {
if ( is_plugin_active( 'acf-repeater/acf-repeater.php' ) ) {
$plugins[] = __( 'Repeater', 'acf' );
}
if ( is_plugin_active( 'acf-flexible-content/acf-flexible-content.php' ) ) {
$plugins[] = __( 'Flexible Content', 'acf' );
}
if ( is_plugin_active( 'acf-gallery/acf-gallery.php' ) ) {
$plugins[] = __( 'Gallery', 'acf' );
}
if ( is_plugin_active( 'acf-options-page/acf-options-page.php' ) ) {
$plugins[] = __( 'Options Page', 'acf' );
}
}
?>
<div id="acf-upgrade-notice" class="notice">
<div class="notice-container">
<div class="col-content">
<img src="<?php echo acf_get_url( 'assets/images/acf-logo.png' ); ?>" />
<h2><?php _e( 'Database Upgrade Required', 'acf' ); ?></h2>
<p><?php printf( __( 'Thank you for updating to %1$s v%2$s!', 'acf' ), acf_get_setting( 'name' ), acf_get_setting( 'version' ) ); ?><br /><?php _e( 'This version contains improvements to your database and requires an upgrade.', 'acf' ); ?></p>
<?php if ( ! empty( $plugins ) ) : ?>
<p><?php printf( __( 'Please also check all premium add-ons (%s) are updated to the latest version.', 'acf' ), implode( ', ', $plugins ) ); ?></p>
<?php endif; ?>
</div>
<div class="col-actions">
<a id="acf-upgrade-button" href="<?php echo $button_url; ?>" class="acf-btn"><?php echo $button_text; ?></a>
</div>
</div>
</div>
<?php if ( $confirm ) : ?>
<script type="text/javascript">
(function($) {
$("#acf-upgrade-button").on("click", function(){
return confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>");
});
})(jQuery);
</script>
<?php endif; ?>

View File

@ -0,0 +1,97 @@
<?php
/**
* Admin Database Upgrade
*
* Shows the databse upgrade process.
*
* @date 24/8/18
* @since 5.7.4
* @param void
*/
?>
<style type="text/css">
/* hide steps */
.step-1,
.step-2,
.step-3 {
display: none;
}
</style>
<div id="acf-upgrade-wrap" class="wrap">
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
<?php if ( acf_has_upgrade() ) : ?>
<p><?php _e( 'Reading upgrade tasks...', 'acf' ); ?></p>
<p class="step-1"><i class="acf-loading"></i> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?></p>
<p class="step-2"></p>
<p class="step-3"><?php printf( __( 'Database upgrade complete. <a href="%s">See what\'s new</a>', 'acf' ), admin_url( 'edit.php?post_type=acf-field-group' ) ); ?></p>
<script type="text/javascript">
(function($) {
var upgrader = new acf.Model({
initialize: function(){
// allow user to read message for 1 second
this.setTimeout( this.upgrade, 1000 );
},
upgrade: function(){
// show step 1
$('.step-1').show();
// vars
var response = '';
var success = false;
// send ajax request to upgrade DB
$.ajax({
url: acf.get('ajaxurl'),
dataType: 'json',
type: 'post',
data: acf.prepareForAjax({
action: 'acf/ajax/upgrade'
}),
success: function( json ){
success = true;
},
error: function( jqXHR, textStatus, errorThrown ){
response = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
if( error = acf.getXhrError(jqXHR) ) {
response += ' <code>' + error + '</code>';
}
},
complete: this.proxy(function(){
// remove spinner
$('.acf-loading').hide();
// display response
if( response ) {
$('.step-2').show().html( response );
}
// display success
if( success ) {
$('.step-3').show();
}
})
});
}
});
})(jQuery);
</script>
<?php else : ?>
<p><?php _e( 'No updates available.', 'acf' ); ?></p>
<?php endif; ?>
</div>