first commit
This commit is contained in:
333
wp-content/plugins/advanced-custom-fields-pro/pro/acf-pro.php
Normal file
333
wp-content/plugins/advanced-custom-fields-pro/pro/acf-pro.php
Normal file
@@ -0,0 +1,333 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_pro' ) ) :
|
||||
|
||||
/**
|
||||
* The main ACF PRO class.
|
||||
*/
|
||||
class acf_pro {
|
||||
|
||||
/**
|
||||
* Main ACF PRO constructor
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
// constants
|
||||
acf()->define( 'ACF_PRO', true );
|
||||
|
||||
// update setting
|
||||
acf_update_setting( 'pro', true );
|
||||
acf_update_setting( 'name', 'Advanced Custom Fields PRO' );
|
||||
|
||||
// includes
|
||||
acf_include( 'pro/blocks.php' );
|
||||
acf_include( 'pro/options-page.php' );
|
||||
acf_include( 'pro/acf-ui-options-page-functions.php' );
|
||||
acf_include( 'pro/updates.php' );
|
||||
|
||||
if ( is_admin() ) {
|
||||
acf_include( 'pro/admin/admin-options-page.php' );
|
||||
acf_include( 'pro/admin/admin-updates.php' );
|
||||
}
|
||||
|
||||
// actions
|
||||
add_action( 'init', array( $this, 'register_assets' ) );
|
||||
add_action( 'acf/init', array( $this, 'update_plugin_name' ) );
|
||||
add_action( 'woocommerce_init', array( $this, 'init_hpos_integration' ), 99 );
|
||||
add_action( 'acf/init_internal_post_types', array( $this, 'register_ui_options_pages' ) );
|
||||
add_action( 'acf/include_fields', array( $this, 'include_options_pages' ) );
|
||||
add_action( 'acf/include_field_types', array( $this, 'include_field_types' ), 5 );
|
||||
add_action( 'acf/include_location_rules', array( $this, 'include_location_rules' ), 5 );
|
||||
add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'input_admin_enqueue_scripts' ) );
|
||||
add_action( 'acf/field_group/admin_enqueue_scripts', array( $this, 'field_group_admin_enqueue_scripts' ) );
|
||||
add_action( 'acf/in_admin_header', array( $this, 'maybe_show_license_status_error' ) );
|
||||
add_action( 'acf/internal_post_type/current_screen', array( $this, 'invalid_license_redirect' ) );
|
||||
add_action( 'acf/internal_post_type_list/current_screen', array( $this, 'invalid_license_redirect_notice' ) );
|
||||
|
||||
// Add filters.
|
||||
add_filter( 'posts_where', array( $this, 'posts_where' ), 10, 2 );
|
||||
add_filter( 'acf/internal_post_type/admin_body_classes', array( $this, 'admin_body_classes' ) );
|
||||
add_filter( 'acf/internal_post_type_list/admin_body_classes', array( $this, 'admin_body_classes' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the plugin name to make it translatable.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function update_plugin_name() {
|
||||
acf_update_setting( 'name', __( 'Advanced Custom Fields PRO', 'acf' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Initializes the ACF WooCommerce HPOS integration.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function init_hpos_integration() {
|
||||
acf_new_instance( 'ACF\Pro\Meta\WooOrder' );
|
||||
acf_new_instance( 'ACF\Pro\Forms\WC_Order' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the `acf-ui-options-page` post type and initializes the UI.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function register_ui_options_pages() {
|
||||
if ( ! acf_get_setting( 'enable_options_pages_ui' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
acf_include( 'pro/post-types/acf-ui-options-page.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Action to include JSON options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function include_options_pages() {
|
||||
/**
|
||||
* Fires during initialization. Used to add JSON options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param int ACF_MAJOR_VERSION The major version of ACF.
|
||||
*/
|
||||
do_action( 'acf/include_options_pages', ACF_MAJOR_VERSION );
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes any files necessary for field types.
|
||||
*
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function include_field_types() {
|
||||
acf_include( 'pro/fields/class-acf-repeater-table.php' );
|
||||
acf_include( 'pro/fields/class-acf-field-repeater.php' );
|
||||
acf_include( 'pro/fields/class-acf-field-flexible-content.php' );
|
||||
acf_include( 'pro/fields/class-acf-field-gallery.php' );
|
||||
acf_include( 'pro/fields/class-acf-field-clone.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes location rules for ACF PRO.
|
||||
*
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function include_location_rules() {
|
||||
acf_include( 'pro/locations/class-acf-location-block.php' );
|
||||
acf_include( 'pro/locations/class-acf-location-options-page.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers styles and scripts used by ACF PRO.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function register_assets() {
|
||||
$version = acf_get_setting( 'version' );
|
||||
$min = defined( 'ACF_DEVELOPMENT_MODE' ) && ACF_DEVELOPMENT_MODE ? '' : '.min';
|
||||
|
||||
// Register scripts.
|
||||
wp_register_script( 'acf-pro-input', acf_get_url( "assets/build/js/pro/acf-pro-input{$min}.js" ), array( 'acf-input' ), $version );
|
||||
wp_register_script( 'acf-pro-field-group', acf_get_url( "assets/build/js/pro/acf-pro-field-group{$min}.js" ), array( 'acf-field-group' ), $version );
|
||||
wp_register_script( 'acf-pro-ui-options-page', acf_get_url( "assets/build/js/pro/acf-pro-ui-options-page{$min}.js" ), array( 'acf-input' ), $version );
|
||||
|
||||
// Register styles.
|
||||
wp_register_style( 'acf-pro-input', acf_get_url( 'assets/build/css/pro/acf-pro-input' . $min . '.css' ), array( 'acf-input' ), $version );
|
||||
wp_register_style( 'acf-pro-field-group', acf_get_url( 'assets/build/css/pro/acf-pro-field-group' . $min . '.css' ), array( 'acf-input' ), $version );
|
||||
|
||||
if ( is_admin() ) {
|
||||
$to_localize = array(
|
||||
'isLicenseActive' => acf_pro_is_license_active(),
|
||||
'isLicenseExpired' => acf_pro_is_license_expired(),
|
||||
);
|
||||
|
||||
acf_localize_data( $to_localize );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the PRO admin screen scripts and styles
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function input_admin_enqueue_scripts() {
|
||||
wp_enqueue_script( 'acf-pro-input' );
|
||||
wp_enqueue_script( 'acf-pro-ui-options-page' );
|
||||
wp_enqueue_style( 'acf-pro-input' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueue the PRO field group scripts and styles
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function field_group_admin_enqueue_scripts() {
|
||||
wp_enqueue_script( 'acf-pro-field-group' );
|
||||
wp_enqueue_style( 'acf-pro-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for a license status error and renders it if necessary.
|
||||
*
|
||||
* @since 6.2.1
|
||||
*/
|
||||
public function maybe_show_license_status_error() {
|
||||
$license_status = acf_pro_get_license_status();
|
||||
$defined_license_errors = acf_pro_get_activation_failure_transient();
|
||||
$manage_url = false;
|
||||
|
||||
if ( ! acf_pro_get_license_key( true ) && ! defined( 'ACF_PRO_LICENSE' ) ) {
|
||||
$error_msg = __( 'Activate your license to enable access to updates, support & PRO features.', 'acf' );
|
||||
$manage_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates#acf_pro_license' );
|
||||
} elseif ( acf_pro_is_license_expired( $license_status ) ) {
|
||||
$error_msg = __( 'Your license has expired. Please renew to continue to have access to updates, support & PRO features.', 'acf' );
|
||||
$manage_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates' );
|
||||
} elseif ( acf_pro_was_license_refunded( $license_status ) ) {
|
||||
$error_msg = __( 'Your ACF PRO license is no longer active. Please renew to continue to have access to updates, support, & PRO features.', 'acf' );
|
||||
$manage_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates' );
|
||||
} elseif ( ! empty( $defined_license_errors ) ) {
|
||||
$error_msg = $defined_license_errors['error'];
|
||||
} elseif ( ! empty( $license_status['error_msg'] ) ) {
|
||||
$error_msg = $license_status['error_msg'];
|
||||
} else {
|
||||
// No errors to show.
|
||||
return;
|
||||
}
|
||||
|
||||
if ( acf_pro_is_updates_page_visible() && ! empty( $manage_url ) && 'acf-settings-updates' !== acf_request_arg( 'page' ) ) {
|
||||
$manage_link = sprintf(
|
||||
'<a href="%1$s">%2$s</a>',
|
||||
esc_url( $manage_url ),
|
||||
__( 'Manage License', 'acf' )
|
||||
);
|
||||
|
||||
$error_msg .= ' ' . $manage_link;
|
||||
}
|
||||
|
||||
acf_add_admin_notice( $error_msg, 'warning', false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects back to the list table when editing an unauthorized item with an invalid license.
|
||||
*
|
||||
* @since 6.2.8
|
||||
*
|
||||
* @param string $post_type The post type being edited.
|
||||
* @return void
|
||||
*/
|
||||
public function invalid_license_redirect( string $post_type ) {
|
||||
if ( ! in_array( $post_type, array( 'acf-field-group', 'acf-ui-options-page' ), true ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Active licenses have no restrictions.
|
||||
if ( acf_pro_is_license_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// The post being edited.
|
||||
$current_post = (int) acf_request_arg( 'post', 0 );
|
||||
|
||||
if ( 'acf-ui-options-page' === $post_type ) {
|
||||
// Only existing options pages can be edited with an expired license.
|
||||
if ( $current_post && acf_pro_is_license_expired() ) {
|
||||
return;
|
||||
}
|
||||
} elseif ( 'acf-field-group' === $post_type ) {
|
||||
// Expired licenses can edit new/existing field groups regardless of block locations.
|
||||
if ( acf_pro_is_license_expired() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No block locations, should still be able to edit.
|
||||
if ( ! acf_field_group_has_location_type( $current_post, 'block' ) ) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
// Redirect back to field groups list table.
|
||||
wp_safe_redirect( admin_url( 'edit.php?acf_invalid_license=true&post_type=' . $post_type ) );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a notice if a user has attempted to edit an ACF item without a valid license.
|
||||
*
|
||||
* @since 6.2.8
|
||||
*
|
||||
* @param string $post_type The post type being edited.
|
||||
* @return void
|
||||
*/
|
||||
public function invalid_license_redirect_notice( string $post_type ) {
|
||||
if ( ! acf_request_arg( 'acf_invalid_license', false ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( 'acf-field-group' === $post_type ) {
|
||||
acf_add_admin_notice( __( 'A valid license is required to edit field groups assigned to a block.', 'acf' ), 'error' );
|
||||
} elseif ( 'acf-ui-options-page' === $post_type ) {
|
||||
acf_add_admin_notice( __( 'A valid license is required to edit options pages.', 'acf' ), 'error' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $where clause allowing for custom WP_Query args.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param string $where The WHERE clause.
|
||||
* @param WP_Query $wp_query The query object.
|
||||
* @return string
|
||||
*/
|
||||
public function posts_where( $where, $wp_query ) {
|
||||
global $wpdb;
|
||||
|
||||
$options_page_key = $wp_query->get( 'acf_ui_options_page_key' );
|
||||
|
||||
// Add custom "acf_options_page_key" arg.
|
||||
if ( $options_page_key ) {
|
||||
$where .= $wpdb->prepare( " AND {$wpdb->posts}.post_name = %s", $options_page_key );
|
||||
}
|
||||
|
||||
return $where;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds admin body classes to ACF post types and post type list pages.
|
||||
*
|
||||
* @since 6.2.5
|
||||
*
|
||||
* @param string $classes The existing body classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_classes( $classes ) {
|
||||
if ( acf_pro_is_license_expired() ) {
|
||||
$classes .= ' acf-pro-expired-license';
|
||||
} elseif ( ! acf_pro_is_license_active() ) {
|
||||
$classes .= ' acf-pro-inactive-license';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// instantiate
|
||||
new acf_pro();
|
||||
|
||||
|
||||
// end class
|
||||
endif;
|
||||
@@ -0,0 +1,272 @@
|
||||
<?php
|
||||
/**
|
||||
* Helper/wrapper Functions for ACF UI Options pages.
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get an ACF UI options page as an array
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The post ID being queried.
|
||||
* @return array|false The UI options page array.
|
||||
*/
|
||||
function acf_get_ui_options_page( $id ) {
|
||||
return acf_get_internal_post_type( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a raw ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The post ID.
|
||||
* @return array|false The UI options page array.
|
||||
*/
|
||||
function acf_get_raw_ui_options_page( $id ) {
|
||||
return acf_get_raw_internal_post_type( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post object for an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The post ID, key, or name.
|
||||
* @return object|boolean The post object, or false on failure.
|
||||
*/
|
||||
function acf_get_ui_options_page_post( $id ) {
|
||||
return acf_get_internal_post_type_post( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given identifier is an ACF UI options page key.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @return boolean
|
||||
*/
|
||||
function acf_is_ui_options_page_key( $id ) {
|
||||
return acf_is_internal_post_type_key( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array to validate.
|
||||
* @return array|boolean
|
||||
*/
|
||||
function acf_validate_ui_options_page( array $ui_options_page = array() ) {
|
||||
return acf_validate_internal_post_type( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the settings for an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_translate_ui_options_page( array $ui_options_page ) {
|
||||
return acf_translate_internal_post_type( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and array of ACF UI options pages for the given $filter.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $filter An array of args to filter results by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_ui_options_pages( array $filter = array() ) {
|
||||
return acf_get_internal_post_type_posts( 'acf-ui-options-page', $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of raw ACF UI options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_raw_ui_options_pages() {
|
||||
return acf_get_raw_internal_post_type_posts( 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered array of ACF UI options pages based on the given $args.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_pages An array of ACF UI options pages.
|
||||
* @param array $args An array of args to filter by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_ui_options_pages( array $ui_options_pages, array $args = array() ) {
|
||||
return acf_filter_internal_post_type_posts( $ui_options_pages, $args, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an ACF UI options page in the database.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The main ACF UI options page array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_update_ui_options_page( array $ui_options_page ) {
|
||||
return acf_update_internal_post_type( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all caches for the provided ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_ui_options_page_cache( array $ui_options_page ) {
|
||||
acf_flush_internal_post_type_cache( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an ACF UI options page from the database.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The ACF UI options page ID, key or name.
|
||||
* @return boolean True if the options page was deleted.
|
||||
*/
|
||||
function acf_delete_ui_options_page( $id = 0 ) {
|
||||
return acf_delete_internal_post_type( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The UI options page ID, key, or name.
|
||||
* @return boolean True if the options page was trashed.
|
||||
*/
|
||||
function acf_trash_ui_options_page( $id = 0 ) {
|
||||
return acf_trash_internal_post_type( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an ACF UI options page from the trash.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The UI options page ID, key, or name.
|
||||
* @return boolean True if the options page was untrashed.
|
||||
*/
|
||||
function acf_untrash_ui_options_page( $id = 0 ) {
|
||||
return acf_untrash_internal_post_type( $id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given params match an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return boolean
|
||||
*/
|
||||
function acf_is_ui_options_page( $ui_options_page ) {
|
||||
return acf_is_internal_post_type( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The ACF UI options page ID, key or name.
|
||||
* @param integer $new_post_id Optional ID to override.
|
||||
* @return array|boolean The new ACF UI options page, or false on failure.
|
||||
*/
|
||||
function acf_duplicate_ui_options_page( $id = 0, $new_post_id = 0 ) {
|
||||
return acf_duplicate_internal_post_type( $id, $new_post_id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates an ACF UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer|string $id The ACF UI options page ID, key or name.
|
||||
* @param boolean $activate True if the UI options page should be activated.
|
||||
* @return boolean
|
||||
*/
|
||||
function acf_update_ui_options_page_active_status( $id, $activate = true ) {
|
||||
return acf_update_internal_post_type_active_status( $id, $activate, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can edit the UI options page and returns the edit URL.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer $post_id The ACF UI options page ID.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_ui_options_page_edit_link( $post_id ) {
|
||||
return acf_get_internal_post_type_edit_link( $post_id, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified ACF UI options page ready for export.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_ui_options_page_for_export( array $ui_options_page = array() ) {
|
||||
return acf_prepare_internal_post_type_for_export( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports an ACF UI options page as PHP.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return string|boolean
|
||||
*/
|
||||
function acf_export_ui_options_page_as_php( array $ui_options_page ) {
|
||||
return acf_export_internal_post_type_as_php( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an ACF UI options page for the import process.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_ui_options_page_for_import( array $ui_options_page = array() ) {
|
||||
return acf_prepare_internal_post_type_for_import( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an ACF UI options page into the database.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $ui_options_page The ACF UI options page array.
|
||||
* @return array The imported options page.
|
||||
*/
|
||||
function acf_import_ui_options_page( array $ui_options_page ) {
|
||||
return acf_import_internal_post_type( $ui_options_page, 'acf-ui-options-page' );
|
||||
}
|
||||
@@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'acf_admin_options_page' ) ) :
|
||||
|
||||
class acf_admin_options_page {
|
||||
|
||||
/** @var array Contains the current options page */
|
||||
var $page;
|
||||
|
||||
|
||||
/**
|
||||
* Initialize filters, action, variables and includes
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function __construct() {
|
||||
// add menu items
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ), 99, 0 );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function admin_menu() {
|
||||
|
||||
// vars
|
||||
$pages = acf_get_options_pages();
|
||||
|
||||
// bail early if no pages
|
||||
if ( empty( $pages ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $pages as $page ) {
|
||||
|
||||
// vars
|
||||
$slug = '';
|
||||
// parent
|
||||
if ( empty( $page['parent_slug'] ) ) {
|
||||
$slug = add_menu_page( $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array( $this, 'html' ), $page['icon_url'], $page['position'] );
|
||||
// child
|
||||
} else {
|
||||
$slug = add_submenu_page( $page['parent_slug'], $page['page_title'], $page['menu_title'], $page['capability'], $page['menu_slug'], array( $this, 'html' ), $page['position'] );
|
||||
}
|
||||
|
||||
// actions
|
||||
add_action( "load-{$slug}", array( $this, 'admin_load' ) );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 2/02/13
|
||||
* @since 3.6
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function admin_load() {
|
||||
|
||||
// globals
|
||||
global $plugin_page;
|
||||
|
||||
// vars
|
||||
$this->page = acf_get_options_page( $plugin_page );
|
||||
|
||||
// get post_id (allow lang modification)
|
||||
$this->page['post_id'] = acf_get_valid_post_id( $this->page['post_id'] );
|
||||
|
||||
// verify and remove nonce
|
||||
if ( acf_verify_nonce( 'options' ) ) {
|
||||
|
||||
// save data
|
||||
if ( acf_validate_save_post( true ) ) {
|
||||
|
||||
// set autoload
|
||||
acf_update_setting( 'autoload', $this->page['autoload'] );
|
||||
|
||||
// save
|
||||
acf_save_post( $this->page['post_id'] );
|
||||
|
||||
/**
|
||||
* Fires after publishing a save on an options page.
|
||||
*
|
||||
* @since 6.1.7
|
||||
*
|
||||
* @param string|int $post_id The current id.
|
||||
* @param string $menu_slug The current options page menu slug.
|
||||
*/
|
||||
do_action( 'acf/options_page/save', $this->page['post_id'], $this->page['menu_slug'] );
|
||||
|
||||
// redirect
|
||||
wp_safe_redirect( add_query_arg( array( 'message' => '1' ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
// load acf scripts
|
||||
acf_enqueue_scripts();
|
||||
|
||||
// actions
|
||||
add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'acf/input/admin_head', array( $this, 'admin_head' ) );
|
||||
|
||||
// add columns support
|
||||
add_screen_option(
|
||||
'layout_columns',
|
||||
array(
|
||||
'max' => 2,
|
||||
'default' => 2,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will enqueue the 'post.js' script which adds support for 'Screen Options' column toggle
|
||||
*
|
||||
* @since 5.3.2
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
|
||||
wp_enqueue_script( 'post' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This action will find and add field groups to the current edit page
|
||||
*
|
||||
* @type action (admin_head)
|
||||
* @since 3.1.8
|
||||
*/
|
||||
public function admin_head() {
|
||||
|
||||
// get field groups
|
||||
$field_groups = acf_get_field_groups(
|
||||
array(
|
||||
'options_page' => $this->page['menu_slug'],
|
||||
)
|
||||
);
|
||||
|
||||
// notices
|
||||
if ( ! empty( $_GET['message'] ) && $_GET['message'] == '1' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Used to display a notice.
|
||||
acf_add_admin_notice( $this->page['updated_message'], 'success' );
|
||||
}
|
||||
|
||||
// add submit div
|
||||
add_meta_box( 'submitdiv', __( 'Publish', 'acf' ), array( $this, 'postbox_submitdiv' ), 'acf_options_page', 'side', 'high' );
|
||||
|
||||
if ( empty( $field_groups ) ) {
|
||||
acf_add_admin_notice( sprintf( __( 'No Custom Field Groups found for this options page. <a href="%s">Create a Custom Field Group</a>', 'acf' ), admin_url( 'post-new.php?post_type=acf-field-group' ) ), 'warning' );
|
||||
} else {
|
||||
foreach ( $field_groups as $i => $field_group ) {
|
||||
|
||||
// vars
|
||||
$id = "acf-{$field_group['key']}";
|
||||
$title = $field_group['title'];
|
||||
$context = $field_group['position'];
|
||||
$priority = 'high';
|
||||
$args = array( 'field_group' => $field_group );
|
||||
|
||||
// tweaks to vars
|
||||
if ( $context == 'acf_after_title' ) {
|
||||
$context = 'normal';
|
||||
} elseif ( $context == 'side' ) {
|
||||
$priority = 'core';
|
||||
}
|
||||
|
||||
// filter for 3rd party customization
|
||||
$priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
|
||||
|
||||
// add meta box
|
||||
add_meta_box( $id, acf_esc_html( $title ), array( $this, 'postbox_acf' ), 'acf_options_page', $context, $priority, $args );
|
||||
}
|
||||
// foreach
|
||||
}
|
||||
// if
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will render the submitdiv metabox
|
||||
*
|
||||
* @type function
|
||||
* @date 23/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function postbox_submitdiv( $post, $args ) {
|
||||
|
||||
/**
|
||||
* Fires before the major-publishing-actions div.
|
||||
*
|
||||
* @date 24/9/18
|
||||
* @since 5.7.7
|
||||
*
|
||||
* @param array $page The current options page.
|
||||
*/
|
||||
do_action( 'acf/options_page/submitbox_before_major_actions', $this->page );
|
||||
?>
|
||||
<div id="major-publishing-actions">
|
||||
|
||||
<div id="publishing-action">
|
||||
<span class="spinner"></span>
|
||||
<input type="submit" accesskey="p" value="<?php echo esc_attr( $this->page['update_button'] ); ?>" class="button button-primary button-large" id="publish" name="publish">
|
||||
</div>
|
||||
|
||||
<?php
|
||||
/**
|
||||
* Fires before the major-publishing-actions div.
|
||||
*
|
||||
* @date 24/9/18
|
||||
* @since 5.7.7
|
||||
*
|
||||
* @param array $page The current options page.
|
||||
*/
|
||||
do_action( 'acf/options_page/submitbox_major_actions', $this->page );
|
||||
?>
|
||||
<div class="clear"></div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders a postbox on an ACF options page.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param object $post The post object
|
||||
* @param array $args The metabox arguments
|
||||
*/
|
||||
public function postbox_acf( $post, $args ) {
|
||||
$id = $args['id'];
|
||||
$field_group = $args['args']['field_group'];
|
||||
|
||||
// vars
|
||||
$o = array(
|
||||
'id' => $id,
|
||||
'key' => $field_group['key'],
|
||||
'style' => $field_group['style'],
|
||||
'label' => $field_group['label_placement'],
|
||||
'editLink' => '',
|
||||
'editTitle' => __( 'Edit field group', 'acf' ),
|
||||
'visibility' => true,
|
||||
);
|
||||
|
||||
// edit_url
|
||||
if ( $field_group['ID'] && acf_current_user_can_admin() ) {
|
||||
$o['editLink'] = admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' );
|
||||
}
|
||||
|
||||
// load fields
|
||||
$fields = acf_get_fields( $field_group );
|
||||
|
||||
// render
|
||||
acf_render_fields( $fields, $this->page['post_id'], 'div', $field_group['instruction_placement'] );
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
if( typeof acf !== 'undefined' ) {
|
||||
|
||||
acf.newPostbox(<?php echo json_encode( $o ); ?>);
|
||||
|
||||
}
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @since 2.0.4
|
||||
*/
|
||||
function html() {
|
||||
|
||||
// load view
|
||||
acf_get_view( __DIR__ . '/views/html-options-page.php', $this->page );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
new acf_admin_options_page();
|
||||
endif;
|
||||
|
||||
?>
|
||||
@@ -0,0 +1,270 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Updates' ) ) :
|
||||
|
||||
class ACF_Admin_Updates {
|
||||
|
||||
/** @var array Data used in the view. */
|
||||
var $view = array();
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* Sets up the class functionality.
|
||||
*
|
||||
* @date 23/06/12
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
|
||||
// Add actions.
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ), 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* display_wp_error
|
||||
*
|
||||
* Adds an admin notice using the provided WP_Error.
|
||||
*
|
||||
* @date 14/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param WP_Error $wp_error The error to display.
|
||||
* @return void
|
||||
*/
|
||||
function display_wp_error( $wp_error ) {
|
||||
|
||||
// Only show one error on page.
|
||||
if ( acf_has_done( 'display_wp_error' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create new notice.
|
||||
acf_new_admin_notice(
|
||||
array(
|
||||
'text' => __( '<strong>Error</strong>. Could not connect to the update server', 'acf' ) . ' <span class="description">(' . esc_html( $wp_error->get_error_message() ) . ').</span>',
|
||||
'type' => 'error',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* get_changelog_changes
|
||||
*
|
||||
* Finds the specific changes for a given version from the provided changelog snippet.
|
||||
*
|
||||
* @date 14/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $changelog The changelog text.
|
||||
* @param string $version The version to find.
|
||||
* @return string
|
||||
*/
|
||||
function get_changelog_changes( $changelog = '', $version = '' ) {
|
||||
|
||||
// Explode changelog into sections.
|
||||
$bits = array_filter( explode( '<h4>', $changelog ) );
|
||||
|
||||
// Loop over each version chunk.
|
||||
foreach ( $bits as $bit ) {
|
||||
|
||||
// Find the version number for this chunk.
|
||||
$bit = explode( '</h4>', $bit );
|
||||
$bit_version = trim( $bit[0] );
|
||||
$bit_text = trim( $bit[1] );
|
||||
|
||||
// Compare the chunk version number against param and return HTML.
|
||||
if ( acf_version_compare( $bit_version, '==', $version ) ) {
|
||||
return '<h4>' . esc_html( $bit_version ) . '</h4>' . acf_esc_html( $bit_text );
|
||||
}
|
||||
}
|
||||
|
||||
// Return.
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_menu
|
||||
*
|
||||
* Adds the admin menu subpage.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function admin_menu() {
|
||||
|
||||
// Bail early if no show_admin.
|
||||
if ( ! acf_get_setting( 'show_admin' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail early if the updates page is not visible.
|
||||
if ( ! acf_pro_is_updates_page_visible() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add submenu.
|
||||
$page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Updates', 'acf' ), __( 'Updates', 'acf' ), acf_get_setting( 'capability' ), 'acf-settings-updates', array( $this, 'html' ) );
|
||||
|
||||
// Add actions to page.
|
||||
add_action( "load-$page", array( $this, 'load' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* load
|
||||
*
|
||||
* Runs when loading the submenu page.
|
||||
*
|
||||
* @date 7/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function load() {
|
||||
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
|
||||
// Check activate.
|
||||
if ( acf_verify_nonce( 'activate_pro_license' ) && ! empty( $_POST['acf_pro_license'] ) ) {
|
||||
acf_pro_activate_license( sanitize_text_field( $_POST['acf_pro_license'] ) ); //phpcs:ignore WordPress.Security.ValidatedSanitizedInput.MissingUnslash -- unslash not needed.
|
||||
|
||||
// Check deactivate.
|
||||
} elseif ( acf_verify_nonce( 'deactivate_pro_license' ) ) {
|
||||
acf_pro_deactivate_license();
|
||||
}
|
||||
|
||||
// Check if we should force check the license status.
|
||||
$force_get_license_status = false;
|
||||
$retry_license_nonce = acf_request_arg( 'acf_retry_nonce' );
|
||||
if ( wp_verify_nonce( $retry_license_nonce, 'acf_recheck_status' ) || ! empty( $_GET['force-license-check'] ) ) {
|
||||
$force_get_license_status = true;
|
||||
}
|
||||
|
||||
// vars
|
||||
$license = acf_pro_get_license_key();
|
||||
$this->view = array(
|
||||
'license' => $license,
|
||||
'license_status' => acf_pro_get_license_status( $force_get_license_status ),
|
||||
'active' => $license ? 1 : 0,
|
||||
'current_version' => acf_get_setting( 'version' ),
|
||||
'remote_version' => '',
|
||||
'update_available' => false,
|
||||
'changelog' => '',
|
||||
'upgrade_notice' => '',
|
||||
'is_defined_license' => defined( 'ACF_PRO_LICENSE' ) && ! empty( ACF_PRO_LICENSE ) && is_string( ACF_PRO_LICENSE ),
|
||||
'license_error' => false,
|
||||
'wp_not_compatible' => false,
|
||||
);
|
||||
|
||||
// get plugin updates
|
||||
$force_check = ! empty( $_GET['force-check'] );
|
||||
$info = acf_updates()->get_plugin_info( 'pro', $force_check );
|
||||
|
||||
// Display error.
|
||||
if ( is_wp_error( $info ) ) {
|
||||
return $this->display_wp_error( $info );
|
||||
}
|
||||
|
||||
// add info to view
|
||||
$this->view['remote_version'] = $info['version'];
|
||||
|
||||
// add changelog if the remote version is '>' than the current version
|
||||
$version = acf_get_setting( 'version' );
|
||||
|
||||
// check if remote version is higher than current version
|
||||
if ( version_compare( $info['version'], $version, '>' ) ) {
|
||||
|
||||
// update view.
|
||||
$this->view['update_available'] = true;
|
||||
$this->view['changelog'] = $this->get_changelog_changes( $info['changelog'], $info['version'] );
|
||||
$this->view['upgrade_notice'] = $this->get_changelog_changes( $info['upgrade_notice'], $info['version'] );
|
||||
|
||||
// perform update checks if license is active.
|
||||
$basename = acf_get_setting( 'basename' );
|
||||
$update = acf_updates()->get_plugin_update( $basename );
|
||||
$no_update = acf_updates()->get_no_update( $basename );
|
||||
|
||||
if ( $no_update && ! empty( $no_update['reason'] ) && $no_update['reason'] === 'wp_not_compatible' ) {
|
||||
$this->view['wp_not_compatible'] = true;
|
||||
acf_new_admin_notice(
|
||||
array(
|
||||
/* translators: %s the version of WordPress required for this ACF update */
|
||||
'text' => sprintf( __( 'An update to ACF is available, but it is not compatible with your version of WordPress. Please upgrade to WordPress %s or newer to update ACF.', 'acf' ), $no_update['requires'] ),
|
||||
'type' => 'error',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( $license ) {
|
||||
if ( isset( $update['license_valid'] ) && ! $update['license_valid'] ) {
|
||||
$this->view['license_error'] = true;
|
||||
acf_new_admin_notice(
|
||||
array(
|
||||
'text' => __( '<strong>Error</strong>. Your license for this site has expired or been deactivated. Please reactivate your ACF PRO license.', 'acf' ),
|
||||
'type' => 'error',
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// display error if no package url - possible if license key or site URL has been modified.
|
||||
if ( $update && ! $update['package'] ) {
|
||||
$this->view['license_error'] = true;
|
||||
acf_new_admin_notice(
|
||||
array(
|
||||
'text' => __( '<strong>Error</strong>. Could not authenticate update package. Please check again or deactivate and reactivate your ACF PRO license.', 'acf' ),
|
||||
'type' => 'error',
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// refresh transient - if no update exists in the transient or if the transient 'new_version' is stale.
|
||||
if ( ! $update || $update['new_version'] !== $info['version'] ) {
|
||||
acf_updates()->refresh_plugins_transient();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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;
|
||||
}
|
||||
|
||||
/**
|
||||
* html
|
||||
*
|
||||
* Displays the submenu page's HTML.
|
||||
*
|
||||
* @date 7/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function html() {
|
||||
acf_get_view( __DIR__ . '/views/html-settings-updates.php', $this->view );
|
||||
}
|
||||
}
|
||||
|
||||
// Initialize.
|
||||
acf_new_instance( 'ACF_Admin_Updates' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,489 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Admin Post Type Class
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_UI_Options_Page' ) ) :
|
||||
|
||||
/**
|
||||
* ACF Admin UI Options Page Class
|
||||
*
|
||||
* All the logic for editing an options page in the UI.
|
||||
*/
|
||||
class ACF_Admin_UI_Options_Page extends ACF_Admin_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-ui-options-page';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-single-options-page';
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'wp_ajax_acf/create_options_page', array( $this, 'ajax_create_options_page' ) );
|
||||
add_action( 'acf/field_group/admin_enqueue_scripts', array( $this, 'add_js_parent_choices' ) );
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the messages shown when editing a UI options page.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $messages Post type messages.
|
||||
* @return array
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages['acf-ui-options-page'] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => $this->options_page_created_message(), // Updated.
|
||||
2 => $this->options_page_created_message(),
|
||||
3 => __( 'Options page deleted.', 'acf' ),
|
||||
4 => __( 'Options page updated.', 'acf' ),
|
||||
5 => false, // Post type does not support revisions.
|
||||
6 => $this->options_page_created_message( true ), // Created.
|
||||
7 => __( 'Options page saved.', 'acf' ),
|
||||
8 => __( 'Options page submitted.', 'acf' ),
|
||||
9 => __( 'Options page scheduled for.', 'acf' ),
|
||||
10 => __( 'Options page draft updated.', 'acf' ),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the options page created message.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param boolean $created True if the options page was just created.
|
||||
* @return string
|
||||
*/
|
||||
public function options_page_created_message( $created = false ) {
|
||||
global $post_id;
|
||||
|
||||
$title = get_the_title( $post_id );
|
||||
|
||||
/* translators: %s options page name */
|
||||
$item_saved_text = sprintf( __( '%s options page updated', 'acf' ), $title );
|
||||
/* translators: %s options page name */
|
||||
$add_fields_text = sprintf( __( 'Add fields to %s', 'acf' ), $title );
|
||||
|
||||
if ( $created ) {
|
||||
/* translators: %s options page name */
|
||||
$item_saved_text = sprintf( __( '%s options page created', 'acf' ), $title );
|
||||
}
|
||||
|
||||
$add_fields_link = wp_nonce_url(
|
||||
admin_url( 'post-new.php?post_type=acf-field-group&use_options_page=' . $post_id ),
|
||||
'add-fields-' . $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 echo esc_html( $add_fields_text ); ?></a>
|
||||
<a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link existing field groups', 'acf' ); ?></a>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Allow other pages to get available option page parents.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function add_js_parent_choices() {
|
||||
acf_localize_data(
|
||||
array(
|
||||
'optionPageParentOptions' => $this->get_parent_page_choices(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any scripts necessary for internal post type.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
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/ui_options_page/admin_enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up all functionality for the post type edit page to work.
|
||||
*
|
||||
* @since 3.1.8
|
||||
*/
|
||||
public function admin_head() {
|
||||
// global.
|
||||
global $post, $acf_ui_options_page;
|
||||
|
||||
// set global var.
|
||||
$acf_ui_options_page = acf_get_internal_post_type( $post->ID, $this->post_type );
|
||||
|
||||
// metaboxes.
|
||||
add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'acf' ), array( $this, 'mb_basic_settings' ), 'acf-ui-options-page', 'normal', 'high' );
|
||||
add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'acf' ), array( $this, 'mb_advanced_settings' ), 'acf-ui-options-page', '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-ui-options-page', array( $this, 'screen_layout' ), 10, 1 );
|
||||
add_filter( 'get_user_option_metaboxhidden_acf-ui-options-page', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-ui-options-page', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-ui-options-page', array( $this, 'force_advanced_settings' ), 10, 1 );
|
||||
|
||||
// 3rd party hook.
|
||||
do_action( 'acf/ui_options_page/admin_head' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This action will allow ACF to render metaboxes after the title.
|
||||
*/
|
||||
public function edit_form_after_title() {
|
||||
|
||||
// globals.
|
||||
global $post;
|
||||
|
||||
// render post data.
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'ui_options_page',
|
||||
'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/ui_options_page/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/ui_options_page/admin_l10n', $l10n );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin footer third party hook support
|
||||
*
|
||||
* @since 5.3.2
|
||||
*/
|
||||
public function admin_footer() {
|
||||
do_action( 'acf/ui_options_page/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 integer $columns Number of columns for layout.
|
||||
* @return integer
|
||||
*/
|
||||
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
|
||||
*/
|
||||
public function post_submitbox_misc_actions() {
|
||||
global $acf_ui_options_page;
|
||||
|
||||
$status_label = $acf_ui_options_page['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 integer $post_id The post ID.
|
||||
* @param WP_Post $post The post object.
|
||||
* @return integer $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_ui_options_page']['ID'] = $post_id;
|
||||
$_POST['acf_ui_options_page']['title'] = isset( $_POST['acf_ui_options_page']['page_title'] ) ? $_POST['acf_ui_options_page']['page_title'] : '';
|
||||
|
||||
// Save the post type.
|
||||
acf_update_internal_post_type( $_POST['acf_ui_options_page'], $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 6.2
|
||||
*/
|
||||
public function mb_basic_settings() {
|
||||
global $acf_ui_options_page, $acf_parent_page_options;
|
||||
|
||||
if ( ! acf_is_internal_post_type_key( $acf_ui_options_page['key'], 'acf-ui-options-page' ) ) {
|
||||
$acf_ui_options_page['key'] = uniqid( 'ui_options_page_' );
|
||||
}
|
||||
|
||||
$acf_parent_page_options = $this->get_parent_page_choices( (int) $acf_ui_options_page['ID'] );
|
||||
|
||||
acf_get_view( __DIR__ . '/../views/acf-ui-options-page/basic-settings.php' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the HTML for the advanced settings metabox.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function mb_advanced_settings() {
|
||||
acf_get_view( __DIR__ . '/../views/acf-ui-options-page/advanced-settings.php' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterates through the registered options pages and finds eligible parent pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param integer $post_id The post ID of a current ACF UI options page used to prevent selection of itself as a child.
|
||||
* @return array
|
||||
*/
|
||||
public function get_parent_page_choices( int $post_id = 0 ) {
|
||||
global $menu;
|
||||
$acf_all_options_pages = acf_get_options_pages();
|
||||
$acf_parent_page_choices = array( 'None' => array( 'none' => __( 'No Parent', 'acf' ) ) );
|
||||
$self_slug = false;
|
||||
|
||||
if ( is_array( $acf_all_options_pages ) ) {
|
||||
foreach ( $acf_all_options_pages as $options_page ) {
|
||||
// Can't assign to child pages.
|
||||
if ( ! empty( $options_page['parent_slug'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Can't be a child of itself.
|
||||
if ( isset( $options_page['ID'] ) && $post_id === $options_page['ID'] ) {
|
||||
$self_slug = $options_page['menu_slug'];
|
||||
continue;
|
||||
}
|
||||
|
||||
$acf_parent_menu_slug = ! empty( $options_page['menu_slug'] ) ? $options_page['menu_slug'] : '';
|
||||
|
||||
// ACF overrides the `menu_slug` of parent pages with one child so they redirect to the child.
|
||||
if ( ! empty( $options_page['_menu_slug'] ) ) {
|
||||
$acf_parent_menu_slug = $options_page['_menu_slug'];
|
||||
}
|
||||
|
||||
$acf_parent_page_choices['acfOptionsPages'][ $acf_parent_menu_slug ] = ! empty( $options_page['page_title'] ) ? $options_page['page_title'] : $options_page['menu_slug'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $menu as $item ) {
|
||||
if ( ! empty( $item[0] ) ) {
|
||||
$page_name = $item[0];
|
||||
$markup = '/<[^>]+>.*<\/[^>]+>/';
|
||||
$sanitized_name = preg_replace( $markup, '', $page_name );
|
||||
|
||||
// Prevent options pages being parents of themselves.
|
||||
if ( ! empty( $item[2] ) && $item[2] === $self_slug ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// If the current item is not an ACF-created options page, add it to the "Others" list.
|
||||
if ( empty( $acf_parent_page_choices['acfOptionsPages'][ $item[2] ] ) ) {
|
||||
$acf_parent_page_choices['Others'][ $item[2] ] = acf_esc_html( $sanitized_name );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $acf_parent_page_choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a simple options page over AJAX.
|
||||
*
|
||||
* @since 6.2
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_create_options_page() {
|
||||
// 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,
|
||||
'acf_ui_options_page' => array(),
|
||||
'field_group_title' => '',
|
||||
'acf_parent_page_choices' => 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();
|
||||
}
|
||||
|
||||
// Process form data.
|
||||
if ( ! empty( $args['acf_ui_options_page'] ) ) {
|
||||
// Prepare for save.
|
||||
$options_page = acf_validate_internal_post_type( $args['acf_ui_options_page'], 'acf-ui-options-page' );
|
||||
$options_page['key'] = uniqid( 'ui_options_page_' );
|
||||
$options_page['title'] = ! empty( $args['acf_ui_options_page']['page_title'] ) ? $args['acf_ui_options_page']['page_title'] : '';
|
||||
$existing_options_pages = acf_get_options_pages();
|
||||
|
||||
// Check for duplicates.
|
||||
if ( ! empty( $existing_options_pages ) ) {
|
||||
foreach ( $existing_options_pages as $existing_options_page ) {
|
||||
if ( $existing_options_page['menu_slug'] === $options_page['menu_slug'] ) {
|
||||
wp_send_json_error(
|
||||
array(
|
||||
'error' => __( 'The provided Menu Slug already exists.', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Save the options page.
|
||||
acf_update_internal_post_type( $options_page, 'acf-ui-options-page' );
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'page_title' => esc_html( $options_page['page_title'] ),
|
||||
'menu_slug' => esc_attr( $options_page['menu_slug'] ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Render the form.
|
||||
ob_start();
|
||||
acf_get_view(
|
||||
__DIR__ . '/../views/acf-ui-options-page/create-options-page-modal.php',
|
||||
array(
|
||||
'field_group_title' => $args['field_group_title'],
|
||||
'acf_parent_page_choices' => $args['acf_parent_page_choices'],
|
||||
)
|
||||
);
|
||||
$content = ob_get_clean();
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'content' => $content,
|
||||
'title' => esc_html__( 'Add New Options Page', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
new ACF_Admin_UI_Options_Page();
|
||||
endif; // Class exists check.
|
||||
@@ -0,0 +1,212 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_UI_Options_Pages' ) ) :
|
||||
|
||||
/**
|
||||
* The ACF Post Types admin controller class
|
||||
*/
|
||||
#[AllowDynamicProperties]
|
||||
class ACF_Admin_UI_Options_Pages extends ACF_Admin_Internal_Post_Type_List {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-ui-options-page';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-options-pages';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = 'options-pages';
|
||||
|
||||
/**
|
||||
* If this is a pro feature or not.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
public $is_pro_feature = true;
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Current screen actions for the post types list admin page.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
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( 'options-pages-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( 'options-pages-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, __( 'Options Pages', 'acf' ), __( 'Options Pages', 'acf' ), $cap, 'edit.php?post_type=acf-ui-options-page' );
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' ),
|
||||
);
|
||||
|
||||
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 ( ! empty( $post['description'] ) && ( is_string( $post['description'] ) || is_numeric( $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;
|
||||
|
||||
// Local JSON.
|
||||
case 'acf-json':
|
||||
$this->render_admin_table_column_local_status( $post );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 integer $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( 'Options page activated.', '%s options pages activated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfdeactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types deactivated */
|
||||
_n( 'Options page deactivated.', '%s options pages deactivated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfduplicatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types duplicated */
|
||||
_n( 'Options page duplicated.', '%s options pages duplicated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfsynccomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types synchronized */
|
||||
_n( 'Options page synchronized.', '%s options pages synchronized.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
acf_new_instance( 'ACF_Admin_UI_Options_Pages' );
|
||||
endif; // Class exists check.
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,306 @@
|
||||
<?php
|
||||
|
||||
global $acf_ui_options_page;
|
||||
|
||||
foreach ( acf_get_combined_options_page_settings_tabs() as $tab_key => $tab_label ) {
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'tab',
|
||||
'label' => $tab_label,
|
||||
'key' => 'acf_ui_options_page_tabs',
|
||||
)
|
||||
);
|
||||
|
||||
$wrapper_class = str_replace( '_', '-', $tab_key );
|
||||
|
||||
echo '<div class="acf-ui-options-page-advanced-settings acf-ui-options-page-' . esc_attr( $wrapper_class ) . '-settings">';
|
||||
|
||||
switch ( $tab_key ) {
|
||||
case 'visibility':
|
||||
$acf_dashicon_class_name = __( 'Dashicon class name', 'acf' );
|
||||
$acf_dashicon_link = '<a href="https://developer.wordpress.org/resource/dashicons/" target="_blank">' . $acf_dashicon_class_name . '</a>';
|
||||
|
||||
$acf_menu_icon_instructions = sprintf(
|
||||
/* translators: %s = "dashicon class name", link to the WordPress dashicon documentation. */
|
||||
__( 'The icon used for the options page menu item in the admin dashboard. Can be a URL or %s to use for the icon.', 'acf' ),
|
||||
$acf_dashicon_link
|
||||
);
|
||||
|
||||
// Set the default value for the icon field.
|
||||
$acf_default_icon_value = array(
|
||||
'type' => 'dashicons',
|
||||
'value' => 'dashicons-admin-generic',
|
||||
);
|
||||
|
||||
$acf_icon_value = $acf_default_icon_value;
|
||||
|
||||
// Override the value for backwards compatibility, if it was saved with the key 'icon_url' as a string.
|
||||
if ( ! empty( $acf_ui_options_page['icon_url'] ) ) {
|
||||
if ( strpos( $acf_ui_options_page['icon_url'], 'dashicons-' ) === 0 ) {
|
||||
$acf_icon_value = array(
|
||||
'type' => 'dashicons',
|
||||
'value' => $acf_ui_options_page['icon_url'],
|
||||
);
|
||||
} else {
|
||||
$acf_icon_value = array(
|
||||
'type' => 'url',
|
||||
'value' => $acf_ui_options_page['icon_url'],
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Override the above value if a 'menu_icon' key exists, and is not empty, which is the new key for storing the icon.
|
||||
if ( ! empty( $acf_ui_options_page['menu_icon'] ) ) {
|
||||
$acf_icon_value = $acf_ui_options_page['menu_icon'];
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Menu Icon', 'acf' ),
|
||||
'type' => 'icon_picker',
|
||||
'name' => 'menu_icon',
|
||||
'key' => 'menu_icon',
|
||||
'class' => 'acf-options-page-menu_icon',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'required' => false,
|
||||
'value' => $acf_icon_value,
|
||||
'default_value' => $acf_default_icon_value,
|
||||
'conditions' => array(
|
||||
'field' => 'parent_slug',
|
||||
'operator' => '==',
|
||||
'value' => 'none',
|
||||
),
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Menu Title', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'menu_title',
|
||||
'key' => 'menu_title',
|
||||
'class' => 'acf-options-page-menu_title',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['menu_title'],
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
$acf_menu_position_link = sprintf(
|
||||
'<a href="https://developer.wordpress.org/reference/functions/add_menu_page/#default-bottom-of-menu-structure" target="_blank">%s</a>',
|
||||
__( 'Learn more about menu positions.', 'acf' )
|
||||
);
|
||||
$acf_menu_position_desc = sprintf(
|
||||
/* translators: %s - link to WordPress docs to learn more about menu positions. */
|
||||
__( 'The position in the menu where this page should appear. %s', 'acf' ),
|
||||
$acf_menu_position_link
|
||||
);
|
||||
|
||||
$acf_menu_position_desc_parent = sprintf(
|
||||
/* translators: %s - link to WordPress docs to learn more about menu positions. */
|
||||
__( 'The position in the menu where this page should appear. %s', 'acf' ),
|
||||
$acf_menu_position_link
|
||||
);
|
||||
|
||||
$acf_menu_position_desc_child = __( 'The position in the menu where this child page should appear. The first child page is 0, the next is 1, etc.', 'acf' );
|
||||
|
||||
$acf_menu_position_desc = '<span class="acf-menu-position-desc-parent">' . $acf_menu_position_desc_parent . '</span>';
|
||||
$acf_menu_position_desc .= '<span class="acf-menu-position-desc-child">' . $acf_menu_position_desc_child . '</span>';
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Menu Position', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'position',
|
||||
'key' => 'position',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['position'],
|
||||
'instructions' => $acf_menu_position_desc,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Redirect to Child Page', 'acf' ),
|
||||
'instructions' => __( 'When child pages exist for this parent page, this page will redirect to the first child page.', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'name' => 'redirect',
|
||||
'key' => 'redirect',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['redirect'],
|
||||
'ui' => 1,
|
||||
'default' => 1,
|
||||
'conditions' => array(
|
||||
'field' => 'parent_slug',
|
||||
'operator' => '==',
|
||||
'value' => 'none',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'text',
|
||||
'name' => 'description',
|
||||
'key' => 'description',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['description'],
|
||||
'label' => __( 'Description', 'acf' ),
|
||||
'instructions' => __( 'A descriptive summary of the options page.', 'acf' ),
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
break;
|
||||
case 'labels':
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Update Button Label', 'acf' ),
|
||||
'instructions' => __( 'The label used for the submit button which updates the fields on the options page.', 'acf' ),
|
||||
'placeholder' => __( 'Update', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'update_button',
|
||||
'key' => 'update_button',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['update_button'],
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Updated Message', 'acf' ),
|
||||
'instructions' => __( 'The message that is displayed after successfully updating the options page.', 'acf' ),
|
||||
'placeholder' => __( 'Updated Options', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'updated_message',
|
||||
'key' => 'updated_message',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['updated_message'],
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
break;
|
||||
case 'permissions':
|
||||
$acf_all_caps = array();
|
||||
|
||||
foreach ( wp_roles()->roles as $acf_role ) {
|
||||
$acf_all_caps = array_merge( $acf_all_caps, $acf_role['capabilities'] );
|
||||
}
|
||||
|
||||
// Get rid of duplicates and set the keys equal to the values.
|
||||
$acf_all_caps = array_unique( array_keys( $acf_all_caps ) );
|
||||
$acf_all_caps = array_combine( $acf_all_caps, $acf_all_caps );
|
||||
|
||||
// Move the "edit_posts" to the first select option.
|
||||
if ( in_array( 'edit_posts', $acf_all_caps, true ) ) {
|
||||
$acf_all_caps = array_diff( $acf_all_caps, array( 'edit_posts' ) );
|
||||
$acf_all_caps = array_merge( array( 'edit_posts' => 'edit_posts' ), $acf_all_caps );
|
||||
}
|
||||
|
||||
// TODO: Should we AJAX load this? Seems to require UI = true, which breaks our custom template.
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'capability',
|
||||
'key' => 'capability',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['capability'],
|
||||
'label' => __( 'Capability', 'acf' ),
|
||||
'instructions' => __( 'The capability required for this menu to be displayed to the user.', 'acf' ),
|
||||
'choices' => $acf_all_caps,
|
||||
'default' => 'edit_posts',
|
||||
'class' => 'acf-options-page-capability',
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'data_storage',
|
||||
'key' => 'data_storage',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['data_storage'],
|
||||
'label' => __( 'Data Storage', 'acf' ),
|
||||
'instructions' => __( 'By default, the option page stores field data in the options table. You can make the page load field data from a post, user, or term.', 'acf' ),
|
||||
'choices' => array(
|
||||
'options' => __( 'Options', 'acf' ),
|
||||
'post_id' => __( 'Custom Storage', 'acf' ),
|
||||
),
|
||||
'default' => 'options',
|
||||
'hide_search' => true,
|
||||
'class' => 'acf-options-page-data_storage',
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
$acf_custom_storage_url = acf_add_url_utm_tags(
|
||||
'https://www.advancedcustomfields.com/resources/get_field/',
|
||||
'docs',
|
||||
'options_page_ui',
|
||||
'get-a-value-from-different-objects'
|
||||
);
|
||||
|
||||
$acf_custom_storage_link = sprintf(
|
||||
'<a href="%1$s" target="_blank">%2$s</a>',
|
||||
$acf_custom_storage_url,
|
||||
__( 'Learn more about available settings.', 'acf' )
|
||||
);
|
||||
|
||||
$acf_custom_storage_desc = sprintf(
|
||||
/* translators: %s = link to learn more about storage locations. */
|
||||
__( 'Set a custom storage location. Can be a numeric post ID (123), or a string (`user_2`). %s', 'acf' ),
|
||||
$acf_custom_storage_link
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Custom Storage', 'acf' ),
|
||||
'instructions' => $acf_custom_storage_desc,
|
||||
'type' => 'text',
|
||||
'name' => 'post_id',
|
||||
'key' => 'post_id',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['post_id'],
|
||||
'conditions' => array(
|
||||
'field' => 'data_storage',
|
||||
'operator' => '==',
|
||||
'value' => 'post_id',
|
||||
),
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Autoload Options', 'acf' ),
|
||||
'instructions' => __( 'Improve performance by loading the fields in the option records automatically when WordPress loads.', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'name' => 'autoload',
|
||||
'key' => 'autoload',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['autoload'],
|
||||
'ui' => 1,
|
||||
'default' => 0,
|
||||
)
|
||||
);
|
||||
break;
|
||||
default:
|
||||
}
|
||||
|
||||
do_action( "acf/ui_options_page/render_settings_tab/{$tab_key}", $acf_ui_options_page );
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
global $acf_ui_options_page, $acf_parent_page_options;
|
||||
|
||||
$acf_duplicate_options_page = acf_get_ui_options_page_from_request_args( 'acfduplicate' );
|
||||
|
||||
if ( acf_is_ui_options_page( $acf_duplicate_options_page ) ) {
|
||||
// Reset vars that likely have to be changed.
|
||||
$acf_duplicate_options_page['key'] = uniqid( 'ui_options_page_' );
|
||||
$acf_duplicate_options_page['title'] = '';
|
||||
$acf_duplicate_options_page['page_title'] = '';
|
||||
$acf_duplicate_options_page['menu_title'] = '';
|
||||
$acf_duplicate_options_page['menu_slug'] = '';
|
||||
|
||||
// Rest of the vars can be reused.
|
||||
$acf_ui_options_page = $acf_duplicate_options_page;
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Page Title', 'acf' ),
|
||||
/* translators: example options page name */
|
||||
'placeholder' => __( 'Site Settings', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'page_title',
|
||||
'key' => 'page_title',
|
||||
'class' => 'acf_options_page_title acf_slugify_to_key',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['page_title'],
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Menu Slug', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'menu_slug',
|
||||
'key' => 'menu_slug',
|
||||
'class' => 'acf-options-page-menu_slug acf_slugified_key',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['menu_slug'],
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Parent Page', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'parent_slug',
|
||||
'key' => 'parent_slug',
|
||||
'class' => 'acf-options-page-parent_slug',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'value' => $acf_ui_options_page['parent_slug'],
|
||||
'choices' => $acf_parent_page_options,
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
do_action( 'acf/post_type/basic_settings', $acf_ui_options_page );
|
||||
|
||||
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_ui_options_page',
|
||||
'value' => $acf_ui_options_page['advanced_configuration'],
|
||||
'ui' => 1,
|
||||
'class' => 'acf-advanced-settings-toggle',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="acf-hidden">
|
||||
<input type="hidden" name="acf_ui_options_page[key]" value="<?php echo esc_attr( $acf_ui_options_page['key'] ); ?>" />
|
||||
</div>
|
||||
<?php
|
||||
@@ -0,0 +1,66 @@
|
||||
<form id="acf-create-options-page-form">
|
||||
<?php
|
||||
|
||||
$acf_options_page_prefilled_title = '';
|
||||
|
||||
if ( ! empty( $field_group_title ) ) {
|
||||
$acf_options_page_prefilled_title = (string) apply_filters( 'acf/options_page_modal/prefill_title', '%s' );
|
||||
$acf_options_page_prefilled_title = sprintf(
|
||||
$acf_options_page_prefilled_title,
|
||||
$field_group_title
|
||||
);
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Page Title', 'acf' ),
|
||||
/* translators: example options page name */
|
||||
'placeholder' => __( 'Site Settings', 'acf' ),
|
||||
'value' => $acf_options_page_prefilled_title,
|
||||
'type' => 'text',
|
||||
'name' => 'page_title',
|
||||
'key' => 'page_title',
|
||||
'class' => 'acf_options_page_title acf_slugify_to_key',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Menu Slug', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'menu_slug',
|
||||
'key' => 'menu_slug',
|
||||
'class' => 'acf-options-page-menu_slug acf_slugified_key',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Parent Page', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'parent_slug',
|
||||
'key' => 'parent_slug',
|
||||
'class' => 'acf-options-page-parent_slug',
|
||||
'prefix' => 'acf_ui_options_page',
|
||||
'choices' => $acf_parent_page_choices,
|
||||
'required' => true,
|
||||
),
|
||||
'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>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
/**
|
||||
* The empty list state for an ACF Options Page
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
$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' )
|
||||
);
|
||||
|
||||
$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' );
|
||||
?>
|
||||
<script>document.body.classList.add('acf-no-options-pages');</script>
|
||||
<div class="acf-no-options-pages-wrapper">
|
||||
<div class="acf-no-options-pages-inner">
|
||||
<img src="<?php echo esc_url( acf_get_url( 'assets/images/empty-post-types.svg' ) ); ?>" />
|
||||
|
||||
<?php
|
||||
if ( acf_pro_is_license_active() ) {
|
||||
$acf_options_pages_title = __( 'Add Your First Options Page', 'acf' );
|
||||
} else {
|
||||
$acf_options_pages_title = __( 'Upgrade to ACF PRO to create options pages in just a few clicks', 'acf' );
|
||||
}
|
||||
?>
|
||||
|
||||
<h2><?php echo esc_html( $acf_options_pages_title ); ?></h2>
|
||||
<p><?php echo acf_esc_html( $acf_options_pages_desc ); ?></p>
|
||||
|
||||
<?php if ( acf_pro_is_license_active() ) : ?>
|
||||
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=acf-ui-options-page' ) ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php esc_html_e( 'Add Options Page', 'acf' ); ?></a>
|
||||
<?php else : ?>
|
||||
<div class="acf-ui-options-page-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><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped on generation. ?>
|
||||
<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><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped on generation. ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<p class="acf-small"><?php echo acf_esc_html( $acf_getting_started ); ?></p>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,46 @@
|
||||
<div class="wrap acf-settings-wrap">
|
||||
|
||||
<h1><?php echo esc_html( $page_title ); ?></h1>
|
||||
|
||||
<form id="post" method="post" name="post">
|
||||
|
||||
<?php
|
||||
|
||||
// render post data
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'options',
|
||||
'post_id' => $post_id,
|
||||
)
|
||||
);
|
||||
|
||||
wp_nonce_field( 'meta-box-order', 'meta-box-order-nonce', false );
|
||||
wp_nonce_field( 'closedpostboxes', 'closedpostboxesnonce', false );
|
||||
|
||||
?>
|
||||
|
||||
<div id="poststuff" class="poststuff">
|
||||
|
||||
<div id="post-body" class="metabox-holder columns-<?php echo 1 == get_current_screen()->get_columns() ? '1' : '2'; ?>">
|
||||
|
||||
<div id="postbox-container-1" class="postbox-container">
|
||||
|
||||
<?php do_meta_boxes( 'acf_options_page', 'side', null ); ?>
|
||||
|
||||
</div>
|
||||
|
||||
<div id="postbox-container-2" class="postbox-container">
|
||||
|
||||
<?php do_meta_boxes( 'acf_options_page', 'normal', null ); ?>
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<br class="clear">
|
||||
|
||||
</div>
|
||||
|
||||
</form>
|
||||
|
||||
</div>
|
||||
@@ -0,0 +1,307 @@
|
||||
<?php
|
||||
/**
|
||||
* Renders the "License Information" and "Update Information" metaboxes.
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
$nonce = $active ? 'deactivate_pro_license' : 'activate_pro_license';
|
||||
$activate_deactivate_btn = $active ? __( 'Deactivate License', 'acf' ) : __( 'Activate License', 'acf' );
|
||||
|
||||
/**
|
||||
* Renders the license status table.
|
||||
*
|
||||
* @since 6.2.3
|
||||
*
|
||||
* @param array $status The current license status array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_pro_render_license_status_table( $status ) {
|
||||
// Bail early if we don't have a status from the server.
|
||||
if ( acf_pro_get_license_key() && empty( $status['status'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$status['status'] = ! empty( $status['status'] ) ? $status['status'] : 'inactive';
|
||||
$status_text = _x( 'Inactive', 'license status', 'acf' );
|
||||
$is_lifetime = ! empty( $status['lifetime'] );
|
||||
|
||||
if ( 'active' === $status['status'] ) {
|
||||
$status_text = _x( 'Active', 'license status', 'acf' );
|
||||
} elseif ( 'expired' === $status['status'] ) {
|
||||
$status_text = _x( 'Expired', 'license status', 'acf' );
|
||||
} elseif ( 'cancelled' === $status['status'] ) {
|
||||
$status_text = _x( 'Cancelled', 'license status', 'acf' );
|
||||
}
|
||||
|
||||
$indicator = '<span class="acf-license-status ' . esc_attr( $status['status'] ) . '">' . esc_html( $status_text ) . '</span>';
|
||||
?>
|
||||
|
||||
<table class="acf-license-status-table">
|
||||
<tr>
|
||||
<th>
|
||||
<?php
|
||||
if ( $is_lifetime || 'inactive' === $status['status'] ) {
|
||||
esc_html_e( 'License Status', 'acf' );
|
||||
} else {
|
||||
esc_html_e( 'Subscription Status', 'acf' );
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<td><?php echo acf_esc_html( $indicator ); ?></td>
|
||||
</tr>
|
||||
<?php if ( ! empty( $status['name'] ) ) : ?>
|
||||
<tr>
|
||||
<th>
|
||||
<?php
|
||||
if ( $is_lifetime ) {
|
||||
esc_html_e( 'License Type', 'acf' );
|
||||
} else {
|
||||
esc_html_e( 'Subscription Type', 'acf' );
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
if ( $is_lifetime ) {
|
||||
esc_html_e( 'Lifetime - ', 'acf' );
|
||||
}
|
||||
echo esc_html( $status['name'] );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
<?php if ( ! $is_lifetime && ! empty( $status['expiry'] ) && is_numeric( $status['expiry'] ) ) : ?>
|
||||
<tr>
|
||||
<th>
|
||||
<?php
|
||||
if ( acf_pro_is_license_expired( $status ) ) {
|
||||
esc_html_e( 'Subscription Expired', 'acf' );
|
||||
} else {
|
||||
esc_html_e( 'Subscription Expires', 'acf' );
|
||||
}
|
||||
?>
|
||||
</th>
|
||||
<td>
|
||||
<?php
|
||||
$date_format = get_option( 'date_format', 'F j, Y' );
|
||||
$expiry_date = date_i18n( $date_format, $status['expiry'] );
|
||||
echo esc_html( $expiry_date );
|
||||
?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the "Manage License"/"Renew Subscription" button.
|
||||
*
|
||||
* @since 6.2.3
|
||||
*
|
||||
* @param array $status The current license status.
|
||||
* @return void
|
||||
*/
|
||||
function acf_pro_render_manage_license_button( $status ) {
|
||||
// Lifetime licenses don't have anything to manage.
|
||||
if ( ! empty( $status['lifetime'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$url = acf_pro_get_manage_license_url( $status );
|
||||
$url = acf_add_url_utm_tags( $url, 'updates page', 'manage license button' );
|
||||
$text = __( 'Manage License', 'acf' );
|
||||
$class = '';
|
||||
|
||||
if ( acf_pro_is_license_expired( $status ) || acf_pro_was_license_refunded( $status ) ) {
|
||||
$text = __( 'Renew Subscription', 'acf' );
|
||||
$class = ' acf-btn acf-renew-subscription';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<a href="%1$s" target="_blank" class="acf-manage-license-btn%2$s">%3$s<i class="acf-icon acf-icon-arrow-up-right"></i></a>',
|
||||
esc_url( $url ),
|
||||
esc_attr( $class ),
|
||||
esc_html( $text )
|
||||
);
|
||||
}
|
||||
?>
|
||||
<div class="wrap acf-settings-wrap acf-updates">
|
||||
|
||||
<h1><?php esc_html_e( 'Updates', 'acf' ); ?></h1>
|
||||
|
||||
<div class="acf-box" id="acf-license-information">
|
||||
<div class="title">
|
||||
<h3><?php esc_html_e( 'License Information', 'acf' ); ?></h3>
|
||||
</div>
|
||||
<div class="inner">
|
||||
<?php if ( $is_defined_license ) : ?>
|
||||
|
||||
<p class="acf-license-defined">
|
||||
<?php echo acf_esc_html( apply_filters( 'acf/admin/license_key_constant_message', __( 'Your license key is defined in wp-config.php.', 'acf' ) ) ); ?>
|
||||
</p>
|
||||
|
||||
<?php if ( ! acf_pro_is_license_active() ) : ?>
|
||||
<div class="acf-retry-activation">
|
||||
<?php
|
||||
$acf_recheck_class = ' acf-btn acf-btn-secondary';
|
||||
|
||||
if ( acf_pro_is_license_expired( $license_status ) || acf_pro_was_license_refunded( $license_status ) ) {
|
||||
acf_pro_render_manage_license_button( $license_status );
|
||||
$acf_recheck_class = '';
|
||||
}
|
||||
|
||||
$acf_recheck_nonce = wp_create_nonce( 'acf_retry_activation' );
|
||||
$acf_recheck_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates&acf_retry_nonce=' . $acf_recheck_nonce );
|
||||
$acf_recheck_text = __( 'Recheck License', 'acf' );
|
||||
printf(
|
||||
'<a class="acf-recheck-license%1$s" href="%2$s"><i class="acf-icon acf-icon-regenerate"></i>%3$s</a>',
|
||||
esc_attr( $acf_recheck_class ),
|
||||
esc_url( $acf_recheck_url ),
|
||||
esc_html( $acf_recheck_text )
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php else : // License is not defined. ?>
|
||||
<form action="" method="post" class="acf-activation-form">
|
||||
<?php acf_nonce_input( $nonce ); ?>
|
||||
<label for="acf-field-acf_pro_license"><?php esc_html_e( 'License Key', 'acf' ); ?></label>
|
||||
<?php
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'text',
|
||||
'name' => 'acf_pro_license',
|
||||
'value' => str_repeat( '*', strlen( $license ) ),
|
||||
'readonly' => $active ? 1 : 0,
|
||||
)
|
||||
);
|
||||
|
||||
$activate_deactivate_btn_id = $active ? 'id="deactivate-license" ' : '';
|
||||
$activate_deactivate_btn_class = $active ? ' acf-btn-tertiary' : '';
|
||||
?>
|
||||
<input <?php echo $activate_deactivate_btn_id; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- manually defined safe HTML. ?>type="submit" value="<?php echo esc_attr( $activate_deactivate_btn ); ?>" class="acf-btn<?php echo esc_attr( $activate_deactivate_btn_class ); ?>">
|
||||
<?php
|
||||
acf_pro_render_manage_license_button( $license_status );
|
||||
|
||||
if ( acf_pro_is_license_expired( $license_status ) || acf_pro_was_license_refunded( $license_status ) ) {
|
||||
$acf_recheck_nonce = wp_create_nonce( 'acf_recheck_status' );
|
||||
$acf_recheck_url = admin_url( 'edit.php?post_type=acf-field-group&page=acf-settings-updates&acf_retry_nonce=' . $acf_recheck_nonce );
|
||||
$acf_recheck_text = __( 'Recheck License', 'acf' );
|
||||
printf(
|
||||
'<a class="acf-recheck-license" href="%1$s"><i class="acf-icon acf-icon-regenerate"></i>%2$s</a>',
|
||||
esc_url( $acf_recheck_url ),
|
||||
esc_html( $acf_recheck_text )
|
||||
);
|
||||
}
|
||||
?>
|
||||
|
||||
</form>
|
||||
<?php endif; // End of license_defined check. ?>
|
||||
<div class="acf-license-status-wrap">
|
||||
<?php
|
||||
acf_pro_render_license_status_table( $license_status );
|
||||
|
||||
if ( ! $active && ! defined( 'ACF_PRO_LICENSE' ) ) :
|
||||
?>
|
||||
<div class="acf-no-license-view-pricing">
|
||||
<span>
|
||||
<?php
|
||||
$acf_view_pricing_text = esc_html__( 'View pricing & purchase', 'acf' );
|
||||
$acf_view_pricing_link = sprintf(
|
||||
'<a href=%s target="_blank">%s <i class="acf-icon acf-icon-arrow-up-right"></i></a>',
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'license activations' ),
|
||||
$acf_view_pricing_text
|
||||
);
|
||||
echo acf_esc_html(
|
||||
sprintf(
|
||||
/* translators: %s - link to ACF website */
|
||||
__( 'Don\'t have an ACF PRO license? %s', 'acf' ),
|
||||
$acf_view_pricing_link
|
||||
)
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="acf-box" id="acf-update-information">
|
||||
<div class="title">
|
||||
<h3><?php esc_html_e( 'Update Information', 'acf' ); ?></h3>
|
||||
</div>
|
||||
<div class="inner">
|
||||
<table class="form-table">
|
||||
<tbody>
|
||||
<tr>
|
||||
<th>
|
||||
<label><?php esc_html_e( 'Current Version', 'acf' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo esc_html( $current_version ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<label><?php esc_html_e( 'Latest Version', 'acf' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo esc_html( $remote_version ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<th>
|
||||
<label><?php esc_html_e( 'Update Available', 'acf' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php if ( $update_available ) : ?>
|
||||
|
||||
<span style="margin-right: 5px;"><?php esc_html_e( 'Yes', 'acf' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="margin-right: 5px;"><?php esc_html_e( 'No', 'acf' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php if ( $upgrade_notice ) : ?>
|
||||
<tr>
|
||||
<th>
|
||||
<label><?php esc_html_e( 'Upgrade Notice', 'acf' ); ?></label>
|
||||
</th>
|
||||
<td>
|
||||
<?php echo acf_esc_html( $upgrade_notice ); ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<?php if ( $changelog ) : ?>
|
||||
<div class="acf-update-changelog">
|
||||
<?php echo acf_esc_html( $changelog ); ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php if ( $update_available ) : ?>
|
||||
<?php if ( $wp_not_compatible ) : ?>
|
||||
<a class="button" disabled="disabled" href="#"><?php esc_html_e( 'Please upgrade WordPress to update ACF', 'acf' ); ?></a>
|
||||
<?php elseif ( $license_error ) : ?>
|
||||
<a class="button" disabled="disabled" href="#"><?php esc_html_e( 'Please reactivate your license to unlock updates', 'acf' ); ?></a>
|
||||
<?php elseif ( $active && is_multisite() ) : ?>
|
||||
<a class="button" disabled="disabled" href="#"><?php esc_html_e( 'Update ACF in Network Admin', 'acf' ); ?></a>
|
||||
<?php elseif ( $active && ! is_plugin_active( ACF_BASENAME ) ) : ?>
|
||||
<a class="button" disabled="disabled" href="#"><?php esc_html_e( 'Updates must be manually installed in this configuration', 'acf' ); ?></a>
|
||||
<?php elseif ( $active ) : ?>
|
||||
<a class="acf-btn" href="<?php echo esc_url( admin_url( 'plugins.php?s=Advanced+Custom+Fields+Pro' ) ); ?>"><?php esc_html_e( 'Update Plugin', 'acf' ); ?></a>
|
||||
<?php else : ?>
|
||||
<a class="button" disabled="disabled" href="#"><?php esc_html_e( 'Enter your license key to unlock updates', 'acf' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<?php else : ?>
|
||||
<a class="acf-btn acf-btn-secondary" href="<?php echo esc_url( add_query_arg( 'force-check', 1 ) ); ?>"><?php esc_html_e( 'Check For Updates', 'acf' ); ?></a>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
1525
wp-content/plugins/advanced-custom-fields-pro/pro/blocks.php
Normal file
1525
wp-content/plugins/advanced-custom-fields-pro/pro/blocks.php
Normal file
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,921 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_gallery' ) ) :
|
||||
|
||||
class acf_field_gallery extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'gallery';
|
||||
$this->label = __( 'Gallery', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'An interactive interface for managing a collection of attachments, such as images.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-gallery.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/gallery/', 'docs', 'field-type-selection' );
|
||||
$this->tutorial_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/how-to-use-the-gallery-field/', 'docs', 'field-type-selection' );
|
||||
$this->pro = true;
|
||||
$this->supports = array( 'bindings' => false );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
'preview_size' => 'medium',
|
||||
'insert' => 'append',
|
||||
'library' => 'all',
|
||||
'min' => 0,
|
||||
'max' => 0,
|
||||
'min_width' => 0,
|
||||
'min_height' => 0,
|
||||
'min_size' => 0,
|
||||
'max_width' => 0,
|
||||
'max_height' => 0,
|
||||
'max_size' => 0,
|
||||
'mime_types' => '',
|
||||
);
|
||||
|
||||
// actions
|
||||
add_action( 'wp_ajax_acf/fields/gallery/get_attachment', array( $this, 'ajax_get_attachment' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/gallery/get_attachment', array( $this, 'ajax_get_attachment' ) );
|
||||
|
||||
add_action( 'wp_ajax_acf/fields/gallery/update_attachment', array( $this, 'ajax_update_attachment' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/gallery/update_attachment', array( $this, 'ajax_update_attachment' ) );
|
||||
|
||||
add_action( 'wp_ajax_acf/fields/gallery/get_sort_order', array( $this, 'ajax_get_sort_order' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/gallery/get_sort_order', array( $this, 'ajax_get_sort_order' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// localize
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Add Image to Gallery' => __( 'Add Image to Gallery', 'acf' ),
|
||||
'Maximum selection reached' => __( 'Maximum selection reached', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for retrieving and rendering an attachment.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_get_attachment() {
|
||||
// Get args.
|
||||
$args = acf_request_args(
|
||||
array(
|
||||
'id' => 0,
|
||||
'field_key' => '',
|
||||
'nonce' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// Validate request.
|
||||
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Cast args.
|
||||
$args['id'] = (int) $args['id'];
|
||||
|
||||
// Bail early if no id.
|
||||
if ( ! $args['id'] ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Load field.
|
||||
$field = acf_get_field( $args['field_key'] );
|
||||
if ( ! $field ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// Render.
|
||||
$this->render_attachment( $args['id'], $field );
|
||||
die;
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for updating an attachment.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_update_attachment() {
|
||||
$args = acf_request_args(
|
||||
array(
|
||||
'nonce' => '',
|
||||
'field_key' => '',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// bail early if no attachments
|
||||
if ( empty( $_POST['attachments'] ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// loop over attachments
|
||||
foreach ( $_POST['attachments'] as $id => $changes ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP core when saved.
|
||||
|
||||
if ( ! current_user_can( 'edit_post', $id ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
$post = get_post( $id, ARRAY_A );
|
||||
|
||||
if ( 'attachment' != $post['post_type'] ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
if ( isset( $changes['title'] ) ) {
|
||||
$post['post_title'] = $changes['title'];
|
||||
}
|
||||
|
||||
if ( isset( $changes['caption'] ) ) {
|
||||
$post['post_excerpt'] = $changes['caption'];
|
||||
}
|
||||
|
||||
if ( isset( $changes['description'] ) ) {
|
||||
$post['post_content'] = $changes['description'];
|
||||
}
|
||||
|
||||
if ( isset( $changes['alt'] ) ) {
|
||||
$alt = wp_unslash( $changes['alt'] );
|
||||
if ( $alt != get_post_meta( $id, '_wp_attachment_image_alt', true ) ) {
|
||||
$alt = wp_strip_all_tags( $alt, true );
|
||||
update_post_meta( $id, '_wp_attachment_image_alt', wp_slash( $alt ) );
|
||||
}
|
||||
}
|
||||
|
||||
// save post
|
||||
wp_update_post( $post );
|
||||
|
||||
/** This filter is documented in wp-admin/includes/media.php */
|
||||
// - seems off to run this filter AFTER the update_post function, but there is a reason
|
||||
// - when placed BEFORE, an empty post_title will be populated by WP
|
||||
// - this filter will still allow 3rd party to save extra image data!
|
||||
$post = apply_filters( 'attachment_fields_to_save', $post, $changes );
|
||||
|
||||
// save meta
|
||||
acf_save_post( $id );
|
||||
}
|
||||
|
||||
// return
|
||||
wp_send_json_success();
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX handler for getting the attachment sort order.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_get_sort_order() {
|
||||
$order = 'DESC';
|
||||
$args = acf_parse_args(
|
||||
$_POST, // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified below.
|
||||
array(
|
||||
'ids' => 0,
|
||||
'sort' => 'date',
|
||||
'field_key' => '',
|
||||
'nonce' => '',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! acf_verify_ajax( $args['nonce'], $args['field_key'], true ) ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// Reverse order.
|
||||
if ( $args['sort'] === 'reverse' ) {
|
||||
$ids = array_reverse( $args['ids'] );
|
||||
wp_send_json_success( $ids );
|
||||
}
|
||||
|
||||
// Ascending order.
|
||||
if ( $args['sort'] === 'title' ) {
|
||||
$order = 'ASC';
|
||||
}
|
||||
|
||||
// Find attachments (DISTINCT POSTS).
|
||||
$ids = get_posts(
|
||||
array(
|
||||
'post_type' => 'attachment',
|
||||
'numberposts' => -1,
|
||||
'post_status' => 'any',
|
||||
'post__in' => $args['ids'],
|
||||
'order' => $order,
|
||||
'orderby' => $args['sort'],
|
||||
'fields' => 'ids',
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! empty( $ids ) ) {
|
||||
wp_send_json_success( $ids );
|
||||
}
|
||||
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the sidebar HTML shown when selecting an attachmemnt.
|
||||
*
|
||||
* @date 13/12/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param integer $id The attachment ID.
|
||||
* @param array $field The field array.
|
||||
* @return void
|
||||
*/
|
||||
function render_attachment( $id, $field ) {
|
||||
// Load attachmenet data.
|
||||
$attachment = wp_prepare_attachment_for_js( $id );
|
||||
$compat = get_compat_media_markup( $id );
|
||||
|
||||
// Get attachment thumbnail (video).
|
||||
if ( isset( $attachment['thumb']['src'] ) ) {
|
||||
$thumb = $attachment['thumb']['src'];
|
||||
|
||||
// Look for thumbnail size (image).
|
||||
} elseif ( isset( $attachment['sizes']['thumbnail']['url'] ) ) {
|
||||
$thumb = $attachment['sizes']['thumbnail']['url'];
|
||||
|
||||
// Use url for svg.
|
||||
} elseif ( $attachment['type'] === 'image' ) {
|
||||
$thumb = $attachment['url'];
|
||||
|
||||
// Default to icon.
|
||||
} else {
|
||||
$thumb = wp_mime_type_icon( $id );
|
||||
}
|
||||
|
||||
// Get attachment dimensions / time / size.
|
||||
$dimensions = '';
|
||||
if ( $attachment['type'] === 'audio' ) {
|
||||
$dimensions = __( 'Length', 'acf' ) . ': ' . $attachment['fileLength'];
|
||||
} elseif ( ! empty( $attachment['width'] ) ) {
|
||||
$dimensions = $attachment['width'] . ' x ' . $attachment['height'];
|
||||
}
|
||||
if ( ! empty( $attachment['filesizeHumanReadable'] ) ) {
|
||||
$dimensions .= ' (' . $attachment['filesizeHumanReadable'] . ')';
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-gallery-side-info">
|
||||
<img src="<?php echo esc_url( $thumb ); ?>" alt="<?php echo esc_attr( $attachment['alt'] ); ?>" />
|
||||
<p class="filename"><strong><?php echo esc_html( $attachment['filename'] ); ?></strong></p>
|
||||
<p class="uploaded"><?php echo esc_html( $attachment['dateFormatted'] ); ?></p>
|
||||
<p class="dimensions"><?php echo esc_html( $dimensions ); ?></p>
|
||||
<p class="actions">
|
||||
<a href="#" class="acf-gallery-edit" data-id="<?php echo esc_attr( $id ); ?>"><?php esc_html_e( 'Edit', 'acf' ); ?></a>
|
||||
<a href="#" class="acf-gallery-remove" data-id="<?php echo esc_attr( $id ); ?>"><?php esc_html_e( 'Remove', 'acf' ); ?></a>
|
||||
</p>
|
||||
</div>
|
||||
<table class="form-table">
|
||||
<tbody>
|
||||
<?php
|
||||
|
||||
// Render fields.
|
||||
$prefix = 'attachments[' . $id . ']';
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
// 'key' => "{$field['key']}-title",
|
||||
'name' => 'title',
|
||||
'prefix' => $prefix,
|
||||
'type' => 'text',
|
||||
'label' => __( 'Title', 'acf' ),
|
||||
'value' => $attachment['title'],
|
||||
),
|
||||
'tr'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
// 'key' => "{$field['key']}-caption",
|
||||
'name' => 'caption',
|
||||
'prefix' => $prefix,
|
||||
'type' => 'textarea',
|
||||
'label' => __( 'Caption', 'acf' ),
|
||||
'value' => $attachment['caption'],
|
||||
),
|
||||
'tr'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
// 'key' => "{$field['key']}-alt",
|
||||
'name' => 'alt',
|
||||
'prefix' => $prefix,
|
||||
'type' => 'text',
|
||||
'label' => __( 'Alt Text', 'acf' ),
|
||||
'value' => $attachment['alt'],
|
||||
),
|
||||
'tr'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
// 'key' => "{$field['key']}-description",
|
||||
'name' => 'description',
|
||||
'prefix' => $prefix,
|
||||
'type' => 'textarea',
|
||||
'label' => __( 'Description', 'acf' ),
|
||||
'value' => $attachment['description'],
|
||||
),
|
||||
'tr'
|
||||
);
|
||||
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
|
||||
// Display compat fields.
|
||||
echo $compat['item']; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped inside get_compat_media_markup().
|
||||
}
|
||||
|
||||
/**
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
|
||||
// Enqueue uploader assets.
|
||||
acf_enqueue_uploader();
|
||||
|
||||
// Control attributes.
|
||||
$attrs = array(
|
||||
'id' => $field['id'],
|
||||
'class' => "acf-gallery {$field['class']}",
|
||||
'data-library' => $field['library'],
|
||||
'data-preview_size' => $field['preview_size'],
|
||||
'data-min' => $field['min'],
|
||||
'data-max' => $field['max'],
|
||||
'data-mime_types' => $field['mime_types'],
|
||||
'data-insert' => $field['insert'],
|
||||
'data-columns' => 4,
|
||||
'data-nonce' => wp_create_nonce( 'acf_field_' . $this->name . '_' . $field['key'] ),
|
||||
);
|
||||
|
||||
// Set gallery height with deafult of 400px and minimum of 200px.
|
||||
$height = acf_get_user_setting( 'gallery_height', 400 );
|
||||
$height = max( $height, 200 );
|
||||
$attrs['style'] = "height:{$height}px";
|
||||
|
||||
// Load attachments.
|
||||
$attachments = array();
|
||||
if ( $field['value'] ) {
|
||||
|
||||
// Clean value into an array of IDs.
|
||||
$attachment_ids = array_map( 'intval', acf_array( $field['value'] ) );
|
||||
|
||||
// Find posts in database (ensures all results are real).
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post_type' => 'attachment',
|
||||
'post__in' => $attachment_ids,
|
||||
'update_post_meta_cache' => true,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// Load attatchment data for each post.
|
||||
$attachments = array_map( 'acf_get_attachment', $posts );
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $attrs ); ?>>
|
||||
<input type="hidden" name="<?php echo esc_attr( $field['name'] ); ?>" value="" />
|
||||
<div class="acf-gallery-main">
|
||||
<div class="acf-gallery-attachments">
|
||||
<?php if ( $attachments ) : ?>
|
||||
<?php
|
||||
foreach ( $attachments as $i => $attachment ) :
|
||||
|
||||
// Vars
|
||||
$a_id = $attachment['ID'];
|
||||
$a_title = $attachment['title'];
|
||||
$a_type = $attachment['type'];
|
||||
$a_filename = $attachment['filename'];
|
||||
$a_class = "acf-gallery-attachment -{$a_type}";
|
||||
|
||||
// Get thumbnail.
|
||||
$a_thumbnail = acf_get_post_thumbnail( $a_id, $field['preview_size'] );
|
||||
$a_class .= ( $a_thumbnail['type'] === 'icon' ) ? ' -icon' : '';
|
||||
|
||||
?>
|
||||
<div class="<?php echo esc_attr( $a_class ); ?>" data-id="<?php echo esc_attr( $a_id ); ?>">
|
||||
<input type="hidden" name="<?php echo esc_attr( $field['name'] ); ?>[]" value="<?php echo esc_attr( $a_id ); ?>" />
|
||||
<div class="margin">
|
||||
<div class="thumbnail">
|
||||
<img src="<?php echo esc_url( $a_thumbnail['url'] ); ?>" alt="" />
|
||||
</div>
|
||||
<?php if ( $a_type !== 'image' ) : ?>
|
||||
<div class="filename"><?php echo acf_esc_html( acf_get_truncated( $a_filename, 30 ) ); ?></div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="actions">
|
||||
<a class="acf-icon -cancel dark acf-gallery-remove" href="#" data-id="<?php echo esc_attr( $a_id ); ?>" title="<?php esc_html_e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="acf-gallery-toolbar">
|
||||
<ul class="acf-hl">
|
||||
<li>
|
||||
<a href="#" class="acf-button button button-primary acf-gallery-add"><?php esc_html_e( 'Add to gallery', 'acf' ); ?></a>
|
||||
</li>
|
||||
<li class="acf-fr">
|
||||
<select class="acf-gallery-sort">
|
||||
<option value=""><?php esc_html_e( 'Bulk actions', 'acf' ); ?></option>
|
||||
<option value="date"><?php esc_html_e( 'Sort by date uploaded', 'acf' ); ?></option>
|
||||
<option value="modified"><?php esc_html_e( 'Sort by date modified', 'acf' ); ?></option>
|
||||
<option value="title"><?php esc_html_e( 'Sort by title', 'acf' ); ?></option>
|
||||
<option value="reverse"><?php esc_html_e( 'Reverse current order', 'acf' ); ?></option>
|
||||
</select>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acf-gallery-side">
|
||||
<div class="acf-gallery-side-inner">
|
||||
<div class="acf-gallery-side-data"></div>
|
||||
<div class="acf-gallery-toolbar">
|
||||
<ul class="acf-hl">
|
||||
<li>
|
||||
<a href="#" class="acf-button button acf-gallery-close"><?php esc_html_e( 'Close', 'acf' ); ?></a>
|
||||
</li>
|
||||
<li class="acf-fr">
|
||||
<a class="acf-button button button-primary acf-gallery-update" href="#"><?php esc_html_e( 'Update', 'acf' ); ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Create extra options for your field. This is rendered when editing a field.
|
||||
* The value of $field['name'] can be used (like bellow) to save extra data to the $field
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'Image Array', 'acf' ),
|
||||
'url' => __( 'Image URL', 'acf' ),
|
||||
'id' => __( 'Image ID', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Library', 'acf' ),
|
||||
'instructions' => __( 'Limit the media library choice', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'library',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'all' => __( 'All', 'acf' ),
|
||||
'uploadedTo' => __( 'Uploaded to post', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Validation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_validation_settings( $field ) {
|
||||
// Clear numeric settings.
|
||||
$clear = array(
|
||||
'min',
|
||||
'max',
|
||||
'min_width',
|
||||
'min_height',
|
||||
'min_size',
|
||||
'max_width',
|
||||
'max_height',
|
||||
'max_size',
|
||||
);
|
||||
|
||||
foreach ( $clear as $k ) {
|
||||
if ( empty( $field[ $k ] ) ) {
|
||||
$field[ $k ] = '';
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Selection', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Selection', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum', 'acf' ),
|
||||
'hint' => __( 'Restrict which images can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'min_width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'min_height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'_append' => 'min_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'min_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
'_append' => 'min_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum', 'acf' ),
|
||||
'hint' => __( 'Restrict which images can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'max_width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'max_height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'_append' => 'max_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'max_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
'_append' => 'max_width',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allowed File Types', 'acf' ),
|
||||
'hint' => __( 'Comma separated list. Leave blank for all types', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'mime_types',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field settings used in the "Presentation" tab.
|
||||
*
|
||||
* @since 6.0
|
||||
*
|
||||
* @param array $field The field settings array.
|
||||
* @return void
|
||||
*/
|
||||
function render_field_presentation_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Insert', 'acf' ),
|
||||
'instructions' => __( 'Specify where new attachments are added', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'insert',
|
||||
'choices' => array(
|
||||
'append' => __( 'Append to the end', 'acf' ),
|
||||
'prepend' => __( 'Prepend to the beginning', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Preview Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'preview_size',
|
||||
'choices' => acf_get_image_sizes(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value which was loaded from the database
|
||||
* @param $post_id (mixed) the post_id from which the value was loaded
|
||||
* @param $field (array) the field array holding all the field options
|
||||
*
|
||||
* @return $value (mixed) the modified value
|
||||
*/
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( ! $value ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Clean value into an array of IDs.
|
||||
$attachment_ids = array_map( 'intval', acf_array( $value ) );
|
||||
|
||||
// Find posts in database (ensures all results are real).
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post_type' => 'attachment',
|
||||
'post__in' => $attachment_ids,
|
||||
'update_post_meta_cache' => true,
|
||||
'update_post_term_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// Bail early if no posts found.
|
||||
if ( ! $posts ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Format values using field settings.
|
||||
$value = array();
|
||||
foreach ( $posts as $post ) {
|
||||
|
||||
// Return object.
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
$item = $post;
|
||||
|
||||
// Return array.
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
$item = acf_get_attachment( $post );
|
||||
|
||||
// Return URL.
|
||||
} elseif ( $field['return_format'] == 'url' ) {
|
||||
$item = wp_get_attachment_url( $post->ID );
|
||||
|
||||
// Return ID.
|
||||
} else {
|
||||
$item = $post->ID;
|
||||
}
|
||||
|
||||
// Append item.
|
||||
$value[] = $item;
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 11/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
if ( empty( $value ) || ! is_array( $value ) ) {
|
||||
$value = array();
|
||||
}
|
||||
|
||||
if ( count( $value ) < $field['min'] ) {
|
||||
$valid = _n( '%1$s requires at least %2$s selection', '%1$s requires at least %2$s selections', $field['min'], 'acf' );
|
||||
$valid = sprintf( $valid, $field['label'], $field['min'] );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value which will be saved in the database
|
||||
* @param $post_id - the post_id of which the value will be saved
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Bail early if no value.
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Convert to array.
|
||||
$value = acf_array( $value );
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates file fields updated via the REST API.
|
||||
*
|
||||
* @param boolean $valid The current validity booleean
|
||||
* @param integer $value The value of the field
|
||||
* @param array $field The field array
|
||||
* @return boolean|WP
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( ! $valid || ! is_array( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
foreach ( $value as $attachment_id ) {
|
||||
$file_valid = acf_get_field_type( 'file' )->validate_rest_value( $valid, $attachment_id, $field );
|
||||
|
||||
if ( is_wp_error( $file_valid ) ) {
|
||||
return $file_valid;
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'number',
|
||||
),
|
||||
);
|
||||
|
||||
if ( ! empty( $field['min'] ) ) {
|
||||
$schema['minItems'] = (int) $field['min'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max'] ) ) {
|
||||
$schema['maxItems'] = (int) $field['max'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param integer|string $post_id
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_links( $value, $post_id, array $field ) {
|
||||
$links = array();
|
||||
|
||||
if ( empty( $value ) ) {
|
||||
return $links;
|
||||
}
|
||||
|
||||
foreach ( (array) $value as $object_id ) {
|
||||
$links[] = array(
|
||||
'rel' => 'acf:attachment',
|
||||
'href' => rest_url( '/wp/v2/media/' . $object_id ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|integer $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_gallery' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,487 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF_Repeater_Table
|
||||
*
|
||||
* Helper class for rendering repeater tables.
|
||||
*
|
||||
*/
|
||||
class ACF_Repeater_Table {
|
||||
|
||||
/**
|
||||
* The main field array used to render the repeater.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $field;
|
||||
|
||||
/**
|
||||
* An array containing the subfields used in the repeater.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $sub_fields;
|
||||
|
||||
/**
|
||||
* The value(s) of the repeater field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* If we should show the "Add Row" button.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $show_add = true;
|
||||
|
||||
/**
|
||||
* If we should show the "Remove Row" button.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $show_remove = true;
|
||||
|
||||
/**
|
||||
* If we should show the order of the fields.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $show_order = true;
|
||||
|
||||
/**
|
||||
* Constructs the ACF_Repeater_Table class.
|
||||
*
|
||||
* @param array $field The main field array for the repeater being rendered.
|
||||
*/
|
||||
public function __construct( $field ) {
|
||||
$this->field = $field;
|
||||
$this->sub_fields = $field['sub_fields'];
|
||||
|
||||
// Default to non-paginated repeaters.
|
||||
if ( empty( $this->field['pagination'] ) ) {
|
||||
$this->field['pagination'] = false;
|
||||
}
|
||||
|
||||
// We don't yet support pagination inside other repeaters or flexible content fields.
|
||||
if ( ! empty( $this->field['parent_repeater'] ) || ! empty( $this->field['parent_layout'] ) ) {
|
||||
$this->field['pagination'] = false;
|
||||
}
|
||||
|
||||
// We don't yet support pagination in frontend forms or inside blocks.
|
||||
if ( ! is_admin() || acf_get_data( 'acf_inside_rest_call' ) || doing_action( 'wp_ajax_acf/ajax/fetch-block' ) ) {
|
||||
$this->field['pagination'] = false;
|
||||
}
|
||||
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the field for rendering.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setup() {
|
||||
if ( $this->field['collapsed'] ) {
|
||||
foreach ( $this->sub_fields as &$sub_field ) {
|
||||
// Add target class.
|
||||
if ( $sub_field['key'] == $this->field['collapsed'] ) {
|
||||
$sub_field['wrapper']['class'] .= ' -collapsed-target';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $this->field['max'] ) {
|
||||
// If max 1 row, don't show order.
|
||||
if ( 1 == $this->field['max'] ) {
|
||||
$this->show_order = false;
|
||||
}
|
||||
|
||||
// If max == min, don't show add or remove buttons.
|
||||
if ( $this->field['max'] <= $this->field['min'] ) {
|
||||
$this->show_remove = false;
|
||||
$this->show_add = false;
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $this->field['rows_per_page'] ) ) {
|
||||
$this->field['rows_per_page'] = 20;
|
||||
}
|
||||
|
||||
if ( (int) $this->field['rows_per_page'] < 1 ) {
|
||||
$this->field['rows_per_page'] = 20;
|
||||
}
|
||||
|
||||
$this->value = $this->prepare_value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the repeater values for rendering.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
private function prepare_value() {
|
||||
$value = is_array( $this->field['value'] ) ? $this->field['value'] : array();
|
||||
|
||||
if ( empty( $this->field['pagination'] ) ) {
|
||||
// If there are fewer values than min, populate the extra values.
|
||||
if ( $this->field['min'] ) {
|
||||
$value = array_pad( $value, $this->field['min'], array() );
|
||||
}
|
||||
|
||||
// If there are more values than max, remove some values.
|
||||
if ( $this->field['max'] ) {
|
||||
$value = array_slice( $value, 0, $this->field['max'] );
|
||||
}
|
||||
}
|
||||
|
||||
$value['acfcloneindex'] = array();
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the full repeater table.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
// Attributes for main wrapper div.
|
||||
$div = array(
|
||||
'class' => 'acf-repeater -' . $this->field['layout'],
|
||||
'data-min' => $this->field['min'],
|
||||
'data-max' => $this->field['max'],
|
||||
'data-pagination' => ! empty( $this->field['pagination'] ),
|
||||
'data-prefix' => $this->field['prefix'],
|
||||
);
|
||||
|
||||
if ( $this->field['pagination'] ) {
|
||||
$div['data-per_page'] = $this->field['rows_per_page'];
|
||||
$div['data-total_rows'] = $this->field['total_rows'];
|
||||
$div['data-orig_name'] = $this->field['orig_name'];
|
||||
$div['data-nonce'] = wp_create_nonce( 'acf_field_' . $this->field['type'] . '_' . $this->field['key'] );
|
||||
}
|
||||
|
||||
if ( empty( $this->value ) ) {
|
||||
$div['class'] .= ' -empty';
|
||||
}
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $this->field['name'],
|
||||
'value' => '',
|
||||
'class' => 'acf-repeater-hidden-input',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<table class="acf-table">
|
||||
<?php $this->thead(); ?>
|
||||
<tbody>
|
||||
<?php $this->rows(); ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php $this->table_actions(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the table head.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function thead() {
|
||||
if ( 'table' !== $this->field['layout'] ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php if ( $this->show_order ) : ?>
|
||||
<th class="acf-row-handle"></th>
|
||||
<?php endif; ?>
|
||||
|
||||
<?php
|
||||
foreach ( $this->sub_fields as $sub_field ) :
|
||||
// Prepare field (allow sub fields to be removed).
|
||||
$sub_field = acf_prepare_field( $sub_field );
|
||||
if ( ! $sub_field ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Define attrs.
|
||||
$attrs = array(
|
||||
'class' => 'acf-th',
|
||||
'data-name' => $sub_field['_name'],
|
||||
'data-type' => $sub_field['type'],
|
||||
'data-key' => $sub_field['key'],
|
||||
);
|
||||
|
||||
if ( $sub_field['wrapper']['width'] ) {
|
||||
$attrs['data-width'] = $sub_field['wrapper']['width'];
|
||||
$attrs['style'] = 'width: ' . $sub_field['wrapper']['width'] . '%;';
|
||||
}
|
||||
|
||||
// Remove "id" to avoid "for" attribute on <label>.
|
||||
$sub_field['id'] = '';
|
||||
?>
|
||||
<th <?php echo acf_esc_attrs( $attrs ); ?>>
|
||||
<?php acf_render_field_label( $sub_field ); ?>
|
||||
<?php acf_render_field_instructions( $sub_field ); ?>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<?php if ( $this->show_remove ) : ?>
|
||||
<th class="acf-row-handle"></th>
|
||||
<?php endif; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders or returns rows for the repeater field table.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param boolean $return If we should return the rows or render them.
|
||||
* @return array|void
|
||||
*/
|
||||
public function rows( $return = false ) {
|
||||
$rows = array();
|
||||
|
||||
// Don't include the clone when rendering via AJAX.
|
||||
if ( $return && isset( $this->value['acfcloneindex'] ) ) {
|
||||
unset( $this->value['acfcloneindex'] );
|
||||
}
|
||||
|
||||
foreach ( $this->value as $i => $row ) {
|
||||
$rows[ $i ] = $this->row( $i, $row, $return );
|
||||
}
|
||||
|
||||
if ( $return ) {
|
||||
return $rows;
|
||||
}
|
||||
|
||||
echo implode( PHP_EOL, $rows ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- HTML already escaped by generating functions.
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders an individual row.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param integer $i The row number.
|
||||
* @param array $row An array containing the row values.
|
||||
* @param boolean $return If we should return the row or render it.
|
||||
* @return string|void
|
||||
*/
|
||||
public function row( $i, $row, $return = false ) {
|
||||
if ( $return ) {
|
||||
ob_start();
|
||||
}
|
||||
|
||||
$id = "row-$i";
|
||||
$class = 'acf-row';
|
||||
|
||||
if ( 'acfcloneindex' === $i ) {
|
||||
$id = 'acfcloneindex';
|
||||
$class .= ' acf-clone';
|
||||
}
|
||||
|
||||
$el = 'td';
|
||||
$before_fields = '';
|
||||
$after_fields = '';
|
||||
|
||||
if ( 'row' === $this->field['layout'] ) {
|
||||
$el = 'div';
|
||||
$before_fields = '<td class="acf-fields -left">';
|
||||
$after_fields = '</td>';
|
||||
} elseif ( 'block' === $this->field['layout'] ) {
|
||||
$el = 'div';
|
||||
$before_fields = '<td class="acf-fields">';
|
||||
$after_fields = '</td>';
|
||||
}
|
||||
|
||||
printf(
|
||||
'<tr class="%s" data-id="%s">',
|
||||
esc_attr( $class ),
|
||||
esc_attr( $id )
|
||||
);
|
||||
|
||||
$this->row_handle( $i );
|
||||
|
||||
echo $before_fields; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- string only contains guarenteed safe HTML.
|
||||
|
||||
foreach ( $this->sub_fields as $sub_field ) {
|
||||
if ( isset( $row[ $sub_field['key'] ] ) ) {
|
||||
$sub_field['value'] = $row[ $sub_field['key'] ];
|
||||
} elseif ( isset( $sub_field['default_value'] ) ) {
|
||||
$sub_field['value'] = $sub_field['default_value'];
|
||||
}
|
||||
|
||||
// Update prefix to allow for nested values.
|
||||
$sub_field['prefix'] = $this->field['name'] . '[' . $id . ']';
|
||||
|
||||
acf_render_field_wrap( $sub_field, $el );
|
||||
}
|
||||
|
||||
echo $after_fields; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- string only contains guarenteed safe HTML.
|
||||
|
||||
$this->row_actions();
|
||||
|
||||
echo '</tr>';
|
||||
|
||||
if ( $return ) {
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the row handle at the start of each row.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param integer $i The current row number.
|
||||
* @return void
|
||||
*/
|
||||
public function row_handle( $i ) {
|
||||
if ( ! $this->show_order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$hr_row_num = intval( $i ) + 1;
|
||||
$classes = 'acf-row-handle order';
|
||||
$title = __( 'Drag to reorder', 'acf' );
|
||||
$row_num_html = sprintf(
|
||||
'<span class="acf-row-number" title="%s">%d</span>',
|
||||
esc_html__( 'Click to reorder', 'acf' ),
|
||||
$hr_row_num
|
||||
);
|
||||
|
||||
if ( ! empty( $this->field['pagination'] ) ) {
|
||||
$classes .= ' pagination';
|
||||
$title = '';
|
||||
$input = sprintf( '<input type="number" class="acf-order-input" value="%d" style="display: none;" />', $hr_row_num );
|
||||
$row_num_html = '<div class="acf-order-input-wrap">' . $input . $row_num_html . '</div>';
|
||||
}
|
||||
?>
|
||||
<td class="<?php echo esc_attr( $classes ); ?>" title="<?php echo esc_attr( $title ); ?>">
|
||||
<?php if ( $this->field['collapsed'] ) : ?>
|
||||
<a class="acf-icon -collapse small" href="#" data-event="collapse-row" title="<?php esc_attr_e( 'Click to toggle', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<?php echo $row_num_html; ?><?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped where necessary on generation. ?>
|
||||
</td>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the actions displayed at the end of each row.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function row_actions() {
|
||||
if ( ! $this->show_remove ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<td class="acf-row-handle remove">
|
||||
<a class="acf-icon -plus small acf-js-tooltip hide-on-shift" href="#" data-event="add-row" title="<?php esc_attr_e( 'Add row', 'acf' ); ?>"></a>
|
||||
<a class="acf-icon -duplicate small acf-js-tooltip show-on-shift" href="#" data-event="duplicate-row" title="<?php esc_attr_e( 'Duplicate row', 'acf' ); ?>"></a>
|
||||
<a class="acf-icon -minus small acf-js-tooltip" href="#" data-event="remove-row" title="<?php esc_attr_e( 'Remove row', 'acf' ); ?>"></a>
|
||||
</td>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the actions displayed underneath the table.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function table_actions() {
|
||||
if ( ! $this->show_add ) {
|
||||
return;
|
||||
}
|
||||
?>
|
||||
<div class="acf-actions">
|
||||
<a class="acf-button acf-repeater-add-row button button-primary" href="#" data-event="add-row"><?php echo acf_esc_html( $this->field['button_label'] ); ?></a>
|
||||
<?php $this->pagination(); ?>
|
||||
<div class="clear"></div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the table pagination.
|
||||
* Mostly lifted from the WordPress core WP_List_Table class.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function pagination() {
|
||||
if ( empty( $this->field['pagination'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$total_rows = isset( $this->field['total_rows'] ) ? (int) $this->field['total_rows'] : 0;
|
||||
$total_pages = ceil( $total_rows / (int) $this->field['rows_per_page'] );
|
||||
$total_pages = max( $total_pages, 1 );
|
||||
|
||||
$html_current_page = sprintf(
|
||||
"%s<input class='current-page' id='current-page-selector' type='text' name='paged' value='%s' size='%d' aria-describedby='table-paging' />",
|
||||
'<label for="current-page-selector" class="screen-reader-text">' . __( 'Current Page', 'acf' ) . '</label>',
|
||||
1,
|
||||
strlen( $total_pages )
|
||||
);
|
||||
|
||||
$html_total_pages = sprintf( "<span class='acf-total-pages'>%s</span>", number_format_i18n( $total_pages ) );
|
||||
?>
|
||||
<div class="acf-tablenav tablenav-pages">
|
||||
<a class="first-page button acf-nav" aria-hidden="true" data-event="first-page" title="<?php esc_attr_e( 'First Page', 'acf' ); ?>">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'First Page', 'acf' ); ?></span>
|
||||
<span aria-hidden="true">«</span>
|
||||
</a>
|
||||
<a class="prev-page button acf-nav" aria-hidden="true" data-event="prev-page" title="<?php esc_attr_e( 'Previous Page', 'acf' ); ?>">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Previous Page', 'acf' ); ?></span>
|
||||
<span aria-hidden="true">‹</span>
|
||||
</a>
|
||||
<span class="paging-input">
|
||||
<label for="current-page-selector" class="screen-reader-text"><?php esc_html_e( 'Current Page', 'acf' ); ?></label>
|
||||
<span class="tablenav-paging-text" title="<?php esc_attr_e( 'Current Page', 'acf' ); ?>">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: 1: Current page, 2: Total pages. */
|
||||
esc_html_x( '%1$s of %2$s', 'paging', 'acf' ),
|
||||
$html_current_page, //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escape not necessary.
|
||||
$html_total_pages //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escape not necessary.
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
<a class="next-page button acf-nav" data-event="next-page" title="<?php esc_attr_e( 'Next Page', 'acf' ); ?>">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Next Page', 'acf' ); ?></span>
|
||||
<span aria-hidden="true">›</span>
|
||||
</a>
|
||||
<a class="last-page button acf-nav" data-event="last-page" title="<?php esc_attr_e( 'Last Page', 'acf' ); ?>">
|
||||
<span class="screen-reader-text"><?php esc_html_e( 'Last Page', 'acf' ); ?></span>
|
||||
<span aria-hidden="true">»</span>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,102 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Location_Block' ) ) :
|
||||
|
||||
class ACF_Location_Block extends ACF_Location {
|
||||
|
||||
/**
|
||||
* Initializes props.
|
||||
*
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'block';
|
||||
$this->label = __( 'Block', 'acf' );
|
||||
$this->category = 'forms';
|
||||
$this->object_type = 'block';
|
||||
|
||||
add_filter( 'acf/field_group/list_table_classes', array( $this, 'field_group_list_table_classes' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the provided rule against the screen args returning a bool result.
|
||||
*
|
||||
* @date 9/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $rule The location rule.
|
||||
* @param array $screen The screen args.
|
||||
* @param array $field_group The field group settings.
|
||||
* @return boolean
|
||||
*/
|
||||
public function match( $rule, $screen, $field_group ) {
|
||||
|
||||
// Check screen args.
|
||||
if ( isset( $screen['block'] ) ) {
|
||||
$block = $screen['block'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare rule against $block.
|
||||
return $this->compare_to_rule( $block, $rule );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of possible values for this rule type.
|
||||
*
|
||||
* @date 9/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $rule A location rule.
|
||||
* @return array
|
||||
*/
|
||||
public function get_values( $rule ) {
|
||||
$choices = array();
|
||||
|
||||
// Append block types.
|
||||
$blocks = acf_get_block_types();
|
||||
if ( $blocks ) {
|
||||
$choices['all'] = __( 'All', 'acf' );
|
||||
foreach ( $blocks as $block ) {
|
||||
$choices[ $block['name'] ] = $block['title'];
|
||||
}
|
||||
} else {
|
||||
$choices[''] = __( 'No block types exist', 'acf' );
|
||||
}
|
||||
|
||||
// Return choices.
|
||||
return $choices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds block-specific classes to field groups in the Field Groups list table.
|
||||
*
|
||||
* @since 6.2.8
|
||||
*
|
||||
* @param array $classes An array of the classes used by the field group.
|
||||
* @param array $css_class An array of additional classes added to the field group.
|
||||
* @param integer $post_id The ID of the field group.
|
||||
* @return array
|
||||
*/
|
||||
public function field_group_list_table_classes( $classes, $css_class, $post_id ) {
|
||||
// Add a CSS class if the field group has a block location.
|
||||
if ( acf_field_group_has_location_type( $post_id, 'block' ) ) {
|
||||
$classes[] = 'acf-has-block-location';
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf_register_location_type( 'ACF_Location_Block' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,84 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Location_Options_Page' ) ) :
|
||||
|
||||
class ACF_Location_Options_Page extends ACF_Location {
|
||||
|
||||
/**
|
||||
* Initializes props.
|
||||
*
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
$this->name = 'options_page';
|
||||
$this->label = __( 'Options Page', 'acf' );
|
||||
$this->category = 'forms';
|
||||
$this->object_type = 'option';
|
||||
}
|
||||
|
||||
/**
|
||||
* Matches the provided rule against the screen args returning a bool result.
|
||||
*
|
||||
* @date 9/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $rule The location rule.
|
||||
* @param array $screen The screen args.
|
||||
* @param array $field_group The field group settings.
|
||||
* @return boolean
|
||||
*/
|
||||
public function match( $rule, $screen, $field_group ) {
|
||||
|
||||
// Check screen args.
|
||||
if ( isset( $screen['options_page'] ) ) {
|
||||
$options_page = $screen['options_page'];
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Compare rule against $nav_menu.
|
||||
return $this->compare_to_rule( $options_page, $rule );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of possible values for this rule type.
|
||||
*
|
||||
* @date 9/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $rule A location rule.
|
||||
* @return array
|
||||
*/
|
||||
public function get_values( $rule ) {
|
||||
$choices = array();
|
||||
|
||||
// Append pages.
|
||||
$pages = acf_get_options_pages();
|
||||
if ( $pages ) {
|
||||
foreach ( $pages as $page ) {
|
||||
$choices[ $page['menu_slug'] ] = $page['page_title'];
|
||||
}
|
||||
} else {
|
||||
$choices[''] = __( 'Select options page...', 'acf' );
|
||||
}
|
||||
|
||||
if ( acf_get_setting( 'enable_options_pages_ui' ) ) {
|
||||
$choices['add_new_options_page'] = __( 'Add New Options Page', 'acf' );
|
||||
}
|
||||
|
||||
// Return choices.
|
||||
return $choices;
|
||||
}
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf_register_location_type( 'ACF_Location_Options_Page' );
|
||||
endif; // class_exists check
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,544 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'acf_options_page' ) ) :
|
||||
|
||||
class acf_options_page {
|
||||
|
||||
/** @var array Contains an array of options page settings */
|
||||
var $pages = array();
|
||||
|
||||
|
||||
/**
|
||||
* Initialize filters, action, variables and includes
|
||||
*
|
||||
* @type function
|
||||
* @date 23/06/12
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
function __construct() {
|
||||
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an Options Page settings array.
|
||||
*
|
||||
* @date 28/2/17
|
||||
* @since 5.5.8
|
||||
*
|
||||
* @param array|string $page The Options Page settings array or name.
|
||||
* @return array
|
||||
*/
|
||||
function validate_page( $page ) {
|
||||
|
||||
// Allow empty arg to generate the default Options Page.
|
||||
if ( empty( $page ) ) {
|
||||
$page_title = __( 'Options', 'acf' );
|
||||
$page = array(
|
||||
'page_title' => $page_title,
|
||||
'menu_title' => $page_title,
|
||||
'menu_slug' => 'acf-options',
|
||||
);
|
||||
|
||||
// Allow string to define Options Page name.
|
||||
} elseif ( is_string( $page ) ) {
|
||||
$page_title = $page;
|
||||
$page = array(
|
||||
'page_title' => $page_title,
|
||||
'menu_title' => $page_title,
|
||||
);
|
||||
}
|
||||
|
||||
// Apply defaults.
|
||||
$page = wp_parse_args(
|
||||
$page,
|
||||
array(
|
||||
'page_title' => '',
|
||||
'menu_title' => '',
|
||||
'menu_slug' => '',
|
||||
'capability' => 'edit_posts',
|
||||
'parent_slug' => '',
|
||||
'position' => null,
|
||||
'icon_url' => false,
|
||||
'redirect' => true,
|
||||
'post_id' => 'options',
|
||||
'autoload' => false,
|
||||
'update_button' => __( 'Update', 'acf' ),
|
||||
'updated_message' => __( 'Options Updated', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Allow compatibility for changed settings.
|
||||
$migrate = array(
|
||||
'title' => 'page_title',
|
||||
'menu' => 'menu_title',
|
||||
'slug' => 'menu_slug',
|
||||
'parent' => 'parent_slug',
|
||||
);
|
||||
foreach ( $migrate as $old => $new ) {
|
||||
if ( ! empty( $page[ $old ] ) ) {
|
||||
$page[ $new ] = $page[ $old ];
|
||||
}
|
||||
}
|
||||
|
||||
// If no menu_title is set, use the page_title value.
|
||||
if ( empty( $page['menu_title'] ) ) {
|
||||
$page['menu_title'] = $page['page_title'];
|
||||
}
|
||||
|
||||
// If no menu_slug is set, generate one using the menu_title value.
|
||||
if ( empty( $page['menu_slug'] ) ) {
|
||||
$page['menu_slug'] = 'acf-options-' . sanitize_title( $page['menu_title'] );
|
||||
}
|
||||
|
||||
// Standardize on position being either null or int.
|
||||
$page['position'] = is_numeric( $page['position'] ) ? (int) $page['position'] : null;
|
||||
|
||||
/**
|
||||
* Filters the $page array after it has been validated.
|
||||
*
|
||||
* @since 5.5.8
|
||||
* @param array $page The Options Page settings array.
|
||||
*/
|
||||
return apply_filters( 'acf/validate_options_page', $page );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will store an options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 9/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $page (array)
|
||||
* @return n/a
|
||||
*/
|
||||
function add_page( $page ) {
|
||||
|
||||
// validate
|
||||
$page = $this->validate_page( $page );
|
||||
$slug = $page['menu_slug'];
|
||||
|
||||
// bail early if already exists
|
||||
if ( isset( $this->pages[ $slug ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// append
|
||||
$this->pages[ $slug ] = $page;
|
||||
|
||||
// return
|
||||
return $page;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 9/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
function add_sub_page( $page ) {
|
||||
|
||||
// validate
|
||||
$page = $this->validate_page( $page );
|
||||
|
||||
// default parent
|
||||
if ( ! $page['parent_slug'] ) {
|
||||
$page['parent_slug'] = 'acf-options';
|
||||
}
|
||||
|
||||
// create default parent if not yet exists
|
||||
if ( $page['parent_slug'] == 'acf-options' && ! $this->get_page( 'acf-options' ) ) {
|
||||
$this->add_page( '' );
|
||||
}
|
||||
|
||||
// return
|
||||
return $this->add_page( $page );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will update an options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 9/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $slug (string)
|
||||
* @param $data (array)
|
||||
* @return (array)
|
||||
*/
|
||||
function update_page( $slug = '', $data = array() ) {
|
||||
|
||||
// vars
|
||||
$page = $this->get_page( $slug );
|
||||
|
||||
// bail early if no page
|
||||
if ( ! $page ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// loop
|
||||
$page = array_merge( $page, $data );
|
||||
|
||||
// set
|
||||
$this->pages[ $slug ] = $page;
|
||||
|
||||
// return
|
||||
return $page;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $slug (string)
|
||||
* @return (mixed)
|
||||
*/
|
||||
function get_page( $slug ) {
|
||||
|
||||
return isset( $this->pages[ $slug ] ) ? $this->pages[ $slug ] : null;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This function will return all options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $slug (string)
|
||||
* @return (mixed)
|
||||
*/
|
||||
function get_pages() {
|
||||
|
||||
return $this->pages;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_options_page
|
||||
*
|
||||
* This function will return the options page instance
|
||||
*
|
||||
* @type function
|
||||
* @date 9/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return (object)
|
||||
*/
|
||||
|
||||
function acf_options_page() {
|
||||
|
||||
global $acf_options_page;
|
||||
|
||||
if ( ! isset( $acf_options_page ) ) {
|
||||
$acf_options_page = new acf_options_page();
|
||||
}
|
||||
|
||||
return $acf_options_page;
|
||||
}
|
||||
|
||||
|
||||
// remove Options Page add-on conflict
|
||||
unset( $GLOBALS['acf_options_page'] );
|
||||
|
||||
|
||||
// initialize
|
||||
acf_options_page();
|
||||
endif; // class_exists check
|
||||
|
||||
|
||||
/**
|
||||
* alias of acf_options_page()->add_page()
|
||||
*
|
||||
* @type function
|
||||
* @date 24/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $page (mixed)
|
||||
* @return (array)
|
||||
*/
|
||||
if ( ! function_exists( 'acf_add_options_page' ) ) :
|
||||
|
||||
function acf_add_options_page( $page = '' ) {
|
||||
return acf_options_page()->add_page( $page );
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* alias of acf_options_page()->add_sub_page()
|
||||
*
|
||||
* @type function
|
||||
* @date 24/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $page (mixed)
|
||||
* @return (array)
|
||||
*/
|
||||
if ( ! function_exists( 'acf_add_options_sub_page' ) ) :
|
||||
|
||||
function acf_add_options_sub_page( $page = '' ) {
|
||||
|
||||
return acf_options_page()->add_sub_page( $page );
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* alias of acf_options_page()->update_page()
|
||||
*
|
||||
* @type function
|
||||
* @date 24/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $slug (string)
|
||||
* @param $page (mixed)
|
||||
* @return (array)
|
||||
*/
|
||||
if ( ! function_exists( 'acf_update_options_page' ) ) :
|
||||
|
||||
function acf_update_options_page( $slug = '', $data = array() ) {
|
||||
|
||||
return acf_options_page()->update_page( $slug, $data );
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This function will return an options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 24/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $slug (string)
|
||||
* @return (array)
|
||||
*/
|
||||
if ( ! function_exists( 'acf_get_options_page' ) ) :
|
||||
|
||||
function acf_get_options_page( $slug ) {
|
||||
|
||||
// vars
|
||||
$page = acf_options_page()->get_page( $slug );
|
||||
|
||||
// bail early if no page
|
||||
if ( ! $page ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// filter
|
||||
$page = apply_filters( 'acf/get_options_page', $page, $slug );
|
||||
|
||||
// return
|
||||
return $page;
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This function will return all options page settings
|
||||
*
|
||||
* @type function
|
||||
* @date 24/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return (array)
|
||||
*/
|
||||
if ( ! function_exists( 'acf_get_options_pages' ) ) :
|
||||
|
||||
function acf_get_options_pages() {
|
||||
|
||||
// global
|
||||
global $_wp_last_utility_menu;
|
||||
|
||||
// vars
|
||||
$pages = acf_options_page()->get_pages();
|
||||
|
||||
// bail early if no pages
|
||||
if ( empty( $pages ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// apply filter to each page
|
||||
foreach ( $pages as $slug => &$page ) {
|
||||
$page = acf_get_options_page( $slug );
|
||||
}
|
||||
|
||||
// calculate parent => child redirectes
|
||||
foreach ( $pages as $slug => &$page ) {
|
||||
|
||||
// bail early if is child
|
||||
if ( $page['parent_slug'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add missing position
|
||||
if ( ! $page['position'] ) {
|
||||
++$_wp_last_utility_menu;
|
||||
$page['position'] = $_wp_last_utility_menu;
|
||||
}
|
||||
|
||||
// bail early if no redirect
|
||||
if ( ! $page['redirect'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars
|
||||
$parent = $page['menu_slug'];
|
||||
$child = '';
|
||||
|
||||
// update children
|
||||
foreach ( $pages as &$sub_page ) {
|
||||
|
||||
// bail early if not child of this parent
|
||||
if ( $sub_page['parent_slug'] !== $parent ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// set child (only once)
|
||||
if ( ! $child ) {
|
||||
$child = $sub_page['menu_slug'];
|
||||
}
|
||||
|
||||
// update parent_slug to the first child
|
||||
$sub_page['parent_slug'] = $child;
|
||||
}
|
||||
|
||||
// finally update parent menu_slug
|
||||
if ( $child ) {
|
||||
$page['_menu_slug'] = $page['menu_slug'];
|
||||
$page['menu_slug'] = $child;
|
||||
}
|
||||
}
|
||||
|
||||
// filter
|
||||
$pages = apply_filters( 'acf/get_options_pages', $pages );
|
||||
|
||||
// return
|
||||
return $pages;
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to customize the options page admin menu title
|
||||
*
|
||||
* @type function
|
||||
* @date 13/07/13
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param $title (string)
|
||||
* @return n/a
|
||||
*/
|
||||
if ( ! function_exists( 'acf_set_options_page_title' ) ) :
|
||||
|
||||
function acf_set_options_page_title( $title = 'Options' ) {
|
||||
|
||||
acf_update_options_page(
|
||||
'acf-options',
|
||||
array(
|
||||
'page_title' => $title,
|
||||
'menu_title' => $title,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to customize the options page admin menu name
|
||||
*
|
||||
* @type function
|
||||
* @date 13/07/13
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param $title (string)
|
||||
* @return n/a
|
||||
*/
|
||||
if ( ! function_exists( 'acf_set_options_page_menu' ) ) :
|
||||
|
||||
function acf_set_options_page_menu( $title = 'Options' ) {
|
||||
|
||||
acf_update_options_page(
|
||||
'acf-options',
|
||||
array(
|
||||
'menu_title' => $title,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This function is used to customize the options page capability. Defaults to 'edit_posts'
|
||||
*
|
||||
* @type function
|
||||
* @date 13/07/13
|
||||
* @since 4.0.0
|
||||
*
|
||||
* @param $title (string)
|
||||
* @return n/a
|
||||
*/
|
||||
if ( ! function_exists( 'acf_set_options_page_capability' ) ) :
|
||||
|
||||
function acf_set_options_page_capability( $capability = 'edit_posts' ) {
|
||||
|
||||
acf_update_options_page(
|
||||
'acf-options',
|
||||
array(
|
||||
'capability' => $capability,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
endif;
|
||||
|
||||
|
||||
/**
|
||||
* This is an old function which is now referencing the new 'acf_add_options_sub_page' function
|
||||
*
|
||||
* @type function
|
||||
* @since 3.0.0
|
||||
* @date 29/01/13
|
||||
*
|
||||
* @param {string} $title
|
||||
* @return N/A
|
||||
*/
|
||||
if ( ! function_exists( 'register_options_page' ) ) :
|
||||
|
||||
function register_options_page( $page = '' ) {
|
||||
|
||||
acf_add_options_sub_page( $page );
|
||||
}
|
||||
|
||||
endif;
|
||||
@@ -0,0 +1,442 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'ACF_UI_Options_Page' ) ) {
|
||||
|
||||
class ACF_UI_Options_Page extends ACF_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The ACF internal post type name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-ui-options-page';
|
||||
|
||||
/**
|
||||
* The prefix for the key used in the main post array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $post_key_prefix = 'ui_options_page_';
|
||||
|
||||
/**
|
||||
* The cache key for a singular post.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cache_key = 'acf_get_ui_options_page_post:key:';
|
||||
|
||||
/**
|
||||
* The cache key for a collection of posts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cache_key_plural = 'acf_get_ui_options_page_posts';
|
||||
|
||||
/**
|
||||
* The hook name for a singular post.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hook_name = 'ui_options_page';
|
||||
|
||||
/**
|
||||
* The hook name for a collection of posts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hook_name_plural = 'ui_options_pages';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = 'ui-options-pages';
|
||||
|
||||
/**
|
||||
* Constructs the class and any parent classes.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register_post_type();
|
||||
|
||||
// Include admin classes in admin.
|
||||
if ( is_admin() ) {
|
||||
acf_include( 'includes/admin/admin-internal-post-type-list.php' );
|
||||
acf_include( 'includes/admin/admin-internal-post-type.php' );
|
||||
acf_include( 'pro/admin/post-types/admin-ui-options-page.php' );
|
||||
acf_include( 'pro/admin/post-types/admin-ui-options-pages.php' );
|
||||
}
|
||||
|
||||
$this->setup_local_json();
|
||||
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'acf/init', array( $this, 'register_ui_options_pages' ), 6 );
|
||||
add_action( 'acf/include_options_pages', array( $this, 'include_json_options_pages' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the acf-ui-options-page custom post type with WordPress.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function register_post_type() {
|
||||
$cap = acf_get_setting( 'capability' );
|
||||
|
||||
register_post_type(
|
||||
'acf-ui-options-page',
|
||||
array(
|
||||
'labels' => array(
|
||||
'name' => __( 'Options Pages', 'acf' ),
|
||||
'singular_name' => __( 'Options Pages', 'acf' ),
|
||||
'add_new' => __( 'Add New', 'acf' ),
|
||||
'add_new_item' => __( 'Add New Options Page', 'acf' ),
|
||||
'edit_item' => __( 'Edit Options Page', 'acf' ),
|
||||
'new_item' => __( 'New Options Page', 'acf' ),
|
||||
'view_item' => __( 'View Options Page', 'acf' ),
|
||||
'search_items' => __( 'Search Options Pages', 'acf' ),
|
||||
'not_found' => __( 'No Options Pages found', 'acf' ),
|
||||
'not_found_in_trash' => __( 'No Options Pages found in Trash', 'acf' ),
|
||||
),
|
||||
'public' => false,
|
||||
'hierarchical' => true,
|
||||
'show_ui' => true,
|
||||
'show_in_menu' => false,
|
||||
'_builtin' => false,
|
||||
'capability_type' => 'post',
|
||||
'capabilities' => array(
|
||||
'edit_post' => $cap,
|
||||
'delete_post' => $cap,
|
||||
'edit_posts' => $cap,
|
||||
'delete_posts' => $cap,
|
||||
),
|
||||
'supports' => false,
|
||||
'rewrite' => false,
|
||||
'query_var' => false,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register activated options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*/
|
||||
public function register_ui_options_pages() {
|
||||
$child_pages = array();
|
||||
|
||||
// Register parent pages first so that child pages can be registered properly.
|
||||
foreach ( $this->get_posts( array( 'active' => true ) ) as $options_page ) {
|
||||
$options_page = $this->get_options_page_args( $options_page );
|
||||
|
||||
if ( empty( $options_page['parent_slug'] ) || 'none' === $options_page['parent_slug'] ) {
|
||||
$options_page['parent_slug'] = '';
|
||||
acf_add_options_page( $options_page );
|
||||
} else {
|
||||
$child_pages[] = $options_page;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $child_pages as $child_page ) {
|
||||
acf_add_options_sub_page( $child_page );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default settings array for an ACF options page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings_array() {
|
||||
return array(
|
||||
// ACF internal settings.
|
||||
'ID' => 0,
|
||||
'key' => '',
|
||||
'title' => '',
|
||||
'active' => true,
|
||||
'menu_order' => 0,
|
||||
// Basic settings.
|
||||
'page_title' => '',
|
||||
'menu_slug' => '',
|
||||
'parent_slug' => '',
|
||||
'advanced_configuration' => false,
|
||||
// Visibility tab.
|
||||
'icon_url' => '',
|
||||
'menu_title' => '',
|
||||
'position' => null,
|
||||
'redirect' => false,
|
||||
'description' => '',
|
||||
'menu_icon' => array(),
|
||||
// Labels tab.
|
||||
'update_button' => __( 'Update', 'acf' ),
|
||||
'updated_message' => __( 'Options Updated', 'acf' ),
|
||||
// Permissions tab.
|
||||
'capability' => 'edit_posts',
|
||||
'data_storage' => 'options',
|
||||
'post_id' => '',
|
||||
'autoload' => false,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates options page values before allowing save from the global $_POST object.
|
||||
* Errors are added to the form using acf_add_internal_post_type_validation_error().
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @return boolean validity status
|
||||
*/
|
||||
public function ajax_validate_values() {
|
||||
if ( empty( $_POST['acf_ui_options_page'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
|
||||
return false;
|
||||
}
|
||||
|
||||
$to_validate = acf_sanitize_request_args( wp_unslash( $_POST['acf_ui_options_page'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
|
||||
$post_id = acf_request_arg( 'post_id' );
|
||||
$valid = true;
|
||||
$menu_slug = (string) $to_validate['menu_slug'];
|
||||
|
||||
if ( preg_match( '/^[a-z0-9_-]*$/', $menu_slug ) !== 1 ) {
|
||||
$valid = false;
|
||||
acf_add_internal_post_type_validation_error( 'menu_slug', __( 'The menu slug must only contain lower case alphanumeric characters, underscores or dashes.', 'acf' ) );
|
||||
}
|
||||
|
||||
// Check for duplicate menu_slug.
|
||||
$options_pages = acf_get_options_pages();
|
||||
$options_pages = is_array( $options_pages ) ? $options_pages : array();
|
||||
$duplicates = array_filter(
|
||||
$options_pages,
|
||||
function ( $options_page ) use ( $post_id, $menu_slug ) {
|
||||
// Current post is not a duplicate.
|
||||
if ( isset( $options_page['ID'] ) && (int) $post_id === (int) $options_page['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Menu slugs match, could be a duplicate.
|
||||
if ( $menu_slug === $options_page['menu_slug'] ) {
|
||||
// Unless the matching slug is a parent page redirecting to the child page.
|
||||
if ( isset( $options_page['_menu_slug'] ) && $options_page['_menu_slug'] !== $menu_slug ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
);
|
||||
|
||||
if ( ! empty( $duplicates ) ) {
|
||||
$valid = false;
|
||||
acf_add_internal_post_type_validation_error(
|
||||
'menu_slug',
|
||||
__( 'This Menu Slug is already in use by another ACF Options Page.', 'acf' ),
|
||||
'acf-ui-options-page'
|
||||
);
|
||||
}
|
||||
|
||||
return apply_filters( "acf/{$this->hook_name}/ajax_validate_values", $valid, $_POST['acf_ui_options_page'] ); // phpcs:ignore WordPress.Security -- Raw input send to hook for validation.
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the settings for ACF UI options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $post The ACF post to update.
|
||||
* @return array
|
||||
*/
|
||||
public function update_post( $post ) {
|
||||
if ( isset( $post['parent_slug'] ) && 'none' !== $post['parent_slug'] ) {
|
||||
$ui_options_pages = $this->get_posts();
|
||||
|
||||
foreach ( $ui_options_pages as $options_page ) {
|
||||
if ( $options_page['menu_slug'] === $post['parent_slug'] ) {
|
||||
$post['_parent'] = $options_page['ID'];
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return parent::update_post( $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the local JSON functionality for options pages.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param ACF_Local_JSON $local_json The ACF_Local_JSON object.
|
||||
* @return void
|
||||
*/
|
||||
public function setup_local_json() {
|
||||
$local_json = acf_get_instance( 'ACF_Local_JSON' );
|
||||
|
||||
// Event listeners.
|
||||
add_action( 'acf/update_ui_options_page', array( $local_json, 'update_internal_post_type' ) );
|
||||
add_action( 'acf/untrash_ui_options_page', array( $local_json, 'update_internal_post_type' ) );
|
||||
add_action( 'acf/trash_ui_options_page', array( $local_json, 'delete_internal_post_type' ) );
|
||||
add_action( 'acf/delete_ui_options_page', array( $local_json, 'delete_internal_post_type' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Includes all local JSON options pages.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function include_json_options_pages() {
|
||||
$local_json = acf_get_instance( 'ACF_Local_JSON' );
|
||||
|
||||
// Bail early if disabled.
|
||||
if ( ! $local_json->is_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get load paths.
|
||||
$files = $local_json->scan_files( 'acf-ui-options-page' );
|
||||
foreach ( $files as $key => $file ) {
|
||||
$json = json_decode( file_get_contents( $file ), true );
|
||||
$json['local'] = 'json';
|
||||
$json['local_file'] = $file;
|
||||
acf_add_local_internal_post_type( $json, 'acf-ui-options-page' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string that can be used to create an options page with PHP.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $post The main options page array.
|
||||
* @return string
|
||||
*/
|
||||
public function export_post_as_php( $post = array() ) {
|
||||
$return = '';
|
||||
if ( empty( $post ) ) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
// Validate and prepare the post for export.
|
||||
$post = $this->validate_post( $post );
|
||||
$args = $this->get_options_page_args( $post );
|
||||
|
||||
unset( $args['ID'] );
|
||||
|
||||
$code = var_export( $args, true ); // phpcs:ignore WordPress.PHP.DevelopmentFunctions -- Used for PHP export.
|
||||
|
||||
if ( ! $code ) {
|
||||
return $return;
|
||||
}
|
||||
|
||||
$code = $this->format_code_for_export( $code );
|
||||
$return .= "acf_add_options_page( {$code} );\r\n";
|
||||
|
||||
return esc_textarea( $return );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function returns whether the value was saved prior to the icon picker field or not.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param mixed $args The args for the icon field.
|
||||
* @return boolean
|
||||
*/
|
||||
public function value_was_saved_prior_to_icon_picker_field( $args ) {
|
||||
if (
|
||||
! empty( $args['menu_icon'] ) &&
|
||||
is_array( $args['menu_icon'] ) &&
|
||||
! empty( $args['menu_icon']['type'] ) &&
|
||||
! empty( $args['menu_icon']['value'] )
|
||||
) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Parses ACF options page settings and returns an array of args
|
||||
* to be handled by `acf_add_options_page()`.
|
||||
*
|
||||
* Omits settings that line up with the defaults to reduce the size
|
||||
* of the array passed to `acf_add_options_page()`, which might be exported.
|
||||
*
|
||||
* @since 6.2
|
||||
*
|
||||
* @param array $post The main ACF options page settings array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_options_page_args( $post ) {
|
||||
$args = array();
|
||||
$defaults = $this->get_settings_array();
|
||||
|
||||
// UI-specific params that don't need to be passed in.
|
||||
$ui_specific = array(
|
||||
'key',
|
||||
'title',
|
||||
'active',
|
||||
'menu_order',
|
||||
'advanced_configuration',
|
||||
'data_storage',
|
||||
);
|
||||
|
||||
foreach ( $post as $setting => $value ) {
|
||||
// Don't pass in UI specific or unknown settings.
|
||||
if ( in_array( $setting, $ui_specific, true ) || ! array_key_exists( $setting, $defaults ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Convert types.
|
||||
$default_type = gettype( $defaults[ $setting ] );
|
||||
if ( 'boolean' === $default_type ) {
|
||||
$value = filter_var( $value, FILTER_VALIDATE_BOOLEAN );
|
||||
}
|
||||
|
||||
// Escape HTML.
|
||||
if ( in_array( $setting, array( 'page_title', 'menu_title' ), true ) ) {
|
||||
$value = esc_html( $value );
|
||||
}
|
||||
|
||||
// A `parent_slug` value of "none" is only used in the UI.
|
||||
if ( 'parent_slug' === $setting && 'none' === $value ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// UI does not default redirect to child to true, but code does.
|
||||
if ( 'redirect' === $setting && ! $value ) {
|
||||
$args[ $setting ] = $value;
|
||||
continue;
|
||||
}
|
||||
|
||||
// Don't need to include if it's the same as a default.
|
||||
if ( $value === $defaults[ $setting ] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$args[ $setting ] = $value;
|
||||
}
|
||||
|
||||
// Override the icon_url if the value was saved after the icon picker was added to ACF in 6.3.
|
||||
if ( ! $this->value_was_saved_prior_to_icon_picker_field( $args ) ) {
|
||||
if ( $args['menu_icon']['type'] === 'url' ) {
|
||||
$args['icon_url'] = $args['menu_icon']['value'];
|
||||
}
|
||||
if ( $args['menu_icon']['type'] === 'media_library' ) {
|
||||
$image_url = wp_get_attachment_image_url($args['menu_icon']['value']);
|
||||
$args['icon_url'] = $image_url;
|
||||
}
|
||||
if ( $args['menu_icon']['type'] === 'dashicons' ) {
|
||||
$args['icon_url'] = $args['menu_icon']['value'];
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'acf/ui_options_page/registration_args', $args, $post );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_UI_Options_Page' );
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
1113
wp-content/plugins/advanced-custom-fields-pro/pro/updates.php
Normal file
1113
wp-content/plugins/advanced-custom-fields-pro/pro/updates.php
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user