initial commit
This commit is contained in:
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,512 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* acf_get_field_group
|
||||
*
|
||||
* Retrieves a field group for the given identifier.
|
||||
*
|
||||
* @date 30/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param (int|string) $id The field group ID, key or name.
|
||||
* @return (array|false) The field group array.
|
||||
*/
|
||||
function acf_get_field_group( $id = 0 ) {
|
||||
return acf_get_internal_post_type( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_raw_field_group
|
||||
*
|
||||
* Retrieves raw field group data for the given identifier.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (int|string) $id The field ID, key or name.
|
||||
* @return (array|false) The field group array.
|
||||
*/
|
||||
function acf_get_raw_field_group( $id = 0 ) {
|
||||
return acf_get_raw_internal_post_type( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_group_post
|
||||
*
|
||||
* Retrieves the field group's WP_Post object.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (int|string) $id The field group's ID, key or name.
|
||||
* @return (array|false) The field group's array.
|
||||
*/
|
||||
function acf_get_field_group_post( $id = 0 ) {
|
||||
return acf_get_internal_post_type_post( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_is_field_group_key
|
||||
*
|
||||
* Returns true if the given identifier is a field group key.
|
||||
*
|
||||
* @date 6/12/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_field_group_key( $id = '' ) {
|
||||
return acf_is_internal_post_type_key( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensures the given field group is valid.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_validate_field_group( $field_group = array() ) {
|
||||
return acf_validate_internal_post_type( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_valid_field_group
|
||||
*
|
||||
* Ensures the given field group is valid.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_valid_field_group( $field_group = false ) {
|
||||
return acf_validate_field_group( $field_group );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_translate_field_group
|
||||
*
|
||||
* Translates a field group's settings.
|
||||
*
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_translate_field_group( $field_group = array() ) {
|
||||
return acf_translate_internal_post_type( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_groups
|
||||
*
|
||||
* Returns and array of field_groups for the given $filter.
|
||||
*
|
||||
* @date 30/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $filter An array of args to filter results by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_field_groups( $filter = array() ) {
|
||||
return acf_get_internal_post_type_posts( 'acf-field-group', $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_raw_field_groups
|
||||
*
|
||||
* Returns and array of raw field_group data.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_raw_field_groups() {
|
||||
return acf_get_raw_internal_post_type_posts( 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_filter_field_groups
|
||||
*
|
||||
* Returns a filtered aray of field groups based on the given $args.
|
||||
*
|
||||
* @date 29/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_groups An array of field groups.
|
||||
* @param array $args An array of location args.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_field_groups( $field_groups, $args = array() ) {
|
||||
return acf_filter_internal_post_type_posts( $field_groups, $args, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_group_visibility
|
||||
*
|
||||
* Returns true if the given field group's location rules match the given $args.
|
||||
*
|
||||
* @date 7/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_groups An array of field groups.
|
||||
* @param array $args An array of location args.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_get_field_group_visibility( $field_group, $args = array() ) {
|
||||
|
||||
// Check if active.
|
||||
if ( ! $field_group['active'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Check if location rules exist
|
||||
if ( $field_group['location'] ) {
|
||||
|
||||
// Get the current screen.
|
||||
$screen = acf_get_location_screen( $args );
|
||||
|
||||
// Loop through location groups.
|
||||
foreach ( $field_group['location'] as $group ) {
|
||||
|
||||
// ignore group if no rules.
|
||||
if ( empty( $group ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Loop over rules and determine if all rules match.
|
||||
$match_group = true;
|
||||
foreach ( $group as $rule ) {
|
||||
if ( ! acf_match_location_rule( $rule, $screen, $field_group ) ) {
|
||||
$match_group = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If this group matches, show the field group.
|
||||
if ( $match_group ) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_update_field_group
|
||||
*
|
||||
* Updates a field group in the database.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_update_field_group( $field_group ) {
|
||||
return acf_update_internal_post_type( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* _acf_apply_unique_field_group_slug
|
||||
*
|
||||
* Allows full control over 'acf-field-group' slugs.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $slug The post slug.
|
||||
* @param int $post_ID Post ID.
|
||||
* @param string $post_status The post status.
|
||||
* @param string $post_type Post type.
|
||||
* @param int $post_parent Post parent ID
|
||||
* @param string $original_slug The original post slug.
|
||||
*/
|
||||
function _acf_apply_unique_field_group_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
|
||||
|
||||
// Check post type and reset to original value.
|
||||
if ( $post_type === 'acf-field-group' ) {
|
||||
return $original_slug;
|
||||
}
|
||||
|
||||
// Return slug.
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_flush_field_group_cache
|
||||
*
|
||||
* Deletes all caches for this field group.
|
||||
*
|
||||
* @date 22/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_field_group_cache( $field_group ) {
|
||||
acf_flush_internal_post_type_cache( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_delete_field_group
|
||||
*
|
||||
* Deletes a field group from the database.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (int|string) $id The field group ID, key or name.
|
||||
* @return bool True if field group was deleted.
|
||||
*/
|
||||
function acf_delete_field_group( $id = 0 ) {
|
||||
return acf_delete_internal_post_type( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_trash_field_group
|
||||
*
|
||||
* Trashes a field group from the database.
|
||||
*
|
||||
* @date 2/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param (int|string) $id The field group ID, key or name.
|
||||
* @return bool True if field group was trashed.
|
||||
*/
|
||||
function acf_trash_field_group( $id = 0 ) {
|
||||
return acf_trash_internal_post_type( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_untrash_field_group
|
||||
*
|
||||
* Restores a field_group from the trash.
|
||||
*
|
||||
* @date 2/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param (int|string) $id The field_group ID, key or name.
|
||||
* @return bool True if field_group was trashed.
|
||||
*/
|
||||
function acf_untrash_field_group( $id = 0 ) {
|
||||
return acf_untrash_internal_post_type( $id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter callback which returns the previous post_status instead of "draft" for the "acf-field-group" post type.
|
||||
*
|
||||
* Prior to WordPress 5.6.0, this filter was not needed as restored posts were always assigned their original status.
|
||||
*
|
||||
* @since 5.9.5
|
||||
*
|
||||
* @param string $new_status The new status of the post being restored.
|
||||
* @param int $post_id The ID of the post being restored.
|
||||
* @param string $previous_status The status of the post at the point where it was trashed.
|
||||
* @return string.
|
||||
*/
|
||||
function _acf_untrash_field_group_post_status( $new_status, $post_id, $previous_status ) {
|
||||
return ( get_post_type( $post_id ) === 'acf-field-group' ) ? $previous_status : $new_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_is_field_group
|
||||
*
|
||||
* Returns true if the given params match a field group.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @param mixed $id An optional identifier to search for.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_field_group( $field_group = false ) {
|
||||
return acf_is_internal_post_type( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_duplicate_field_group
|
||||
*
|
||||
* Duplicates a field group.
|
||||
*
|
||||
* @date 16/06/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param (int|string) $id The field_group ID, key or name.
|
||||
* @param int $new_post_id Optional post ID to override.
|
||||
* @return array The new field group.
|
||||
*/
|
||||
function acf_duplicate_field_group( $id = 0, $new_post_id = 0 ) {
|
||||
return acf_duplicate_internal_post_type( $id, $new_post_id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates a field group.
|
||||
*
|
||||
* @param int|string $id The field_group ID, key or name.
|
||||
* @param bool $activate True if the post should be activated.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_update_field_group_active_status( $id, $activate = true ) {
|
||||
return acf_update_internal_post_type_active_status( $id, $activate, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_group_style
|
||||
*
|
||||
* Returns the CSS styles generated from field group settings.
|
||||
*
|
||||
* @date 20/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return string.
|
||||
*/
|
||||
function acf_get_field_group_style( $field_group ) {
|
||||
|
||||
// Vars.
|
||||
$style = '';
|
||||
$elements = array(
|
||||
'permalink' => '#edit-slug-box',
|
||||
'the_content' => '#postdivrich',
|
||||
'excerpt' => '#postexcerpt',
|
||||
'custom_fields' => '#postcustom',
|
||||
'discussion' => '#commentstatusdiv',
|
||||
'comments' => '#commentsdiv',
|
||||
'slug' => '#slugdiv',
|
||||
'author' => '#authordiv',
|
||||
'format' => '#formatdiv',
|
||||
'page_attributes' => '#pageparentdiv',
|
||||
'featured_image' => '#postimagediv',
|
||||
'revisions' => '#revisionsdiv',
|
||||
'categories' => '#categorydiv',
|
||||
'tags' => '#tagsdiv-post_tag',
|
||||
'send-trackbacks' => '#trackbacksdiv',
|
||||
);
|
||||
|
||||
// Loop over field group settings and generate list of selectors to hide.
|
||||
if ( is_array( $field_group['hide_on_screen'] ) ) {
|
||||
$hide = array();
|
||||
foreach ( $field_group['hide_on_screen'] as $k ) {
|
||||
if ( isset( $elements[ $k ] ) ) {
|
||||
$id = $elements[ $k ];
|
||||
$hide[] = $id;
|
||||
$hide[] = '#screen-meta label[for=' . substr( $id, 1 ) . '-hide]';
|
||||
}
|
||||
}
|
||||
$style = implode( ', ', $hide ) . ' {display: none;}';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the generated CSS styles.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $style The CSS styles.
|
||||
* @param array $field_group The field group array.
|
||||
*/
|
||||
return apply_filters( 'acf/get_field_group_style', $style, $field_group );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_group_edit_link
|
||||
*
|
||||
* Checks if the current user can edit the field group and returns the edit url.
|
||||
*
|
||||
* @date 23/9/18
|
||||
* @since 5.7.7
|
||||
*
|
||||
* @param int $post_id The field group ID.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_field_group_edit_link( $post_id ) {
|
||||
return acf_get_internal_post_type_edit_link( $post_id, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_prepare_field_group_for_export
|
||||
*
|
||||
* Returns a modified field group ready for export.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_field_group_for_export( $field_group = array() ) {
|
||||
return acf_prepare_internal_post_type_for_export( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_prepare_field_group_for_import
|
||||
*
|
||||
* Prepares a field group for the import process.
|
||||
*
|
||||
* @date 21/11/19
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_field_group_for_import( $field_group ) {
|
||||
return acf_prepare_internal_post_type_for_import( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_import_field_group
|
||||
*
|
||||
* Imports a field group into the databse.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field_group The field group array.
|
||||
* @return array The new field group.
|
||||
*/
|
||||
function acf_import_field_group( $field_group ) {
|
||||
return acf_import_internal_post_type( $field_group, 'acf-field-group' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tabs for the field group settings.
|
||||
* We combine a list of default tabs with filtered tabs.
|
||||
* I.E. Default tabs should be static and should not be changed by the
|
||||
* filtered tabs.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array Key/value array of the default settings tabs for field group settings.
|
||||
*/
|
||||
function acf_get_combined_field_group_settings_tabs() {
|
||||
$default_field_group_settings_tabs = array(
|
||||
'location_rules' => __( 'Location Rules', 'acf' ),
|
||||
'presentation' => __( 'Presentation', 'acf' ),
|
||||
'group_settings' => __( 'Group Settings', 'acf' ),
|
||||
);
|
||||
|
||||
$field_group_settings_tabs = (array) apply_filters( 'acf/field_group/additional_group_settings_tabs', array() );
|
||||
|
||||
// remove any default tab values from the filter tabs.
|
||||
foreach ( $field_group_settings_tabs as $key => $tab ) {
|
||||
if ( isset( $default_field_group_settings_tabs[ $key ] ) ) {
|
||||
unset( $field_group_settings_tabs[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
$combined_field_group_settings_tabs = array_merge( $default_field_group_settings_tabs, $field_group_settings_tabs );
|
||||
|
||||
return $combined_field_group_settings_tabs;
|
||||
}
|
@ -0,0 +1,171 @@
|
||||
<?php
|
||||
|
||||
// Register store for form data.
|
||||
acf_register_store( 'form' );
|
||||
|
||||
/**
|
||||
* acf_set_form_data
|
||||
*
|
||||
* Sets data about the current form.
|
||||
*
|
||||
* @date 6/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $name The store name.
|
||||
* @param array $data Array of data to start the store with.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function acf_set_form_data( $name = '', $data = false ) {
|
||||
return acf_get_store( 'form' )->set( $name, $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_form_data
|
||||
*
|
||||
* Gets data about the current form.
|
||||
*
|
||||
* @date 6/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $name The store name.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_get_form_data( $name = '' ) {
|
||||
return acf_get_store( 'form' )->get( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_form_data
|
||||
*
|
||||
* Called within a form to set important information and render hidden inputs.
|
||||
*
|
||||
* @date 15/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function acf_form_data( $data = array() ) {
|
||||
|
||||
// Apply defaults.
|
||||
$data = wp_parse_args(
|
||||
$data,
|
||||
array(
|
||||
|
||||
/** @type string The current screen (post, user, taxonomy, etc). */
|
||||
'screen' => 'post',
|
||||
|
||||
/** @type int|string The ID of current post being edited. */
|
||||
'post_id' => 0,
|
||||
|
||||
/** @type bool Enables AJAX validation. */
|
||||
'validation' => true,
|
||||
)
|
||||
);
|
||||
|
||||
// Create nonce using screen.
|
||||
$data['nonce'] = wp_create_nonce( $data['screen'] );
|
||||
|
||||
// Append "changed" input used within "_wp_post_revision_fields" action.
|
||||
$data['changed'] = 0;
|
||||
|
||||
// Set data.
|
||||
acf_set_form_data( $data );
|
||||
|
||||
// Render HTML.
|
||||
?>
|
||||
<div id="acf-form-data" class="acf-hidden">
|
||||
<?php
|
||||
|
||||
// Create hidden inputs from $data
|
||||
foreach ( $data as $name => $value ) {
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'id' => '_acf_' . $name,
|
||||
'name' => '_acf_' . $name,
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires within the #acf-form-data element to add extra HTML.
|
||||
*
|
||||
* @date 15/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $data The form data.
|
||||
*/
|
||||
do_action( 'acf/form_data', $data );
|
||||
do_action( 'acf/input/form_data', $data );
|
||||
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* acf_save_post
|
||||
*
|
||||
* Saves the $_POST data.
|
||||
*
|
||||
* @date 15/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @param array $values An array of values to override $_POST.
|
||||
* @return bool True if save was successful.
|
||||
*/
|
||||
function acf_save_post( $post_id = 0, $values = null ) {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
|
||||
// Override $_POST data with $values.
|
||||
if ( $values !== null ) {
|
||||
$_POST['acf'] = $values;
|
||||
}
|
||||
|
||||
// Bail early if no data to save.
|
||||
if ( empty( $_POST['acf'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set form data (useful in various filters/actions).
|
||||
acf_set_form_data( 'post_id', $post_id );
|
||||
|
||||
// Filter $_POST data for users without the 'unfiltered_html' capability.
|
||||
if ( ! acf_allow_unfiltered_html() ) {
|
||||
$_POST['acf'] = wp_kses_post_deep( $_POST['acf'] );
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
// Do generic action.
|
||||
do_action( 'acf/save_post', $post_id );
|
||||
|
||||
// Return true.
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* _acf_do_save_post
|
||||
*
|
||||
* Private function hooked into 'acf/save_post' to actually save the $_POST data.
|
||||
* This allows developers to hook in before and after ACF has actually saved the data.
|
||||
*
|
||||
* @date 11/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @return void
|
||||
*/
|
||||
function _acf_do_save_post( $post_id = 0 ) {
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Verified elsewhere.
|
||||
if ( ! empty( $_POST['acf'] ) ) {
|
||||
acf_update_values( $_POST['acf'], $post_id ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized by WP when saved.
|
||||
}
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
}
|
||||
|
||||
// Run during generic action.
|
||||
add_action( 'acf/save_post', '_acf_do_save_post' );
|
@ -0,0 +1,655 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* acf_is_empty
|
||||
*
|
||||
* Returns true if the value provided is considered "empty". Allows numbers such as 0.
|
||||
*
|
||||
* @date 6/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param mixed $var The value to check.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_empty( $var ) {
|
||||
return ( ! $var && ! is_numeric( $var ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_not_empty
|
||||
*
|
||||
* Returns true if the value provided is considered "not empty". Allows numbers such as 0.
|
||||
*
|
||||
* @date 15/7/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param mixed $var The value to check.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_not_empty( $var ) {
|
||||
return ( $var || is_numeric( $var ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_uniqid
|
||||
*
|
||||
* Returns a unique numeric based id.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $prefix The id prefix. Defaults to 'acf'.
|
||||
* @return string
|
||||
*/
|
||||
function acf_uniqid( $prefix = 'acf' ) {
|
||||
|
||||
// Instantiate global counter.
|
||||
global $acf_uniqid;
|
||||
if ( ! isset( $acf_uniqid ) ) {
|
||||
$acf_uniqid = 1;
|
||||
}
|
||||
|
||||
// Return id.
|
||||
return $prefix . '-' . $acf_uniqid++;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_merge_attributes
|
||||
*
|
||||
* Merges together two arrays but with extra functionality to append class names.
|
||||
*
|
||||
* @date 22/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $array1 An array of attributes.
|
||||
* @param array $array2 An array of attributes.
|
||||
* @return array
|
||||
*/
|
||||
function acf_merge_attributes( $array1, $array2 ) {
|
||||
|
||||
// Merge together attributes.
|
||||
$array3 = array_merge( $array1, $array2 );
|
||||
|
||||
// Append together special attributes.
|
||||
foreach ( array( 'class', 'style' ) as $key ) {
|
||||
if ( isset( $array1[ $key ] ) && isset( $array2[ $key ] ) ) {
|
||||
$array3[ $key ] = trim( $array1[ $key ] ) . ' ' . trim( $array2[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $array3;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_cache_key
|
||||
*
|
||||
* Returns a filtered cache key.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @return string
|
||||
*/
|
||||
function acf_cache_key( $key = '' ) {
|
||||
|
||||
/**
|
||||
* Filters the cache key.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $key The cache key.
|
||||
* @param string $original_key The original cache key.
|
||||
*/
|
||||
return apply_filters( 'acf/get_cache_key', $key, $key );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_request_args
|
||||
*
|
||||
* Returns an array of $_REQUEST values using the provided defaults.
|
||||
*
|
||||
* @date 28/2/19
|
||||
* @since 5.7.13
|
||||
*
|
||||
* @param array $args An array of args.
|
||||
* @return array
|
||||
*/
|
||||
function acf_request_args( $args = array() ) {
|
||||
foreach ( $args as $k => $v ) {
|
||||
$args[ $k ] = isset( $_REQUEST[ $k ] ) ? acf_sanitize_request_args( $_REQUEST[ $k ] ) : $args[ $k ]; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Verified elsewhere.
|
||||
}
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a single $_REQUEST arg with fallback.
|
||||
*
|
||||
* @date 23/10/20
|
||||
* @since 5.9.2
|
||||
*
|
||||
* @param string $key The property name.
|
||||
* @param mixed $default The default value to fallback to.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_request_arg( $name = '', $default = null ) {
|
||||
return isset( $_REQUEST[ $name ] ) ? acf_sanitize_request_args( $_REQUEST[ $name ] ) : $default; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
}
|
||||
|
||||
// Register store.
|
||||
acf_register_store( 'filters' );
|
||||
|
||||
/**
|
||||
* acf_enable_filter
|
||||
*
|
||||
* Enables a filter with the given name.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param string name The modifer name.
|
||||
* @return void
|
||||
*/
|
||||
function acf_enable_filter( $name = '' ) {
|
||||
acf_get_store( 'filters' )->set( $name, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_disable_filter
|
||||
*
|
||||
* Disables a filter with the given name.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param string name The modifer name.
|
||||
* @return void
|
||||
*/
|
||||
function acf_disable_filter( $name = '' ) {
|
||||
acf_get_store( 'filters' )->set( $name, false );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_is_filter_enabled
|
||||
*
|
||||
* Returns the state of a filter for the given name.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param string name The modifer name.
|
||||
* @return array
|
||||
*/
|
||||
function acf_is_filter_enabled( $name = '' ) {
|
||||
return acf_get_store( 'filters' )->get( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_filters
|
||||
*
|
||||
* Returns an array of filters in their current state.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param void
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_filters() {
|
||||
return acf_get_store( 'filters' )->get();
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_set_filters
|
||||
*
|
||||
* Sets an array of filter states.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param array $filters An Array of modifers
|
||||
* @return array
|
||||
*/
|
||||
function acf_set_filters( $filters = array() ) {
|
||||
acf_get_store( 'filters' )->set( $filters );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_disable_filters
|
||||
*
|
||||
* Disables all filters and returns the previous state.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param void
|
||||
* @return array
|
||||
*/
|
||||
function acf_disable_filters() {
|
||||
|
||||
// Get state.
|
||||
$prev_state = acf_get_filters();
|
||||
|
||||
// Set all modifers as false.
|
||||
acf_set_filters( array_map( '__return_false', $prev_state ) );
|
||||
|
||||
// Return prev state.
|
||||
return $prev_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_enable_filters
|
||||
*
|
||||
* Enables all or an array of specific filters and returns the previous state.
|
||||
*
|
||||
* @date 14/7/16
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param array $filters An Array of modifers
|
||||
* @return array
|
||||
*/
|
||||
function acf_enable_filters( $filters = array() ) {
|
||||
|
||||
// Get state.
|
||||
$prev_state = acf_get_filters();
|
||||
|
||||
// Allow specific filters to be enabled.
|
||||
if ( $filters ) {
|
||||
acf_set_filters( $filters );
|
||||
|
||||
// Set all modifers as true.
|
||||
} else {
|
||||
acf_set_filters( array_map( '__return_true', $prev_state ) );
|
||||
}
|
||||
|
||||
// Return prev state.
|
||||
return $prev_state;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_idval
|
||||
*
|
||||
* Parses the provided value for an ID.
|
||||
*
|
||||
* @date 29/3/19
|
||||
* @since 5.7.14
|
||||
*
|
||||
* @param mixed $value A value to parse.
|
||||
* @return int
|
||||
*/
|
||||
function acf_idval( $value ) {
|
||||
|
||||
// Check if value is numeric.
|
||||
if ( is_numeric( $value ) ) {
|
||||
return (int) $value;
|
||||
|
||||
// Check if value is array.
|
||||
} elseif ( is_array( $value ) ) {
|
||||
return (int) isset( $value['ID'] ) ? $value['ID'] : 0;
|
||||
|
||||
// Check if value is object.
|
||||
} elseif ( is_object( $value ) ) {
|
||||
return (int) isset( $value->ID ) ? $value->ID : 0;
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_maybe_idval
|
||||
*
|
||||
* Checks value for potential id value.
|
||||
*
|
||||
* @date 6/4/19
|
||||
* @since 5.7.14
|
||||
*
|
||||
* @param mixed $value A value to parse.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_maybe_idval( $value ) {
|
||||
if ( $id = acf_idval( $value ) ) {
|
||||
return $id;
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert any numeric strings into their equivalent numeric type. This function will
|
||||
* work with both single values and arrays.
|
||||
*
|
||||
* @param mixed $value Either a single value or an array of values.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_format_numerics( $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
return array_map(
|
||||
function ( $v ) {
|
||||
return is_numeric( $v ) ? $v + 0 : $v;
|
||||
},
|
||||
$value
|
||||
);
|
||||
}
|
||||
|
||||
return is_numeric( $value ) ? $value + 0 : $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_numval
|
||||
*
|
||||
* Casts the provided value as eiter an int or float using a simple hack.
|
||||
*
|
||||
* @date 11/4/19
|
||||
* @since 5.7.14
|
||||
*
|
||||
* @param mixed $value A value to parse.
|
||||
* @return (int|float)
|
||||
*/
|
||||
function acf_numval( $value ) {
|
||||
return ( intval( $value ) == floatval( $value ) ) ? intval( $value ) : floatval( $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_idify
|
||||
*
|
||||
* Returns an id attribute friendly string.
|
||||
*
|
||||
* @date 24/12/17
|
||||
* @since 5.6.5
|
||||
*
|
||||
* @param string $str The string to convert.
|
||||
* @return string
|
||||
*/
|
||||
function acf_idify( $str = '' ) {
|
||||
return str_replace( array( '][', '[', ']' ), array( '-', '-', '' ), strtolower( $str ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a slug friendly string.
|
||||
*
|
||||
* @date 24/12/17
|
||||
* @since 5.6.5
|
||||
*
|
||||
* @param string $str The string to convert.
|
||||
* @param string $glue The glue between each slug piece.
|
||||
* @return string
|
||||
*/
|
||||
function acf_slugify( $str = '', $glue = '-' ) {
|
||||
$raw = $str;
|
||||
$slug = str_replace( array( '_', '-', '/', ' ' ), $glue, strtolower( remove_accents( $raw ) ) );
|
||||
$slug = preg_replace( '/[^A-Za-z0-9' . preg_quote( $glue ) . ']/', '', $slug );
|
||||
|
||||
/**
|
||||
* Filters the slug created by acf_slugify().
|
||||
*
|
||||
* @since 5.11.4
|
||||
*
|
||||
* @param string $slug The newly created slug.
|
||||
* @param string $raw The original string.
|
||||
* @param string $glue The separator used to join the string into a slug.
|
||||
*/
|
||||
return apply_filters( 'acf/slugify', $slug, $raw, $glue );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string with correct full stop punctuation.
|
||||
*
|
||||
* @date 12/7/19
|
||||
* @since 5.8.2
|
||||
*
|
||||
* @param string $str The string to format.
|
||||
* @return string
|
||||
*/
|
||||
function acf_punctify( $str = '' ) {
|
||||
if ( substr( trim( strip_tags( $str ) ), -1 ) !== '.' ) {
|
||||
return trim( $str ) . '.';
|
||||
}
|
||||
return trim( $str );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_did
|
||||
*
|
||||
* Returns true if ACF already did an event.
|
||||
*
|
||||
* @date 30/8/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param string $name The name of the event.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_did( $name ) {
|
||||
|
||||
// Return true if already did the event (preventing event).
|
||||
if ( acf_get_data( "acf_did_$name" ) ) {
|
||||
return true;
|
||||
|
||||
// Otherwise, update store and return false (alowing event).
|
||||
} else {
|
||||
acf_set_data( "acf_did_$name", true );
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the length of a string that has been submitted via $_POST.
|
||||
*
|
||||
* Uses the following process:
|
||||
* 1. Unslash the string because posted values will be slashed.
|
||||
* 2. Decode special characters because wp_kses() will normalize entities.
|
||||
* 3. Treat line-breaks as a single character instead of two.
|
||||
* 4. Use mb_strlen() to accomodate special characters.
|
||||
*
|
||||
* @date 04/06/2020
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $str The string to review.
|
||||
* @return int
|
||||
*/
|
||||
function acf_strlen( $str ) {
|
||||
return mb_strlen( str_replace( "\r\n", "\n", wp_specialchars_decode( wp_unslash( $str ) ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a value with default fallback.
|
||||
*
|
||||
* @date 6/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param mixed $value The value.
|
||||
* @param mixed $default_value The default value.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_with_default( $value, $default_value ) {
|
||||
return $value ? $value : $default_value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current priority of a running action.
|
||||
*
|
||||
* @date 14/07/2020
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $action The action name.
|
||||
* @return int|bool
|
||||
*/
|
||||
function acf_doing_action( $action ) {
|
||||
global $wp_filter;
|
||||
if ( isset( $wp_filter[ $action ] ) ) {
|
||||
return $wp_filter[ $action ]->current_priority();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the current URL.
|
||||
*
|
||||
* @date 23/01/2015
|
||||
* @since 5.1.5
|
||||
*
|
||||
* @param void
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_current_url() {
|
||||
// Ensure props exist to avoid PHP Notice during CLI commands.
|
||||
if ( isset( $_SERVER['HTTP_HOST'], $_SERVER['REQUEST_URI'] ) ) {
|
||||
return ( is_ssl() ? 'https' : 'http' ) . '://' . filter_var( $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'], FILTER_SANITIZE_URL );
|
||||
}
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Add UTM tracking tags to internal ACF URLs
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param string $url The URL to be tagged.
|
||||
* @param string $campaign The campaign tag.
|
||||
* @param string $content The UTM content tag.
|
||||
* @return string
|
||||
*/
|
||||
function acf_add_url_utm_tags( $url, $campaign, $content, $anchor = false ) {
|
||||
$anchor_url = $anchor ? '#' . $anchor : '';
|
||||
$query = http_build_query(
|
||||
apply_filters(
|
||||
'acf/admin/acf_url_utm_parameters',
|
||||
array(
|
||||
'utm_source' => ( defined( 'ACF_PRO' ) && ACF_PRO ) ? 'ACF PRO' : 'ACF Free',
|
||||
'utm_medium' => 'insideplugin',
|
||||
'utm_campaign' => $campaign,
|
||||
'utm_content' => $content,
|
||||
)
|
||||
)
|
||||
);
|
||||
if ( $query ) {
|
||||
$query = '?' . $query;
|
||||
}
|
||||
return esc_url( $url . $query . $anchor_url );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes request arguments.
|
||||
*
|
||||
* @param mixed $args The data to sanitize.
|
||||
*
|
||||
* @return array|bool|float|int|mixed|string
|
||||
*/
|
||||
function acf_sanitize_request_args( $args = array() ) {
|
||||
switch ( gettype( $args ) ) {
|
||||
case 'boolean':
|
||||
return (bool) $args;
|
||||
case 'integer':
|
||||
return (int) $args;
|
||||
case 'double':
|
||||
return (float) $args;
|
||||
case 'array':
|
||||
$sanitized = array();
|
||||
foreach ( $args as $key => $value ) {
|
||||
$key = sanitize_text_field( $key );
|
||||
$sanitized[ $key ] = acf_sanitize_request_args( $value );
|
||||
}
|
||||
return $sanitized;
|
||||
case 'object':
|
||||
return wp_kses_post_deep( $args );
|
||||
case 'string':
|
||||
default:
|
||||
return wp_kses( $args, 'acf' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes file upload arrays.
|
||||
*
|
||||
* @since 6.0.4
|
||||
*
|
||||
* @param array $args The file array.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_sanitize_files_array( array $args = array() ) {
|
||||
$defaults = array(
|
||||
'name' => '',
|
||||
'tmp_name' => '',
|
||||
'type' => '',
|
||||
'size' => 0,
|
||||
'error' => '',
|
||||
);
|
||||
|
||||
$args = wp_parse_args( $args, $defaults );
|
||||
|
||||
if ( empty( $args['name'] ) ) {
|
||||
return $defaults;
|
||||
}
|
||||
|
||||
if ( is_array( $args['name'] ) ) {
|
||||
$files = array();
|
||||
$files['name'] = acf_sanitize_files_value_array( $args['name'], 'sanitize_file_name' );
|
||||
$files['tmp_name'] = acf_sanitize_files_value_array( $args['tmp_name'], 'sanitize_text_field' );
|
||||
$files['type'] = acf_sanitize_files_value_array( $args['type'], 'sanitize_text_field' );
|
||||
$files['size'] = acf_sanitize_files_value_array( $args['size'], 'absint' );
|
||||
$files['error'] = acf_sanitize_files_value_array( $args['error'], 'absint' );
|
||||
return $files;
|
||||
}
|
||||
|
||||
$file = array();
|
||||
$file['name'] = sanitize_file_name( $args['name'] );
|
||||
$file['tmp_name'] = sanitize_text_field( $args['tmp_name'] );
|
||||
$file['type'] = sanitize_text_field( $args['type'] );
|
||||
$file['size'] = absint( $args['size'] );
|
||||
$file['error'] = absint( $args['error'] );
|
||||
|
||||
return $file;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sanitizes file upload values within the array.
|
||||
*
|
||||
* This addresses nested file fields within repeaters and groups.
|
||||
*
|
||||
* @since 6.0.5
|
||||
*
|
||||
* @param array $array The file upload array.
|
||||
* @param string $sanitize_function Callback used to sanitize array value.
|
||||
* @return array
|
||||
*/
|
||||
function acf_sanitize_files_value_array( $array, $sanitize_function ) {
|
||||
if ( ! function_exists( $sanitize_function ) ) {
|
||||
return $array;
|
||||
}
|
||||
|
||||
if ( ! is_array( $array ) ) {
|
||||
return $sanitize_function( $array );
|
||||
}
|
||||
|
||||
foreach ( $array as $key => $value ) {
|
||||
if ( is_array( $value ) ) {
|
||||
$array[ $key ] = acf_sanitize_files_value_array( $value, $sanitize_function );
|
||||
} else {
|
||||
$array[ $key ] = $sanitize_function( $value );
|
||||
}
|
||||
}
|
||||
|
||||
return $array;
|
||||
}
|
||||
|
||||
/**
|
||||
* Maybe unserialize, but don't allow any classes.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $data String to be unserialized, if serialized.
|
||||
* @return mixed The unserialized, or original data.
|
||||
*/
|
||||
function acf_maybe_unserialize( $data ) {
|
||||
if ( is_serialized( $data ) ) { // Don't attempt to unserialize data that wasn't serialized going in.
|
||||
if ( PHP_VERSION_ID >= 70000 ) {
|
||||
return @unserialize( trim( $data ), array( 'allowed_classes' => false ) ); //phpcs:ignore -- code only runs on PHP7+
|
||||
} else {
|
||||
return @\ACF\Brumann\Polyfill\unserialize::unserialize( trim( $data ), array( 'allowed_classes' => false ) );
|
||||
}
|
||||
}
|
||||
|
||||
return $data;
|
||||
}
|
@ -0,0 +1,223 @@
|
||||
<?php
|
||||
|
||||
// Register store.
|
||||
acf_register_store( 'hook-variations' );
|
||||
|
||||
/**
|
||||
* acf_add_filter_variations
|
||||
*
|
||||
* Registers variations for the given filter.
|
||||
*
|
||||
* @date 26/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $filter The filter name.
|
||||
* @param array $variations An array variation keys.
|
||||
* @param int $index The param index to find variation values.
|
||||
* @return void
|
||||
*/
|
||||
function acf_add_filter_variations( $filter = '', $variations = array(), $index = 0 ) {
|
||||
|
||||
// Store replacement data.
|
||||
acf_get_store( 'hook-variations' )->set(
|
||||
$filter,
|
||||
array(
|
||||
'type' => 'filter',
|
||||
'variations' => $variations,
|
||||
'index' => $index,
|
||||
)
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
|
||||
add_filter( $filter, '_acf_apply_hook_variations', 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_add_action_variations
|
||||
*
|
||||
* Registers variations for the given action.
|
||||
*
|
||||
* @date 26/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $action The action name.
|
||||
* @param array $variations An array variation keys.
|
||||
* @param int $index The param index to find variation values.
|
||||
* @return void
|
||||
*/
|
||||
function acf_add_action_variations( $action = '', $variations = array(), $index = 0 ) {
|
||||
|
||||
// Store replacement data.
|
||||
acf_get_store( 'hook-variations' )->set(
|
||||
$action,
|
||||
array(
|
||||
'type' => 'action',
|
||||
'variations' => $variations,
|
||||
'index' => $index,
|
||||
)
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priotiry of 10, and accepted args of 10 (ignored by WP).
|
||||
add_action( $action, '_acf_apply_hook_variations', 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* _acf_apply_hook_variations
|
||||
*
|
||||
* Applies hook variations during apply_filters() or do_action().
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param mixed
|
||||
* @return mixed
|
||||
*/
|
||||
function _acf_apply_hook_variations() {
|
||||
|
||||
// Get current filter.
|
||||
$filter = current_filter();
|
||||
|
||||
// Get args provided.
|
||||
$args = func_get_args();
|
||||
|
||||
// Get variation information.
|
||||
$variations = acf_get_store( 'hook-variations' )->get( $filter );
|
||||
$index = $variations['index'];
|
||||
$type = $variations['type'];
|
||||
$variations = $variations['variations'];
|
||||
|
||||
// Find field in args using index.
|
||||
$field = $args[ $index ];
|
||||
|
||||
// Loop over variations and apply filters.
|
||||
foreach ( $variations as $variation ) {
|
||||
|
||||
// Get value from field.
|
||||
// First look for "backup" value ("_name", "_key").
|
||||
if ( isset( $field[ "_$variation" ] ) ) {
|
||||
$value = $field[ "_$variation" ];
|
||||
} elseif ( isset( $field[ $variation ] ) ) {
|
||||
$value = $field[ $variation ];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Apply filters.
|
||||
if ( $type === 'filter' ) {
|
||||
$args[0] = apply_filters_ref_array( "$filter/$variation=$value", $args );
|
||||
|
||||
// Or do action.
|
||||
} else {
|
||||
do_action_ref_array( "$filter/$variation=$value", $args );
|
||||
}
|
||||
}
|
||||
|
||||
// Return first arg.
|
||||
return $args[0];
|
||||
}
|
||||
|
||||
// Register store.
|
||||
acf_register_store( 'deprecated-hooks' );
|
||||
|
||||
/**
|
||||
* acf_add_deprecated_filter
|
||||
*
|
||||
* Registers a deprecated filter to run during the replacement.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $deprecated The deprecated hook.
|
||||
* @param string $version The version this hook was deprecated.
|
||||
* @param string $replacement The replacement hook.
|
||||
* @return void
|
||||
*/
|
||||
function acf_add_deprecated_filter( $deprecated, $version, $replacement ) {
|
||||
|
||||
// Store replacement data.
|
||||
acf_get_store( 'deprecated-hooks' )->append(
|
||||
array(
|
||||
'type' => 'filter',
|
||||
'deprecated' => $deprecated,
|
||||
'replacement' => $replacement,
|
||||
'version' => $version,
|
||||
)
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priority of 10, and accepted args of 10 (ignored by WP).
|
||||
add_filter( $replacement, '_acf_apply_deprecated_hook', 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_add_deprecated_action
|
||||
*
|
||||
* Registers a deprecated action to run during the replacement.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $deprecated The deprecated hook.
|
||||
* @param string $version The version this hook was deprecated.
|
||||
* @param string $replacement The replacement hook.
|
||||
* @return void
|
||||
*/
|
||||
function acf_add_deprecated_action( $deprecated, $version, $replacement ) {
|
||||
|
||||
// Store replacement data.
|
||||
acf_get_store( 'deprecated-hooks' )->append(
|
||||
array(
|
||||
'type' => 'action',
|
||||
'deprecated' => $deprecated,
|
||||
'replacement' => $replacement,
|
||||
'version' => $version,
|
||||
)
|
||||
);
|
||||
|
||||
// Add generic handler.
|
||||
// Use a priority of 10, and accepted args of 10 (ignored by WP).
|
||||
add_filter( $replacement, '_acf_apply_deprecated_hook', 10, 10 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Applies a deprecated filter during apply_filters() or do_action().
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param mixed
|
||||
* @return mixed
|
||||
*/
|
||||
function _acf_apply_deprecated_hook() {
|
||||
// Get current hook.
|
||||
$current_hook = current_filter();
|
||||
|
||||
// Get args provided.
|
||||
$args = func_get_args();
|
||||
|
||||
// Get deprecated items for this hook.
|
||||
$deprecated_hooks = acf_get_store( 'deprecated-hooks' )->query( array( 'replacement' => $current_hook ) );
|
||||
|
||||
// Loop over results.
|
||||
foreach ( $deprecated_hooks as $hook ) {
|
||||
// Check if anyone is hooked into this deprecated hook.
|
||||
if ( isset( $hook['deprecated'] ) && has_filter( $hook['deprecated'] ) ) {
|
||||
|
||||
// Log warning.
|
||||
// _deprecated_hook( $deprecated, $version, $hook );
|
||||
|
||||
// Apply the item/do the action.
|
||||
if ( $hook['type'] === 'filter' ) {
|
||||
$args[0] = apply_filters_ref_array( $hook['deprecated'], $args );
|
||||
} else {
|
||||
do_action_ref_array( $hook['deprecated'], $args );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Return first arg.
|
||||
return $args[0];
|
||||
}
|
||||
|
@ -0,0 +1,532 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* acf_filter_attrs
|
||||
*
|
||||
* Filters out empty attrs from the provided array.
|
||||
*
|
||||
* @date 11/6/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_attrs( $attrs ) {
|
||||
|
||||
// Filter out empty attrs but allow "0" values.
|
||||
$filtered = array_filter( $attrs, 'acf_not_empty' );
|
||||
|
||||
// Correct specific attributes (required="required").
|
||||
foreach ( array( 'required', 'readonly', 'disabled', 'multiple' ) as $key ) {
|
||||
unset( $filtered[ $key ] );
|
||||
if ( ! empty( $attrs[ $key ] ) ) {
|
||||
$filtered[ $key ] = $key;
|
||||
}
|
||||
}
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_esc_attrs
|
||||
*
|
||||
* Generated valid HTML from an array of attrs.
|
||||
*
|
||||
* @date 11/6/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_attrs( $attrs ) {
|
||||
$html = '';
|
||||
|
||||
// Loop over attrs and validate data types.
|
||||
foreach ( $attrs as $k => $v ) {
|
||||
|
||||
// String (but don't trim value).
|
||||
if ( is_string( $v ) && ( $k !== 'value' ) ) {
|
||||
$v = trim( $v );
|
||||
|
||||
// Boolean
|
||||
} elseif ( is_bool( $v ) ) {
|
||||
$v = $v ? 1 : 0;
|
||||
|
||||
// Object
|
||||
} elseif ( is_array( $v ) || is_object( $v ) ) {
|
||||
$v = json_encode( $v );
|
||||
}
|
||||
|
||||
// Generate HTML.
|
||||
$html .= sprintf( ' %s="%s"', esc_attr( $k ), esc_attr( $v ) );
|
||||
}
|
||||
|
||||
// Return trimmed.
|
||||
return trim( $html );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Sanitizes text content and strips out disallowed HTML.
|
||||
*
|
||||
* This function emulates `wp_kses_post()` with a context of "acf" for extensibility.
|
||||
*
|
||||
* @date 16/4/21
|
||||
* @since 5.9.6
|
||||
*
|
||||
* @param string $string
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_html( $string = '' ) {
|
||||
return wp_kses( (string) $string, 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Private callback for the "wp_kses_allowed_html" filter used to return allowed HTML for "acf" context.
|
||||
*
|
||||
* @date 16/4/21
|
||||
* @since 5.9.6
|
||||
*
|
||||
* @param array $tags An array of allowed tags.
|
||||
* @param string $context The context name.
|
||||
* @return array.
|
||||
*/
|
||||
|
||||
function _acf_kses_allowed_html( $tags, $context ) {
|
||||
global $allowedposttags;
|
||||
|
||||
if ( $context === 'acf' ) {
|
||||
return $allowedposttags;
|
||||
}
|
||||
return $tags;
|
||||
}
|
||||
|
||||
add_filter( 'wp_kses_allowed_html', '_acf_kses_allowed_html', 0, 2 );
|
||||
|
||||
/**
|
||||
* acf_html_input
|
||||
*
|
||||
* Returns the HTML of an input.
|
||||
*
|
||||
* @date 13/6/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
// function acf_html_input( $attrs = array() ) {
|
||||
// return sprintf( '<input %s/>', acf_esc_attrs($attrs) );
|
||||
// }
|
||||
|
||||
/**
|
||||
* acf_hidden_input
|
||||
*
|
||||
* Renders the HTML of a hidden input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_hidden_input( $attrs = array() ) {
|
||||
echo acf_get_hidden_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_hidden_input
|
||||
*
|
||||
* Returns the HTML of a hidden input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_hidden_input( $attrs = array() ) {
|
||||
return sprintf( '<input type="hidden" %s/>', acf_esc_attrs( $attrs ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_text_input
|
||||
*
|
||||
* Renders the HTML of a text input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_text_input( $attrs = array() ) {
|
||||
echo acf_get_text_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_text_input
|
||||
*
|
||||
* Returns the HTML of a text input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_text_input( $attrs = array() ) {
|
||||
$attrs = wp_parse_args(
|
||||
$attrs,
|
||||
array(
|
||||
'type' => 'text',
|
||||
)
|
||||
);
|
||||
if ( isset( $attrs['value'] ) && is_string( $attrs['value'] ) ) {
|
||||
$attrs['value'] = htmlspecialchars( $attrs['value'] );
|
||||
}
|
||||
return sprintf( '<input %s/>', acf_esc_attrs( $attrs ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_file_input
|
||||
*
|
||||
* Renders the HTML of a file input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_file_input( $attrs = array() ) {
|
||||
echo acf_get_file_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_file_input
|
||||
*
|
||||
* Returns the HTML of a file input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_file_input( $attrs = array() ) {
|
||||
$field_key = isset( $attrs['key'] ) && is_string( $attrs['key'] ) ? $attrs['key'] : '';
|
||||
$nonce_field = '';
|
||||
|
||||
/**
|
||||
* If we don't have a field key (most likely because this was called by a third-party field),
|
||||
* we have to try to guess the field key based on the field name.
|
||||
*/
|
||||
if ( '' === $field_key ) {
|
||||
$parts = explode( '[', $attrs['name'] );
|
||||
if ( is_array( $parts ) && ! empty( $parts[1] ) ) {
|
||||
// Remove the trailing `]`.
|
||||
$field_key = substr( end( $parts ), 0, -1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* We only output the nonce if we have a field key, as it's possible to render
|
||||
* the file input without a real field. But, basic uploaders that don't have any
|
||||
* custom logic will likely fail to upload anyway if they don't have a field key.
|
||||
*/
|
||||
if ( '' !== $field_key ) {
|
||||
$nonce_attrs = array(
|
||||
'name' => 'acf[' . $field_key . '_file_nonce]',
|
||||
'value' => wp_create_nonce( 'acf/file_uploader_nonce/' . $field_key ),
|
||||
);
|
||||
$nonce_field = sprintf(
|
||||
'<input type="hidden" %s />',
|
||||
acf_esc_attrs( $nonce_attrs )
|
||||
);
|
||||
}
|
||||
|
||||
return sprintf(
|
||||
'<input type="file" %1$s />%2$s',
|
||||
acf_esc_attrs( $attrs ),
|
||||
$nonce_field
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_textarea_input
|
||||
*
|
||||
* Renders the HTML of a textarea input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_textarea_input( $attrs = array() ) {
|
||||
echo acf_get_textarea_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_textarea_input
|
||||
*
|
||||
* Returns the HTML of a textarea input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_textarea_input( $attrs = array() ) {
|
||||
$value = '';
|
||||
if ( isset( $attrs['value'] ) ) {
|
||||
$value = $attrs['value'];
|
||||
unset( $attrs['value'] );
|
||||
}
|
||||
return sprintf( '<textarea %s>%s</textarea>', acf_esc_attrs( $attrs ), esc_textarea( $value ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_checkbox_input
|
||||
*
|
||||
* Renders the HTML of a checkbox input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_checkbox_input( $attrs = array() ) {
|
||||
echo acf_get_checkbox_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_checkbox_input
|
||||
*
|
||||
* Returns the HTML of a checkbox input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_checkbox_input( $attrs = array() ) {
|
||||
|
||||
// Allow radio or checkbox type.
|
||||
$attrs = wp_parse_args(
|
||||
$attrs,
|
||||
array(
|
||||
'type' => 'checkbox',
|
||||
)
|
||||
);
|
||||
|
||||
// Get label.
|
||||
$label = '';
|
||||
if ( isset( $attrs['label'] ) ) {
|
||||
$label = $attrs['label'];
|
||||
unset( $attrs['label'] );
|
||||
}
|
||||
|
||||
// Render.
|
||||
$checked = isset( $attrs['checked'] );
|
||||
return '<label' . ( $checked ? ' class="selected"' : '' ) . '><input ' . acf_esc_attr( $attrs ) . '/> ' . acf_esc_html( $label ) . '</label>';
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_radio_input
|
||||
*
|
||||
* Renders the HTML of a radio input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_radio_input( $attrs = array() ) {
|
||||
echo acf_get_radio_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_radio_input
|
||||
*
|
||||
* Returns the HTML of a radio input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_radio_input( $attrs = array() ) {
|
||||
$attrs['type'] = 'radio';
|
||||
return acf_get_checkbox_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_select_input
|
||||
*
|
||||
* Renders the HTML of a select input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_select_input( $attrs = array() ) {
|
||||
echo acf_get_select_input( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_select_input
|
||||
*
|
||||
* Returns the HTML of a select input.
|
||||
*
|
||||
* @date 3/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_select_input( $attrs = array() ) {
|
||||
$value = (array) acf_extract_var( $attrs, 'value' );
|
||||
$choices = (array) acf_extract_var( $attrs, 'choices' );
|
||||
return sprintf(
|
||||
'<select %s>%s</select>',
|
||||
acf_esc_attrs( $attrs ),
|
||||
acf_walk_select_input( $choices, $value )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_walk_select_input
|
||||
*
|
||||
* Returns the HTML of a select input's choices.
|
||||
*
|
||||
* @date 27/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param array $choices The choices to walk through.
|
||||
* @param array $values The selected choices.
|
||||
* @param array $depth The current walk depth.
|
||||
* @return string
|
||||
*/
|
||||
function acf_walk_select_input( $choices = array(), $values = array(), $depth = 0 ) {
|
||||
$html = '';
|
||||
|
||||
// Sanitize values for 'selected' matching (only once).
|
||||
if ( $depth == 0 ) {
|
||||
$values = array_map( 'esc_attr', $values );
|
||||
}
|
||||
|
||||
// Loop over choices and append to html.
|
||||
if ( $choices ) {
|
||||
foreach ( $choices as $value => $label ) {
|
||||
|
||||
// Multiple (optgroup)
|
||||
if ( is_array( $label ) ) {
|
||||
$html .= sprintf(
|
||||
'<optgroup label="%s">%s</optgroup>',
|
||||
esc_attr( $value ),
|
||||
acf_walk_select_input( $label, $values, $depth + 1 )
|
||||
);
|
||||
|
||||
// single (option)
|
||||
} else {
|
||||
$attrs = array(
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// If is selected.
|
||||
$pos = array_search( esc_attr( $value ), $values );
|
||||
if ( $pos !== false ) {
|
||||
$attrs['selected'] = 'selected';
|
||||
$attrs['data-i'] = $pos;
|
||||
}
|
||||
$html .= sprintf( '<option %s>%s</option>', acf_esc_attr( $attrs ), esc_html( $label ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_clean_atts
|
||||
*
|
||||
* See acf_filter_attrs().
|
||||
*
|
||||
* @date 3/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_clean_atts( $attrs ) {
|
||||
return acf_filter_attrs( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_esc_atts
|
||||
*
|
||||
* See acf_esc_attrs().
|
||||
*
|
||||
* @date 27/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_atts( $attrs ) {
|
||||
return acf_esc_attrs( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_esc_attr
|
||||
*
|
||||
* See acf_esc_attrs().
|
||||
*
|
||||
* @date 13/6/19
|
||||
* @since 5.8.1
|
||||
* @deprecated 5.6.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_attr( $attrs ) {
|
||||
return acf_esc_attrs( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_esc_attr_e
|
||||
*
|
||||
* See acf_esc_attrs().
|
||||
*
|
||||
* @date 13/6/19
|
||||
* @since 5.8.1
|
||||
* @deprecated 5.6.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_attr_e( $attrs ) {
|
||||
echo acf_esc_attrs( $attrs );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_esc_atts_e
|
||||
*
|
||||
* See acf_esc_attrs().
|
||||
*
|
||||
* @date 13/6/19
|
||||
* @since 5.8.1
|
||||
* @deprecated 5.6.0
|
||||
*
|
||||
* @param array $attrs The array of attrs.
|
||||
* @return string
|
||||
*/
|
||||
function acf_esc_atts_e( $attrs ) {
|
||||
echo acf_esc_attrs( $attrs );
|
||||
}
|
@ -0,0 +1,622 @@
|
||||
<?php
|
||||
/**
|
||||
* Generic functions for accessing ACF objects stored as WordPress post types which aren't handled by type specific functions.
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Gets an instance of an ACF_Internal_Post_Type.
|
||||
*
|
||||
* @param string $post_type The ACF internal post type to get the instance for.
|
||||
* @return ACF_Internal_Post_Type|bool The internal post type class instance, or false on failure.
|
||||
*/
|
||||
function acf_get_internal_post_type_instance( $post_type = 'acf-field-group' ) {
|
||||
$store = acf_get_store( 'internal-post-types' );
|
||||
if ( ! $store ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$instance = $store->get( $post_type );
|
||||
if ( ! $instance ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return acf_get_instance( $instance );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ACF CPT object as an array
|
||||
*
|
||||
* @param int $id The post ID being queried.
|
||||
* @param string $post_type The post type being queried.
|
||||
* @return array|false The post type object.
|
||||
*/
|
||||
function acf_get_internal_post_type( $id, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( ! $instance ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $instance->get_post( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves raw internal post type data for the given identifier.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID.
|
||||
* @param string $post_type The post type name.
|
||||
* @return array|false The internal post type array.
|
||||
*/
|
||||
function acf_get_raw_internal_post_type( $id, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( ! $instance ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $instance->get_raw_post( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post object from an ACF internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID, key, or name.
|
||||
* @param string $post_type The post type name.
|
||||
* @return object|bool The post object, or false on failure.
|
||||
*/
|
||||
function acf_get_internal_post_type_post( $id, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( ! $instance ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $instance->get_post_object( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given identifier is a ACF internal post type key.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @param string $post_type The ACF post type the key is for.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_internal_post_type_key( $id = '', $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
if ( ! $instance ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $instance->is_post_key( $id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an ACF internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $internal_post_type The internal post type array.
|
||||
* @param string $post_type_name The post type name.
|
||||
* @return array|bool
|
||||
*/
|
||||
function acf_validate_internal_post_type( $internal_post_type, $post_type_name ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type_name );
|
||||
|
||||
if ( ! $instance ) {
|
||||
return false; // TODO: Should this return an empty array instead?
|
||||
}
|
||||
|
||||
return $instance->validate_post( $internal_post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the settings for an ACF internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $internal_post_type The ACF post array.
|
||||
* @param string $post_type The post type name.
|
||||
* @return array
|
||||
*/
|
||||
function acf_translate_internal_post_type( $internal_post_type, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( ! $instance ) {
|
||||
return $internal_post_type;
|
||||
}
|
||||
|
||||
return $instance->translate_post( $internal_post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and array of ACF posts for the given $filter.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $post_type The ACF post type to get posts for.
|
||||
* @param array $filter An array of args to filter results by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_internal_post_type_posts( $post_type = 'acf-field-group', $filter = array() ) {
|
||||
$posts = array();
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$posts = $instance->get_posts( $filter );
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of raw/unvalidated ACF post data.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $post_type The ACF post type to get post data for.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_raw_internal_post_type_posts( $post_type ) {
|
||||
$raw_posts = array();
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$raw_posts = $instance->get_raw_posts();
|
||||
}
|
||||
|
||||
return $raw_posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered array of ACF posts based on the given $args.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $posts An array of ACF posts.
|
||||
* @param array $args An array of args to filter by.
|
||||
* @param string $post_type The ACF post type of the posts being filtered.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_internal_post_type_posts( $posts, $args = array(), $post_type = 'acf-field-group' ) {
|
||||
$filtered = array();
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$filtered = $instance->filter_posts( $posts, $args );
|
||||
}
|
||||
|
||||
return $filtered;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a internal post type in the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $internal_post_type Array of data to be saved.
|
||||
* @param string $post_type_name The internal post type being updated.
|
||||
* @return array
|
||||
*/
|
||||
function acf_update_internal_post_type( $internal_post_type, $post_type_name ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type_name );
|
||||
|
||||
if ( $instance ) {
|
||||
$internal_post_type = $instance->update_post( $internal_post_type );
|
||||
}
|
||||
|
||||
return $internal_post_type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all caches for the provided ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The ACF post type the cache is being cleared for.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_internal_post_type_cache( $post, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$instance->flush_post_cache( $post );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an internal post type from the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The internal post type ID, key or name.
|
||||
* @param string $post_type_name The post type to be deleted.
|
||||
* @return bool True if field group was deleted.
|
||||
*/
|
||||
function acf_delete_internal_post_type( $id = 0, $post_type_name = '' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type_name );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->delete_post( $id );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes an internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The internal post type ID, key, or name.
|
||||
* @param string $post_type_name The post type being trashed.
|
||||
* @return bool True if post was trashed.
|
||||
*/
|
||||
function acf_trash_internal_post_type( $id = 0, $post_type_name = '' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type_name );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->trash_post( $id );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an ACF post from the trash.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The internal post type ID, key, or name.
|
||||
* @param string $post_type_name The post type being untrashed.
|
||||
* @return bool True if post was untrashed.
|
||||
*/
|
||||
function acf_untrash_internal_post_type( $id = 0, $post_type_name = '' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type_name );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->untrash_post( $id );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given params match an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The ACF post type.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_internal_post_type( $post, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->is_post( $post );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The field_group ID, key or name.
|
||||
* @param int $new_post_id Optional ID to override.
|
||||
* @param string $post_type The post type of the post being duplicated.
|
||||
* @return array|bool The new ACF post, or false on failure.
|
||||
*/
|
||||
function acf_duplicate_internal_post_type( $id = 0, $new_post_id = 0, $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->duplicate_post( $id, $new_post_id );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates an ACF post.
|
||||
*
|
||||
* @param int|string $id The field_group ID, key or name.
|
||||
* @param bool $activate True if the post should be activated.
|
||||
* @param string $post_type The post type being activated/deactivated.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_update_internal_post_type_active_status( $id, $activate = true, $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->update_post_active_status( $id, $activate );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can edit the field group and returns the edit url.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int $post_id The ACF post ID.
|
||||
* @param string $post_type The ACF post type to get the edit link for.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_internal_post_type_edit_link( $post_id, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->get_post_edit_link( $post_id );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified field group ready for export.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The post type of the ACF post being exported.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_internal_post_type_for_export( $post = array(), $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$post = $instance->prepare_post_for_export( $post );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports an ACF post as PHP.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The post type of the ACF post being exported.
|
||||
* @return string|bool
|
||||
*/
|
||||
function acf_export_internal_post_type_as_php( $post, $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
return $instance->export_post_as_php( $post );
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an ACF post for the import process.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The post type of the ACF post being imported.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_internal_post_type_for_import( $post = array(), $post_type = 'acf-field-group' ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$post = $instance->prepare_post_for_import( $post );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an ACF post into the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @param string $post_type The post type of the ACF post being imported.
|
||||
* @return array The imported post.
|
||||
*/
|
||||
function acf_import_internal_post_type( $post, $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
|
||||
if ( $instance ) {
|
||||
$post = $instance->import_post( $post );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Tries to determine the ACF post type for the provided key.
|
||||
*
|
||||
* @param string $key The key to check.
|
||||
* @return string|bool
|
||||
*/
|
||||
function acf_determine_internal_post_type( $key ) {
|
||||
$store = acf_get_store( 'internal-post-types' );
|
||||
$post_types = array();
|
||||
|
||||
if ( $store ) {
|
||||
$post_types = $store->get();
|
||||
$post_types = array_keys( $post_types );
|
||||
}
|
||||
|
||||
foreach ( $post_types as $post_type ) {
|
||||
if ( acf_is_internal_post_type_key( $key, $post_type ) ) {
|
||||
return $post_type;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tabs for the post type advanced settings.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_combined_post_type_settings_tabs() {
|
||||
$default_post_type_tabs = array(
|
||||
'general' => __( 'General', 'acf' ),
|
||||
'labels' => __( 'Labels', 'acf' ),
|
||||
'visibility' => __( 'Visibility', 'acf' ),
|
||||
'urls' => __( 'URLs', 'acf' ),
|
||||
'permissions' => __( 'Permissions', 'acf' ),
|
||||
'rest_api' => __( 'REST API', 'acf' ),
|
||||
);
|
||||
|
||||
$additional_post_type_tabs = (array) apply_filters( 'acf/post_type/additional_settings_tabs', array() );
|
||||
|
||||
// Remove any default tab values from the filtered tabs.
|
||||
foreach ( $additional_post_type_tabs as $key => $tab ) {
|
||||
if ( isset( $default_post_type_tabs[ $key ] ) ) {
|
||||
unset( $additional_post_type_tabs[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge( $default_post_type_tabs, $additional_post_type_tabs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tabs for the taxonomy advanced settings.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_combined_taxonomy_settings_tabs() {
|
||||
$default_taxonomy_tabs = array(
|
||||
'general' => __( 'General', 'acf' ),
|
||||
'labels' => __( 'Labels', 'acf' ),
|
||||
'visibility' => __( 'Visibility', 'acf' ),
|
||||
'urls' => __( 'URLs', 'acf' ),
|
||||
'rest_api' => __( 'REST API', 'acf' ),
|
||||
);
|
||||
|
||||
$additional_taxonomy_tabs = (array) apply_filters( 'acf/taxonomy/additional_settings_tabs', array() );
|
||||
|
||||
// Remove any default tab values from the filtered tabs.
|
||||
foreach ( $additional_taxonomy_tabs as $key => $tab ) {
|
||||
if ( isset( $default_taxonomy_tabs[ $key ] ) ) {
|
||||
unset( $additional_taxonomy_tabs[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
return array_merge( $default_taxonomy_tabs, $additional_taxonomy_tabs );
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts an _acf_screen or hook value into a post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $screen The ACF screen being viewed.
|
||||
* @return string The post type matching the screen or hook value.
|
||||
*/
|
||||
function acf_get_post_type_from_screen_value( $screen ) {
|
||||
switch ( $screen ) {
|
||||
case 'post_type':
|
||||
return 'acf-post-type';
|
||||
case 'taxonomy':
|
||||
return 'acf-taxonomy';
|
||||
case 'field_group':
|
||||
return 'acf-field-group';
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the ajax validator for a post type
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $post_type The post type being validated.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_validate_internal_post_type_values( $post_type ) {
|
||||
if ( $post_type ) {
|
||||
$instance = acf_get_internal_post_type_instance( $post_type );
|
||||
return $instance->ajax_validate_values();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds a validation error for ACF internal post types.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $name The name of the input.
|
||||
* @param string $message An optional error message to display.
|
||||
* @return void
|
||||
*/
|
||||
function acf_add_internal_post_type_validation_error( $name, $message = '' ) {
|
||||
$screen = isset( $_POST['_acf_screen'] ) ? (string) $_POST['_acf_screen'] : 'post_type'; // phpcs:ignore WordPress.Security -- Nonce verified upstream, value only used for comparison.
|
||||
$post_type = acf_get_post_type_from_screen_value( $screen );
|
||||
|
||||
if ( ! $post_type ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$input_prefix = str_replace( '-', '_', $post_type );
|
||||
|
||||
if ( substr( $name, 0, strlen( $input_prefix ) ) !== $input_prefix ) {
|
||||
$name = "{$input_prefix}[$name]";
|
||||
}
|
||||
|
||||
return acf_add_validation_error( $name, $message );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ACF post type from request args and verifies nonce based on action.
|
||||
*
|
||||
* @since 6.1.5
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @return array|bool
|
||||
*/
|
||||
function acf_get_post_type_from_request_args( $action = '' ) {
|
||||
$acf_use_post_type = acf_request_arg( 'use_post_type', false );
|
||||
|
||||
if ( ! $acf_use_post_type || ! wp_verify_nonce( acf_request_arg( '_wpnonce' ), $action . '-' . $acf_use_post_type ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return acf_get_internal_post_type( (int) $acf_use_post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets an ACF taxonomy from request args and verifies nonce based on action.
|
||||
*
|
||||
* @since 6.1.5
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @return array|bool
|
||||
*/
|
||||
function acf_get_taxonomy_from_request_args( $action = '' ) {
|
||||
$acf_use_taxonomy = acf_request_arg( 'use_taxonomy', false );
|
||||
|
||||
if ( ! $acf_use_taxonomy || ! wp_verify_nonce( acf_request_arg( '_wpnonce' ), $action . '-' . $acf_use_taxonomy ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return acf_get_internal_post_type( (int) $acf_use_taxonomy, 'acf-taxonomy' );
|
||||
}
|
@ -0,0 +1,384 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Returns an array of "ACF only" meta for the given post_id.
|
||||
*
|
||||
* @date 9/10/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param mixed $post_id The post_id for this data.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_meta( $post_id = 0 ) {
|
||||
|
||||
// Allow filter to short-circuit load_value logic.
|
||||
$null = apply_filters( 'acf/pre_load_meta', null, $post_id );
|
||||
if ( $null !== null ) {
|
||||
return ( $null === '__return_null' ) ? null : $null;
|
||||
}
|
||||
|
||||
// Decode $post_id for $type and $id.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
|
||||
/**
|
||||
* Determine CRUD function.
|
||||
*
|
||||
* - Relies on decoded post_id result to identify option or meta types.
|
||||
* - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
|
||||
*/
|
||||
if ( $decoded['type'] === 'option' ) {
|
||||
$allmeta = acf_get_option_meta( $decoded['id'] );
|
||||
} else {
|
||||
$allmeta = get_metadata( $decoded['type'], $decoded['id'], '' );
|
||||
}
|
||||
|
||||
// Loop over meta and check that a reference exists for each value.
|
||||
$meta = array();
|
||||
if ( $allmeta ) {
|
||||
foreach ( $allmeta as $key => $value ) {
|
||||
|
||||
// If a reference exists for this value, add it to the meta array.
|
||||
if ( isset( $allmeta[ "_$key" ] ) ) {
|
||||
$meta[ $key ] = $allmeta[ $key ][0];
|
||||
$meta[ "_$key" ] = $allmeta[ "_$key" ][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unserialized results (get_metadata does not unserialize if $key is empty).
|
||||
$meta = array_map( 'acf_maybe_unserialize', $meta );
|
||||
|
||||
/**
|
||||
* Filters the $meta array after it has been loaded.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param array $meta The array of loaded meta.
|
||||
* @param string $post_id The $post_id for this meta.
|
||||
*/
|
||||
return apply_filters( 'acf/load_meta', $meta, $post_id );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* acf_get_option_meta
|
||||
*
|
||||
* Returns an array of meta for the given wp_option name prefix in the same format as get_post_meta().
|
||||
*
|
||||
* @date 9/10/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param string $prefix The wp_option name prefix.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_option_meta( $prefix = '' ) {
|
||||
|
||||
// Globals.
|
||||
global $wpdb;
|
||||
|
||||
// Vars.
|
||||
$meta = array();
|
||||
$search = "{$prefix}_%";
|
||||
$_search = "_{$prefix}_%";
|
||||
|
||||
// Escape underscores for LIKE.
|
||||
$search = str_replace( '_', '\_', $search );
|
||||
$_search = str_replace( '_', '\_', $_search );
|
||||
|
||||
// Query database for results.
|
||||
$rows = $wpdb->get_results(
|
||||
$wpdb->prepare(
|
||||
"SELECT *
|
||||
FROM $wpdb->options
|
||||
WHERE option_name LIKE %s
|
||||
OR option_name LIKE %s",
|
||||
$search,
|
||||
$_search
|
||||
),
|
||||
ARRAY_A
|
||||
);
|
||||
|
||||
// Loop over results and append meta (removing the $prefix from the option name).
|
||||
$len = strlen( "{$prefix}_" );
|
||||
foreach ( $rows as $row ) {
|
||||
$meta[ substr( $row['option_name'], $len ) ][] = $row['option_value'];
|
||||
}
|
||||
|
||||
// Return results.
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves specific metadata from the database.
|
||||
*
|
||||
* @date 16/10/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @param string $name The meta name.
|
||||
* @param bool $hidden If the meta is hidden (starts with an underscore).
|
||||
*
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_get_metadata( $post_id = 0, $name = '', $hidden = false ) {
|
||||
// Allow filter to short-circuit logic.
|
||||
$null = apply_filters( 'acf/pre_load_metadata', null, $post_id, $name, $hidden );
|
||||
if ( $null !== null ) {
|
||||
return ( $null === '__return_null' ) ? null : $null;
|
||||
}
|
||||
|
||||
// Decode $post_id for $type and $id.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
$id = $decoded['id'];
|
||||
$type = $decoded['type'];
|
||||
|
||||
// Hidden meta uses an underscore prefix.
|
||||
$prefix = $hidden ? '_' : '';
|
||||
|
||||
// Bail early if no $id (possible during new acf_form).
|
||||
if ( ! $id ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// Determine CRUD function.
|
||||
// - Relies on decoded post_id result to identify option or meta types.
|
||||
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
|
||||
if ( $type === 'option' ) {
|
||||
return get_option( "{$prefix}{$id}_{$name}", null );
|
||||
} else {
|
||||
$meta = get_metadata( $type, $id, "{$prefix}{$name}", false );
|
||||
return isset( $meta[0] ) ? $meta[0] : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates metadata in the database.
|
||||
*
|
||||
* @date 16/10/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @param string $name The meta name.
|
||||
* @param mixed $value The meta value.
|
||||
* @param bool $hidden If the meta is hidden (starts with an underscore).
|
||||
*
|
||||
* @return int|bool Meta ID if the key didn't exist, true on successful update, false on failure.
|
||||
*/
|
||||
function acf_update_metadata( $post_id = 0, $name = '', $value = '', $hidden = false ) {
|
||||
// Allow filter to short-circuit logic.
|
||||
$pre = apply_filters( 'acf/pre_update_metadata', null, $post_id, $name, $value, $hidden );
|
||||
if ( $pre !== null ) {
|
||||
return $pre;
|
||||
}
|
||||
|
||||
// Decode $post_id for $type and $id.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
$id = $decoded['id'];
|
||||
$type = $decoded['type'];
|
||||
|
||||
// Hidden meta uses an underscore prefix.
|
||||
$prefix = $hidden ? '_' : '';
|
||||
|
||||
// Bail early if no $id (possible during new acf_form).
|
||||
if ( ! $id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine CRUD function.
|
||||
// - Relies on decoded post_id result to identify option or meta types.
|
||||
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
|
||||
if ( $type === 'option' ) {
|
||||
$value = wp_unslash( $value );
|
||||
$autoload = (bool) acf_get_setting( 'autoload' );
|
||||
return update_option( "{$prefix}{$id}_{$name}", $value, $autoload );
|
||||
} else {
|
||||
return update_metadata( $type, $id, "{$prefix}{$name}", $value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes metadata from the database.
|
||||
*
|
||||
* @date 16/10/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @param string $name The meta name.
|
||||
* @param bool $hidden If the meta is hidden (starts with an underscore).
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function acf_delete_metadata( $post_id = 0, $name = '', $hidden = false ) {
|
||||
// Allow filter to short-circuit logic.
|
||||
$pre = apply_filters( 'acf/pre_delete_metadata', null, $post_id, $name, $hidden );
|
||||
if ( $pre !== null ) {
|
||||
return $pre;
|
||||
}
|
||||
|
||||
// Decode $post_id for $type and $id.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
$id = $decoded['id'];
|
||||
$type = $decoded['type'];
|
||||
|
||||
// Hidden meta uses an underscore prefix.
|
||||
$prefix = $hidden ? '_' : '';
|
||||
|
||||
// Bail early if no $id (possible during new acf_form).
|
||||
if ( ! $id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Determine CRUD function.
|
||||
// - Relies on decoded post_id result to identify option or meta types.
|
||||
// - Uses xxx_metadata(type) instead of xxx_type_meta() to bypass additional logic that could alter the ID.
|
||||
if ( $type === 'option' ) {
|
||||
return delete_option( "{$prefix}{$id}_{$name}" );
|
||||
} else {
|
||||
return delete_metadata( $type, $id, "{$prefix}{$name}" );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_copy_postmeta
|
||||
*
|
||||
* Copies meta from one post to another. Useful for saving and restoring revisions.
|
||||
*
|
||||
* @date 25/06/2016
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param (int|string) $from_post_id The post id to copy from.
|
||||
* @param (int|string) $to_post_id The post id to paste to.
|
||||
* @return void
|
||||
*/
|
||||
function acf_copy_metadata( $from_post_id = 0, $to_post_id = 0 ) {
|
||||
|
||||
// Get all postmeta.
|
||||
$meta = acf_get_meta( $from_post_id );
|
||||
|
||||
// Check meta.
|
||||
if ( $meta ) {
|
||||
|
||||
// Slash data. WP expects all data to be slashed and will unslash it (fixes '\' character issues).
|
||||
$meta = wp_slash( $meta );
|
||||
|
||||
// Loop over meta.
|
||||
foreach ( $meta as $name => $value ) {
|
||||
acf_update_metadata( $to_post_id, $name, $value );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_copy_postmeta
|
||||
*
|
||||
* Copies meta from one post to another. Useful for saving and restoring revisions.
|
||||
*
|
||||
* @date 25/06/2016
|
||||
* @since 5.3.8
|
||||
* @deprecated 5.7.11
|
||||
*
|
||||
* @param int $from_post_id The post id to copy from.
|
||||
* @param int $to_post_id The post id to paste to.
|
||||
* @return void
|
||||
*/
|
||||
function acf_copy_postmeta( $from_post_id = 0, $to_post_id = 0 ) {
|
||||
return acf_copy_metadata( $from_post_id, $to_post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_meta_field
|
||||
*
|
||||
* Returns a field using the provided $id and $post_id parameters.
|
||||
* Looks for a reference to help loading the correct field via name.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $key The meta name (field name).
|
||||
* @param (int|string) $post_id The post_id where this field's value is saved.
|
||||
* @return (array|false) The field array.
|
||||
*/
|
||||
function acf_get_meta_field( $key = 0, $post_id = 0 ) {
|
||||
|
||||
// Try reference.
|
||||
$field_key = acf_get_reference( $key, $post_id );
|
||||
|
||||
if ( $field_key ) {
|
||||
$field = acf_get_field( $field_key );
|
||||
if ( $field ) {
|
||||
$field['name'] = $key;
|
||||
return $field;
|
||||
}
|
||||
}
|
||||
|
||||
// Return false.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_metaref
|
||||
*
|
||||
* Retrieves reference metadata from the database.
|
||||
*
|
||||
* @date 16/10/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param string type The reference type (fields|groups).
|
||||
* @param string $name An optional specific name
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_get_metaref( $post_id = 0, $type = 'fields', $name = '' ) {
|
||||
|
||||
// Load existing meta.
|
||||
$meta = acf_get_metadata( $post_id, "_acf_$type" );
|
||||
|
||||
// Handle no meta.
|
||||
if ( ! $meta ) {
|
||||
return $name ? '' : array();
|
||||
}
|
||||
|
||||
// Return specific reference.
|
||||
if ( $name ) {
|
||||
return isset( $meta[ $name ] ) ? $meta[ $name ] : '';
|
||||
|
||||
// Or return all references.
|
||||
} else {
|
||||
return $meta;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_update_metaref
|
||||
*
|
||||
* Updates reference metadata in the database.
|
||||
*
|
||||
* @date 16/10/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param string type The reference type (fields|groups).
|
||||
* @param array $references An array of references.
|
||||
* @return (int|bool) Meta ID if the key didn't exist, true on successful update, false on failure.
|
||||
*/
|
||||
function acf_update_metaref( $post_id = 0, $type = 'fields', $references = array() ) {
|
||||
|
||||
// Get current references.
|
||||
$current = acf_get_metaref( $post_id, $type );
|
||||
|
||||
// Merge in new references.
|
||||
$references = array_merge( $current, $references );
|
||||
|
||||
// Simplify groups
|
||||
if ( $type === 'groups' ) {
|
||||
$references = array_values( $references );
|
||||
}
|
||||
|
||||
// Remove duplicate references.
|
||||
$references = array_unique( $references );
|
||||
|
||||
// Update metadata.
|
||||
return acf_update_metadata( $post_id, "_acf_$type", $references );
|
||||
}
|
@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Returns available templates for each post type.
|
||||
*
|
||||
* @date 29/8/17
|
||||
* @since 5.6.2
|
||||
*
|
||||
* @param void
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_post_templates() {
|
||||
|
||||
// Check store.
|
||||
$cache = acf_get_data( 'post_templates' );
|
||||
if ( $cache !== null ) {
|
||||
return $cache;
|
||||
}
|
||||
|
||||
// Initialize templates with default placeholder for pages.
|
||||
$post_templates = array();
|
||||
$post_templates['page'] = array();
|
||||
|
||||
// Loop over post types and append their templates.
|
||||
if ( method_exists( 'WP_Theme', 'get_page_templates' ) ) {
|
||||
$post_types = get_post_types();
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$templates = wp_get_theme()->get_page_templates( null, $post_type );
|
||||
if ( $templates ) {
|
||||
$post_templates[ $post_type ] = $templates;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Update store.
|
||||
acf_set_data( 'post_templates', $post_templates );
|
||||
|
||||
// Return templates.
|
||||
return $post_templates;
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/**
|
||||
* Functions for ACF post type objects.
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get an ACF CPT as an array
|
||||
*
|
||||
* @param int|string $id The post ID being queried.
|
||||
* @return array|false The post type object.
|
||||
*/
|
||||
function acf_get_post_type( $id ) {
|
||||
return acf_get_internal_post_type( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a raw ACF CPT.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID.
|
||||
* @return array|false The internal post type array.
|
||||
*/
|
||||
function acf_get_raw_post_type( $id ) {
|
||||
return acf_get_raw_internal_post_type( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post object for an ACF CPT.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID, key, or name.
|
||||
* @return object|bool The post object, or false on failure.
|
||||
*/
|
||||
function acf_get_post_type_post( $id ) {
|
||||
return acf_get_internal_post_type_post( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given identifier is an ACF CPT key.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_post_type_key( $id ) {
|
||||
return acf_is_internal_post_type_key( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an ACF CPT.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return array|bool
|
||||
*/
|
||||
function acf_validate_post_type( array $post_type = array() ) {
|
||||
return acf_validate_internal_post_type( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the settings for an ACF internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_translate_post_type( array $post_type ) {
|
||||
return acf_translate_internal_post_type( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns and array of ACF post types for the given $filter.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $filter An array of args to filter results by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_acf_post_types( array $filter = array() ) {
|
||||
return acf_get_internal_post_type_posts( 'acf-post-type', $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of raw ACF post types.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_raw_post_types() {
|
||||
return acf_get_raw_internal_post_type_posts( 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered array of ACF post types based on the given $args.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_types An array of ACF posts.
|
||||
* @param array $args An array of args to filter by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_post_types( array $post_types, array $args = array() ) {
|
||||
return acf_filter_internal_post_type_posts( $post_types, $args, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an ACF post type in the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The main ACF post type array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_update_post_type( array $post_type ) {
|
||||
return acf_update_internal_post_type( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all caches for the provided ACF post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_post_type_cache( array $post_type ) {
|
||||
acf_flush_internal_post_type_cache( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an ACF post type from the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ACF post type ID, key or name.
|
||||
* @return bool True if post type was deleted.
|
||||
*/
|
||||
function acf_delete_post_type( $id = 0 ) {
|
||||
return acf_delete_internal_post_type( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes an ACF post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post type ID, key, or name.
|
||||
* @return bool True if post was trashed.
|
||||
*/
|
||||
function acf_trash_post_type( $id = 0 ) {
|
||||
return acf_trash_internal_post_type( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an ACF post type from the trash.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post type ID, key, or name.
|
||||
* @return bool True if post was untrashed.
|
||||
*/
|
||||
function acf_untrash_post_type( $id = 0 ) {
|
||||
return acf_untrash_internal_post_type( $id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given params match an ACF post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_post_type( $post_type ) {
|
||||
return acf_is_internal_post_type( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an ACF post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ACF post type ID, key or name.
|
||||
* @param int $new_post_id Optional ID to override.
|
||||
* @return array|bool The new ACF post type, or false on failure.
|
||||
*/
|
||||
function acf_duplicate_post_type( $id = 0, $new_post_id = 0 ) {
|
||||
return acf_duplicate_internal_post_type( $id, $new_post_id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates an ACF post type.
|
||||
*
|
||||
* @param int|string $id The ACF post type ID, key or name.
|
||||
* @param bool $activate True if the post type should be activated.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_update_post_type_active_status( $id, $activate = true ) {
|
||||
return acf_update_internal_post_type_active_status( $id, $activate, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can edit the post type and returns the edit url.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int $post_id The ACF post type ID.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_post_type_edit_link( $post_id ) {
|
||||
return acf_get_internal_post_type_edit_link( $post_id, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified ACF post type ready for export.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_post_type_for_export( array $post_type = array() ) {
|
||||
return acf_prepare_internal_post_type_for_export( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports an ACF post type as PHP.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return string|bool
|
||||
*/
|
||||
function acf_export_post_type_as_php( array $post_type ) {
|
||||
return acf_export_internal_post_type_as_php( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an ACF post type for the import process.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_post_type_for_import( array $post_type = array() ) {
|
||||
return acf_prepare_internal_post_type_for_import( $post_type, 'acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an ACF post type into the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The ACF post type array.
|
||||
* @return array The imported post type.
|
||||
*/
|
||||
function acf_import_post_type( array $post_type ) {
|
||||
return acf_import_internal_post_type( $post_type, 'acf-post-type' );
|
||||
}
|
@ -0,0 +1,268 @@
|
||||
<?php
|
||||
/**
|
||||
* Functions for ACF taxonomy objects.
|
||||
*
|
||||
* @package ACF
|
||||
*/
|
||||
|
||||
/**
|
||||
* Get an ACF taxonomy as an array
|
||||
*
|
||||
* @param int|string $id The post ID being queried.
|
||||
* @return array|false The taxonomy object.
|
||||
*/
|
||||
function acf_get_taxonomy( $id ) {
|
||||
return acf_get_internal_post_type( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a raw ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID.
|
||||
* @return array|false The taxonomy array.
|
||||
*/
|
||||
function acf_get_raw_taxonomy( $id ) {
|
||||
return acf_get_raw_internal_post_type( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a post object for an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID, key, or name.
|
||||
* @return object|bool The post object, or false on failure.
|
||||
*/
|
||||
function acf_get_taxonomy_post( $id ) {
|
||||
return acf_get_internal_post_type_post( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given identifier is an ACF taxonomy key.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_taxonomy_key( $id ) {
|
||||
return acf_is_internal_post_type_key( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return array|bool
|
||||
*/
|
||||
function acf_validate_taxonomy( array $taxonomy = array() ) {
|
||||
return acf_validate_internal_post_type( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates the settings for an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_translate_taxonomy( array $taxonomy ) {
|
||||
return acf_translate_internal_post_type( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of ACF taxonomies for the given $filter.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $filter An array of args to filter results by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_acf_taxonomies( array $filter = array() ) {
|
||||
return acf_get_internal_post_type_posts( 'acf-taxonomy', $filter );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of raw ACF taxonomies.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_raw_taxonomies() {
|
||||
return acf_get_raw_internal_post_type_posts( 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a filtered array of ACF taxonomies based on the given $args.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomies An array of ACF taxonomies.
|
||||
* @param array $args An array of args to filter by.
|
||||
* @return array
|
||||
*/
|
||||
function acf_filter_taxonomies( array $taxonomies, array $args = array() ) {
|
||||
return acf_filter_internal_post_type_posts( $taxonomies, $args, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an ACF taxonomy in the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The main ACF taxonomy array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_update_taxonomy( array $taxonomy ) {
|
||||
return acf_update_internal_post_type( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all caches for the provided ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_taxonomy_cache( array $taxonomy ) {
|
||||
acf_flush_internal_post_type_cache( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an ACF taxonomy from the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ACF taxonomy ID, key or name.
|
||||
* @return bool True if taxonomy was deleted.
|
||||
*/
|
||||
function acf_delete_taxonomy( $id = 0 ) {
|
||||
return acf_delete_internal_post_type( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The taxonomy ID, key, or name.
|
||||
* @return bool True if taxonomy was trashed.
|
||||
*/
|
||||
function acf_trash_taxonomy( $id = 0 ) {
|
||||
return acf_trash_internal_post_type( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an ACF taxonomy from the trash.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The taxonomy ID, key, or name.
|
||||
* @return bool True if taxonomy was untrashed.
|
||||
*/
|
||||
function acf_untrash_taxonomy( $id = 0 ) {
|
||||
return acf_untrash_internal_post_type( $id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given params match an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_is_taxonomy( $taxonomy ) {
|
||||
return acf_is_internal_post_type( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an ACF taxonomy.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ACF taxonomy ID, key or name.
|
||||
* @param int $new_post_id Optional ID to override.
|
||||
* @return array|bool The new ACF taxonomy, or false on failure.
|
||||
*/
|
||||
function acf_duplicate_taxonomy( $id = 0, $new_post_id = 0 ) {
|
||||
return acf_duplicate_internal_post_type( $id, $new_post_id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates an ACF taxonomy.
|
||||
*
|
||||
* @param int|string $id The ACF taxonomy ID, key or name.
|
||||
* @param bool $activate True if the taxonomy should be activated.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_update_taxonomy_active_status( $id, $activate = true ) {
|
||||
return acf_update_internal_post_type_active_status( $id, $activate, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can edit the taxonomy and returns the edit url.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int $post_id The ACF taxonomy ID.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_taxonomy_edit_link( $post_id ) {
|
||||
return acf_get_internal_post_type_edit_link( $post_id, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified ACF taxonomy ready for export.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_taxonomy_for_export( array $taxonomy = array() ) {
|
||||
return acf_prepare_internal_post_type_for_export( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Exports an ACF taxonomy as PHP.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return string|bool
|
||||
*/
|
||||
function acf_export_taxonomy_as_php( array $taxonomy ) {
|
||||
return acf_export_internal_post_type_as_php( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an ACF taxonomy for the import process.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return array
|
||||
*/
|
||||
function acf_prepare_taxonomy_for_import( array $taxonomy = array() ) {
|
||||
return acf_prepare_internal_post_type_for_import( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an ACF taxonomy into the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The ACF taxonomy array.
|
||||
* @return array The imported taxonomy.
|
||||
*/
|
||||
function acf_import_taxonomy( array $taxonomy ) {
|
||||
return acf_import_internal_post_type( $taxonomy, 'acf-taxonomy' );
|
||||
}
|
@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* acf_get_users
|
||||
*
|
||||
* Similar to the get_users() function but with extra functionality.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $args The query args.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_users( $args = array() ) {
|
||||
|
||||
// Get users.
|
||||
$users = get_users( $args );
|
||||
|
||||
// Maintain order.
|
||||
if ( $users && $args['include'] ) {
|
||||
|
||||
// Generate order array.
|
||||
$order = array();
|
||||
foreach ( $users as $i => $user ) {
|
||||
$order[ $i ] = array_search( $user->ID, $args['include'] );
|
||||
}
|
||||
|
||||
// Sort results.
|
||||
array_multisort( $order, $users );
|
||||
}
|
||||
|
||||
// Return
|
||||
return $users;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_user_result
|
||||
*
|
||||
* Returns a result containing "id" and "text" for the given user.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param WP_User $user The user object.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_user_result( $user ) {
|
||||
|
||||
// Vars.
|
||||
$id = $user->ID;
|
||||
$text = $user->user_login;
|
||||
|
||||
// Add name.
|
||||
if ( $user->first_name && $user->last_name ) {
|
||||
$text .= " ({$user->first_name} {$user->last_name})";
|
||||
} elseif ( $user->first_name ) {
|
||||
$text .= " ({$user->first_name})";
|
||||
}
|
||||
return compact( 'id', 'text' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* acf_get_user_role_labels
|
||||
*
|
||||
* Returns an array of user roles in the format "name => label".
|
||||
*
|
||||
* @date 20/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $roles A specific array of roles.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_user_role_labels( $roles = array() ) {
|
||||
$all_roles = wp_roles()->get_names();
|
||||
|
||||
// Load all roles if none provided.
|
||||
if ( empty( $roles ) ) {
|
||||
$roles = array_keys( $all_roles );
|
||||
}
|
||||
|
||||
// Loop over roles and populare labels.
|
||||
$lables = array();
|
||||
foreach ( $roles as $role ) {
|
||||
if ( isset( $all_roles[ $role ] ) ) {
|
||||
$lables[ $role ] = translate_user_role( $all_roles[ $role ] );
|
||||
}
|
||||
}
|
||||
|
||||
// Return labels.
|
||||
return $lables;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_allow_unfiltered_html
|
||||
*
|
||||
* Returns true if the current user is allowed to save unfiltered HTML.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return bool
|
||||
*/
|
||||
function acf_allow_unfiltered_html() {
|
||||
|
||||
// Check capability.
|
||||
$allow_unfiltered_html = current_user_can( 'unfiltered_html' );
|
||||
|
||||
/**
|
||||
* Filters whether the current user is allowed to save unfiltered HTML.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param bool allow_unfiltered_html The result.
|
||||
*/
|
||||
return apply_filters( 'acf/allow_unfiltered_html', $allow_unfiltered_html );
|
||||
}
|
@ -0,0 +1,156 @@
|
||||
<?php
|
||||
|
||||
// Globals.
|
||||
global $acf_stores, $acf_instances;
|
||||
|
||||
// Initialize plaeholders.
|
||||
$acf_stores = array();
|
||||
$acf_instances = array();
|
||||
|
||||
/**
|
||||
* acf_new_instance
|
||||
*
|
||||
* Creates a new instance of the given class and stores it in the instances data store.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $class The class name.
|
||||
* @return object The instance.
|
||||
*/
|
||||
function acf_new_instance( $class = '' ) {
|
||||
global $acf_instances;
|
||||
return $acf_instances[ $class ] = new $class();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an instance for the given class.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $class The class name.
|
||||
* @return object The instance.
|
||||
*/
|
||||
function acf_get_instance( $class = '' ) {
|
||||
global $acf_instances;
|
||||
if ( ! isset( $acf_instances[ $class ] ) ) {
|
||||
$acf_instances[ $class ] = new $class();
|
||||
}
|
||||
return $acf_instances[ $class ];
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_register_store
|
||||
*
|
||||
* Registers a data store.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $name The store name.
|
||||
* @param array $data Array of data to start the store with.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function acf_register_store( $name = '', $data = false ) {
|
||||
|
||||
// Create store.
|
||||
$store = new ACF_Data( $data );
|
||||
|
||||
// Register store.
|
||||
global $acf_stores;
|
||||
$acf_stores[ $name ] = $store;
|
||||
|
||||
// Return store.
|
||||
return $store;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_store
|
||||
*
|
||||
* Returns a data store.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $name The store name.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function acf_get_store( $name = '' ) {
|
||||
global $acf_stores;
|
||||
return isset( $acf_stores[ $name ] ) ? $acf_stores[ $name ] : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_switch_stores
|
||||
*
|
||||
* Triggered when switching between sites on a multisite installation.
|
||||
*
|
||||
* @date 13/2/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param int $site_id New blog ID.
|
||||
* @param int prev_blog_id Prev blog ID.
|
||||
* @return void
|
||||
*/
|
||||
function acf_switch_stores( $site_id, $prev_site_id ) {
|
||||
|
||||
// Loop over stores and call switch_site().
|
||||
global $acf_stores;
|
||||
foreach ( $acf_stores as $store ) {
|
||||
$store->switch_site( $site_id, $prev_site_id );
|
||||
}
|
||||
}
|
||||
add_action( 'switch_blog', 'acf_switch_stores', 10, 2 );
|
||||
|
||||
/**
|
||||
* acf_get_path
|
||||
*
|
||||
* Returns the plugin path to a specified file.
|
||||
*
|
||||
* @date 28/9/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $filename The specified file.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_path( $filename = '' ) {
|
||||
return ACF_PATH . ltrim( $filename, '/' );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_url
|
||||
*
|
||||
* Returns the plugin url to a specified file.
|
||||
* This function also defines the ACF_URL constant.
|
||||
*
|
||||
* @date 12/12/17
|
||||
* @since 5.6.8
|
||||
*
|
||||
* @param string $filename The specified file.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_url( $filename = '' ) {
|
||||
if ( ! defined( 'ACF_URL' ) ) {
|
||||
define( 'ACF_URL', acf_get_setting( 'url' ) );
|
||||
}
|
||||
return ACF_URL . ltrim( $filename, '/' );
|
||||
}
|
||||
|
||||
/*
|
||||
* acf_include
|
||||
*
|
||||
* Includes a file within the ACF plugin.
|
||||
*
|
||||
* @date 10/3/14
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $filename The specified file.
|
||||
* @return void
|
||||
*/
|
||||
function acf_include( $filename = '' ) {
|
||||
$file_path = acf_get_path( $filename );
|
||||
if ( file_exists( $file_path ) ) {
|
||||
include_once $file_path;
|
||||
}
|
||||
}
|
@ -0,0 +1,380 @@
|
||||
<?php
|
||||
|
||||
// Register store.
|
||||
acf_register_store( 'values' )->prop( 'multisite', true );
|
||||
|
||||
/**
|
||||
* acf_get_reference
|
||||
*
|
||||
* Retrieves the field key for a given field name and post_id.
|
||||
*
|
||||
* @date 26/1/18
|
||||
* @since 5.6.5
|
||||
*
|
||||
* @param string $field_name The name of the field. eg 'sub_heading'.
|
||||
* @param mixed $post_id The post_id of which the value is saved against.
|
||||
* @return string The field key.
|
||||
*/
|
||||
function acf_get_reference( $field_name, $post_id ) {
|
||||
|
||||
// Allow filter to short-circuit load_value logic.
|
||||
$reference = apply_filters( 'acf/pre_load_reference', null, $field_name, $post_id );
|
||||
if ( $reference !== null ) {
|
||||
return $reference;
|
||||
}
|
||||
|
||||
// Get hidden meta for this field name.
|
||||
$reference = acf_get_metadata( $post_id, $field_name, true );
|
||||
|
||||
/**
|
||||
* Filters the reference value.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param string $reference The reference value.
|
||||
* @param string $field_name The field name.
|
||||
* @param (int|string) $post_id The post ID where meta is stored.
|
||||
*/
|
||||
return apply_filters( 'acf/load_reference', $reference, $field_name, $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value for a given field and post_id.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int|string $post_id The post id.
|
||||
* @param array $field The field array.
|
||||
* @return mixed
|
||||
*/
|
||||
function acf_get_value( $post_id, $field ) {
|
||||
|
||||
// Allow filter to short-circuit load_value logic.
|
||||
$value = apply_filters( 'acf/pre_load_value', null, $post_id, $field );
|
||||
if ( $value !== null ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Get field name.
|
||||
$field_name = $field['name'];
|
||||
|
||||
// Get field ID & type.
|
||||
$decoded = acf_decode_post_id( $post_id );
|
||||
|
||||
$allow_load = true;
|
||||
|
||||
// If we don't have a proper field array, the field doesn't exist currently.
|
||||
if ( empty( $field['type'] ) && empty( $field['key'] ) ) {
|
||||
|
||||
// Check if we should trigger warning about accessing fields too early via action.
|
||||
do_action( 'acf/get_invalid_field_value', $field, __FUNCTION__ );
|
||||
|
||||
if ( apply_filters( 'acf/prevent_access_to_unknown_fields', false ) || ( 'option' === $decoded['type'] && 'options' !== $decoded['id'] ) ) {
|
||||
$allow_load = false;
|
||||
}
|
||||
}
|
||||
|
||||
// If we're using a non options_ option key, ensure we have a valid reference key.
|
||||
if ( 'option' === $decoded['type'] && 'options' !== $decoded['id'] ) {
|
||||
$meta = acf_get_metadata( $post_id, $field_name, true );
|
||||
if ( ! $meta ) {
|
||||
$allow_load = false;
|
||||
} elseif ( $meta !== $field['key'] ) {
|
||||
if ( ! isset( $field['__key'] ) || $meta !== $field['__key'] ) {
|
||||
$allow_load = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Load Store.
|
||||
$store = acf_get_store( 'values' );
|
||||
|
||||
// If we're allowing load, check the store or load value from database.
|
||||
if ( $allow_load ) {
|
||||
if ( $store->has( "$post_id:$field_name" ) ) {
|
||||
return $store->get( "$post_id:$field_name" );
|
||||
}
|
||||
|
||||
$value = acf_get_metadata( $post_id, $field_name );
|
||||
}
|
||||
|
||||
// Use field's default_value if no meta was found.
|
||||
if ( $value === null && isset( $field['default_value'] ) ) {
|
||||
$value = $field['default_value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $value after it has been loaded.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The value to preview.
|
||||
* @param string $post_id The post ID for this value.
|
||||
* @param array $field The field array.
|
||||
*/
|
||||
$value = apply_filters( 'acf/load_value', $value, $post_id, $field );
|
||||
|
||||
// Update store if we allowed the value load.
|
||||
if ( $allow_load ) {
|
||||
$store->set( "$post_id:$field_name", $value );
|
||||
}
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Register variation.
|
||||
acf_add_filter_variations( 'acf/load_value', array( 'type', 'name', 'key' ), 2 );
|
||||
|
||||
/**
|
||||
* acf_format_value
|
||||
*
|
||||
* Returns a formatted version of the provided value.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The field value.
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param array $field The field array.
|
||||
* @return mixed.
|
||||
*/
|
||||
function acf_format_value( $value, $post_id, $field ) {
|
||||
|
||||
// Allow filter to short-circuit load_value logic.
|
||||
$check = apply_filters( 'acf/pre_format_value', null, $value, $post_id, $field );
|
||||
if ( $check !== null ) {
|
||||
return $check;
|
||||
}
|
||||
|
||||
// Get field name.
|
||||
$field_name = $field['name'];
|
||||
|
||||
// Check store.
|
||||
$store = acf_get_store( 'values' );
|
||||
if ( $store->has( "$post_id:$field_name:formatted" ) ) {
|
||||
return $store->get( "$post_id:$field_name:formatted" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $value for use in a template function.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The value to preview.
|
||||
* @param string $post_id The post ID for this value.
|
||||
* @param array $field The field array.
|
||||
*/
|
||||
$value = apply_filters( 'acf/format_value', $value, $post_id, $field );
|
||||
|
||||
// Update store.
|
||||
$store->set( "$post_id:$field_name:formatted", $value );
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Register variation.
|
||||
acf_add_filter_variations( 'acf/format_value', array( 'type', 'name', 'key' ), 2 );
|
||||
|
||||
/**
|
||||
* acf_update_value
|
||||
*
|
||||
* Updates the value for a given field and post_id.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The new value.
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param array $field The field array.
|
||||
* @return bool.
|
||||
*/
|
||||
function acf_update_value( $value, $post_id, $field ) {
|
||||
|
||||
// Allow filter to short-circuit update_value logic.
|
||||
$check = apply_filters( 'acf/pre_update_value', null, $value, $post_id, $field );
|
||||
if ( $check !== null ) {
|
||||
return $check;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the $value before it is updated.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The value to update.
|
||||
* @param string $post_id The post ID for this value.
|
||||
* @param array $field The field array.
|
||||
* @param mixed $original The original value before modification.
|
||||
*/
|
||||
$value = apply_filters( 'acf/update_value', $value, $post_id, $field, $value );
|
||||
|
||||
// Allow null to delete value.
|
||||
if ( $value === null ) {
|
||||
return acf_delete_value( $post_id, $field );
|
||||
}
|
||||
|
||||
// Update meta.
|
||||
$return = acf_update_metadata( $post_id, $field['name'], $value );
|
||||
|
||||
// Update reference.
|
||||
acf_update_metadata( $post_id, $field['name'], $field['key'], true );
|
||||
|
||||
// Delete stored data.
|
||||
acf_flush_value_cache( $post_id, $field['name'] );
|
||||
|
||||
// Return update status.
|
||||
return $return;
|
||||
}
|
||||
|
||||
// Register variation.
|
||||
acf_add_filter_variations( 'acf/update_value', array( 'type', 'name', 'key' ), 2 );
|
||||
|
||||
/**
|
||||
* acf_update_values
|
||||
*
|
||||
* Updates an array of values.
|
||||
*
|
||||
* @date 26/2/19
|
||||
* @since 5.7.13
|
||||
*
|
||||
* @param array values The array of values.
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @return void
|
||||
*/
|
||||
function acf_update_values( $values, $post_id ) {
|
||||
|
||||
// Loop over values.
|
||||
foreach ( $values as $key => $value ) {
|
||||
|
||||
// Get field.
|
||||
$field = acf_get_field( $key );
|
||||
|
||||
// Update value.
|
||||
if ( $field ) {
|
||||
acf_update_value( $value, $post_id, $field );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_flush_value_cache
|
||||
*
|
||||
* Deletes all cached data for this value.
|
||||
*
|
||||
* @date 22/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param string $field_name The field name.
|
||||
* @return void
|
||||
*/
|
||||
function acf_flush_value_cache( $post_id = 0, $field_name = '' ) {
|
||||
|
||||
// Delete stored data.
|
||||
acf_get_store( 'values' )
|
||||
->remove( "$post_id:$field_name" )
|
||||
->remove( "$post_id:$field_name:formatted" );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_delete_value
|
||||
*
|
||||
* Deletes the value for a given field and post_id.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param array $field The field array.
|
||||
* @return bool.
|
||||
*/
|
||||
function acf_delete_value( $post_id, $field ) {
|
||||
|
||||
/**
|
||||
* Fires before a value is deleted.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $post_id The post ID for this value.
|
||||
* @param mixed $name The meta name.
|
||||
* @param array $field The field array.
|
||||
*/
|
||||
do_action( 'acf/delete_value', $post_id, $field['name'], $field );
|
||||
|
||||
// Delete meta.
|
||||
$return = acf_delete_metadata( $post_id, $field['name'] );
|
||||
|
||||
// Delete reference.
|
||||
acf_delete_metadata( $post_id, $field['name'], true );
|
||||
|
||||
// Delete stored data.
|
||||
acf_flush_value_cache( $post_id, $field['name'] );
|
||||
|
||||
// Return delete status.
|
||||
return $return;
|
||||
}
|
||||
|
||||
// Register variation.
|
||||
acf_add_filter_variations( 'acf/delete_value', array( 'type', 'name', 'key' ), 2 );
|
||||
|
||||
/**
|
||||
* acf_preview_value
|
||||
*
|
||||
* Return a human friendly 'preview' for a given field value.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param mixed $value The new value.
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @param array $field The field array.
|
||||
* @return bool.
|
||||
*/
|
||||
function acf_preview_value( $value, $post_id, $field ) {
|
||||
|
||||
/**
|
||||
* Filters the $value before used in HTML.
|
||||
*
|
||||
* @date 24/10/16
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param mixed $value The value to preview.
|
||||
* @param string $post_id The post ID for this value.
|
||||
* @param array $field The field array.
|
||||
*/
|
||||
return apply_filters( 'acf/preview_value', $value, $post_id, $field );
|
||||
}
|
||||
|
||||
// Register variation.
|
||||
acf_add_filter_variations( 'acf/preview_value', array( 'type', 'name', 'key' ), 2 );
|
||||
|
||||
/**
|
||||
* Potentially log an error if a field doesn't exist when we expect it to.
|
||||
*
|
||||
* @param array $field An array representing the field that a value was requested for.
|
||||
* @param string $function The function that noticed the problem.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function acf_log_invalid_field_notice( $field, $function ) {
|
||||
// If "init" has fired, ACF probably wasn't initialized early.
|
||||
if ( did_action( 'init' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$error_text = sprintf(
|
||||
__( '<strong>%1$s</strong> - We\'ve detected one or more calls to retrieve ACF field values before ACF has been initialized. This is not supported and can result in malformed or missing data. <a href="%2$s" target="_blank">Learn how to fix this</a>.', 'acf' ),
|
||||
acf_get_setting( 'name' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/acf-field-functions/', 'docs', 'early_init_warning' )
|
||||
);
|
||||
_doing_it_wrong( $function, $error_text, '5.11.1' );
|
||||
}
|
||||
add_action( 'acf/get_invalid_field_value', 'acf_log_invalid_field_notice', 10, 2 );
|
@ -0,0 +1,263 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Returns a WordPress object type.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $object_type The object type (post, term, user, etc).
|
||||
* @param string $object_subtype Optional object subtype (post type, taxonomy).
|
||||
* @return object
|
||||
*/
|
||||
function acf_get_object_type( $object_type, $object_subtype = '' ) {
|
||||
$props = array(
|
||||
'type' => $object_type,
|
||||
'subtype' => $object_subtype,
|
||||
'name' => '',
|
||||
'label' => '',
|
||||
'icon' => '',
|
||||
);
|
||||
|
||||
// Set unique identifier as name.
|
||||
if ( $object_subtype ) {
|
||||
$props['name'] = "$object_type/$object_subtype";
|
||||
} else {
|
||||
$props['name'] = $object_type;
|
||||
}
|
||||
|
||||
// Set label and icon.
|
||||
switch ( $object_type ) {
|
||||
case 'post':
|
||||
if ( $object_subtype ) {
|
||||
$post_type = get_post_type_object( $object_subtype );
|
||||
if ( $post_type ) {
|
||||
$props['label'] = $post_type->labels->name;
|
||||
$props['icon'] = acf_with_default( $post_type->menu_icon, 'dashicons-admin-post' );
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$props['label'] = __( 'Posts', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-post';
|
||||
}
|
||||
break;
|
||||
case 'term':
|
||||
if ( $object_subtype ) {
|
||||
$taxonomy = get_taxonomy( $object_subtype );
|
||||
if ( $taxonomy ) {
|
||||
$props['label'] = $taxonomy->labels->name;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
} else {
|
||||
$props['label'] = __( 'Taxonomies', 'acf' );
|
||||
}
|
||||
$props['icon'] = 'dashicons-tag';
|
||||
break;
|
||||
case 'attachment':
|
||||
$props['label'] = __( 'Attachments', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-media';
|
||||
break;
|
||||
case 'comment':
|
||||
$props['label'] = __( 'Comments', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-comments';
|
||||
break;
|
||||
case 'widget':
|
||||
$props['label'] = __( 'Widgets', 'acf' );
|
||||
$props['icon'] = 'dashicons-screenoptions';
|
||||
break;
|
||||
case 'menu':
|
||||
$props['label'] = __( 'Menus', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-appearance';
|
||||
break;
|
||||
case 'menu_item':
|
||||
$props['label'] = __( 'Menu items', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-appearance';
|
||||
break;
|
||||
case 'user':
|
||||
$props['label'] = __( 'Users', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-users';
|
||||
break;
|
||||
case 'option':
|
||||
$props['label'] = __( 'Options', 'acf' );
|
||||
$props['icon'] = 'dashicons-admin-generic';
|
||||
break;
|
||||
case 'block':
|
||||
$props['label'] = __( 'Blocks', 'acf' );
|
||||
$props['icon'] = acf_version_compare( 'wp', '>=', '5.5' ) ? 'dashicons-block-default' : 'dashicons-layout';
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
|
||||
// Convert to object.
|
||||
$object = (object) $props;
|
||||
|
||||
/**
|
||||
* Filters the object type.
|
||||
*
|
||||
* @date 6/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param object $object The object props.
|
||||
* @param string $object_type The object type (post, term, user, etc).
|
||||
* @param string $object_subtype Optional object subtype (post type, taxonomy).
|
||||
*/
|
||||
return apply_filters( 'acf/get_object_type', $object, $object_type, $object_subtype );
|
||||
}
|
||||
|
||||
/**
|
||||
* Decodes a post_id value such as 1 or "user_1" into an array containing the type and ID.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param (int|string) $post_id The post id.
|
||||
* @return array
|
||||
*/
|
||||
function acf_decode_post_id( $post_id = 0 ) {
|
||||
$type = '';
|
||||
$id = 0;
|
||||
|
||||
// Interpret numeric value (123).
|
||||
if ( is_numeric( $post_id ) ) {
|
||||
$type = 'post';
|
||||
$id = $post_id;
|
||||
|
||||
// Interpret string value ("user_123" or "option").
|
||||
} elseif ( is_string( $post_id ) ) {
|
||||
$i = strrpos( $post_id, '_' );
|
||||
if ( $i > 0 ) {
|
||||
$type = substr( $post_id, 0, $i );
|
||||
$id = substr( $post_id, $i + 1 );
|
||||
} else {
|
||||
$type = $post_id;
|
||||
$id = '';
|
||||
}
|
||||
|
||||
// Handle incorrect param type.
|
||||
} else {
|
||||
return compact( 'type', 'id' );
|
||||
}
|
||||
|
||||
// Validate props based on param format.
|
||||
$format = $type . '_' . ( is_numeric( $id ) ? '%d' : '%s' );
|
||||
switch ( $format ) {
|
||||
case 'post_%d':
|
||||
$type = 'post';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'term_%d':
|
||||
$type = 'term';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'attachment_%d':
|
||||
$type = 'post';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'comment_%d':
|
||||
$type = 'comment';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'widget_%s':
|
||||
case 'widget_%d':
|
||||
$type = 'option';
|
||||
$id = $post_id;
|
||||
break;
|
||||
case 'menu_%d':
|
||||
$type = 'term';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'menu_item_%d':
|
||||
$type = 'post';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'user_%d':
|
||||
$type = 'user';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
case 'block_%s':
|
||||
case 'block_%d':
|
||||
$type = 'block';
|
||||
$id = $post_id;
|
||||
break;
|
||||
case 'option_%s':
|
||||
$type = 'option';
|
||||
$id = $post_id;
|
||||
break;
|
||||
case 'blog_%d':
|
||||
case 'site_%d':
|
||||
// Allow backwards compatibility for custom taxonomies.
|
||||
$type = taxonomy_exists( $type ) ? 'term' : 'blog';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
default:
|
||||
// Check for taxonomy name.
|
||||
if ( taxonomy_exists( $type ) && is_numeric( $id ) ) {
|
||||
$type = 'term';
|
||||
$id = absint( $id );
|
||||
break;
|
||||
}
|
||||
|
||||
// Treat unknown post_id format as an option.
|
||||
$type = 'option';
|
||||
$id = $post_id;
|
||||
break;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the decoded post_id information.
|
||||
*
|
||||
* @date 25/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param array $props An array containing "type" and "id" information.
|
||||
* @param (int|string) $post_id The post id.
|
||||
*/
|
||||
return apply_filters( 'acf/decode_post_id', compact( 'type', 'id' ), $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* Determine the REST base for a post type or taxonomy object. Note that this is not intended for use
|
||||
* with term or post objects but is, instead, to be used with the underlying WP_Post_Type and WP_Taxonomy
|
||||
* instances.
|
||||
*
|
||||
* @param WP_Post_Type|WP_Taxonomy $type_object
|
||||
* @return string|null
|
||||
*/
|
||||
function acf_get_object_type_rest_base( $type_object ) {
|
||||
if ( $type_object instanceof WP_Post_Type || $type_object instanceof WP_Taxonomy ) {
|
||||
return ! empty( $type_object->rest_base ) ? $type_object->rest_base : $type_object->name;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Extract the ID of a given object/array. This supports all expected types handled by our update_fields() and
|
||||
* load_fields() callbacks.
|
||||
*
|
||||
* @param WP_Post|WP_User|WP_Term|WP_Comment|array $object
|
||||
* @return int|mixed|null
|
||||
*/
|
||||
function acf_get_object_id( $object ) {
|
||||
if ( is_object( $object ) ) {
|
||||
switch ( get_class( $object ) ) {
|
||||
case WP_User::class:
|
||||
case WP_Post::class:
|
||||
return (int) $object->ID;
|
||||
case WP_Term::class:
|
||||
return (int) $object->term_id;
|
||||
case WP_Comment::class:
|
||||
return (int) $object->comment_ID;
|
||||
}
|
||||
} elseif ( isset( $object['id'] ) ) {
|
||||
return (int) $object['id'];
|
||||
|
||||
} elseif ( isset( $object['ID'] ) ) {
|
||||
return (int) $object['ID'];
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
@ -0,0 +1,924 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Internal Post Type List class
|
||||
*
|
||||
* Base class to add functionality to ACF internal post type list pages.
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
* @since 6.1
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Internal_Post_Type_List' ) ) :
|
||||
|
||||
class ACF_Admin_Internal_Post_Type_List {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = '';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = '';
|
||||
|
||||
/**
|
||||
* Array of post objects available for sync.
|
||||
*
|
||||
* @since 5.9.0
|
||||
* @var array
|
||||
*/
|
||||
public $sync = array();
|
||||
|
||||
/**
|
||||
* The current view (post_status).
|
||||
*
|
||||
* @since 5.9.0
|
||||
* @var string
|
||||
*/
|
||||
public $view = '';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = '';
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'current_screen', array( $this, 'current_screen' ) );
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
||||
|
||||
// Handle post status change events.
|
||||
add_action( 'trashed_post', array( $this, 'trashed_post' ) );
|
||||
add_action( 'untrashed_post', array( $this, 'untrashed_post' ) );
|
||||
add_action( 'deleted_post', array( $this, 'deleted_post' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any menu items required for post types.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function admin_menu() {}
|
||||
|
||||
/**
|
||||
* Returns the admin URL for the current post type edit page.
|
||||
*
|
||||
* @date 27/3/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $params Extra URL params.
|
||||
* @return string
|
||||
*/
|
||||
public function get_admin_url( $params = '' ) {
|
||||
return admin_url( "edit.php?post_type={$this->post_type}{$params}" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the post type admin URL taking into account the current view.
|
||||
*
|
||||
* @date 27/3/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $params Extra URL params.
|
||||
* @return string
|
||||
*/
|
||||
public function get_current_admin_url( $params = '' ) {
|
||||
return $this->get_admin_url( ( $this->view ? '&post_status=' . $this->view : '' ) . $params );
|
||||
}
|
||||
|
||||
/**
|
||||
* Constructor for all ACF internal post type admin list pages.
|
||||
*
|
||||
* @date 21/07/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function current_screen() {
|
||||
// Bail early if not the list admin page.
|
||||
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Get the current view.
|
||||
$this->view = acf_request_arg( 'post_status', '' );
|
||||
|
||||
// Setup and check for custom actions.
|
||||
$this->setup_sync();
|
||||
$this->check_sync();
|
||||
$this->check_duplicate();
|
||||
$this->check_activate();
|
||||
$this->check_deactivate();
|
||||
|
||||
// Modify publish post status text and order.
|
||||
global $wp_post_statuses;
|
||||
$wp_post_statuses['publish']->label_count = _n_noop( 'Active <span class="count">(%s)</span>', 'Active <span class="count">(%s)</span>', 'acf' );
|
||||
$wp_post_statuses['trash'] = acf_extract_var( $wp_post_statuses, 'trash' );
|
||||
|
||||
// Add hooks.
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
add_filter( "views_edit-{$this->post_type}", array( $this, 'admin_table_views' ), 10, 1 );
|
||||
add_filter( "manage_{$this->post_type}_posts_columns", array( $this, 'admin_table_columns' ), 10, 1 );
|
||||
add_action( "manage_{$this->post_type}_posts_custom_column", array( $this, 'admin_table_columns_html' ), 10, 2 );
|
||||
add_filter( 'display_post_states', array( $this, 'display_post_states' ), 10, 2 );
|
||||
add_filter( "bulk_actions-edit-{$this->post_type}", array( $this, 'admin_table_bulk_actions' ), 10, 1 );
|
||||
add_action( 'admin_footer', array( $this, 'admin_footer' ), 1 );
|
||||
|
||||
if ( $this->view !== 'trash' ) {
|
||||
add_filter( 'page_row_actions', array( $this, 'page_row_actions' ), 10, 2 );
|
||||
}
|
||||
|
||||
// Add hooks for "sync" view.
|
||||
if ( $this->view === 'sync' ) {
|
||||
add_action( 'admin_footer', array( $this, 'admin_footer__sync' ), 1 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the field groups ready for sync.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function setup_sync() {
|
||||
// Review local json files.
|
||||
if ( acf_get_local_json_files( $this->post_type ) ) {
|
||||
|
||||
// Get all posts in a single cached query to check if sync is available.
|
||||
$all_posts = acf_get_internal_post_type_posts( $this->post_type );
|
||||
foreach ( $all_posts as $post ) {
|
||||
|
||||
// Extract vars.
|
||||
$local = acf_maybe_get( $post, 'local' );
|
||||
$modified = acf_maybe_get( $post, 'modified' );
|
||||
$private = acf_maybe_get( $post, 'private' );
|
||||
|
||||
// Ignore if is private.
|
||||
if ( $private ) {
|
||||
continue;
|
||||
|
||||
// Ignore not local "json".
|
||||
} elseif ( $local !== 'json' ) {
|
||||
continue;
|
||||
|
||||
// Append to sync if not yet in database.
|
||||
} elseif ( ! $post['ID'] ) {
|
||||
$this->sync[ $post['key'] ] = $post;
|
||||
|
||||
// Append to sync if "json" modified time is newer than database.
|
||||
} elseif ( $modified && $modified > get_post_modified_time( 'U', true, $post['ID'] ) ) {
|
||||
$this->sync[ $post['key'] ] = $post;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues admin scripts.
|
||||
*
|
||||
* @date 18/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
acf_enqueue_script( 'acf' );
|
||||
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Review local JSON changes' => __( 'Review local JSON changes', 'acf' ),
|
||||
'Loading diff' => __( 'Loading diff', 'acf' ),
|
||||
'Sync changes' => __( 'Sync changes', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin body class.
|
||||
*
|
||||
* @date 18/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $classes Space-separated list of CSS classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_class( $classes ) {
|
||||
$classes .= ' acf-admin-page acf-internal-post-type ' . esc_attr( $this->admin_body_class );
|
||||
|
||||
if ( $this->view ) {
|
||||
$classes .= ' view-' . esc_attr( $this->view );
|
||||
}
|
||||
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the disabled post state HTML.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_disabled_post_state() {
|
||||
return '<span class="dashicons dashicons-hidden"></span> ' . _x( 'Inactive', 'post status', 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registration error state.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_registration_error_state() {
|
||||
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
|
||||
__( 'This item could not be registered because its key is in use by another item registered by another plugin or theme.', 'acf' ) .
|
||||
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the "disabled" post state for the admin table title.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $post_states An array of post display states.
|
||||
* @param WP_Post $post The current post object.
|
||||
* @return array
|
||||
*/
|
||||
public function display_post_states( $post_states, $post ) {
|
||||
if ( $post->post_status === 'acf-disabled' ) {
|
||||
$post_states['acf-disabled'] = $this->get_disabled_post_state();
|
||||
}
|
||||
|
||||
// Check the post store to see if this failed registration.
|
||||
if ( ! empty( $this->store ) && ! empty( $post->ID ) ) {
|
||||
$store = acf_get_store( $this->store );
|
||||
$store_item = $store->get( $post->ID );
|
||||
if ( ! empty( $store_item ) && ! empty( $store_item['not_registered'] ) ) {
|
||||
$post_states['acf-registration-warning'] = $this->get_registration_error_state();
|
||||
}
|
||||
}
|
||||
|
||||
return $post_states;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the HTML for when there are no post objects found.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_not_found_html() {
|
||||
ob_start();
|
||||
acf_get_view( $this->post_type . '/list-empty' );
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table columns.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $_columns The columns array.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_columns( $_columns ) {
|
||||
return $_columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the admin table column HTML
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $column_name The name of the column to display.
|
||||
* @param int $post_id The current post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function admin_table_columns_html( $column_name, $post_id ) {
|
||||
$post = acf_get_internal_post_type( $post_id, $this->post_type );
|
||||
|
||||
if ( $post ) {
|
||||
$this->render_admin_table_column( $column_name, $post );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a specific admin table column.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $column_name The name of the column to display.
|
||||
* @param array $post The main ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column( $column_name, $post ) {}
|
||||
|
||||
/**
|
||||
* Returns a human-readable file location.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $file The full file path.
|
||||
* @return string
|
||||
*/
|
||||
public function get_human_readable_file_location( $file ) {
|
||||
// Generate friendly file path.
|
||||
$theme_path = get_stylesheet_directory();
|
||||
if ( strpos( $file, $theme_path ) !== false ) {
|
||||
$rel_file = str_replace( $theme_path, '', $file );
|
||||
$located = sprintf( __( 'Located in theme: %s', 'acf' ), $rel_file );
|
||||
} elseif ( strpos( $file, WP_PLUGIN_DIR ) !== false ) {
|
||||
$rel_file = str_replace( WP_PLUGIN_DIR, '', $file );
|
||||
$located = sprintf( __( 'Located in plugin: %s', 'acf' ), $rel_file );
|
||||
} else {
|
||||
$rel_file = str_replace( ABSPATH, '', $file );
|
||||
$located = sprintf( __( 'Located in: %s', 'acf' ), $rel_file );
|
||||
}
|
||||
|
||||
return $located;
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the local JSON status of an ACF post.
|
||||
*
|
||||
* @date 14/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $post The main ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_local_status( $post ) {
|
||||
$json = acf_get_local_json_files( $this->post_type );
|
||||
if ( isset( $json[ $post['key'] ] ) ) {
|
||||
if ( isset( $this->sync[ $post['key'] ] ) ) {
|
||||
$url = $this->get_admin_url( '&acfsync=' . $post['key'] . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
|
||||
echo '<strong>' . __( 'Sync available', 'acf' ) . '</strong>';
|
||||
if ( $post['ID'] ) {
|
||||
echo '<div class="row-actions">
|
||||
<span class="sync"><a href="' . esc_url( $url ) . '">' . __( 'Sync', 'acf' ) . '</a> | </span>
|
||||
<span class="review"><a href="#" data-event="review-sync" data-id="' . esc_attr( $post['ID'] ) . '" data-href="' . esc_url( $url ) . '">' . __( 'Review changes', 'acf' ) . '</a></span>
|
||||
</div>';
|
||||
} else {
|
||||
echo '<div class="row-actions">
|
||||
<span class="sync"><a href="' . esc_url( $url ) . '">' . __( 'Import', 'acf' ) . '</a></span>
|
||||
</div>';
|
||||
}
|
||||
} else {
|
||||
echo __( 'Saved', 'acf' );
|
||||
}
|
||||
} else {
|
||||
echo '<span class="acf-secondary-text">' . __( 'Awaiting save', 'acf' ) . '</span>';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the page row actions visible on hover.
|
||||
*
|
||||
* @date 14/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $actions The array of actions HTML.
|
||||
* @param WP_Post $post The post.
|
||||
* @return array
|
||||
*/
|
||||
public function page_row_actions( $actions, $post ) {
|
||||
|
||||
// Remove "Quick Edit" action.
|
||||
unset( $actions['inline'], $actions['inline hide-if-no-js'] );
|
||||
|
||||
// Append "Duplicate" action.
|
||||
// TODO: We'll likely have to add support for CPTs/Taxonomies!
|
||||
if ( 'acf-field-group' === $this->post_type ) {
|
||||
$duplicate_action_url = $this->get_admin_url( '&acfduplicate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
|
||||
$actions['acfduplicate'] = '<a href="' . esc_url( $duplicate_action_url ) . '" aria-label="' . esc_attr__( 'Duplicate this item', 'acf' ) . '">' . __( 'Duplicate', 'acf' ) . '</a>';
|
||||
}
|
||||
|
||||
// Append the "Activate" or "Deactivate" actions.
|
||||
if ( 'acf-disabled' === $post->post_status ) {
|
||||
$activate_deactivate_action = 'acfactivate';
|
||||
$activate_action_url = $this->get_admin_url( '&acfactivate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
|
||||
$actions['acfactivate'] = '<a href="' . esc_url( $activate_action_url ) . '" aria-label="' . esc_attr__( 'Activate this item', 'acf' ) . '">' . __( 'Activate', 'acf' ) . '</a>';
|
||||
} else {
|
||||
$activate_deactivate_action = 'acfdeactivate';
|
||||
$deactivate_action_url = $this->get_admin_url( '&acfdeactivate=' . $post->ID . '&_wpnonce=' . wp_create_nonce( 'bulk-posts' ) );
|
||||
$actions['acfdeactivate'] = '<a href="' . esc_url( $deactivate_action_url ) . '" aria-label="' . esc_attr__( 'Deactivate this item', 'acf' ) . '">' . __( 'Deactivate', 'acf' ) . '</a>';
|
||||
}
|
||||
|
||||
// Return actions in custom order.
|
||||
// TODO: We'll likely have to add support for CPTs/Taxonomies!
|
||||
if ( 'acf-field-group' === $this->post_type ) {
|
||||
$order = array( 'edit', 'acfduplicate', $activate_deactivate_action, 'trash' );
|
||||
} else {
|
||||
$order = array( 'edit', $activate_deactivate_action, 'trash' );
|
||||
}
|
||||
|
||||
return array_merge( array_flip( $order ), $actions );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin table bulk actions dropdown.
|
||||
*
|
||||
* @date 15/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $actions The actions array.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_bulk_actions( $actions ) {
|
||||
if ( ! in_array( $this->view, array( 'sync', 'trash' ), true ) ) {
|
||||
// TODO: We'll likely have to add support for CPTs/Taxonomies!
|
||||
if ( 'acf-field-group' === $this->post_type ) {
|
||||
$actions['acfduplicate'] = __( 'Duplicate', 'acf' );
|
||||
}
|
||||
|
||||
$actions['acfactivate'] = __( 'Activate', 'acf' );
|
||||
$actions['acfdeactivate'] = __( 'Deactivate', 'acf' );
|
||||
}
|
||||
|
||||
if ( $this->sync ) {
|
||||
if ( $this->view === 'sync' ) {
|
||||
$actions = array();
|
||||
}
|
||||
$actions['acfsync'] = __( 'Sync changes', 'acf' );
|
||||
}
|
||||
|
||||
return $actions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @param int $count The number of items the action was performed on.
|
||||
* @return string
|
||||
*/
|
||||
public function get_action_notice_text( $action, $count = 1 ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the custom "Activate" bulk action.
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public function check_activate() {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
|
||||
// Display notice on success redirect.
|
||||
if ( isset( $_GET['acfactivatecomplete'] ) ) {
|
||||
$ids = array_map( 'intval', explode( ',', $_GET['acfactivatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
// Generate text.
|
||||
$text = $this->get_action_notice_text( 'acfactivatecomplete', count( $ids ) );
|
||||
|
||||
// Append links to text.
|
||||
$links = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
|
||||
// Add notice.
|
||||
acf_add_admin_notice( $text, 'success' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find items to activate.
|
||||
$ids = array();
|
||||
if ( isset( $_GET['acfactivate'] ) ) {
|
||||
$ids[] = intval( $_GET['acfactivate'] );
|
||||
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfactivate' ) {
|
||||
$ids = array_map( 'intval', $_GET['post'] );
|
||||
}
|
||||
|
||||
if ( $ids ) {
|
||||
check_admin_referer( 'bulk-posts' );
|
||||
|
||||
// Activate the field groups and return an array of IDs that were activated.
|
||||
$new_ids = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$post_type = get_post_type( $id );
|
||||
if ( $post_type && acf_update_internal_post_type_active_status( $id, true, $post_type ) ) {
|
||||
$new_ids[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
wp_safe_redirect( $this->get_admin_url( '&acfactivatecomplete=' . implode( ',', $new_ids ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the custom "Deactivate" bulk action.
|
||||
*
|
||||
* @since 6.0
|
||||
*/
|
||||
public function check_deactivate() {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
|
||||
// Display notice on success redirect.
|
||||
if ( isset( $_GET['acfdeactivatecomplete'] ) ) {
|
||||
$ids = array_map( 'intval', explode( ',', $_GET['acfdeactivatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
// Generate text.
|
||||
$text = $this->get_action_notice_text( 'acfdeactivatecomplete', count( $ids ) );
|
||||
|
||||
// Append links to text.
|
||||
$links = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
|
||||
// Add notice.
|
||||
acf_add_admin_notice( $text, 'success' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find items to activate.
|
||||
$ids = array();
|
||||
if ( isset( $_GET['acfdeactivate'] ) ) {
|
||||
$ids[] = intval( $_GET['acfdeactivate'] );
|
||||
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfdeactivate' ) {
|
||||
$ids = array_map( 'intval', $_GET['post'] );
|
||||
}
|
||||
|
||||
if ( $ids ) {
|
||||
check_admin_referer( 'bulk-posts' );
|
||||
|
||||
// Activate the field groups and return an array of IDs.
|
||||
$new_ids = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$post_type = get_post_type( $id );
|
||||
if ( $post_type && acf_update_internal_post_type_active_status( $id, false, $post_type ) ) {
|
||||
$new_ids[] = $id;
|
||||
}
|
||||
}
|
||||
|
||||
wp_safe_redirect( $this->get_admin_url( '&acfdeactivatecomplete=' . implode( ',', $new_ids ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the custom "duplicate" action.
|
||||
*
|
||||
* @date 15/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check_duplicate() {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended -- Used for redirect notice.
|
||||
// Display notice on success redirect.
|
||||
if ( isset( $_GET['acfduplicatecomplete'] ) ) {
|
||||
$ids = array_map( 'intval', explode( ',', $_GET['acfduplicatecomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
// Generate text.
|
||||
$text = $this->get_action_notice_text( 'acfduplicatecomplete', count( $ids ) );
|
||||
|
||||
// Append links to text.
|
||||
$links = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
|
||||
// Add notice.
|
||||
acf_add_admin_notice( $text, 'success' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find items to duplicate.
|
||||
$ids = array();
|
||||
if ( isset( $_GET['acfduplicate'] ) ) {
|
||||
$ids[] = intval( $_GET['acfduplicate'] );
|
||||
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfduplicate' ) {
|
||||
$ids = array_map( 'intval', $_GET['post'] );
|
||||
}
|
||||
|
||||
if ( $ids ) {
|
||||
check_admin_referer( 'bulk-posts' );
|
||||
|
||||
// Duplicate field groups and generate array of new IDs.
|
||||
$new_ids = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$field_group = acf_duplicate_field_group( $id );
|
||||
$new_ids[] = $field_group['ID'];
|
||||
}
|
||||
|
||||
// Redirect.
|
||||
wp_safe_redirect( $this->get_admin_url( '&acfduplicatecomplete=' . implode( ',', $new_ids ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks for the custom "acfsync" action.
|
||||
*
|
||||
* @date 15/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function check_sync() {
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Recommended
|
||||
// Display notice on success redirect.
|
||||
if ( isset( $_GET['acfsynccomplete'] ) ) {
|
||||
$ids = array_map( 'intval', explode( ',', $_GET['acfsynccomplete'] ) ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized with intval().
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Recommended
|
||||
// Generate text.
|
||||
$text = $this->get_action_notice_text( 'acfsynccomplete', count( $ids ) );
|
||||
|
||||
// Append links to text.
|
||||
$links = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
|
||||
// Add notice.
|
||||
acf_add_admin_notice( $text, 'success' );
|
||||
return;
|
||||
}
|
||||
|
||||
// Find items to sync.
|
||||
$keys = array();
|
||||
if ( isset( $_GET['acfsync'] ) ) {
|
||||
$keys[] = sanitize_text_field( $_GET['acfsync'] );
|
||||
} elseif ( isset( $_GET['post'], $_GET['action2'] ) && $_GET['action2'] === 'acfsync' ) {
|
||||
$keys = array_map( 'sanitize_text_field', $_GET['post'] );
|
||||
}
|
||||
|
||||
if ( $keys && $this->sync ) {
|
||||
check_admin_referer( 'bulk-posts' );
|
||||
|
||||
// Disabled "Local JSON" controller to prevent the .json file from being modified during import.
|
||||
acf_update_setting( 'json', false );
|
||||
|
||||
// Sync field groups and generate array of new IDs.
|
||||
$files = acf_get_local_json_files( $this->post_type );
|
||||
$new_ids = array();
|
||||
foreach ( $this->sync as $key => $post ) {
|
||||
if ( $post['key'] && in_array( $post['key'], $keys ) ) {
|
||||
// Import.
|
||||
} elseif ( $post['ID'] && in_array( $post['ID'], $keys ) ) {
|
||||
// Import.
|
||||
} else {
|
||||
// Ignore.
|
||||
continue;
|
||||
}
|
||||
$local_post = json_decode( file_get_contents( $files[ $key ] ), true );
|
||||
$local_post['ID'] = $post['ID'];
|
||||
$result = acf_import_internal_post_type( $local_post, $this->post_type );
|
||||
$new_ids[] = $result['ID'];
|
||||
}
|
||||
|
||||
// Redirect.
|
||||
wp_safe_redirect( $this->get_current_admin_url( '&acfsynccomplete=' . implode( ',', $new_ids ) ) );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table subnav.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $views The available views.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_views( $views ) {
|
||||
global $wp_list_table, $wp_query;
|
||||
|
||||
// Count items.
|
||||
$count = count( $this->sync );
|
||||
|
||||
// Append "sync" link to subnav.
|
||||
if ( $count ) {
|
||||
$views['sync'] = sprintf(
|
||||
'<a %s href="%s">%s <span class="count">(%s)</span></a>',
|
||||
( $this->view === 'sync' ? 'class="current"' : '' ),
|
||||
esc_url( $this->get_admin_url( '&post_status=sync' ) ),
|
||||
esc_html( __( 'Sync available', 'acf' ) ),
|
||||
$count
|
||||
);
|
||||
}
|
||||
|
||||
// Modify table pagination args to match JSON data.
|
||||
if ( $this->view === 'sync' ) {
|
||||
$wp_list_table->set_pagination_args(
|
||||
array(
|
||||
'total_items' => $count,
|
||||
'total_pages' => 1,
|
||||
'per_page' => $count,
|
||||
)
|
||||
);
|
||||
$wp_query->post_count = 1; // At least one post is needed to render bulk drop-down.
|
||||
}
|
||||
return $views;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints scripts into the admin footer.
|
||||
*
|
||||
* @date 20/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer() {
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function($){
|
||||
|
||||
// Displays a modal comparing local changes.
|
||||
function reviewSync( props ) {
|
||||
var modal = acf.newModal({
|
||||
title: acf.__('Review local JSON changes'),
|
||||
content: '<p class="acf-modal-feedback"><i class="acf-loading"></i> ' + acf.__('Loading diff') + '</p>',
|
||||
toolbar: '<a href="' + props.href + '" class="button button-primary button-sync-changes disabled">' + acf.__('Sync changes') + '</a>',
|
||||
});
|
||||
|
||||
// Call AJAX.
|
||||
var xhr = $.ajax({
|
||||
url: acf.get('ajaxurl'),
|
||||
method: 'POST',
|
||||
dataType: 'json',
|
||||
data: acf.prepareForAjax({
|
||||
action: 'acf/ajax/local_json_diff',
|
||||
id: props.id
|
||||
})
|
||||
})
|
||||
.done(function( data, textStatus, jqXHR ) {
|
||||
modal.content( data.html );
|
||||
modal.$('.button-sync-changes').removeClass('disabled');
|
||||
})
|
||||
.fail(function( jqXHR, textStatus, errorThrown ) {
|
||||
if( error = acf.getXhrError(jqXHR) ) {
|
||||
modal.content( '<p class="acf-modal-feedback error">' + error + '</p>' );
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// Add event listener.
|
||||
$(document).on('click', 'a[data-event="review-sync"]', function( e ){
|
||||
e.preventDefault();
|
||||
reviewSync( $(this).data() );
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table HTML when viewing "sync" post_status.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer__sync() {
|
||||
global $wp_list_table;
|
||||
|
||||
// Get table columns.
|
||||
$columns = $wp_list_table->get_columns();
|
||||
$hidden = get_hidden_columns( $wp_list_table->screen );
|
||||
?>
|
||||
<div style="display: none;">
|
||||
<table>
|
||||
<tbody id="acf-the-list">
|
||||
<?php
|
||||
foreach ( $this->sync as $k => $field_group ) {
|
||||
echo '<tr>';
|
||||
foreach ( $columns as $column_name => $column_label ) {
|
||||
$el = 'td';
|
||||
if ( $column_name === 'cb' ) {
|
||||
$el = 'th';
|
||||
$classes = 'check-column';
|
||||
$column_label = '';
|
||||
} elseif ( $column_name === 'title' ) {
|
||||
$classes = "$column_name column-$column_name column-primary";
|
||||
} else {
|
||||
$classes = "$column_name column-$column_name";
|
||||
}
|
||||
if ( in_array( $column_name, $hidden, true ) ) {
|
||||
$classes .= ' hidden';
|
||||
}
|
||||
echo "<$el class=\"$classes\" data-colname=\"$column_label\">";
|
||||
switch ( $column_name ) {
|
||||
|
||||
// Checkbox.
|
||||
case 'cb':
|
||||
echo '<label for="cb-select-' . esc_attr( $k ) . '" class="screen-reader-text">' . esc_html( sprintf( __( 'Select %s', 'acf' ), $field_group['title'] ) ) . '</label>';
|
||||
echo '<input id="cb-select-' . esc_attr( $k ) . '" type="checkbox" value="' . esc_attr( $k ) . '" name="post[]">';
|
||||
break;
|
||||
|
||||
// Title.
|
||||
case 'title':
|
||||
$post_state = '';
|
||||
if ( ! $field_group['active'] ) {
|
||||
$post_state = ' — <span class="post-state">' . $this->get_disabled_post_state() . '</span>';
|
||||
}
|
||||
echo '<strong><span class="row-title">' . esc_html( $field_group['title'] ) . '</span>' . $post_state . '</strong>';
|
||||
echo '<div class="row-actions"><span class="file acf-secondary-text">' . $this->get_human_readable_file_location( $field_group['local_file'] ) . '</span></div>';
|
||||
echo '<button type="button" class="toggle-row"><span class="screen-reader-text">Show more details</span></button>';
|
||||
break;
|
||||
|
||||
// All other columns.
|
||||
default:
|
||||
$this->render_admin_table_column( $column_name, $field_group );
|
||||
break;
|
||||
}
|
||||
echo "</$el>";
|
||||
}
|
||||
echo '</tr>';
|
||||
}
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
(function($){
|
||||
$('#the-list').html( $('#acf-the-list').children() );
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when trashing an internal post type.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function trashed_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_trash_internal_post_type( $post_id, $this->post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when untrashing an internal post type.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function untrashed_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_untrash_internal_post_type( $post_id, $this->post_type );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when deleting an internal post type.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function deleted_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_delete_internal_post_type( $post_id, $this->post_type );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
endif; // Class exists check.
|
@ -0,0 +1,350 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Internal Post Type class
|
||||
*
|
||||
* Base class to add functionality to ACF internal post types.
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
* @since 6.1
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Internal_Post_Type' ) ) :
|
||||
|
||||
/**
|
||||
* ACF Internal Post Type class.
|
||||
*
|
||||
* Adds logic to the edit page for ACF internal post types.
|
||||
*/
|
||||
class ACF_Admin_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = '';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = '';
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'current_screen', array( $this, 'current_screen' ) );
|
||||
add_action( 'save_post_' . $this->post_type, array( $this, 'save_post' ), 10, 2 );
|
||||
add_action( 'wp_ajax_acf/link_field_groups', array( $this, 'ajax_link_field_groups' ) );
|
||||
add_filter( 'post_updated_messages', array( $this, 'post_updated_messages' ) );
|
||||
add_filter( 'use_block_editor_for_post_type', array( $this, 'use_block_editor_for_post_type' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prevents the block editor from loading when editing an ACF field group.
|
||||
*
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param bool $use_block_editor Whether the post type can be edited or not. Default true.
|
||||
* @param string $post_type The post type being checked.
|
||||
* @return bool
|
||||
*/
|
||||
public function use_block_editor_for_post_type( $use_block_editor, $post_type ) {
|
||||
if ( $post_type === $this->post_type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $use_block_editor;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will customize the message shown when editing a field group
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $messages Post type messages.
|
||||
* @return array
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function is fired when loading the admin page before HTML has been rendered.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function current_screen() {
|
||||
if ( ! acf_is_screen( $this->post_type ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
acf_disable_filters();
|
||||
acf_enqueue_scripts();
|
||||
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
add_action( 'acf/input/admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'acf/input/admin_head', array( $this, 'admin_head' ) );
|
||||
add_action( 'acf/input/form_data', array( $this, 'form_data' ) );
|
||||
add_action( 'acf/input/admin_footer', array( $this, 'admin_footer' ) );
|
||||
|
||||
add_filter( 'acf/input/admin_l10n', array( $this, 'admin_l10n' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin body class.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param string $classes Space-separated list of CSS classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_class( $classes ) {
|
||||
return $classes . ' acf-admin-page acf-internal-post-type ' . esc_attr( $this->admin_body_class );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any scripts necessary for internal post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
wp_enqueue_script( 'acf-internal-post-type' );
|
||||
|
||||
wp_dequeue_script( 'autosave' );
|
||||
wp_enqueue_style( $this->post_type );
|
||||
wp_enqueue_script( $this->post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up functionality for the field group edit page.
|
||||
*
|
||||
* @since 3.1.8
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_head() {
|
||||
// Override as necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds extra HTML to the acf form data element.
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $args Arguments array to pass through to action.
|
||||
* @return void
|
||||
*/
|
||||
public function form_data( $args ) {
|
||||
// Override as necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin footer third party hook support
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer() {
|
||||
// Override as necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will append extra l10n strings to the acf JS object
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $l10n The array of translated strings.
|
||||
* @return array $l10n
|
||||
*/
|
||||
public function admin_l10n( $l10n ) {
|
||||
// Override as necessary.
|
||||
}
|
||||
|
||||
/**
|
||||
* Ran during the `save_post` hook to verify that the post should be saved.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int $post_id The ID of the post being saved.
|
||||
* @param WP_Post $post The post object.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function verify_save_post( $post_id, $post ) {
|
||||
// Do not save if this is an auto save routine.
|
||||
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bail early if not an ACF internal post type.
|
||||
if ( $post->post_type !== $this->post_type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only save once! WordPress saves a revision as well.
|
||||
if ( wp_is_post_revision( $post_id ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Verify nonce.
|
||||
$nonce_name = str_replace(
|
||||
array( 'acf-', '-' ),
|
||||
array( '', '_' ),
|
||||
$this->post_type
|
||||
);
|
||||
|
||||
if ( ! acf_verify_nonce( $nonce_name ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bail early if request came from an unauthorised user.
|
||||
if ( ! current_user_can( acf_get_setting( 'capability' ) ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Powers the modal for linking field groups to newly-created CPTs/taxonomies.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_link_field_groups() {
|
||||
// Disable filters to ensure ACF loads raw data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
$args = acf_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'nonce' => '',
|
||||
'post_id' => 0,
|
||||
'field_groups' => array(),
|
||||
)
|
||||
);
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
// Verify nonce and user capability.
|
||||
if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) || ! acf_current_user_can_admin() || ! $args['post_id'] ) {
|
||||
die();
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $args['post_id'] );
|
||||
$saved_post = acf_get_internal_post_type( $args['post_id'], $post_type );
|
||||
|
||||
// Link the selected field groups.
|
||||
if ( is_array( $args['field_groups'] ) && ! empty( $args['field_groups'] ) && $saved_post ) {
|
||||
foreach ( $args['field_groups'] as $field_group_id ) {
|
||||
$field_group = acf_get_field_group( $field_group_id );
|
||||
|
||||
if ( ! is_array( $field_group ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$field_group['location'][] = array(
|
||||
array(
|
||||
'param' => 'acf-post-type' === $post_type ? 'post_type' : 'taxonomy',
|
||||
'operator' => '==',
|
||||
'value' => 'acf-post-type' === $post_type ? $saved_post['post_type'] : $saved_post['taxonomy'],
|
||||
),
|
||||
);
|
||||
|
||||
acf_update_field_group( $field_group );
|
||||
}
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<p class="acf-link-successful">
|
||||
<?php
|
||||
$link_successful_text = _n(
|
||||
'Field group linked successfully.',
|
||||
'Field groups linked successfully.',
|
||||
count( $args['field_groups'] ),
|
||||
'acf'
|
||||
);
|
||||
echo esc_html( $link_successful_text );
|
||||
?>
|
||||
</p>
|
||||
<div class="acf-actions">
|
||||
<button type="button" class="acf-btn acf-btn-secondary acf-close-popup"><?php esc_html_e( 'Close Modal', 'acf' ); ?></button>
|
||||
</div>
|
||||
<?php
|
||||
$content = ob_get_clean();
|
||||
wp_send_json_success( array( 'content' => $content ) );
|
||||
}
|
||||
|
||||
// Render the field group select.
|
||||
$field_groups = acf_get_field_groups();
|
||||
$choices = array();
|
||||
|
||||
if ( ! empty( $field_groups ) ) {
|
||||
foreach ( $field_groups as $field_group ) {
|
||||
if ( ! $field_group['ID'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices[ $field_group['ID'] ] = $field_group['title'];
|
||||
}
|
||||
}
|
||||
|
||||
$field = acf_get_valid_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'acf_field_groups',
|
||||
'choices' => $choices,
|
||||
'aria-label' => __( 'Please select the field groups to link.', 'acf' ),
|
||||
'placeholder' => __( 'Select one or many field groups...', 'acf' ),
|
||||
'instructions' => __( 'Field group(s)', 'acf' ),
|
||||
'ui' => true,
|
||||
'multiple' => true,
|
||||
'allow_null' => true,
|
||||
)
|
||||
);
|
||||
|
||||
ob_start();
|
||||
?>
|
||||
<form id="acf-link-field-groups-form">
|
||||
<?php acf_render_field_wrap( $field ); ?>
|
||||
<div class="acf-actions">
|
||||
<button type="button" class="acf-btn acf-btn-secondary acf-close-popup"><?php esc_html_e( 'Cancel', 'acf' ); ?></button>
|
||||
<button type="submit" class="acf-btn acf-btn-primary"><?php esc_html_e( 'Done', 'acf' ); ?></button>
|
||||
</div>
|
||||
</form>
|
||||
<?php
|
||||
$content = ob_get_clean();
|
||||
$title = sprintf(
|
||||
/* translators: %1$s - name of newly created post. %2$s - either "post type" or "taxonomy". */
|
||||
__( 'Link %1$s %2$s to field groups', 'acf' ),
|
||||
isset( $saved_post['title'] ) ? $saved_post['title'] : '',
|
||||
'acf-post-type' === $post_type ? __( 'post type', 'acf' ) : __( 'taxonomy', 'acf' )
|
||||
);
|
||||
|
||||
wp_send_json_success(
|
||||
array(
|
||||
'content' => $content,
|
||||
'title' => $title,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
endif; // Class exists check.
|
@ -0,0 +1,150 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Admin Notices
|
||||
*
|
||||
* Functions and classes to manage admin notices.
|
||||
*
|
||||
* @date 10/1/19
|
||||
* @since 5.7.10
|
||||
*/
|
||||
|
||||
// Exit if accessed directly.
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Register notices store.
|
||||
acf_register_store( 'notices' );
|
||||
|
||||
/**
|
||||
* ACF_Admin_Notice
|
||||
*
|
||||
* Class used to create an admin notice.
|
||||
*
|
||||
* @date 10/1/19
|
||||
* @since 5.7.10
|
||||
*/
|
||||
if ( ! class_exists( 'ACF_Admin_Notice' ) ) :
|
||||
|
||||
class ACF_Admin_Notice extends ACF_Data {
|
||||
|
||||
/** @var array Storage for data. */
|
||||
var $data = array(
|
||||
|
||||
/** @type string Text displayed in notice. */
|
||||
'text' => '',
|
||||
|
||||
/** @type string The type of notice (warning, error, success, info). */
|
||||
'type' => 'info',
|
||||
|
||||
/** @type bool If the notice can be dismissed. */
|
||||
'dismissible' => true,
|
||||
|
||||
/** @type bool If the dismissed state should be persisted to ACF user preferences. */
|
||||
'persisted' => false,
|
||||
);
|
||||
|
||||
/**
|
||||
* render
|
||||
*
|
||||
* Renders the notice HTML.
|
||||
*
|
||||
* @date 27/12/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function render() {
|
||||
$notice_text = $this->get( 'text' );
|
||||
$notice_type = $this->get( 'type' );
|
||||
$is_dismissible = $this->get( 'dismissible' );
|
||||
$is_persisted = $this->get( 'persisted' );
|
||||
|
||||
printf(
|
||||
'<div class="acf-admin-notice notice notice-%s %s" data-persisted="%s" data-persist-id="%s">%s</div>',
|
||||
esc_attr( $notice_type ),
|
||||
$is_dismissible ? 'is-dismissible' : '',
|
||||
$is_persisted ? 'true' : 'false',
|
||||
esc_attr( md5( $notice_text ) ),
|
||||
acf_esc_html( wpautop( acf_punctify( $notice_text ) ) )
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
/**
|
||||
* acf_new_admin_notice
|
||||
*
|
||||
* Instantiates and returns a new model.
|
||||
*
|
||||
* @date 23/12/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param array $data Optional data to set.
|
||||
* @return ACF_Admin_Notice
|
||||
*/
|
||||
function acf_new_admin_notice( $data = false ) {
|
||||
|
||||
// Create notice.
|
||||
$instance = new ACF_Admin_Notice( $data );
|
||||
|
||||
// Register notice.
|
||||
acf_get_store( 'notices' )->set( $instance->cid, $instance );
|
||||
|
||||
// Return notice.
|
||||
return $instance;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_render_admin_notices
|
||||
*
|
||||
* Renders all admin notices HTML.
|
||||
*
|
||||
* @date 10/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function acf_render_admin_notices() {
|
||||
|
||||
// Get notices.
|
||||
$notices = acf_get_store( 'notices' )->get_data();
|
||||
|
||||
// Loop over notices and render.
|
||||
if ( $notices ) {
|
||||
foreach ( $notices as $notice ) {
|
||||
$notice->render();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Render notices during admin action.
|
||||
add_action( 'admin_notices', 'acf_render_admin_notices', 99 );
|
||||
|
||||
/**
|
||||
* acf_add_admin_notice
|
||||
*
|
||||
* Creates and returns a new notice.
|
||||
*
|
||||
* @date 17/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $text The admin notice text.
|
||||
* @param string $class The type of notice (warning, error, success, info).
|
||||
* @param boolean $dismissable Is this notification dismissible (default true) (since 5.11.0)
|
||||
* @param boolean $persisted Store once a notice has been dismissed per user and prevent showing it again. (since 6.1.0)
|
||||
* @return ACF_Admin_Notice
|
||||
*/
|
||||
function acf_add_admin_notice( $text = '', $type = 'info', $dismissible = true, $persisted = false ) {
|
||||
return acf_new_admin_notice(
|
||||
array(
|
||||
'text' => $text,
|
||||
'type' => $type,
|
||||
'dismissible' => $dismissible,
|
||||
'persisted' => $persisted,
|
||||
)
|
||||
);
|
||||
}
|
@ -0,0 +1,360 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'acf_admin_tools' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_admin_tools {
|
||||
|
||||
|
||||
/** @var array Contains an array of admin tool instances */
|
||||
var $tools = array();
|
||||
|
||||
|
||||
/** @var string The active tool */
|
||||
var $active = '';
|
||||
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* This function will setup the class functionality
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function __construct() {
|
||||
|
||||
// actions
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ), 15 );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* register_tool
|
||||
*
|
||||
* This function will store a tool tool class
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param string $class
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function register_tool( $class ) {
|
||||
|
||||
$instance = new $class();
|
||||
$this->tools[ $instance->name ] = $instance;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_tool
|
||||
*
|
||||
* This function will return a tool tool class
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param string $name
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function get_tool( $name ) {
|
||||
|
||||
return isset( $this->tools[ $name ] ) ? $this->tools[ $name ] : null;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_tools
|
||||
*
|
||||
* This function will return an array of all tools
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return array
|
||||
*/
|
||||
|
||||
function get_tools() {
|
||||
|
||||
return $this->tools;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* admin_menu
|
||||
*
|
||||
* This function will add the ACF menu item to the WP admin
|
||||
*
|
||||
* @type action (admin_menu)
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function admin_menu() {
|
||||
|
||||
// bail early if no show_admin
|
||||
if ( ! acf_get_setting( 'show_admin' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add page
|
||||
$page = add_submenu_page( 'edit.php?post_type=acf-field-group', __( 'Tools', 'acf' ), __( 'Tools', 'acf' ), acf_get_setting( 'capability' ), 'acf-tools', array( $this, 'html' ) );
|
||||
|
||||
// actions
|
||||
add_action( 'load-' . $page, array( $this, 'load' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function load() {
|
||||
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
|
||||
// disable filters (default to raw data)
|
||||
acf_disable_filters();
|
||||
|
||||
// include tools
|
||||
$this->include_tools();
|
||||
|
||||
// check submit
|
||||
$this->check_submit();
|
||||
|
||||
// load acf scripts
|
||||
acf_enqueue_scripts();
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin body class.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param string $classes Space-separated list of CSS classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_class( $classes ) {
|
||||
$classes .= ' acf-admin-page';
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* include_tools
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function include_tools() {
|
||||
|
||||
// include
|
||||
acf_include( 'includes/admin/tools/class-acf-admin-tool.php' );
|
||||
acf_include( 'includes/admin/tools/class-acf-admin-tool-export.php' );
|
||||
acf_include( 'includes/admin/tools/class-acf-admin-tool-import.php' );
|
||||
|
||||
// action
|
||||
do_action( 'acf/include_admin_tools' );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* check_submit
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function check_submit() {
|
||||
|
||||
// loop
|
||||
foreach ( $this->get_tools() as $tool ) {
|
||||
|
||||
// load
|
||||
$tool->load();
|
||||
|
||||
// submit
|
||||
if ( acf_verify_nonce( $tool->name ) ) {
|
||||
$tool->submit();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* html
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html() {
|
||||
|
||||
// vars
|
||||
$screen = get_current_screen();
|
||||
$active = acf_maybe_get_GET( 'tool' );
|
||||
|
||||
// view
|
||||
$view = array(
|
||||
'screen_id' => $screen->id,
|
||||
'active' => $active,
|
||||
);
|
||||
|
||||
// register metaboxes
|
||||
foreach ( $this->get_tools() as $tool ) {
|
||||
|
||||
// check active
|
||||
if ( $active && $active !== $tool->name ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// add metabox
|
||||
add_meta_box( 'acf-admin-tool-' . $tool->name, acf_esc_html( $tool->title ), array( $this, 'metabox_html' ), $screen->id, 'normal', 'default', array( 'tool' => $tool->name ) );
|
||||
|
||||
}
|
||||
|
||||
// view
|
||||
acf_get_view( 'tools/tools', $view );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* meta_box_html
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function metabox_html( $post, $metabox ) {
|
||||
|
||||
// vars
|
||||
$tool = $this->get_tool( $metabox['args']['tool'] );
|
||||
|
||||
?>
|
||||
<form method="post">
|
||||
<?php $tool->html(); ?>
|
||||
<?php acf_nonce_input( $tool->name ); ?>
|
||||
</form>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf()->admin_tools = new acf_admin_tools();
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
||||
/*
|
||||
* acf_register_admin_tool
|
||||
*
|
||||
* alias of acf()->admin_tools->register_tool()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_register_admin_tool( $class ) {
|
||||
|
||||
return acf()->admin_tools->register_tool( $class );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_admin_tools_url
|
||||
*
|
||||
* This function will return the admin URL to the tools page
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_get_admin_tools_url() {
|
||||
|
||||
return admin_url( 'edit.php?post_type=acf-field-group&page=acf-tools' );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_admin_tool_url
|
||||
*
|
||||
* This function will return the admin URL to the tools page
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_get_admin_tool_url( $tool = '' ) {
|
||||
|
||||
return acf_get_admin_tools_url() . '&tool=' . $tool;
|
||||
|
||||
}
|
||||
|
||||
|
||||
?>
|
@ -0,0 +1,297 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Upgrade' ) ) :
|
||||
|
||||
class ACF_Admin_Upgrade {
|
||||
|
||||
/**
|
||||
* The name of the transient to store the network update check status.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $network_upgrade_needed_transient;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* Sets up the class functionality.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
|
||||
$this->network_upgrade_needed_transient = 'acf_network_upgrade_needed_' . ACF_UPGRADE_VERSION;
|
||||
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ), 20 );
|
||||
if ( is_multisite() ) {
|
||||
add_action( 'network_admin_menu', array( $this, 'network_admin_menu' ), 20 );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_menu
|
||||
*
|
||||
* Setus up logic if DB Upgrade is needed on a single site.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function admin_menu() {
|
||||
|
||||
// check if upgrade is avaialble
|
||||
if ( acf_has_upgrade() ) {
|
||||
|
||||
// add notice
|
||||
add_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
||||
|
||||
// add page
|
||||
$page = add_submenu_page( 'index.php', __( 'Upgrade Database', 'acf' ), __( 'Upgrade Database', 'acf' ), acf_get_setting( 'capability' ), 'acf-upgrade', array( $this, 'admin_html' ) );
|
||||
|
||||
// actions
|
||||
add_action( 'load-' . $page, array( $this, 'admin_load' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a “Database Upgrade Required” network admin notice and adds
|
||||
* the “Upgrade Database” submenu under the “Dashboard” network admin
|
||||
* menu item if an ACF upgrade needs to run on any network site.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
* @since 6.0.0 Reduce memory usage, cache network upgrade checks.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
function network_admin_menu() {
|
||||
$network_upgrade_needed = get_site_transient( $this->network_upgrade_needed_transient );
|
||||
|
||||
// No transient value exists, so run the upgrade check.
|
||||
if ( $network_upgrade_needed === false ) {
|
||||
$network_upgrade_needed = $this->check_for_network_upgrades();
|
||||
}
|
||||
|
||||
if ( $network_upgrade_needed === 'no' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
|
||||
|
||||
$page = add_submenu_page(
|
||||
'index.php',
|
||||
__( 'Upgrade Database', 'acf' ),
|
||||
__( 'Upgrade Database', 'acf' ),
|
||||
acf_get_setting( 'capability' ),
|
||||
'acf-upgrade-network',
|
||||
array( $this, 'network_admin_html' )
|
||||
);
|
||||
|
||||
add_action( "load-$page", array( $this, 'network_admin_load' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if an ACF database upgrade is required on any site in the
|
||||
* multisite network.
|
||||
*
|
||||
* Stores the result in `$this->network_upgrade_needed_transient`,
|
||||
* which is version-linked to ACF_UPGRADE_VERSION: the highest ACF
|
||||
* version that requires an upgrade function to run. Bumping
|
||||
* ACF_UPGRADE_VERSION will trigger new upgrade checks but incrementing
|
||||
* ACF_VERSION alone will not.
|
||||
*
|
||||
* @since 6.0.0
|
||||
* @return string 'yes' if any site in the network requires an upgrade,
|
||||
* otherwise 'no'. String instead of boolean so that
|
||||
* `false` returned from a get_site_transient check can
|
||||
* denote that an upgrade check is needed.
|
||||
*/
|
||||
public function check_for_network_upgrades() {
|
||||
$network_upgrade_needed = 'no';
|
||||
|
||||
$sites = get_sites(
|
||||
array(
|
||||
'number' => 0,
|
||||
'fields' => 'ids', // Reduces PHP memory usage.
|
||||
)
|
||||
);
|
||||
|
||||
if ( $sites ) {
|
||||
// Reduces memory usage (same pattern used in wp-includes/ms-site.php).
|
||||
remove_action( 'switch_blog', 'wp_switch_roles_and_user', 1 );
|
||||
|
||||
foreach ( $sites as $site_id ) {
|
||||
switch_to_blog( $site_id );
|
||||
|
||||
$site_needs_upgrade = acf_has_upgrade();
|
||||
|
||||
restore_current_blog(); // Restores global vars.
|
||||
|
||||
if ( $site_needs_upgrade ) {
|
||||
$network_upgrade_needed = 'yes';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
add_action( 'switch_blog', 'wp_switch_roles_and_user', 1, 2 );
|
||||
}
|
||||
|
||||
set_site_transient(
|
||||
$this->network_upgrade_needed_transient,
|
||||
$network_upgrade_needed,
|
||||
3 * MONTH_IN_SECONDS
|
||||
);
|
||||
|
||||
return $network_upgrade_needed;
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_load
|
||||
*
|
||||
* Runs during the loading of the admin page.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function admin_load() {
|
||||
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
|
||||
// remove prompt
|
||||
remove_action( 'admin_notices', array( $this, 'admin_notices' ) );
|
||||
|
||||
// Enqueue core script.
|
||||
acf_enqueue_script( 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* network_admin_load
|
||||
*
|
||||
* Runs during the loading of the network admin page.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function network_admin_load() {
|
||||
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
|
||||
// remove prompt
|
||||
remove_action( 'network_admin_notices', array( $this, 'network_admin_notices' ) );
|
||||
|
||||
// Enqueue core script.
|
||||
acf_enqueue_script( 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin body class.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param string $classes Space-separated list of CSS classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_class( $classes ) {
|
||||
$classes .= ' acf-admin-page';
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_notices
|
||||
*
|
||||
* Displays the DB Upgrade prompt.
|
||||
*
|
||||
* @date 23/8/18
|
||||
* @since 5.7.3
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function admin_notices() {
|
||||
|
||||
// vars
|
||||
$view = array(
|
||||
'button_text' => __( 'Upgrade Database', 'acf' ),
|
||||
'button_url' => admin_url( 'index.php?page=acf-upgrade' ),
|
||||
'confirm' => true,
|
||||
);
|
||||
|
||||
// view
|
||||
acf_get_view( 'upgrade/notice', $view );
|
||||
}
|
||||
|
||||
/**
|
||||
* network_admin_notices
|
||||
*
|
||||
* Displays the DB Upgrade prompt on a multi site.
|
||||
*
|
||||
* @date 23/8/18
|
||||
* @since 5.7.3
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function network_admin_notices() {
|
||||
|
||||
// vars
|
||||
$view = array(
|
||||
'button_text' => __( 'Review sites & upgrade', 'acf' ),
|
||||
'button_url' => network_admin_url( 'index.php?page=acf-upgrade-network' ),
|
||||
'confirm' => false,
|
||||
);
|
||||
|
||||
// view
|
||||
acf_get_view( 'upgrade/notice', $view );
|
||||
}
|
||||
|
||||
/**
|
||||
* admin_html
|
||||
*
|
||||
* Displays the HTML for the admin page.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function admin_html() {
|
||||
acf_get_view( 'upgrade/upgrade' );
|
||||
}
|
||||
|
||||
/**
|
||||
* network_admin_html
|
||||
*
|
||||
* Displays the HTML for the network upgrade admin page.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function network_admin_html() {
|
||||
acf_get_view( 'upgrade/network' );
|
||||
}
|
||||
}
|
||||
|
||||
// instantiate
|
||||
acf_new_instance( 'ACF_Admin_Upgrade' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,277 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin' ) ) :
|
||||
|
||||
class ACF_Admin {
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @date 23/06/12
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
// Add actions.
|
||||
add_action( 'admin_menu', array( $this, 'admin_menu' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'admin_enqueue_scripts' ) );
|
||||
add_action( 'admin_body_class', array( $this, 'admin_body_class' ) );
|
||||
add_action( 'current_screen', array( $this, 'current_screen' ) );
|
||||
add_filter( 'parent_file', array( $this, 'ensure_menu_selection' ) );
|
||||
add_filter( 'submenu_file', array( $this, 'ensure_submenu_selection' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the ACF menu item.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*/
|
||||
public function admin_menu() {
|
||||
|
||||
// Bail early if ACF is hidden.
|
||||
if ( ! acf_get_setting( 'show_admin' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Vars.
|
||||
$cap = acf_get_setting( 'capability' );
|
||||
$parent_slug = 'edit.php?post_type=acf-field-group';
|
||||
|
||||
// Add menu items.
|
||||
add_menu_page( __( 'ACF', 'acf' ), __( 'ACF', 'acf' ), $cap, $parent_slug, false, 'dashicons-welcome-widgets-menus', 80 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues global admin styling.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function admin_enqueue_scripts() {
|
||||
wp_enqueue_style( 'acf-global' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends custom admin body classes.
|
||||
*
|
||||
* @date 5/11/19
|
||||
* @since 5.8.7
|
||||
*
|
||||
* @param string $classes Space-separated list of CSS classes.
|
||||
* @return string
|
||||
*/
|
||||
public function admin_body_class( $classes ) {
|
||||
global $wp_version;
|
||||
|
||||
// Determine body class version.
|
||||
$wp_minor_version = floatval( $wp_version );
|
||||
if ( $wp_minor_version >= 5.3 ) {
|
||||
$classes .= ' acf-admin-5-3';
|
||||
} else {
|
||||
$classes .= ' acf-admin-3-8';
|
||||
}
|
||||
|
||||
// Add browser for specific CSS.
|
||||
$classes .= ' acf-browser-' . esc_attr( acf_get_browser() );
|
||||
|
||||
// Return classes.
|
||||
return $classes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds custom functionality to "ACF" admin pages.
|
||||
*
|
||||
* @date 7/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function current_screen( $screen ) {
|
||||
// Determine if the current page being viewed is "ACF" related.
|
||||
if ( isset( $screen->post_type ) && in_array( $screen->post_type, acf_get_internal_post_types(), true ) ) {
|
||||
add_action( 'in_admin_header', array( $this, 'in_admin_header' ) );
|
||||
add_filter( 'admin_footer_text', array( $this, 'admin_footer_text' ) );
|
||||
$this->setup_help_tab();
|
||||
$this->maybe_show_import_from_cptui_notice();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up the admin help tab.
|
||||
*
|
||||
* @date 20/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function setup_help_tab() {
|
||||
$screen = get_current_screen();
|
||||
|
||||
// Overview tab.
|
||||
$screen->add_help_tab(
|
||||
array(
|
||||
'id' => 'overview',
|
||||
'title' => __( 'Overview', 'acf' ),
|
||||
'content' =>
|
||||
'<p><strong>' . __( 'Overview', 'acf' ) . '</strong></p>' .
|
||||
'<p>' . __( 'The Advanced Custom Fields plugin provides a visual form builder to customize WordPress edit screens with extra fields, and an intuitive API to display custom field values in any theme template file.', 'acf' ) . '</p>' .
|
||||
'<p>' . sprintf(
|
||||
__( 'Before creating your first Field Group, we recommend first reading our <a href="%s" target="_blank">Getting started</a> guide to familiarize yourself with the plugin\'s philosophy and best practises.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'help-tab' )
|
||||
) . '</p>' .
|
||||
'<p>' . __( 'Please use the Help & Support tab to get in touch should you find yourself requiring assistance.', 'acf' ) . '</p>' .
|
||||
'',
|
||||
)
|
||||
);
|
||||
|
||||
// Help tab.
|
||||
$screen->add_help_tab(
|
||||
array(
|
||||
'id' => 'help',
|
||||
'title' => __( 'Help & Support', 'acf' ),
|
||||
'content' =>
|
||||
'<p><strong>' . __( 'Help & Support', 'acf' ) . '</strong></p>' .
|
||||
'<p>' . __( 'We are fanatical about support, and want you to get the best out of your website with ACF. If you run into any difficulties, there are several places you can find help:', 'acf' ) . '</p>' .
|
||||
'<ul>' .
|
||||
'<li>' . sprintf(
|
||||
__( '<a href="%s" target="_blank">Documentation</a>. Our extensive documentation contains references and guides for most situations you may encounter.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/', 'docs', 'help-tab' )
|
||||
) . '</li>' .
|
||||
'<li>' . sprintf(
|
||||
__( '<a href="%s" target="_blank">Discussions</a>. We have an active and friendly community on our Community Forums who may be able to help you figure out the \'how-tos\' of the ACF world.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://support.advancedcustomfields.com/', 'docs', 'help-tab' )
|
||||
) . '</li>' .
|
||||
'<li>' . sprintf(
|
||||
__( '<a href="%s" target="_blank">Help Desk</a>. The support professionals on our Help Desk will assist with your more in depth, technical challenges.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/support/', 'docs', 'help-tab' )
|
||||
) . '</li>' .
|
||||
'</ul>',
|
||||
)
|
||||
);
|
||||
|
||||
// Sidebar.
|
||||
$screen->set_help_sidebar(
|
||||
'<p><strong>' . __( 'Information', 'acf' ) . '</strong></p>' .
|
||||
'<p><span class="dashicons dashicons-admin-plugins"></span> ' . sprintf( __( 'Version %s', 'acf' ), ACF_VERSION ) . '</p>' .
|
||||
'<p><span class="dashicons dashicons-wordpress"></span> <a href="https://wordpress.org/plugins/advanced-custom-fields/" target="_blank">' . __( 'View details', 'acf' ) . '</a></p>' .
|
||||
'<p><span class="dashicons dashicons-admin-home"></span> <a href="' . acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/', 'docs', 'help-tab' ) . '" target="_blank" target="_blank">' . __( 'Visit website', 'acf' ) . '</a></p>' .
|
||||
''
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a notice to import post types and taxonomies from CPTUI if that plugin is active.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function maybe_show_import_from_cptui_notice() {
|
||||
global $plugin_page;
|
||||
|
||||
// Only show if CPTUI is active and post types are enabled.
|
||||
if ( ! acf_get_setting( 'enable_post_types' ) || ! is_plugin_active( 'custom-post-type-ui/custom-post-type-ui.php' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// No need to show on the tools page.
|
||||
if ( 'acf-tools' === $plugin_page ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$text = sprintf(
|
||||
/* translators: %s - URL to ACF tools page. */
|
||||
__( 'Import Post Types and Taxonomies registered with Custom Post Type UI and manage them with ACF. <a href="%s">Get Started</a>.', 'acf' ),
|
||||
acf_get_admin_tools_url()
|
||||
);
|
||||
|
||||
acf_add_admin_notice( $text, 'success', true, true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the admin navigation element.
|
||||
*
|
||||
* @date 27/3/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function in_admin_header() {
|
||||
acf_get_view( 'global/navigation' );
|
||||
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( isset( $screen->base ) && 'post' === $screen->base ) {
|
||||
acf_get_view( 'global/form-top' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Modifies the admin footer text.
|
||||
*
|
||||
* @date 7/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $text The admin footer text.
|
||||
* @return string
|
||||
*/
|
||||
function admin_footer_text( $text ) {
|
||||
if ( null === $text ) {
|
||||
$text = '';
|
||||
}
|
||||
// Use RegExp to append "ACF" after the <a> element allowing translations to read correctly.
|
||||
return preg_replace( '/(<a[\S\s]+?\/a>)/', '$1 ' . __( 'and', 'acf' ) . ' <a href="' . acf_add_url_utm_tags( 'https://www.advancedcustomfields.com', 'footer', 'footer' ) . '" target="_blank">ACF</a>', $text, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Ensure the ACF parent menu is selected for add-new.php
|
||||
*
|
||||
* @since 6.1
|
||||
* @param string $parent_file The parent file checked against menu activation.
|
||||
* @return string The modified parent file
|
||||
*/
|
||||
public function ensure_menu_selection( $parent_file ) {
|
||||
if ( ! is_string( $parent_file ) ) {
|
||||
return $parent_file;
|
||||
}
|
||||
if ( strpos( $parent_file, 'edit.php?post_type=acf-' ) === 0 ) {
|
||||
return 'edit.php?post_type=acf-field-group';
|
||||
}
|
||||
return $parent_file;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Ensure the correct ACF submenu item is selected when in post-new versions of edit pages
|
||||
*
|
||||
* @since 6.1
|
||||
* @param string $submenu_file The submenu filename.
|
||||
* @return string The modified submenu filename
|
||||
*/
|
||||
public function ensure_submenu_selection( $submenu_file ) {
|
||||
if ( ! is_string( $submenu_file ) ) {
|
||||
return $submenu_file;
|
||||
}
|
||||
if ( strpos( $submenu_file, 'post-new.php?post_type=acf-' ) === 0 ) {
|
||||
return str_replace( 'post-new', 'edit', $submenu_file );
|
||||
}
|
||||
return $submenu_file;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
acf_new_instance( 'ACF_Admin' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,603 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Admin Field Group Class
|
||||
*
|
||||
* @class acf_admin_field_group
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'acf_admin_field_group' ) ) :
|
||||
|
||||
/**
|
||||
* ACF Admin Field Group Class
|
||||
*
|
||||
* All the logic for editing a field group
|
||||
*/
|
||||
class acf_admin_field_group extends ACF_Admin_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-field-group';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-single-field-group';
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
parent::__construct();
|
||||
|
||||
add_action( 'wp_ajax_acf/field_group/render_field_settings', array( $this, 'ajax_render_field_settings' ) );
|
||||
add_action( 'wp_ajax_acf/field_group/render_location_rule', array( $this, 'ajax_render_location_rule' ) );
|
||||
add_action( 'wp_ajax_acf/field_group/move_field', array( $this, 'ajax_move_field' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will customize the message shown when editing a field group
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $messages Post type messages.
|
||||
* @return array
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages['acf-field-group'] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => __( 'Field group updated.', 'acf' ),
|
||||
2 => __( 'Field group updated.', 'acf' ),
|
||||
3 => __( 'Field group deleted.', 'acf' ),
|
||||
4 => __( 'Field group updated.', 'acf' ),
|
||||
5 => false, // field group does not support revisions.
|
||||
6 => __( 'Field group published.', 'acf' ),
|
||||
7 => __( 'Field group saved.', 'acf' ),
|
||||
8 => __( 'Field group submitted.', 'acf' ),
|
||||
9 => __( 'Field group scheduled for.', 'acf' ),
|
||||
10 => __( 'Field group draft updated.', 'acf' ),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any scripts necessary for internal post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
parent::admin_enqueue_scripts();
|
||||
|
||||
acf_localize_text(
|
||||
array(
|
||||
'The string "field_" may not be used at the start of a field name' => __( 'The string "field_" may not be used at the start of a field name', 'acf' ),
|
||||
'This field cannot be moved until its changes have been saved' => __( 'This field cannot be moved until its changes have been saved', 'acf' ),
|
||||
'Field group title is required' => __( 'Field group title is required', 'acf' ),
|
||||
'Move field group to trash?' => __( 'Move field group to trash?', 'acf' ),
|
||||
'No toggle fields available' => __( 'No toggle fields available', 'acf' ),
|
||||
'Move Custom Field' => __( 'Move Custom Field', 'acf' ),
|
||||
'Close modal' => __( 'Close modal', 'acf' ),
|
||||
'Field moved to other group' => __( 'Field moved to other group', 'acf' ),
|
||||
'Field groups linked successfully.' => __( 'Field groups linked successfully.', 'acf' ),
|
||||
'Checked' => __( 'Checked', 'acf' ),
|
||||
'(no label)' => __( '(no label)', 'acf' ),
|
||||
'(this field)' => __( '(this field)', 'acf' ),
|
||||
'copy' => __( 'copy', 'acf' ),
|
||||
'or' => __( 'or', 'acf' ),
|
||||
'Show this field group if' => __( 'Show this field group if', 'acf' ),
|
||||
'Null' => __( 'Null', 'acf' ),
|
||||
'PRO Only' => __( 'PRO Only', 'acf' ),
|
||||
|
||||
// Conditions.
|
||||
'Has any value' => __( 'Has any value', 'acf' ),
|
||||
'Has no value' => __( 'Has no value', 'acf' ),
|
||||
'Value is equal to' => __( 'Value is equal to', 'acf' ),
|
||||
'Value is not equal to' => __( 'Value is not equal to', 'acf' ),
|
||||
'Value matches pattern' => __( 'Value matches pattern', 'acf' ),
|
||||
'Value contains' => __( 'Value contains', 'acf' ),
|
||||
'Value is greater than' => __( 'Value is greater than', 'acf' ),
|
||||
'Value is less than' => __( 'Value is less than', 'acf' ),
|
||||
'Selection is greater than' => __( 'Selection is greater than', 'acf' ),
|
||||
'Selection is less than' => __( 'Selection is less than', 'acf' ),
|
||||
|
||||
// Field type selection modal.
|
||||
'Type to search...' => __( 'Type to search...', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_localize_data(
|
||||
array(
|
||||
'fieldTypes' => acf_get_field_types_info(),
|
||||
'fieldCategoriesL10n' => acf_get_field_categories_i18n(),
|
||||
'PROUpgradeURL' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'field-type-selection' ),
|
||||
'PROFieldTypes' => acf_get_pro_field_types(),
|
||||
'PROLocationTypes' => array(
|
||||
'block' => __( 'Block', 'acf' ),
|
||||
'options_page' => __( 'Options Page', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
do_action( 'acf/field_group/admin_enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Set up functionality for the field group edit page.
|
||||
*
|
||||
* @since 3.1.8
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_head() {
|
||||
global $post, $field_group;
|
||||
|
||||
// Set global var.
|
||||
$field_group = acf_get_field_group( $post->ID );
|
||||
|
||||
// metaboxes.
|
||||
add_meta_box( 'acf-field-group-fields', __( 'Fields', 'acf' ), array( $this, 'mb_fields' ), 'acf-field-group', 'normal', 'high' );
|
||||
if ( ! defined( 'ACF_PRO' ) || ! ACF_PRO ) {
|
||||
add_meta_box( 'acf-field-group-pro-features', 'ACF PRO', array( $this, 'mb_pro_features' ), 'acf-field-group', 'normal', 'high' );
|
||||
}
|
||||
add_meta_box( 'acf-field-group-options', __( 'Settings', 'acf' ), array( $this, 'mb_options' ), 'acf-field-group', 'normal', 'high' );
|
||||
|
||||
// actions.
|
||||
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
|
||||
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
|
||||
|
||||
// filters.
|
||||
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_screen_layout_acf-field-group', array( $this, 'screen_layout' ), 10, 1 );
|
||||
|
||||
// 3rd party hook.
|
||||
do_action( 'acf/field_group/admin_head' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This action will allow ACF to render metaboxes after the title.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit_form_after_title() {
|
||||
global $post;
|
||||
|
||||
// Render post data.
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'field_group',
|
||||
'post_id' => $post->ID,
|
||||
'delete_fields' => 0,
|
||||
'validation' => 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will add extra HTML to the acf form data element
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $args Arguments array to pass through to action.
|
||||
* @return void
|
||||
*/
|
||||
public function form_data( $args ) {
|
||||
do_action( 'acf/field_group/form_data', $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will append extra l10n strings to the acf JS object
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $l10n The array of translated strings.
|
||||
* @return array $l10n
|
||||
*/
|
||||
public function admin_l10n( $l10n ) {
|
||||
return apply_filters( 'acf/field_group/admin_l10n', $l10n );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin footer third party hook support
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer() {
|
||||
do_action( 'acf/field_group/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 ) {
|
||||
$show_field_keys = acf_get_user_setting( 'show_field_keys' ) ? 'checked="checked"' : '';
|
||||
$show_field_settings_tabs = acf_get_user_setting( 'show_field_settings_tabs', true ) ? 'checked="checked"' : '';
|
||||
$hide_field_settings_tabs = apply_filters( 'acf/field_group/disable_field_settings_tabs', false );
|
||||
|
||||
$html .= '<div id="acf-append-show-on-screen" class="acf-hidden">';
|
||||
$html .= '<label for="acf-field-key-hide"><input id="acf-field-key-hide" type="checkbox" value="1" name="show_field_keys" ' . $show_field_keys . ' /> ' . __( 'Field Keys', 'acf' ) . '</label>';
|
||||
|
||||
if ( ! $hide_field_settings_tabs ) {
|
||||
$html .= '<label for="acf-field-settings-tabs"><input id="acf-field-settings-tabs" type="checkbox" value="1" name="show_field_settings_tabs" ' . $show_field_settings_tabs . ' />' . __( 'Field Settings Tabs', 'acf' ) . '</label>';
|
||||
}
|
||||
|
||||
$html .= '</div>';
|
||||
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "Edit Field Group" screen to use a one-column layout.
|
||||
*
|
||||
* @param int $columns Number of columns for layout.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function screen_layout( $columns = 0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will customize the publish metabox
|
||||
*
|
||||
* @since 5.2.9
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function post_submitbox_misc_actions() {
|
||||
global $field_group;
|
||||
$status_label = $field_group['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves field group data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @param WP_Post $post The post object.
|
||||
*
|
||||
* @return int $post_id
|
||||
*/
|
||||
public function save_post( $post_id, $post ) {
|
||||
if ( ! $this->verify_save_post( $post_id, $post ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// disable filters to ensure ACF loads raw data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// save fields.
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated by WordPress.
|
||||
if ( ! empty( $_POST['acf_fields'] ) ) {
|
||||
|
||||
// loop.
|
||||
foreach ( $_POST['acf_fields'] as $field ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
|
||||
|
||||
if ( ! isset( $field['key'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars.
|
||||
$specific = false;
|
||||
$save = acf_extract_var( $field, 'save' );
|
||||
|
||||
// only saved field if has changed.
|
||||
if ( $save == 'meta' ) {
|
||||
$specific = array(
|
||||
'menu_order',
|
||||
'post_parent',
|
||||
);
|
||||
}
|
||||
|
||||
// set parent.
|
||||
if ( ! $field['parent'] ) {
|
||||
$field['parent'] = $post_id;
|
||||
}
|
||||
|
||||
// save field.
|
||||
acf_update_field( $field, $specific );
|
||||
}
|
||||
}
|
||||
|
||||
// delete fields.
|
||||
if ( $_POST['_acf_delete_fields'] ) { // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below.
|
||||
|
||||
// clean.
|
||||
$ids = explode( '|', $_POST['_acf_delete_fields'] ); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized below.
|
||||
$ids = array_map( 'intval', $ids );
|
||||
|
||||
// loop.
|
||||
foreach ( $ids as $id ) {
|
||||
|
||||
// bai early if no id.
|
||||
if ( ! $id ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// delete.
|
||||
acf_delete_field( $id );
|
||||
}
|
||||
}
|
||||
|
||||
$_POST['acf_field_group']['ID'] = $post_id;
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
|
||||
$_POST['acf_field_group']['title'] = $_POST['post_title'];
|
||||
|
||||
// save field group.
|
||||
acf_update_field_group( $_POST['acf_field_group'] );
|
||||
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will render the HTML for the metabox 'acf-field-group-fields'
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_fields() {
|
||||
global $field_group;
|
||||
|
||||
$view = array(
|
||||
'fields' => acf_get_fields( $field_group ),
|
||||
'parent' => 0,
|
||||
);
|
||||
|
||||
acf_get_view( $this->post_type . '/fields', $view );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will render the HTML for the metabox 'acf-field-group-pro-features'
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_pro_features() {
|
||||
acf_get_view( $this->post_type . '/pro-features' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will render the HTML for the metabox 'acf-field-group-options'
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_options() {
|
||||
global $field_group;
|
||||
|
||||
// Field group key (leave in for compatibility).
|
||||
if ( ! acf_is_field_group_key( $field_group['key'] ) ) {
|
||||
$field_group['key'] = uniqid( 'group_' );
|
||||
}
|
||||
|
||||
acf_get_view( $this->post_type . '/options' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function can be accessed via an AJAX action and will return the result from the render_location_value function
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_render_location_rule() {
|
||||
// validate.
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// verify user capability.
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// validate rule.
|
||||
$rule = acf_validate_location_rule( acf_sanitize_request_args( $_POST['rule'] ) );
|
||||
|
||||
acf_get_view(
|
||||
'acf-field-group/location-rule',
|
||||
array(
|
||||
'rule' => $rule,
|
||||
)
|
||||
);
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will return HTML containing the field's settings based on it's new type
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function ajax_render_field_settings() {
|
||||
// Verify the current request.
|
||||
if ( ! acf_verify_ajax() || ! acf_current_user_can_admin() ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
// Make sure we have a field.
|
||||
$field = acf_maybe_get_POST( 'field' );
|
||||
if ( ! $field ) {
|
||||
wp_send_json_error();
|
||||
}
|
||||
|
||||
$field['prefix'] = acf_maybe_get_POST( 'prefix' );
|
||||
$field = acf_get_valid_field( $field );
|
||||
$tabs = acf_get_combined_field_type_settings_tabs();
|
||||
$tab_keys = array_keys( $tabs );
|
||||
$sections = array();
|
||||
|
||||
foreach ( $tab_keys as $tab ) {
|
||||
ob_start();
|
||||
|
||||
if ( 'general' === $tab ) {
|
||||
// Back-compat for fields not using tab-specific hooks.
|
||||
do_action( "acf/render_field_settings/type={$field['type']}", $field );
|
||||
}
|
||||
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab}_settings/type={$field['type']}", $field );
|
||||
|
||||
$sections[ $tab ] = ob_get_clean();
|
||||
}
|
||||
|
||||
wp_send_json_success( $sections );
|
||||
}
|
||||
|
||||
/**
|
||||
* Move field AJAX function
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void No return, HTML output for AJAX consumption.
|
||||
*/
|
||||
public function ajax_move_field() {
|
||||
// disable filters to ensure ACF loads raw data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||
$args = acf_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'nonce' => '',
|
||||
'post_id' => 0,
|
||||
'field_id' => 0,
|
||||
'field_group_id' => 0,
|
||||
)
|
||||
);
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
// verify nonce.
|
||||
if ( ! wp_verify_nonce( $args['nonce'], 'acf_nonce' ) ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// verify user capability.
|
||||
if ( ! acf_current_user_can_admin() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// confirm?
|
||||
if ( $args['field_id'] && $args['field_group_id'] ) {
|
||||
|
||||
// vars.
|
||||
$field = acf_get_field( $args['field_id'] );
|
||||
$field_group = acf_get_field_group( $args['field_group_id'] );
|
||||
|
||||
// update parent.
|
||||
$field['parent'] = $field_group['ID'];
|
||||
|
||||
// remove conditional logic.
|
||||
$field['conditional_logic'] = 0;
|
||||
|
||||
// update field.
|
||||
acf_update_field( $field );
|
||||
|
||||
// Output HTML.
|
||||
$link = '<a href="' . admin_url( 'post.php?post=' . $field_group['ID'] . '&action=edit' ) . '" target="_blank">' . esc_html( $field_group['title'] ) . '</a>';
|
||||
|
||||
echo '' .
|
||||
'<p><strong>' . __( 'Move Complete.', 'acf' ) . '</strong></p>' .
|
||||
'<p>' . sprintf(
|
||||
/* translators: Confirmation message once a field has been moved to a different field group. */
|
||||
acf_punctify( __( 'The %1$s field can now be found in the %2$s field group', 'acf' ) ),
|
||||
esc_html( $field['label'] ),
|
||||
$link //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
) . '</p>' .
|
||||
'<a href="#" class="button button-primary acf-close-popup">' . __( 'Close Modal', 'acf' ) . '</a>';
|
||||
die();
|
||||
}
|
||||
|
||||
// get all field groups.
|
||||
$field_groups = acf_get_field_groups();
|
||||
$choices = array();
|
||||
|
||||
// check.
|
||||
if ( ! empty( $field_groups ) ) {
|
||||
|
||||
// loop.
|
||||
foreach ( $field_groups as $field_group ) {
|
||||
|
||||
// bail early if no ID.
|
||||
if ( ! $field_group['ID'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// bail early if is current.
|
||||
if ( $field_group['ID'] == $args['post_id'] ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$choices[ $field_group['ID'] ] = $field_group['title'];
|
||||
}
|
||||
}
|
||||
|
||||
// render options.
|
||||
$field = acf_get_valid_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'acf_field_group',
|
||||
'choices' => $choices,
|
||||
'aria-label' => __( 'Please select the destination for this field', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
echo '<p>' . __( 'Please select the destination for this field', 'acf' ) . '</p>';
|
||||
|
||||
echo '<form id="acf-move-field-form">';
|
||||
|
||||
// render.
|
||||
acf_render_field_wrap( $field );
|
||||
|
||||
echo '<button type="submit" class="acf-btn">' . __( 'Move Field', 'acf' ) . '</button>';
|
||||
|
||||
echo '</form>';
|
||||
|
||||
die();
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initialize.
|
||||
new acf_admin_field_group();
|
||||
endif; // Class exists check.
|
||||
|
||||
?>
|
@ -0,0 +1,373 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Field_Groups' ) ) :
|
||||
|
||||
#[AllowDynamicProperties]
|
||||
class ACF_Admin_Field_Groups extends ACF_Admin_Internal_Post_Type_List {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-field-group';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-field-groups';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = 'field-groups';
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @date 5/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'load-edit.php', array( $this, 'handle_redirection' ) );
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any menu items required for field groups.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function admin_menu() {
|
||||
$parent_slug = 'edit.php?post_type=acf-field-group';
|
||||
$cap = acf_get_setting( 'capability' );
|
||||
add_submenu_page( $parent_slug, __( 'Field Groups', 'acf' ), __( 'Field Groups', 'acf' ), $cap, $parent_slug );
|
||||
}
|
||||
|
||||
/**
|
||||
* Redirects users from ACF 4.0 admin page.
|
||||
*
|
||||
* @date 17/9/18
|
||||
* @since 5.7.6
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function handle_redirection() {
|
||||
if ( isset( $_GET['post_type'] ) && $_GET['post_type'] === 'acf' ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||
wp_redirect( $this->get_admin_url() );
|
||||
exit;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table columns.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $_columns The columns array.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_columns( $_columns ) {
|
||||
// Set the "no found" label to be our custom HTML for no results.
|
||||
if ( empty( acf_request_arg( 's' ) ) ) {
|
||||
global $wp_post_types;
|
||||
$this->not_found_label = $wp_post_types['acf-field-group']->labels->not_found;
|
||||
$wp_post_types['acf-field-group']->labels->not_found = $this->get_not_found_html();
|
||||
}
|
||||
|
||||
$columns = array(
|
||||
'cb' => $_columns['cb'],
|
||||
'title' => $_columns['title'],
|
||||
'acf-description' => __( 'Description', 'acf' ),
|
||||
'acf-key' => __( 'Key', 'acf' ),
|
||||
'acf-location' => __( 'Location', 'acf' ),
|
||||
'acf-count' => __( 'Fields', 'acf' ),
|
||||
);
|
||||
|
||||
if ( acf_get_local_json_files( $this->post_type ) ) {
|
||||
$columns['acf-json'] = __( 'Local JSON', 'acf' );
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a specific admin table column.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $column_name The name of the column to display.
|
||||
* @param array $post The main ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column( $column_name, $post ) {
|
||||
switch ( $column_name ) {
|
||||
|
||||
// Key.
|
||||
case 'acf-key':
|
||||
echo '<i class="acf-icon acf-icon-key-solid"></i>';
|
||||
echo esc_html( $post['key'] );
|
||||
break;
|
||||
|
||||
// Description.
|
||||
case 'acf-description':
|
||||
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
|
||||
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
|
||||
} else {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
|
||||
}
|
||||
break;
|
||||
|
||||
// Location.
|
||||
case 'acf-location':
|
||||
$this->render_admin_table_column_locations( $post );
|
||||
break;
|
||||
|
||||
// Count.
|
||||
case 'acf-count':
|
||||
$this->render_admin_table_column_num_fields( $post );
|
||||
break;
|
||||
|
||||
// Local JSON.
|
||||
case 'acf-json':
|
||||
$this->render_admin_table_column_local_status( $post );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays a visual representation of the field group's locations.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $field_group The field group.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_locations( $field_group ) {
|
||||
$objects = array();
|
||||
|
||||
// Loop over location rules and determine connected object types.
|
||||
if ( $field_group['location'] ) {
|
||||
foreach ( $field_group['location'] as $i => $rules ) {
|
||||
|
||||
// Determine object types for each rule.
|
||||
foreach ( $rules as $j => $rule ) {
|
||||
|
||||
// Get location type and subtype for the current rule.
|
||||
$location = acf_get_location_rule( $rule['param'] );
|
||||
$location_object_type = '';
|
||||
$location_object_subtype = '';
|
||||
if ( $location ) {
|
||||
$location_object_type = $location->get_object_type( $rule );
|
||||
$location_object_subtype = $location->get_object_subtype( $rule );
|
||||
}
|
||||
$rules[ $j ]['object_type'] = $location_object_type;
|
||||
$rules[ $j ]['object_subtype'] = $location_object_subtype;
|
||||
}
|
||||
|
||||
// Now that each $rule conains object type data...
|
||||
$object_types = array_column( $rules, 'object_type' );
|
||||
$object_types = array_filter( $object_types );
|
||||
$object_types = array_values( $object_types );
|
||||
if ( $object_types ) {
|
||||
$object_type = $object_types[0];
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
|
||||
$object_subtypes = array_column( $rules, 'object_subtype' );
|
||||
$object_subtypes = array_filter( $object_subtypes );
|
||||
$object_subtypes = array_values( $object_subtypes );
|
||||
$object_subtypes = array_map( 'acf_array', $object_subtypes );
|
||||
if ( count( $object_subtypes ) > 1 ) {
|
||||
$object_subtypes = call_user_func_array( 'array_intersect', $object_subtypes );
|
||||
$object_subtypes = array_values( $object_subtypes );
|
||||
} elseif ( $object_subtypes ) {
|
||||
$object_subtypes = $object_subtypes[0];
|
||||
} else {
|
||||
$object_subtypes = array( '' );
|
||||
}
|
||||
|
||||
// Append to objects.
|
||||
foreach ( $object_subtypes as $object_subtype ) {
|
||||
$object = acf_get_object_type( $object_type, $object_subtype );
|
||||
if ( $object ) {
|
||||
$objects[ $object->name ] = $object;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Reset keys.
|
||||
$objects = array_values( $objects );
|
||||
|
||||
// Display.
|
||||
$html = '';
|
||||
if ( $objects ) {
|
||||
$limit = 3;
|
||||
$total = count( $objects );
|
||||
|
||||
// Icon.
|
||||
$html .= '<span class="dashicons ' . $objects[0]->icon . ( $total > 1 ? ' acf-multi-dashicon' : '' ) . '"></span>';
|
||||
|
||||
// Labels.
|
||||
$labels = array_column( $objects, 'label' );
|
||||
$labels = array_slice( $labels, 0, 3 );
|
||||
$html .= implode( ', ', $labels );
|
||||
|
||||
// More.
|
||||
if ( $total > $limit ) {
|
||||
$html .= ', ...';
|
||||
}
|
||||
} else {
|
||||
$html = '<span class="dashicons dashicons-businesswoman"></span> ' . __( 'Various', 'acf' );
|
||||
}
|
||||
|
||||
// Filter.
|
||||
echo acf_esc_html( $html );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the number of fields created for the field group in the list table.
|
||||
*
|
||||
* @since 6.1.5
|
||||
*
|
||||
* @param array $field_group The main field group array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_num_fields( $field_group ) {
|
||||
$field_count = acf_get_field_count( $field_group );
|
||||
|
||||
if ( ! $field_count || ! is_numeric( $field_count ) ) {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No fields', 'acf' ) . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
// If in JSON but not synced or in trash, the link won't work.
|
||||
if ( empty( $field_group['ID'] ) || 'trash' === get_post_status( $field_group['ID'] ) ) {
|
||||
echo esc_html( number_format_i18n( $field_count ) );
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( admin_url( 'post.php?action=edit&post=' . $field_group['ID'] ) ),
|
||||
esc_html( number_format_i18n( $field_count ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when trashing a field group.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function trashed_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_trash_field_group( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when untrashing a field group.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function untrashed_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_untrash_field_group( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires when deleting a field group.
|
||||
*
|
||||
* @date 8/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @return void
|
||||
*/
|
||||
public function deleted_post( $post_id ) {
|
||||
if ( get_post_type( $post_id ) === $this->post_type ) {
|
||||
acf_delete_field_group( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @param int $count The number of items the action was performed on.
|
||||
* @return string
|
||||
*/
|
||||
public function get_action_notice_text( $action, $count = 1 ) {
|
||||
$text = '';
|
||||
$count = (int) $count;
|
||||
|
||||
switch ( $action ) {
|
||||
case 'acfactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of field groups activated */
|
||||
_n( 'Field group activated.', '%s field groups activated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfdeactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of field groups deactivated */
|
||||
_n( 'Field group deactivated.', '%s field groups deactivated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfduplicatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of field groups duplicated */
|
||||
_n( 'Field group duplicated.', '%s field groups duplicated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfsynccomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of field groups synchronized */
|
||||
_n( 'Field group synchronized.', '%s field groups synchronized.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
acf_new_instance( 'ACF_Admin_Field_Groups' );
|
||||
|
||||
endif; // Class exists check.
|
@ -0,0 +1,369 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Admin Post Type Class
|
||||
*
|
||||
* @class ACF_Admin_Post_Type
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Post_Type' ) ) :
|
||||
|
||||
/**
|
||||
* ACF Admin Post Type Class
|
||||
*
|
||||
* All the logic for editing a post type.
|
||||
*/
|
||||
class ACF_Admin_Post_type extends ACF_Admin_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-post-type';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-single-post-type';
|
||||
|
||||
/**
|
||||
* This function will customize the message shown when editing a post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $messages Post type messages.
|
||||
* @return array
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages['acf-post-type'] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => $this->post_type_created_message(), // Updated.
|
||||
2 => $this->post_type_created_message(),
|
||||
3 => __( 'Post type deleted.', 'acf' ),
|
||||
4 => __( 'Post type updated.', 'acf' ),
|
||||
5 => false, // Post type does not support revisions.
|
||||
6 => $this->post_type_created_message( true ), // Created.
|
||||
7 => __( 'Post type saved.', 'acf' ),
|
||||
8 => __( 'Post type submitted.', 'acf' ),
|
||||
9 => __( 'Post type scheduled for.', 'acf' ),
|
||||
10 => __( 'Post type draft updated.', 'acf' ),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the post type created message.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param bool $created True if the post was just created.
|
||||
* @return string
|
||||
*/
|
||||
public function post_type_created_message( $created = false ) {
|
||||
global $post_id;
|
||||
|
||||
$title = get_the_title( $post_id );
|
||||
|
||||
/* translators: %s post type name */
|
||||
$item_saved_text = sprintf( __( '%s post type updated', 'acf' ), $title );
|
||||
/* translators: %s post type name */
|
||||
$add_fields_text = sprintf( __( 'Add fields to %s', 'acf' ), $title );
|
||||
|
||||
if ( $created ) {
|
||||
/* translators: %s post type name */
|
||||
$item_saved_text = sprintf( __( '%s post type created', 'acf' ), $title );
|
||||
}
|
||||
|
||||
$add_fields_link = wp_nonce_url(
|
||||
admin_url( 'post-new.php?post_type=acf-field-group&use_post_type=' . $post_id ),
|
||||
'add-fields-' . $post_id
|
||||
);
|
||||
|
||||
$create_post_type_link = admin_url( 'post-new.php?post_type=acf-post-type' );
|
||||
|
||||
$create_taxonomy_link = wp_nonce_url(
|
||||
admin_url( 'post-new.php?post_type=acf-taxonomy&use_post_type=' . $post_id ),
|
||||
'create-taxonomy-' . $post_id
|
||||
);
|
||||
|
||||
ob_start(); ?>
|
||||
<p class="acf-item-saved-text"><?php echo esc_html( $item_saved_text ); ?></p>
|
||||
<div class="acf-item-saved-links">
|
||||
<a href="<?php echo esc_url( $add_fields_link ); ?>"><?php echo esc_html( $add_fields_text ); ?></a>
|
||||
<a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link existing field groups', 'acf' ); ?></a>
|
||||
<a href="<?php echo esc_url( $create_post_type_link ); ?>"><?php esc_html_e( 'Create new post type', 'acf' ); ?></a>
|
||||
<a href="<?php echo esc_url( $create_taxonomy_link ); ?>"><?php esc_html_e( 'Create new taxonomy', 'acf' ); ?></a>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any scripts necessary for internal post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
|
||||
wp_enqueue_style( 'acf-field-group' );
|
||||
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Post' => __( 'Post', 'acf' ),
|
||||
'Posts' => __( 'Posts', 'acf' ),
|
||||
'Page' => __( 'Page', 'acf' ),
|
||||
'Pages' => __( 'Pages', 'acf' ),
|
||||
'Default' => __( 'Default', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
parent::admin_enqueue_scripts();
|
||||
|
||||
do_action( 'acf/post_type/admin_enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up all functionality for the post type edit page to work.
|
||||
*
|
||||
* @since 3.1.8
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_head() {
|
||||
|
||||
// global.
|
||||
global $post, $acf_post_type;
|
||||
|
||||
// set global var.
|
||||
$acf_post_type = acf_get_internal_post_type( $post->ID, $this->post_type );
|
||||
|
||||
if ( ! empty( $acf_post_type['not_registered'] ) ) {
|
||||
acf_add_admin_notice(
|
||||
__( 'This post type could not be registered because its key is in use by another post type registered by another plugin or theme.', 'acf' ),
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
// metaboxes.
|
||||
add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'acf' ), array( $this, 'mb_basic_settings' ), 'acf-post-type', 'normal', 'high' );
|
||||
add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'acf' ), array( $this, 'mb_advanced_settings' ), 'acf-post-type', 'normal', 'high' );
|
||||
|
||||
// actions.
|
||||
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
|
||||
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
|
||||
|
||||
// filters.
|
||||
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_screen_layout_acf-post-type', array( $this, 'screen_layout' ), 10, 1 );
|
||||
add_filter( 'get_user_option_metaboxhidden_acf-post-type', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-post-type', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-post-type', array( $this, 'force_advanced_settings' ), 10, 1 );
|
||||
|
||||
// 3rd party hook.
|
||||
do_action( 'acf/post_type/admin_head' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This action will allow ACF to render metaboxes after the title.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit_form_after_title() {
|
||||
|
||||
// globals.
|
||||
global $post;
|
||||
|
||||
// render post data.
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'post_type',
|
||||
'post_id' => $post->ID,
|
||||
'delete_fields' => 0,
|
||||
'validation' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will add extra HTML to the acf form data element
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $args Arguments array to pass through to action.
|
||||
* @return void
|
||||
*/
|
||||
public function form_data( $args ) {
|
||||
do_action( 'acf/post_type/form_data', $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will append extra l10n strings to the acf JS object
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $l10n The array of translated strings.
|
||||
* @return array $l10n
|
||||
*/
|
||||
public function admin_l10n( $l10n ) {
|
||||
return apply_filters( 'acf/post_type/admin_l10n', $l10n );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin footer third party hook support
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer() {
|
||||
do_action( 'acf/post_type/admin_footer' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen settings html output
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param string $html Current screen settings HTML.
|
||||
* @return string $html
|
||||
*/
|
||||
public function screen_settings( $html ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "Edit Post Type" screen to use a one-column layout.
|
||||
*
|
||||
* @param int $columns Number of columns for layout.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function screen_layout( $columns = 0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force basic settings to always be visible
|
||||
*
|
||||
* @param array $hidden_metaboxes The metaboxes hidden on this page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function force_basic_settings( $hidden_metaboxes ) {
|
||||
if ( ! is_array( $hidden_metaboxes ) ) {
|
||||
return $hidden_metaboxes;
|
||||
}
|
||||
return array_diff( $hidden_metaboxes, array( 'acf-basic-settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Force advanced settings to be visible
|
||||
*
|
||||
* @param array $hidden_metaboxes The metaboxes hidden on this page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function force_advanced_settings( $hidden_metaboxes ) {
|
||||
if ( ! is_array( $hidden_metaboxes ) ) {
|
||||
return $hidden_metaboxes;
|
||||
}
|
||||
return array_diff( $hidden_metaboxes, array( 'acf-advanced-settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will customize the publish metabox
|
||||
*
|
||||
* @since 5.2.9
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function post_submitbox_misc_actions() {
|
||||
global $acf_post_type;
|
||||
$status_label = $acf_post_type['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves post type data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @param WP_Post $post The post object.
|
||||
*
|
||||
* @return int $post_id
|
||||
*/
|
||||
public function save_post( $post_id, $post ) {
|
||||
if ( ! $this->verify_save_post( $post_id, $post ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Disable filters to ensure ACF loads raw data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated in $this->verify_save_post() above.
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
|
||||
$_POST['acf_post_type']['ID'] = $post_id;
|
||||
$_POST['acf_post_type']['title'] = isset( $_POST['acf_post_type']['labels']['name'] ) ? $_POST['acf_post_type']['labels']['name'] : '';
|
||||
|
||||
// Save the post type.
|
||||
acf_update_internal_post_type( $_POST['acf_post_type'], $this->post_type ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Validated in verify_save_post
|
||||
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders HTML for the basic settings metabox.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_basic_settings() {
|
||||
global $acf_post_type;
|
||||
|
||||
if ( ! acf_is_internal_post_type_key( $acf_post_type['key'], 'acf-post-type' ) ) {
|
||||
$acf_post_type['key'] = uniqid( 'post_type_' );
|
||||
}
|
||||
|
||||
acf_get_view( $this->post_type . '/basic-settings' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the HTML for the advanced settings metabox.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_advanced_settings() {
|
||||
acf_get_view( $this->post_type . '/advanced-settings' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new ACF_Admin_Post_Type();
|
||||
|
||||
endif; // Class exists check.
|
||||
|
||||
?>
|
@ -0,0 +1,346 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Post_Types' ) ) :
|
||||
|
||||
/**
|
||||
* The ACF Post Types admin controller class
|
||||
*/
|
||||
#[AllowDynamicProperties]
|
||||
class ACF_Admin_Post_Types extends ACF_Admin_Internal_Post_Type_List {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-post-type';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-post-types';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = 'post-types';
|
||||
|
||||
/**
|
||||
* Current screen actions for the post types list admin page.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function current_screen() {
|
||||
// Bail early if not post types admin page.
|
||||
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::current_screen();
|
||||
|
||||
// Run a first-run routine to set some defaults which are stored in user preferences.
|
||||
if ( ! acf_get_user_setting( 'post-type-first-run', false ) ) {
|
||||
$option_key = 'manageedit-' . $this->post_type . 'columnshidden';
|
||||
$hidden_items = get_user_option( $option_key );
|
||||
|
||||
if ( ! is_array( $hidden_items ) ) {
|
||||
$hidden_items = array();
|
||||
}
|
||||
|
||||
if ( ! in_array( 'acf-key', $hidden_items ) ) {
|
||||
$hidden_items[] = 'acf-key';
|
||||
}
|
||||
update_user_option( get_current_user_id(), $option_key, $hidden_items, true );
|
||||
|
||||
acf_update_user_setting( 'post-type-first-run', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any menu items required for post types.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function admin_menu() {
|
||||
$parent_slug = 'edit.php?post_type=acf-field-group';
|
||||
$cap = acf_get_setting( 'capability' );
|
||||
add_submenu_page( $parent_slug, __( 'Post Types', 'acf' ), __( 'Post Types', 'acf' ), $cap, 'edit.php?post_type=acf-post-type' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table columns.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $_columns The columns array.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_columns( $_columns ) {
|
||||
// Set the "no found" label to be our custom HTML for no results.
|
||||
if ( empty( acf_request_arg( 's' ) ) ) {
|
||||
global $wp_post_types;
|
||||
$this->not_found_label = $wp_post_types[ $this->post_type ]->labels->not_found;
|
||||
$wp_post_types[ $this->post_type ]->labels->not_found = $this->get_not_found_html();
|
||||
}
|
||||
|
||||
$columns = array(
|
||||
'cb' => $_columns['cb'],
|
||||
'title' => $_columns['title'],
|
||||
'acf-description' => __( 'Description', 'acf' ),
|
||||
'acf-key' => __( 'Key', 'acf' ),
|
||||
'acf-taxonomies' => __( 'Taxonomies', 'acf' ),
|
||||
'acf-field-groups' => __( 'Field Groups', 'acf' ),
|
||||
'acf-count' => __( 'Posts', 'acf' ),
|
||||
);
|
||||
|
||||
if ( acf_get_local_json_files( $this->post_type ) ) {
|
||||
$columns['acf-json'] = __( 'Local JSON', 'acf' );
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a specific admin table column.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $column_name The name of the column to display.
|
||||
* @param array $post The main ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column( $column_name, $post ) {
|
||||
switch ( $column_name ) {
|
||||
case 'acf-key':
|
||||
echo '<i class="acf-icon acf-icon-key-solid"></i>';
|
||||
echo esc_html( $post['key'] );
|
||||
break;
|
||||
|
||||
// Description.
|
||||
case 'acf-description':
|
||||
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
|
||||
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
|
||||
} else {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'acf-taxonomies':
|
||||
$this->render_admin_table_column_taxonomies( $post );
|
||||
break;
|
||||
|
||||
case 'acf-field-groups':
|
||||
$this->render_admin_table_column_field_groups( $post );
|
||||
break;
|
||||
|
||||
case 'acf-count':
|
||||
$this->render_admin_table_column_num_posts( $post );
|
||||
break;
|
||||
|
||||
// Local JSON.
|
||||
case 'acf-json':
|
||||
$this->render_admin_table_column_local_status( $post );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field groups attached to the post type in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The main post type array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_field_groups( $post_type ) {
|
||||
$field_groups = acf_get_field_groups( array( 'post_type' => $post_type['post_type'] ) );
|
||||
|
||||
if ( empty( $field_groups ) ) {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No field groups', 'acf' ) . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
$labels = wp_list_pluck( $field_groups, 'title' );
|
||||
$limit = 3;
|
||||
$shown_labels = array_slice( $labels, 0, $limit );
|
||||
$hidden_labels = array_slice( $labels, $limit );
|
||||
$text = implode( ', ', $shown_labels );
|
||||
|
||||
if ( ! empty( $hidden_labels ) ) {
|
||||
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
|
||||
}
|
||||
|
||||
echo acf_esc_html( $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the taxonomies attached to the post type in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The main post type array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_taxonomies( $post_type ) {
|
||||
$taxonomies = array();
|
||||
$labels = array();
|
||||
|
||||
if ( is_array( $post_type['taxonomies'] ) ) {
|
||||
$taxonomies = $post_type['taxonomies'];
|
||||
}
|
||||
|
||||
$acf_taxonomies = acf_get_internal_post_type_posts( 'acf-taxonomy' );
|
||||
|
||||
foreach ( $acf_taxonomies as $acf_taxonomy ) {
|
||||
if ( is_array( $acf_taxonomy['object_type'] ) && in_array( $post_type['post_type'], $acf_taxonomy['object_type'], true ) ) {
|
||||
$taxonomies[] = $acf_taxonomy['taxonomy'];
|
||||
}
|
||||
}
|
||||
|
||||
$taxonomies = array_unique( $taxonomies );
|
||||
|
||||
foreach ( $taxonomies as $tax_slug ) {
|
||||
$taxonomy = get_taxonomy( $tax_slug );
|
||||
|
||||
if ( ! is_object( $taxonomy ) || empty( $taxonomy->label ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$labels[] = $taxonomy->label;
|
||||
}
|
||||
|
||||
if ( empty( $labels ) ) {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No taxonomies', 'acf' ) . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
$limit = 3;
|
||||
$shown_labels = array_slice( $labels, 0, $limit );
|
||||
$hidden_labels = array_slice( $labels, $limit );
|
||||
$text = implode( ', ', $shown_labels );
|
||||
|
||||
if ( ! empty( $hidden_labels ) ) {
|
||||
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
|
||||
}
|
||||
|
||||
echo acf_esc_html( $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the number of posts created for the post type in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post_type The main post type array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_num_posts( $post_type ) {
|
||||
$no_posts = '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
$no_posts .= '<span class="screen-reader-text">' . esc_html__( 'No posts', 'acf' ) . '</span>';
|
||||
|
||||
// WP doesn't count posts for post types that don't exist.
|
||||
if ( empty( $post_type['active'] ) || 'trash' === get_post_status( $post_type['ID'] ) ) {
|
||||
echo acf_esc_html( $no_posts );
|
||||
return;
|
||||
}
|
||||
|
||||
$num_posts = wp_count_posts( $post_type['post_type'] );
|
||||
if ( is_object( $num_posts ) && property_exists( $num_posts, 'publish' ) ) {
|
||||
$num_posts = $num_posts->publish;
|
||||
}
|
||||
|
||||
if ( ! $num_posts || ! is_numeric( $num_posts ) ) {
|
||||
echo acf_esc_html( $no_posts );
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( admin_url( 'edit.php?post_type=' . $post_type['post_type'] ) ),
|
||||
esc_html( number_format_i18n( $num_posts ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @param int $count The number of items the action was performed on.
|
||||
* @return string
|
||||
*/
|
||||
public function get_action_notice_text( $action, $count = 1 ) {
|
||||
$text = '';
|
||||
$count = (int) $count;
|
||||
|
||||
switch ( $action ) {
|
||||
case 'acfactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types activated */
|
||||
_n( 'Post type activated.', '%s post types activated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfdeactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types deactivated */
|
||||
_n( 'Post type deactivated.', '%s post types deactivated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfduplicatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types duplicated */
|
||||
_n( 'Post type duplicated.', '%s post types duplicated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfsynccomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of post types synchronized */
|
||||
_n( 'Post type synchronized.', '%s post types synchronized.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registration error state.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_registration_error_state() {
|
||||
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
|
||||
__( 'This post type could not be registered because its key is in use by another post type registered by another plugin or theme.', 'acf' ) .
|
||||
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
acf_new_instance( 'ACF_Admin_Post_Types' );
|
||||
|
||||
endif; // Class exists check.
|
@ -0,0 +1,353 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Taxonomies' ) ) :
|
||||
|
||||
/**
|
||||
* The ACF Post Types admin controller class
|
||||
*/
|
||||
#[AllowDynamicProperties]
|
||||
class ACF_Admin_Taxonomies extends ACF_Admin_Internal_Post_Type_List {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-taxonomy';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-taxonomies';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = 'taxonomies';
|
||||
|
||||
/**
|
||||
* Current screen actions for the taxonomies list admin page.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function current_screen() {
|
||||
// Bail early if not post types admin page.
|
||||
if ( ! acf_is_screen( "edit-{$this->post_type}" ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
parent::current_screen();
|
||||
|
||||
// Run a first-run routine to set some defaults which are stored in user preferences.
|
||||
if ( ! acf_get_user_setting( 'taxonomies-first-run', false ) ) {
|
||||
$option_key = 'manageedit-' . $this->post_type . 'columnshidden';
|
||||
$hidden_items = get_user_option( $option_key );
|
||||
|
||||
if ( ! is_array( $hidden_items ) ) {
|
||||
$hidden_items = array();
|
||||
}
|
||||
|
||||
if ( ! in_array( 'acf-key', $hidden_items ) ) {
|
||||
$hidden_items[] = 'acf-key';
|
||||
}
|
||||
update_user_option( get_current_user_id(), $option_key, $hidden_items, true );
|
||||
|
||||
acf_update_user_setting( 'taxonomies-first-run', true );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add any menu items required for taxonomies.
|
||||
*
|
||||
* @since 6.1
|
||||
*/
|
||||
public function admin_menu() {
|
||||
$parent_slug = 'edit.php?post_type=acf-field-group';
|
||||
$cap = acf_get_setting( 'capability' );
|
||||
add_submenu_page( $parent_slug, __( 'Taxonomies', 'acf' ), __( 'Taxonomies', 'acf' ), $cap, 'edit.php?post_type=acf-taxonomy' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Customizes the admin table columns.
|
||||
*
|
||||
* @date 1/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $_columns The columns array.
|
||||
* @return array
|
||||
*/
|
||||
public function admin_table_columns( $_columns ) {
|
||||
// Set the "no found" label to be our custom HTML for no results.
|
||||
if ( empty( acf_request_arg( 's' ) ) ) {
|
||||
global $wp_post_types;
|
||||
$this->not_found_label = $wp_post_types[ $this->post_type ]->labels->not_found;
|
||||
$wp_post_types[ $this->post_type ]->labels->not_found = $this->get_not_found_html();
|
||||
}
|
||||
|
||||
$columns = array(
|
||||
'cb' => $_columns['cb'],
|
||||
'title' => $_columns['title'],
|
||||
'acf-description' => __( 'Description', 'acf' ),
|
||||
'acf-key' => __( 'Key', 'acf' ),
|
||||
'acf-post-types' => __( 'Post Types', 'acf' ),
|
||||
'acf-field-groups' => __( 'Field Groups', 'acf' ),
|
||||
'acf-count' => __( 'Terms', 'acf' ),
|
||||
);
|
||||
|
||||
if ( acf_get_local_json_files( $this->post_type ) ) {
|
||||
$columns['acf-json'] = __( 'Local JSON', 'acf' );
|
||||
}
|
||||
|
||||
return $columns;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a specific admin table column.
|
||||
*
|
||||
* @date 17/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $column_name The name of the column to display.
|
||||
* @param array $post The main ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column( $column_name, $post ) {
|
||||
switch ( $column_name ) {
|
||||
case 'acf-key':
|
||||
echo '<i class="acf-icon acf-icon-key-solid"></i>';
|
||||
echo esc_html( $post['key'] );
|
||||
break;
|
||||
|
||||
// Description.
|
||||
case 'acf-description':
|
||||
if ( is_string( $post['description'] ) && ! empty( $post['description'] ) ) {
|
||||
echo '<span class="acf-description">' . acf_esc_html( $post['description'] ) . '</span>';
|
||||
} else {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No description', 'acf' ) . '</span>';
|
||||
}
|
||||
break;
|
||||
|
||||
case 'acf-field-groups':
|
||||
$this->render_admin_table_column_field_groups( $post );
|
||||
break;
|
||||
|
||||
case 'acf-post-types':
|
||||
$this->render_admin_table_column_post_types( $post );
|
||||
break;
|
||||
|
||||
case 'acf-count':
|
||||
$this->render_admin_table_column_num_terms( $post );
|
||||
break;
|
||||
|
||||
// Local JSON.
|
||||
case 'acf-json':
|
||||
$this->render_admin_table_column_local_status( $post );
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field groups attached to the taxonomy in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The main taxonomy array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_field_groups( $taxonomy ) {
|
||||
$field_groups = acf_get_field_groups( array( 'taxonomy' => $taxonomy['taxonomy'] ) );
|
||||
|
||||
if ( empty( $field_groups ) ) {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No field groups', 'acf' ) . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
$labels = wp_list_pluck( $field_groups, 'title' );
|
||||
$limit = 3;
|
||||
$shown_labels = array_slice( $labels, 0, $limit );
|
||||
$hidden_labels = array_slice( $labels, $limit );
|
||||
$text = implode( ', ', $shown_labels );
|
||||
|
||||
if ( ! empty( $hidden_labels ) ) {
|
||||
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
|
||||
}
|
||||
|
||||
echo acf_esc_html( $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the post types attached to the taxonomy in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The main taxonomy array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_post_types( $taxonomy ) {
|
||||
$post_types = get_post_types( array(), 'objects' );
|
||||
$labels = array();
|
||||
$object_types = array();
|
||||
|
||||
if ( ! empty( $taxonomy['object_type'] ) ) {
|
||||
$object_types = (array) $taxonomy['object_type'];
|
||||
}
|
||||
|
||||
foreach ( $object_types as $post_type_slug ) {
|
||||
if ( ! isset( $post_types[ $post_type_slug ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$post_type = $post_types[ $post_type_slug ];
|
||||
|
||||
if ( empty( $post_type->label ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$labels[] = $post_type->label;
|
||||
}
|
||||
|
||||
$acf_post_types = acf_get_internal_post_type_posts( 'acf-post-type' );
|
||||
|
||||
foreach ( $acf_post_types as $acf_post_type ) {
|
||||
if ( is_array( $acf_post_type['taxonomies'] ) && in_array( $taxonomy['taxonomy'], $acf_post_type['taxonomies'], true ) ) {
|
||||
$labels[] = $acf_post_type['title'];
|
||||
}
|
||||
}
|
||||
|
||||
if ( empty( $labels ) ) {
|
||||
echo '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
echo '<span class="screen-reader-text">' . esc_html__( 'No post types', 'acf' ) . '</span>';
|
||||
return;
|
||||
}
|
||||
|
||||
$labels = array_unique( $labels );
|
||||
$limit = 3;
|
||||
$shown_labels = array_slice( $labels, 0, $limit );
|
||||
$hidden_labels = array_slice( $labels, $limit );
|
||||
$text = implode( ', ', $shown_labels );
|
||||
|
||||
if ( ! empty( $hidden_labels ) ) {
|
||||
$text .= ', <span class="acf-more-items acf-tooltip-js" title="' . implode( ', ', $hidden_labels ) . '">+' . count( $hidden_labels ) . '</span>';
|
||||
}
|
||||
|
||||
echo acf_esc_html( $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the number of terms created for the taxonomy in the list table.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $taxonomy The main taxonomy array.
|
||||
* @return void
|
||||
*/
|
||||
public function render_admin_table_column_num_terms( $taxonomy ) {
|
||||
$no_terms = '<span class="acf-emdash" aria-hidden="true">—</span>';
|
||||
$no_terms .= '<span class="screen-reader-text">' . esc_html__( 'No terms', 'acf' ) . '</span>';
|
||||
|
||||
// WP doesn't count terms for taxonomies that don't exist and instead returns WP_Error.
|
||||
if ( empty( $taxonomy['active'] ) || 'trash' === get_post_status( $taxonomy['ID'] ) ) {
|
||||
echo acf_esc_html( $no_terms );
|
||||
return;
|
||||
}
|
||||
|
||||
$num_terms = wp_count_terms(
|
||||
$taxonomy['taxonomy'],
|
||||
array(
|
||||
'hide_empty' => false,
|
||||
'parent' => 0,
|
||||
)
|
||||
);
|
||||
|
||||
if ( ! $num_terms || ! is_numeric( $num_terms ) ) {
|
||||
echo acf_esc_html( $no_terms );
|
||||
return;
|
||||
}
|
||||
|
||||
printf(
|
||||
'<a href="%s">%s</a>',
|
||||
esc_url( admin_url( 'edit-tags.php?taxonomy=' . $taxonomy['taxonomy'] ) ),
|
||||
esc_html( number_format_i18n( $num_terms ) )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the translated action notice text for list table actions (activate, deactivate, sync, etc.).
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $action The action being performed.
|
||||
* @param int $count The number of items the action was performed on.
|
||||
* @return string
|
||||
*/
|
||||
public function get_action_notice_text( $action, $count = 1 ) {
|
||||
$text = '';
|
||||
$count = (int) $count;
|
||||
|
||||
switch ( $action ) {
|
||||
case 'acfactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of taxonomies activated */
|
||||
_n( 'Taxonomy activated.', '%s taxonomies activated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfdeactivatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of taxonomies deactivated */
|
||||
_n( 'Taxonomy deactivated.', '%s taxonomies deactivated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfduplicatecomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of taxonomies duplicated */
|
||||
_n( 'Taxonomy duplicated.', '%s taxonomies duplicated.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
case 'acfsynccomplete':
|
||||
$text = sprintf(
|
||||
/* translators: %s number of taxonomies synchronized */
|
||||
_n( 'Taxonomy synchronized.', '%s taxonomies synchronized.', $count, 'acf' ),
|
||||
$count
|
||||
);
|
||||
break;
|
||||
}
|
||||
|
||||
return $text;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the registration error state.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_registration_error_state() {
|
||||
return '<span class="acf-js-tooltip dashicons dashicons-warning" title="' .
|
||||
__( 'This taxonomy could not be registered because its key is in use by another taxonomy registered by another plugin or theme.', 'acf' ) .
|
||||
'"></span> ' . _x( 'Registration Failed', 'post status', 'acf' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Instantiate.
|
||||
acf_new_instance( 'ACF_Admin_Taxonomies' );
|
||||
|
||||
endif; // Class exists check.
|
@ -0,0 +1,368 @@
|
||||
<?php
|
||||
/**
|
||||
* ACF Admin Taxonomy Class
|
||||
*
|
||||
* @class ACF_Admin_Taxonomiy
|
||||
*
|
||||
* @package ACF
|
||||
* @subpackage Admin
|
||||
*/
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Taxonomy' ) ) :
|
||||
|
||||
/**
|
||||
* ACF Admin Field Group Class
|
||||
*
|
||||
* All the logic for editing a taxonomy.
|
||||
*/
|
||||
class ACF_Admin_Taxonomy extends ACF_Admin_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The slug for the internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = 'acf-taxonomy';
|
||||
|
||||
/**
|
||||
* The admin body class used for the post type.
|
||||
*
|
||||
* @since 6.1
|
||||
* @var string
|
||||
*/
|
||||
public $admin_body_class = 'acf-admin-single-taxonomy';
|
||||
|
||||
/**
|
||||
* This function will customize the message shown when editing a field group
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $messages Post type messages.
|
||||
* @return array
|
||||
*/
|
||||
public function post_updated_messages( $messages ) {
|
||||
$messages['acf-taxonomy'] = array(
|
||||
0 => '', // Unused. Messages start at index 1.
|
||||
1 => $this->taxonomy_saved_message(),
|
||||
2 => __( 'Taxonomy updated.', 'acf' ),
|
||||
3 => __( 'Taxonomy deleted.', 'acf' ),
|
||||
4 => $this->taxonomy_saved_message(),
|
||||
5 => false, // taxonomy does not support revisions.
|
||||
6 => $this->taxonomy_saved_message( true ),
|
||||
7 => __( 'Taxonomy saved.', 'acf' ),
|
||||
8 => __( 'Taxonomy submitted.', 'acf' ),
|
||||
9 => __( 'Taxonomy scheduled for.', 'acf' ),
|
||||
10 => __( 'Taxonomy draft updated.', 'acf' ),
|
||||
);
|
||||
|
||||
return $messages;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the post type created message.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param bool $created True if the post was just created.
|
||||
* @return string
|
||||
*/
|
||||
public function taxonomy_saved_message( $created = false ) {
|
||||
global $post_id;
|
||||
|
||||
$title = get_the_title( $post_id );
|
||||
|
||||
/* translators: %s taxonomy name */
|
||||
$item_saved_text = sprintf( __( '%s taxonomy updated', 'acf' ), $title );
|
||||
/* translators: %s taxonomy name */
|
||||
$add_fields_text = sprintf( __( 'Add fields to %s', 'acf' ), $title );
|
||||
|
||||
if ( $created ) {
|
||||
/* translators: %s taxonomy name */
|
||||
$item_saved_text = sprintf( __( '%s taxonomy created', 'acf' ), $title );
|
||||
}
|
||||
|
||||
$add_fields_link = wp_nonce_url(
|
||||
admin_url( 'post-new.php?post_type=acf-field-group&use_taxonomy=' . $post_id ),
|
||||
'add-fields-' . $post_id
|
||||
);
|
||||
|
||||
$create_taxonomy_link = admin_url( 'post-new.php?post_type=acf-taxonomy' );
|
||||
|
||||
$create_post_type_link = wp_nonce_url(
|
||||
admin_url( 'post-new.php?post_type=acf-post-type&use_taxonomy=' . $post_id ),
|
||||
'create-post-type-' . $post_id
|
||||
);
|
||||
|
||||
ob_start(); ?>
|
||||
<p class="acf-item-saved-text"><?php echo esc_html( $item_saved_text ); ?></p>
|
||||
<div class="acf-item-saved-links">
|
||||
<a href="<?php echo esc_url( $add_fields_link ); ?>"><?php echo esc_html( $add_fields_text ); ?></a>
|
||||
<a class="acf-link-field-groups" href="#"><?php esc_html_e( 'Link existing field groups', 'acf' ); ?></a>
|
||||
<a href="<?php echo esc_url( $create_taxonomy_link ); ?>"><?php esc_html_e( 'Create new taxonomy', 'acf' ); ?></a>
|
||||
<a href="<?php echo esc_url( $create_post_type_link ); ?>"><?php esc_html_e( 'Create new post type', 'acf' ); ?></a>
|
||||
</div>
|
||||
<?php
|
||||
return ob_get_clean();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues any scripts necessary for internal post type.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_enqueue_scripts() {
|
||||
|
||||
wp_enqueue_style( 'acf-field-group' );
|
||||
|
||||
acf_localize_text(
|
||||
array(
|
||||
'Tag' => __( 'Tag', 'acf' ),
|
||||
'Tags' => __( 'Tags', 'acf' ),
|
||||
'Category' => __( 'Category', 'acf' ),
|
||||
'Categories' => __( 'Categories', 'acf' ),
|
||||
'Default' => __( 'Default', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
parent::admin_enqueue_scripts();
|
||||
|
||||
do_action( 'acf/taxonomy/admin_enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets up all functionality for the taxonomy edit page to work.
|
||||
*
|
||||
* @since 3.1.8
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_head() {
|
||||
|
||||
// global.
|
||||
global $post, $acf_taxonomy;
|
||||
|
||||
// set global var.
|
||||
$acf_taxonomy = acf_get_internal_post_type( $post->ID, $this->post_type );
|
||||
|
||||
if ( ! empty( $acf_taxonomy['not_registered'] ) ) {
|
||||
acf_add_admin_notice(
|
||||
__( 'This taxonomy could not be registered because its key is in use by another taxonomy registered by another plugin or theme.', 'acf' ),
|
||||
'error'
|
||||
);
|
||||
}
|
||||
|
||||
// metaboxes.
|
||||
add_meta_box( 'acf-basic-settings', __( 'Basic Settings', 'acf' ), array( $this, 'mb_basic_settings' ), 'acf-taxonomy', 'normal', 'high' );
|
||||
add_meta_box( 'acf-advanced-settings', __( 'Advanced Settings', 'acf' ), array( $this, 'mb_advanced_settings' ), 'acf-taxonomy', 'normal', 'high' );
|
||||
|
||||
// actions.
|
||||
add_action( 'post_submitbox_misc_actions', array( $this, 'post_submitbox_misc_actions' ), 10, 0 );
|
||||
add_action( 'edit_form_after_title', array( $this, 'edit_form_after_title' ), 10, 0 );
|
||||
|
||||
// filters.
|
||||
add_filter( 'screen_settings', array( $this, 'screen_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_screen_layout_acf-taxonomy', array( $this, 'screen_layout' ), 10, 1 );
|
||||
add_filter( 'get_user_option_metaboxhidden_acf-taxonomy', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-taxonomy', array( $this, 'force_basic_settings' ), 10, 1 );
|
||||
add_filter( 'get_user_option_closedpostboxes_acf-taxonomy', array( $this, 'force_advanced_settings' ), 10, 1 );
|
||||
|
||||
// 3rd party hook.
|
||||
do_action( 'acf/taxonomy/admin_head' );
|
||||
}
|
||||
|
||||
/**
|
||||
* This action will allow ACF to render metaboxes after the title.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function edit_form_after_title() {
|
||||
|
||||
// globals.
|
||||
global $post;
|
||||
|
||||
// render post data.
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'taxonomy',
|
||||
'post_id' => $post->ID,
|
||||
'delete_fields' => 0,
|
||||
'validation' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will add extra HTML to the acf form data element
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $args Arguments array to pass through to action.
|
||||
* @return void
|
||||
*/
|
||||
public function form_data( $args ) {
|
||||
do_action( 'acf/taxonomy/form_data', $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will append extra l10n strings to the acf JS object
|
||||
*
|
||||
* @since 5.3.8
|
||||
*
|
||||
* @param array $l10n The array of translated strings.
|
||||
* @return array $l10n
|
||||
*/
|
||||
public function admin_l10n( $l10n ) {
|
||||
return apply_filters( 'acf/taxonomy/admin_l10n', $l10n );
|
||||
}
|
||||
|
||||
/**
|
||||
* Admin footer third party hook support
|
||||
*
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function admin_footer() {
|
||||
do_action( 'acf/taxonomy/admin_footer' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Screen settings html output
|
||||
*
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param string $html Current screen settings HTML.
|
||||
* @return string $html
|
||||
*/
|
||||
public function screen_settings( $html ) {
|
||||
return $html;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the "Edit Field Group" screen to use a one-column layout.
|
||||
*
|
||||
* @param int $columns Number of columns for layout.
|
||||
*
|
||||
* @return int
|
||||
*/
|
||||
public function screen_layout( $columns = 0 ) {
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Force basic settings to always be visible
|
||||
*
|
||||
* @param array $hidden_metaboxes The metaboxes hidden on this page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function force_basic_settings( $hidden_metaboxes ) {
|
||||
if ( ! is_array( $hidden_metaboxes ) ) {
|
||||
return $hidden_metaboxes;
|
||||
}
|
||||
return array_diff( $hidden_metaboxes, array( 'acf-basic-settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Force advanced settings to be visible
|
||||
*
|
||||
* @param array $hidden_metaboxes The metaboxes hidden on this page.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function force_advanced_settings( $hidden_metaboxes ) {
|
||||
if ( ! is_array( $hidden_metaboxes ) ) {
|
||||
return $hidden_metaboxes;
|
||||
}
|
||||
return array_diff( $hidden_metaboxes, array( 'acf-advanced-settings' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* This function will customize the publish metabox
|
||||
*
|
||||
* @since 5.2.9
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function post_submitbox_misc_actions() {
|
||||
global $acf_taxonomy;
|
||||
$status_label = $acf_taxonomy['active'] ? _x( 'Active', 'post status', 'acf' ) : _x( 'Inactive', 'post status', 'acf' );
|
||||
|
||||
?>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
$('#post-status-display').html( '<?php echo esc_html( $status_label ); ?>' );
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves taxonomy data.
|
||||
*
|
||||
* @since 1.0.0
|
||||
*
|
||||
* @param int $post_id The post ID.
|
||||
* @param WP_Post $post The post object.
|
||||
*
|
||||
* @return int $post_id
|
||||
*/
|
||||
public function save_post( $post_id, $post ) {
|
||||
if ( ! $this->verify_save_post( $post_id, $post ) ) {
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
// Disable filters to ensure ACF loads raw data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// phpcs:disable WordPress.Security.NonceVerification.Missing -- Validated in $this->verify_save_post() above.
|
||||
// phpcs:disable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- Sanitized when saved.
|
||||
$_POST['acf_taxonomy']['ID'] = $post_id;
|
||||
$_POST['acf_taxonomy']['title'] = isset( $_POST['acf_taxonomy']['labels']['name'] ) ? $_POST['acf_taxonomy']['labels']['name'] : '';
|
||||
|
||||
// Save the taxonomy.
|
||||
acf_update_internal_post_type( $_POST['acf_taxonomy'], $this->post_type ); // phpcs:ignore WordPress.Security.NonceVerification.Missing -- Validated in verify_save_post
|
||||
// phpcs:enable WordPress.Security.ValidatedSanitizedInput.InputNotSanitized
|
||||
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
|
||||
return $post_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders HTML for the 'acf-taxonomy-fields' metabox.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_basic_settings() {
|
||||
global $acf_taxonomy;
|
||||
|
||||
if ( ! acf_is_internal_post_type_key( $acf_taxonomy['key'], 'acf-taxonomy' ) ) {
|
||||
$acf_taxonomy['key'] = uniqid( 'taxonomy_' );
|
||||
}
|
||||
|
||||
acf_get_view( $this->post_type . '/basic-settings' );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the HTML for the 'acf-taxonomy-options' metabox.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function mb_advanced_settings() {
|
||||
acf_get_view( $this->post_type . '/advanced-settings' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
new ACF_Admin_Taxonomy();
|
||||
endif; // Class exists check.
|
||||
|
||||
?>
|
@ -0,0 +1,566 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Tool_Export' ) ) :
|
||||
|
||||
class ACF_Admin_Tool_Export extends ACF_Admin_Tool {
|
||||
|
||||
/** @var string View context */
|
||||
var $view = '';
|
||||
|
||||
|
||||
/** @var array Export data */
|
||||
var $json = '';
|
||||
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* This function will initialize the admin tool
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'export';
|
||||
$this->title = __( 'Export Field Groups', 'acf' );
|
||||
|
||||
// active
|
||||
if ( $this->is_active() ) {
|
||||
$this->title .= ' - ' . __( 'Generate PHP', 'acf' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* submit
|
||||
*
|
||||
* This function will run when the tool's form has been submit
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function submit() {
|
||||
|
||||
// vars
|
||||
$action = acf_maybe_get_POST( 'action' );
|
||||
|
||||
// download
|
||||
if ( $action === 'download' ) {
|
||||
|
||||
$this->submit_download();
|
||||
|
||||
// generate
|
||||
} elseif ( $action === 'generate' ) {
|
||||
|
||||
$this->submit_generate();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* submit_download
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 17/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function submit_download() {
|
||||
|
||||
// vars
|
||||
$json = $this->get_selected();
|
||||
|
||||
// validate
|
||||
if ( $json === false ) {
|
||||
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
// headers
|
||||
$file_name = 'acf-export-' . date( 'Y-m-d' ) . '.json';
|
||||
header( 'Content-Description: File Transfer' );
|
||||
header( "Content-Disposition: attachment; filename={$file_name}" );
|
||||
header( 'Content-Type: application/json; charset=utf-8' );
|
||||
|
||||
// return
|
||||
echo acf_json_encode( $json );
|
||||
die;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* submit_generate
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 17/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function submit_generate() {
|
||||
|
||||
// vars
|
||||
$keys = $this->get_selected_keys();
|
||||
|
||||
// validate
|
||||
if ( ! $keys ) {
|
||||
return acf_add_admin_notice( __( 'No field groups selected', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
// url
|
||||
$url = add_query_arg( 'keys', implode( '+', $keys ), $this->get_url() );
|
||||
|
||||
// redirect
|
||||
wp_redirect( $url );
|
||||
exit;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* load
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 21/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function load() {
|
||||
|
||||
// active
|
||||
if ( $this->is_active() ) {
|
||||
|
||||
// get selected keys
|
||||
$selected = $this->get_selected_keys();
|
||||
|
||||
// add notice
|
||||
if ( $selected ) {
|
||||
$count = count( $selected );
|
||||
$text = sprintf( _n( 'Exported 1 item.', 'Exported %s items.', $count, 'acf' ), $count );
|
||||
acf_add_admin_notice( $text, 'success' );
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* html
|
||||
*
|
||||
* This function will output the metabox HTML
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html() {
|
||||
|
||||
// single (generate PHP)
|
||||
if ( $this->is_active() ) {
|
||||
|
||||
$this->html_single();
|
||||
|
||||
// archive
|
||||
} else {
|
||||
|
||||
$this->html_archive();
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Renders the checkboxes to select items to export.
|
||||
*
|
||||
* @date 24/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function html_field_selection() {
|
||||
// Ensure `l10n_var_export` is always false at the point we're outputting the options.
|
||||
acf_update_setting( 'l10n_var_export', false );
|
||||
// Reset the field-groups store which may have been corrupted by export.
|
||||
$store = acf_get_store( 'field-groups' );
|
||||
if ( $store ) {
|
||||
$store->reset();
|
||||
}
|
||||
|
||||
$choices = array();
|
||||
$selected = $this->get_selected_keys();
|
||||
$field_groups = acf_get_internal_post_type_posts( 'acf-field-group' );
|
||||
|
||||
if ( $field_groups ) {
|
||||
foreach ( $field_groups as $field_group ) {
|
||||
$choices[ $field_group['key'] ] = esc_html( $field_group['title'] );
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Select Field Groups', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'keys',
|
||||
'prefix' => false,
|
||||
'value' => $selected,
|
||||
'toggle' => true,
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
|
||||
$choices = array();
|
||||
$selected = $this->get_selected_keys();
|
||||
$post_types = acf_get_internal_post_type_posts( 'acf-post-type' );
|
||||
|
||||
if ( $post_types ) {
|
||||
foreach ( $post_types as $post_type ) {
|
||||
$choices[ $post_type['key'] ] = esc_html( $post_type['title'] );
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Select Post Types', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'post_type_keys',
|
||||
'prefix' => false,
|
||||
'value' => $selected,
|
||||
'toggle' => true,
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
$choices = array();
|
||||
$selected = $this->get_selected_keys();
|
||||
$taxonomies = acf_get_internal_post_type_posts( 'acf-taxonomy' );
|
||||
|
||||
if ( $taxonomies ) {
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
$choices[ $taxonomy['key'] ] = esc_html( $taxonomy['title'] );
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Select Taxonomies', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'taxonomy_keys',
|
||||
'prefix' => false,
|
||||
'value' => $selected,
|
||||
'toggle' => true,
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the side panel for selecting ACF items to export via PHP.
|
||||
*
|
||||
* @date 21/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function html_panel_selection() {
|
||||
?>
|
||||
<div class="acf-panel acf-panel-selection">
|
||||
<?php $this->html_field_selection(); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* html_panel_settings
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 21/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html_panel_settings() {
|
||||
|
||||
?>
|
||||
<div class="acf-panel acf-panel-settings">
|
||||
<h3 class="acf-panel-title"><?php _e( 'Settings', 'acf' ); ?> <i class="dashicons dashicons-arrow-right"></i></h3>
|
||||
<div class="acf-panel-inside">
|
||||
<?php
|
||||
|
||||
/*
|
||||
acf_render_field_wrap(array(
|
||||
'label' => __('Empty settings', 'acf'),
|
||||
'type' => 'select',
|
||||
'name' => 'minimal',
|
||||
'prefix' => false,
|
||||
'value' => '',
|
||||
'choices' => array(
|
||||
'all' => __('Include all settings', 'acf'),
|
||||
'minimal' => __('Ignore empty settings', 'acf'),
|
||||
)
|
||||
));
|
||||
*/
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* html_archive
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 20/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html_archive() {
|
||||
|
||||
?>
|
||||
<div class="acf-postbox-header">
|
||||
<h2 class="acf-postbox-title"><?php esc_html_e( 'Export', 'acf' ); ?></h2>
|
||||
<div class="acf-tip"><i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Select the items you would like to export and then select your export method. Export As JSON to export to a .json file which you can then import to another ACF installation. Generate PHP to export to PHP code which you can place in your theme.', 'acf' ); ?>">?</i></div>
|
||||
</div>
|
||||
<div class="acf-postbox-inner">
|
||||
<div class="acf-fields">
|
||||
<?php $this->html_field_selection(); ?>
|
||||
</div>
|
||||
<p class="acf-submit acf-actions-strip">
|
||||
<button type="submit" name="action" class="acf-btn acf-button-primary" value="download"><?php _e( 'Export As JSON', 'acf' ); ?></button>
|
||||
<button type="submit" name="action" class="acf-btn acf-btn-secondary" value="generate"><?php _e( 'Generate PHP', 'acf' ); ?></button>
|
||||
</p>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the PHP export screen.
|
||||
*
|
||||
* @date 20/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function html_single() {
|
||||
?>
|
||||
<div class="acf-postbox-header">
|
||||
<h2 class="acf-postbox-title"><?php esc_html_e( 'Export - Generate PHP', 'acf' ); ?></h2>
|
||||
<i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( "The following code can be used to register a local version of the selected items. Storing field groups, post types, or taxonomies locally can provide many benefits such as faster load times, version control & dynamic fields/settings. Simply copy and paste the following code to your theme's functions.php file or include it within an external file, then deactivate or delete the items from the ACF admin.", 'acf' ); ?>">?</i>
|
||||
</div>
|
||||
<div class="acf-postbox-columns">
|
||||
<div class="acf-postbox-main">
|
||||
<?php $this->html_generate(); ?>
|
||||
</div>
|
||||
<div class="acf-postbox-side">
|
||||
<?php $this->html_panel_selection(); ?>
|
||||
<p class="acf-submit">
|
||||
<button type="submit" name="action" class="acf-btn" value="generate"><?php esc_html_e( 'Generate PHP', 'acf' ); ?></button>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates the HTML for the PHP export functionality.
|
||||
*
|
||||
* @date 17/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function html_generate() {
|
||||
// Prevent default translation and fake __() within string.
|
||||
acf_update_setting( 'l10n_var_export', true );
|
||||
|
||||
$json = $this->get_selected();
|
||||
$to_export = array();
|
||||
|
||||
// Sort by ACF post type first so we can wrap them in related functions.
|
||||
foreach ( $json as $post ) {
|
||||
$post_type = acf_determine_internal_post_type( $post['key'] );
|
||||
|
||||
if ( $post_type ) {
|
||||
$to_export[ $post_type ][] = $post;
|
||||
}
|
||||
}
|
||||
|
||||
echo '<textarea id="acf-export-textarea" readonly="readonly">';
|
||||
|
||||
foreach ( $to_export as $post_type => $posts ) {
|
||||
if ( 'acf-field-group' === $post_type ) {
|
||||
echo "add_action( 'acf/include_fields', function() {\r\n";
|
||||
echo "\tif ( ! function_exists( 'acf_add_local_field_group' ) ) {\r\n\t\treturn;\r\n\t}\r\n\r\n";
|
||||
} elseif ( 'acf-post-type' === $post_type || 'acf-taxonomy' === $post_type ) {
|
||||
echo "add_action( 'init', function() {\r\n";
|
||||
}
|
||||
|
||||
$count = 0;
|
||||
foreach ( $posts as $post ) {
|
||||
if ( $count !== 0 ) {
|
||||
echo "\r\n";
|
||||
}
|
||||
|
||||
echo "\t" . acf_export_internal_post_type_as_php( $post, $post_type ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- esc_textarea() used earlier.
|
||||
$count++;
|
||||
}
|
||||
|
||||
if ( in_array( $post_type, array( 'acf-post-type', 'acf-taxonomy', 'acf-field-group' ), true ) ) {
|
||||
echo "} );\r\n\r\n";
|
||||
}
|
||||
}
|
||||
|
||||
echo '</textarea>';
|
||||
?>
|
||||
<p class="acf-submit">
|
||||
<a class="button" id="acf-export-copy"><?php _e( 'Copy to clipboard', 'acf' ); ?></a>
|
||||
</p>
|
||||
<script type="text/javascript">
|
||||
(function($){
|
||||
const $a = $('#acf-export-copy');
|
||||
const $textarea = $('#acf-export-textarea');
|
||||
|
||||
// Remove $a if 'copy' is not supported.
|
||||
if( !document.queryCommandSupported('copy') ) {
|
||||
return $a.remove();
|
||||
}
|
||||
|
||||
$a.on('click', function( e ){
|
||||
e.preventDefault();
|
||||
|
||||
$textarea.get(0).select();
|
||||
|
||||
try {
|
||||
var copy = document.execCommand('copy');
|
||||
if ( ! copy ) {
|
||||
return;
|
||||
}
|
||||
|
||||
acf.newTooltip({
|
||||
text: "<?php esc_html_e( 'Copied', 'acf' ); ?>",
|
||||
timeout: 250,
|
||||
target: $(this),
|
||||
});
|
||||
} catch (err) {
|
||||
// Do nothing.
|
||||
}
|
||||
});
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Return an array of keys that have been selected in the export tool.
|
||||
*
|
||||
* @date 20/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function get_selected_keys() {
|
||||
$key_names = array( 'keys', 'post_type_keys', 'taxonomy_keys' );
|
||||
$all_keys = array();
|
||||
|
||||
foreach ( $key_names as $key_name ) {
|
||||
if ( $keys = acf_maybe_get_POST( $key_name ) ) {
|
||||
$all_keys = array_merge( $all_keys, (array) $keys );
|
||||
} elseif ( $keys = acf_maybe_get_GET( $key_name ) ) {
|
||||
$keys = str_replace( ' ', '+', $keys );
|
||||
$keys = explode( '+', $keys );
|
||||
$all_keys = array_merge( $all_keys, (array) $keys );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $all_keys ) ) {
|
||||
return $all_keys;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the JSON data for given $_POST args.
|
||||
*
|
||||
* @date 17/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return array|bool
|
||||
*/
|
||||
public function get_selected() {
|
||||
$selected = $this->get_selected_keys();
|
||||
$json = array();
|
||||
|
||||
if ( ! $selected ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
foreach ( $selected as $key ) {
|
||||
$post_type = acf_determine_internal_post_type( $key );
|
||||
$post = acf_get_internal_post_type( $key, $post_type );
|
||||
|
||||
if ( empty( $post ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( 'acf-field-group' === $post_type ) {
|
||||
$post['fields'] = acf_get_fields( $post );
|
||||
}
|
||||
|
||||
$post = acf_prepare_internal_post_type_for_export( $post, $post_type );
|
||||
$json[] = $post;
|
||||
}
|
||||
|
||||
return $json;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf_register_admin_tool( 'ACF_Admin_Tool_Export' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,302 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Tool_Import' ) ) :
|
||||
|
||||
class ACF_Admin_Tool_Import extends ACF_Admin_Tool {
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* This function will initialize the admin tool
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'import';
|
||||
$this->title = __( 'Import Field Groups', 'acf' );
|
||||
$this->icon = 'dashicons-upload';
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* html
|
||||
*
|
||||
* This function will output the metabox HTML
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html() {
|
||||
|
||||
?>
|
||||
<div class="acf-postbox-header">
|
||||
<h2 class="acf-postbox-title"><?php esc_html_e( 'Import', 'acf' ); ?></h2>
|
||||
<div class="acf-tip"><i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Select the Advanced Custom Fields JSON file you would like to import. When you click the import button below, ACF will import the items in that file.', 'acf' ); ?>">?</i></div>
|
||||
</div>
|
||||
<div class="acf-postbox-inner">
|
||||
<div class="acf-fields">
|
||||
<?php
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Select File', 'acf' ),
|
||||
'type' => 'file',
|
||||
'name' => 'acf_import_file',
|
||||
'value' => false,
|
||||
'uploader' => 'basic',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
</div>
|
||||
<p class="acf-submit">
|
||||
<button type="submit" class="acf-btn" name="import_type" value="json">
|
||||
<?php esc_html_e( 'Import JSON', 'acf' ); ?>
|
||||
</button>
|
||||
</p>
|
||||
|
||||
<?php
|
||||
if ( is_plugin_active( 'custom-post-type-ui/custom-post-type-ui.php' ) && acf_get_setting( 'enable_post_types' ) ) {
|
||||
$cptui_post_types = get_option( 'cptui_post_types' );
|
||||
$cptui_taxonomies = get_option( 'cptui_taxonomies' );
|
||||
$choices = array();
|
||||
$overwrite_warning = false;
|
||||
|
||||
if ( $cptui_post_types ) {
|
||||
$choices['post_types'] = __( 'Post Types', 'acf' );
|
||||
$existing_post_types = acf_get_acf_post_types();
|
||||
|
||||
foreach ( $existing_post_types as $existing_post_type ) {
|
||||
if ( isset( $cptui_post_types[ $existing_post_type['post_type'] ] ) ) {
|
||||
$overwrite_warning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( $cptui_taxonomies ) {
|
||||
$choices['taxonomies'] = __( 'Taxonomies', 'acf' );
|
||||
|
||||
if ( ! $overwrite_warning ) {
|
||||
$existing_taxonomies = acf_get_acf_taxonomies();
|
||||
foreach ( $existing_taxonomies as $existing_taxonomy ) {
|
||||
if ( isset( $cptui_taxonomies[ $existing_taxonomy['taxonomy'] ] ) ) {
|
||||
$overwrite_warning = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $choices ) ) :
|
||||
?>
|
||||
<div class="acf-fields import-cptui">
|
||||
<?php
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Import from Custom Post Type UI', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'acf_import_cptui',
|
||||
'choices' => $choices,
|
||||
'toggle' => true,
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
if ( $overwrite_warning ) {
|
||||
echo '<p class="acf-inline-notice notice notice-info">' . esc_html__( 'Importing a Post Type or Taxonomy with the same key as one that already exists will overwrite the settings for the existing Post Type or Taxonomy with those of the import.', 'acf' ) . '</p>';
|
||||
}
|
||||
?>
|
||||
<p class="acf-submit">
|
||||
<button type="submit" class="acf-btn" name="import_type" value="cptui">
|
||||
<?php esc_html_e( 'Import from Custom Post Type UI', 'acf' ); ?>
|
||||
</button>
|
||||
</p>
|
||||
<?php
|
||||
endif;
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports the selected ACF posts and returns an admin notice on completion.
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @return ACF_Admin_Notice
|
||||
*/
|
||||
public function submit() {
|
||||
//phpcs:disable WordPress.Security.NonceVerification.Missing -- nonce verified before this function is called.
|
||||
if ( 'cptui' === acf_request_arg( 'import_type', '' ) ) {
|
||||
$import = acf_sanitize_request_args( $_POST['acf_import_cptui'] );
|
||||
return $this->import_cpt_ui( $import );
|
||||
}
|
||||
|
||||
// Check file size.
|
||||
if ( empty( $_FILES['acf_import_file']['size'] ) ) {
|
||||
return acf_add_admin_notice( __( 'No file selected', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
$file = acf_sanitize_files_array( $_FILES['acf_import_file'] );
|
||||
|
||||
// Check errors.
|
||||
if ( $file['error'] ) {
|
||||
return acf_add_admin_notice( __( 'Error uploading file. Please try again', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
// Check file type.
|
||||
if ( pathinfo( $file['name'], PATHINFO_EXTENSION ) !== 'json' ) {
|
||||
return acf_add_admin_notice( __( 'Incorrect file type', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
// Read JSON.
|
||||
$json = file_get_contents( $file['tmp_name'] );
|
||||
$json = json_decode( $json, true );
|
||||
|
||||
// Check if empty.
|
||||
if ( ! $json || ! is_array( $json ) ) {
|
||||
return acf_add_admin_notice( __( 'Import file empty', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
// Ensure $json is an array of posts.
|
||||
if ( isset( $json['key'] ) ) {
|
||||
$json = array( $json );
|
||||
}
|
||||
|
||||
// Remember imported post ids.
|
||||
$ids = array();
|
||||
|
||||
// Loop over json.
|
||||
foreach ( $json as $to_import ) {
|
||||
// Search database for existing post.
|
||||
$post_type = acf_determine_internal_post_type( $to_import['key'] );
|
||||
$post = acf_get_internal_post_type_post( $to_import['key'], $post_type );
|
||||
|
||||
if ( $post ) {
|
||||
$to_import['ID'] = $post->ID;
|
||||
}
|
||||
|
||||
// Import the post.
|
||||
$to_import = acf_import_internal_post_type( $to_import, $post_type );
|
||||
|
||||
// Append message.
|
||||
$ids[] = $to_import['ID'];
|
||||
}
|
||||
|
||||
// Count number of imported posts.
|
||||
$total = count( $ids );
|
||||
|
||||
// Generate text.
|
||||
$text = sprintf( _n( 'Imported 1 item', 'Imported %s items', $total, 'acf' ), $total );
|
||||
|
||||
// Add links to text.
|
||||
$links = array();
|
||||
foreach ( $ids as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
|
||||
// Add notice.
|
||||
return acf_add_admin_notice( $text, 'success' );
|
||||
//phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the import of CPTUI post types and taxonomies.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $import_args What to import.
|
||||
* @return ACF_Admin_Notice
|
||||
*/
|
||||
public function import_cpt_ui( $import_args ) {
|
||||
if ( ! is_array( $import_args ) ) {
|
||||
return acf_add_admin_notice( __( 'Nothing from Custom Post Type UI plugin selected for import.', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
$imported = array();
|
||||
|
||||
// Import any post types.
|
||||
if ( in_array( 'post_types', $import_args, true ) ) {
|
||||
$cptui_post_types = get_option( 'cptui_post_types' );
|
||||
$instance = acf_get_internal_post_type_instance( 'acf-post-type' );
|
||||
|
||||
if ( ! is_array( $cptui_post_types ) || ! $instance ) {
|
||||
return acf_add_admin_notice( __( 'Failed to import post types.', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
foreach ( $cptui_post_types as $post_type ) {
|
||||
$result = $instance->import_cptui_post_type( $post_type );
|
||||
|
||||
if ( is_array( $result ) && isset( $result['ID'] ) ) {
|
||||
$imported[] = (int) $result['ID'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Import any taxonomies.
|
||||
if ( in_array( 'taxonomies', $import_args, true ) ) {
|
||||
$cptui_taxonomies = get_option( 'cptui_taxonomies' );
|
||||
$instance = acf_get_internal_post_type_instance( 'acf-taxonomy' );
|
||||
|
||||
if ( ! is_array( $cptui_taxonomies ) || ! $instance ) {
|
||||
return acf_add_admin_notice( __( 'Failed to import taxonomies.', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
foreach ( $cptui_taxonomies as $taxonomy ) {
|
||||
$result = $instance->import_cptui_taxonomy( $taxonomy );
|
||||
|
||||
if ( is_array( $result ) && isset( $result['ID'] ) ) {
|
||||
$imported[] = (int) $result['ID'];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! empty( $imported ) ) {
|
||||
// Generate text.
|
||||
$total = count( $imported );
|
||||
/* translators: %d - number of items imported from CPTUI */
|
||||
$text = sprintf( _n( 'Imported %d item from Custom Post Type UI -', 'Imported %d items from Custom Post Type UI -', $total, 'acf' ), $total );
|
||||
|
||||
// Add links to text.
|
||||
$links = array();
|
||||
foreach ( $imported as $id ) {
|
||||
$links[] = '<a href="' . get_edit_post_link( $id ) . '">' . get_the_title( $id ) . '</a>';
|
||||
}
|
||||
|
||||
$text .= ' ' . implode( ', ', $links );
|
||||
$text .= __( '. The Custom Post Type UI plugin can be deactivated.', 'acf' );
|
||||
|
||||
return acf_add_admin_notice( $text, 'success' );
|
||||
}
|
||||
|
||||
return acf_add_admin_notice( __( 'Nothing to import', 'acf' ), 'warning' );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Initialize.
|
||||
acf_register_admin_tool( 'ACF_Admin_Tool_Import' );
|
||||
|
||||
endif; // class_exists check.
|
||||
|
||||
?>
|
@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Admin_Tool' ) ) :
|
||||
|
||||
class ACF_Admin_Tool {
|
||||
|
||||
|
||||
/** @var string Tool name */
|
||||
var $name = '';
|
||||
|
||||
|
||||
/** @var string Tool title */
|
||||
var $title = '';
|
||||
|
||||
|
||||
/** @var string Dashicon slug */
|
||||
var $icon = '';
|
||||
|
||||
|
||||
/** @var boolean Redirect form to single */
|
||||
// var $redirect = false;
|
||||
|
||||
|
||||
/**
|
||||
* get_name
|
||||
*
|
||||
* This function will return the Tool's name
|
||||
*
|
||||
* @date 19/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function get_name() {
|
||||
return $this->name;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_title
|
||||
*
|
||||
* This function will return the Tool's title
|
||||
*
|
||||
* @date 19/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function get_title() {
|
||||
return $this->title;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* get_url
|
||||
*
|
||||
* This function will return the Tool's title
|
||||
*
|
||||
* @date 19/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function get_url() {
|
||||
return acf_get_admin_tool_url( $this->name );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* is_active
|
||||
*
|
||||
* This function will return true if the tool is active
|
||||
*
|
||||
* @date 19/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return bool
|
||||
*/
|
||||
|
||||
function is_active() {
|
||||
return acf_maybe_get_GET( 'tool' ) === $this->name;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* This function will setup the class functionality
|
||||
*
|
||||
* @type function
|
||||
* @date 27/6/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function __construct() {
|
||||
|
||||
// initialize
|
||||
$this->initialize();
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* This function will initialize the admin tool
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
/* do nothing */
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* load
|
||||
*
|
||||
* This function is called during the admin page load
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function load() {
|
||||
|
||||
/* do nothing */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* html
|
||||
*
|
||||
* This function will output the metabox HTML
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function html() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* submit
|
||||
*
|
||||
* This function will run when the tool's form has been submit
|
||||
*
|
||||
* @date 10/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function submit() {
|
||||
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,173 @@
|
||||
<?php
|
||||
|
||||
// vars
|
||||
$disabled = false;
|
||||
|
||||
// empty
|
||||
if ( empty( $field['conditional_logic'] ) ) {
|
||||
|
||||
$disabled = true;
|
||||
$field['conditional_logic'] = array(
|
||||
|
||||
// group 0
|
||||
array(
|
||||
|
||||
// rule 0
|
||||
array(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-field acf-field-true-false acf-field-setting-conditional_logic" data-type="true_false" data-name="conditional_logic">
|
||||
<div class="acf-conditional-toggle">
|
||||
<div class="acf-label">
|
||||
<?php $acf_label_for = acf_idify( $field['prefix'] . '[conditional_logic]' ); ?>
|
||||
<label for="<?php echo esc_attr( $acf_label_for ); ?>"><?php _e( 'Conditional Logic', 'acf' ); ?></label>
|
||||
</div>
|
||||
<div class="acf-input">
|
||||
<?php
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'true_false',
|
||||
'name' => 'conditional_logic',
|
||||
'prefix' => $field['prefix'],
|
||||
'value' => $disabled ? 0 : 1,
|
||||
'ui' => 1,
|
||||
'class' => 'conditions-toggle',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<div class="rule-groups" <?php if ( $disabled ) echo ' style="display:none"'; ?>>
|
||||
<?php
|
||||
foreach ( $field['conditional_logic'] as $group_id => $group ) :
|
||||
|
||||
// validate
|
||||
if ( empty( $group ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
// vars
|
||||
// $group_id must be completely different to $rule_id to avoid JS issues
|
||||
$group_id = "group_{$group_id}";
|
||||
$h4 = ( $group_id == 'group_0' ) ? __( 'Show this field if', 'acf' ) : __( 'or', 'acf' );
|
||||
|
||||
?>
|
||||
<div class="rule-group" data-id="<?php echo $group_id; ?>">
|
||||
|
||||
<h4><?php echo $h4; ?></h4>
|
||||
|
||||
<table class="acf-table -clear">
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $group as $rule_id => $rule ) :
|
||||
|
||||
// valid rule
|
||||
$rule = wp_parse_args(
|
||||
$rule,
|
||||
array(
|
||||
'field' => '',
|
||||
'operator' => '',
|
||||
'value' => '',
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// vars
|
||||
// $group_id must be completely different to $rule_id to avoid JS issues
|
||||
$rule_id = "rule_{$rule_id}";
|
||||
$prefix = "{$field['prefix']}[conditional_logic][{$group_id}][{$rule_id}]";
|
||||
|
||||
// data attributes
|
||||
$attributes = array(
|
||||
'data-id' => $rule_id,
|
||||
'data-field' => $rule['field'],
|
||||
'data-operator' => $rule['operator'],
|
||||
'data-value' => $rule['value'],
|
||||
);
|
||||
|
||||
?>
|
||||
<tr class="rule" <?php echo acf_esc_attrs( $attributes ); ?>>
|
||||
<td class="param">
|
||||
<?php
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'prefix' => $prefix,
|
||||
'name' => 'field',
|
||||
'class' => 'condition-rule-field',
|
||||
'disabled' => $disabled,
|
||||
'value' => $rule['field'],
|
||||
'choices' => array(
|
||||
$rule['field'] => $rule['field'],
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="operator">
|
||||
<?php
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'prefix' => $prefix,
|
||||
'name' => 'operator',
|
||||
'class' => 'condition-rule-operator',
|
||||
'disabled' => $disabled,
|
||||
'value' => $rule['operator'],
|
||||
'choices' => array(
|
||||
$rule['operator'] => $rule['operator'],
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="value">
|
||||
<?php
|
||||
|
||||
// create field
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'prefix' => $prefix,
|
||||
'name' => 'value',
|
||||
'class' => 'condition-rule-value',
|
||||
'disabled' => $disabled,
|
||||
'value' => $rule['value'],
|
||||
'choices' => array(
|
||||
$rule['value'] => $rule['value'],
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="add">
|
||||
<a href="#" class="button add-conditional-rule"><?php _e( 'and', 'acf' ); ?></a>
|
||||
</td>
|
||||
<td class="remove">
|
||||
<a href="#" class="acf-icon -minus remove-conditional-rule"></a>
|
||||
</td>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
||||
<?php endforeach; ?>
|
||||
|
||||
<h4><?php _e( 'or', 'acf' ); ?></h4>
|
||||
|
||||
<a href="#" class="button add-conditional-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,324 @@
|
||||
<?php
|
||||
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
|
||||
|
||||
// Define input name prefix using unique identifier.
|
||||
$input_prefix = 'acf_fields[' . $field['ID'] . ']';
|
||||
$input_id = acf_idify( $input_prefix );
|
||||
|
||||
// Update field props.
|
||||
$field['prefix'] = $input_prefix;
|
||||
|
||||
// Elements.
|
||||
$div_attrs = array(
|
||||
'class' => 'acf-field-object acf-field-object-' . acf_slugify( $field['type'] ),
|
||||
'data-id' => $field['ID'],
|
||||
'data-key' => $field['key'],
|
||||
'data-type' => $field['type'],
|
||||
);
|
||||
|
||||
// Add additional class if the field is an endpoint.
|
||||
if ( isset( $field['endpoint'] ) && $field['endpoint'] ) {
|
||||
$div_attrs['class'] .= ' acf-field-is-endpoint';
|
||||
}
|
||||
|
||||
// Misc template vars.
|
||||
$field_label = acf_get_field_label( $field, 'admin' );
|
||||
$field_type_label = acf_get_field_type_label( $field['type'] );
|
||||
|
||||
if ( ! isset( $num_field_groups ) ) {
|
||||
$num_field_groups = 0;
|
||||
}
|
||||
|
||||
$conditional_logic_class = $conditional_logic_text = '';
|
||||
if ( isset( $field['conditional_logic'] ) && is_array( $field['conditional_logic'] ) && count( $field['conditional_logic'] ) > 0 ) {
|
||||
$conditional_logic_class = ' is-enabled';
|
||||
$conditional_logic_text = __( 'Active', 'acf' );
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div_attrs ); ?>>
|
||||
|
||||
<div class="meta">
|
||||
<?php
|
||||
$meta_inputs = array(
|
||||
'ID' => $field['ID'],
|
||||
'key' => $field['key'],
|
||||
'parent' => $field['parent'],
|
||||
'menu_order' => $i,
|
||||
'save' => '',
|
||||
);
|
||||
foreach ( $meta_inputs as $k => $v ) :
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $input_prefix . '[' . $k . ']',
|
||||
'value' => $v,
|
||||
'id' => $input_id . '-' . $k,
|
||||
)
|
||||
);
|
||||
endforeach;
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="handle">
|
||||
<ul class="acf-hl acf-tbody">
|
||||
<li class="li-field-order">
|
||||
<span class="acf-icon acf-sortable-handle" title="<?php _e( 'Drag to reorder', 'acf' ); ?>"><?php echo ( $i + 1 ); ?></span>
|
||||
</li>
|
||||
<li class="li-field-label">
|
||||
<strong>
|
||||
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php echo acf_esc_html( $field_label ); ?></a>
|
||||
</strong>
|
||||
<div class="row-options">
|
||||
<a class="edit-field" title="<?php _e( 'Edit field', 'acf' ); ?>" href="#"><?php _e( 'Edit', 'acf' ); ?></a>
|
||||
<a class="duplicate-field" title="<?php _e( 'Duplicate field', 'acf' ); ?>" href="#"><?php _e( 'Duplicate', 'acf' ); ?></a>
|
||||
<?php if ( $num_field_groups > 1 ) : ?>
|
||||
<a class="move-field" title="<?php _e( 'Move field to another group', 'acf' ); ?>" href="#"><?php _e( 'Move', 'acf' ); ?></a>
|
||||
<?php endif; ?>
|
||||
<a class="delete-field" title="<?php _e( 'Delete field', 'acf' ); ?>" href="#"><?php _e( 'Delete', 'acf' ); ?></a>
|
||||
</div>
|
||||
</li>
|
||||
<li class="li-field-name"><span class="copyable"><?php echo esc_html( $field['name'] ); ?></span></li>
|
||||
<li class="li-field-key"><span class="copyable"><?php echo esc_html( $field['key'] ); ?></span></li>
|
||||
<li class="li-field-type">
|
||||
<i class="field-type-icon field-type-icon-<?php echo acf_slugify( $field['type'] ); ?>"></i>
|
||||
<span class="field-type-label">
|
||||
<?php echo acf_esc_html( $field_type_label ); ?>
|
||||
</span>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="settings">
|
||||
<div class="acf-field-editor">
|
||||
<div class="acf-field-settings acf-fields">
|
||||
|
||||
<?php
|
||||
foreach ( acf_get_combined_field_type_settings_tabs() as $tab_key => $tab_label ) {
|
||||
$field_to_render = array(
|
||||
'type' => 'tab',
|
||||
'label' => $tab_label,
|
||||
'key' => 'acf_field_settings_tabs',
|
||||
'settings-type' => $tab_key,
|
||||
);
|
||||
|
||||
if ( $tab_key === 'conditional_logic' ) {
|
||||
$field_to_render['label'] = __( 'Conditional Logic', 'acf' ) . '<i class="conditional-logic-badge' . $conditional_logic_class . '">' . $conditional_logic_text . '</i>';
|
||||
}
|
||||
|
||||
acf_render_field_wrap( $field_to_render );
|
||||
?>
|
||||
<?php
|
||||
$wrapper_class = str_replace( '_', '-', $tab_key );
|
||||
?>
|
||||
<div class="acf-field-settings-main acf-field-settings-main-<?php echo esc_attr( $wrapper_class ); ?>">
|
||||
<?php
|
||||
switch ( $tab_key ) {
|
||||
case 'general':
|
||||
$field_type_select_class = 'field-type';
|
||||
if ( ! apply_filters( 'acf/field_group/enable_field_type_select2', true ) ) {
|
||||
$field_type_select_class .= ' disable-select2';
|
||||
}
|
||||
// type
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Field Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'type',
|
||||
'choices' => acf_get_grouped_field_types(),
|
||||
'class' => $field_type_select_class,
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
if ( apply_filters( 'acf/field_group/enable_field_browser', true ) ) {
|
||||
?>
|
||||
<div class="acf-field acf-field-setting-browse-fields" data-append="type">
|
||||
<div class="acf-input">
|
||||
<button class="acf-btn browse-fields">
|
||||
<i class="acf-icon acf-icon-dots-grid"></i>
|
||||
<?php _e( 'Browse Fields', 'acf' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
// label
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Field Label', 'acf' ),
|
||||
'instructions' => __( 'This is the name which will appear on the EDIT page', 'acf' ),
|
||||
'name' => 'label',
|
||||
'type' => 'text',
|
||||
'class' => 'field-label',
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// name
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Field Name', 'acf' ),
|
||||
'instructions' => __( 'Single word, no spaces. Underscores and dashes allowed', 'acf' ),
|
||||
'name' => 'name',
|
||||
'type' => 'text',
|
||||
'class' => 'field-name',
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
// 3rd party settings
|
||||
do_action( 'acf/render_field_settings', $field );
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
|
||||
?>
|
||||
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
|
||||
<?php
|
||||
do_action( "acf/render_field_settings/type={$field['type']}", $field );
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
break;
|
||||
case 'validation':
|
||||
// required
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Required', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'required',
|
||||
'ui' => 1,
|
||||
'class' => 'field-required',
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
|
||||
?>
|
||||
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
|
||||
<?php
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
break;
|
||||
case 'presentation':
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Instructions', 'acf' ),
|
||||
'instructions' => __( 'Instructions for authors. Shown when submitting data', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'instructions',
|
||||
'rows' => 5,
|
||||
),
|
||||
true
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => '',
|
||||
'instructions' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'class',
|
||||
'prefix' => $field['prefix'] . '[wrapper]',
|
||||
'value' => $field['wrapper']['class'],
|
||||
'prepend' => __( 'class', 'acf' ),
|
||||
'wrapper' => array(
|
||||
'data-append' => 'wrapper',
|
||||
),
|
||||
),
|
||||
'div'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => '',
|
||||
'instructions' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'id',
|
||||
'prefix' => $field['prefix'] . '[wrapper]',
|
||||
'value' => $field['wrapper']['id'],
|
||||
'prepend' => __( 'id', 'acf' ),
|
||||
'wrapper' => array(
|
||||
'data-append' => 'wrapper',
|
||||
),
|
||||
),
|
||||
'div'
|
||||
);
|
||||
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
|
||||
?>
|
||||
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
|
||||
<?php
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Wrapper Attributes', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'width',
|
||||
'prefix' => $field['prefix'] . '[wrapper]',
|
||||
'value' => $field['wrapper']['width'],
|
||||
'prepend' => __( 'width', 'acf' ),
|
||||
'append' => '%',
|
||||
'wrapper' => array(
|
||||
'data-name' => 'wrapper',
|
||||
'class' => 'acf-field-setting-wrapper',
|
||||
),
|
||||
),
|
||||
'div'
|
||||
);
|
||||
break;
|
||||
case 'conditional_logic':
|
||||
acf_get_view( 'acf-field-group/conditional-logic', array( 'field' => $field ) );
|
||||
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
|
||||
?>
|
||||
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
|
||||
<?php
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
break;
|
||||
default:
|
||||
// Global action hook for custom tabs.
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}", $field );
|
||||
?>
|
||||
<div class="acf-field-type-settings" data-parent-tab="<?php echo esc_attr( $tab_key ); ?>">
|
||||
<?php
|
||||
// Type-specific action hook for custom tabs.
|
||||
do_action( "acf/field_group/render_field_settings_tab/{$tab_key}/type={$field['type']}", $field );
|
||||
do_action( "acf/render_field_{$tab_key}_settings/type={$field['type']}", $field );
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-field-settings-footer">
|
||||
<a class="button close-field edit-field" title="<?php _e( 'Close Field', 'acf' ); ?>" href="#"><?php _e( 'Close Field', 'acf' ); ?></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
@ -0,0 +1,128 @@
|
||||
<?php
|
||||
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- template include file
|
||||
$field_groups = acf_get_field_groups();
|
||||
$num_field_groups = 0;
|
||||
if ( is_array( $field_groups ) ) {
|
||||
$num_field_groups = count( $field_groups );
|
||||
}
|
||||
$is_subfield = ! empty( $is_subfield );
|
||||
$wrapper_class = '';
|
||||
if ( $is_subfield ) {
|
||||
$wrapper_class = ' acf-is-subfields';
|
||||
if ( ! $fields ) {
|
||||
$wrapper_class .= ' -empty';
|
||||
}
|
||||
} elseif ( ! $fields && ! $parent ) {
|
||||
$wrapper_class = ' acf-auto-add-field';
|
||||
}
|
||||
?>
|
||||
<?php if ( $parent || $is_subfield ) { ?>
|
||||
<div class="acf-sub-field-list-header">
|
||||
<h3 class="acf-sub-field-list-title"><?php _e( 'Fields', 'acf' ); ?></h3>
|
||||
<a href="#" class="acf-btn acf-btn-secondary add-field"><i class="acf-icon acf-icon-plus"></i><?php _e( 'Add Field', 'acf' ); ?></a>
|
||||
</div>
|
||||
<?php } ?>
|
||||
<?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- fixed string output ?>
|
||||
<div class="acf-field-list-wrap<?php echo $wrapper_class; ?>">
|
||||
|
||||
<ul class="acf-hl acf-thead">
|
||||
<li class="li-field-order">
|
||||
<?php
|
||||
/* translators: A symbol (or text, if not available in your locale) meaning "Order Number", in terms of positional placement. */
|
||||
_e( '#', 'acf' );
|
||||
?>
|
||||
<span class="acf-hidden">
|
||||
<?php
|
||||
/* translators: Hidden accessibility text for the positional order number of the field. */
|
||||
_e( 'Order', 'acf' );
|
||||
?>
|
||||
</span>
|
||||
</li>
|
||||
<li class="li-field-label"><?php _e( 'Label', 'acf' ); ?></li>
|
||||
<li class="li-field-name"><?php _e( 'Name', 'acf' ); ?></li>
|
||||
<li class="li-field-key"><?php _e( 'Key', 'acf' ); ?></li>
|
||||
<li class="li-field-type"><?php _e( 'Type', 'acf' ); ?></li>
|
||||
</ul>
|
||||
|
||||
<?php //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- fixed string output ?>
|
||||
<div class="acf-field-list<?php echo $wrapper_class; ?>">
|
||||
|
||||
<div class="no-fields-message">
|
||||
<div class="no-fields-message-inner">
|
||||
<img src="<?php echo acf_get_url( 'assets/images/empty-group.svg' ); ?>" />
|
||||
<h2><?php _e( 'Add Your First Field', 'acf' ); ?></h2>
|
||||
<p><?php _e( 'Get started creating new custom fields for your posts, pages, custom post types and other WordPress content.', 'acf' ); ?></p>
|
||||
<a href="#" class="acf-btn acf-btn-primary add-field add-first-field
|
||||
"><i class="acf-icon acf-icon-plus"></i> <?php _e( 'Add Field', 'acf' ); ?></a>
|
||||
<p class="acf-small">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s url to field types list */
|
||||
__( 'Choose from over 30 field types. <a href="%s" target="_blank">Learn more</a>.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/', 'docs', 'empty-field-group', 'field-types' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
if ( $fields ) :
|
||||
|
||||
foreach ( $fields as $i => $field ) :
|
||||
|
||||
acf_get_view(
|
||||
'acf-field-group/field',
|
||||
array(
|
||||
'field' => $field,
|
||||
'i' => $i,
|
||||
'num_field_groups' => $num_field_groups,
|
||||
)
|
||||
);
|
||||
|
||||
endforeach;
|
||||
|
||||
endif;
|
||||
?>
|
||||
|
||||
</div>
|
||||
|
||||
<ul class="acf-hl acf-tfoot">
|
||||
<li class="acf-fr">
|
||||
<a href="#" class="acf-btn acf-btn-secondary add-field"><i class="acf-icon acf-icon-plus"></i><?php _e( 'Add Field', 'acf' ); ?></a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<?php
|
||||
if ( ! $parent ) :
|
||||
|
||||
// get clone
|
||||
$clone = acf_get_valid_field(
|
||||
array(
|
||||
'ID' => 'acfcloneindex',
|
||||
'key' => 'acfcloneindex',
|
||||
'label' => __( 'New Field', 'acf' ),
|
||||
'name' => 'new_field',
|
||||
'type' => 'text',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
<script type="text/html" id="tmpl-acf-field">
|
||||
<?php
|
||||
acf_get_view(
|
||||
'acf-field-group/field',
|
||||
array(
|
||||
'field' => $clone,
|
||||
'i' => 0,
|
||||
'num_field_groups' => $num_field_groups,
|
||||
)
|
||||
);
|
||||
?>
|
||||
</script>
|
||||
<script type="text/html" id="tmpl-acf-browse-fields-modal">
|
||||
<?php acf_get_view( 'browse-fields-modal' ); ?>
|
||||
</script>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
@ -0,0 +1,26 @@
|
||||
<script>document.body.classList.add('acf-no-field-groups');</script>
|
||||
<div class="acf-no-field-groups-wrapper">
|
||||
<div class="acf-no-field-groups-inner">
|
||||
<img src="<?php echo acf_get_url( 'assets/images/empty-group.svg' ); ?>" />
|
||||
<h2><?php _e( 'Add Your First Field Group', 'acf' ); ?></h2>
|
||||
<p>
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s url to creating a field group page */
|
||||
__( 'ACF uses <a href="%s" target="_blank">field groups</a> to group custom fields together, and then attach those fields to edit screens.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/creating-a-field-group/', 'docs', 'no-field-groups' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<a href="<?php echo admin_url( 'post-new.php?post_type=acf-field-group' ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php _e( 'Add Field Group', 'acf' ); ?></a>
|
||||
<p class="acf-small">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s url to getting started guide */
|
||||
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-field-groups' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,30 @@
|
||||
<div class="rule-group" data-id="<?php echo $group_id; ?>">
|
||||
|
||||
<h4><?php echo ( $group_id == 'group_0' ) ? __( 'Show this field group if', 'acf' ) : __( 'or', 'acf' ); ?></h4>
|
||||
|
||||
<table class="acf-table -clear">
|
||||
<tbody>
|
||||
<?php
|
||||
foreach ( $group as $i => $rule ) :
|
||||
|
||||
// validate rule
|
||||
$rule = acf_validate_location_rule( $rule );
|
||||
|
||||
// append id and group
|
||||
$rule['id'] = "rule_{$i}";
|
||||
$rule['group'] = $group_id;
|
||||
|
||||
// view
|
||||
acf_get_view(
|
||||
'acf-field-group/location-rule',
|
||||
array(
|
||||
'rule' => $rule,
|
||||
)
|
||||
);
|
||||
|
||||
endforeach;
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
</div>
|
@ -0,0 +1,96 @@
|
||||
<?php
|
||||
|
||||
// vars
|
||||
$prefix = 'acf_field_group[location][' . $rule['group'] . '][' . $rule['id'] . ']';
|
||||
|
||||
?>
|
||||
<tr data-id="<?php echo $rule['id']; ?>">
|
||||
<td class="param">
|
||||
<?php
|
||||
|
||||
// vars
|
||||
$choices = acf_get_location_rule_types();
|
||||
|
||||
// array
|
||||
if ( is_array( $choices ) ) {
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'param',
|
||||
'prefix' => $prefix,
|
||||
'value' => $rule['param'],
|
||||
'choices' => $choices,
|
||||
'class' => 'refresh-location-rule',
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="operator">
|
||||
<?php
|
||||
|
||||
// vars
|
||||
$choices = acf_get_location_rule_operators( $rule );
|
||||
|
||||
|
||||
// array
|
||||
if ( is_array( $choices ) ) {
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'operator',
|
||||
'prefix' => $prefix,
|
||||
'value' => $rule['operator'],
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
|
||||
// custom
|
||||
} else {
|
||||
|
||||
echo $choices;
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="value">
|
||||
<?php
|
||||
|
||||
// vars
|
||||
$choices = acf_get_location_rule_values( $rule );
|
||||
|
||||
|
||||
// array
|
||||
if ( is_array( $choices ) ) {
|
||||
|
||||
acf_render_field(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'value',
|
||||
'prefix' => $prefix,
|
||||
'value' => $rule['value'],
|
||||
'choices' => $choices,
|
||||
)
|
||||
);
|
||||
|
||||
// custom
|
||||
} else {
|
||||
|
||||
echo $choices;
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
</td>
|
||||
<td class="add">
|
||||
<a href="#" class="button add-location-rule"><?php _e( 'and', 'acf' ); ?></a>
|
||||
</td>
|
||||
<td class="remove">
|
||||
<a href="#" class="acf-icon -minus remove-location-rule"></a>
|
||||
</td>
|
||||
</tr>
|
@ -0,0 +1,52 @@
|
||||
<?php
|
||||
|
||||
// global
|
||||
global $field_group;
|
||||
|
||||
?>
|
||||
<div class="acf-field">
|
||||
<div class="acf-label">
|
||||
<label><?php _e( 'Rules', 'acf' ); ?></label>
|
||||
<i tabindex="0" class="acf-icon acf-icon-help acf-js-tooltip" title="<?php esc_attr_e( 'Create a set of rules to determine which edit screens will use these advanced custom fields', 'acf' ); ?>">?</i>
|
||||
</div>
|
||||
<div class="acf-input">
|
||||
<div class="rule-groups">
|
||||
|
||||
<?php
|
||||
foreach ( $field_group['location'] as $i => $group ) :
|
||||
|
||||
// bail early if no group
|
||||
if ( empty( $group ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
// view
|
||||
acf_get_view(
|
||||
'acf-field-group/location-group',
|
||||
array(
|
||||
'group' => $group,
|
||||
'group_id' => "group_{$i}",
|
||||
)
|
||||
);
|
||||
|
||||
endforeach;
|
||||
?>
|
||||
|
||||
<h4><?php _e( 'or', 'acf' ); ?></h4>
|
||||
|
||||
<a href="#" class="button add-location-group"><?php _e( 'Add rule group', 'acf' ); ?></a>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
if( typeof acf !== 'undefined' ) {
|
||||
|
||||
acf.newPostbox({
|
||||
'id': 'acf-field-group-locations',
|
||||
'label': 'left'
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
@ -0,0 +1,282 @@
|
||||
<?php
|
||||
|
||||
// global
|
||||
global $field_group;
|
||||
|
||||
// UI needs at lease 1 location rule
|
||||
if ( empty( $field_group['location'] ) ) {
|
||||
$field_group['location'] = array(
|
||||
// Group 0.
|
||||
array(
|
||||
// Rule 0.
|
||||
array(
|
||||
'param' => 'post_type',
|
||||
'operator' => '==',
|
||||
'value' => 'post',
|
||||
),
|
||||
),
|
||||
);
|
||||
|
||||
$acf_use_post_type = acf_get_post_type_from_request_args( 'add-fields' );
|
||||
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'add-fields' );
|
||||
|
||||
if ( $acf_use_post_type && ! empty( $acf_use_post_type['post_type'] ) ) {
|
||||
$field_group['location'] = array(
|
||||
array(
|
||||
array(
|
||||
'param' => 'post_type',
|
||||
'operator' => '==',
|
||||
'value' => $acf_use_post_type['post_type'],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
if ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['taxonomy'] ) ) {
|
||||
$field_group['location'] = array(
|
||||
array(
|
||||
array(
|
||||
'param' => 'taxonomy',
|
||||
'operator' => '==',
|
||||
'value' => $acf_use_taxonomy['taxonomy'],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( acf_get_combined_field_group_settings_tabs() as $tab_key => $tab_label ) {
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'tab',
|
||||
'label' => $tab_label,
|
||||
'key' => 'acf_field_group_settings_tabs',
|
||||
'settings-type' => $tab_key,
|
||||
)
|
||||
);
|
||||
|
||||
switch ( $tab_key ) {
|
||||
case 'location_rules':
|
||||
echo '<div class="field-group-locations field-group-settings-tab">';
|
||||
acf_get_view( 'acf-field-group/locations' );
|
||||
echo '</div>';
|
||||
break;
|
||||
case 'presentation':
|
||||
echo '<div class="field-group-setting-split-container field-group-settings-tab">';
|
||||
echo '<div class="field-group-setting-split">';
|
||||
|
||||
// style
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Style', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'button_group',
|
||||
'name' => 'style',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['style'],
|
||||
'choices' => array(
|
||||
'default' => __( 'Standard (WP metabox)', 'acf' ),
|
||||
'seamless' => __( 'Seamless (no metabox)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// position
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Position', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'button_group',
|
||||
'name' => 'position',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['position'],
|
||||
'choices' => array(
|
||||
'acf_after_title' => __( 'High (after title)', 'acf' ),
|
||||
'normal' => __( 'Normal (after content)', 'acf' ),
|
||||
'side' => __( 'Side', 'acf' ),
|
||||
),
|
||||
'default_value' => 'normal',
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// label_placement
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Label placement', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'button_group',
|
||||
'name' => 'label_placement',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['label_placement'],
|
||||
'choices' => array(
|
||||
'top' => __( 'Top aligned', 'acf' ),
|
||||
'left' => __( 'Left aligned', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// instruction_placement
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Instruction placement', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'button_group',
|
||||
'name' => 'instruction_placement',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['instruction_placement'],
|
||||
'choices' => array(
|
||||
'label' => __( 'Below labels', 'acf' ),
|
||||
'field' => __( 'Below fields', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
|
||||
// menu_order
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Order No.', 'acf' ),
|
||||
'instructions' => __( 'Field groups with a lower order will appear first', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'menu_order',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['menu_order'],
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
echo '<div class="field-group-setting-split">';
|
||||
|
||||
// hide on screen
|
||||
$choices = array(
|
||||
'permalink' => __( 'Permalink', 'acf' ),
|
||||
'the_content' => __( 'Content Editor', 'acf' ),
|
||||
'excerpt' => __( 'Excerpt', 'acf' ),
|
||||
'custom_fields' => __( 'Custom Fields', 'acf' ),
|
||||
'discussion' => __( 'Discussion', 'acf' ),
|
||||
'comments' => __( 'Comments', 'acf' ),
|
||||
'revisions' => __( 'Revisions', 'acf' ),
|
||||
'slug' => __( 'Slug', 'acf' ),
|
||||
'author' => __( 'Author', 'acf' ),
|
||||
'format' => __( 'Format', 'acf' ),
|
||||
'page_attributes' => __( 'Page Attributes', 'acf' ),
|
||||
'featured_image' => __( 'Featured Image', 'acf' ),
|
||||
'categories' => __( 'Categories', 'acf' ),
|
||||
'tags' => __( 'Tags', 'acf' ),
|
||||
'send-trackbacks' => __( 'Send Trackbacks', 'acf' ),
|
||||
);
|
||||
if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
|
||||
unset( $choices['custom_fields'] );
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Hide on screen', 'acf' ),
|
||||
'instructions' => __( '<b>Select</b> items to <b>hide</b> them from the edit screen.', 'acf' ) . '<br /><br />' . __( "If multiple field groups appear on an edit screen, the first field group's options will be used (the one with the lowest order number)", 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'hide_on_screen',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['hide_on_screen'],
|
||||
'toggle' => true,
|
||||
'choices' => $choices,
|
||||
),
|
||||
'div',
|
||||
'label',
|
||||
true
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
echo '</div>';
|
||||
break;
|
||||
case 'group_settings':
|
||||
echo '<div class="field-group-settings field-group-settings-tab">';
|
||||
|
||||
// active
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Active', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'active',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['active'],
|
||||
'ui' => 1,
|
||||
// 'ui_on_text' => __('Active', 'acf'),
|
||||
// 'ui_off_text' => __('Inactive', 'acf'),
|
||||
)
|
||||
);
|
||||
|
||||
// Show fields in REST API.
|
||||
if ( acf_get_setting( 'rest_api_enabled' ) ) {
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Show in REST API', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'show_in_rest',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['show_in_rest'],
|
||||
'ui' => 1,
|
||||
// 'ui_on_text' => __('Active', 'acf'),
|
||||
// 'ui_off_text' => __('Inactive', 'acf'),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// description
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Description', 'acf' ),
|
||||
'instructions' => __( 'Shown in field group list', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'description',
|
||||
'prefix' => 'acf_field_group',
|
||||
'value' => $field_group['description'],
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
/* translators: 1: Post creation date 2: Post creation time */
|
||||
$acf_created_on = sprintf( __( 'Created on %1$s at %2$s', 'acf' ), get_the_date(), get_the_time() );
|
||||
?>
|
||||
<div class="acf-field-group-settings-footer">
|
||||
<span class="acf-created-on"><?php echo esc_html( $acf_created_on ); ?></span>
|
||||
<a href="<?php echo get_delete_post_link(); ?>" class="acf-btn acf-btn-tertiary acf-delete-field-group">
|
||||
<i class="acf-icon acf-icon-trash"></i>
|
||||
<?php esc_html_e( 'Delete Field Group', 'acf' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
echo '</div>';
|
||||
break;
|
||||
default:
|
||||
echo '<div class="field-group-' . esc_attr( $tab_key ) . ' field-group-settings-tab">';
|
||||
do_action( 'acf/field_group/render_group_settings_tab/' . $tab_key, $field_group );
|
||||
echo '</div>';
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// 3rd party settings
|
||||
do_action( 'acf/render_field_group_settings', $field_group );
|
||||
?>
|
||||
|
||||
<div class="acf-hidden">
|
||||
<input type="hidden" name="acf_field_group[key]" value="<?php echo $field_group['key']; ?>" />
|
||||
</div>
|
||||
<script type="text/javascript">
|
||||
if( typeof acf !== 'undefined' ) {
|
||||
|
||||
acf.newPostbox({
|
||||
'id': 'acf-field-group-options',
|
||||
'label': 'top'
|
||||
});
|
||||
|
||||
}
|
||||
</script>
|
@ -0,0 +1,19 @@
|
||||
<div class="acf-field-group-pro-features-wrapper">
|
||||
|
||||
<div class="acf-field-group-pro-features-content">
|
||||
<h1><i class="acf-icon acf-icon-stars"></i><?php _e( 'Unlock Extra Features with ACF PRO', 'acf' ); ?></h1>
|
||||
<ul class="acf-pro-features-list">
|
||||
<li><?php _e( 'Repeater Field', 'acf' ); ?></li>
|
||||
<li><?php _e( 'Flexible Content Field', 'acf' ); ?></li>
|
||||
<li><?php _e( 'Gallery Field', 'acf' ); ?></li>
|
||||
<li><?php _e( 'Clone Field', 'acf' ); ?></li>
|
||||
<li><?php _e( 'ACF Blocks', 'acf' ); ?></li>
|
||||
<li><?php _e( 'Options Pages', 'acf' ); ?></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div class="acf-field-group-pro-features-actions">
|
||||
<a target="_blank" href="<?php echo acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'metabox' ); ?>" class="acf-btn acf-btn-upgrade"><?php _e( 'Upgrade Now', 'acf' ); ?><i class="acf-icon acf-icon-arrow-right"></i></a>
|
||||
</div>
|
||||
|
||||
</div>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,137 @@
|
||||
<?php
|
||||
global $acf_post_type;
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Plural Label', 'acf' ),
|
||||
/* translators: example post type */
|
||||
'placeholder' => __( 'Movies', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'name',
|
||||
'key' => 'name',
|
||||
'class' => 'acf_plural_label',
|
||||
'prefix' => 'acf_post_type[labels]',
|
||||
'value' => $acf_post_type['labels']['name'],
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Singular Label', 'acf' ),
|
||||
/* translators: example post type */
|
||||
'placeholder' => __( 'Movie', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'singular_name',
|
||||
'key' => 'singular_name',
|
||||
'class' => 'acf_slugify_to_key acf_singular_label',
|
||||
'prefix' => 'acf_post_type[labels]',
|
||||
'value' => $acf_post_type['labels']['singular_name'],
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Post Type Key', 'acf' ),
|
||||
'instructions' => __( 'Lower case letters, underscores and dashes only, Max 20 characters.', 'acf' ),
|
||||
/* translators: example post type */
|
||||
'placeholder' => __( 'movie', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'post_type',
|
||||
'key' => 'post_type',
|
||||
'maxlength' => 20,
|
||||
'class' => 'acf_slugified_key',
|
||||
'prefix' => 'acf_post_type',
|
||||
'value' => $acf_post_type['post_type'],
|
||||
'required' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
// Allow preselecting the linked taxonomies based on previously created taxonomy.
|
||||
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'create-post-type' );
|
||||
if ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['taxonomy'] ) ) {
|
||||
$acf_post_type['taxonomies'] = array( $acf_use_taxonomy['taxonomy'] );
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomies',
|
||||
'key' => 'taxonomies',
|
||||
'prefix' => 'acf_post_type',
|
||||
'value' => $acf_post_type['taxonomies'],
|
||||
'label' => __( 'Taxonomies', 'acf' ),
|
||||
'instructions' => __( 'Select existing taxonomies to classify items of the post type.', 'acf' ),
|
||||
'choices' => acf_get_taxonomy_labels(),
|
||||
'ui' => true,
|
||||
'allow_null' => true,
|
||||
'multiple' => true,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap( array( 'type' => 'seperator' ) );
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'true_false',
|
||||
'name' => 'public',
|
||||
'key' => 'public',
|
||||
'prefix' => 'acf_post_type',
|
||||
'value' => $acf_post_type['public'],
|
||||
'label' => __( 'Public', 'acf' ),
|
||||
'instructions' => __( 'Visible on the frontend and in the admin dashboard.', 'acf' ),
|
||||
'ui' => true,
|
||||
'default' => 1,
|
||||
),
|
||||
'div'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'true_false',
|
||||
'name' => 'hierarchical',
|
||||
'key' => 'hierarchical',
|
||||
'class' => 'acf_hierarchical_switch',
|
||||
'prefix' => 'acf_post_type',
|
||||
'value' => $acf_post_type['hierarchical'],
|
||||
'label' => __( 'Hierarchical', 'acf' ),
|
||||
'instructions' => __( 'Hierarchical post types can have descendants (like pages).', 'acf' ),
|
||||
'ui' => true,
|
||||
),
|
||||
'div'
|
||||
);
|
||||
|
||||
do_action( 'acf/post_type/basic_settings', $acf_post_type );
|
||||
|
||||
acf_render_field_wrap( array( 'type' => 'seperator' ) );
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Advanced Configuration', 'acf' ),
|
||||
'instructions' => __( 'I know what I\'m doing, show me all the options.', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'name' => 'advanced_configuration',
|
||||
'key' => 'advanced_configuration',
|
||||
'prefix' => 'acf_post_type',
|
||||
'value' => $acf_post_type['advanced_configuration'],
|
||||
'ui' => 1,
|
||||
'class' => 'acf-advanced-settings-toggle',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="acf-hidden">
|
||||
<input type="hidden" name="acf_post_type[key]" value="<?php echo esc_attr( $acf_post_type['key'] ); ?>" />
|
||||
<input type="hidden" name="acf_post_type[import_source]" value="<?php echo esc_attr( $acf_post_type['import_source'] ); ?>" />
|
||||
<input type="hidden" name="acf_post_type[import_date]" value="<?php echo esc_attr( $acf_post_type['import_date'] ); ?>" />
|
||||
</div>
|
||||
<?php
|
@ -0,0 +1,18 @@
|
||||
<script>document.body.classList.add('acf-no-post-types');</script>
|
||||
<div class="acf-no-post-types-wrapper">
|
||||
<div class="acf-no-post-types-inner">
|
||||
<img src="<?php echo esc_url( acf_get_url( 'assets/images/empty-post-types.svg' ) ); ?>" />
|
||||
<h2><?php esc_html_e( 'Add Your First Post Type', 'acf' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Expand the functionality of WordPress beyond standard posts and pages with custom post types.', 'acf' ); ?></p>
|
||||
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=acf-post-type' ) ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php esc_html_e( 'Add Post Type', 'acf' ); ?></a>
|
||||
<p class="acf-small">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s url to getting started guide */
|
||||
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-post-types' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,136 @@
|
||||
<?php
|
||||
|
||||
global $acf_taxonomy;
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Plural Label', 'acf' ),
|
||||
/* translators: example taxonomy */
|
||||
'placeholder' => __( 'Genres', 'acf' ),
|
||||
'type' => 'text',
|
||||
'key' => 'name',
|
||||
'name' => 'name',
|
||||
'class' => 'acf_plural_label',
|
||||
'prefix' => 'acf_taxonomy[labels]',
|
||||
'value' => $acf_taxonomy['labels']['name'],
|
||||
'required' => 1,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Singular Label', 'acf' ),
|
||||
/* translators: example taxonomy */
|
||||
'placeholder' => __( 'Genre', 'acf' ),
|
||||
'type' => 'text',
|
||||
'key' => 'singular_name',
|
||||
'name' => 'singular_name',
|
||||
'class' => 'acf_slugify_to_key acf_singular_label',
|
||||
'prefix' => 'acf_taxonomy[labels]',
|
||||
'value' => $acf_taxonomy['labels']['singular_name'],
|
||||
'required' => 1,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Taxonomy Key', 'acf' ),
|
||||
'instructions' => __( 'Lower case letters, underscores and dashes only, Max 20 characters.', 'acf' ),
|
||||
/* translators: example taxonomy */
|
||||
'placeholder' => __( 'genre', 'acf' ),
|
||||
'type' => 'text',
|
||||
'key' => 'taxonomy',
|
||||
'name' => 'taxonomy',
|
||||
'maxlength' => 20,
|
||||
'class' => 'acf_slugified_key',
|
||||
'prefix' => 'acf_taxonomy',
|
||||
'value' => $acf_taxonomy['taxonomy'],
|
||||
'required' => 1,
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
// Allow preselecting the linked post types based on previously created post type.
|
||||
$acf_use_post_type = acf_get_post_type_from_request_args( 'create-taxonomy' );
|
||||
if ( $acf_use_post_type && ! empty( $acf_use_post_type['post_type'] ) ) {
|
||||
$acf_taxonomy['object_type'] = array( $acf_use_post_type['post_type'] );
|
||||
}
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Post Types', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'object_type',
|
||||
'prefix' => 'acf_taxonomy',
|
||||
'value' => $acf_taxonomy['object_type'],
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'instructions' => __( 'One or many post types that can be classified with this taxonomy.', 'acf' ),
|
||||
),
|
||||
'div',
|
||||
'field'
|
||||
);
|
||||
|
||||
acf_render_field_wrap( array( 'type' => 'seperator' ) );
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'true_false',
|
||||
'key' => 'public',
|
||||
'name' => 'public',
|
||||
'prefix' => 'acf_taxonomy',
|
||||
'value' => $acf_taxonomy['public'],
|
||||
'label' => __( 'Public', 'acf' ),
|
||||
'instructions' => __( 'Makes a taxonomy visible on the frontend and in the admin dashboard.', 'acf' ),
|
||||
'ui' => true,
|
||||
'default' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'true_false',
|
||||
'key' => 'hierarchical',
|
||||
'name' => 'hierarchical',
|
||||
'class' => 'acf_hierarchical_switch',
|
||||
'prefix' => 'acf_taxonomy',
|
||||
'value' => $acf_taxonomy['hierarchical'],
|
||||
'label' => __( 'Hierarchical', 'acf' ),
|
||||
'instructions' => __( 'Hierarchical taxonomies can have descendants (like categories).', 'acf' ),
|
||||
'ui' => true,
|
||||
),
|
||||
'div'
|
||||
);
|
||||
|
||||
do_action( 'acf/taxonomy/basic_settings', $acf_taxonomy );
|
||||
|
||||
acf_render_field_wrap( array( 'type' => 'seperator' ) );
|
||||
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'label' => __( 'Advanced Configuration', 'acf' ),
|
||||
'instructions' => __( 'I know what I\'m doing, show me all the options.', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'key' => 'advanced_configuration',
|
||||
'name' => 'advanced_configuration',
|
||||
'prefix' => 'acf_taxonomy',
|
||||
'value' => $acf_taxonomy['advanced_configuration'],
|
||||
'ui' => 1,
|
||||
'class' => 'acf-advanced-settings-toggle',
|
||||
)
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="acf-hidden">
|
||||
<input type="hidden" name="acf_taxonomy[key]" value="<?php echo esc_attr( $acf_taxonomy['key'] ); ?>" />
|
||||
<input type="hidden" name="acf_taxonomy[import_source]" value="<?php echo esc_attr( $acf_taxonomy['import_source'] ); ?>" />
|
||||
<input type="hidden" name="acf_taxonomy[import_date]" value="<?php echo esc_attr( $acf_taxonomy['import_date'] ); ?>" />
|
||||
</div>
|
||||
<?php
|
@ -0,0 +1,18 @@
|
||||
<script>document.body.classList.add('acf-no-taxonomies');</script>
|
||||
<div class="acf-no-taxonomies-wrapper">
|
||||
<div class="acf-no-taxonomies-inner">
|
||||
<img src="<?php echo esc_url( acf_get_url( 'assets/images/empty-taxonomies.svg' ) ); ?>" />
|
||||
<h2><?php esc_html_e( 'Add Your First Taxonomy', 'acf' ); ?></h2>
|
||||
<p><?php esc_html_e( 'Create custom taxonomies to classify post type content', 'acf' ); ?></p>
|
||||
<a href="<?php echo esc_url( admin_url( 'post-new.php?post_type=acf-taxonomy' ) ); ?>" class="acf-btn"><i class="acf-icon acf-icon-plus"></i> <?php esc_html_e( 'Add Taxonomy', 'acf' ); ?></a>
|
||||
<p class="acf-small">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s url to getting started guide */
|
||||
__( 'New to ACF? Take a look at our <a href="%s" target="_blank">getting started guide</a>.', 'acf' ),
|
||||
acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/getting-started-with-acf/', 'docs', 'no-taxonomies' )
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
|
||||
|
||||
$browse_fields_tabs = array( 'popular' => __( 'Popular', 'acf' ) );
|
||||
$browse_fields_tabs = $browse_fields_tabs + acf_get_field_categories_i18n();
|
||||
?>
|
||||
<div class="acf-browse-fields-modal-wrap">
|
||||
<div class="acf-modal acf-browse-fields-modal">
|
||||
<div class="acf-field-picker">
|
||||
<div class="acf-modal-title">
|
||||
<h1><?php esc_html_e( 'Select Field Type', 'acf' ); ?></h1>
|
||||
<span class="acf-search-field-types-wrap">
|
||||
<input class="acf-search-field-types" type="search" placeholder="<?php esc_attr_e( 'Search fields...', 'acf' ); ?>" />
|
||||
</span>
|
||||
</div>
|
||||
<div class="acf-modal-content">
|
||||
<?php
|
||||
foreach ( $browse_fields_tabs as $name => $label ) {
|
||||
acf_render_field_wrap(
|
||||
array(
|
||||
'type' => 'tab',
|
||||
'label' => $label,
|
||||
'key' => 'acf_browse_fields_tabs',
|
||||
)
|
||||
);
|
||||
|
||||
printf(
|
||||
'<div class="acf-field-types-tab" data-category="%s"></div>',
|
||||
esc_attr( $name )
|
||||
);
|
||||
}
|
||||
?>
|
||||
<div class="acf-field-type-search-results"></div>
|
||||
<div class="acf-field-type-search-no-results">
|
||||
<img src="<?php echo esc_url( acf_get_url( 'assets/images/face-sad.svg' ) ); ?>" />
|
||||
<p class="acf-no-results-text">
|
||||
<?php
|
||||
printf(
|
||||
/* translators: %s: The invalid search term */
|
||||
acf_esc_html( __( "No search results for '%s'", 'acf' ) ),
|
||||
'<span class="acf-invalid-search-term"></span>'
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
<p>
|
||||
<?php
|
||||
$browse_popular_link = '<a href="#" class="acf-browse-popular-fields">' . esc_html( __( 'Popular fields', 'acf' ) ) . '</a>';
|
||||
printf(
|
||||
/* translators: %s: A link to the popular fields used in ACF */
|
||||
acf_esc_html( __( 'Try a different search term or browse %s', 'acf' ) ),
|
||||
$browse_popular_link //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||
);
|
||||
?>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acf-modal-toolbar acf-field-picker-toolbar">
|
||||
<div class="acf-field-picker-label">
|
||||
<input class="acf-insert-field-label" type="text" placeholder="<?php esc_attr_e( 'Field Label', 'acf' ); ?>" />
|
||||
</div>
|
||||
<div class="acf-field-picker-actions">
|
||||
<button class="button acf-cancel acf-modal-close"><?php esc_html_e( 'Cancel', 'acf' ); ?></button>
|
||||
<button class="acf-btn acf-select-field"><?php esc_html_e( 'Select Field', 'acf' ); ?></button>
|
||||
<a target="_blank" data-url-base="<?php echo esc_attr( acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'field-type-modal', '' ) ); ?>" class="acf-btn acf-btn-pro">
|
||||
<?php _e( 'Upgrade to PRO', 'acf' ); ?>
|
||||
</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acf-field-type-preview">
|
||||
<div class="field-type-info">
|
||||
<h2 class="field-type-name"></h2>
|
||||
<a target="_blank" data-url-base="<?php echo esc_attr( acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'field-type-modal', '' ) ); ?>" class="field-type-upgrade-to-unlock">
|
||||
<i class="acf-icon acf-icon-lock"></i>
|
||||
<?php _e( 'Available with ACF PRO', 'acf' ); ?>
|
||||
</a>
|
||||
<p class="field-type-desc"></p>
|
||||
<div class="field-type-preview-container">
|
||||
<img class="field-type-image" />
|
||||
</div>
|
||||
</div>
|
||||
<ul class="acf-hl field-type-links">
|
||||
<li>
|
||||
<a class="field-type-tutorial" href="#" target="_blank">
|
||||
<i class="acf-icon acf-icon-play"></i>
|
||||
<?php esc_html_e( 'Tutorial', 'acf' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="field-type-doc" href="#" target="_blank">
|
||||
<i class="acf-icon acf-icon-document"></i>
|
||||
<?php esc_html_e( 'Documentation', 'acf' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acf-modal-backdrop acf-modal-close"></div>
|
||||
</div>
|
@ -0,0 +1,62 @@
|
||||
<?php
|
||||
global $title, $post_new_file, $post_type_object, $post;
|
||||
$acf_title_placeholder = apply_filters( 'enter_title_here', __( 'Add title' ), $post );
|
||||
$acf_title = $post->post_title;
|
||||
$acf_post_type = is_object( $post_type_object ) ? $post_type_object->name : '';
|
||||
$acf_publish_btn_name = 'save';
|
||||
|
||||
if ( 'publish' !== $post->post_status ) {
|
||||
$acf_publish_btn_name = 'publish';
|
||||
}
|
||||
|
||||
if ( 'acf-field-group' === $acf_post_type ) {
|
||||
$acf_use_post_type = acf_get_post_type_from_request_args( 'add-fields' );
|
||||
$acf_use_taxonomy = acf_get_taxonomy_from_request_args( 'add-fields' );
|
||||
|
||||
/* translators: %s - singular label of post type/taxonomy, i.e. "Movie"/"Genre" */
|
||||
$acf_prefilled_title = (string) apply_filters( 'acf/field_group/prefill_title', __( '%s fields', 'acf' ) );
|
||||
|
||||
if ( $acf_use_post_type && ! empty( $acf_use_post_type['labels']['singular_name'] ) ) {
|
||||
$acf_prefilled_title = sprintf( $acf_prefilled_title, $acf_use_post_type['labels']['singular_name'] );
|
||||
} elseif ( $acf_use_taxonomy && ! empty( $acf_use_taxonomy['labels']['singular_name'] ) ) {
|
||||
$acf_prefilled_title = sprintf( $acf_prefilled_title, $acf_use_taxonomy['labels']['singular_name'] );
|
||||
} else {
|
||||
$acf_prefilled_title = false;
|
||||
}
|
||||
|
||||
if ( empty( $acf_title ) && $acf_prefilled_title ) {
|
||||
$acf_title = $acf_prefilled_title;
|
||||
}
|
||||
}
|
||||
?>
|
||||
<div class="acf-headerbar acf-headerbar-field-editor">
|
||||
<div class="acf-headerbar-inner">
|
||||
|
||||
<div class="acf-headerbar-content">
|
||||
<h1 class="acf-page-title">
|
||||
<?php
|
||||
echo esc_html( $title );
|
||||
?>
|
||||
</h1>
|
||||
<?php if ( 'acf-field-group' === $acf_post_type ) : ?>
|
||||
<div class="acf-title-wrap">
|
||||
<label class="screen-reader-text" id="title-prompt-text" for="title"><?php echo esc_html( $acf_title_placeholder ); ?></label>
|
||||
<input form="post" type="text" name="post_title" size="30" value="<?php echo esc_attr( $acf_title ); ?>" id="title" class="acf-headerbar-title-field" spellcheck="true" autocomplete="off" placeholder="<?php esc_attr_e( 'Field Group Title', 'acf' ); ?>" />
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="acf-headerbar-actions" id="submitpost">
|
||||
<?php if ( 'acf-field-group' === $acf_post_type ) : ?>
|
||||
<a href="#" class="acf-btn acf-btn-secondary add-field">
|
||||
<i class="acf-icon acf-icon-plus"></i>
|
||||
<?php esc_html_e( 'Add Field', 'acf' ); ?>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
<button form="post" class="acf-btn acf-publish" name="<?php echo esc_attr( $acf_publish_btn_name ); ?>" type="submit">
|
||||
<?php esc_html_e( 'Save Changes', 'acf' ); ?>
|
||||
</button>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
@ -0,0 +1,33 @@
|
||||
<?php
|
||||
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
|
||||
|
||||
global $post_type, $post_type_object, $acf_page_title;
|
||||
$post_new_file = sprintf(
|
||||
'post-new.php?post_type=%s',
|
||||
is_string( $post_type ) ? $post_type : 'acf-field-group'
|
||||
);
|
||||
|
||||
$page_title = false;
|
||||
if ( isset( $acf_page_title ) ) {
|
||||
$page_title = $acf_page_title;
|
||||
} elseif ( is_object( $post_type_object ) ) {
|
||||
$page_title = $post_type_object->labels->name;
|
||||
}
|
||||
if ( $page_title ) {
|
||||
?>
|
||||
<div class="acf-headerbar">
|
||||
|
||||
<h1 class="acf-page-title">
|
||||
<?php
|
||||
echo esc_html( $page_title );
|
||||
?>
|
||||
</h1>
|
||||
|
||||
<?php
|
||||
if ( ! empty( $post_type_object ) && current_user_can( $post_type_object->cap->create_posts ) ) {
|
||||
echo ' <a href="' . esc_url( admin_url( $post_new_file ) ) . '" class="acf-btn acf-btn-sm"><i class="acf-icon acf-icon-plus"></i>' . esc_html( $post_type_object->labels->add_new ) . '</a>';
|
||||
}
|
||||
?>
|
||||
|
||||
</div>
|
||||
<?php } ?>
|
@ -0,0 +1,144 @@
|
||||
<?php
|
||||
//phpcs:disable WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedVariableFound -- included template file.
|
||||
/**
|
||||
* The template for displaying admin navigation.
|
||||
*
|
||||
* @date 27/3/20
|
||||
* @since 5.9.0
|
||||
*/
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
global $submenu, $parent_file, $submenu_file, $plugin_page, $pagenow, $acf_page_title;
|
||||
|
||||
// Vars.
|
||||
$parent_slug = 'edit.php?post_type=acf-field-group';
|
||||
|
||||
// Generate array of navigation items.
|
||||
$more_items = array();
|
||||
$core_tabs = array();
|
||||
if ( isset( $submenu[ $parent_slug ] ) ) {
|
||||
foreach ( $submenu[ $parent_slug ] as $i => $sub_item ) {
|
||||
|
||||
// Check user can access page.
|
||||
if ( ! current_user_can( $sub_item[1] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Define tab.
|
||||
$menu_item = array(
|
||||
'text' => $sub_item[0],
|
||||
'url' => $sub_item[2],
|
||||
);
|
||||
|
||||
// Convert submenu slug "test" to "$parent_slug&page=test".
|
||||
if ( ! strpos( $sub_item[2], '.php' ) ) {
|
||||
$menu_item['url'] = add_query_arg( array( 'page' => $sub_item[2] ), $parent_slug );
|
||||
$menu_item['class'] = $sub_item[2];
|
||||
} else {
|
||||
// Build class from URL.
|
||||
$menu_item['class'] = str_replace( 'edit.php?post_type=', '', $sub_item[2] );
|
||||
}
|
||||
|
||||
// Detect active state.
|
||||
if ( $submenu_file === $sub_item[2] || $plugin_page === $sub_item[2] ) {
|
||||
$menu_item['is_active'] = true;
|
||||
}
|
||||
|
||||
// Handle "Add New" versions of edit page.
|
||||
if ( str_replace( 'edit', 'post-new', $sub_item[2] ) === $submenu_file ) {
|
||||
$menu_item['is_active'] = true;
|
||||
}
|
||||
|
||||
// Flag core tabs.
|
||||
$core_tabs_classes = array_merge( acf_get_internal_post_types(), array( 'acf-tools', 'acf-settings-updates' ) );
|
||||
if ( in_array( $menu_item['class'], $core_tabs_classes, true ) ) {
|
||||
$core_tabs[] = $menu_item;
|
||||
} else {
|
||||
$more_items[] = $menu_item;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the admin navigation more items.
|
||||
*
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $more_items The array of navigation tabs.
|
||||
*/
|
||||
$more_items = apply_filters( 'acf/admin/toolbar', $more_items );
|
||||
|
||||
// Bail early if set to false.
|
||||
if ( $core_tabs === false ) {
|
||||
return;
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-admin-toolbar">
|
||||
|
||||
<a href="<?php echo admin_url( 'edit.php?post_type=acf-field-group' ); ?>" class="acf-logo">
|
||||
<img src="<?php echo acf_get_url( 'assets/images/acf-logo.svg' ); ?>" alt="<?php esc_attr_e( 'Advanced Custom Fields logo', 'acf' ); ?>">
|
||||
<?php if ( defined( 'ACF_PRO' ) && ACF_PRO ) { ?>
|
||||
<div class="acf-pro-label">PRO</div>
|
||||
<?php } ?>
|
||||
</a>
|
||||
|
||||
<h2><?php echo acf_get_setting( 'name' ); ?></h2>
|
||||
<?php
|
||||
foreach ( $core_tabs as $menu_item ) {
|
||||
$classname = ! empty( $menu_item['class'] ) ? $menu_item['class'] : $menu_item['text'];
|
||||
printf(
|
||||
'<a class="acf-tab%s %s" href="%s"><i class="acf-icon"></i>%s</a>',
|
||||
! empty( $menu_item['is_active'] ) ? ' is-active' : '',
|
||||
'acf-header-tab-' . acf_slugify( $classname ),
|
||||
esc_url( $menu_item['url'] ),
|
||||
acf_esc_html( $menu_item['text'] )
|
||||
);
|
||||
}
|
||||
?>
|
||||
<?php if ( $more_items ) { ?>
|
||||
<div class="acf-more acf-header-tab-acf-more" tabindex="0">
|
||||
<span class="acf-tab acf-more-tab"><i class="acf-icon acf-icon-more"></i><?php esc_html_e( 'More', 'acf' ); ?> <i class="acf-icon acf-icon-dropdown"></i></span>
|
||||
<ul>
|
||||
<?php
|
||||
foreach ( $more_items as $more_item ) {
|
||||
$classname = ! empty( $more_item['class'] ) ? $more_item['class'] : $more_item['text'];
|
||||
printf(
|
||||
'<li><a class="acf-tab%s %s" href="%s"><i class="acf-icon"></i>%s</a></li>',
|
||||
! empty( $more_item['is_active'] ) ? ' is-active' : '',
|
||||
'acf-header-tab-' . acf_slugify( $classname ),
|
||||
esc_url( $more_item['url'] ),
|
||||
acf_esc_html( $more_item['text'] )
|
||||
);
|
||||
}
|
||||
?>
|
||||
</ul>
|
||||
</div>
|
||||
<?php } ?>
|
||||
|
||||
<?php if ( ! defined( 'ACF_PRO' ) || ! ACF_PRO ) : ?>
|
||||
<a target="_blank" href="<?php echo acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/pro/', 'ACF upgrade', 'header' ); ?>" class="btn-upgrade acf-admin-toolbar-upgrade-btn">
|
||||
<i class="acf-icon acf-icon-stars"></i>
|
||||
<p><?php _e( 'Unlock Extra Features with ACF PRO', 'acf' ); ?></p>
|
||||
</a>
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
|
||||
<?php
|
||||
|
||||
global $plugin_page;
|
||||
$screen = get_current_screen();
|
||||
|
||||
if ( ! in_array( $screen->id, acf_get_internal_post_types(), true ) ) {
|
||||
if ( $plugin_page == 'acf-tools' ) {
|
||||
$acf_page_title = __( 'Tools', 'acf' );
|
||||
} elseif ( $plugin_page == 'acf-settings-updates' ) {
|
||||
$acf_page_title = __( 'Updates', 'acf' );
|
||||
}
|
||||
acf_get_view( 'global/header' );
|
||||
}
|
||||
?>
|
@ -0,0 +1,30 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* html-admin-tools
|
||||
*
|
||||
* View to output admin tools for both archive and single
|
||||
*
|
||||
* @date 20/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param string $screen_id The screen ID used to display metaboxes
|
||||
* @param string $active The active Tool
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
$class = $active ? 'single' : 'grid';
|
||||
$tool = $active ? ' tool-' . $active : '';
|
||||
?>
|
||||
<div id="acf-admin-tools" class="wrap<?php echo esc_attr( $tool ); ?>">
|
||||
|
||||
<h1><?php _e( 'Tools', 'acf' ); ?> <?php
|
||||
if ( $active ) :
|
||||
?>
|
||||
<a class="page-title-action" href="<?php echo acf_get_admin_tools_url(); ?>"><?php _e( 'Back to all tools', 'acf' ); ?></a><?php endif; ?></h1>
|
||||
|
||||
<div class="acf-meta-box-wrap -<?php echo $class; ?>">
|
||||
<?php do_meta_boxes( $screen_id, 'normal', '' ); ?>
|
||||
</div>
|
||||
|
||||
</div>
|
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Network Admin Database Upgrade
|
||||
*
|
||||
* Shows the databse upgrade process.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
* @param void
|
||||
*/
|
||||
|
||||
?>
|
||||
<style type="text/css">
|
||||
|
||||
/* hide steps */
|
||||
.show-on-complete {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="acf-upgrade-wrap" class="wrap">
|
||||
|
||||
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
|
||||
|
||||
<p><?php echo sprintf( __( 'The following sites require a DB upgrade. Check the ones you want to update and then click %s.', 'acf' ), '"' . __( 'Upgrade Sites', 'acf' ) . '"' ); ?></p>
|
||||
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites"></p>
|
||||
|
||||
<table class="wp-list-table widefat">
|
||||
<thead>
|
||||
<tr>
|
||||
<td class="manage-column check-column" scope="col">
|
||||
<input type="checkbox" id="sites-select-all">
|
||||
</td>
|
||||
<th class="manage-column" scope="col" style="width:33%;">
|
||||
<label for="sites-select-all"><?php _e( 'Site', 'acf' ); ?></label>
|
||||
</th>
|
||||
<th><?php _e( 'Description', 'acf' ); ?></th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tfoot>
|
||||
<tr>
|
||||
<td class="manage-column check-column" scope="col">
|
||||
<input type="checkbox" id="sites-select-all-2">
|
||||
</td>
|
||||
<th class="manage-column" scope="col">
|
||||
<label for="sites-select-all-2"><?php _e( 'Site', 'acf' ); ?></label>
|
||||
</th>
|
||||
<th><?php _e( 'Description', 'acf' ); ?></th>
|
||||
</tr>
|
||||
</tfoot>
|
||||
<tbody id="the-list">
|
||||
<?php
|
||||
|
||||
$sites = acf_get_sites();
|
||||
if ( $sites ) :
|
||||
foreach ( $sites as $i => $site ) :
|
||||
|
||||
// switch blog
|
||||
switch_to_blog( $site['blog_id'] );
|
||||
|
||||
?>
|
||||
<tr
|
||||
<?php
|
||||
if ( $i % 2 == 0 ) :
|
||||
?>
|
||||
class="alternate"<?php endif; ?>>
|
||||
<th class="check-column" scope="row">
|
||||
<?php if ( acf_has_upgrade() ) : ?>
|
||||
<input type="checkbox" value="<?php echo $site['blog_id']; ?>" name="checked[]">
|
||||
<?php endif; ?>
|
||||
</th>
|
||||
<td>
|
||||
<strong><?php echo get_bloginfo( 'name' ); ?></strong><br /><?php echo home_url(); ?>
|
||||
</td>
|
||||
<td>
|
||||
<?php if ( acf_has_upgrade() ) : ?>
|
||||
<span class="response"><?php printf( __( 'Site requires database upgrade from %1$s to %2$s', 'acf' ), acf_get_db_version(), ACF_VERSION ); ?></span>
|
||||
<?php else : ?>
|
||||
<?php _e( 'Site is up to date', 'acf' ); ?>
|
||||
<?php endif; ?>
|
||||
</td>
|
||||
</tr>
|
||||
<?php
|
||||
|
||||
// restore
|
||||
restore_current_blog();
|
||||
|
||||
endforeach;
|
||||
endif;
|
||||
|
||||
?>
|
||||
</tbody>
|
||||
</table>
|
||||
|
||||
<p><input type="submit" name="upgrade" value="<?php _e( 'Upgrade Sites', 'acf' ); ?>" class="button" id="upgrade-sites-2"></p>
|
||||
<p class="show-on-complete"><?php echo sprintf( __( 'Database Upgrade complete. <a href="%s">Return to network dashboard</a>', 'acf' ), network_admin_url() ); ?></p>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
|
||||
var upgrader = new acf.Model({
|
||||
events: {
|
||||
'click #upgrade-sites': 'onClick',
|
||||
'click #upgrade-sites-2': 'onClick'
|
||||
},
|
||||
$inputs: function(){
|
||||
return $('#the-list input:checked');
|
||||
},
|
||||
onClick: function( e, $el ){
|
||||
|
||||
// prevent default
|
||||
e.preventDefault();
|
||||
|
||||
// bail early if no selection
|
||||
if( !this.$inputs().length ) {
|
||||
return alert('<?php _e( 'Please select at least one site to upgrade.', 'acf' ); ?>');
|
||||
}
|
||||
|
||||
// confirm action
|
||||
if( !confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>") ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// upgrade
|
||||
this.upgrade();
|
||||
},
|
||||
upgrade: function(){
|
||||
|
||||
// vars
|
||||
var $inputs = this.$inputs();
|
||||
|
||||
// bail early if no sites selected
|
||||
if( !$inputs.length ) {
|
||||
return this.complete();
|
||||
}
|
||||
|
||||
// disable buttons
|
||||
$('.button').prop('disabled', true);
|
||||
|
||||
// vars
|
||||
var $input = $inputs.first();
|
||||
var $row = $input.closest('tr');
|
||||
var text = '';
|
||||
var success = false;
|
||||
|
||||
// show loading
|
||||
$row.find('.response').html('<i class="acf-loading"></i></span> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?>');
|
||||
|
||||
// send ajax request to upgrade DB
|
||||
$.ajax({
|
||||
url: acf.get('ajaxurl'),
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
data: acf.prepareForAjax({
|
||||
action: 'acf/ajax/upgrade',
|
||||
blog_id: $input.val()
|
||||
}),
|
||||
success: function( json ){
|
||||
success = true;
|
||||
$input.remove();
|
||||
text = '<?php _e( 'Upgrade complete.', 'acf' ); ?>';
|
||||
},
|
||||
error: function( jqXHR, textStatus, errorThrown ){
|
||||
text = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
|
||||
if( error = acf.getXhrError(jqXHR) ) {
|
||||
text += ' <code>' + error + '</code>';
|
||||
}
|
||||
},
|
||||
complete: this.proxy(function(){
|
||||
|
||||
// display text
|
||||
$row.find('.response').html( text );
|
||||
|
||||
// if successful upgrade, proceed to next site. Otherwise, skip to complete.
|
||||
if( success ) {
|
||||
this.upgrade();
|
||||
} else {
|
||||
this.complete();
|
||||
}
|
||||
})
|
||||
});
|
||||
},
|
||||
complete: function(){
|
||||
|
||||
// enable buttons
|
||||
$('.button').prop('disabled', false);
|
||||
|
||||
// show message
|
||||
$('.show-on-complete').show();
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
</div>
|
@ -0,0 +1,49 @@
|
||||
<?php
|
||||
|
||||
// calculate add-ons (non pro only)
|
||||
$plugins = array();
|
||||
|
||||
if ( ! acf_get_setting( 'pro' ) ) {
|
||||
|
||||
if ( is_plugin_active( 'acf-repeater/acf-repeater.php' ) ) {
|
||||
$plugins[] = __( 'Repeater', 'acf' );
|
||||
}
|
||||
if ( is_plugin_active( 'acf-flexible-content/acf-flexible-content.php' ) ) {
|
||||
$plugins[] = __( 'Flexible Content', 'acf' );
|
||||
}
|
||||
if ( is_plugin_active( 'acf-gallery/acf-gallery.php' ) ) {
|
||||
$plugins[] = __( 'Gallery', 'acf' );
|
||||
}
|
||||
if ( is_plugin_active( 'acf-options-page/acf-options-page.php' ) ) {
|
||||
$plugins[] = __( 'Options Page', 'acf' );
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div id="acf-upgrade-notice" class="notice">
|
||||
<div class="notice-container">
|
||||
<div class="col-content">
|
||||
<img src="<?php echo acf_get_url( 'assets/images/acf-logo.png' ); ?>" />
|
||||
<h2><?php _e( 'Database Upgrade Required', 'acf' ); ?></h2>
|
||||
<p><?php printf( __( 'Thank you for updating to %1$s v%2$s!', 'acf' ), acf_get_setting( 'name' ), acf_get_setting( 'version' ) ); ?><br /><?php _e( 'This version contains improvements to your database and requires an upgrade.', 'acf' ); ?></p>
|
||||
<?php if ( ! empty( $plugins ) ) : ?>
|
||||
<p><?php printf( __( 'Please also check all premium add-ons (%s) are updated to the latest version.', 'acf' ), implode( ', ', $plugins ) ); ?></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="col-actions">
|
||||
<a id="acf-upgrade-button" href="<?php echo $button_url; ?>" class="acf-btn"><?php echo $button_text; ?></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php if ( $confirm ) : ?>
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
|
||||
$("#acf-upgrade-button").on("click", function(){
|
||||
return confirm("<?php _e( 'It is strongly recommended that you backup your database before proceeding. Are you sure you wish to run the updater now?', 'acf' ); ?>");
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
<?php endif; ?>
|
@ -0,0 +1,97 @@
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Admin Database Upgrade
|
||||
*
|
||||
* Shows the databse upgrade process.
|
||||
*
|
||||
* @date 24/8/18
|
||||
* @since 5.7.4
|
||||
* @param void
|
||||
*/
|
||||
|
||||
?>
|
||||
<style type="text/css">
|
||||
|
||||
/* hide steps */
|
||||
.step-1,
|
||||
.step-2,
|
||||
.step-3 {
|
||||
display: none;
|
||||
}
|
||||
|
||||
</style>
|
||||
<div id="acf-upgrade-wrap" class="wrap">
|
||||
|
||||
<h1><?php _e( 'Upgrade Database', 'acf' ); ?></h1>
|
||||
|
||||
<?php if ( acf_has_upgrade() ) : ?>
|
||||
|
||||
<p><?php _e( 'Reading upgrade tasks...', 'acf' ); ?></p>
|
||||
<p class="step-1"><i class="acf-loading"></i> <?php printf( __( 'Upgrading data to version %s', 'acf' ), ACF_VERSION ); ?></p>
|
||||
<p class="step-2"></p>
|
||||
<p class="step-3"><?php echo sprintf( __( 'Database upgrade complete. <a href="%s">See what\'s new</a>', 'acf' ), admin_url( 'edit.php?post_type=acf-field-group' ) ); ?></p>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function($) {
|
||||
|
||||
var upgrader = new acf.Model({
|
||||
initialize: function(){
|
||||
|
||||
// allow user to read message for 1 second
|
||||
this.setTimeout( this.upgrade, 1000 );
|
||||
},
|
||||
upgrade: function(){
|
||||
|
||||
// show step 1
|
||||
$('.step-1').show();
|
||||
|
||||
// vars
|
||||
var response = '';
|
||||
var success = false;
|
||||
|
||||
// send ajax request to upgrade DB
|
||||
$.ajax({
|
||||
url: acf.get('ajaxurl'),
|
||||
dataType: 'json',
|
||||
type: 'post',
|
||||
data: acf.prepareForAjax({
|
||||
action: 'acf/ajax/upgrade'
|
||||
}),
|
||||
success: function( json ){
|
||||
success = true;
|
||||
},
|
||||
error: function( jqXHR, textStatus, errorThrown ){
|
||||
response = '<?php _e( 'Upgrade failed.', 'acf' ); ?>';
|
||||
if( error = acf.getXhrError(jqXHR) ) {
|
||||
response += ' <code>' + error + '</code>';
|
||||
}
|
||||
},
|
||||
complete: this.proxy(function(){
|
||||
|
||||
// remove spinner
|
||||
$('.acf-loading').hide();
|
||||
|
||||
// display response
|
||||
if( response ) {
|
||||
$('.step-2').show().html( response );
|
||||
}
|
||||
|
||||
// display success
|
||||
if( success ) {
|
||||
$('.step-3').show();
|
||||
}
|
||||
})
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
})(jQuery);
|
||||
</script>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<p><?php _e( 'No updates available.', 'acf' ); ?></p>
|
||||
|
||||
<?php endif; ?>
|
||||
</div>
|
@ -0,0 +1,110 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_Check_Screen' ) ) :
|
||||
|
||||
class ACF_Ajax_Check_Screen extends ACF_Ajax {
|
||||
|
||||
/** @var string The AJAX action name. */
|
||||
var $action = 'acf/ajax/check_screen';
|
||||
|
||||
/** @var bool Prevents access for non-logged in users. */
|
||||
var $public = false;
|
||||
|
||||
/**
|
||||
* get_response
|
||||
*
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return mixed The response data or WP_Error.
|
||||
*/
|
||||
function get_response( $request ) {
|
||||
|
||||
// vars
|
||||
$args = wp_parse_args(
|
||||
$this->request,
|
||||
array(
|
||||
'screen' => '',
|
||||
'post_id' => 0,
|
||||
'ajax' => true,
|
||||
'exists' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => array(),
|
||||
'style' => '',
|
||||
);
|
||||
|
||||
// get field groups
|
||||
$field_groups = acf_get_field_groups( $args );
|
||||
|
||||
// loop through field groups
|
||||
if ( $field_groups ) {
|
||||
foreach ( $field_groups as $i => $field_group ) {
|
||||
|
||||
// vars
|
||||
$item = array(
|
||||
'id' => 'acf-' . $field_group['key'],
|
||||
'key' => $field_group['key'],
|
||||
'title' => $field_group['title'],
|
||||
'position' => $field_group['position'],
|
||||
'classes' => postbox_classes( 'acf-' . $field_group['key'], $args['screen'] ),
|
||||
'style' => $field_group['style'],
|
||||
'label' => $field_group['label_placement'],
|
||||
'edit' => acf_get_field_group_edit_link( $field_group['ID'] ),
|
||||
'html' => '',
|
||||
);
|
||||
|
||||
$hidden_metaboxes = get_hidden_meta_boxes( $args['screen'] );
|
||||
|
||||
if ( is_array( $hidden_metaboxes ) && in_array( $item['id'], $hidden_metaboxes ) ) {
|
||||
$item['classes'] = trim( $item['classes'] . ' hide-if-js' );
|
||||
}
|
||||
|
||||
// append html if doesnt already exist on page
|
||||
if ( ! in_array( $field_group['key'], $args['exists'] ) ) {
|
||||
|
||||
// load fields
|
||||
$fields = acf_get_fields( $field_group );
|
||||
|
||||
// get field HTML
|
||||
ob_start();
|
||||
|
||||
// render
|
||||
acf_render_fields( $fields, $args['post_id'], 'div', $field_group['instruction_placement'] );
|
||||
|
||||
$item['html'] = ob_get_clean();
|
||||
}
|
||||
|
||||
// append
|
||||
$response['results'][] = $item;
|
||||
}
|
||||
|
||||
// Get style from first field group.
|
||||
$response['style'] = acf_get_field_group_style( $field_groups[0] );
|
||||
}
|
||||
|
||||
// Custom metabox order.
|
||||
if ( $this->get( 'screen' ) == 'post' ) {
|
||||
$response['sorted'] = get_user_option( 'meta-box-order_' . $this->get( 'post_type' ) );
|
||||
}
|
||||
|
||||
// return
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Ajax_Check_Screen' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_Local_JSON_Diff' ) ) :
|
||||
|
||||
class ACF_Ajax_Local_JSON_Diff extends ACF_Ajax {
|
||||
|
||||
/**
|
||||
* The AJAX action name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $action = 'acf/ajax/local_json_diff';
|
||||
|
||||
/**
|
||||
* Prevents access for non-logged in users.
|
||||
*
|
||||
* @var bool
|
||||
*/
|
||||
public $public = false;
|
||||
|
||||
/**
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return array|WP_Error The response data or WP_Error.
|
||||
*/
|
||||
public function get_response( $request ) {
|
||||
$json = array();
|
||||
|
||||
// Extract props.
|
||||
$id = isset( $request['id'] ) ? intval( $request['id'] ) : 0;
|
||||
|
||||
// Bail early if missing props.
|
||||
if ( ! $id ) {
|
||||
return new WP_Error( 'acf_invalid_param', __( 'Invalid field group parameter(s).', 'acf' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $id );
|
||||
if ( ! in_array( $post_type, acf_get_internal_post_types(), true ) ) {
|
||||
return new WP_Error( 'acf_invalid_post_type', __( 'Invalid post type selected for review.', 'acf' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Disable filters and load the post directly from database.
|
||||
acf_disable_filters();
|
||||
|
||||
$post = acf_get_internal_post_type( $id, $post_type );
|
||||
if ( ! $post ) {
|
||||
return new WP_Error( 'acf_invalid_id', __( 'Invalid post ID.', 'acf' ), array( 'status' => 404 ) );
|
||||
}
|
||||
|
||||
// Field groups also load in fields.
|
||||
if ( 'acf-field-group' === $post_type ) {
|
||||
$post['fields'] = acf_get_fields( $post );
|
||||
}
|
||||
|
||||
$post['modified'] = get_post_modified_time( 'U', true, $post['ID'] );
|
||||
$post = acf_prepare_internal_post_type_for_export( $post, $post_type );
|
||||
|
||||
// Load local field group file.
|
||||
$files = acf_get_local_json_files( $post_type );
|
||||
$key = $post['key'];
|
||||
if ( ! isset( $files[ $key ] ) ) {
|
||||
return new WP_Error( 'acf_cannot_compare', __( 'Sorry, this post is unavailable for diff comparison.', 'acf' ), array( 'status' => 404 ) );
|
||||
}
|
||||
$local_post = json_decode( file_get_contents( $files[ $key ] ), true );
|
||||
|
||||
// Render diff HTML.
|
||||
$date_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
|
||||
$date_template = __( 'Last updated: %s', 'acf' );
|
||||
$json['html'] = '
|
||||
<div class="acf-diff">
|
||||
<div class="acf-diff-title">
|
||||
<div class="acf-diff-title-left">
|
||||
<strong>' . __( 'Original', 'acf' ) . '</strong>
|
||||
<span>' . sprintf( $date_template, wp_date( $date_format, $post['modified'] ) ) . '</span>
|
||||
</div>
|
||||
<div class="acf-diff-title-right">
|
||||
<strong>' . __( 'JSON (newer)', 'acf' ) . '</strong>
|
||||
<span>' . sprintf( $date_template, wp_date( $date_format, $local_post['modified'] ) ) . '</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="acf-diff-content">
|
||||
' . wp_text_diff( acf_json_encode( $post ), acf_json_encode( $local_post ) ) . '
|
||||
</div>
|
||||
</div>';
|
||||
return $json;
|
||||
}
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Ajax_Local_JSON_Diff' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_Query_Users' ) ) :
|
||||
|
||||
class ACF_Ajax_Query_Users extends ACF_Ajax_Query {
|
||||
|
||||
/** @var string The AJAX action name. */
|
||||
var $action = 'acf/ajax/query_users';
|
||||
|
||||
/**
|
||||
* init_request
|
||||
*
|
||||
* Called at the beginning of a request to setup properties.
|
||||
*
|
||||
* @date 23/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return void
|
||||
*/
|
||||
function init_request( $request ) {
|
||||
parent::init_request( $request );
|
||||
|
||||
// Customize query.
|
||||
add_filter( 'user_search_columns', array( $this, 'filter_search_columns' ), 10, 3 );
|
||||
|
||||
/**
|
||||
* Fires when a request is made.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $request The query request.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
*/
|
||||
do_action( 'acf/ajax/query_users/init', $request, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_args
|
||||
*
|
||||
* Returns an array of args for this query.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return array
|
||||
*/
|
||||
function get_args( $request ) {
|
||||
$args = parent::get_args( $request );
|
||||
$args['number'] = $this->per_page;
|
||||
$args['paged'] = $this->page;
|
||||
if ( $this->is_search ) {
|
||||
$args['search'] = "*{$this->search}*";
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the query args.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $args The query args.
|
||||
* @param array $request The query request.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
*/
|
||||
return apply_filters( 'acf/ajax/query_users/args', $args, $request, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares args for the get_results() method.
|
||||
*
|
||||
* @date 23/3/20
|
||||
* @since 5.8.9
|
||||
*
|
||||
* @param array args The query args.
|
||||
* @return array
|
||||
*/
|
||||
function prepare_args( $args ) {
|
||||
|
||||
// Parse pagination args that may have been modified.
|
||||
if ( isset( $args['users_per_page'] ) ) {
|
||||
$this->per_page = intval( $args['users_per_page'] );
|
||||
unset( $args['users_per_page'] );
|
||||
|
||||
} elseif ( isset( $args['number'] ) ) {
|
||||
$this->per_page = intval( $args['number'] );
|
||||
}
|
||||
|
||||
if ( isset( $args['paged'] ) ) {
|
||||
$this->page = intval( $args['paged'] );
|
||||
unset( $args['paged'] );
|
||||
}
|
||||
|
||||
// Set pagination args for fine control.
|
||||
$args['number'] = $this->per_page;
|
||||
$args['offset'] = $this->per_page * ( $this->page - 1 );
|
||||
$args['count_total'] = true;
|
||||
return $args;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_results
|
||||
*
|
||||
* Returns an array of results for the given args.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array args The query args.
|
||||
* @return array
|
||||
*/
|
||||
function get_results( $args ) {
|
||||
$results = array();
|
||||
|
||||
// Prepare args for quey.
|
||||
$args = $this->prepare_args( $args );
|
||||
|
||||
// Get result groups.
|
||||
if ( ! empty( $args['role__in'] ) ) {
|
||||
$roles = acf_get_user_role_labels( $args['role__in'] );
|
||||
} else {
|
||||
$roles = acf_get_user_role_labels();
|
||||
}
|
||||
|
||||
// Return a flat array of results when searching or when queriying one group only.
|
||||
if ( $this->is_search || count( $roles ) === 1 ) {
|
||||
|
||||
// Query users and append to results.
|
||||
$wp_user_query = new WP_User_Query( $args );
|
||||
$users = (array) $wp_user_query->get_results();
|
||||
$total_users = $wp_user_query->get_total();
|
||||
foreach ( $users as $user ) {
|
||||
$results[] = $this->get_result( $user );
|
||||
}
|
||||
|
||||
// Determine if more results exist.
|
||||
// As this query does not return grouped results, the calculation can be exact (">").
|
||||
$this->more = ( $total_users > count( $users ) + $args['offset'] );
|
||||
|
||||
// Otherwise, group results via role.
|
||||
} else {
|
||||
|
||||
// Unset args that will interfer with query results.
|
||||
unset( $args['role__in'], $args['role__not_in'] );
|
||||
|
||||
// Loop over each role.
|
||||
foreach ( $roles as $role => $role_label ) {
|
||||
|
||||
// Query users (for this role only).
|
||||
$args['role'] = $role;
|
||||
$wp_user_query = new WP_User_Query( $args );
|
||||
$users = (array) $wp_user_query->get_results();
|
||||
$total_users = $wp_user_query->get_total();
|
||||
|
||||
// acf_log( $args );
|
||||
// acf_log( '- ', count($users) );
|
||||
// acf_log( '- ', $total_users );
|
||||
|
||||
// If users were found for this query...
|
||||
if ( $users ) {
|
||||
|
||||
// Append optgroup of results.
|
||||
$role_results = array();
|
||||
foreach ( $users as $user ) {
|
||||
$role_results[] = $this->get_result( $user );
|
||||
}
|
||||
$results[] = array(
|
||||
'text' => $role_label,
|
||||
'children' => $role_results,
|
||||
);
|
||||
|
||||
// End loop when enough results have been found.
|
||||
if ( count( $users ) === $args['number'] ) {
|
||||
|
||||
// Determine if more results exist.
|
||||
// As this query does return grouped results, the calculation is best left fuzzy to avoid querying the next group (">=").
|
||||
$this->more = ( $total_users >= count( $users ) + $args['offset'] );
|
||||
break;
|
||||
|
||||
// Otherwise, modify the args so that the next query can continue on correctly.
|
||||
} else {
|
||||
$args['offset'] = 0;
|
||||
$args['number'] -= count( $users );
|
||||
}
|
||||
|
||||
// If no users were found (for the current pagination args), but there were users found for previous pages...
|
||||
// Modify the args so that the next query is offset slightly less (the number of total users) and can continue on correctly.
|
||||
} elseif ( $total_users ) {
|
||||
$args['offset'] -= $total_users;
|
||||
continue;
|
||||
|
||||
// Ignore roles that will never return a result.
|
||||
} else {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the query results.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $results The query results.
|
||||
* @param array $args The query args.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
*/
|
||||
return apply_filters( 'acf/ajax/query_users/results', $results, $args, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* get_result
|
||||
*
|
||||
* Returns a single result for the given item object.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param mixed $item A single item from the queried results.
|
||||
* @return string
|
||||
*/
|
||||
function get_result( $user ) {
|
||||
$item = acf_get_user_result( $user );
|
||||
|
||||
/**
|
||||
* Filters the result item.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $item The choice id and text.
|
||||
* @param ACF_User $user The user object.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
*/
|
||||
return apply_filters( 'acf/ajax/query_users/result', $item, $user, $this );
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the WP_User_Query search columns.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $columns An array of column names to be searched.
|
||||
* @param string $search The search term.
|
||||
* @param WP_User_Query $WP_User_Query The WP_User_Query instance.
|
||||
* @return array
|
||||
*/
|
||||
function filter_search_columns( $columns, $search, $WP_User_Query ) {
|
||||
|
||||
/**
|
||||
* Filters the column names to be searched.
|
||||
*
|
||||
* @date 21/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $columns An array of column names to be searched.
|
||||
* @param string $search The search term.
|
||||
* @param WP_User_Query $WP_User_Query The WP_User_Query instance.
|
||||
* @param ACF_Ajax_Query $query The query object.
|
||||
*/
|
||||
return apply_filters( 'acf/ajax/query_users/search_columns', $columns, $search, $WP_User_Query, $this );
|
||||
}
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Ajax_Query_Users' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_Query' ) ) :
|
||||
|
||||
class ACF_Ajax_Query extends ACF_Ajax {
|
||||
|
||||
/** @var bool Prevents access for non-logged in users. */
|
||||
var $public = true;
|
||||
|
||||
/** @var int The page of results to return. */
|
||||
var $page = 1;
|
||||
|
||||
/** @var int The number of results per page. */
|
||||
var $per_page = 20;
|
||||
|
||||
/** @var bool Signifies whether or not this AJAX query has more pages to load. */
|
||||
var $more = false;
|
||||
|
||||
/** @var string The searched term. */
|
||||
var $search = '';
|
||||
|
||||
/** @var bool Signifies whether the current query is a search. */
|
||||
var $is_search = false;
|
||||
|
||||
/** @var (int|string) The post_id being edited. */
|
||||
var $post_id = 0;
|
||||
|
||||
/** @var array The ACF field related to this query. */
|
||||
var $field = false;
|
||||
|
||||
/**
|
||||
* get_response
|
||||
*
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return (array|WP_Error) The response data or WP_Error.
|
||||
*/
|
||||
function get_response( $request ) {
|
||||
|
||||
// Init request.
|
||||
$this->init_request( $request );
|
||||
|
||||
// Get query args.
|
||||
$args = $this->get_args( $request );
|
||||
|
||||
// Get query results.
|
||||
$results = $this->get_results( $args );
|
||||
if ( is_wp_error( $results ) ) {
|
||||
return $results;
|
||||
}
|
||||
|
||||
// Return response.
|
||||
return array(
|
||||
'results' => $results,
|
||||
'more' => $this->more,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* init_request
|
||||
*
|
||||
* Called at the beginning of a request to setup properties.
|
||||
*
|
||||
* @date 23/5/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return void
|
||||
*/
|
||||
function init_request( $request ) {
|
||||
|
||||
// Get field for this query.
|
||||
if ( isset( $request['field_key'] ) ) {
|
||||
$this->field = acf_get_field( $request['field_key'] );
|
||||
}
|
||||
|
||||
// Update query properties.
|
||||
if ( isset( $request['page'] ) ) {
|
||||
$this->page = intval( $request['page'] );
|
||||
}
|
||||
if ( isset( $request['per_page'] ) ) {
|
||||
$this->per_page = intval( $request['per_page'] );
|
||||
}
|
||||
if ( isset( $request['search'] ) && acf_not_empty( $request['search'] ) ) {
|
||||
$this->search = sanitize_text_field( $request['search'] );
|
||||
$this->is_search = true;
|
||||
}
|
||||
if ( isset( $request['post_id'] ) ) {
|
||||
$this->post_id = $request['post_id'];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_args
|
||||
*
|
||||
* Returns an array of args for this query.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return array
|
||||
*/
|
||||
function get_args( $request ) {
|
||||
|
||||
// Allow for custom "query" arg.
|
||||
if ( isset( $request['query'] ) ) {
|
||||
return (array) $request['query'];
|
||||
}
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* get_items
|
||||
*
|
||||
* Returns an array of results for the given args.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array args The query args.
|
||||
* @return array
|
||||
*/
|
||||
function get_results( $args ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* get_item
|
||||
*
|
||||
* Returns a single result for the given item object.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param mixed $item A single item from the queried results.
|
||||
* @return array An array containing "id" and "text".
|
||||
*/
|
||||
function get_result( $item ) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,56 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_Upgrade' ) ) :
|
||||
|
||||
class ACF_Ajax_Upgrade extends ACF_Ajax {
|
||||
|
||||
/** @var string The AJAX action name */
|
||||
var $action = 'acf/ajax/upgrade';
|
||||
|
||||
/**
|
||||
* get_response
|
||||
*
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return mixed The response data or WP_Error.
|
||||
*/
|
||||
function get_response( $request ) {
|
||||
|
||||
// Switch blog.
|
||||
if ( isset( $request['blog_id'] ) ) {
|
||||
switch_to_blog( $request['blog_id'] );
|
||||
}
|
||||
|
||||
// Bail early if no upgrade avaiable.
|
||||
if ( ! acf_has_upgrade() ) {
|
||||
return new WP_Error( 'upgrade_error', __( 'No updates available.', 'acf' ) );
|
||||
}
|
||||
|
||||
// Listen for output.
|
||||
ob_start();
|
||||
|
||||
// Run upgrades.
|
||||
acf_upgrade_all();
|
||||
|
||||
// Store output.
|
||||
$error = ob_get_clean();
|
||||
|
||||
// Return error or success.
|
||||
if ( $error ) {
|
||||
return new WP_Error( 'upgrade_error', $error );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Ajax_Upgrade' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,43 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax_User_Setting' ) ) :
|
||||
|
||||
class ACF_Ajax_User_Setting extends ACF_Ajax {
|
||||
|
||||
/** @var string The AJAX action name. */
|
||||
var $action = 'acf/ajax/user_setting';
|
||||
|
||||
/** @var bool Prevents access for non-logged in users. */
|
||||
var $public = true;
|
||||
|
||||
/**
|
||||
* get_response
|
||||
*
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return mixed The response data or WP_Error.
|
||||
*/
|
||||
function get_response( $request ) {
|
||||
|
||||
// update
|
||||
if ( $this->has( 'value' ) ) {
|
||||
return acf_update_user_setting( $this->get( 'name' ), $this->get( 'value' ) );
|
||||
|
||||
// get
|
||||
} else {
|
||||
return acf_get_user_setting( $this->get( 'name' ) );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Ajax_User_Setting' );
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,232 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Ajax' ) ) :
|
||||
|
||||
class ACF_Ajax {
|
||||
|
||||
/** @var string The AJAX action name. */
|
||||
var $action = '';
|
||||
|
||||
/** @var array The $_REQUEST data. */
|
||||
var $request;
|
||||
|
||||
/** @var bool Prevents access for non-logged in users. */
|
||||
var $public = false;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* Sets up the class functionality.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
$this->initialize();
|
||||
$this->add_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* has
|
||||
*
|
||||
* Returns true if the request has data for the given key.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param string $key The data key.
|
||||
* @return boolean
|
||||
*/
|
||||
function has( $key = '' ) {
|
||||
return isset( $this->request[ $key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* get
|
||||
*
|
||||
* Returns request data for the given key.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param string $key The data key.
|
||||
* @return mixed
|
||||
*/
|
||||
function get( $key = '' ) {
|
||||
return isset( $this->request[ $key ] ) ? $this->request[ $key ] : null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets request data for the given key.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param string $key The data key.
|
||||
* @param mixed $value The data value.
|
||||
* @return ACF_Ajax
|
||||
*/
|
||||
function set( $key = '', $value = null ) {
|
||||
$this->request[ $key ] = $value;
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* Allows easy access to modifying properties without changing constructor.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function initialize() {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
/**
|
||||
* add_actions
|
||||
*
|
||||
* Adds the ajax actions for this response.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function add_actions() {
|
||||
|
||||
// add action for logged-in users
|
||||
add_action( "wp_ajax_{$this->action}", array( $this, 'request' ) );
|
||||
|
||||
// add action for non logged-in users
|
||||
if ( $this->public ) {
|
||||
add_action( "wp_ajax_nopriv_{$this->action}", array( $this, 'request' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* request
|
||||
*
|
||||
* Callback for ajax action. Sets up properties and calls the get_response() function.
|
||||
*
|
||||
* @date 1/8/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function request() {
|
||||
|
||||
// Store data for has() and get() functions.
|
||||
$this->request = wp_unslash( $_REQUEST ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Verified below in verify_request().
|
||||
|
||||
// Verify request and handle error.
|
||||
$error = $this->verify_request( $this->request );
|
||||
if ( is_wp_error( $error ) ) {
|
||||
$this->send( $error );
|
||||
}
|
||||
|
||||
// Send response.
|
||||
$this->send( $this->get_response( $this->request ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies the request.
|
||||
*
|
||||
* @date 9/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return (bool|WP_Error) True on success, WP_Error on fail.
|
||||
*/
|
||||
function verify_request( $request ) {
|
||||
|
||||
// Verify nonce.
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
return new WP_Error( 'acf_invalid_nonce', __( 'Invalid nonce.', 'acf' ), array( 'status' => 404 ) );
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* get_response
|
||||
*
|
||||
* Returns the response data to sent back.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $request The request args.
|
||||
* @return mixed The response data or WP_Error.
|
||||
*/
|
||||
function get_response( $request ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* send
|
||||
*
|
||||
* Sends back JSON based on the $response as either success or failure.
|
||||
*
|
||||
* @date 31/7/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param mixed $response The response to send back.
|
||||
* @return void
|
||||
*/
|
||||
function send( $response ) {
|
||||
|
||||
// Return error.
|
||||
if ( is_wp_error( $response ) ) {
|
||||
$this->send_error( $response );
|
||||
|
||||
// Return success.
|
||||
} else {
|
||||
wp_send_json( $response );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sends a JSON response for the given WP_Error object.
|
||||
*
|
||||
* @date 8/3/20
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param WP_Error error The error object.
|
||||
* @return void
|
||||
*/
|
||||
function send_error( $error ) {
|
||||
|
||||
// Get error status
|
||||
$error_data = $error->get_error_data();
|
||||
if ( is_array( $error_data ) && isset( $error_data['status'] ) ) {
|
||||
$status_code = $error_data['status'];
|
||||
} else {
|
||||
$status_code = 500;
|
||||
}
|
||||
|
||||
wp_send_json(
|
||||
array(
|
||||
'code' => $error->get_error_code(),
|
||||
'message' => $error->get_error_message(),
|
||||
'data' => $error->get_error_data(),
|
||||
),
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,522 @@
|
||||
<?php
|
||||
|
||||
/*
|
||||
* acf_get_taxonomies
|
||||
*
|
||||
* Returns an array of taxonomy names.
|
||||
*
|
||||
* @date 7/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $args An array of args used in the get_taxonomies() function.
|
||||
* @return array An array of taxonomy names.
|
||||
*/
|
||||
|
||||
function acf_get_taxonomies( $args = array() ) {
|
||||
|
||||
// vars
|
||||
$taxonomies = array();
|
||||
|
||||
// get taxonomy objects
|
||||
$objects = get_taxonomies( $args, 'objects' );
|
||||
|
||||
// loop
|
||||
foreach ( $objects as $i => $object ) {
|
||||
|
||||
// bail early if is builtin (WP) private post type
|
||||
// - nav_menu_item, revision, customize_changeset, etc
|
||||
if ( $object->_builtin && ! $object->public ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append
|
||||
$taxonomies[] = $i;
|
||||
}
|
||||
|
||||
// custom post_type arg which does not yet exist in core
|
||||
if ( isset( $args['post_type'] ) ) {
|
||||
$taxonomies = acf_get_taxonomies_for_post_type( $args['post_type'] );
|
||||
}
|
||||
|
||||
// filter
|
||||
$taxonomies = apply_filters( 'acf/get_taxonomies', $taxonomies, $args );
|
||||
|
||||
// return
|
||||
return $taxonomies;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_taxonomies_for_post_type
|
||||
*
|
||||
* Returns an array of taxonomies for a given post type(s)
|
||||
*
|
||||
* @date 7/9/18
|
||||
* @since 5.7.5
|
||||
*
|
||||
* @param string|array $post_types The post types to compare against.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_taxonomies_for_post_type( $post_types = 'post' ) {
|
||||
|
||||
// vars
|
||||
$taxonomies = array();
|
||||
|
||||
// loop
|
||||
foreach ( (array) $post_types as $post_type ) {
|
||||
$object_taxonomies = get_object_taxonomies( $post_type );
|
||||
foreach ( (array) $object_taxonomies as $taxonomy ) {
|
||||
$taxonomies[] = $taxonomy;
|
||||
}
|
||||
}
|
||||
|
||||
// remove duplicates
|
||||
$taxonomies = array_unique( $taxonomies );
|
||||
|
||||
// return
|
||||
return $taxonomies;
|
||||
}
|
||||
|
||||
/*
|
||||
* acf_get_taxonomy_labels
|
||||
*
|
||||
* Returns an array of taxonomies in the format "name => label" for use in a select field.
|
||||
*
|
||||
* @date 3/8/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $taxonomies Optional. An array of specific taxonomies to return.
|
||||
* @return array
|
||||
*/
|
||||
|
||||
function acf_get_taxonomy_labels( $taxonomies = array() ) {
|
||||
|
||||
// default
|
||||
if ( empty( $taxonomies ) ) {
|
||||
$taxonomies = acf_get_taxonomies();
|
||||
}
|
||||
|
||||
// vars
|
||||
$ref = array();
|
||||
$data = array();
|
||||
|
||||
// loop
|
||||
foreach ( $taxonomies as $taxonomy ) {
|
||||
|
||||
// vars
|
||||
$object = get_taxonomy( $taxonomy );
|
||||
$label = $object->labels->singular_name;
|
||||
|
||||
// append
|
||||
$data[ $taxonomy ] = $label;
|
||||
|
||||
// increase counter
|
||||
if ( ! isset( $ref[ $label ] ) ) {
|
||||
$ref[ $label ] = 0;
|
||||
}
|
||||
$ref[ $label ]++;
|
||||
}
|
||||
|
||||
// show taxonomy name next to label for shared labels
|
||||
foreach ( $data as $taxonomy => $label ) {
|
||||
if ( $ref[ $label ] > 1 ) {
|
||||
$data[ $taxonomy ] .= ' (' . $taxonomy . ')';
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_term_title
|
||||
*
|
||||
* Returns the title for this term object.
|
||||
*
|
||||
* @date 10/9/18
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param object $term The WP_Term object.
|
||||
* @return string
|
||||
*/
|
||||
|
||||
function acf_get_term_title( $term ) {
|
||||
$title = $term->name;
|
||||
|
||||
// Allow for empty name.
|
||||
if ( $title === '' ) {
|
||||
$title = __( '(no title)', 'acf' );
|
||||
}
|
||||
|
||||
// Prepend ancestors indentation.
|
||||
if ( is_taxonomy_hierarchical( $term->taxonomy ) ) {
|
||||
$ancestors = get_ancestors( $term->term_id, $term->taxonomy );
|
||||
$title = str_repeat( '- ', count( $ancestors ) ) . $title;
|
||||
}
|
||||
|
||||
return $title;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_grouped_terms
|
||||
*
|
||||
* Returns an array of terms for the given query $args and groups by taxonomy name.
|
||||
*
|
||||
* @date 2/8/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $args An array of args used in the get_terms() function.
|
||||
* @return array
|
||||
*/
|
||||
|
||||
function acf_get_grouped_terms( $args ) {
|
||||
|
||||
// vars
|
||||
$data = array();
|
||||
|
||||
// defaults
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'taxonomy' => null,
|
||||
'hide_empty' => false,
|
||||
'update_term_meta_cache' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$taxonomies = acf_get_taxonomy_labels( acf_get_array( $args['taxonomy'] ) );
|
||||
$is_single = ( count( $taxonomies ) == 1 );
|
||||
|
||||
// specify exact taxonomies required for _acf_terms_clauses() to work.
|
||||
$args['taxonomy'] = array_keys( $taxonomies );
|
||||
|
||||
// add filter to group results by taxonomy
|
||||
if ( ! $is_single ) {
|
||||
add_filter( 'terms_clauses', '_acf_terms_clauses', 10, 3 );
|
||||
}
|
||||
|
||||
// get terms
|
||||
$terms = get_terms( $args );
|
||||
|
||||
// remove this filter (only once)
|
||||
if ( ! $is_single ) {
|
||||
remove_filter( 'terms_clauses', '_acf_terms_clauses', 10, 3 );
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $taxonomies as $taxonomy => $label ) {
|
||||
|
||||
// vars
|
||||
$this_terms = array();
|
||||
|
||||
// populate $this_terms
|
||||
foreach ( $terms as $term ) {
|
||||
if ( $term->taxonomy == $taxonomy ) {
|
||||
$this_terms[] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
// bail early if no $items
|
||||
if ( empty( $this_terms ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// sort into hierachial order
|
||||
// this will fail if a search has taken place because parents wont exist
|
||||
if ( is_taxonomy_hierarchical( $taxonomy ) && empty( $args['s'] ) ) {
|
||||
|
||||
// get all terms from this taxonomy
|
||||
$all_terms = get_terms(
|
||||
array_merge(
|
||||
$args,
|
||||
array(
|
||||
'number' => 0,
|
||||
'offset' => 0,
|
||||
'taxonomy' => $taxonomy,
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$length = count( $this_terms );
|
||||
$offset = 0;
|
||||
|
||||
// find starting point (offset)
|
||||
foreach ( $all_terms as $i => $term ) {
|
||||
if ( $term->term_id == $this_terms[0]->term_id ) {
|
||||
$offset = $i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// order terms
|
||||
$parent = acf_maybe_get( $args, 'parent', 0 );
|
||||
$parent = acf_maybe_get( $args, 'child_of', $parent );
|
||||
$ordered_terms = _get_term_children( $parent, $all_terms, $taxonomy );
|
||||
|
||||
// compare aray lengths
|
||||
// if $ordered_posts is smaller than $all_posts, WP has lost posts during the get_page_children() function
|
||||
// this is possible when get_post( $args ) filter out parents (via taxonomy, meta and other search parameters)
|
||||
if ( count( $ordered_terms ) == count( $all_terms ) ) {
|
||||
$this_terms = array_slice( $ordered_terms, $offset, $length );
|
||||
}
|
||||
}
|
||||
|
||||
// populate group
|
||||
$data[ $label ] = array();
|
||||
foreach ( $this_terms as $term ) {
|
||||
$data[ $label ][ $term->term_id ] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* _acf_terms_clauses
|
||||
*
|
||||
* Used in the 'terms_clauses' filter to order terms by taxonomy name.
|
||||
*
|
||||
* @date 2/8/18
|
||||
* @since 5.7.2
|
||||
*
|
||||
* @param array $pieces Terms query SQL clauses.
|
||||
* @param array $taxonomies An array of taxonomies.
|
||||
* @param array $args An array of terms query arguments.
|
||||
* @return array $pieces
|
||||
*/
|
||||
|
||||
function _acf_terms_clauses( $pieces, $taxonomies, $args ) {
|
||||
|
||||
// prepend taxonomy to 'orderby' SQL
|
||||
if ( is_array( $taxonomies ) ) {
|
||||
$sql = "FIELD(tt.taxonomy,'" . implode( "', '", array_map( 'esc_sql', $taxonomies ) ) . "')";
|
||||
$pieces['orderby'] = str_replace( 'ORDER BY', "ORDER BY $sql,", $pieces['orderby'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $pieces;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_pretty_taxonomies
|
||||
*
|
||||
* Deprecated in favor of acf_get_taxonomy_labels() function.
|
||||
*
|
||||
* @date 7/10/13
|
||||
* @since 5.0.0
|
||||
* @deprecated 5.7.2
|
||||
*/
|
||||
|
||||
function acf_get_pretty_taxonomies( $taxonomies = array() ) {
|
||||
return acf_get_taxonomy_labels( $taxonomies );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_term
|
||||
*
|
||||
* Similar to get_term() but with some extra functionality.
|
||||
*
|
||||
* @date 19/8/18
|
||||
* @since 5.7.3
|
||||
*
|
||||
* @param mixed $term_id The term ID or a string of "taxonomy:slug".
|
||||
* @param string $taxonomy The taxonomyname.
|
||||
* @return WP_Term
|
||||
*/
|
||||
|
||||
function acf_get_term( $term_id, $taxonomy = '' ) {
|
||||
|
||||
// allow $term_id parameter to be a string of "taxonomy:slug" or "taxonomy:id"
|
||||
if ( is_string( $term_id ) && strpos( $term_id, ':' ) ) {
|
||||
list( $taxonomy, $term_id ) = explode( ':', $term_id );
|
||||
$term = get_term_by( 'slug', $term_id, $taxonomy );
|
||||
if ( $term ) {
|
||||
return $term;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return get_term( $term_id, $taxonomy );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_encode_term
|
||||
*
|
||||
* Returns a "taxonomy:slug" string for a given WP_Term.
|
||||
*
|
||||
* @date 27/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param WP_Term $term The term object.
|
||||
* @return string
|
||||
*/
|
||||
function acf_encode_term( $term ) {
|
||||
return "{$term->taxonomy}:{$term->slug}";
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_decode_term
|
||||
*
|
||||
* Decodes a "taxonomy:slug" string into an array of taxonomy and slug.
|
||||
*
|
||||
* @date 27/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param WP_Term $term The term object.
|
||||
* @return string
|
||||
*/
|
||||
function acf_decode_term( $string ) {
|
||||
if ( is_string( $string ) && strpos( $string, ':' ) ) {
|
||||
list( $taxonomy, $slug ) = explode( ':', $string );
|
||||
return compact( 'taxonomy', 'slug' );
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_encoded_terms
|
||||
*
|
||||
* Returns an array of WP_Term objects from an array of encoded strings
|
||||
*
|
||||
* @date 9/9/18
|
||||
* @since 5.7.5
|
||||
*
|
||||
* @param array $values The array of encoded strings.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_encoded_terms( $values ) {
|
||||
|
||||
// vars
|
||||
$terms = array();
|
||||
|
||||
// loop over values
|
||||
foreach ( (array) $values as $value ) {
|
||||
|
||||
// find term from string
|
||||
$term = acf_get_term( $value );
|
||||
|
||||
// append
|
||||
if ( $term instanceof WP_Term ) {
|
||||
$terms[] = $term;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $terms;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_choices_from_terms
|
||||
*
|
||||
* Returns an array of choices from the terms provided.
|
||||
*
|
||||
* @date 8/9/18
|
||||
* @since 5.7.5
|
||||
*
|
||||
* @param array $values and array of WP_Terms objects or encoded strings.
|
||||
* @param string $format The value format (term_id, slug).
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_choices_from_terms( $terms, $format = 'term_id' ) {
|
||||
|
||||
// vars
|
||||
$groups = array();
|
||||
|
||||
// get taxonomy lables
|
||||
$labels = acf_get_taxonomy_labels();
|
||||
|
||||
// convert array of encoded strings to terms
|
||||
$term = reset( $terms );
|
||||
if ( ! $term instanceof WP_Term ) {
|
||||
$terms = acf_get_encoded_terms( $terms );
|
||||
}
|
||||
|
||||
// loop over terms
|
||||
foreach ( $terms as $term ) {
|
||||
$group = $labels[ $term->taxonomy ];
|
||||
$choice = acf_get_choice_from_term( $term, $format );
|
||||
$groups[ $group ][ $choice['id'] ] = $choice['text'];
|
||||
}
|
||||
|
||||
// return
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_choices_from_grouped_terms
|
||||
*
|
||||
* Returns an array of choices from the grouped terms provided.
|
||||
*
|
||||
* @date 8/9/18
|
||||
* @since 5.7.5
|
||||
*
|
||||
* @param array $value A grouped array of WP_Terms objects.
|
||||
* @param string $format The value format (term_id, slug).
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_choices_from_grouped_terms( $value, $format = 'term_id' ) {
|
||||
|
||||
// vars
|
||||
$groups = array();
|
||||
|
||||
// loop over values
|
||||
foreach ( $value as $group => $terms ) {
|
||||
$groups[ $group ] = array();
|
||||
foreach ( $terms as $term_id => $term ) {
|
||||
$choice = acf_get_choice_from_term( $term, $format );
|
||||
$groups[ $group ][ $choice['id'] ] = $choice['text'];
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_choice_from_term
|
||||
*
|
||||
* Returns an array containing the id and text for this item.
|
||||
*
|
||||
* @date 10/9/18
|
||||
* @since 5.7.6
|
||||
*
|
||||
* @param object $item The item object such as WP_Post or WP_Term.
|
||||
* @param string $format The value format (term_id, slug)
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_choice_from_term( $term, $format = 'term_id' ) {
|
||||
|
||||
// vars
|
||||
$id = $term->term_id;
|
||||
$text = acf_get_term_title( $term );
|
||||
|
||||
// return format
|
||||
if ( $format == 'slug' ) {
|
||||
$id = acf_encode_term( $term );
|
||||
}
|
||||
|
||||
// return
|
||||
return array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a valid post_id string for a given term and taxonomy.
|
||||
* No longer needed since WP introduced the termmeta table in WP 4.4.
|
||||
*
|
||||
* @date 6/2/17
|
||||
* @since 5.5.6
|
||||
* @deprecated 5.9.2
|
||||
*
|
||||
* @param $taxonomy (string) The taxonomy type.
|
||||
* @param $term_id (int) The term ID.
|
||||
* @return (string)
|
||||
*/
|
||||
function acf_get_term_post_id( $taxonomy, $term_id ) {
|
||||
_deprecated_function( __FUNCTION__, '5.9.2', 'string format term_%d' );
|
||||
return 'term_' . $term_id;
|
||||
}
|
@ -0,0 +1,616 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Assets' ) ) :
|
||||
|
||||
class ACF_Assets {
|
||||
|
||||
/**
|
||||
* Storage for i18n data.
|
||||
*
|
||||
* @since 5.6.9
|
||||
* @var array
|
||||
*/
|
||||
public $text = array();
|
||||
|
||||
/**
|
||||
* Storage for l10n data.
|
||||
*
|
||||
* @since 5.6.9
|
||||
* @var array
|
||||
*/
|
||||
public $data = array();
|
||||
|
||||
/**
|
||||
* List of enqueue flags.
|
||||
*
|
||||
* @since 5.9.0
|
||||
* @var bool
|
||||
*/
|
||||
private $enqueue = array();
|
||||
|
||||
/**
|
||||
* Constructor.
|
||||
*
|
||||
* @date 10/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'init', array( $this, 'register_scripts' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Magic __call method for backwards compatibility.
|
||||
*
|
||||
* @date 10/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $name The method name.
|
||||
* @param array $arguments The array of arguments.
|
||||
* @return mixed
|
||||
*/
|
||||
public function __call( $name, $arguments ) {
|
||||
switch ( $name ) {
|
||||
case 'admin_enqueue_scripts':
|
||||
case 'admin_print_scripts':
|
||||
case 'admin_head':
|
||||
case 'admin_footer':
|
||||
case 'admin_print_footer_scripts':
|
||||
_doing_it_wrong( __FUNCTION__, 'The ACF_Assets class should not be accessed directly.', '5.9.0' );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of i18n data.
|
||||
*
|
||||
* @date 13/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param array $text An array of text for i18n.
|
||||
* @return void
|
||||
*/
|
||||
public function add_text( $text ) {
|
||||
foreach ( (array) $text as $k => $v ) {
|
||||
$this->text[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of l10n data.
|
||||
*
|
||||
* @date 13/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param array $data An array of data for l10n.
|
||||
* @return void
|
||||
*/
|
||||
public function add_data( $data ) {
|
||||
foreach ( (array) $data as $k => $v ) {
|
||||
$this->data[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the ACF scripts and styles.
|
||||
*
|
||||
* @date 10/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function register_scripts() {
|
||||
// Extract vars.
|
||||
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
$version = acf_get_setting( 'version' );
|
||||
|
||||
// Register scripts.
|
||||
wp_register_script( 'acf', acf_get_url( 'assets/build/js/acf' . $suffix . '.js' ), array( 'jquery' ), $version );
|
||||
wp_register_script( 'acf-input', acf_get_url( 'assets/build/js/acf-input' . $suffix . '.js' ), array( 'jquery', 'jquery-ui-sortable', 'jquery-ui-resizable', 'acf' ), $version );
|
||||
wp_register_script( 'acf-field-group', acf_get_url( 'assets/build/js/acf-field-group' . $suffix . '.js' ), array( 'acf-input' ), $version );
|
||||
wp_register_script( 'acf-internal-post-type', acf_get_url( 'assets/build/js/acf-internal-post-type' . $suffix . '.js' ), array( 'acf-input' ), $version );
|
||||
|
||||
// Register styles.
|
||||
wp_register_style( 'acf-global', acf_get_url( 'assets/build/css/acf-global.css' ), array( 'dashicons' ), $version );
|
||||
wp_register_style( 'acf-input', acf_get_url( 'assets/build/css/acf-input.css' ), array( 'acf-global' ), $version );
|
||||
wp_register_style( 'acf-field-group', acf_get_url( 'assets/build/css/acf-field-group.css' ), array( 'acf-input' ), $version );
|
||||
|
||||
/**
|
||||
* Fires after core scripts and styles have been registered.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param string $version The ACF version.
|
||||
* @param string $suffix The potential ".min" filename suffix.
|
||||
*/
|
||||
do_action( 'acf/register_scripts', $version, $suffix );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a script and sets up actions for priting supplemental scripts.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $name The script name.
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_script( $name ) {
|
||||
wp_enqueue_script( $name );
|
||||
$this->add_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a style.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $name The style name.
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_style( $name ) {
|
||||
wp_enqueue_style( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds the actions needed to print supporting inline scripts.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
private function add_actions() {
|
||||
|
||||
// Only run once.
|
||||
if ( acf_has_done( 'ACF_Assets::add_actions' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Add actions.
|
||||
$this->add_action( 'admin_enqueue_scripts', 'enqueue_scripts', 20 );
|
||||
$this->add_action( 'admin_print_scripts', 'print_scripts', 20 );
|
||||
$this->add_action( 'admin_print_footer_scripts', 'print_footer_scripts', 20 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Extends the add_action() function with two additional features:
|
||||
* 1. Renames $action depending on the current page (customizer, login, front-end).
|
||||
* 2. Alters the priotiry or calls the method directly if the action has already passed.
|
||||
*
|
||||
* @date 28/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $action The action name.
|
||||
* @param string $method The method name.
|
||||
* @param int $priority See add_action().
|
||||
* @param int $accepted_args See add_action().
|
||||
* @return void
|
||||
*/
|
||||
public function add_action( $action, $method, $priority = 10, $accepted_args = 1 ) {
|
||||
|
||||
// Generate an array of action replacements.
|
||||
$replacements = array(
|
||||
'customizer' => array(
|
||||
'admin_enqueue_scripts' => 'admin_enqueue_scripts',
|
||||
'admin_print_scripts' => 'customize_controls_print_scripts',
|
||||
'admin_head' => 'customize_controls_print_scripts',
|
||||
'admin_footer' => 'customize_controls_print_footer_scripts',
|
||||
'admin_print_footer_scripts' => 'customize_controls_print_footer_scripts',
|
||||
),
|
||||
'login' => array(
|
||||
'admin_enqueue_scripts' => 'login_enqueue_scripts',
|
||||
'admin_print_scripts' => 'login_head',
|
||||
'admin_head' => 'login_head',
|
||||
'admin_footer' => 'login_footer',
|
||||
'admin_print_footer_scripts' => 'login_footer',
|
||||
),
|
||||
'wp' => array(
|
||||
'admin_enqueue_scripts' => 'wp_enqueue_scripts',
|
||||
'admin_print_scripts' => 'wp_print_scripts',
|
||||
'admin_head' => 'wp_head',
|
||||
'admin_footer' => 'wp_footer',
|
||||
'admin_print_footer_scripts' => 'wp_print_footer_scripts',
|
||||
),
|
||||
);
|
||||
|
||||
// Determine the current context.
|
||||
if ( did_action( 'customize_controls_init' ) ) {
|
||||
$context = 'customizer';
|
||||
} elseif ( did_action( 'login_form_register' ) ) {
|
||||
$context = 'login';
|
||||
} elseif ( is_admin() ) {
|
||||
$context = 'admin';
|
||||
} else {
|
||||
$context = 'wp';
|
||||
}
|
||||
|
||||
// Replace action if possible.
|
||||
if ( isset( $replacements[ $context ][ $action ] ) ) {
|
||||
$action = $replacements[ $context ][ $action ];
|
||||
}
|
||||
|
||||
// Check if action is currently being or has already been run.
|
||||
if ( did_action( $action ) ) {
|
||||
$doing = acf_doing_action( $action );
|
||||
if ( $doing && $doing < $priority ) {
|
||||
// Allow action to be added as per usual.
|
||||
} else {
|
||||
// Call method directly.
|
||||
return call_user_func( array( $this, $method ) );
|
||||
}
|
||||
}
|
||||
|
||||
// Add action.
|
||||
add_action( $action, array( $this, $method ), $priority, $accepted_args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Generic controller for enqueuing scripts and styles.
|
||||
*
|
||||
* @date 28/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param array $args {
|
||||
* @type bool $uploader Whether or not to enqueue uploader scripts.
|
||||
* }
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue( $args = array() ) {
|
||||
|
||||
// Apply defaults.
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'input' => true,
|
||||
'uploader' => false,
|
||||
)
|
||||
);
|
||||
|
||||
// Set enqueue flags and add actions.
|
||||
if ( $args['input'] ) {
|
||||
$this->enqueue[] = 'input';
|
||||
}
|
||||
if ( $args['uploader'] ) {
|
||||
$this->enqueue[] = 'uploader';
|
||||
}
|
||||
$this->add_actions();
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the scripts and styles needed for the WP media uploader.
|
||||
*
|
||||
* @date 27/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_uploader() {
|
||||
|
||||
// Only run once.
|
||||
if ( acf_has_done( 'ACF_Assets::enqueue_uploader' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Enqueue media assets.
|
||||
if ( current_user_can( 'upload_files' ) ) {
|
||||
wp_enqueue_media();
|
||||
}
|
||||
|
||||
// Add actions.
|
||||
$this->add_action( 'admin_footer', 'print_uploader_scripts', 1 );
|
||||
|
||||
/**
|
||||
* Fires when enqueuing the uploader.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/enqueue_uploader' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues and localizes scripts.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function enqueue_scripts() {
|
||||
|
||||
// Enqueue input scripts.
|
||||
if ( in_array( 'input', $this->enqueue ) ) {
|
||||
wp_enqueue_script( 'acf-input' );
|
||||
wp_enqueue_style( 'acf-input' );
|
||||
}
|
||||
|
||||
// Enqueue media scripts.
|
||||
if ( in_array( 'uploader', $this->enqueue ) ) {
|
||||
$this->enqueue_uploader();
|
||||
}
|
||||
|
||||
// Localize text.
|
||||
acf_localize_text(
|
||||
array(
|
||||
|
||||
// Tooltip
|
||||
'Are you sure?' => __( 'Are you sure?', 'acf' ),
|
||||
'Yes' => __( 'Yes', 'acf' ),
|
||||
'No' => __( 'No', 'acf' ),
|
||||
'Remove' => __( 'Remove', 'acf' ),
|
||||
'Cancel' => __( 'Cancel', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Localize "input" text.
|
||||
if ( wp_script_is( 'acf-input' ) ) {
|
||||
acf_localize_text(
|
||||
array(
|
||||
|
||||
// Unload
|
||||
'The changes you made will be lost if you navigate away from this page' => __( 'The changes you made will be lost if you navigate away from this page', 'acf' ),
|
||||
|
||||
// Validation
|
||||
'Validation successful' => __( 'Validation successful', 'acf' ),
|
||||
'Validation failed' => __( 'Validation failed', 'acf' ),
|
||||
'1 field requires attention' => __( '1 field requires attention', 'acf' ),
|
||||
'%d fields require attention' => __( '%d fields require attention', 'acf' ),
|
||||
|
||||
// Other
|
||||
'Edit field group' => __( 'Edit field group', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
/**
|
||||
* Fires during "admin_enqueue_scripts" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/input/admin_enqueue_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires during "admin_enqueue_scripts" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/admin_enqueue_scripts' );
|
||||
do_action( 'acf/enqueue_scripts' );
|
||||
|
||||
// Filter i18n translations that differ from English and localize script.
|
||||
$text = array();
|
||||
foreach ( $this->text as $k => $v ) {
|
||||
if ( str_replace( '.verb', '', $k ) !== $v ) {
|
||||
$text[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
if ( $text ) {
|
||||
wp_localize_script( 'acf', 'acfL10n', $text );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints scripts in head.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function print_scripts() {
|
||||
if ( wp_script_is( 'acf-input' ) ) {
|
||||
|
||||
/**
|
||||
* Fires during "admin_head" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/input/admin_head' );
|
||||
do_action( 'acf/input/admin_print_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires during "admin_head" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/admin_head' );
|
||||
do_action( 'acf/admin_print_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints scripts in footer.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function print_footer_scripts() {
|
||||
global $wp_version;
|
||||
|
||||
// Bail early if 'acf' script was never enqueued (fixes Elementor enqueue reset conflict).
|
||||
if ( ! wp_script_is( 'acf' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Localize data.
|
||||
acf_localize_data(
|
||||
array(
|
||||
'admin_url' => admin_url(),
|
||||
'ajaxurl' => admin_url( 'admin-ajax.php' ),
|
||||
'nonce' => wp_create_nonce( 'acf_nonce' ),
|
||||
'acf_version' => acf_get_setting( 'version' ),
|
||||
'wp_version' => $wp_version,
|
||||
'browser' => acf_get_browser(),
|
||||
'locale' => acf_get_locale(),
|
||||
'rtl' => is_rtl(),
|
||||
'screen' => acf_get_form_data( 'screen' ),
|
||||
'post_id' => acf_get_form_data( 'post_id' ),
|
||||
'validation' => acf_get_form_data( 'validation' ),
|
||||
'editor' => acf_is_block_editor() ? 'block' : 'classic',
|
||||
'is_pro' => defined( 'ACF_PRO' ) && ACF_PRO,
|
||||
)
|
||||
);
|
||||
|
||||
// Print inline script.
|
||||
printf( "<script>\n%s\n</script>\n", 'acf.data = ' . wp_json_encode( $this->data ) . ';' );
|
||||
|
||||
if ( wp_script_is( 'acf-input' ) ) {
|
||||
|
||||
/**
|
||||
* Filters an empty array for compat l10n data.
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $data An array of data to append to.
|
||||
*/
|
||||
$compat_l10n = apply_filters( 'acf/input/admin_l10n', array() );
|
||||
if ( $compat_l10n ) {
|
||||
printf( "<script>\n%s\n</script>\n", 'acf.l10n = ' . wp_json_encode( $compat_l10n ) . ';' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires during "admin_footer" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/input/admin_footer' );
|
||||
do_action( 'acf/input/admin_print_footer_scripts' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fires during "admin_footer" when ACF scripts are enqueued.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/admin_footer' );
|
||||
do_action( 'acf/admin_print_footer_scripts' );
|
||||
|
||||
// Once all data is localized, trigger acf.prepare() to execute functionality before DOM ready.
|
||||
printf( "<script>\n%s\n</script>\n", "acf.doAction( 'prepare' );" );
|
||||
}
|
||||
|
||||
/**
|
||||
* Prints uploader scripts in footer.
|
||||
*
|
||||
* @date 11/06/2020
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
public function print_uploader_scripts() {
|
||||
// Todo: investigate output-buffer to hide HTML.
|
||||
?>
|
||||
<div id="acf-hidden-wp-editor" style="display: none;">
|
||||
<?php wp_editor( '', 'acf_content' ); ?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
/**
|
||||
* Fires when printing uploader scripts.
|
||||
*
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param void
|
||||
*/
|
||||
do_action( 'acf/admin_print_uploader_scripts' );
|
||||
}
|
||||
}
|
||||
|
||||
// instantiate
|
||||
acf_new_instance( 'ACF_Assets' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
/**
|
||||
* Appends an array of i18n data for localization.
|
||||
*
|
||||
* @date 13/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param array $text An array of text for i18n.
|
||||
* @return void
|
||||
*/
|
||||
function acf_localize_text( $text ) {
|
||||
return acf_get_instance( 'ACF_Assets' )->add_text( $text );
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends an array of l10n data for localization.
|
||||
*
|
||||
* @date 13/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param array $data An array of data for l10n.
|
||||
* @return void
|
||||
*/
|
||||
function acf_localize_data( $data ) {
|
||||
return acf_get_instance( 'ACF_Assets' )->add_data( $data );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues a script with support for supplemental inline scripts.
|
||||
*
|
||||
* @date 27/4/20
|
||||
* @since 5.9.0
|
||||
*
|
||||
* @param string $name The script name.
|
||||
* @return void
|
||||
*/
|
||||
function acf_enqueue_script( $name ) {
|
||||
return acf_get_instance( 'ACF_Assets' )->enqueue_script( $name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the input scripts required for fields.
|
||||
*
|
||||
* @date 13/4/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param array $args See ACF_Assets::enqueue_scripts() for a list of args.
|
||||
* @return void
|
||||
*/
|
||||
function acf_enqueue_scripts( $args = array() ) {
|
||||
return acf_get_instance( 'ACF_Assets' )->enqueue( $args );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues the WP media uploader scripts and styles.
|
||||
*
|
||||
* @date 27/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function acf_enqueue_uploader() {
|
||||
return acf_get_instance( 'ACF_Assets' )->enqueue_uploader();
|
||||
}
|
@ -0,0 +1,357 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Data' ) ) :
|
||||
|
||||
#[AllowDynamicProperties]
|
||||
class ACF_Data {
|
||||
|
||||
/** @var string Unique identifier. */
|
||||
var $cid = '';
|
||||
|
||||
/** @var array Storage for data. */
|
||||
var $data = array();
|
||||
|
||||
/** @var array Storage for data aliases. */
|
||||
var $aliases = array();
|
||||
|
||||
/** @var bool Enables unique data per site. */
|
||||
var $multisite = false;
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* Sets up the class functionality.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $data Optional data to set.
|
||||
* @return void
|
||||
*/
|
||||
function __construct( $data = false ) {
|
||||
|
||||
// Set cid.
|
||||
$this->cid = acf_uniqid();
|
||||
|
||||
// Set data.
|
||||
if ( $data ) {
|
||||
$this->set( $data );
|
||||
}
|
||||
|
||||
// Initialize.
|
||||
$this->initialize();
|
||||
}
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* Called during constructor to setup class functionality.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function initialize() {
|
||||
// Do nothing.
|
||||
}
|
||||
|
||||
/**
|
||||
* prop
|
||||
*
|
||||
* Sets a property for the given name and returns $this for chaining.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (string|array) $name The data name or an array of data.
|
||||
* @param mixed $value The data value.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function prop( $name = '', $value = null ) {
|
||||
|
||||
// Update property.
|
||||
$this->{$name} = $value;
|
||||
|
||||
// Return this for chaining.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* _key
|
||||
*
|
||||
* Returns a key for the given name allowing aliasses to work.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function _key( $name = '' ) {
|
||||
return isset( $this->aliases[ $name ] ) ? $this->aliases[ $name ] : $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* has
|
||||
*
|
||||
* Returns true if this has data for the given name.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $name The data name.
|
||||
* @return boolean
|
||||
*/
|
||||
function has( $name = '' ) {
|
||||
$key = $this->_key( $name );
|
||||
return isset( $this->data[ $key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* is
|
||||
*
|
||||
* Similar to has() but does not check aliases.
|
||||
*
|
||||
* @date 7/2/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function is( $key = '' ) {
|
||||
return isset( $this->data[ $key ] );
|
||||
}
|
||||
|
||||
/**
|
||||
* get
|
||||
*
|
||||
* Returns data for the given name of null if doesn't exist.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $name The data name.
|
||||
* @return mixed
|
||||
*/
|
||||
function get( $name = false ) {
|
||||
|
||||
// Get all.
|
||||
if ( $name === false ) {
|
||||
return $this->data;
|
||||
|
||||
// Get specific.
|
||||
} else {
|
||||
$key = $this->_key( $name );
|
||||
return isset( $this->data[ $key ] ) ? $this->data[ $key ] : null;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* get_data
|
||||
*
|
||||
* Returns an array of all data.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return array
|
||||
*/
|
||||
function get_data() {
|
||||
return $this->data;
|
||||
}
|
||||
|
||||
/**
|
||||
* set
|
||||
*
|
||||
* Sets data for the given name and returns $this for chaining.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param (string|array) $name The data name or an array of data.
|
||||
* @param mixed $value The data value.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function set( $name = '', $value = null ) {
|
||||
|
||||
// Set multiple.
|
||||
if ( is_array( $name ) ) {
|
||||
$this->data = array_merge( $this->data, $name );
|
||||
|
||||
// Set single.
|
||||
} else {
|
||||
$this->data[ $name ] = $value;
|
||||
}
|
||||
|
||||
// Return this for chaining.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* append
|
||||
*
|
||||
* Appends data for the given name and returns $this for chaining.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param mixed $value The data value.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function append( $value = null ) {
|
||||
|
||||
// Append.
|
||||
$this->data[] = $value;
|
||||
|
||||
// Return this for chaining.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* remove
|
||||
*
|
||||
* Removes data for the given name.
|
||||
*
|
||||
* @date 9/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param string $name The data name.
|
||||
* @return ACF_Data
|
||||
*/
|
||||
function remove( $name = '' ) {
|
||||
|
||||
// Remove data.
|
||||
unset( $this->data[ $name ] );
|
||||
|
||||
// Return this for chaining.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* reset
|
||||
*
|
||||
* Resets the data.
|
||||
*
|
||||
* @date 22/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function reset() {
|
||||
$this->data = array();
|
||||
$this->aliases = array();
|
||||
}
|
||||
|
||||
/**
|
||||
* count
|
||||
*
|
||||
* Returns the data count.
|
||||
*
|
||||
* @date 23/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return int
|
||||
*/
|
||||
function count() {
|
||||
return count( $this->data );
|
||||
}
|
||||
|
||||
/**
|
||||
* query
|
||||
*
|
||||
* Returns a filtered array of data based on the set of key => value arguments.
|
||||
*
|
||||
* @date 23/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param void
|
||||
* @return int
|
||||
*/
|
||||
function query( $args, $operator = 'AND' ) {
|
||||
return wp_list_filter( $this->data, $args, $operator );
|
||||
}
|
||||
|
||||
/**
|
||||
* alias
|
||||
*
|
||||
* Sets an alias for the given name allowing data to be found via multiple identifiers.
|
||||
*
|
||||
* @date 18/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function alias( $name = '' /*, $alias, $alias2, etc */ ) {
|
||||
|
||||
// Get all aliases.
|
||||
$args = func_get_args();
|
||||
array_shift( $args );
|
||||
|
||||
// Loop over aliases and add to data.
|
||||
foreach ( $args as $alias ) {
|
||||
$this->aliases[ $alias ] = $name;
|
||||
}
|
||||
|
||||
// Return this for chaining.
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* switch_site
|
||||
*
|
||||
* Triggered when switching between sites on a multisite installation.
|
||||
*
|
||||
* @date 13/2/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param int $site_id New blog ID.
|
||||
* @param int prev_blog_id Prev blog ID.
|
||||
* @return void
|
||||
*/
|
||||
function switch_site( $site_id, $prev_site_id ) {
|
||||
|
||||
// Bail early if not multisite compatible.
|
||||
if ( ! $this->multisite ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Bail early if no change in blog ID.
|
||||
if ( $site_id === $prev_site_id ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Create storage.
|
||||
if ( ! isset( $this->site_data ) ) {
|
||||
$this->site_data = array();
|
||||
$this->site_aliases = array();
|
||||
}
|
||||
|
||||
// Save state.
|
||||
$this->site_data[ $prev_site_id ] = $this->data;
|
||||
$this->site_aliases[ $prev_site_id ] = $this->aliases;
|
||||
|
||||
// Reset state.
|
||||
$this->data = array();
|
||||
$this->aliases = array();
|
||||
|
||||
// Load state.
|
||||
if ( isset( $this->site_data[ $site_id ] ) ) {
|
||||
$this->data = $this->site_data[ $site_id ];
|
||||
$this->aliases = $this->site_aliases[ $site_id ];
|
||||
unset( $this->site_data[ $site_id ] );
|
||||
unset( $this->site_aliases[ $site_id ] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
endif; // class_exists check
|
@ -0,0 +1,932 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly.
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Internal_Post_Type' ) ) {
|
||||
abstract class ACF_Internal_Post_Type {
|
||||
|
||||
/**
|
||||
* The ACF internal post type name.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $post_type = '';
|
||||
|
||||
/**
|
||||
* The prefix for the key used in the main post array.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $post_key_prefix = '';
|
||||
|
||||
/**
|
||||
* The cache key for a singular post.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cache_key = '';
|
||||
|
||||
/**
|
||||
* The cache key for a collection of posts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $cache_key_plural = '';
|
||||
|
||||
/**
|
||||
* The hook name for a singular post.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hook_name = '';
|
||||
|
||||
/**
|
||||
* The hook name for a collection of posts.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $hook_name_plural = '';
|
||||
|
||||
/**
|
||||
* The name of the store used for the post type.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public $store = '';
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*/
|
||||
public function __construct() {
|
||||
acf_register_store( $this->store )->prop( 'multisite', true );
|
||||
|
||||
$internal_post_types_store = acf_get_store( 'internal-post-types' );
|
||||
|
||||
if ( ! $internal_post_types_store ) {
|
||||
$internal_post_types_store = acf_register_store( 'internal-post-types' );
|
||||
}
|
||||
|
||||
$internal_post_types_store->set( $this->post_type, get_class( $this ) );
|
||||
|
||||
add_action( "acf/validate_{$this->hook_name}", array( $this, 'translate_post' ) );
|
||||
|
||||
add_filter( 'wp_unique_post_slug', array( $this, 'apply_unique_post_slug' ), 999, 6 );
|
||||
add_action( 'wp_untrash_post_status', array( $this, 'untrash_post_status' ), 10, 3 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Get an ACF CPT object as an array.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|WP_Post $id The post ID being queried.
|
||||
* @return array|bool The main ACF array for the post, or false on failure.
|
||||
*/
|
||||
public function get_post( $id = 0 ) {
|
||||
// Allow WP_Post to be passed.
|
||||
if ( is_object( $id ) ) {
|
||||
$id = $id->ID;
|
||||
}
|
||||
|
||||
// Check store.
|
||||
$store = acf_get_store( $this->store );
|
||||
if ( $store->has( $id ) ) {
|
||||
return $store->get( $id );
|
||||
}
|
||||
|
||||
if ( acf_is_local_internal_post_type( $id, $this->post_type ) ) {
|
||||
$post = acf_get_local_internal_post_type( $id, $this->post_type );
|
||||
} else {
|
||||
$post = $this->get_raw_post( $id );
|
||||
}
|
||||
|
||||
// Bail early if no post.
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = $this->validate_post( $post );
|
||||
|
||||
/**
|
||||
* Filters the post array after it has been loaded.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The post array.
|
||||
*/
|
||||
$post = apply_filters( "acf/load_{$this->hook_name}", $post );
|
||||
|
||||
// Store field group using aliases to also find via key, ID and name.
|
||||
$store->set( $post['key'], $post );
|
||||
$store->alias( $post['key'], $post['ID'] );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves raw post data for the given identifier.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The field ID, key or name.
|
||||
* @return array|false The field group array, or false on failure.
|
||||
*/
|
||||
public function get_raw_post( $id = 0 ) {
|
||||
// Get raw internal post from database.
|
||||
$post = $this->get_post_object( $id );
|
||||
if ( ! $post ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Bail early if incorrect post type.
|
||||
if ( $post->post_type !== $this->post_type ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Unserialize post_content.
|
||||
$raw_post = (array) acf_maybe_unserialize( $post->post_content );
|
||||
|
||||
// Update attributes.
|
||||
$raw_post['ID'] = $post->ID;
|
||||
$raw_post['title'] = $post->post_title;
|
||||
$raw_post['key'] = $post->post_name;
|
||||
$raw_post['menu_order'] = $post->menu_order;
|
||||
$raw_post['active'] = in_array( $post->post_status, array( 'publish', 'auto-draft' ) );
|
||||
|
||||
return $raw_post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the WP_Post object for an ACF internal CPT.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The post ID, key, or name.
|
||||
* @return WP_Post|bool The post object, or false on failure.
|
||||
*/
|
||||
public function get_post_object( $id = 0 ) {
|
||||
if ( is_numeric( $id ) ) {
|
||||
$post_object = get_post( $id );
|
||||
|
||||
if ( $post_object && $post_object->post_type === $this->post_type ) {
|
||||
return $post_object;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
if ( is_string( $id ) ) {
|
||||
// Try cache.
|
||||
$cache_key = $this->cache_key . $id;
|
||||
$post_id = wp_cache_get( $cache_key, 'acf' );
|
||||
|
||||
if ( $post_id === false ) {
|
||||
$query_key = 'acf_' . $this->post_key_prefix . 'key';
|
||||
|
||||
// Query posts.
|
||||
$posts = get_posts(
|
||||
array(
|
||||
'posts_per_page' => 1,
|
||||
'post_type' => $this->post_type,
|
||||
'post_status' => array( 'publish', 'acf-disabled', 'trash' ),
|
||||
'orderby' => 'menu_order title',
|
||||
'order' => 'ASC',
|
||||
'suppress_filters' => false,
|
||||
'cache_results' => true,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
$query_key => $id, // Used to check post_name for field group/post type/taxonomy key.
|
||||
)
|
||||
);
|
||||
|
||||
// Update $post_id with a non-false value.
|
||||
$post_id = $posts ? $posts[0]->ID : 0;
|
||||
|
||||
// Update cache.
|
||||
wp_cache_set( $cache_key, $post_id, 'acf' );
|
||||
}
|
||||
|
||||
// Check $post_id and return the post when possible.
|
||||
if ( $post_id ) {
|
||||
return get_post( $post_id );
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given identifier is an ACF post key.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $id The identifier.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_post_key( $id = '' ) {
|
||||
// Check if $id is a string starting with $this->post_key.
|
||||
if ( is_string( $id ) && substr( $id, 0, strlen( $this->post_key_prefix ) ) === $this->post_key_prefix ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters whether the $id is an ACF post key.
|
||||
*
|
||||
* @date 23/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param bool $bool The result.
|
||||
* @param string $id The identifier.
|
||||
*/
|
||||
return apply_filters( "acf/is_{$this->hook_name}_key", false, $id, $this->post_type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates an ACF internal post type.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The main post array.
|
||||
* @return array
|
||||
*/
|
||||
public function validate_post( $post = array() ) {
|
||||
// Bail early if already valid.
|
||||
if ( is_array( $post ) && ! empty( $post['_valid'] ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
$post = wp_parse_args(
|
||||
$post,
|
||||
$this->get_settings_array()
|
||||
);
|
||||
|
||||
// Convert types.
|
||||
$post['ID'] = (int) $post['ID'];
|
||||
$post['menu_order'] = (int) $post['menu_order'];
|
||||
$post['active'] = (bool) $post['active'];
|
||||
|
||||
// Post is now valid.
|
||||
$post['_valid'] = true;
|
||||
|
||||
/**
|
||||
* Filters the ACF post array to validate settings.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The post array.
|
||||
*/
|
||||
return apply_filters( "acf/validate_{$this->hook_name}", $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates post type 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.1
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
public function ajax_validate_values() {}
|
||||
|
||||
/**
|
||||
* Ensures the given ACF post is valid.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The main post array.
|
||||
* @return array
|
||||
*/
|
||||
public function get_valid_post( $post = false ) {
|
||||
return $this->validate_post( $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the default settings array for an ACF post type.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_settings_array() {
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Translates an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The field group array.
|
||||
* @return array
|
||||
*/
|
||||
public function translate_post( $post = array() ) {
|
||||
// Get settings.
|
||||
$l10n = acf_get_setting( 'l10n' );
|
||||
$l10n_textdomain = acf_get_setting( 'l10n_textdomain' );
|
||||
|
||||
// Translate field settings if textdomain is set.
|
||||
if ( $l10n && $l10n_textdomain ) {
|
||||
$post['title'] = acf_translate( $post['title'] );
|
||||
|
||||
/**
|
||||
* Filters the post array to translate strings.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The post array.
|
||||
*/
|
||||
$post = apply_filters( "acf/translate_{$this->hook_name}", $post );
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of ACF posts for the given $filter.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $filter An array of args to filter by.
|
||||
* @return array
|
||||
*/
|
||||
public function get_posts( $filter = array() ) {
|
||||
$posts = array();
|
||||
|
||||
// Check database.
|
||||
$raw_posts = $this->get_raw_posts();
|
||||
if ( $raw_posts ) {
|
||||
foreach ( $raw_posts as $raw_post ) {
|
||||
$posts[] = $this->get_post( $raw_post['ID'] );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the posts array.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $posts The array of ACF posts.
|
||||
*/
|
||||
$posts = apply_filters( "acf/load_{$this->hook_name_plural}", $posts, $this->post_type );
|
||||
|
||||
// Filter results.
|
||||
if ( $filter && $posts ) {
|
||||
return $this->filter_posts( $posts, $filter );
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of raw ACF post data.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_raw_posts() {
|
||||
// Try cache.
|
||||
$cache_key = acf_cache_key( $this->cache_key_plural );
|
||||
$post_ids = wp_cache_get( $cache_key, 'acf' ); // TODO: Do we need to change the group at all?
|
||||
|
||||
if ( $post_ids === false ) {
|
||||
|
||||
// Query posts.
|
||||
$posts = get_posts(
|
||||
array(
|
||||
'posts_per_page' => -1,
|
||||
'post_type' => $this->post_type,
|
||||
'orderby' => 'menu_order title',
|
||||
'order' => 'ASC',
|
||||
'suppress_filters' => false, // Allow WPML to modify the query.
|
||||
'cache_results' => true,
|
||||
'update_post_meta_cache' => false,
|
||||
'update_post_term_cache' => false,
|
||||
'post_status' => array( 'publish', 'acf-disabled' ),
|
||||
)
|
||||
);
|
||||
|
||||
// Update $post_ids with a non-false value.
|
||||
$post_ids = array();
|
||||
foreach ( $posts as $post ) {
|
||||
$post_ids[] = $post->ID;
|
||||
}
|
||||
|
||||
// Update cache.
|
||||
wp_cache_set( $cache_key, $post_ids, 'acf' );
|
||||
}
|
||||
|
||||
// Loop over ids and populate array of ACF posts.
|
||||
$return = array();
|
||||
foreach ( $post_ids as $post_id ) {
|
||||
$raw_post = $this->get_raw_post( $post_id );
|
||||
if ( $raw_post ) {
|
||||
$return[] = $raw_post;
|
||||
}
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter the posts returned by $this->get_posts().
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $posts An array of posts to filter.
|
||||
* @param array $args An array of args to filter by.
|
||||
* @return array
|
||||
*/
|
||||
public function filter_posts( $posts, $args = array() ) {
|
||||
if ( ! empty( $args['active'] ) ) {
|
||||
$posts = array_filter(
|
||||
$posts,
|
||||
function( $post ) {
|
||||
return $post['active'];
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
return $posts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post to update.
|
||||
* @return array
|
||||
*/
|
||||
public function update_post( $post ) {
|
||||
// Validate internal post type.
|
||||
$post = $this->validate_post( $post );
|
||||
|
||||
// May have been posted. Remove slashes.
|
||||
$post = wp_unslash( $post );
|
||||
|
||||
// Parse types (converts string '0' to int 0).
|
||||
$post = acf_parse_types( $post );
|
||||
|
||||
/**
|
||||
* Fires before updating an ACF post in the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The main ACF post array.
|
||||
*/
|
||||
$post = apply_filters( "acf/pre_update_{$this->hook_name}", $post );
|
||||
|
||||
// Make a backup of internal post type data and remove some args.
|
||||
$_post = $post;
|
||||
acf_extract_vars( $_post, array( 'ID', 'key', 'title', 'menu_order', 'fields', 'active', '_valid' ) );
|
||||
|
||||
// Create array of data to save.
|
||||
$save = array(
|
||||
'ID' => $post['ID'],
|
||||
'post_status' => $post['active'] ? 'publish' : 'acf-disabled',
|
||||
'post_type' => $this->post_type,
|
||||
'post_title' => $post['title'],
|
||||
'post_name' => $post['key'],
|
||||
'post_excerpt' => sanitize_title( $post['title'] ),
|
||||
'post_content' => maybe_serialize( $_post ),
|
||||
'menu_order' => $post['menu_order'],
|
||||
'comment_status' => 'closed',
|
||||
'ping_status' => 'closed',
|
||||
);
|
||||
|
||||
// Unhook wp_targeted_link_rel() filter from WP 5.1 corrupting serialized data.
|
||||
remove_filter( 'content_save_pre', 'wp_targeted_link_rel' );
|
||||
|
||||
// Slash data.
|
||||
// WP expects all data to be slashed and will unslash it (fixes '\' character issues).
|
||||
$save = wp_slash( $save );
|
||||
|
||||
// Update or Insert.
|
||||
if ( $post['ID'] ) {
|
||||
wp_update_post( $save );
|
||||
} else {
|
||||
$post['ID'] = wp_insert_post( $save );
|
||||
}
|
||||
|
||||
$this->flush_post_cache( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been updated.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The main ACF post array.
|
||||
*/
|
||||
do_action( "acf/update_{$this->hook_name}", $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Allows full control over ACF post slugs.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $slug The post slug.
|
||||
* @param int $post_ID Post ID.
|
||||
* @param string $post_status The post status.
|
||||
* @param string $post_type Post type.
|
||||
* @param int $post_parent Post parent ID.
|
||||
* @param string $original_slug The original post slug.
|
||||
* @return string
|
||||
*/
|
||||
public function apply_unique_post_slug( $slug, $post_ID, $post_status, $post_type, $post_parent, $original_slug ) {
|
||||
// Check post type and reset to original value.
|
||||
if ( $post_type === $this->post_type ) {
|
||||
return $original_slug;
|
||||
}
|
||||
|
||||
return $slug;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all caches for this ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @return void
|
||||
*/
|
||||
public function flush_post_cache( $post ) {
|
||||
// Delete stored data.
|
||||
acf_get_store( $this->store )->remove( $post['key'] );
|
||||
|
||||
// Flush cached post_id for this field group's key.
|
||||
wp_cache_delete( acf_cache_key( $this->cache_key . $post['key'] ), 'acf' );
|
||||
|
||||
// Flush cached array of post_ids for collection of field groups.
|
||||
wp_cache_delete( acf_cache_key( $this->cache_key_plural ), 'acf' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ID of the ACF post to delete.
|
||||
* @return bool
|
||||
*/
|
||||
public function delete_post( $id = 0 ) {
|
||||
// Disable filters to ensure ACF loads data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
// Get the post.
|
||||
$post = $this->get_post( $id );
|
||||
|
||||
// Bail early if post was not found.
|
||||
if ( ! $post || ! $post['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Delete post and flush cache.
|
||||
wp_delete_post( $post['ID'], true );
|
||||
$this->flush_post_cache( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been deleted.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
do_action( "acf/delete_{$this->hook_name}", $post );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Trashes an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ID of the ACF post to trash.
|
||||
* @return bool
|
||||
*/
|
||||
public function trash_post( $id = 0 ) {
|
||||
// Disable filters to ensure ACF loads data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
$post = $this->get_post( $id );
|
||||
if ( ! $post || ! $post['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wp_trash_post( $post['ID'] );
|
||||
$this->flush_post_cache( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after a field_group has been trashed.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
do_action( "acf/trash_{$this->hook_name}", $post );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Restores an ACF post from the trash.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ID of the ACF post to untrash.
|
||||
* @return bool
|
||||
*/
|
||||
public function untrash_post( $id = 0 ) {
|
||||
// Disable filters to ensure ACF loads data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
$post = $this->get_post( $id );
|
||||
if ( ! $post || ! $post['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
wp_untrash_post( $post['ID'] );
|
||||
$this->flush_post_cache( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been untrashed.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
do_action( "acf/untrash_{$this->hook_name}", $post );
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the previous post_status instead of "draft" for the ACF internal post types.
|
||||
* Prior to WordPress 5.6.0, this filter was not needed as restored posts were always assigned their original status.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $new_status The new status of the post being restored.
|
||||
* @param int $post_id The ID of the post being restored.
|
||||
* @param string $previous_status The status of the post at the point where it was trashed.
|
||||
* @return string
|
||||
*/
|
||||
public function untrash_post_status( $new_status, $post_id, $previous_status ) {
|
||||
return ( get_post_type( $post_id ) === $this->post_type ) ? $previous_status : $new_status;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns true if the given params match an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The post array to check.
|
||||
* @return bool
|
||||
*/
|
||||
public function is_post( $post = false ) {
|
||||
return (
|
||||
is_array( $post )
|
||||
&& isset( $post['key'] )
|
||||
&& isset( $post['title'] )
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Duplicates an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ID of the post to duplicate.
|
||||
* @param int $new_post_id Optional post ID to override.
|
||||
* @return array The new ACF post array.
|
||||
*/
|
||||
public function duplicate_post( $id = 0, $new_post_id = 0 ) {
|
||||
// Disable filters to ensure ACF loads data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
$post = $this->get_post( $id );
|
||||
if ( ! $post || ! $post['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Update attributes.
|
||||
$post['ID'] = $new_post_id;
|
||||
$post['key'] = uniqid( 'group_' );
|
||||
|
||||
// Add (copy) to title when appropriate.
|
||||
if ( ! $new_post_id ) {
|
||||
$post['title'] .= ' (' . __( 'copy', 'acf' ) . ')';
|
||||
}
|
||||
|
||||
// When importing a new field group, insert a temporary post and set the field group's ID.
|
||||
// This allows fields to be updated before the field group (field group ID is needed for field parent setting).
|
||||
if ( ! $post['ID'] ) {
|
||||
$post['ID'] = wp_insert_post( array( 'post_title' => $post['key'] ) );
|
||||
}
|
||||
|
||||
$post = $this->update_post( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been duplicated.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
do_action( "acf/duplicate_{$this->hook_name}", $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Activates or deactivates an ACF post.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int|string $id The ID of the ACF post to activate/deactivate.
|
||||
* @param bool $activate True if the post should be activated.
|
||||
* @return bool
|
||||
*/
|
||||
public function update_post_active_status( $id, $activate = true ) {
|
||||
// Disable filters to ensure ACF loads data from DB.
|
||||
acf_disable_filters();
|
||||
|
||||
$post = $this->get_post( $id );
|
||||
if ( ! $post || ! $post['ID'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post['active'] = (bool) $activate;
|
||||
$updated_post = $this->update_post( $post );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been made active/inactive.
|
||||
*
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param array $updated_post The updated ACF post array.
|
||||
*/
|
||||
do_action( "acf/update_{$this->hook_name}_active_status", $updated_post );
|
||||
|
||||
if ( ! isset( $updated_post['active'] ) || $activate !== $updated_post['active'] ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current user can edit ACF posts and returns the edit url.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param int $post_id The ACF post ID.
|
||||
* @return string
|
||||
*/
|
||||
public function get_post_edit_link( $post_id ) {
|
||||
if ( $post_id && acf_current_user_can_admin() ) {
|
||||
return admin_url( 'post.php?post=' . $post_id . '&action=edit' );
|
||||
}
|
||||
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a modified ACF post array ready for export.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_post_for_export( $post = array() ) {
|
||||
// Remove args.
|
||||
acf_extract_vars( $post, array( 'ID', 'local', '_valid' ) );
|
||||
|
||||
/**
|
||||
* Filters the ACF post array before being returned to the export tool.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
return apply_filters( "acf/prepare_{$this->hook_name}_for_export", $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a string containing PHP code that can be used to create the post in ACF.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The post being exported.
|
||||
* @return string
|
||||
*/
|
||||
public function export_post_as_php( $post = array() ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
/**
|
||||
* Formats code used for PHP exports.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param string $code The code being formatted.
|
||||
* @return string
|
||||
*/
|
||||
public function format_code_for_export( $code = '' ) {
|
||||
if ( ! is_string( $code ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
$str_replace = array(
|
||||
"\n" => "\n\t",
|
||||
' ' => "\t",
|
||||
"'!!__(!!\'" => "__('",
|
||||
"!!\', !!\'" => "', '",
|
||||
"!!\')!!'" => "')",
|
||||
'array (' => 'array(',
|
||||
);
|
||||
$preg_replace = array(
|
||||
'/([\t\r\n]+?)array/' => 'array',
|
||||
'/[0-9]+ => array/' => 'array',
|
||||
);
|
||||
|
||||
$code = str_replace( array_keys( $str_replace ), array_values( $str_replace ), $code );
|
||||
$code = preg_replace( array_keys( $preg_replace ), array_values( $preg_replace ), $code );
|
||||
|
||||
return $code;
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares an ACF post for import.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @return array
|
||||
*/
|
||||
public function prepare_post_for_import( $post ) {
|
||||
/**
|
||||
* Filters the ACF post array before being returned to the import tool.
|
||||
*
|
||||
* @date 21/11/19
|
||||
* @since 5.8.8
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
return apply_filters( "acf/prepare_{$this->hook_name}_for_import", $post );
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports an ACF post into the database.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
* @return array
|
||||
*/
|
||||
public function import_post( $post ) {
|
||||
// Disable filters to ensure data is not modified by local, clone, etc.
|
||||
$filters = acf_disable_filters();
|
||||
|
||||
// Validate the post (ensures all settings exist).
|
||||
$post = $this->get_valid_post( $post );
|
||||
|
||||
// Prepare post for import (modifies settings).
|
||||
$post = $this->prepare_post_for_import( $post );
|
||||
|
||||
// Save field group.
|
||||
$post = $this->update_post( $post );
|
||||
|
||||
// Enable filters again.
|
||||
acf_enable_filters( $filters );
|
||||
|
||||
/**
|
||||
* Fires immediately after an ACF post has been imported.
|
||||
*
|
||||
* @date 12/02/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $post The ACF post array.
|
||||
*/
|
||||
do_action( "acf/import_{$this->hook_name}", $post );
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,488 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'ACF_Compatibility' ) ) :
|
||||
|
||||
class ACF_Compatibility {
|
||||
|
||||
/**
|
||||
* __construct
|
||||
*
|
||||
* Sets up the class functionality.
|
||||
*
|
||||
* @date 30/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function __construct() {
|
||||
|
||||
// actions
|
||||
add_filter( 'acf/validate_field', array( $this, 'validate_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=textarea', array( $this, 'validate_textarea_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=relationship', array( $this, 'validate_relationship_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=post_object', array( $this, 'validate_relationship_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=page_link', array( $this, 'validate_relationship_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=image', array( $this, 'validate_image_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=file', array( $this, 'validate_image_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=wysiwyg', array( $this, 'validate_wysiwyg_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=date_picker', array( $this, 'validate_date_picker_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=taxonomy', array( $this, 'validate_taxonomy_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=date_time_picker', array( $this, 'validate_date_time_picker_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field/type=user', array( $this, 'validate_user_field' ), 20, 1 );
|
||||
add_filter( 'acf/validate_field_group', array( $this, 'validate_field_group' ), 20, 1 );
|
||||
|
||||
// Modify field wrapper attributes
|
||||
add_filter( 'acf/field_wrapper_attributes', array( $this, 'field_wrapper_attributes' ), 20, 2 );
|
||||
|
||||
// location
|
||||
add_filter( 'acf/location/validate_rule/type=post_taxonomy', array( $this, 'validate_post_taxonomy_location_rule' ), 20, 1 );
|
||||
add_filter( 'acf/location/validate_rule/type=post_category', array( $this, 'validate_post_taxonomy_location_rule' ), 20, 1 );
|
||||
|
||||
// Update settings
|
||||
add_action( 'acf/init', array( $this, 'init' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* init
|
||||
*
|
||||
* Adds compatibility for deprecated settings.
|
||||
*
|
||||
* @date 10/6/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param void
|
||||
* @return void
|
||||
*/
|
||||
function init() {
|
||||
|
||||
// Update "show_admin" setting based on defined constant.
|
||||
if ( defined( 'ACF_LITE' ) && ACF_LITE ) {
|
||||
acf_update_setting( 'show_admin', false );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* field_wrapper_attributes
|
||||
*
|
||||
* Adds compatibility with deprecated field wrap attributes.
|
||||
*
|
||||
* @date 21/1/19
|
||||
* @since 5.7.10
|
||||
*
|
||||
* @param array $wrapper The wrapper attributes array.
|
||||
* @param array $field The field array.
|
||||
*/
|
||||
function field_wrapper_attributes( $wrapper, $field ) {
|
||||
|
||||
// Check compatibility setting.
|
||||
if ( acf_get_compatibility( 'field_wrapper_class' ) ) {
|
||||
$wrapper['class'] .= " field_type-{$field['type']}";
|
||||
if ( $field['key'] ) {
|
||||
$wrapper['class'] .= " field_key-{$field['key']}";
|
||||
}
|
||||
}
|
||||
|
||||
// Return wrapper.
|
||||
return $wrapper;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_field( $field ) {
|
||||
|
||||
// conditional logic data structure changed to groups in version 5.0.0
|
||||
// convert previous data (status, rules, allorany) into groups
|
||||
if ( isset( $field['conditional_logic']['status'] ) ) {
|
||||
|
||||
// check status
|
||||
if ( $field['conditional_logic']['status'] ) {
|
||||
$field['conditional_logic'] = acf_convert_rules_to_groups( $field['conditional_logic']['rules'], $field['conditional_logic']['allorany'] );
|
||||
} else {
|
||||
$field['conditional_logic'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_textarea_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_textarea_field( $field ) {
|
||||
|
||||
// formatting has been removed
|
||||
$formatting = acf_extract_var( $field, 'formatting' );
|
||||
if ( $formatting === 'br' ) {
|
||||
$field['new_lines'] = 'br';
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_relationship_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_relationship_field( $field ) {
|
||||
|
||||
// remove 'all' from post_type
|
||||
if ( acf_in_array( 'all', $field['post_type'] ) ) {
|
||||
$field['post_type'] = array();
|
||||
}
|
||||
|
||||
// remove 'all' from taxonomy
|
||||
if ( acf_in_array( 'all', $field['taxonomy'] ) ) {
|
||||
$field['taxonomy'] = array();
|
||||
}
|
||||
|
||||
// result_elements is now elements
|
||||
if ( isset( $field['result_elements'] ) ) {
|
||||
$field['elements'] = acf_extract_var( $field, 'result_elements' );
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_image_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_image_field( $field ) {
|
||||
|
||||
// save_format is now return_format
|
||||
if ( isset( $field['save_format'] ) ) {
|
||||
$field['return_format'] = acf_extract_var( $field, 'save_format' );
|
||||
}
|
||||
|
||||
// object is now array
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
$field['return_format'] = 'array';
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_wysiwyg_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_wysiwyg_field( $field ) {
|
||||
|
||||
// media_upload is now numeric
|
||||
if ( $field['media_upload'] === 'yes' ) {
|
||||
$field['media_upload'] = 1;
|
||||
} elseif ( $field['media_upload'] === 'no' ) {
|
||||
$field['media_upload'] = 0;
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_date_picker_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_date_picker_field( $field ) {
|
||||
|
||||
// date_format has changed to display_format
|
||||
if ( isset( $field['date_format'] ) ) {
|
||||
|
||||
// extract vars
|
||||
$date_format = $field['date_format'];
|
||||
$display_format = $field['display_format'];
|
||||
|
||||
// convert from js to php
|
||||
$display_format = acf_convert_date_to_php( $display_format );
|
||||
|
||||
// append settings
|
||||
$field['display_format'] = $display_format;
|
||||
$field['save_format'] = $date_format;
|
||||
|
||||
// clean up
|
||||
unset( $field['date_format'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_taxonomy_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.2.7
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_taxonomy_field( $field ) {
|
||||
|
||||
// load_save_terms deprecated in favour of separate save_terms
|
||||
if ( isset( $field['load_save_terms'] ) ) {
|
||||
$field['save_terms'] = acf_extract_var( $field, 'load_save_terms' );
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_date_time_picker_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.2.7
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_date_time_picker_field( $field ) {
|
||||
|
||||
// 3rd party date time picker
|
||||
// https://github.com/soderlind/acf-field-date-time-picker
|
||||
if ( ! empty( $field['time_format'] ) ) {
|
||||
|
||||
// extract vars
|
||||
$time_format = acf_extract_var( $field, 'time_format' );
|
||||
$date_format = acf_extract_var( $field, 'date_format' );
|
||||
$get_as_timestamp = acf_extract_var( $field, 'get_as_timestamp' );
|
||||
|
||||
// convert from js to php
|
||||
$time_format = acf_convert_time_to_php( $time_format );
|
||||
$date_format = acf_convert_date_to_php( $date_format );
|
||||
|
||||
// append settings
|
||||
$field['return_format'] = $date_format . ' ' . $time_format;
|
||||
$field['display_format'] = $date_format . ' ' . $time_format;
|
||||
|
||||
// timestamp
|
||||
if ( $get_as_timestamp === 'true' ) {
|
||||
$field['return_format'] = 'U';
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_user_field
|
||||
*
|
||||
* Adds compatibility with deprecated settings
|
||||
*
|
||||
* @date 23/04/2014
|
||||
* @since 5.2.7
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return array $field
|
||||
*/
|
||||
function validate_user_field( $field ) {
|
||||
|
||||
// remove 'all' from roles
|
||||
if ( acf_in_array( 'all', $field['role'] ) ) {
|
||||
$field['role'] = '';
|
||||
}
|
||||
|
||||
// field_type removed in favour of multiple
|
||||
if ( isset( $field['field_type'] ) ) {
|
||||
|
||||
// extract vars
|
||||
$field_type = acf_extract_var( $field, 'field_type' );
|
||||
|
||||
// multiple
|
||||
if ( $field_type === 'multi_select' ) {
|
||||
$field['multiple'] = true;
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
/*
|
||||
* validate_field_group
|
||||
*
|
||||
* This function will provide compatibility with ACF4 field groups
|
||||
*
|
||||
* @type function
|
||||
* @date 23/04/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $field_group (array)
|
||||
* @return $field_group
|
||||
*/
|
||||
function validate_field_group( $field_group ) {
|
||||
|
||||
// vars
|
||||
$version = 5;
|
||||
|
||||
// field group key was added in version 5.0.0
|
||||
// detect ACF4 data and generate key
|
||||
if ( ! $field_group['key'] ) {
|
||||
$version = 4;
|
||||
$field_group['key'] = isset( $field_group['id'] ) ? "group_{$field_group['id']}" : uniqid( 'group_' );
|
||||
}
|
||||
|
||||
// prior to version 5.0.0, settings were saved in an 'options' array
|
||||
// extract and merge options into the field group
|
||||
if ( isset( $field_group['options'] ) ) {
|
||||
$options = acf_extract_var( $field_group, 'options' );
|
||||
$field_group = array_merge( $field_group, $options );
|
||||
}
|
||||
|
||||
// location data structure changed to groups in version 4.1.0
|
||||
// convert previous data (rules, allorany) into groups
|
||||
if ( isset( $field_group['location']['rules'] ) ) {
|
||||
$field_group['location'] = acf_convert_rules_to_groups( $field_group['location']['rules'], $field_group['location']['allorany'] );
|
||||
}
|
||||
|
||||
// some location rule names have changed in version 5.0.0
|
||||
// loop over location data and modify rules
|
||||
$replace = array(
|
||||
'taxonomy' => 'post_taxonomy',
|
||||
'ef_media' => 'attachment',
|
||||
'ef_taxonomy' => 'taxonomy',
|
||||
'ef_user' => 'user_role',
|
||||
'user_type' => 'current_user_role', // 5.2.0
|
||||
);
|
||||
|
||||
// only replace 'taxonomy' rule if is an ACF4 field group
|
||||
if ( $version > 4 ) {
|
||||
unset( $replace['taxonomy'] );
|
||||
}
|
||||
|
||||
// loop over location groups
|
||||
if ( $field_group['location'] ) {
|
||||
foreach ( $field_group['location'] as $i => $group ) {
|
||||
|
||||
// loop over group rules
|
||||
if ( $group ) {
|
||||
foreach ( $group as $j => $rule ) {
|
||||
|
||||
// migrate param
|
||||
if ( isset( $replace[ $rule['param'] ] ) ) {
|
||||
$field_group['location'][ $i ][ $j ]['param'] = $replace[ $rule['param'] ];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// change layout to style (v5.0.0)
|
||||
if ( isset( $field_group['layout'] ) ) {
|
||||
$field_group['style'] = acf_extract_var( $field_group, 'layout' );
|
||||
}
|
||||
|
||||
// change no_box to seamless (v5.0.0)
|
||||
if ( $field_group['style'] === 'no_box' ) {
|
||||
$field_group['style'] = 'seamless';
|
||||
}
|
||||
|
||||
// return
|
||||
return $field_group;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_post_taxonomy_location_rule
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @date 27/8/18
|
||||
* @since 5.7.4
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
function validate_post_taxonomy_location_rule( $rule ) {
|
||||
|
||||
// previous versions of ACF (v4.4.12) saved value as term_id
|
||||
// convert term_id into "taxonomy:slug" string
|
||||
if ( is_numeric( $rule['value'] ) ) {
|
||||
$term = acf_get_term( $rule['value'] );
|
||||
if ( $term ) {
|
||||
$rule['value'] = acf_encode_term( $term );
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $rule;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
acf_new_instance( 'ACF_Compatibility' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
/*
|
||||
* acf_get_compatibility
|
||||
*
|
||||
* Returns true if compatibility is enabled for the given component.
|
||||
*
|
||||
* @date 20/1/15
|
||||
* @since 5.1.5
|
||||
*
|
||||
* @param string $name The name of the component to check.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_get_compatibility( $name ) {
|
||||
return apply_filters( "acf/compatibility/{$name}", false );
|
||||
}
|
@ -0,0 +1,154 @@
|
||||
<?php
|
||||
|
||||
// Register deprecated filters ( $deprecated, $version, $replacement ).
|
||||
acf_add_deprecated_filter( 'acf/settings/export_textdomain', '5.3.3', 'acf/settings/l10n_textdomain' );
|
||||
acf_add_deprecated_filter( 'acf/settings/export_translate', '5.3.3', 'acf/settings/l10n_field' );
|
||||
acf_add_deprecated_filter( 'acf/settings/export_translate', '5.3.3', 'acf/settings/l10n_field_group' );
|
||||
acf_add_deprecated_filter( 'acf/settings/dir', '5.6.8', 'acf/settings/url' );
|
||||
acf_add_deprecated_filter( 'acf/get_valid_field', '5.5.6', 'acf/validate_field' );
|
||||
acf_add_deprecated_filter( 'acf/get_valid_field_group', '5.5.6', 'acf/validate_field_group' );
|
||||
acf_add_deprecated_filter( 'acf/get_valid_post_id', '5.5.6', 'acf/validate_post_id' );
|
||||
acf_add_deprecated_filter( 'acf/get_field_reference', '5.6.5', 'acf/load_reference' );
|
||||
acf_add_deprecated_filter( 'acf/get_field_group', '5.7.11', 'acf/load_field_group' );
|
||||
acf_add_deprecated_filter( 'acf/get_field_groups', '5.7.11', 'acf/load_field_groups' );
|
||||
acf_add_deprecated_filter( 'acf/get_fields', '5.7.11', 'acf/load_fields' );
|
||||
|
||||
// Register variations for deprecated filters.
|
||||
acf_add_filter_variations( 'acf/get_valid_field', array( 'type' ), 0 );
|
||||
|
||||
/**
|
||||
* acf_render_field_wrap_label
|
||||
*
|
||||
* Renders the field's label.
|
||||
*
|
||||
* @date 19/9/17
|
||||
* @since 5.6.3
|
||||
* @deprecated 5.6.5
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_render_field_wrap_label( $field ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_render_field_label()' );
|
||||
|
||||
// Render.
|
||||
acf_render_field_label( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_render_field_wrap_description
|
||||
*
|
||||
* Renders the field's instructions.
|
||||
*
|
||||
* @date 19/9/17
|
||||
* @since 5.6.3
|
||||
* @deprecated 5.6.5
|
||||
*
|
||||
* @param array $field The field array.
|
||||
* @return void
|
||||
*/
|
||||
function acf_render_field_wrap_description( $field ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_render_field_instructions()' );
|
||||
|
||||
// Render.
|
||||
acf_render_field_instructions( $field );
|
||||
}
|
||||
|
||||
/*
|
||||
* acf_get_fields_by_id
|
||||
*
|
||||
* Returns and array of fields for the given $parent_id.
|
||||
*
|
||||
* @date 27/02/2014
|
||||
* @since 5.0.0.
|
||||
* @deprecated 5.7.11
|
||||
*
|
||||
* @param int $parent_id The parent ID.
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_fields_by_id( $parent_id = 0 ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.7.11', 'acf_get_fields()' );
|
||||
|
||||
// Return fields.
|
||||
return acf_get_fields(
|
||||
array(
|
||||
'ID' => $parent_id,
|
||||
'key' => "group_$parent_id",
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_update_option
|
||||
*
|
||||
* A wrapper for the WP update_option but provides logic for a 'no' autoload
|
||||
*
|
||||
* @date 4/01/2014
|
||||
* @since 5.0.0
|
||||
* @deprecated 5.7.11
|
||||
*
|
||||
* @param string $option The option name.
|
||||
* @param string $value The option value.
|
||||
* @param string $autoload An optional autoload value.
|
||||
* @return bool
|
||||
*/
|
||||
function acf_update_option( $option = '', $value = '', $autoload = null ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.7.11', 'update_option()' );
|
||||
|
||||
// Update.
|
||||
if ( $autoload === null ) {
|
||||
$autoload = (bool) acf_get_setting( 'autoload' );
|
||||
}
|
||||
return update_option( $option, $value, $autoload );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_field_reference
|
||||
*
|
||||
* Finds the field key for a given field name and post_id.
|
||||
*
|
||||
* @date 26/1/18
|
||||
* @since 5.6.5
|
||||
* @deprecated 5.6.8
|
||||
*
|
||||
* @param string $field_name The name of the field. eg 'sub_heading'
|
||||
* @param mixed $post_id The post_id of which the value is saved against
|
||||
* @return string $reference The field key
|
||||
*/
|
||||
function acf_get_field_reference( $field_name, $post_id ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.6.8', 'acf_get_reference()' );
|
||||
|
||||
// Return reference.
|
||||
return acf_get_reference( $field_name, $post_id );
|
||||
}
|
||||
|
||||
/**
|
||||
* acf_get_dir
|
||||
*
|
||||
* Returns the plugin url to a specified file.
|
||||
*
|
||||
* @date 28/09/13
|
||||
* @since 5.0.0
|
||||
* @deprecated 5.6.8
|
||||
*
|
||||
* @param string $filename The specified file.
|
||||
* @return string
|
||||
*/
|
||||
function acf_get_dir( $filename = '' ) {
|
||||
|
||||
// Warning.
|
||||
_deprecated_function( __FUNCTION__, '5.6.8', 'acf_get_url()' );
|
||||
|
||||
// Return.
|
||||
return acf_get_url( $filename );
|
||||
}
|
@ -0,0 +1,479 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit; // Exit if accessed directly
|
||||
}
|
||||
|
||||
if ( ! class_exists( 'acf_fields' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_fields {
|
||||
|
||||
/** @var array Contains an array of field type instances */
|
||||
var $types = array();
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* This function will setup the class functionality
|
||||
*
|
||||
* @type function
|
||||
* @date 5/03/2014
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function __construct() {
|
||||
/* do nothing */
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* register_field_type
|
||||
*
|
||||
* This function will register a field type instance
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $class (string)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function register_field_type( $class ) {
|
||||
|
||||
// allow instance
|
||||
if ( $class instanceof acf_field ) {
|
||||
$this->types[ $class->name ] = $class;
|
||||
|
||||
// allow class name
|
||||
} else {
|
||||
$instance = new $class();
|
||||
$this->types[ $instance->name ] = $instance;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_field_type
|
||||
*
|
||||
* This function will return a field type instance
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $name (string)
|
||||
* @return (mixed)
|
||||
*/
|
||||
|
||||
function get_field_type( $name ) {
|
||||
return isset( $this->types[ $name ] ) ? $this->types[ $name ] : null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* is_field_type
|
||||
*
|
||||
* This function will return true if a field type exists
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $name (string)
|
||||
* @return (mixed)
|
||||
*/
|
||||
|
||||
function is_field_type( $name ) {
|
||||
return isset( $this->types[ $name ] );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* register_field_type_info
|
||||
*
|
||||
* This function will store a basic array of info about the field type
|
||||
* to later be overriden by the above register_field_type function
|
||||
*
|
||||
* @type function
|
||||
* @date 29/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $info (array)
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function register_field_type_info( $info ) {
|
||||
|
||||
// convert to object
|
||||
$instance = (object) $info;
|
||||
$this->types[ $instance->name ] = $instance;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_field_types
|
||||
*
|
||||
* This function will return an array of all field types
|
||||
*
|
||||
* @type function
|
||||
* @date 6/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $name (string)
|
||||
* @return (mixed)
|
||||
*/
|
||||
|
||||
function get_field_types() {
|
||||
return $this->types;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf()->fields = new acf_fields();
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
||||
/*
|
||||
* acf_register_field_type
|
||||
*
|
||||
* alias of acf()->fields->register_field_type()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_register_field_type( $class ) {
|
||||
return acf()->fields->register_field_type( $class );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_register_field_type_info
|
||||
*
|
||||
* alias of acf()->fields->register_field_type_info()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_register_field_type_info( $info ) {
|
||||
return acf()->fields->register_field_type_info( $info );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_field_type
|
||||
*
|
||||
* alias of acf()->fields->get_field_type()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_get_field_type( $name ) {
|
||||
return acf()->fields->get_field_type( $name );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_field_types
|
||||
*
|
||||
* alias of acf()->fields->get_field_types()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_get_field_types( $args = array() ) {
|
||||
|
||||
// default
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'public' => true, // true, false
|
||||
)
|
||||
);
|
||||
|
||||
// get field types
|
||||
$field_types = acf()->fields->get_field_types();
|
||||
|
||||
// filter
|
||||
return wp_filter_object_list( $field_types, $args );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* acf_get_field_types_info
|
||||
*
|
||||
* Returns an array containing information about each field type
|
||||
*
|
||||
* @date 18/6/18
|
||||
* @since 5.6.9
|
||||
*
|
||||
* @param type $var Description. Default.
|
||||
* @return type Description.
|
||||
*/
|
||||
|
||||
function acf_get_field_types_info( $args = array() ) {
|
||||
|
||||
// vars
|
||||
$data = array();
|
||||
$field_types = acf_get_field_types();
|
||||
|
||||
// loop
|
||||
foreach ( $field_types as $type ) {
|
||||
$data[ $type->name ] = array_filter(
|
||||
array(
|
||||
'label' => $type->label,
|
||||
'name' => $type->name,
|
||||
'description' => $type->description,
|
||||
'category' => $type->category,
|
||||
'public' => $type->public,
|
||||
'doc_url' => $type->doc_url,
|
||||
'tutorial_url' => $type->tutorial_url,
|
||||
'preview_image' => $type->preview_image,
|
||||
'pro' => $type->pro,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// return
|
||||
return $data;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_is_field_type
|
||||
*
|
||||
* alias of acf()->fields->is_field_type()
|
||||
*
|
||||
* @type function
|
||||
* @date 31/5/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function acf_is_field_type( $name = '' ) {
|
||||
return acf()->fields->is_field_type( $name );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_field_type_prop
|
||||
*
|
||||
* This function will return a field type's property
|
||||
*
|
||||
* @type function
|
||||
* @date 1/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function acf_get_field_type_prop( $name = '', $prop = '' ) {
|
||||
$type = acf_get_field_type( $name );
|
||||
return ( $type && isset( $type->$prop ) ) ? $type->$prop : null;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_get_field_type_label
|
||||
*
|
||||
* This function will return the label of a field type
|
||||
*
|
||||
* @type function
|
||||
* @date 1/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param n/a
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function acf_get_field_type_label( $name = '' ) {
|
||||
$label = acf_get_field_type_prop( $name, 'label' );
|
||||
return $label ? $label : '<span class="acf-tooltip-js" title="' . __( 'Field type does not exist', 'acf' ) . '">' . __( 'Unknown', 'acf' ) . '</span>';
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* acf_field_type_exists (deprecated)
|
||||
*
|
||||
* deprecated in favour of acf_is_field_type()
|
||||
*
|
||||
* @type function
|
||||
* @date 1/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $type (string)
|
||||
* @return (boolean)
|
||||
*/
|
||||
|
||||
function acf_field_type_exists( $type = '' ) {
|
||||
return acf_is_field_type( $type );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of localised field categories.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_field_categories_i18n() {
|
||||
|
||||
$categories_i18n = array(
|
||||
'basic' => __( 'Basic', 'acf' ),
|
||||
'content' => __( 'Content', 'acf' ),
|
||||
'choice' => __( 'Choice', 'acf' ),
|
||||
'relational' => __( 'Relational', 'acf' ),
|
||||
'advanced' => __( 'Advanced', 'acf' ),
|
||||
'layout' => __( 'Layout', 'acf' ),
|
||||
'pro' => __( 'PRO', 'acf' ),
|
||||
);
|
||||
|
||||
return apply_filters( 'acf/localized_field_categories', $categories_i18n );
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns an multi-dimentional array of field types "name => label" grouped by category
|
||||
*
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function acf_get_grouped_field_types() {
|
||||
|
||||
// vars
|
||||
$types = acf_get_field_types();
|
||||
$groups = array();
|
||||
$l10n = acf_get_field_categories_i18n();
|
||||
|
||||
// loop
|
||||
foreach ( $types as $type ) {
|
||||
|
||||
// translate
|
||||
$cat = $type->category;
|
||||
$cat = isset( $l10n[ $cat ] ) ? $l10n[ $cat ] : $cat;
|
||||
|
||||
// append
|
||||
$groups[ $cat ][ $type->name ] = $type->label;
|
||||
}
|
||||
|
||||
// filter
|
||||
$groups = apply_filters( 'acf/get_field_types', $groups );
|
||||
|
||||
// return
|
||||
return $groups;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of tabs for a field type.
|
||||
* We combine a list of default tabs with filtered tabs.
|
||||
* I.E. Default tabs should be static and should not be changed by the
|
||||
* filtered tabs.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array Key/value array of the default settings tabs for field type settings.
|
||||
*/
|
||||
function acf_get_combined_field_type_settings_tabs() {
|
||||
$default_field_type_settings_tabs = array(
|
||||
'general' => __( 'General', 'acf' ),
|
||||
'validation' => __( 'Validation', 'acf' ),
|
||||
'presentation' => __( 'Presentation', 'acf' ),
|
||||
'conditional_logic' => __( 'Conditional Logic', 'acf' ),
|
||||
);
|
||||
|
||||
$field_type_settings_tabs = (array) apply_filters( 'acf/field_group/additional_field_settings_tabs', array() );
|
||||
|
||||
// remove any default tab values from filter tabs.
|
||||
foreach ( $field_type_settings_tabs as $key => $tab ) {
|
||||
if ( isset( $default_field_type_settings_tabs[ $key ] ) ) {
|
||||
unset( $field_type_settings_tabs[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
$combined_field_type_settings_tabs = array_merge( $default_field_type_settings_tabs, $field_type_settings_tabs );
|
||||
|
||||
return $combined_field_type_settings_tabs;
|
||||
}
|
||||
|
||||
|
||||
|
||||
/**
|
||||
* Get the PRO only fields and their core metadata.
|
||||
*
|
||||
* @since 6.1
|
||||
*
|
||||
* @return array An array of all the pro field types and their field type selection required meta data.
|
||||
*/
|
||||
function acf_get_pro_field_types() {
|
||||
return array(
|
||||
'clone' => array(
|
||||
'name' => 'clone',
|
||||
'label' => _x( 'Clone', 'noun', 'acf' ),
|
||||
'doc_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/clone/', 'docs', 'field-type-selection' ),
|
||||
'preview_image' => acf_get_url() . '/assets/images/field-type-previews/field-preview-clone.png',
|
||||
'description' => __( 'This allows you to select and display existing fields. It does not duplicate any fields in the database, but loads and displays the selected fields at run-time. The Clone field can either replace itself with the selected fields or display the selected fields as a group of subfields.', 'acf' ),
|
||||
'category' => 'layout',
|
||||
'pro' => true,
|
||||
),
|
||||
'flexible_content' => array(
|
||||
'name' => 'flexible_content',
|
||||
'label' => __( 'Flexible Content', 'acf' ),
|
||||
'doc_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/flexible-content/', 'docs', 'field-type-selection' ),
|
||||
'preview_image' => acf_get_url() . '/assets/images/field-type-previews/field-preview-flexible-content.png',
|
||||
'description' => __( 'This provides a simple, structured, layout-based editor. The Flexible Content field allows you to define, create and manage content with total control by using layouts and subfields to design the available blocks.', 'acf' ),
|
||||
'tutorial_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/building-layouts-with-the-flexible-content-field-in-a-theme/', 'docs', 'field-type-selection' ),
|
||||
'category' => 'layout',
|
||||
'pro' => true,
|
||||
),
|
||||
'gallery' => array(
|
||||
'name' => 'gallery',
|
||||
'label' => __( 'Gallery', 'acf' ),
|
||||
'doc_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/gallery/', 'docs', 'field-type-selection' ),
|
||||
'preview_image' => acf_get_url() . '/assets/images/field-type-previews/field-preview-gallery.png',
|
||||
'description' => __( 'This provides an interactive interface for managing a collection of attachments. Most settings are similar to the Image field type. Additional settings allow you to specify where new attachments are added in the gallery and the minimum/maximum number of attachments allowed.', 'acf' ),
|
||||
'tutorial_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/how-to-use-the-gallery-field/', 'docs', 'field-type-selection' ),
|
||||
'category' => 'content',
|
||||
'pro' => true,
|
||||
),
|
||||
'repeater' => array(
|
||||
'name' => 'repeater',
|
||||
'label' => __( 'Repeater', 'acf' ),
|
||||
'doc_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/repeater/', 'docs', 'field-type-selection' ),
|
||||
'preview_image' => acf_get_url() . '/assets/images/field-type-previews/field-preview-repeater.png',
|
||||
'description' => __( 'This provides a solution for repeating content such as slides, team members, and call-to-action tiles, by acting as a parent to a set of subfields which can be repeated again and again.', 'acf' ),
|
||||
'tutorial_url' => acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/repeater/how-to-use-the-repeater-field/', 'docs', 'field-type-selection' ),
|
||||
'category' => 'layout',
|
||||
'pro' => true,
|
||||
),
|
||||
);
|
||||
}
|
@ -0,0 +1,152 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field__accordion' ) ) :
|
||||
|
||||
class acf_field__accordion extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/**
|
||||
* initialize
|
||||
*
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @date 30/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'accordion';
|
||||
$this->label = __( 'Accordion', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Allows you to group and organize custom fields into collapsable panels that are shown while editing content. Useful for keeping large datasets tidy.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-accordion.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/accordion/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'open' => 0,
|
||||
'multi_expand' => 0,
|
||||
'endpoint' => 0,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field
|
||||
*
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @date 30/10/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'class' => 'acf-fields',
|
||||
'data-open' => $field['open'],
|
||||
'data-multi_expand' => $field['multi_expand'],
|
||||
'data-endpoint' => $field['endpoint'],
|
||||
);
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>></div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Open', 'acf' ),
|
||||
'instructions' => __( 'Display this accordion as open on page load.', 'acf' ),
|
||||
'name' => 'open',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Multi-expand', 'acf' ),
|
||||
'instructions' => __( 'Allow this accordion to open without closing others.', 'acf' ),
|
||||
'name' => 'multi_expand',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Endpoint', 'acf' ),
|
||||
'instructions' => __( 'Define an endpoint for the previous accordion to stop. This accordion will not be visible.', 'acf' ),
|
||||
'name' => 'endpoint',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_field()
|
||||
*
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field__accordion' );
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,348 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_button_group' ) ) :
|
||||
|
||||
class acf_field_button_group extends acf_field {
|
||||
|
||||
|
||||
/**
|
||||
* initialize()
|
||||
*
|
||||
* This function will setup the field type data
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param n/a
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function initialize() {
|
||||
|
||||
// vars
|
||||
$this->name = 'button_group';
|
||||
$this->label = __( 'Button Group', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of buttons with values that you specify, users can choose one option from the values provided.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-button-group.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/button-group/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'value',
|
||||
'layout' => 'horizontal',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field()
|
||||
*
|
||||
* Creates the field's input HTML
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field settings array
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
$selected = null;
|
||||
$buttons = array();
|
||||
$value = esc_attr( $field['value'] );
|
||||
|
||||
// bail ealrly if no choices
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// buttons
|
||||
foreach ( $field['choices'] as $_value => $_label ) {
|
||||
|
||||
// checked
|
||||
$checked = ( $value === esc_attr( $_value ) );
|
||||
if ( $checked ) {
|
||||
$selected = true;
|
||||
}
|
||||
|
||||
// append
|
||||
$buttons[] = array(
|
||||
'name' => $field['name'],
|
||||
'value' => $_value,
|
||||
'label' => $_label,
|
||||
'checked' => $checked,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// maybe select initial value
|
||||
if ( ! $field['allow_null'] && $selected === null ) {
|
||||
$buttons[0]['checked'] = true;
|
||||
}
|
||||
|
||||
// div
|
||||
$div = array( 'class' => 'acf-button-group' );
|
||||
|
||||
if ( $field['layout'] == 'vertical' ) {
|
||||
$div['class'] .= ' -vertical'; }
|
||||
if ( $field['class'] ) {
|
||||
$div['class'] .= ' ' . $field['class']; }
|
||||
if ( $field['allow_null'] ) {
|
||||
$div['data-allow_null'] = 1; }
|
||||
|
||||
// hdden input
|
||||
$html .= acf_get_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// open
|
||||
$html .= '<div ' . acf_esc_attr( $div ) . '>';
|
||||
|
||||
// loop
|
||||
foreach ( $buttons as $button ) {
|
||||
|
||||
// checked
|
||||
if ( $button['checked'] ) {
|
||||
$button['checked'] = 'checked';
|
||||
} else {
|
||||
unset( $button['checked'] );
|
||||
}
|
||||
|
||||
// append
|
||||
$html .= acf_get_radio_input( $button );
|
||||
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* render_field_settings()
|
||||
*
|
||||
* Creates the field's settings HTML
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field settings array
|
||||
* @return n/a
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', '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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function update_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->update_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* This filter is appied to the $value after it is loaded from the db
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post ID from which the value was loaded from
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $value
|
||||
*/
|
||||
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->load_value( $value, $post_id, $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->translate_field( $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* This filter is appied to the $value after it is loaded from the db and before it is returned to the template
|
||||
*
|
||||
* @date 18/9/17
|
||||
* @since 5.6.3
|
||||
*
|
||||
* @param mixed $value The value found in the database
|
||||
* @param mixed $post_id The post ID from which the value was loaded from
|
||||
* @param array $field The field array holding all the field options
|
||||
* @return $value
|
||||
*/
|
||||
|
||||
function format_value( $value, $post_id, $field ) {
|
||||
|
||||
return acf_get_field_type( 'radio' )->format_value( $value, $post_id, $field );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user has defined keys for the buttons,
|
||||
* we should use the keys for the available options to POST to,
|
||||
* since they are what is displayed in GET requests.
|
||||
*/
|
||||
$button_keys = array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
);
|
||||
|
||||
$schema['enum'] = empty( $button_keys ) ? $field['choices'] : $button_keys;
|
||||
$schema['enum'][] = null;
|
||||
|
||||
// Allow null via UI will value to empty string.
|
||||
if ( ! empty( $field['allow_null'] ) ) {
|
||||
$schema['enum'][] = '';
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_button_group' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,658 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_checkbox' ) ) :
|
||||
|
||||
class acf_field_checkbox extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'checkbox';
|
||||
$this->label = __( 'Checkbox', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of checkbox inputs that allow the user to select one, or multiple values that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-checkbox.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/checkbox/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'layout' => 'vertical',
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'allow_custom' => 0,
|
||||
'save_custom' => 0,
|
||||
'toggle' => 0,
|
||||
'return_format' => 'value',
|
||||
'custom_choice_button_text' => __( 'Add new choice', 'acf' ),
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field (array) the $field being rendered
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array) the $field being edited
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function render_field( $field ) {
|
||||
|
||||
// reset vars
|
||||
$this->_values = array();
|
||||
$this->_all_checked = true;
|
||||
|
||||
// ensure array
|
||||
$field['value'] = acf_get_array( $field['value'] );
|
||||
$field['choices'] = acf_get_array( $field['choices'] );
|
||||
|
||||
// hiden input
|
||||
acf_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// vars
|
||||
$li = '';
|
||||
$ul = array(
|
||||
'class' => 'acf-checkbox-list',
|
||||
);
|
||||
|
||||
// append to class
|
||||
$ul['class'] .= ' ' . ( $field['layout'] == 'horizontal' ? 'acf-hl' : 'acf-bl' );
|
||||
$ul['class'] .= ' ' . $field['class'];
|
||||
|
||||
// checkbox saves an array
|
||||
$field['name'] .= '[]';
|
||||
|
||||
// choices
|
||||
if ( ! empty( $field['choices'] ) ) {
|
||||
|
||||
// choices
|
||||
$li .= $this->render_field_choices( $field );
|
||||
|
||||
// toggle
|
||||
if ( $field['toggle'] ) {
|
||||
$li = $this->render_field_toggle( $field ) . $li;
|
||||
}
|
||||
}
|
||||
|
||||
// custom
|
||||
if ( $field['allow_custom'] ) {
|
||||
$li .= $this->render_field_custom( $field );
|
||||
}
|
||||
|
||||
// return
|
||||
echo '<ul ' . acf_esc_attr( $ul ) . '>' . "\n" . $li . '</ul>' . "\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_choices
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function render_field_choices( $field ) {
|
||||
|
||||
// walk
|
||||
return $this->walk( $field['choices'], $field );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates values for the checkbox field
|
||||
*
|
||||
* @date 09/12/2022
|
||||
* @since 6.0.0
|
||||
*
|
||||
* @param bool $valid If the field is valid.
|
||||
* @param mixed $value The value to validate.
|
||||
* @param array $field The main field array.
|
||||
* @param string $input The input element's name attribute.
|
||||
*
|
||||
* @return bool
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
if ( ! is_array( $value ) || empty( $field['allow_custom'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
foreach ( $value as $value ) {
|
||||
if ( empty( $value ) && $value !== '0' ) {
|
||||
return __( 'Checkbox custom values cannot be empty. Uncheck any empty values.', 'acf' );
|
||||
}
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_toggle
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function render_field_toggle( $field ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'type' => 'checkbox',
|
||||
'class' => 'acf-checkbox-toggle',
|
||||
'label' => __( 'Toggle All', 'acf' ),
|
||||
);
|
||||
|
||||
// custom label
|
||||
if ( is_string( $field['toggle'] ) ) {
|
||||
$atts['label'] = $field['toggle'];
|
||||
}
|
||||
|
||||
// checked
|
||||
if ( $this->_all_checked ) {
|
||||
$atts['checked'] = 'checked';
|
||||
}
|
||||
|
||||
// return
|
||||
return '<li>' . acf_get_checkbox_input( $atts ) . '</li>' . "\n";
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_custom
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 15/7/17
|
||||
* @since 5.6.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function render_field_custom( $field ) {
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
|
||||
// loop
|
||||
foreach ( $field['value'] as $value ) {
|
||||
|
||||
// ignore if already eixsts
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars
|
||||
$esc_value = esc_attr( $value );
|
||||
$text_input = array(
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// bail early if choice already exists
|
||||
if ( in_array( $esc_value, $this->_values ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append
|
||||
$html .= '<li><input class="acf-checkbox-custom" type="checkbox" checked="checked" />' . acf_get_text_input( $text_input ) . '</li>' . "\n";
|
||||
|
||||
}
|
||||
|
||||
// append button
|
||||
$html .= '<li><a href="#" class="button acf-add-checkbox">' . esc_attr( $field['custom_choice_button_text'] ) . '</a></li>' . "\n";
|
||||
|
||||
// return
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
function walk( $choices = array(), $args = array(), $depth = 0 ) {
|
||||
|
||||
// bail early if no choices
|
||||
if ( empty( $choices ) ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
// defaults
|
||||
$args = wp_parse_args(
|
||||
$args,
|
||||
array(
|
||||
'id' => '',
|
||||
'type' => 'checkbox',
|
||||
'name' => '',
|
||||
'value' => array(),
|
||||
'disabled' => array(),
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$html = '';
|
||||
|
||||
// sanitize values for 'selected' matching
|
||||
if ( $depth == 0 ) {
|
||||
$args['value'] = array_map( 'esc_attr', $args['value'] );
|
||||
$args['disabled'] = array_map( 'esc_attr', $args['disabled'] );
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $choices as $value => $label ) {
|
||||
|
||||
// open
|
||||
$html .= '<li>';
|
||||
|
||||
// optgroup
|
||||
if ( is_array( $label ) ) {
|
||||
|
||||
$html .= '<ul>' . "\n";
|
||||
$html .= $this->walk( $label, $args, $depth + 1 );
|
||||
$html .= '</ul>';
|
||||
|
||||
// option
|
||||
} else {
|
||||
|
||||
// vars
|
||||
$esc_value = esc_attr( $value );
|
||||
$atts = array(
|
||||
'id' => $args['id'] . '-' . str_replace( ' ', '-', $value ),
|
||||
'type' => $args['type'],
|
||||
'name' => $args['name'],
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
);
|
||||
|
||||
// selected
|
||||
if ( in_array( $esc_value, $args['value'] ) ) {
|
||||
$atts['checked'] = 'checked';
|
||||
} else {
|
||||
$this->_all_checked = false;
|
||||
}
|
||||
|
||||
// disabled
|
||||
if ( in_array( $esc_value, $args['disabled'] ) ) {
|
||||
$atts['disabled'] = 'disabled';
|
||||
}
|
||||
|
||||
// store value added
|
||||
$this->_values[] = $esc_value;
|
||||
|
||||
// append
|
||||
$html .= acf_get_checkbox_input( $atts );
|
||||
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</li>' . "\n";
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_encode_choices( $field['default_value'], false );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Enter each default value on a new line', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', '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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Custom Values', 'acf' ),
|
||||
'name' => 'allow_custom',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Allow 'custom' values to be added", 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Custom Values', 'acf' ),
|
||||
'name' => 'save_custom',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Save 'custom' values to the field's choices", 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'allow_custom',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Add Toggle All', 'acf' ),
|
||||
'instructions' => __( 'Prepend an extra checkbox to toggle all choices', 'acf' ),
|
||||
'name' => 'toggle',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the field group ID (post_type = acf)
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
|
||||
function update_field( $field ) {
|
||||
|
||||
// Decode choices (convert to array).
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_decode_choices( $field['default_value'], true );
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 is empty
|
||||
if ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// select -> update_value()
|
||||
$value = acf_get_field_type( 'select' )->update_value( $value, $post_id, $field );
|
||||
|
||||
// save_other_choice
|
||||
if ( $field['save_custom'] ) {
|
||||
|
||||
// get raw $field (may have been changed via repeater field)
|
||||
// if field is local, it won't have an ID
|
||||
$selector = $field['ID'] ? $field['ID'] : $field['key'];
|
||||
$field = acf_get_field( $selector );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if no ID (JSON only)
|
||||
if ( ! $field['ID'] ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $value as $v ) {
|
||||
|
||||
// ignore if already eixsts
|
||||
if ( isset( $field['choices'][ $v ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// unslash (fixes serialize single quote issue)
|
||||
$v = wp_unslash( $v );
|
||||
|
||||
// sanitize (remove tags)
|
||||
$v = sanitize_text_field( $v );
|
||||
|
||||
// append
|
||||
$field['choices'][ $v ] = $v;
|
||||
|
||||
}
|
||||
|
||||
// save
|
||||
acf_update_field( $field );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->translate_field( $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 is empty.
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return array();
|
||||
}
|
||||
|
||||
// Always convert to array of items.
|
||||
$value = acf_array( $value );
|
||||
|
||||
// Return.
|
||||
return acf_get_field_type( 'select' )->format_value( $value, $post_id, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'string', 'array', 'null' ),
|
||||
'required' => isset( $field['required'] ) && $field['required'],
|
||||
'items' => array(
|
||||
'type' => array( 'string', 'integer' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
// If we allow custom values, nothing else to do here.
|
||||
if ( ! empty( $field['allow_custom'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user has defined keys for the checkboxes,
|
||||
* we should use the keys for the available options to POST to,
|
||||
* since they are what is displayed in GET requests.
|
||||
*/
|
||||
$checkbox_keys = array_map(
|
||||
'strval',
|
||||
array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
)
|
||||
);
|
||||
|
||||
// Support users passing integers for the keys as well.
|
||||
$checkbox_keys = array_merge( $checkbox_keys, array_map( 'intval', array_keys( $field['choices'] ) ) );
|
||||
|
||||
$schema['items']['enum'] = empty( $checkbox_keys ) ? $field['choices'] : $checkbox_keys;
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_checkbox' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_color_picker' ) ) :
|
||||
|
||||
class acf_field_color_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'color_picker';
|
||||
$this->label = __( 'Color Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for selecting a color, or specifying a Hex value.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-color-picker.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/color-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'enable_opacity' => false,
|
||||
'return_format' => 'string', // 'string'|'array'
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// Register scripts for non-admin.
|
||||
// Applies logic from wp_default_scripts() function defined in "wp-includes/script-loader.php".
|
||||
if ( ! is_admin() ) {
|
||||
$suffix = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
$scripts = wp_scripts();
|
||||
$scripts->add( 'iris', '/wp-admin/js/iris.min.js', array( 'jquery-ui-draggable', 'jquery-ui-slider', 'jquery-touch-punch' ), '1.0.7', 1 );
|
||||
$scripts->add( 'wp-color-picker', "/wp-admin/js/color-picker$suffix.js", array( 'iris' ), false, 1 );
|
||||
|
||||
// Handle localisation across multiple WP versions.
|
||||
// WP 5.0+
|
||||
if ( method_exists( $scripts, 'set_translations' ) ) {
|
||||
$scripts->set_translations( 'wp-color-picker' );
|
||||
// WP 4.9
|
||||
} else {
|
||||
$scripts->localize(
|
||||
'wp-color-picker',
|
||||
'wpColorPickerL10n',
|
||||
array(
|
||||
'clear' => __( 'Clear', 'acf' ),
|
||||
'clearAriaLabel' => __( 'Clear color', 'acf' ),
|
||||
'defaultString' => __( 'Default', 'acf' ),
|
||||
'defaultAriaLabel' => __( 'Select default color', 'acf' ),
|
||||
'pick' => __( 'Select Color', 'acf' ),
|
||||
'defaultLabel' => __( 'Color value', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// Enqueue alpha color picker assets.
|
||||
wp_enqueue_script(
|
||||
'acf-color-picker-alpha',
|
||||
acf_get_url( 'assets/inc/color-picker-alpha/wp-color-picker-alpha.js' ),
|
||||
array( 'jquery', 'wp-color-picker' ),
|
||||
'3.0.0'
|
||||
);
|
||||
|
||||
// Enqueue.
|
||||
wp_enqueue_style( 'wp-color-picker' );
|
||||
wp_enqueue_script( 'wp-color-picker' );
|
||||
|
||||
acf_localize_data(
|
||||
array(
|
||||
'colorPickerL10n' => array(
|
||||
'hex_string' => __( 'Hex String', 'acf' ),
|
||||
'rgba_string' => __( 'RGBA String', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$text_input = acf_get_sub_array( $field, array( 'id', 'class', 'name', 'value' ) );
|
||||
$hidden_input = acf_get_sub_array( $field, array( 'name', 'value' ) );
|
||||
|
||||
// Color picker alpha library requires a specific data attribute to exist.
|
||||
if ( $field['enable_opacity'] ) {
|
||||
$text_input['data-alpha-enabled'] = true;
|
||||
}
|
||||
|
||||
// html
|
||||
?>
|
||||
<div class="acf-color-picker">
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// display_format
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
'placeholder' => '#FFFFFF',
|
||||
)
|
||||
);
|
||||
|
||||
// Toggle opacity control.
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Enable Transparency', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'enable_opacity',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// Return format control.
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'string' => __( 'Hex String', 'acf' ),
|
||||
'array' => __( 'RGBA Array', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Format the value for use in templates. At this stage, the value has been loaded from the
|
||||
* database and is being returned by an API function such as get_field(), the_field(), etc.
|
||||
*
|
||||
* @since 5.10
|
||||
* @date 15/12/20
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int $post_id
|
||||
* @param array $field
|
||||
*
|
||||
* @return string|array
|
||||
*/
|
||||
public function format_value( $value, $post_id, $field ) {
|
||||
if ( isset( $field['return_format'] ) && $field['return_format'] === 'array' ) {
|
||||
$value = $this->string_to_array( $value );
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert either a Hexadecimal or RGBA string to an RGBA array.
|
||||
*
|
||||
* @since 5.10
|
||||
* @date 15/12/20
|
||||
*
|
||||
* @param string $value
|
||||
* @return array
|
||||
*/
|
||||
private function string_to_array( $value ) {
|
||||
$value = is_string( $value ) ? trim( $value ) : '';
|
||||
|
||||
// Match and collect r,g,b values from 6 digit hex code. If there are 4
|
||||
// match-results, we have the values we need to build an r,g,b,a array.
|
||||
preg_match( '/^#([0-9a-f]{2})([0-9a-f]{2})([0-9a-f]{2})$/i', $value, $matches );
|
||||
if ( count( $matches ) === 4 ) {
|
||||
return array(
|
||||
'red' => hexdec( $matches[1] ),
|
||||
'green' => hexdec( $matches[2] ),
|
||||
'blue' => hexdec( $matches[3] ),
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Match and collect r,g,b values from 3 digit hex code. If there are 4
|
||||
// match-results, we have the values we need to build an r,g,b,a array.
|
||||
// We have to duplicate the matched hex digit for 3 digit hex codes.
|
||||
preg_match( '/^#([0-9a-f])([0-9a-f])([0-9a-f])$/i', $value, $matches );
|
||||
if ( count( $matches ) === 4 ) {
|
||||
return array(
|
||||
'red' => hexdec( $matches[1] . $matches[1] ),
|
||||
'green' => hexdec( $matches[2] . $matches[2] ),
|
||||
'blue' => hexdec( $matches[3] . $matches[3] ),
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
|
||||
// Attempt to match an rgba(…) or rgb(…) string (case-insensitive), capturing the decimals
|
||||
// as a string. If there are two match results, we have the RGBA decimal values as a
|
||||
// comma-separated string. Break it apart and, depending on the number of values, return
|
||||
// our formatted r,g,b,a array.
|
||||
preg_match( '/^rgba?\(([0-9,.]+)\)/i', $value, $matches );
|
||||
if ( count( $matches ) === 2 ) {
|
||||
$decimals = explode( ',', $matches[1] );
|
||||
|
||||
// Handle rgba() format.
|
||||
if ( count( $decimals ) === 4 ) {
|
||||
return array(
|
||||
'red' => (int) $decimals[0],
|
||||
'green' => (int) $decimals[1],
|
||||
'blue' => (int) $decimals[2],
|
||||
'alpha' => (float) $decimals[3],
|
||||
);
|
||||
}
|
||||
|
||||
// Handle rgb() format.
|
||||
if ( count( $decimals ) === 3 ) {
|
||||
return array(
|
||||
'red' => (int) $decimals[0],
|
||||
'green' => (int) $decimals[1],
|
||||
'blue' => (int) $decimals[2],
|
||||
'alpha' => (float) 1,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
return array(
|
||||
'red' => 0,
|
||||
'green' => 0,
|
||||
'blue' => 0,
|
||||
'alpha' => (float) 0,
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_color_picker' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,334 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_picker' ) ) :
|
||||
|
||||
class acf_field_date_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'date_picker';
|
||||
$this->label = __( 'Date Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a date. The date return format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-date-picker.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/date-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'd/m/Y',
|
||||
'return_format' => 'd/m/Y',
|
||||
'first_day' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_datepicker' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// localize
|
||||
global $wp_locale;
|
||||
acf_localize_data(
|
||||
array(
|
||||
'datePickerL10n' => array(
|
||||
'closeText' => _x( 'Done', 'Date Picker JS closeText', 'acf' ),
|
||||
'currentText' => _x( 'Today', 'Date Picker JS currentText', 'acf' ),
|
||||
'nextText' => _x( 'Next', 'Date Picker JS nextText', 'acf' ),
|
||||
'prevText' => _x( 'Prev', 'Date Picker JS prevText', 'acf' ),
|
||||
'weekHeader' => _x( 'Wk', 'Date Picker JS weekHeader', 'acf' ),
|
||||
'monthNames' => array_values( $wp_locale->month ),
|
||||
'monthNamesShort' => array_values( $wp_locale->month_abbrev ),
|
||||
'dayNames' => array_values( $wp_locale->weekday ),
|
||||
'dayNamesMin' => array_values( $wp_locale->weekday_initial ),
|
||||
'dayNamesShort' => array_values( $wp_locale->weekday_abbrev ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// script
|
||||
wp_enqueue_script( 'jquery-ui-datepicker' );
|
||||
|
||||
// style
|
||||
wp_enqueue_style( 'acf-datepicker', acf_get_url( 'assets/inc/datepicker/jquery-ui.min.css' ), array(), '1.11.4' );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$hidden_value = '';
|
||||
$display_value = '';
|
||||
|
||||
// format value
|
||||
if ( $field['value'] ) {
|
||||
$hidden_value = acf_format_date( $field['value'], 'Ymd' );
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// elements
|
||||
$div = array(
|
||||
'class' => 'acf-date-picker acf-input-wrap',
|
||||
'data-date_format' => acf_convert_date_to_js( $field['display_format'] ),
|
||||
'data-first_day' => $field['first_day'],
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'name' => $field['name'],
|
||||
'value' => $hidden_value,
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'value' => $display_value,
|
||||
);
|
||||
|
||||
// special attributes
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
|
||||
// add custom JS save format
|
||||
$div['data-save_format'] = $field['save_format'];
|
||||
|
||||
// revert hidden input value to raw DB value
|
||||
$hidden_input['value'] = $field['value'];
|
||||
|
||||
// remove formatted value (will do this via JS)
|
||||
$text_input['value'] = '';
|
||||
}
|
||||
|
||||
// html
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
global $wp_locale;
|
||||
|
||||
$d_m_Y = date_i18n( 'd/m/Y' );
|
||||
$m_d_Y = date_i18n( 'm/d/Y' );
|
||||
$F_j_Y = date_i18n( 'F j, Y' );
|
||||
$Ymd = date_i18n( 'Ymd' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y' => '<span>' . $d_m_Y . '</span><code>d/m/Y</code>',
|
||||
'm/d/Y' => '<span>' . $m_d_Y . '</span><code>m/d/Y</code>',
|
||||
'F j, Y' => '<span>' . $F_j_Y . '</span><code>F j, Y</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Format', 'acf' ),
|
||||
'hint' => __( 'The format used when saving a value', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'save_format',
|
||||
// 'readonly' => 1 // this setting was not readonly in v4
|
||||
)
|
||||
);
|
||||
} else {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y' => '<span>' . $d_m_Y . '</span><code>d/m/Y</code>',
|
||||
'm/d/Y' => '<span>' . $m_d_Y . '</span><code>m/d/Y</code>',
|
||||
'F j, Y' => '<span>' . $F_j_Y . '</span><code>F j, Y</code>',
|
||||
'Ymd' => '<span>' . $Ymd . '</span><code>Ymd</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Week Starts On', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'first_day',
|
||||
'choices' => array_values( $wp_locale->weekday ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// save_format - compatibility with ACF < 5.0.0
|
||||
if ( ! empty( $field['save_format'] ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
* @date 28/09/21
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `Ymd` formatted date string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( ! $value ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return (string) $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_date_picker' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,298 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_date_and_time_picker' ) ) :
|
||||
|
||||
class acf_field_date_and_time_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'date_time_picker';
|
||||
$this->label = __( 'Date Time Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a date and time. The date return format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-date-time.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/date-time-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'd/m/Y g:i a',
|
||||
'return_format' => 'd/m/Y g:i a',
|
||||
'first_day' => 1,
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_datetimepicker' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// vars
|
||||
$version = '1.6.1';
|
||||
|
||||
// script
|
||||
wp_enqueue_script( 'acf-timepicker', acf_get_url( 'assets/inc/timepicker/jquery-ui-timepicker-addon.min.js' ), array( 'jquery-ui-datepicker' ), $version );
|
||||
|
||||
// style
|
||||
wp_enqueue_style( 'acf-timepicker', acf_get_url( 'assets/inc/timepicker/jquery-ui-timepicker-addon.min.css' ), '', $version );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'dateTimePickerL10n' => array(
|
||||
'timeOnlyTitle' => _x( 'Choose Time', 'Date Time Picker JS timeOnlyTitle', 'acf' ),
|
||||
'timeText' => _x( 'Time', 'Date Time Picker JS timeText', 'acf' ),
|
||||
'hourText' => _x( 'Hour', 'Date Time Picker JS hourText', 'acf' ),
|
||||
'minuteText' => _x( 'Minute', 'Date Time Picker JS minuteText', 'acf' ),
|
||||
'secondText' => _x( 'Second', 'Date Time Picker JS secondText', 'acf' ),
|
||||
'millisecText' => _x( 'Millisecond', 'Date Time Picker JS millisecText', 'acf' ),
|
||||
'microsecText' => _x( 'Microsecond', 'Date Time Picker JS microsecText', 'acf' ),
|
||||
'timezoneText' => _x( 'Time Zone', 'Date Time Picker JS timezoneText', 'acf' ),
|
||||
'currentText' => _x( 'Now', 'Date Time Picker JS currentText', 'acf' ),
|
||||
'closeText' => _x( 'Done', 'Date Time Picker JS closeText', 'acf' ),
|
||||
'selectText' => _x( 'Select', 'Date Time Picker JS selectText', 'acf' ),
|
||||
'amNames' => array(
|
||||
_x( 'AM', 'Date Time Picker JS amText', 'acf' ),
|
||||
_x( 'A', 'Date Time Picker JS amTextShort', 'acf' ),
|
||||
),
|
||||
'pmNames' => array(
|
||||
_x( 'PM', 'Date Time Picker JS pmText', 'acf' ),
|
||||
_x( 'P', 'Date Time Picker JS pmTextShort', 'acf' ),
|
||||
),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Set value.
|
||||
$hidden_value = '';
|
||||
$display_value = '';
|
||||
|
||||
if ( $field['value'] ) {
|
||||
$hidden_value = acf_format_date( $field['value'], 'Y-m-d H:i:s' );
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// Convert "display_format" setting to individual date and time formats.
|
||||
$formats = acf_split_date_time( $field['display_format'] );
|
||||
|
||||
// Elements.
|
||||
$div = array(
|
||||
'class' => 'acf-date-time-picker acf-input-wrap',
|
||||
'data-date_format' => acf_convert_date_to_js( $formats['date'] ),
|
||||
'data-time_format' => acf_convert_time_to_js( $formats['time'] ),
|
||||
'data-first_day' => $field['first_day'],
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'class' => 'input-alt',
|
||||
'name' => $field['name'],
|
||||
'value' => $hidden_value,
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'value' => $display_value,
|
||||
);
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// Output.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
global $wp_locale;
|
||||
|
||||
$d_m_Y = date_i18n( 'd/m/Y g:i a' );
|
||||
$m_d_Y = date_i18n( 'm/d/Y g:i a' );
|
||||
$F_j_Y = date_i18n( 'F j, Y g:i a' );
|
||||
$Ymd = date_i18n( 'Y-m-d H:i:s' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y g:i a' => '<span>' . $d_m_Y . '</span><code>d/m/Y g:i a</code>',
|
||||
'm/d/Y g:i a' => '<span>' . $m_d_Y . '</span><code>m/d/Y g:i a</code>',
|
||||
'F j, Y g:i a' => '<span>' . $F_j_Y . '</span><code>F j, Y g:i a</code>',
|
||||
'Y-m-d H:i:s' => '<span>' . $Ymd . '</span><code>Y-m-d H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'd/m/Y g:i a' => '<span>' . $d_m_Y . '</span><code>d/m/Y g:i a</code>',
|
||||
'm/d/Y g:i a' => '<span>' . $m_d_Y . '</span><code>m/d/Y g:i a</code>',
|
||||
'F j, Y g:i a' => '<span>' . $F_j_Y . '</span><code>F j, Y g:i a</code>',
|
||||
'Y-m-d H:i:s' => '<span>' . $Ymd . '</span><code>Y-m-d H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Week Starts On', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'first_day',
|
||||
'choices' => array_values( $wp_locale->weekday ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
* @date 28/09/21
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `Y-m-d H:i:s` formatted date string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_date_and_time_picker' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,208 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_email' ) ) :
|
||||
|
||||
class acf_field_email extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'email';
|
||||
$this->label = __( 'Email', 'acf' );
|
||||
$this->description = __( 'A text input specifically designed for storing email addresses.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-email.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/email/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required', 'multiple' );
|
||||
$html = '';
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
|
||||
}
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( $atts ) . '</div>';
|
||||
|
||||
// return
|
||||
echo $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the email value. If this method returns TRUE, the input value is valid. If
|
||||
* FALSE or a string is returned, the input value is invalid and the user is shown a
|
||||
* notice. If a string is returned, the string is show as the message text.
|
||||
*
|
||||
* @param bool $valid Whether the value is valid.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The request variable name for the inbound field.
|
||||
*
|
||||
* @return bool|string
|
||||
*/
|
||||
public function validate_value( $valid, $value, $field, $input ) {
|
||||
$flags = defined( 'FILTER_FLAG_EMAIL_UNICODE' ) ? FILTER_FLAG_EMAIL_UNICODE : 0;
|
||||
|
||||
if ( $value && filter_var( wp_unslash( $value ), FILTER_VALIDATE_EMAIL, $flags ) === false ) {
|
||||
return sprintf( __( "'%s' is not a valid email address", 'acf' ), esc_html( $value ) );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'email';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_email' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,552 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_file' ) ) :
|
||||
|
||||
class acf_field_file extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'file';
|
||||
$this->label = __( 'File', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'Uses the native WordPress media picker to upload, or choose files.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-file.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/file/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
'library' => 'all',
|
||||
'min_size' => 0,
|
||||
'max_size' => 0,
|
||||
'mime_types' => '',
|
||||
);
|
||||
|
||||
// filters
|
||||
add_filter( 'get_media_item_args', array( $this, 'get_media_item_args' ) );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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(
|
||||
'Select File' => __( 'Select File', 'acf' ),
|
||||
'Edit File' => __( 'Edit File', 'acf' ),
|
||||
'Update File' => __( 'Update File', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$uploader = acf_get_setting( 'uploader' );
|
||||
|
||||
// allow custom uploader
|
||||
$uploader = acf_maybe_get( $field, 'uploader', $uploader );
|
||||
|
||||
// enqueue
|
||||
if ( $uploader == 'wp' ) {
|
||||
acf_enqueue_uploader();
|
||||
}
|
||||
|
||||
// vars
|
||||
$o = array(
|
||||
'icon' => '',
|
||||
'title' => '',
|
||||
'url' => '',
|
||||
'filename' => '',
|
||||
'filesize' => '',
|
||||
);
|
||||
|
||||
$div = array(
|
||||
'class' => 'acf-file-uploader',
|
||||
'data-library' => $field['library'],
|
||||
'data-mime_types' => $field['mime_types'],
|
||||
'data-uploader' => $uploader,
|
||||
);
|
||||
|
||||
// has value?
|
||||
if ( $field['value'] ) {
|
||||
|
||||
$attachment = acf_get_attachment( $field['value'] );
|
||||
if ( $attachment ) {
|
||||
|
||||
// has value
|
||||
$div['class'] .= ' has-value';
|
||||
|
||||
// update
|
||||
$o['icon'] = $attachment['icon'];
|
||||
$o['title'] = $attachment['title'];
|
||||
$o['url'] = $attachment['url'];
|
||||
$o['filename'] = $attachment['filename'];
|
||||
if ( $attachment['filesize'] ) {
|
||||
$o['filesize'] = size_format( $attachment['filesize'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
'data-name' => 'id',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="show-if-value file-wrap">
|
||||
<div class="file-icon">
|
||||
<img data-name="icon" src="<?php echo esc_url( $o['icon'] ); ?>" alt=""/>
|
||||
</div>
|
||||
<div class="file-info">
|
||||
<p>
|
||||
<strong data-name="title"><?php echo esc_html( $o['title'] ); ?></strong>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php _e( 'File name', 'acf' ); ?>:</strong>
|
||||
<a data-name="filename" href="<?php echo esc_url( $o['url'] ); ?>" target="_blank"><?php echo esc_html( $o['filename'] ); ?></a>
|
||||
</p>
|
||||
<p>
|
||||
<strong><?php _e( 'File size', 'acf' ); ?>:</strong>
|
||||
<span data-name="filesize"><?php echo esc_html( $o['filesize'] ); ?></span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="acf-actions -hover">
|
||||
<?php if ( $uploader != 'basic' ) : ?>
|
||||
<a class="acf-icon -pencil dark" data-name="edit" href="#" title="<?php _e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php _e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide-if-value">
|
||||
<?php if ( $uploader == 'basic' ) : ?>
|
||||
|
||||
<?php if ( $field['value'] && ! is_numeric( $field['value'] ) ) : ?>
|
||||
<div class="acf-error-message"><p><?php echo acf_esc_html( $field['value'] ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
|
||||
<label class="acf-basic-uploader">
|
||||
<?php
|
||||
acf_file_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'id' => $field['id'],
|
||||
'key' => $field['key'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
|
||||
<?php else : ?>
|
||||
|
||||
<p><?php _e( 'No file selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php _e( 'Add File', 'acf' ); ?></a></p>
|
||||
|
||||
<?php endif; ?>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'File Array', 'acf' ),
|
||||
'url' => __( 'File URL', 'acf' ),
|
||||
'id' => __( 'File 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_size',
|
||||
'max_size',
|
||||
);
|
||||
|
||||
foreach ( $clear as $k ) {
|
||||
|
||||
if ( empty( $field[ $k ] ) ) {
|
||||
$field[ $k ] = '';
|
||||
}
|
||||
}
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum', 'acf' ),
|
||||
'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'min_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum', 'acf' ),
|
||||
'instructions' => __( 'Restrict which files can be uploaded', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'max_size',
|
||||
'prepend' => __( 'File size', 'acf' ),
|
||||
'append' => 'MB',
|
||||
)
|
||||
);
|
||||
|
||||
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',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if not numeric (error message)
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert to int
|
||||
$value = intval( $value );
|
||||
|
||||
// format
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
|
||||
return wp_get_attachment_url( $value );
|
||||
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
|
||||
return acf_get_attachment( $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_media_item_args
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 27/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param $vars (array)
|
||||
* @return $vars
|
||||
*/
|
||||
|
||||
function get_media_item_args( $vars ) {
|
||||
|
||||
$vars['send'] = true;
|
||||
return( $vars );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Parse value for id.
|
||||
$attachment_id = acf_idval( $value );
|
||||
|
||||
// Connect attacment to post.
|
||||
acf_connect_attachment_to_post( $attachment_id, $post_id );
|
||||
|
||||
// Return id.
|
||||
return $attachment_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* This function will validate a basic file input
|
||||
*
|
||||
* @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 ) {
|
||||
|
||||
// bail early if empty
|
||||
if ( empty( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if is numeric
|
||||
if ( is_numeric( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if not basic string
|
||||
if ( ! is_string( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// decode value
|
||||
$file = null;
|
||||
parse_str( $value, $file );
|
||||
|
||||
// bail early if no attachment
|
||||
if ( empty( $file ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// get errors
|
||||
$errors = acf_validate_attachment( $file, $field, 'basic_upload' );
|
||||
|
||||
// append error
|
||||
if ( ! empty( $errors ) ) {
|
||||
$valid = implode( "\n", $errors );
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates file fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) && empty( $field['required'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* A bit of a hack, but we use `wp_prepare_attachment_for_js()` here
|
||||
* since it returns all the data we need to validate the file, and we use this anyways
|
||||
* to validate fields updated via UI.
|
||||
*/
|
||||
$attachment = wp_prepare_attachment_for_js( $value );
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array(
|
||||
'param' => $param,
|
||||
'value' => (int) $value,
|
||||
);
|
||||
|
||||
if ( ! $attachment ) {
|
||||
$error = sprintf( __( '%s requires a valid attachment ID.', 'acf' ), $param );
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
$errors = acf_validate_attachment( $attachment, $field, 'prepare' );
|
||||
|
||||
if ( ! empty( $errors ) ) {
|
||||
$error = $param . ' - ' . implode( ' ', $errors );
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
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( 'integer', 'null' ),
|
||||
'required' => isset( $field['required'] ) && $field['required'],
|
||||
);
|
||||
|
||||
if ( ! empty( $field['min_width'] ) ) {
|
||||
$schema['minWidth'] = (int) $field['min_width'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['min_height'] ) ) {
|
||||
$schema['minHeight'] = (int) $field['min_height'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['min_size'] ) ) {
|
||||
$schema['minSize'] = $field['min_size'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_width'] ) ) {
|
||||
$schema['maxWidth'] = (int) $field['max_width'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_height'] ) ) {
|
||||
$schema['maxHeight'] = (int) $field['max_height'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max_size'] ) ) {
|
||||
$schema['maxSize'] = $field['max_size'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['mime_types'] ) ) {
|
||||
$schema['mimeTypes'] = $field['mime_types'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_file' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,391 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_google_map' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_google_map extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'google_map';
|
||||
$this->label = __( 'Google Map', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for selecting a location using Google Maps. Requires a Google Maps API key and additional configuration to display correctly.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-google-map.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/google-map/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'height' => '',
|
||||
'center_lat' => '',
|
||||
'center_lng' => '',
|
||||
'zoom' => '',
|
||||
);
|
||||
$this->default_values = array(
|
||||
'height' => '400',
|
||||
'center_lat' => '-37.81411',
|
||||
'center_lng' => '144.96328',
|
||||
'zoom' => '14',
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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(
|
||||
'Sorry, this browser does not support geolocation' => __( 'Sorry, this browser does not support geolocation', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_google_maps' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// vars
|
||||
$api = array(
|
||||
'key' => acf_get_setting( 'google_api_key' ),
|
||||
'client' => acf_get_setting( 'google_api_client' ),
|
||||
'libraries' => 'places',
|
||||
'ver' => 3,
|
||||
'callback' => 'Function.prototype',
|
||||
'language' => acf_get_locale(),
|
||||
);
|
||||
|
||||
// filter
|
||||
$api = apply_filters( 'acf/fields/google_map/api', $api );
|
||||
|
||||
// remove empty
|
||||
if ( empty( $api['key'] ) ) {
|
||||
unset( $api['key'] );
|
||||
}
|
||||
if ( empty( $api['client'] ) ) {
|
||||
unset( $api['client'] );
|
||||
}
|
||||
|
||||
// construct url
|
||||
$url = add_query_arg( $api, 'https://maps.googleapis.com/maps/api/js' );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'google_map_api' => $url,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Apply defaults.
|
||||
foreach ( $this->default_values as $k => $v ) {
|
||||
if ( ! $field[ $k ] ) {
|
||||
$field[ $k ] = $v;
|
||||
}
|
||||
}
|
||||
|
||||
// Attrs.
|
||||
$attrs = array(
|
||||
'id' => $field['id'],
|
||||
'class' => "acf-google-map {$field['class']}",
|
||||
'data-lat' => $field['center_lat'],
|
||||
'data-lng' => $field['center_lng'],
|
||||
'data-zoom' => $field['zoom'],
|
||||
);
|
||||
|
||||
$search = '';
|
||||
if ( $field['value'] ) {
|
||||
$attrs['class'] .= ' -value';
|
||||
$search = $field['value']['address'];
|
||||
} else {
|
||||
$field['value'] = '';
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $attrs ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<div class="title">
|
||||
|
||||
<div class="acf-actions -hover">
|
||||
<a href="#" data-name="search" class="acf-icon -search grey" title="<?php _e( 'Search', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="clear" class="acf-icon -cancel grey" title="<?php _e( 'Clear location', 'acf' ); ?>"></a>
|
||||
<a href="#" data-name="locate" class="acf-icon -location grey" title="<?php _e( 'Find current location', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
<input class="search" type="text" placeholder="<?php _e( 'Search for address...', 'acf' ); ?>" value="<?php echo esc_attr( $search ); ?>" />
|
||||
<i class="acf-loading"></i>
|
||||
|
||||
</div>
|
||||
|
||||
<div class="canvas" style="<?php echo esc_attr( 'height: ' . $field['height'] . 'px' ); ?>"></div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// center_lat
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Center', 'acf' ),
|
||||
'hint' => __( 'Center the initial map', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'center_lat',
|
||||
'prepend' => 'lat',
|
||||
'placeholder' => $this->default_values['center_lat'],
|
||||
)
|
||||
);
|
||||
|
||||
// center_lng
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Center', 'acf' ),
|
||||
'hint' => __( 'Center the initial map', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'center_lng',
|
||||
'prepend' => 'lng',
|
||||
'placeholder' => $this->default_values['center_lng'],
|
||||
'_append' => 'center_lat',
|
||||
)
|
||||
);
|
||||
|
||||
// zoom
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Zoom', 'acf' ),
|
||||
'instructions' => __( 'Set the initial zoom level', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'zoom',
|
||||
'placeholder' => $this->default_values['zoom'],
|
||||
)
|
||||
);
|
||||
|
||||
// allow_null
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Height', 'acf' ),
|
||||
'instructions' => __( 'Customize the map height', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'height',
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->default_values['height'],
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* load_value
|
||||
*
|
||||
* Filters the value loaded from the database.
|
||||
*
|
||||
* @date 16/10/19
|
||||
* @since 5.8.1
|
||||
*
|
||||
* @param mixed $value The value loaded from the database.
|
||||
* @param mixed $post_id The post ID where the value is saved.
|
||||
* @param array $field The field settings array.
|
||||
* @return (array|false)
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// Ensure value is an array.
|
||||
if ( $value ) {
|
||||
return wp_parse_args(
|
||||
$value,
|
||||
array(
|
||||
'address' => '',
|
||||
'lat' => 0,
|
||||
'lng' => 0,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// decode JSON string.
|
||||
if ( is_string( $value ) ) {
|
||||
$value = json_decode( wp_unslash( $value ), true );
|
||||
}
|
||||
|
||||
// Ensure value is an array.
|
||||
if ( $value ) {
|
||||
return (array) $value;
|
||||
}
|
||||
|
||||
// Return default.
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'properties' => array(
|
||||
'address' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'lat' => array(
|
||||
'type' => array( 'string', 'float' ),
|
||||
),
|
||||
'lng' => array(
|
||||
'type' => array( 'string', 'float' ),
|
||||
),
|
||||
'zoom' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'place_id' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'name' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'street_number' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'street_name' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'street_name_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'city' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'state' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'state_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'post_code' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
),
|
||||
'country' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'country_short' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( ! $value ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return acf_format_numerics( $value );
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_google_map' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,724 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field__group' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field__group extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'group';
|
||||
$this->label = __( 'Group', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Provides a way to structure fields into groups to better organize the data and the edit screen.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-group.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/group/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'sub_fields' => array(),
|
||||
'layout' => 'block',
|
||||
);
|
||||
$this->have_rows = 'single';
|
||||
|
||||
// field filters
|
||||
$this->add_field_filter( 'acf/prepare_field_for_export', array( $this, 'prepare_field_for_export' ) );
|
||||
$this->add_field_filter( 'acf/prepare_field_for_import', array( $this, 'prepare_field_for_import' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_field()
|
||||
*
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
|
||||
function load_field( $field ) {
|
||||
|
||||
// vars
|
||||
$sub_fields = acf_get_fields( $field );
|
||||
|
||||
// append
|
||||
if ( $sub_fields ) {
|
||||
|
||||
$field['sub_fields'] = $sub_fields;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* This filter is applied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value found in 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
|
||||
*/
|
||||
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// load sub fields
|
||||
$value = array();
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// load
|
||||
$value[ $sub_field['key'] ] = acf_get_value( $post_id, $sub_field );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// extract value
|
||||
$sub_value = acf_extract_var( $value, $sub_field['key'] );
|
||||
|
||||
// format value
|
||||
$sub_value = acf_format_value( $sub_value, $post_id, $sub_field );
|
||||
|
||||
// append to $row
|
||||
$value[ $sub_field['_name'] ] = $sub_value;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 $field - the field array holding all the field options
|
||||
* @param $post_id - the $post_id of which the value will be saved
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if no value
|
||||
if ( ! acf_is_array( $value ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// vars
|
||||
$v = false;
|
||||
|
||||
// key (backend)
|
||||
if ( isset( $value[ $sub_field['key'] ] ) ) {
|
||||
|
||||
$v = $value[ $sub_field['key'] ];
|
||||
|
||||
// name (frontend)
|
||||
} elseif ( isset( $value[ $sub_field['_name'] ] ) ) {
|
||||
|
||||
$v = $value[ $sub_field['_name'] ];
|
||||
|
||||
// empty
|
||||
} else {
|
||||
|
||||
// input is not set (hidden by conditioanl logic)
|
||||
continue;
|
||||
|
||||
}
|
||||
|
||||
// update value
|
||||
acf_update_value( $v, $post_id, $sub_field );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return '';
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* prepare_field_for_db
|
||||
*
|
||||
* This function will modify sub fields ready for update / load
|
||||
*
|
||||
* @type function
|
||||
* @date 4/11/16
|
||||
* @since 5.5.0
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function prepare_field_for_db( $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $field;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as &$sub_field ) {
|
||||
|
||||
// prefix name
|
||||
$sub_field['name'] = $field['name'] . '_' . $sub_field['_name'];
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// load values
|
||||
foreach ( $field['sub_fields'] as &$sub_field ) {
|
||||
|
||||
// add value
|
||||
if ( isset( $field['value'][ $sub_field['key'] ] ) ) {
|
||||
|
||||
// this is a normal value
|
||||
$sub_field['value'] = $field['value'][ $sub_field['key'] ];
|
||||
|
||||
} elseif ( isset( $sub_field['default_value'] ) ) {
|
||||
|
||||
// no value, but this sub field has a default value
|
||||
$sub_field['value'] = $sub_field['default_value'];
|
||||
|
||||
}
|
||||
|
||||
// update prefix to allow for nested values
|
||||
$sub_field['prefix'] = $field['name'];
|
||||
|
||||
// restore required
|
||||
if ( $field['required'] ) {
|
||||
$sub_field['required'] = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
if ( $field['layout'] == 'table' ) {
|
||||
|
||||
$this->render_field_table( $field );
|
||||
|
||||
} else {
|
||||
|
||||
$this->render_field_block( $field );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_block
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 12/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function render_field_block( $field ) {
|
||||
|
||||
// vars
|
||||
$label_placement = ( $field['layout'] == 'block' ) ? 'top' : 'left';
|
||||
|
||||
// html
|
||||
echo '<div class="acf-fields -' . $label_placement . ' -border">';
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
acf_render_field_wrap( $sub_field );
|
||||
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_table
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 12/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function render_field_table( $field ) {
|
||||
|
||||
?>
|
||||
<table class="acf-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
foreach ( $field['sub_fields'] as $sub_field ) :
|
||||
|
||||
// prepare field (allow sub fields to be removed)
|
||||
$sub_field = acf_prepare_field( $sub_field );
|
||||
|
||||
// bail early if no field
|
||||
if ( ! $sub_field ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$atts['class'] = 'acf-th';
|
||||
$atts['data-name'] = $sub_field['_name'];
|
||||
$atts['data-type'] = $sub_field['type'];
|
||||
$atts['data-key'] = $sub_field['key'];
|
||||
|
||||
// Add custom width
|
||||
if ( $sub_field['wrapper']['width'] ) {
|
||||
|
||||
$atts['data-width'] = $sub_field['wrapper']['width'];
|
||||
$atts['style'] = 'width: ' . $sub_field['wrapper']['width'] . '%;';
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
<th <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
<?php acf_render_field_label( $sub_field ); ?>
|
||||
<?php acf_render_field_instructions( $sub_field ); ?>
|
||||
</th>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr class="acf-row">
|
||||
<?php
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
acf_render_field_wrap( $sub_field, 'td' );
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$args = array(
|
||||
'fields' => $field['sub_fields'],
|
||||
'parent' => $field['ID'],
|
||||
'is_subfield' => true,
|
||||
);
|
||||
|
||||
?>
|
||||
<div class="acf-field acf-field-setting-sub_fields" data-setting="group" data-name="sub_fields">
|
||||
<div class="acf-label">
|
||||
<label><?php _e( 'Sub Fields', 'acf' ); ?></label>
|
||||
</div>
|
||||
<div class="acf-input acf-input-sub">
|
||||
<?php
|
||||
|
||||
acf_get_view( 'acf-field-group/fields', $args );
|
||||
|
||||
?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
// layout
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Layout', 'acf' ),
|
||||
'instructions' => __( 'Specify the style used to render the selected fields', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'block' => __( 'Block', 'acf' ),
|
||||
'table' => __( 'Table', 'acf' ),
|
||||
'row' => __( 'Row', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if no $value
|
||||
if ( empty( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// get sub field
|
||||
$k = $sub_field['key'];
|
||||
|
||||
// bail early if value not set (conditional logic?)
|
||||
if ( ! isset( $value[ $k ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// required
|
||||
if ( $field['required'] ) {
|
||||
$sub_field['required'] = 1;
|
||||
}
|
||||
|
||||
// validate
|
||||
acf_validate_value( $value[ $k ], $sub_field, "{$input}[{$k}]" );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* duplicate_field()
|
||||
*
|
||||
* This filter is appied to the $field before it is duplicated and saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
|
||||
function duplicate_field( $field ) {
|
||||
|
||||
// get sub fields
|
||||
$sub_fields = acf_extract_var( $field, 'sub_fields' );
|
||||
|
||||
// save field to get ID
|
||||
$field = acf_update_field( $field );
|
||||
|
||||
// duplicate sub fields
|
||||
acf_duplicate_fields( $sub_fields, $field['ID'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_field_for_export
|
||||
*
|
||||
* Prepares the field for export.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return array
|
||||
*/
|
||||
function prepare_field_for_export( $field ) {
|
||||
|
||||
// Check for sub fields.
|
||||
if ( ! empty( $field['sub_fields'] ) ) {
|
||||
$field['sub_fields'] = acf_prepare_fields_for_export( $field['sub_fields'] );
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* prepare_field_for_import
|
||||
*
|
||||
* Returns a flat array of fields containing all sub fields ready for import.
|
||||
*
|
||||
* @date 11/03/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return array
|
||||
*/
|
||||
function prepare_field_for_import( $field ) {
|
||||
|
||||
// Check for sub fields.
|
||||
if ( ! empty( $field['sub_fields'] ) ) {
|
||||
$sub_fields = acf_extract_var( $field, 'sub_fields' );
|
||||
|
||||
// Modify sub fields.
|
||||
foreach ( $sub_fields as $i => $sub_field ) {
|
||||
$sub_fields[ $i ]['parent'] = $field['key'];
|
||||
$sub_fields[ $i ]['menu_order'] = $i;
|
||||
}
|
||||
|
||||
// Return array of [field, sub_1, sub_2, ...].
|
||||
return array_merge( array( $field ), $sub_fields );
|
||||
|
||||
}
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* delete_value
|
||||
*
|
||||
* Called when deleting this field's value.
|
||||
*
|
||||
* @date 1/07/2015
|
||||
* @since 5.2.3
|
||||
*
|
||||
* @param mixed $post_id The post ID being saved
|
||||
* @param string $meta_key The field name as seen by the DB
|
||||
* @param array $field The field settings
|
||||
* @return void
|
||||
*/
|
||||
|
||||
function delete_value( $post_id, $meta_key, $field ) {
|
||||
|
||||
// bail early if no sub fields
|
||||
if ( empty( $field['sub_fields'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// modify names
|
||||
$field = $this->prepare_field_for_db( $field );
|
||||
|
||||
// loop
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_delete_value( $post_id, $sub_field );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* delete_field
|
||||
*
|
||||
* Called when deleting a field of this type.
|
||||
*
|
||||
* @date 8/11/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param arra $field The field settings.
|
||||
* @return void
|
||||
*/
|
||||
function delete_field( $field ) {
|
||||
|
||||
// loop over sub fields and delete them
|
||||
if ( $field['sub_fields'] ) {
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
acf_delete_field( $sub_field['ID'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'properties' => array(),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
if ( $sub_field_schema = acf_get_field_rest_schema( $sub_field ) ) {
|
||||
$schema['properties'][ $sub_field['name'] ] = $sub_field_schema;
|
||||
}
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param int|string $post_id
|
||||
* @param array $field
|
||||
* @return array|mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
if ( empty( $value ) || ! is_array( $value ) || empty( $field['sub_fields'] ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// Loop through each row and within that, each sub field to process sub fields individually.
|
||||
foreach ( $field['sub_fields'] as $sub_field ) {
|
||||
|
||||
// Extract the sub field 'field_key'=>'value' pair from the $value and format it.
|
||||
$sub_value = acf_extract_var( $value, $sub_field['key'] );
|
||||
$sub_value = acf_format_value_for_rest( $sub_value, $post_id, $sub_field );
|
||||
|
||||
// Add the sub field value back to the $value but mapped to the field name instead
|
||||
// of the key reference.
|
||||
$value[ $sub_field['name'] ] = $sub_value;
|
||||
}
|
||||
|
||||
return $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field__group' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,496 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_image' ) ) :
|
||||
|
||||
class acf_field_image extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'image';
|
||||
$this->label = __( 'Image', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'Uses the native WordPress media picker to upload, or choose images.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-image.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/image/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
'preview_size' => 'medium',
|
||||
'library' => 'all',
|
||||
'min_width' => 0,
|
||||
'min_height' => 0,
|
||||
'min_size' => 0,
|
||||
'max_width' => 0,
|
||||
'max_height' => 0,
|
||||
'max_size' => 0,
|
||||
'mime_types' => '',
|
||||
);
|
||||
|
||||
// filters
|
||||
add_filter( 'get_media_item_args', array( $this, 'get_media_item_args' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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(
|
||||
'Select Image' => __( 'Select Image', 'acf' ),
|
||||
'Edit Image' => __( 'Edit Image', 'acf' ),
|
||||
'Update Image' => __( 'Update Image', 'acf' ),
|
||||
'All images' => __( 'All images', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the field HTML.
|
||||
*
|
||||
* @date 23/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param array $field The field settings.
|
||||
* @return void
|
||||
*/
|
||||
function render_field( $field ) {
|
||||
$uploader = acf_get_setting( 'uploader' );
|
||||
|
||||
// Enqueue uploader scripts
|
||||
if ( $uploader === 'wp' ) {
|
||||
acf_enqueue_uploader();
|
||||
}
|
||||
|
||||
// Elements and attributes.
|
||||
$value = '';
|
||||
$div_attrs = array(
|
||||
'class' => 'acf-image-uploader',
|
||||
'data-preview_size' => $field['preview_size'],
|
||||
'data-library' => $field['library'],
|
||||
'data-mime_types' => $field['mime_types'],
|
||||
'data-uploader' => $uploader,
|
||||
);
|
||||
$img_attrs = array(
|
||||
'src' => '',
|
||||
'alt' => '',
|
||||
'data-name' => 'image',
|
||||
);
|
||||
|
||||
// Detect value.
|
||||
if ( $field['value'] && is_numeric( $field['value'] ) ) {
|
||||
$image = wp_get_attachment_image_src( $field['value'], $field['preview_size'] );
|
||||
if ( $image ) {
|
||||
$value = $field['value'];
|
||||
$img_attrs['src'] = $image[0];
|
||||
$img_attrs['alt'] = get_post_meta( $field['value'], '_wp_attachment_image_alt', true );
|
||||
$div_attrs['class'] .= ' has-value';
|
||||
}
|
||||
}
|
||||
|
||||
// Add "preview size" max width and height style.
|
||||
// Apply max-width to wrap, and max-height to img for max compatibility with field widths.
|
||||
$size = acf_get_image_size( $field['preview_size'] );
|
||||
$size_w = $size['width'] ? $size['width'] . 'px' : '100%';
|
||||
$size_h = $size['height'] ? $size['height'] . 'px' : '100%';
|
||||
$img_attrs['style'] = sprintf( 'max-height: %s;', $size_h );
|
||||
|
||||
// Render HTML.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div_attrs ); ?>>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="show-if-value image-wrap" style="max-width: <?php echo esc_attr( $size_w ); ?>">
|
||||
<img <?php echo acf_esc_attrs( $img_attrs ); ?> />
|
||||
<div class="acf-actions -hover">
|
||||
<?php if ( $uploader !== 'basic' ) : ?>
|
||||
<a class="acf-icon -pencil dark" data-name="edit" href="#" title="<?php _e( 'Edit', 'acf' ); ?>"></a>
|
||||
<?php endif; ?>
|
||||
<a class="acf-icon -cancel dark" data-name="remove" href="#" title="<?php _e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="hide-if-value">
|
||||
<?php if ( $uploader === 'basic' ) : ?>
|
||||
<?php if ( $field['value'] && ! is_numeric( $field['value'] ) ) : ?>
|
||||
<div class="acf-error-message"><p><?php echo acf_esc_html( $field['value'] ); ?></p></div>
|
||||
<?php endif; ?>
|
||||
<label class="acf-basic-uploader">
|
||||
<?php
|
||||
acf_file_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'id' => $field['id'],
|
||||
'key' => $field['key'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
</label>
|
||||
<?php else : ?>
|
||||
<p><?php _e( 'No image selected', 'acf' ); ?> <a data-name="add" class="acf-button button" href="#"><?php _e( 'Add Image', 'acf' ); ?></a></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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_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', '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' ),
|
||||
'instructions' => __( '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' => __( 'Preview Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'preview_size',
|
||||
'choices' => acf_get_image_sizes(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// bail early if not numeric (error message)
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// convert to int
|
||||
$value = intval( $value );
|
||||
|
||||
// format
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
|
||||
return wp_get_attachment_url( $value );
|
||||
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
|
||||
return acf_get_attachment( $value );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_media_item_args
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 27/01/13
|
||||
* @since 3.6.0
|
||||
*
|
||||
* @param $vars (array)
|
||||
* @return $vars
|
||||
*/
|
||||
|
||||
function get_media_item_args( $vars ) {
|
||||
|
||||
$vars['send'] = true;
|
||||
return( $vars );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
return acf_get_field_type( 'file' )->update_value( $value, $post_id, $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* This function will validate a basic file input
|
||||
*
|
||||
* @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 ) {
|
||||
return acf_get_field_type( 'file' )->validate_value( $valid, $value, $field, $input );
|
||||
}
|
||||
|
||||
/**
|
||||
* Additional validation for the image field when submitted via REST.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'file' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return acf_get_field_type( 'file' )->get_rest_schema( $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_image' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,316 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_link' ) ) :
|
||||
|
||||
class acf_field_link extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'link';
|
||||
$this->label = __( 'Link', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'Allows you to specify a link and its properties such as title and target using the WordPress native link picker.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-link.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/link/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'return_format' => 'array',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_link
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/5/17
|
||||
* @since 5.5.13
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function get_link( $value = '' ) {
|
||||
|
||||
// vars
|
||||
$link = array(
|
||||
'title' => '',
|
||||
'url' => '',
|
||||
'target' => '',
|
||||
);
|
||||
|
||||
// array (ACF 5.6.0)
|
||||
if ( is_array( $value ) ) {
|
||||
|
||||
$link = array_merge( $link, $value );
|
||||
|
||||
// post id (ACF < 5.6.0)
|
||||
} elseif ( is_numeric( $value ) ) {
|
||||
|
||||
$link['title'] = get_the_title( $value );
|
||||
$link['url'] = get_permalink( $value );
|
||||
|
||||
// string (ACF < 5.6.0)
|
||||
} elseif ( is_string( $value ) ) {
|
||||
|
||||
$link['url'] = $value;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $link;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$div = array(
|
||||
'id' => $field['id'],
|
||||
'class' => $field['class'] . ' acf-link',
|
||||
);
|
||||
|
||||
// render scripts/styles
|
||||
acf_enqueue_uploader();
|
||||
|
||||
// get link
|
||||
$link = $this->get_link( $field['value'] );
|
||||
|
||||
// classes
|
||||
if ( $link['url'] ) {
|
||||
$div['class'] .= ' -value';
|
||||
}
|
||||
|
||||
if ( $link['target'] === '_blank' ) {
|
||||
$div['class'] .= ' -external';
|
||||
}
|
||||
|
||||
/*
|
||||
<textarea id="<?php echo esc_attr($field['id']); ?>-textarea"><?php
|
||||
echo esc_textarea('<a href="'.$link['url'].'" target="'.$link['target'].'">'.$link['title'].'</a>');
|
||||
?></textarea>*/
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
|
||||
<div class="acf-hidden">
|
||||
<a class="link-node" href="<?php echo esc_url( $link['url'] ); ?>" target="<?php echo esc_attr( $link['target'] ); ?>"><?php echo esc_html( $link['title'] ); ?></a>
|
||||
<?php foreach ( $link as $k => $v ) : ?>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => "input-$k",
|
||||
'name' => $field['name'] . "[$k]",
|
||||
'value' => $v,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<a href="#" class="button" data-name="add" target=""><?php _e( 'Select Link', 'acf' ); ?></a>
|
||||
|
||||
<div class="link-wrap">
|
||||
<span class="link-title"><?php echo esc_html( $link['title'] ); ?></span>
|
||||
<a class="link-url" href="<?php echo esc_url( $link['url'] ); ?>" target="_blank"><?php echo esc_html( $link['url'] ); ?></a>
|
||||
<i class="acf-icon -link-ext acf-js-tooltip" title="<?php _e( 'Opens in a new window/tab', 'acf' ); ?>"></i><a class="acf-icon -pencil -clear acf-js-tooltip" data-name="edit" href="#" title="<?php _e( 'Edit', 'acf' ); ?>"></a><a class="acf-icon -cancel -clear acf-js-tooltip" data-name="remove" href="#" title="<?php _e( 'Remove', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'array' => __( 'Link Array', 'acf' ),
|
||||
'url' => __( 'Link URL', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// get link
|
||||
$link = $this->get_link( $value );
|
||||
|
||||
// format value
|
||||
if ( $field['return_format'] == 'url' ) {
|
||||
|
||||
return $link['url'];
|
||||
|
||||
}
|
||||
|
||||
// return link
|
||||
return $link;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
// URL is required
|
||||
if ( empty( $value ) || empty( $value['url'] ) ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Check if value is an empty array and convert to empty string.
|
||||
if ( empty( $value ) || empty( $value['url'] ) ) {
|
||||
$value = '';
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'object', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'properties' => array(
|
||||
'title' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
'url' => array(
|
||||
'type' => 'string',
|
||||
'required' => true,
|
||||
'format' => 'uri',
|
||||
),
|
||||
'target' => array(
|
||||
'type' => 'string',
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_link' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,196 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_message' ) ) :
|
||||
|
||||
class acf_field_message extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'message';
|
||||
$this->label = __( 'Message', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Used to display a message to editors alongside other fields. Useful for providing additional context or instructions around your fields.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-message.png';
|
||||
$this->defaults = array(
|
||||
'message' => '',
|
||||
'esc_html' => 0,
|
||||
'new_lines' => 'wpautop',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$m = $field['message'];
|
||||
|
||||
// wptexturize (improves "quotes")
|
||||
$m = wptexturize( $m );
|
||||
|
||||
// esc_html
|
||||
if ( $field['esc_html'] ) {
|
||||
|
||||
$m = esc_html( $m );
|
||||
|
||||
}
|
||||
|
||||
// new lines
|
||||
if ( $field['new_lines'] == 'wpautop' ) {
|
||||
|
||||
$m = wpautop( $m );
|
||||
|
||||
} elseif ( $field['new_lines'] == 'br' ) {
|
||||
|
||||
$m = nl2br( $m );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
echo acf_esc_html( $m );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Message', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'textarea',
|
||||
'name' => 'message',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Lines', 'acf' ),
|
||||
'instructions' => __( 'Controls how new lines are rendered', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'new_lines',
|
||||
'choices' => array(
|
||||
'wpautop' => __( 'Automatically add paragraphs', 'acf' ),
|
||||
'br' => __( 'Automatically add <br>', 'acf' ),
|
||||
'' => __( 'No Formatting', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Escape HTML', 'acf' ),
|
||||
'instructions' => __( 'Allow HTML markup to display as visible text instead of rendering', 'acf' ),
|
||||
'name' => 'esc_html',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
// translate
|
||||
$field['message'] = acf_translate( $field['message'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_field()
|
||||
*
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove instructions
|
||||
$field['instructions'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_message' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,360 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_number' ) ) :
|
||||
|
||||
class acf_field_number extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'number';
|
||||
$this->label = __( 'Number', 'acf' );
|
||||
$this->description = __( 'An input limited to numerical values.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-number.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/number/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'step' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'min', 'max', 'step', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// step
|
||||
if ( ! $field['step'] ) {
|
||||
$field['step'] = 'any';
|
||||
}
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
|
||||
}
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( $atts ) . '</div>';
|
||||
|
||||
// return
|
||||
echo $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Step Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'step',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// remove ','
|
||||
if ( acf_str_exists( ',', $value ) ) {
|
||||
|
||||
$value = str_replace( ',', '', $value );
|
||||
|
||||
}
|
||||
|
||||
// if value is not numeric...
|
||||
if ( ! is_numeric( $value ) ) {
|
||||
|
||||
// allow blank to be saved
|
||||
if ( ! empty( $value ) ) {
|
||||
|
||||
$valid = __( 'Value must be a number', 'acf' );
|
||||
|
||||
}
|
||||
|
||||
// return early
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
// convert
|
||||
$value = floatval( $value );
|
||||
|
||||
// min
|
||||
if ( is_numeric( $field['min'] ) && $value < floatval( $field['min'] ) ) {
|
||||
|
||||
$valid = sprintf( __( 'Value must be equal to or higher than %d', 'acf' ), $field['min'] );
|
||||
|
||||
}
|
||||
|
||||
// max
|
||||
if ( is_numeric( $field['max'] ) && $value > floatval( $field['max'] ) ) {
|
||||
|
||||
$valid = sprintf( __( 'Value must be equal to or lower than %d', 'acf' ), $field['max'] );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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 $field - the field array holding all the field options
|
||||
* @param $post_id - the $post_id of which the value will be saved
|
||||
*
|
||||
* @return $value - the modified value
|
||||
*/
|
||||
|
||||
function update_value( $value, $post_id, $field ) {
|
||||
|
||||
// no formatting needed for empty value
|
||||
if ( empty( $value ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// remove ','
|
||||
if ( acf_str_exists( ',', $value ) ) {
|
||||
|
||||
$value = str_replace( ',', '', $value );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'number', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
if ( ! empty( $field['min'] ) ) {
|
||||
$schema['minimum'] = (float) $field['min'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['max'] ) ) {
|
||||
$schema['maximum'] = (float) $field['max'];
|
||||
}
|
||||
|
||||
if ( isset( $field['default_value'] ) && is_numeric( $field['default_value'] ) ) {
|
||||
$schema['default'] = (float) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_number' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,339 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_oembed' ) ) :
|
||||
#[AllowDynamicProperties]
|
||||
class acf_field_oembed extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'oembed';
|
||||
$this->label = __( 'oEmbed', 'acf' );
|
||||
$this->category = 'content';
|
||||
$this->description = __( 'An interactive component for embedding videos, images, tweets, audio and other content by making use of the native WordPress oEmbed functionality.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-oembed.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/oembed/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'width' => '',
|
||||
'height' => '',
|
||||
);
|
||||
$this->width = 640;
|
||||
$this->height = 390;
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/oembed/search', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/oembed/search', array( $this, 'ajax_query' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* prepare_field
|
||||
*
|
||||
* This function will prepare the field for input
|
||||
*
|
||||
* @type function
|
||||
* @date 14/2/17
|
||||
* @since 5.5.8
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return (int)
|
||||
*/
|
||||
|
||||
function prepare_field( $field ) {
|
||||
|
||||
// defaults
|
||||
if ( ! $field['width'] ) {
|
||||
$field['width'] = $this->width;
|
||||
}
|
||||
if ( ! $field['height'] ) {
|
||||
$field['height'] = $this->height;
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to fetch the HTML for the provided URL using oEmbed.
|
||||
*
|
||||
* @date 24/01/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param string $url The URL that should be embedded.
|
||||
* @param int|string $width Optional maxwidth value passed to the provider URL.
|
||||
* @param int|string $height Optional maxheight value passed to the provider URL.
|
||||
* @return string|false The embedded HTML on success, false on failure.
|
||||
*/
|
||||
function wp_oembed_get( $url = '', $width = 0, $height = 0 ) {
|
||||
$embed = false;
|
||||
$res = array(
|
||||
'width' => $width,
|
||||
'height' => $height,
|
||||
);
|
||||
|
||||
if ( function_exists( 'wp_oembed_get' ) ) {
|
||||
$embed = wp_oembed_get( $url, $res );
|
||||
}
|
||||
|
||||
// try shortcode
|
||||
if ( ! $embed ) {
|
||||
global $wp_embed;
|
||||
$embed = $wp_embed->shortcode( $res, $url );
|
||||
}
|
||||
|
||||
return $embed;
|
||||
}
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
wp_send_json( $response );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_ajax_query( $args = array() ) {
|
||||
|
||||
// defaults
|
||||
$args = acf_parse_args(
|
||||
$args,
|
||||
array(
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $args['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// prepare field to correct width and height
|
||||
$field = $this->prepare_field( $field );
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'url' => $args['s'],
|
||||
'html' => $this->wp_oembed_get( $args['s'], $field['width'], $field['height'] ),
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// atts
|
||||
$atts = array(
|
||||
'class' => 'acf-oembed',
|
||||
);
|
||||
|
||||
// <strong><?php _e("Error.", 'acf'); </strong> _e("No embed found for the given URL.", 'acf');
|
||||
|
||||
// value
|
||||
if ( $field['value'] ) {
|
||||
$atts['class'] .= ' has-value';
|
||||
}
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => 'input-value',
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<div class="title">
|
||||
<?php
|
||||
acf_text_input(
|
||||
array(
|
||||
'class' => 'input-search',
|
||||
'value' => $field['value'],
|
||||
'placeholder' => __( 'Enter URL', 'acf' ),
|
||||
'autocomplete' => 'off',
|
||||
)
|
||||
);
|
||||
?>
|
||||
<div class="acf-actions -hover">
|
||||
<a data-name="clear-button" href="#" class="acf-icon -cancel grey"></a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="canvas">
|
||||
<div class="canvas-media">
|
||||
<?php
|
||||
if ( $field['value'] ) {
|
||||
echo $this->wp_oembed_get( $field['value'], $field['width'], $field['height'] );
|
||||
}
|
||||
?>
|
||||
</div>
|
||||
<i class="acf-icon -picture hide-if-value"></i>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Embed Size', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'width',
|
||||
'prepend' => __( 'Width', 'acf' ),
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->width,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Embed Size', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'height',
|
||||
'prepend' => __( 'Height', 'acf' ),
|
||||
'append' => 'px',
|
||||
'placeholder' => $this->height,
|
||||
'_append' => 'width',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* format_value()
|
||||
*
|
||||
* 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 ( empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// prepare field to correct width and height
|
||||
$field = $this->prepare_field( $field );
|
||||
|
||||
// get oembed
|
||||
$value = $this->wp_oembed_get( $value, $field['width'], $field['height'] );
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'uri';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_oembed' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_output' ) ) :
|
||||
|
||||
class acf_field_output extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'output';
|
||||
$this->label = 'output';
|
||||
$this->public = false;
|
||||
$this->defaults = array(
|
||||
'html' => false,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field (array) the $field being rendered
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array) the $field being edited
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function render_field( $field ) {
|
||||
|
||||
// bail early if no html
|
||||
if ( ! $field['html'] ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// html
|
||||
if ( is_string( $field['html'] ) && ! function_exists( $field['html'] ) ) {
|
||||
|
||||
echo $field['html'];
|
||||
|
||||
// function
|
||||
} else {
|
||||
|
||||
call_user_func_array( $field['html'], array( $field ) );
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_output' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,745 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_page_link' ) ) :
|
||||
|
||||
class acf_field_page_link extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'page_link';
|
||||
$this->label = __( 'Page Link', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'An interactive dropdown to select one or more posts, pages, custom post type items or archive URLs, with the option to search.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-page-link.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/page-link/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'allow_null' => 0,
|
||||
'multiple' => 0,
|
||||
'allow_archives' => 1,
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/page_link/query', array( $this, 'ajax_query' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$_POST,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = $options['paged'];
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
|
||||
}
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// update $args
|
||||
if ( ! empty( $field['post_type'] ) ) {
|
||||
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
|
||||
} else {
|
||||
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
|
||||
}
|
||||
|
||||
// create tax queries
|
||||
if ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// decode terms
|
||||
$taxonomies = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $taxonomies as $taxonomy => $terms ) {
|
||||
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $taxonomy,
|
||||
'field' => 'slug',
|
||||
'terms' => $terms,
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/page_link/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/page_link/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/page_link/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// add archives to $results
|
||||
if ( $field['allow_archives'] && $args['paged'] == 1 ) {
|
||||
|
||||
// Generate unique list of URLs.
|
||||
$links = array();
|
||||
$links[] = home_url();
|
||||
foreach ( $args['post_type'] as $post_type ) {
|
||||
$links[] = get_post_type_archive_link( $post_type );
|
||||
}
|
||||
$links = array_filter( $links );
|
||||
$links = array_unique( $links );
|
||||
|
||||
// Convert list into choices.
|
||||
$children = array();
|
||||
foreach ( $links as $link ) {
|
||||
|
||||
// Ignore if search does not match.
|
||||
if ( $is_search && stripos( $link, $s ) === false ) {
|
||||
continue;
|
||||
}
|
||||
$children[] = array(
|
||||
'id' => $link,
|
||||
'text' => $link,
|
||||
);
|
||||
}
|
||||
if ( $children ) {
|
||||
$results[] = array(
|
||||
'text' => __( 'Archives', 'acf' ),
|
||||
'children' => $children,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// loop
|
||||
if ( ! empty( $groups ) ) {
|
||||
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'], $is_search );
|
||||
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
acf_send_ajax_results(
|
||||
array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @type function
|
||||
* @date 7/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $id (mixed)
|
||||
* @param $text (string)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// look for parent
|
||||
$search = '| ' . __( 'Parent', 'acf' ) . ':';
|
||||
$pos = strpos( $text, $search );
|
||||
|
||||
if ( $pos !== false ) {
|
||||
|
||||
$result['description'] = substr( $text, $pos + 2 );
|
||||
$result['text'] = substr( $text, 0, $pos );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* This function returns the HTML for a result
|
||||
*
|
||||
* @type function
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post (object)
|
||||
* @param $field (array)
|
||||
* @param $post_id (int) the post_id to which this value is saved to
|
||||
* @return (string)
|
||||
*/
|
||||
|
||||
function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/page_link/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/page_link/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/page_link/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return
|
||||
return $title;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_posts
|
||||
*
|
||||
* This function will return an array of posts for a given field value
|
||||
*
|
||||
* @type function
|
||||
* @date 13/06/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $value (array)
|
||||
* @return $value
|
||||
*/
|
||||
|
||||
function get_posts( $value, $field ) {
|
||||
|
||||
// force value to array
|
||||
$value = acf_get_array( $value );
|
||||
|
||||
// get selected post ID's
|
||||
$post__in = array();
|
||||
|
||||
foreach ( $value as $k => $v ) {
|
||||
|
||||
if ( is_numeric( $v ) ) {
|
||||
|
||||
// append to $post__in
|
||||
$post__in[] = (int) $v;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $post__in ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $post__in,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// override value with post
|
||||
$return = array();
|
||||
|
||||
// append to $return
|
||||
foreach ( $value as $k => $v ) {
|
||||
|
||||
if ( is_numeric( $v ) ) {
|
||||
|
||||
// extract first post
|
||||
$post = array_shift( $posts );
|
||||
|
||||
// append
|
||||
if ( $post ) {
|
||||
|
||||
$return[] = $post;
|
||||
|
||||
}
|
||||
} else {
|
||||
|
||||
$return[] = $v;
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $return;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
|
||||
// populate choices if value exists
|
||||
if ( ! empty( $field['value'] ) ) {
|
||||
|
||||
// get posts
|
||||
$posts = $this->get_posts( $field['value'], $field );
|
||||
|
||||
// set choices
|
||||
if ( ! empty( $posts ) ) {
|
||||
|
||||
foreach ( array_keys( $posts ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $posts, $i );
|
||||
|
||||
if ( is_object( $post ) ) {
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post->ID ] = $this->get_post_title( $post, $field );
|
||||
|
||||
} else {
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post ] = $post;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
acf_render_field( $field );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Archives URLs', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_archives',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select multiple values?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// ACF4 null
|
||||
if ( $value === 'null' ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// get posts
|
||||
$value = $this->get_posts( $value, $field );
|
||||
|
||||
// set choices
|
||||
foreach ( array_keys( $value ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $value, $i );
|
||||
|
||||
// convert $post to permalink
|
||||
if ( is_object( $post ) ) {
|
||||
|
||||
$post = get_permalink( $post );
|
||||
|
||||
}
|
||||
|
||||
// append back to $value
|
||||
$value[ $i ] = $post;
|
||||
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( ! $field['multiple'] ) {
|
||||
|
||||
$value = array_shift( $value );
|
||||
|
||||
}
|
||||
|
||||
// return value
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_maybe_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_maybe_idval( $value );
|
||||
}
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates page link fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => array( 'integer' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( ! empty( $field['allow_archives'] ) ) {
|
||||
$schema['type'][] = 'string';
|
||||
$schema['items']['type'][] = 'string';
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param int|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 ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type );
|
||||
$links[] = array(
|
||||
'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_page_link' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,120 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_password' ) ) :
|
||||
|
||||
class acf_field_password extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'password';
|
||||
$this->label = __( 'Password', 'acf' );
|
||||
$this->description = __( 'An input for providing a password using a masked field.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-password.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/password/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
acf_get_field_type( 'text' )->render_field( $field );
|
||||
|
||||
}
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
// TODO: Delete this method?
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_password' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,795 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_post_object' ) ) :
|
||||
|
||||
class acf_field_post_object extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'post_object';
|
||||
$this->label = __( 'Post Object', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'An interactive and customizable UI for picking one or many posts, pages or post type items with the option to search. ', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-post-object.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/post-object/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'allow_null' => 0,
|
||||
'multiple' => 0,
|
||||
'return_format' => 'object',
|
||||
'ui' => 1,
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/post_object/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/post_object/query', array( $this, 'ajax_query' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_ajax_query( $options = array() ) {
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = $options['paged'];
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
|
||||
}
|
||||
|
||||
// post_type
|
||||
if ( ! empty( $field['post_type'] ) ) {
|
||||
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
|
||||
} else {
|
||||
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
|
||||
}
|
||||
|
||||
// taxonomy
|
||||
if ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$terms = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $terms as $k => $v ) {
|
||||
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $k,
|
||||
'field' => 'slug',
|
||||
'terms' => $v,
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/post_object/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/post_object/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/post_object/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $groups ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'], $is_search );
|
||||
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
|
||||
}
|
||||
|
||||
// optgroup or single
|
||||
$post_type = acf_get_array( $args['post_type'] );
|
||||
if ( count( $post_type ) == 1 ) {
|
||||
$results = $results[0]['children'];
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @type function
|
||||
* @date 7/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $id (mixed)
|
||||
* @param $text (string)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// look for parent
|
||||
$search = '| ' . __( 'Parent', 'acf' ) . ':';
|
||||
$pos = strpos( $text, $search );
|
||||
|
||||
if ( $pos !== false ) {
|
||||
|
||||
$result['description'] = substr( $text, $pos + 2 );
|
||||
$result['text'] = substr( $text, 0, $pos );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* This function returns the HTML for a result
|
||||
*
|
||||
* @type function
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post (object)
|
||||
* @param $field (array)
|
||||
* @param $post_id (int) the post_id to which this value is saved to
|
||||
* @return (string)
|
||||
*/
|
||||
|
||||
function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/post_object/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/post_object/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/post_object/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return
|
||||
return $title;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Change Field into a select
|
||||
$field['type'] = 'select';
|
||||
$field['ui'] = 1;
|
||||
$field['ajax'] = 1;
|
||||
$field['choices'] = array();
|
||||
|
||||
// load posts
|
||||
$posts = $this->get_posts( $field['value'], $field );
|
||||
|
||||
if ( $posts ) {
|
||||
|
||||
foreach ( array_keys( $posts ) as $i ) {
|
||||
|
||||
// vars
|
||||
$post = acf_extract_var( $posts, $i );
|
||||
|
||||
// append to choices
|
||||
$field['choices'][ $post->ID ] = $this->get_post_title( $post, $field );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// render
|
||||
acf_render_field( $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'object' => __( 'Post Object', 'acf' ),
|
||||
'id' => __( 'Post ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select multiple values?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* This filter is applied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value found in 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
|
||||
*/
|
||||
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// ACF4 null
|
||||
if ( $value === 'null' ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// numeric
|
||||
$value = acf_get_numeric( $value );
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// load posts if needed
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
|
||||
$value = $this->get_posts( $value, $field );
|
||||
|
||||
}
|
||||
|
||||
// convert back from array if neccessary
|
||||
if ( ! $field['multiple'] && is_array( $value ) ) {
|
||||
|
||||
$value = current( $value );
|
||||
|
||||
}
|
||||
|
||||
// return value
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_idval( $value );
|
||||
}
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_posts
|
||||
*
|
||||
* This function will return an array of posts for a given field value
|
||||
*
|
||||
* @type function
|
||||
* @date 13/06/2014
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $value (array)
|
||||
* @return $value
|
||||
*/
|
||||
|
||||
function get_posts( $value, $field ) {
|
||||
|
||||
// numeric
|
||||
$value = acf_get_numeric( $value );
|
||||
|
||||
// bail early if no value
|
||||
if ( empty( $value ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $value,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// return
|
||||
return $posts;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates post object fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
if ( is_null( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array( 'param' => $param );
|
||||
$value = is_array( $value ) ? $value : array( $value );
|
||||
|
||||
$invalid_posts = array();
|
||||
$post_type_errors = array();
|
||||
$taxonomy_errors = array();
|
||||
|
||||
foreach ( $value as $post_id ) {
|
||||
if ( is_string( $post_id ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$post_type = get_post_type( $post_id );
|
||||
if ( ! $post_type ) {
|
||||
$invalid_posts[] = $post_id;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (
|
||||
is_array( $field['post_type'] ) &&
|
||||
! empty( $field['post_type'] ) &&
|
||||
! in_array( $post_type, $field['post_type'] )
|
||||
) {
|
||||
$post_type_errors[] = $post_id;
|
||||
}
|
||||
|
||||
if ( is_array( $field['taxonomy'] ) && ! empty( $field['taxonomy'] ) ) {
|
||||
$found = false;
|
||||
foreach ( $field['taxonomy'] as $taxonomy_term ) {
|
||||
$decoded = acf_decode_taxonomy_term( $taxonomy_term );
|
||||
if ( $decoded && is_object_in_term( $post_id, $decoded['taxonomy'], $decoded['term'] ) ) {
|
||||
$found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $found ) {
|
||||
$taxonomy_errors[] = $post_id;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $invalid_posts ) ) {
|
||||
$error = sprintf(
|
||||
__( '%1$s must have a valid post ID.', 'acf' ),
|
||||
$param
|
||||
);
|
||||
$data['value'] = $invalid_posts;
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
if ( count( $post_type_errors ) ) {
|
||||
$error = sprintf(
|
||||
_n(
|
||||
'%1$s must be of post type %2$s.',
|
||||
'%1$s must be of one of the following post types: %2$s',
|
||||
count( $field['post_type'] ),
|
||||
'acf'
|
||||
),
|
||||
$param,
|
||||
count( $field['post_type'] ) > 1 ? implode( ', ', $field['post_type'] ) : $field['post_type'][0]
|
||||
);
|
||||
$data['value'] = $post_type_errors;
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
if ( count( $taxonomy_errors ) ) {
|
||||
$error = sprintf(
|
||||
_n(
|
||||
'%1$s must have term %2$s.',
|
||||
'%1$s must have one of the following terms: %2$s',
|
||||
count( $field['taxonomy'] ),
|
||||
'acf'
|
||||
),
|
||||
$param,
|
||||
count( $field['taxonomy'] ) > 1 ? implode( ', ', $field['taxonomy'] ) : $field['taxonomy'][0]
|
||||
);
|
||||
$data['value'] = $taxonomy_errors;
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
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( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* @see \acf_field::get_rest_links()
|
||||
* @param mixed $value The raw (unformatted) field value.
|
||||
* @param int|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 ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $post_type_object = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type_object );
|
||||
$links[] = array(
|
||||
'rel' => $post_type_object->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_post_object' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,501 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_radio' ) ) :
|
||||
|
||||
class acf_field_radio extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'radio';
|
||||
$this->label = __( 'Radio Button', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A group of radio button inputs that allows the user to make a single selection from values that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-radio-button.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/radio-button/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'layout' => 'vertical',
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'other_choice' => 0,
|
||||
'save_other_choice' => 0,
|
||||
'allow_null' => 0,
|
||||
'return_format' => 'value',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* Create the HTML interface for your field
|
||||
*
|
||||
* @param $field (array) the $field being rendered
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field (array) the $field being edited
|
||||
* @return n/a
|
||||
*/
|
||||
|
||||
function render_field( $field ) {
|
||||
|
||||
// vars
|
||||
$e = '';
|
||||
$ul = array(
|
||||
'class' => 'acf-radio-list',
|
||||
'data-allow_null' => $field['allow_null'],
|
||||
'data-other_choice' => $field['other_choice'],
|
||||
);
|
||||
|
||||
// append to class
|
||||
$ul['class'] .= ' ' . ( $field['layout'] == 'horizontal' ? 'acf-hl' : 'acf-bl' );
|
||||
$ul['class'] .= ' ' . $field['class'];
|
||||
|
||||
// Determine selected value.
|
||||
$value = (string) $field['value'];
|
||||
|
||||
// 1. Selected choice.
|
||||
if ( isset( $field['choices'][ $value ] ) ) {
|
||||
$checked = (string) $value;
|
||||
|
||||
// 2. Custom choice.
|
||||
} elseif ( $field['other_choice'] && $value !== '' ) {
|
||||
$checked = 'other';
|
||||
|
||||
// 3. Empty choice.
|
||||
} elseif ( $field['allow_null'] ) {
|
||||
$checked = '';
|
||||
|
||||
// 4. Default to first choice.
|
||||
} else {
|
||||
$checked = (string) key( $field['choices'] );
|
||||
}
|
||||
|
||||
// other choice
|
||||
$other_input = false;
|
||||
if ( $field['other_choice'] ) {
|
||||
|
||||
// Define other input attrs.
|
||||
$other_input = array(
|
||||
'type' => 'text',
|
||||
'name' => $field['name'],
|
||||
'value' => '',
|
||||
'disabled' => 'disabled',
|
||||
'class' => 'acf-disabled',
|
||||
);
|
||||
|
||||
// Select other choice if value is not a valid choice.
|
||||
if ( $checked === 'other' ) {
|
||||
unset( $other_input['disabled'] );
|
||||
$other_input['value'] = $field['value'];
|
||||
}
|
||||
|
||||
// Ensure an 'other' choice is defined.
|
||||
if ( ! isset( $field['choices']['other'] ) ) {
|
||||
$field['choices']['other'] = '';
|
||||
}
|
||||
}
|
||||
|
||||
// Bail early if no choices.
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Hiden input.
|
||||
$e .= acf_get_hidden_input( array( 'name' => $field['name'] ) );
|
||||
|
||||
// Open <ul>.
|
||||
$e .= '<ul ' . acf_esc_attr( $ul ) . '>';
|
||||
|
||||
// Loop through choices.
|
||||
foreach ( $field['choices'] as $value => $label ) {
|
||||
$is_selected = false;
|
||||
|
||||
// Ensure value is a string.
|
||||
$value = (string) $value;
|
||||
|
||||
// Define input attrs.
|
||||
$attrs = array(
|
||||
'type' => 'radio',
|
||||
'id' => sanitize_title( $field['id'] . '-' . $value ),
|
||||
'name' => $field['name'],
|
||||
'value' => $value,
|
||||
);
|
||||
|
||||
// Check if selected.
|
||||
if ( esc_attr( $value ) === esc_attr( $checked ) ) {
|
||||
$attrs['checked'] = 'checked';
|
||||
$is_selected = true;
|
||||
}
|
||||
|
||||
// Check if is disabled.
|
||||
if ( isset( $field['disabled'] ) && acf_in_array( $value, $field['disabled'] ) ) {
|
||||
$attrs['disabled'] = 'disabled';
|
||||
}
|
||||
|
||||
// Additional HTML (the "Other" input).
|
||||
$additional_html = '';
|
||||
if ( $value === 'other' && $other_input ) {
|
||||
$additional_html = ' ' . acf_get_text_input( $other_input );
|
||||
}
|
||||
|
||||
// append
|
||||
$e .= '<li><label' . ( $is_selected ? ' class="selected"' : '' ) . '><input ' . acf_esc_attr( $attrs ) . '/>' . acf_esc_html( $label ) . '</label>' . $additional_html . '</li>';
|
||||
}
|
||||
|
||||
// Close <ul>.
|
||||
$e .= '</ul>';
|
||||
|
||||
// Output HTML.
|
||||
echo $e;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
// Encode choices (convert from array).
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'type' => 'textarea',
|
||||
'name' => 'choices',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Value', 'acf' ),
|
||||
'instructions' => __( 'Specify the returned value on front end', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', '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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Other Choice', 'acf' ),
|
||||
'name' => 'other_choice',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Add 'other' choice to allow for custom values", 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Save Other Choice', 'acf' ),
|
||||
'name' => 'save_other_choice',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'instructions' => __( "Save 'other' values to the field's choices", 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'other_choice',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Layout', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'layout',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'vertical' => __( 'Vertical', 'acf' ),
|
||||
'horizontal' => __( 'Horizontal', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the field group ID (post_type = acf)
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
|
||||
function update_field( $field ) {
|
||||
|
||||
// decode choices (convert to array)
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* This filter is appied to the $value before it is updated in the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
* @todo Fix bug where $field was found via json and has no ID
|
||||
*
|
||||
* @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 (allow 0 to be saved)
|
||||
if ( ! $value && ! is_numeric( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// save_other_choice
|
||||
if ( $field['save_other_choice'] ) {
|
||||
|
||||
// value isn't in choices yet
|
||||
if ( ! isset( $field['choices'][ $value ] ) ) {
|
||||
|
||||
// get raw $field (may have been changed via repeater field)
|
||||
// if field is local, it won't have an ID
|
||||
$selector = $field['ID'] ? $field['ID'] : $field['key'];
|
||||
$field = acf_get_field( $selector );
|
||||
|
||||
// bail early if no ID (JSON only)
|
||||
if ( ! $field['ID'] ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// unslash (fixes serialize single quote issue)
|
||||
$value = wp_unslash( $value );
|
||||
|
||||
// sanitize (remove tags)
|
||||
$value = sanitize_text_field( $value );
|
||||
|
||||
// update $field
|
||||
$field['choices'][ $value ] = $value;
|
||||
|
||||
// save
|
||||
acf_update_field( $field );
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* This filter is appied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.2.9
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value - the value found in the database
|
||||
* @param $post_id - the $post_id from which the value was loaded from
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $value - the value to be saved in te database
|
||||
*/
|
||||
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// must be single value
|
||||
if ( is_array( $value ) ) {
|
||||
|
||||
$value = array_pop( $value );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->translate_field( $field );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
return acf_get_field_type( 'select' )->format_value( $value, $post_id, $field );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
// If other/custom choices are allowed, nothing else to do here.
|
||||
if ( ! empty( $field['other_choice'] ) ) {
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* If a user has defined keys for the radio options,
|
||||
* we should use the keys for the available options to POST to,
|
||||
* since they are what is displayed in GET requests.
|
||||
*/
|
||||
$radio_keys = array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
);
|
||||
|
||||
$schema['enum'] = empty( $radio_keys ) ? $field['choices'] : $radio_keys;
|
||||
if ( ! empty( $field['allow_null'] ) ) {
|
||||
$schema['enum'][] = null;
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_radio' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,288 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_range' ) ) :
|
||||
|
||||
class acf_field_range extends acf_field_number {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'range';
|
||||
$this->label = __( 'Range', 'acf' );
|
||||
$this->description = __( 'An input for selecting a numerical value within a specified range using a range slider element.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-range.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/range/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'min' => '',
|
||||
'max' => '',
|
||||
'step' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'min', 'max', 'step' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// step
|
||||
if ( ! $field['step'] ) {
|
||||
$field['step'] = 1;
|
||||
}
|
||||
|
||||
// min / max
|
||||
if ( ! $field['min'] ) {
|
||||
$field['min'] = 0;
|
||||
}
|
||||
if ( ! $field['max'] ) {
|
||||
$field['max'] = 100;
|
||||
}
|
||||
|
||||
// allow for prev 'non numeric' value
|
||||
if ( ! is_numeric( $field['value'] ) ) {
|
||||
$field['value'] = 0;
|
||||
}
|
||||
|
||||
// constrain within max and min
|
||||
$field['value'] = max( $field['value'], $field['min'] );
|
||||
$field['value'] = min( $field['value'], $field['max'] );
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// open
|
||||
$html .= '<div class="acf-range-wrap">';
|
||||
|
||||
// prepend
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$html .= '<div class="acf-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// range
|
||||
$html .= acf_get_text_input( $atts );
|
||||
|
||||
// Calculate input width based on the largest possible input character length.
|
||||
// Also take into account the step size for decimal steps minus - 1.5 chars for leading "0.".
|
||||
$len = max(
|
||||
strlen( strval( $field['min'] ) ),
|
||||
strlen( strval( $field['max'] ) )
|
||||
);
|
||||
if ( floatval( $atts['step'] ) < 1 ) {
|
||||
$len += strlen( strval( $field['step'] ) ) - 1.5;
|
||||
}
|
||||
|
||||
// input
|
||||
$html .= acf_get_text_input(
|
||||
array(
|
||||
'type' => 'number',
|
||||
'id' => $atts['id'] . '-alt',
|
||||
'value' => $atts['value'],
|
||||
'step' => $atts['step'],
|
||||
// 'min' => $atts['min'], // removed to avoid browser validation errors
|
||||
// 'max' => $atts['max'],
|
||||
'style' => 'width: ' . ( 1.8 + $len * 0.7 ) . 'em;',
|
||||
)
|
||||
);
|
||||
|
||||
// append
|
||||
if ( $field['append'] !== '' ) {
|
||||
$html .= '<div class="acf-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// close
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
'placeholder' => '0',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
'placeholder' => '100',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Step Size', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'step',
|
||||
'placeholder' => '1',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'number', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'minimum' => empty( $field['min'] ) ? 0 : (int) $field['min'],
|
||||
'maximum' => empty( $field['max'] ) ? 100 : (int) $field['max'],
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && is_numeric( $field['default_value'] ) ) {
|
||||
$schema['default'] = (int) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_range' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,929 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_relationship' ) ) :
|
||||
|
||||
class acf_field_relationship extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'relationship';
|
||||
$this->label = __( 'Relationship', 'acf' );
|
||||
$this->category = 'relational';
|
||||
$this->description = __( 'A dual-column interface to select one or more posts, pages, or custom post type items to create a relationship with the item that you\'re currently editing. Includes options to search and filter.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-relationship.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/relationship/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'post_type' => array(),
|
||||
'taxonomy' => array(),
|
||||
'min' => 0,
|
||||
'max' => 0,
|
||||
'filters' => array( 'search', 'post_type', 'taxonomy' ),
|
||||
'elements' => array(),
|
||||
'return_format' => 'object',
|
||||
);
|
||||
|
||||
// extra
|
||||
add_action( 'wp_ajax_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/relationship/query', array( $this, 'ajax_query' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* 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(
|
||||
// 'Minimum values reached ( {min} values )' => __('Minimum values reached ( {min} values )', 'acf'),
|
||||
'Maximum values reached ( {max} values )' => __( 'Maximum values reached ( {max} values )', 'acf' ),
|
||||
'Loading' => __( 'Loading', 'acf' ),
|
||||
'No matches found' => __( 'No matches found', 'acf' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_ajax_query( $options = array() ) {
|
||||
|
||||
// defaults
|
||||
$options = wp_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
'post_type' => '',
|
||||
'taxonomy' => '',
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$args = array();
|
||||
$s = false;
|
||||
$is_search = false;
|
||||
|
||||
// paged
|
||||
$args['posts_per_page'] = 20;
|
||||
$args['paged'] = intval( $options['paged'] );
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = wp_unslash( strval( $options['s'] ) );
|
||||
|
||||
// update vars
|
||||
$args['s'] = $s;
|
||||
$is_search = true;
|
||||
|
||||
}
|
||||
|
||||
// post_type
|
||||
if ( ! empty( $options['post_type'] ) ) {
|
||||
|
||||
$args['post_type'] = acf_get_array( $options['post_type'] );
|
||||
|
||||
} elseif ( ! empty( $field['post_type'] ) ) {
|
||||
|
||||
$args['post_type'] = acf_get_array( $field['post_type'] );
|
||||
|
||||
} else {
|
||||
|
||||
$args['post_type'] = acf_get_post_types();
|
||||
|
||||
}
|
||||
|
||||
// post status
|
||||
if ( ! empty( $options['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $options['post_status'] );
|
||||
|
||||
} elseif ( ! empty( $field['post_status'] ) ) {
|
||||
|
||||
$args['post_status'] = acf_get_array( $field['post_status'] );
|
||||
|
||||
}
|
||||
|
||||
// taxonomy
|
||||
if ( ! empty( $options['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$term = acf_decode_taxonomy_term( $options['taxonomy'] );
|
||||
|
||||
// tax query
|
||||
$args['tax_query'] = array();
|
||||
|
||||
// append
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $term['taxonomy'],
|
||||
'field' => 'slug',
|
||||
'terms' => $term['term'],
|
||||
);
|
||||
|
||||
} elseif ( ! empty( $field['taxonomy'] ) ) {
|
||||
|
||||
// vars
|
||||
$terms = acf_decode_taxonomy_terms( $field['taxonomy'] );
|
||||
|
||||
// append to $args
|
||||
$args['tax_query'] = array(
|
||||
'relation' => 'OR',
|
||||
);
|
||||
|
||||
// now create the tax queries
|
||||
foreach ( $terms as $k => $v ) {
|
||||
|
||||
$args['tax_query'][] = array(
|
||||
'taxonomy' => $k,
|
||||
'field' => 'slug',
|
||||
'terms' => $v,
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
// filters
|
||||
$args = apply_filters( 'acf/fields/relationship/query', $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/relationship/query/name=' . $field['name'], $args, $field, $options['post_id'] );
|
||||
$args = apply_filters( 'acf/fields/relationship/query/key=' . $field['key'], $args, $field, $options['post_id'] );
|
||||
|
||||
// get posts grouped by post type
|
||||
$groups = acf_get_grouped_posts( $args );
|
||||
|
||||
// bail early if no posts
|
||||
if ( empty( $groups ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( array_keys( $groups ) as $group_title ) {
|
||||
|
||||
// vars
|
||||
$posts = acf_extract_var( $groups, $group_title );
|
||||
|
||||
// data
|
||||
$data = array(
|
||||
'text' => $group_title,
|
||||
'children' => array(),
|
||||
);
|
||||
|
||||
// convert post objects to post titles
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$posts[ $post_id ] = $this->get_post_title( $posts[ $post_id ], $field, $options['post_id'] );
|
||||
|
||||
}
|
||||
|
||||
// order posts by search
|
||||
if ( $is_search && empty( $args['orderby'] ) && isset( $args['s'] ) ) {
|
||||
|
||||
$posts = acf_order_by_search( $posts, $args['s'] );
|
||||
|
||||
}
|
||||
|
||||
// append to $data
|
||||
foreach ( array_keys( $posts ) as $post_id ) {
|
||||
|
||||
$data['children'][] = $this->get_post_result( $post_id, $posts[ $post_id ] );
|
||||
|
||||
}
|
||||
|
||||
// append to $results
|
||||
$results[] = $data;
|
||||
|
||||
}
|
||||
|
||||
// add as optgroup or results
|
||||
if ( count( $args['post_type'] ) == 1 ) {
|
||||
|
||||
$results = $results[0]['children'];
|
||||
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
'limit' => $args['posts_per_page'],
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_result
|
||||
*
|
||||
* This function will return an array containing id, text and maybe description data
|
||||
*
|
||||
* @type function
|
||||
* @date 7/07/2016
|
||||
* @since 5.4.0
|
||||
*
|
||||
* @param $id (mixed)
|
||||
* @param $text (string)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_post_result( $id, $text ) {
|
||||
|
||||
// vars
|
||||
$result = array(
|
||||
'id' => $id,
|
||||
'text' => $text,
|
||||
);
|
||||
|
||||
// return
|
||||
return $result;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_post_title
|
||||
*
|
||||
* This function returns the HTML for a result
|
||||
*
|
||||
* @type function
|
||||
* @date 1/11/2013
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post (object)
|
||||
* @param $field (array)
|
||||
* @param $post_id (int) the post_id to which this value is saved to
|
||||
* @return (string)
|
||||
*/
|
||||
|
||||
function get_post_title( $post, $field, $post_id = 0, $is_search = 0 ) {
|
||||
|
||||
// get post_id
|
||||
if ( ! $post_id ) {
|
||||
$post_id = acf_get_form_data( 'post_id' );
|
||||
}
|
||||
|
||||
// vars
|
||||
$title = acf_get_post_title( $post, $is_search );
|
||||
|
||||
// featured_image
|
||||
if ( acf_in_array( 'featured_image', $field['elements'] ) ) {
|
||||
|
||||
// vars
|
||||
$class = 'thumbnail';
|
||||
$thumbnail = acf_get_post_thumbnail( $post->ID, array( 17, 17 ) );
|
||||
|
||||
// icon
|
||||
if ( $thumbnail['type'] == 'icon' ) {
|
||||
|
||||
$class .= ' -' . $thumbnail['type'];
|
||||
|
||||
}
|
||||
|
||||
// append
|
||||
$title = '<div class="' . $class . '">' . $thumbnail['html'] . '</div>' . $title;
|
||||
|
||||
}
|
||||
|
||||
// filters
|
||||
$title = apply_filters( 'acf/fields/relationship/result', $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/relationship/result/name=' . $field['_name'], $title, $post, $field, $post_id );
|
||||
$title = apply_filters( 'acf/fields/relationship/result/key=' . $field['key'], $title, $post, $field, $post_id );
|
||||
|
||||
// return
|
||||
return $title;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$post_type = acf_get_array( $field['post_type'] );
|
||||
$taxonomy = acf_get_array( $field['taxonomy'] );
|
||||
$filters = acf_get_array( $field['filters'] );
|
||||
|
||||
// filters
|
||||
$filter_count = count( $filters );
|
||||
$filter_post_type_choices = array();
|
||||
$filter_taxonomy_choices = array();
|
||||
|
||||
// post_type filter
|
||||
if ( in_array( 'post_type', $filters ) ) {
|
||||
|
||||
$filter_post_type_choices = array(
|
||||
'' => __( 'Select post type', 'acf' ),
|
||||
) + acf_get_pretty_post_types( $post_type );
|
||||
}
|
||||
|
||||
// taxonomy filter
|
||||
if ( in_array( 'taxonomy', $filters ) ) {
|
||||
|
||||
$term_choices = array();
|
||||
$filter_taxonomy_choices = array(
|
||||
'' => __( 'Select taxonomy', 'acf' ),
|
||||
);
|
||||
|
||||
// check for specific taxonomy setting
|
||||
if ( $taxonomy ) {
|
||||
$terms = acf_get_encoded_terms( $taxonomy );
|
||||
$term_choices = acf_get_choices_from_terms( $terms, 'slug' );
|
||||
|
||||
// if no terms were specified, find all terms
|
||||
} else {
|
||||
|
||||
// restrict taxonomies by the post_type selected
|
||||
$term_args = array();
|
||||
if ( $post_type ) {
|
||||
$term_args['taxonomy'] = acf_get_taxonomies(
|
||||
array(
|
||||
'post_type' => $post_type,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// get terms
|
||||
$terms = acf_get_grouped_terms( $term_args );
|
||||
$term_choices = acf_get_choices_from_grouped_terms( $terms, 'slug' );
|
||||
}
|
||||
|
||||
// append term choices
|
||||
$filter_taxonomy_choices = $filter_taxonomy_choices + $term_choices;
|
||||
|
||||
}
|
||||
|
||||
// div attributes
|
||||
$atts = array(
|
||||
'id' => $field['id'],
|
||||
'class' => "acf-relationship {$field['class']}",
|
||||
'data-min' => $field['min'],
|
||||
'data-max' => $field['max'],
|
||||
'data-s' => '',
|
||||
'data-paged' => 1,
|
||||
'data-post_type' => '',
|
||||
'data-taxonomy' => '',
|
||||
);
|
||||
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $atts ); ?>>
|
||||
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'],
|
||||
'value' => '',
|
||||
)
|
||||
);
|
||||
?>
|
||||
|
||||
<?php
|
||||
|
||||
/* filters */
|
||||
if ( $filter_count ) :
|
||||
?>
|
||||
<div class="filters -f<?php echo esc_attr( $filter_count ); ?>">
|
||||
<?php
|
||||
|
||||
/* search */
|
||||
if ( in_array( 'search', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -search">
|
||||
<?php
|
||||
acf_text_input(
|
||||
array(
|
||||
'placeholder' => __( 'Search...', 'acf' ),
|
||||
'data-filter' => 's',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
/* post_type */
|
||||
if ( in_array( 'post_type', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -post_type">
|
||||
<?php
|
||||
acf_select_input(
|
||||
array(
|
||||
'choices' => $filter_post_type_choices,
|
||||
'data-filter' => 'post_type',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php
|
||||
endif;
|
||||
|
||||
/* post_type */
|
||||
if ( in_array( 'taxonomy', $filters ) ) :
|
||||
?>
|
||||
<div class="filter -taxonomy">
|
||||
<?php
|
||||
acf_select_input(
|
||||
array(
|
||||
'choices' => $filter_taxonomy_choices,
|
||||
'data-filter' => 'taxonomy',
|
||||
)
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="selection">
|
||||
<div class="choices">
|
||||
<ul class="acf-bl list choices-list"></ul>
|
||||
</div>
|
||||
<div class="values">
|
||||
<ul class="acf-bl list values-list">
|
||||
<?php
|
||||
if ( ! empty( $field['value'] ) ) :
|
||||
|
||||
// get posts
|
||||
$posts = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $field['value'],
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
// loop
|
||||
foreach ( $posts as $post ) :
|
||||
?>
|
||||
<li>
|
||||
<?php
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $field['name'] . '[]',
|
||||
'value' => $post->ID,
|
||||
)
|
||||
);
|
||||
?>
|
||||
<span tabindex="0" data-id="<?php echo esc_attr( $post->ID ); ?>" class="acf-rel-item acf-rel-item-remove">
|
||||
<?php echo acf_esc_html( $this->get_post_title( $post, $field ) ); ?>
|
||||
<a href="#" class="acf-icon -minus small dark" data-name="remove_item"></a>
|
||||
</span>
|
||||
</li>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Filter by Post Type', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_type',
|
||||
'choices' => acf_get_pretty_post_types(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All post types', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Post Status', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'post_status',
|
||||
'choices' => acf_get_pretty_post_statuses(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'Any post status', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filter by Taxonomy', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'select',
|
||||
'name' => 'taxonomy',
|
||||
'choices' => acf_get_taxonomy_terms(),
|
||||
'multiple' => 1,
|
||||
'ui' => 1,
|
||||
'allow_null' => 1,
|
||||
'placeholder' => __( 'All taxonomies', 'acf' ),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Filters', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'checkbox',
|
||||
'name' => 'filters',
|
||||
'choices' => array(
|
||||
'search' => __( 'Search', 'acf' ),
|
||||
'post_type' => __( 'Post Type', 'acf' ),
|
||||
'taxonomy' => __( 'Taxonomy', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'choices' => array(
|
||||
'object' => __( 'Post Object', 'acf' ),
|
||||
'id' => __( 'Post ID', 'acf' ),
|
||||
),
|
||||
'layout' => 'horizontal',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
$field['min'] = empty( $field['min'] ) ? '' : $field['min'];
|
||||
$field['max'] = empty( $field['max'] ) ? '' : $field['max'];
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Minimum posts', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'min',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Maximum posts', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'number',
|
||||
'name' => 'max',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Elements', 'acf' ),
|
||||
'instructions' => __( 'Selected elements will be displayed in each result', 'acf' ),
|
||||
'type' => 'checkbox',
|
||||
'name' => 'elements',
|
||||
'choices' => array(
|
||||
'featured_image' => __( 'Featured Image', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* This filter is applied 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 ( empty( $value ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// force value to array
|
||||
$value = acf_get_array( $value );
|
||||
|
||||
// convert to int
|
||||
$value = array_map( 'intval', $value );
|
||||
|
||||
// load posts if needed
|
||||
if ( $field['return_format'] == 'object' ) {
|
||||
|
||||
// get posts
|
||||
$value = acf_get_posts(
|
||||
array(
|
||||
'post__in' => $value,
|
||||
'post_type' => $field['post_type'],
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// default
|
||||
if ( empty( $value ) || ! is_array( $value ) ) {
|
||||
|
||||
$value = array();
|
||||
|
||||
}
|
||||
|
||||
// min
|
||||
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
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* update_value()
|
||||
*
|
||||
* This filter is applied 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;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - ensure each value is an id.
|
||||
// - Parse each id as string for SQL LIKE queries.
|
||||
if ( acf_is_sequential_array( $value ) ) {
|
||||
$value = array_map( 'acf_idval', $value );
|
||||
$value = array_map( 'strval', $value );
|
||||
|
||||
// Parse single value for id.
|
||||
} else {
|
||||
$value = acf_idval( $value );
|
||||
}
|
||||
|
||||
// Return value.
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates relationship fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
return acf_get_field_type( 'post_object' )->validate_rest_value( $valid, $value, $field );
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'integer', 'array', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => 'integer',
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
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 int|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 ) {
|
||||
if ( ! $post_type = get_post_type( $object_id ) or ! $post_type = get_post_type_object( $post_type ) ) {
|
||||
continue;
|
||||
}
|
||||
$rest_base = acf_get_object_type_rest_base( $post_type );
|
||||
$links[] = array(
|
||||
'rel' => $post_type->name === 'attachment' ? 'acf:attachment' : 'acf:post',
|
||||
'href' => rest_url( sprintf( '/wp/v2/%s/%s', $rest_base, $object_id ) ),
|
||||
'embeddable' => true,
|
||||
);
|
||||
}
|
||||
|
||||
return $links;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $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_relationship' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,750 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_select' ) ) :
|
||||
|
||||
class acf_field_select extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'select';
|
||||
$this->label = _x( 'Select', 'noun', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A dropdown list with a selection of choices that you specify.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-select.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/select/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'multiple' => 0,
|
||||
'allow_null' => 0,
|
||||
'choices' => array(),
|
||||
'default_value' => '',
|
||||
'ui' => 0,
|
||||
'ajax' => 0,
|
||||
'placeholder' => '',
|
||||
'return_format' => 'value',
|
||||
);
|
||||
|
||||
// ajax
|
||||
add_action( 'wp_ajax_acf/fields/select/query', array( $this, 'ajax_query' ) );
|
||||
add_action( 'wp_ajax_nopriv_acf/fields/select/query', array( $this, 'ajax_query' ) );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* input_admin_enqueue_scripts
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 16/12/2015
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function input_admin_enqueue_scripts() {
|
||||
|
||||
// bail early if no enqueue
|
||||
if ( ! acf_get_setting( 'enqueue_select2' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// globals
|
||||
global $wp_scripts, $wp_styles;
|
||||
|
||||
// vars
|
||||
$min = defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG ? '' : '.min';
|
||||
$major = acf_get_setting( 'select2_version' );
|
||||
$version = '';
|
||||
$script = '';
|
||||
$style = '';
|
||||
|
||||
// attempt to find 3rd party Select2 version
|
||||
// - avoid including v3 CSS when v4 JS is already enququed
|
||||
if ( isset( $wp_scripts->registered['select2'] ) ) {
|
||||
|
||||
$major = (int) $wp_scripts->registered['select2']->ver;
|
||||
|
||||
}
|
||||
|
||||
// v4
|
||||
if ( $major == 4 ) {
|
||||
|
||||
$version = '4.0.13';
|
||||
$script = acf_get_url( "assets/inc/select2/4/select2.full{$min}.js" );
|
||||
$style = acf_get_url( "assets/inc/select2/4/select2{$min}.css" );
|
||||
|
||||
// v3
|
||||
} else {
|
||||
|
||||
$version = '3.5.2';
|
||||
$script = acf_get_url( "assets/inc/select2/3/select2{$min}.js" );
|
||||
$style = acf_get_url( 'assets/inc/select2/3/select2.css' );
|
||||
|
||||
}
|
||||
|
||||
// enqueue
|
||||
wp_enqueue_script( 'select2', $script, array( 'jquery' ), $version );
|
||||
wp_enqueue_style( 'select2', $style, '', $version );
|
||||
|
||||
// localize
|
||||
acf_localize_data(
|
||||
array(
|
||||
'select2L10n' => array(
|
||||
'matches_1' => _x( 'One result is available, press enter to select it.', 'Select2 JS matches_1', 'acf' ),
|
||||
'matches_n' => _x( '%d results are available, use up and down arrow keys to navigate.', 'Select2 JS matches_n', 'acf' ),
|
||||
'matches_0' => _x( 'No matches found', 'Select2 JS matches_0', 'acf' ),
|
||||
'input_too_short_1' => _x( 'Please enter 1 or more characters', 'Select2 JS input_too_short_1', 'acf' ),
|
||||
'input_too_short_n' => _x( 'Please enter %d or more characters', 'Select2 JS input_too_short_n', 'acf' ),
|
||||
'input_too_long_1' => _x( 'Please delete 1 character', 'Select2 JS input_too_long_1', 'acf' ),
|
||||
'input_too_long_n' => _x( 'Please delete %d characters', 'Select2 JS input_too_long_n', 'acf' ),
|
||||
'selection_too_long_1' => _x( 'You can only select 1 item', 'Select2 JS selection_too_long_1', 'acf' ),
|
||||
'selection_too_long_n' => _x( 'You can only select %d items', 'Select2 JS selection_too_long_n', 'acf' ),
|
||||
'load_more' => _x( 'Loading more results…', 'Select2 JS load_more', 'acf' ),
|
||||
'searching' => _x( 'Searching…', 'Select2 JS searching', 'acf' ),
|
||||
'load_fail' => _x( 'Loading failed', 'Select2 JS load_fail', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* ajax_query
|
||||
*
|
||||
* description
|
||||
*
|
||||
* @type function
|
||||
* @date 24/10/13
|
||||
* @since 5.0.0
|
||||
*
|
||||
* @param $post_id (int)
|
||||
* @return $post_id (int)
|
||||
*/
|
||||
|
||||
function ajax_query() {
|
||||
|
||||
// validate
|
||||
if ( ! acf_verify_ajax() ) {
|
||||
die();
|
||||
}
|
||||
|
||||
// get choices
|
||||
$response = $this->get_ajax_query( $_POST );
|
||||
|
||||
// return
|
||||
acf_send_ajax_results( $response );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* get_ajax_query
|
||||
*
|
||||
* This function will return an array of data formatted for use in a select2 AJAX response
|
||||
*
|
||||
* @type function
|
||||
* @date 15/10/2014
|
||||
* @since 5.0.9
|
||||
*
|
||||
* @param $options (array)
|
||||
* @return (array)
|
||||
*/
|
||||
|
||||
function get_ajax_query( $options = array() ) {
|
||||
|
||||
// defaults
|
||||
$options = acf_parse_args(
|
||||
$options,
|
||||
array(
|
||||
'post_id' => 0,
|
||||
's' => '',
|
||||
'field_key' => '',
|
||||
'paged' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
// load field
|
||||
$field = acf_get_field( $options['field_key'] );
|
||||
if ( ! $field ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// get choices
|
||||
$choices = acf_get_array( $field['choices'] );
|
||||
if ( empty( $field['choices'] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// vars
|
||||
$results = array();
|
||||
$s = null;
|
||||
|
||||
// search
|
||||
if ( $options['s'] !== '' ) {
|
||||
|
||||
// strip slashes (search may be integer)
|
||||
$s = strval( $options['s'] );
|
||||
$s = wp_unslash( $s );
|
||||
|
||||
}
|
||||
|
||||
// loop
|
||||
foreach ( $field['choices'] as $k => $v ) {
|
||||
|
||||
// ensure $v is a string
|
||||
$v = strval( $v );
|
||||
|
||||
// if searching, but doesn't exist
|
||||
if ( is_string( $s ) && stripos( $v, $s ) === false ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// append
|
||||
$results[] = array(
|
||||
'id' => $k,
|
||||
'text' => $v,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// vars
|
||||
$response = array(
|
||||
'results' => $results,
|
||||
);
|
||||
|
||||
// return
|
||||
return $response;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// convert
|
||||
$value = acf_get_array( $field['value'] );
|
||||
$choices = acf_get_array( $field['choices'] );
|
||||
|
||||
// placeholder
|
||||
if ( empty( $field['placeholder'] ) ) {
|
||||
$field['placeholder'] = _x( 'Select', 'verb', 'acf' );
|
||||
}
|
||||
|
||||
// add empty value (allows '' to be selected)
|
||||
if ( empty( $value ) ) {
|
||||
$value = array( '' );
|
||||
}
|
||||
|
||||
// prepend empty choice
|
||||
// - only for single selects
|
||||
// - have tried array_merge but this causes keys to re-index if is numeric (post ID's)
|
||||
if ( $field['allow_null'] && ! $field['multiple'] ) {
|
||||
$choices = array( '' => "- {$field['placeholder']} -" ) + $choices;
|
||||
}
|
||||
|
||||
// clean up choices if using ajax
|
||||
if ( $field['ui'] && $field['ajax'] ) {
|
||||
$minimal = array();
|
||||
foreach ( $value as $key ) {
|
||||
if ( isset( $choices[ $key ] ) ) {
|
||||
$minimal[ $key ] = $choices[ $key ];
|
||||
}
|
||||
}
|
||||
$choices = $minimal;
|
||||
}
|
||||
|
||||
// vars
|
||||
$select = array(
|
||||
'id' => $field['id'],
|
||||
'class' => $field['class'],
|
||||
'name' => $field['name'],
|
||||
'data-ui' => $field['ui'],
|
||||
'data-ajax' => $field['ajax'],
|
||||
'data-multiple' => $field['multiple'],
|
||||
'data-placeholder' => $field['placeholder'],
|
||||
'data-allow_null' => $field['allow_null'],
|
||||
);
|
||||
|
||||
if ( $field['aria-label'] ) {
|
||||
$select['aria-label'] = $field['aria-label'];
|
||||
}
|
||||
|
||||
// multiple
|
||||
if ( $field['multiple'] ) {
|
||||
|
||||
$select['multiple'] = 'multiple';
|
||||
$select['size'] = 5;
|
||||
$select['name'] .= '[]';
|
||||
|
||||
// Reduce size to single line if UI.
|
||||
if ( $field['ui'] ) {
|
||||
$select['size'] = 1;
|
||||
}
|
||||
}
|
||||
|
||||
// special atts
|
||||
if ( ! empty( $field['readonly'] ) ) {
|
||||
$select['readonly'] = 'readonly';
|
||||
}
|
||||
if ( ! empty( $field['disabled'] ) ) {
|
||||
$select['disabled'] = 'disabled';
|
||||
}
|
||||
if ( ! empty( $field['ajax_action'] ) ) {
|
||||
$select['data-ajax_action'] = $field['ajax_action'];
|
||||
}
|
||||
|
||||
if ( ! empty( $field['hide_search'] ) ) {
|
||||
$select['data-minimum-results-for-search'] = '-1';
|
||||
}
|
||||
|
||||
// hidden input is needed to allow validation to see <select> element with no selected value
|
||||
if ( $field['multiple'] || $field['ui'] ) {
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'id' => $field['id'] . '-input',
|
||||
'name' => $field['name'],
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
if ( ! empty( $field['query_nonce'] ) ) {
|
||||
$select['data-query-nonce'] = $field['query_nonce'];
|
||||
}
|
||||
|
||||
// append
|
||||
$select['value'] = $value;
|
||||
$select['choices'] = $choices;
|
||||
|
||||
// render
|
||||
acf_select_input( $select );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// encode choices (convert from array)
|
||||
$field['choices'] = acf_encode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_encode_choices( $field['default_value'], false );
|
||||
|
||||
// choices
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Choices', 'acf' ),
|
||||
'instructions' => __( 'Enter each choice on a new line.', 'acf' ) . '<br />' . __( 'For more control, you may specify both a value and label like this:', 'acf' ) . '<br /><span class="acf-field-setting-example">' . __( 'red : Red', 'acf' ) . '</span>',
|
||||
'name' => 'choices',
|
||||
'type' => 'textarea',
|
||||
)
|
||||
);
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Enter each default value on a new line', 'acf' ),
|
||||
'name' => 'default_value',
|
||||
'type' => 'textarea',
|
||||
)
|
||||
);
|
||||
|
||||
// return_format
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'instructions' => __( 'Specify the value returned', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'layout' => 'horizontal',
|
||||
'choices' => array(
|
||||
'value' => __( 'Value', 'acf' ),
|
||||
'label' => __( 'Label', 'acf' ),
|
||||
'array' => __( 'Both (Array)', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Select multiple values?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'multiple',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Allow Null?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'allow_null',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Stylized UI', 'acf' ),
|
||||
'instructions' => __( 'Use a stylized checkbox using select2', 'acf' ),
|
||||
'name' => 'ui',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Use AJAX to lazy load choices?', 'acf' ),
|
||||
'instructions' => '',
|
||||
'name' => 'ajax',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* load_value()
|
||||
*
|
||||
* This filter is applied to the $value after it is loaded from the db
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $value (mixed) the value found in 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
|
||||
*/
|
||||
function load_value( $value, $post_id, $field ) {
|
||||
|
||||
// Return an array when field is set for multiple.
|
||||
if ( $field['multiple'] ) {
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return array();
|
||||
}
|
||||
return acf_array( $value );
|
||||
}
|
||||
|
||||
// Otherwise, return a single value.
|
||||
return acf_unarray( $value );
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_field()
|
||||
*
|
||||
* This filter is appied to the $field before it is saved to the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
* @param $post_id - the field group ID (post_type = acf)
|
||||
*
|
||||
* @return $field - the modified field
|
||||
*/
|
||||
|
||||
function update_field( $field ) {
|
||||
|
||||
// decode choices (convert to array)
|
||||
$field['choices'] = acf_decode_choices( $field['choices'] );
|
||||
$field['default_value'] = acf_decode_choices( $field['default_value'], true );
|
||||
|
||||
// Convert back to string for single selects.
|
||||
if ( ! $field['multiple'] ) {
|
||||
$field['default_value'] = acf_unarray( $field['default_value'] );
|
||||
}
|
||||
|
||||
// return
|
||||
return $field;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* update_value()
|
||||
*
|
||||
* 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;
|
||||
}
|
||||
|
||||
// Format array of values.
|
||||
// - Parse each value as string for SQL LIKE queries.
|
||||
if ( is_array( $value ) ) {
|
||||
$value = array_map( 'strval', $value );
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
// translate
|
||||
$field['choices'] = acf_translate( $field['choices'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
if ( is_array( $value ) ) {
|
||||
foreach ( $value as $i => $val ) {
|
||||
$value[ $i ] = $this->format_value_single( $val, $post_id, $field );
|
||||
}
|
||||
} else {
|
||||
$value = $this->format_value_single( $value, $post_id, $field );
|
||||
}
|
||||
return $value;
|
||||
}
|
||||
|
||||
|
||||
function format_value_single( $value, $post_id, $field ) {
|
||||
|
||||
// bail early if is empty
|
||||
if ( acf_is_empty( $value ) ) {
|
||||
return $value;
|
||||
}
|
||||
|
||||
// vars
|
||||
$label = acf_maybe_get( $field['choices'], $value, $value );
|
||||
|
||||
// value
|
||||
if ( $field['return_format'] == 'value' ) {
|
||||
|
||||
// do nothing
|
||||
|
||||
// label
|
||||
} elseif ( $field['return_format'] == 'label' ) {
|
||||
|
||||
$value = $label;
|
||||
|
||||
// array
|
||||
} elseif ( $field['return_format'] == 'array' ) {
|
||||
|
||||
$value = array(
|
||||
'value' => $value,
|
||||
'label' => $label,
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates select fields updated via the REST API.
|
||||
*
|
||||
* @param bool $valid
|
||||
* @param int $value
|
||||
* @param array $field
|
||||
*
|
||||
* @return bool|WP_Error
|
||||
*/
|
||||
public function validate_rest_value( $valid, $value, $field ) {
|
||||
// rest_validate_request_arg() handles the other types, we just worry about strings.
|
||||
if ( is_null( $value ) || is_array( $value ) ) {
|
||||
return $valid;
|
||||
}
|
||||
|
||||
$option_keys = array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
);
|
||||
|
||||
$allowed = empty( $option_keys ) ? $field['choices'] : $option_keys;
|
||||
|
||||
if ( ! in_array( $value, $allowed ) ) {
|
||||
$param = sprintf( '%s[%s]', $field['prefix'], $field['name'] );
|
||||
$data = array(
|
||||
'param' => $param,
|
||||
'value' => $value,
|
||||
);
|
||||
$error = sprintf(
|
||||
__( '%1$s is not one of %2$s', 'acf' ),
|
||||
$param,
|
||||
implode( ', ', $allowed )
|
||||
);
|
||||
|
||||
return new WP_Error( 'rest_invalid_param', $error, $data );
|
||||
}
|
||||
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
/**
|
||||
* If a user has defined keys for the select options,
|
||||
* we should use the keys for the available options to POST to,
|
||||
* since they are what is displayed in GET requests.
|
||||
*/
|
||||
$option_keys = array_diff(
|
||||
array_keys( $field['choices'] ),
|
||||
array_values( $field['choices'] )
|
||||
);
|
||||
|
||||
$schema = array(
|
||||
'type' => array( 'string', 'array', 'int', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
'items' => array(
|
||||
'type' => array( 'string', 'int' ),
|
||||
'enum' => empty( $option_keys ) ? $field['choices'] : $option_keys,
|
||||
),
|
||||
);
|
||||
|
||||
if ( empty( $field['allow_null'] ) ) {
|
||||
$schema['minItems'] = 1;
|
||||
}
|
||||
|
||||
if ( empty( $field['multiple'] ) ) {
|
||||
$schema['maxItems'] = 1;
|
||||
}
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_select' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,89 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_separator' ) ) :
|
||||
|
||||
class acf_field_separator extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'separator';
|
||||
$this->label = __( 'Separator', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-separator.png';
|
||||
$this->category = 'layout';
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
/* do nothing */
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_field()
|
||||
*
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_separator' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,175 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_tab' ) ) :
|
||||
|
||||
class acf_field_tab extends acf_field {
|
||||
|
||||
public $show_in_rest = false;
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'tab';
|
||||
$this->label = __( 'Tab', 'acf' );
|
||||
$this->category = 'layout';
|
||||
$this->description = __( 'Allows you to group fields into tabbed sections in the edit screen. Useful for keeping fields organized and structured.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-tabs.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/tab/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'placement' => 'top',
|
||||
'endpoint' => 0, // added in 5.2.8
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array(
|
||||
'href' => '',
|
||||
'class' => 'acf-tab-button',
|
||||
'data-placement' => $field['placement'],
|
||||
'data-endpoint' => $field['endpoint'],
|
||||
'data-key' => $field['key'],
|
||||
);
|
||||
|
||||
if ( isset( $field['settings-type'] ) ) {
|
||||
$atts['class'] .= ' acf-settings-type-' . acf_slugify( $field['settings-type'] );
|
||||
}
|
||||
|
||||
?>
|
||||
<a <?php echo acf_esc_attrs( $atts ); ?>><?php echo acf_esc_html( $field['label'] ); ?></a>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
|
||||
function render_field_settings( $field ) {
|
||||
|
||||
/*
|
||||
// message
|
||||
$message = '';
|
||||
$message .= '<p>' . __( 'Use "Tab Fields" to better organize your edit screen by grouping fields together.', 'acf') . '</p>';
|
||||
$message .= '<p>' . __( 'All fields following this "tab field" (or until another "tab field" is defined) will be grouped together using this field\'s label as the tab heading.','acf') . '</p>';
|
||||
|
||||
|
||||
// default_value
|
||||
acf_render_field_setting( $field, array(
|
||||
'label' => __('Instructions','acf'),
|
||||
'instructions' => '',
|
||||
'name' => 'notes',
|
||||
'type' => 'message',
|
||||
'message' => $message,
|
||||
));
|
||||
*/
|
||||
|
||||
// preview_size
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placement', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'placement',
|
||||
'choices' => array(
|
||||
'top' => __( 'Top aligned', 'acf' ),
|
||||
'left' => __( 'Left aligned', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
// endpoint
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Tab Group', 'acf' ),
|
||||
'instructions' => __( 'Start a new group of tabs at this tab.', 'acf' ),
|
||||
'name' => 'endpoint',
|
||||
'type' => 'true_false',
|
||||
'ui' => 1,
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* load_field()
|
||||
*
|
||||
* This filter is appied to the $field after it is loaded from the database
|
||||
*
|
||||
* @type filter
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*
|
||||
* @param $field - the field array holding all the field options
|
||||
*
|
||||
* @return $field - the field array holding all the field options
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
|
||||
// remove name to avoid caching issue
|
||||
$field['name'] = '';
|
||||
|
||||
// remove instructions
|
||||
$field['instructions'] = '';
|
||||
|
||||
// remove required to avoid JS issues
|
||||
$field['required'] = 0;
|
||||
|
||||
// set value other than 'null' to avoid ACF loading / caching issue
|
||||
$field['value'] = false;
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_tab' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,213 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_text' ) ) :
|
||||
|
||||
class acf_field_text extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'text';
|
||||
$this->label = __( 'Text', 'acf' );
|
||||
$this->description = __( 'A basic text input, useful for storing single string values.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-text.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/text/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'maxlength' => '',
|
||||
'placeholder' => '',
|
||||
'prepend' => '',
|
||||
'append' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
$html = '';
|
||||
|
||||
// Prepend text.
|
||||
if ( $field['prepend'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-prepended';
|
||||
$html .= '<div class="acf-input-prepend">' . acf_esc_html( $field['prepend'] ) . '</div>';
|
||||
}
|
||||
|
||||
// Append text.
|
||||
if ( $field['append'] !== '' ) {
|
||||
$field['class'] .= ' acf-is-appended';
|
||||
$html .= '<div class="acf-input-append">' . acf_esc_html( $field['append'] ) . '</div>';
|
||||
}
|
||||
|
||||
// Input.
|
||||
$input_attrs = array();
|
||||
foreach ( array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'maxlength', 'pattern', 'readonly', 'disabled', 'required' ) as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$input_attrs[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
$html .= '<div class="acf-input-wrap">' . acf_get_text_input( acf_filter_attrs( $input_attrs ) ) . '</div>';
|
||||
|
||||
// Display.
|
||||
echo $html;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Character Limit', 'acf' ),
|
||||
'instructions' => __( 'Leave blank for no limit', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'maxlength',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Prepend', 'acf' ),
|
||||
'instructions' => __( 'Appears before the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'prepend',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Append', 'acf' ),
|
||||
'instructions' => __( 'Appears after the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'append',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* Validates a field's value.
|
||||
*
|
||||
* @date 29/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param (bool|string) Whether the value is vaid or not.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The HTML input name.
|
||||
* @return (bool|string)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// Check maxlength
|
||||
if ( $field['maxlength'] && ( acf_strlen( $value ) > $field['maxlength'] ) ) {
|
||||
return sprintf( __( 'Value must not exceed %d characters', 'acf' ), $field['maxlength'] );
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( ! empty( $field['maxlength'] ) ) {
|
||||
$schema['maxLength'] = (int) $field['maxlength'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_text' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,266 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_textarea' ) ) :
|
||||
|
||||
class acf_field_textarea extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'textarea';
|
||||
$this->label = __( 'Text Area', 'acf' );
|
||||
$this->description = __( 'A basic textarea input for storing paragraphs of text.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-textarea.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/textarea/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'new_lines' => '',
|
||||
'maxlength' => '',
|
||||
'placeholder' => '',
|
||||
'rows' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'id', 'class', 'name', 'value', 'placeholder', 'rows', 'maxlength' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
|
||||
// rows
|
||||
if ( ! $field['rows'] ) {
|
||||
$field['rows'] = 8;
|
||||
}
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// return
|
||||
acf_textarea_input( $atts );
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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
|
||||
*
|
||||
* @param $field - an array holding all the field's data
|
||||
*
|
||||
* @type action
|
||||
* @since 3.6
|
||||
* @date 23/01/13
|
||||
*/
|
||||
function render_field_settings( $field ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'textarea',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 ) {
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Character Limit', 'acf' ),
|
||||
'instructions' => __( 'Leave blank for no limit', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'maxlength',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Rows', 'acf' ),
|
||||
'instructions' => __( 'Sets the textarea height', 'acf' ),
|
||||
'type' => 'number',
|
||||
'name' => 'rows',
|
||||
'placeholder' => 8,
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'New Lines', 'acf' ),
|
||||
'instructions' => __( 'Controls how new lines are rendered', 'acf' ),
|
||||
'type' => 'select',
|
||||
'name' => 'new_lines',
|
||||
'choices' => array(
|
||||
'wpautop' => __( 'Automatically add paragraphs', 'acf' ),
|
||||
'br' => __( 'Automatically add <br>', 'acf' ),
|
||||
'' => __( 'No Formatting', 'acf' ),
|
||||
),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* This filter is applied 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 or not for template
|
||||
if ( empty( $value ) || ! is_string( $value ) ) {
|
||||
|
||||
return $value;
|
||||
|
||||
}
|
||||
|
||||
// new lines
|
||||
if ( $field['new_lines'] == 'wpautop' ) {
|
||||
|
||||
$value = wpautop( $value );
|
||||
|
||||
} elseif ( $field['new_lines'] == 'br' ) {
|
||||
|
||||
$value = nl2br( $value );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $value;
|
||||
}
|
||||
|
||||
/**
|
||||
* validate_value
|
||||
*
|
||||
* Validates a field's value.
|
||||
*
|
||||
* @date 29/1/19
|
||||
* @since 5.7.11
|
||||
*
|
||||
* @param (bool|string) Whether the value is vaid or not.
|
||||
* @param mixed $value The field value.
|
||||
* @param array $field The field array.
|
||||
* @param string $input The HTML input name.
|
||||
* @return (bool|string)
|
||||
*/
|
||||
function validate_value( $valid, $value, $field, $input ) {
|
||||
|
||||
// Check maxlength.
|
||||
if ( $field['maxlength'] && ( acf_strlen( $value ) > $field['maxlength'] ) ) {
|
||||
return sprintf( __( 'Value must not exceed %d characters', 'acf' ), $field['maxlength'] );
|
||||
}
|
||||
|
||||
// Return.
|
||||
return $valid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
|
||||
if ( ! empty( $field['maxlength'] ) ) {
|
||||
$schema['maxLength'] = (int) $field['maxlength'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_textarea' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
@ -0,0 +1,214 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_time_picker' ) ) :
|
||||
|
||||
class acf_field_time_picker extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'time_picker';
|
||||
$this->label = __( 'Time Picker', 'acf' );
|
||||
$this->category = 'advanced';
|
||||
$this->description = __( 'An interactive UI for picking a time. The time format can be customized using the field settings.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-time.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/time-picker/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'display_format' => 'g:i a',
|
||||
'return_format' => 'g:i a',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// Set value.
|
||||
$display_value = '';
|
||||
|
||||
if ( $field['value'] ) {
|
||||
$display_value = acf_format_date( $field['value'], $field['display_format'] );
|
||||
}
|
||||
|
||||
// Elements.
|
||||
$div = array(
|
||||
'class' => 'acf-time-picker acf-input-wrap',
|
||||
'data-time_format' => acf_convert_time_to_js( $field['display_format'] ),
|
||||
);
|
||||
$hidden_input = array(
|
||||
'id' => $field['id'],
|
||||
'class' => 'input-alt',
|
||||
'type' => 'hidden',
|
||||
'name' => $field['name'],
|
||||
'value' => $field['value'],
|
||||
);
|
||||
$text_input = array(
|
||||
'class' => $field['class'] . ' input',
|
||||
'type' => 'text',
|
||||
'value' => $display_value,
|
||||
);
|
||||
foreach ( array( 'readonly', 'disabled' ) as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$hidden_input[ $k ] = $k;
|
||||
$text_input[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// Output.
|
||||
?>
|
||||
<div <?php echo acf_esc_attrs( $div ); ?>>
|
||||
<?php acf_hidden_input( $hidden_input ); ?>
|
||||
<?php acf_text_input( $text_input ); ?>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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 ) {
|
||||
$g_i_a = date_i18n( 'g:i a' );
|
||||
$H_i_s = date_i18n( 'H:i:s' );
|
||||
|
||||
echo '<div class="acf-field-settings-split">';
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Display Format', 'acf' ),
|
||||
'hint' => __( 'The format displayed when editing a post', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'display_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'g:i a' => '<span>' . $g_i_a . '</span><code>g:i a</code>',
|
||||
'H:i:s' => '<span>' . $H_i_s . '</span><code>H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Return Format', 'acf' ),
|
||||
'hint' => __( 'The format returned via template functions', 'acf' ),
|
||||
'type' => 'radio',
|
||||
'name' => 'return_format',
|
||||
'other_choice' => 1,
|
||||
'choices' => array(
|
||||
'g:i a' => '<span>' . $g_i_a . '</span><code>g:i a</code>',
|
||||
'H:i:s' => '<span>' . $H_i_s . '</span><code>H:i:s</code>',
|
||||
'other' => '<span>' . __( 'Custom:', 'acf' ) . '</span>',
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
return acf_format_date( $value, $field['return_format'] );
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* This filter is applied to the $field after it is loaded from the database
|
||||
* and ensures the return and display values are set.
|
||||
*
|
||||
* @type filter
|
||||
* @since 5.11.0
|
||||
* @date 28/09/21
|
||||
*
|
||||
* @param array $field The field array holding all the field options.
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
function load_field( $field ) {
|
||||
if ( empty( $field['display_format'] ) ) {
|
||||
$field['display_format'] = $this->defaults['display_format'];
|
||||
}
|
||||
|
||||
if ( empty( $field['return_format'] ) ) {
|
||||
$field['return_format'] = $this->defaults['return_format'];
|
||||
}
|
||||
|
||||
return $field;
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
return array(
|
||||
'type' => array( 'string', 'null' ),
|
||||
'description' => 'A `H:i:s` formatted time string.',
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_time_picker' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,331 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_true_false' ) ) :
|
||||
|
||||
class acf_field_true_false extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* __construct
|
||||
*
|
||||
* 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 = 'true_false';
|
||||
$this->label = __( 'True / False', 'acf' );
|
||||
$this->category = 'choice';
|
||||
$this->description = __( 'A toggle that allows you to pick a value of 1 or 0 (on or off, true or false, etc). Can be presented as a stylized switch or checkbox.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-true-false.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/true-false/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => 0,
|
||||
'message' => '',
|
||||
'ui' => 0,
|
||||
'ui_on_text' => '',
|
||||
'ui_off_text' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$input = array(
|
||||
'type' => 'checkbox',
|
||||
'id' => $field['id'],
|
||||
'name' => $field['name'],
|
||||
'value' => '1',
|
||||
'class' => $field['class'],
|
||||
'autocomplete' => 'off',
|
||||
);
|
||||
|
||||
$hidden = array(
|
||||
'name' => $field['name'],
|
||||
'value' => 0,
|
||||
);
|
||||
|
||||
$active = $field['value'] ? true : false;
|
||||
$switch = '';
|
||||
|
||||
// checked
|
||||
if ( $active ) {
|
||||
$input['checked'] = 'checked';
|
||||
}
|
||||
|
||||
// ui
|
||||
if ( $field['ui'] ) {
|
||||
|
||||
// vars
|
||||
if ( $field['ui_on_text'] === '' ) {
|
||||
$field['ui_on_text'] = __( 'Yes', 'acf' );
|
||||
}
|
||||
if ( $field['ui_off_text'] === '' ) {
|
||||
$field['ui_off_text'] = __( 'No', 'acf' );
|
||||
}
|
||||
|
||||
// update input
|
||||
$input['class'] .= ' acf-switch-input';
|
||||
// $input['style'] = 'display:none;';
|
||||
|
||||
$switch .= '<div class="acf-switch' . ( $active ? ' -on' : '' ) . '">';
|
||||
$switch .= '<span class="acf-switch-on">' . $field['ui_on_text'] . '</span>';
|
||||
$switch .= '<span class="acf-switch-off">' . $field['ui_off_text'] . '</span>';
|
||||
$switch .= '<div class="acf-switch-slider"></div>';
|
||||
$switch .= '</div>';
|
||||
|
||||
}
|
||||
|
||||
?>
|
||||
<div class="acf-true-false">
|
||||
<?php acf_hidden_input( $hidden ); ?>
|
||||
<label>
|
||||
<input <?php echo acf_esc_attr( $input ); ?>/>
|
||||
<?php
|
||||
if ( $switch ) {
|
||||
echo acf_esc_html( $switch );}
|
||||
?>
|
||||
<?php
|
||||
if ( $field['message'] ) :
|
||||
?>
|
||||
<span class="message"><?php echo acf_esc_html( $field['message'] ); ?></span><?php endif; ?>
|
||||
</label>
|
||||
</div>
|
||||
<?php
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Message', 'acf' ),
|
||||
'instructions' => __( 'Displays text alongside the checkbox', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'message',
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => '',
|
||||
'type' => 'true_false',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'On Text', 'acf' ),
|
||||
'instructions' => __( 'Text shown when active', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'ui_on_text',
|
||||
'placeholder' => __( 'Yes', 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Off Text', 'acf' ),
|
||||
'instructions' => __( 'Text shown when inactive', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'ui_off_text',
|
||||
'placeholder' => __( 'No', 'acf' ),
|
||||
'conditions' => array(
|
||||
'field' => 'ui',
|
||||
'operator' => '==',
|
||||
'value' => 1,
|
||||
),
|
||||
)
|
||||
);
|
||||
|
||||
acf_render_field_setting(
|
||||
$field,
|
||||
array(
|
||||
'label' => __( 'Stylized UI', 'acf' ),
|
||||
'instructions' => __( 'Use a stylized checkbox using select2', 'acf' ),
|
||||
'type' => 'true_false',
|
||||
'name' => 'ui',
|
||||
'ui' => 1,
|
||||
'class' => 'acf-field-object-true-false-ui',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/*
|
||||
* format_value()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
return empty( $value ) ? false : true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if not required
|
||||
if ( ! $field['required'] ) {
|
||||
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
// value may be '0'
|
||||
if ( ! $value ) {
|
||||
|
||||
return false;
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* translate_field
|
||||
*
|
||||
* This function will translate field settings
|
||||
*
|
||||
* @type function
|
||||
* @date 8/03/2016
|
||||
* @since 5.3.2
|
||||
*
|
||||
* @param $field (array)
|
||||
* @return $field
|
||||
*/
|
||||
|
||||
function translate_field( $field ) {
|
||||
|
||||
// translate
|
||||
$field['message'] = acf_translate( $field['message'] );
|
||||
$field['ui_on_text'] = acf_translate( $field['ui_on_text'] );
|
||||
$field['ui_off_text'] = acf_translate( $field['ui_off_text'] );
|
||||
|
||||
// return
|
||||
return $field;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = array(
|
||||
'type' => array( 'boolean', 'null' ),
|
||||
'required' => ! empty( $field['required'] ),
|
||||
);
|
||||
|
||||
if ( isset( $field['default_value'] ) && '' !== $field['default_value'] ) {
|
||||
$schema['default'] = (bool) $field['default_value'];
|
||||
}
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
/**
|
||||
* Apply basic formatting to prepare the value for default REST output.
|
||||
*
|
||||
* @param mixed $value
|
||||
* @param string|int $post_id
|
||||
* @param array $field
|
||||
* @return mixed
|
||||
*/
|
||||
public function format_value_for_rest( $value, $post_id, array $field ) {
|
||||
return (bool) $value;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_true_false' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
?>
|
@ -0,0 +1,192 @@
|
||||
<?php
|
||||
|
||||
if ( ! class_exists( 'acf_field_url' ) ) :
|
||||
|
||||
class acf_field_url extends acf_field {
|
||||
|
||||
|
||||
/*
|
||||
* initialize
|
||||
*
|
||||
* 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 = 'url';
|
||||
$this->label = __( 'URL', 'acf' );
|
||||
$this->description = __( 'A text input specifically designed for storing web addresses.', 'acf' );
|
||||
$this->preview_image = acf_get_url() . '/assets/images/field-type-previews/field-preview-url.png';
|
||||
$this->doc_url = acf_add_url_utm_tags( 'https://www.advancedcustomfields.com/resources/url/', 'docs', 'field-type-selection' );
|
||||
$this->defaults = array(
|
||||
'default_value' => '',
|
||||
'placeholder' => '',
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field()
|
||||
*
|
||||
* 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 ) {
|
||||
|
||||
// vars
|
||||
$atts = array();
|
||||
$keys = array( 'type', 'id', 'class', 'name', 'value', 'placeholder', 'pattern' );
|
||||
$keys2 = array( 'readonly', 'disabled', 'required' );
|
||||
$html = '';
|
||||
|
||||
// atts (value="123")
|
||||
foreach ( $keys as $k ) {
|
||||
if ( isset( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $field[ $k ];
|
||||
}
|
||||
}
|
||||
|
||||
// atts2 (disabled="disabled")
|
||||
foreach ( $keys2 as $k ) {
|
||||
if ( ! empty( $field[ $k ] ) ) {
|
||||
$atts[ $k ] = $k;
|
||||
}
|
||||
}
|
||||
|
||||
// remove empty atts
|
||||
$atts = acf_clean_atts( $atts );
|
||||
|
||||
// render
|
||||
$html .= '<div class="acf-input-wrap acf-url">';
|
||||
$html .= '<i class="acf-icon -globe -small"></i>' . acf_get_text_input( $atts );
|
||||
$html .= '</div>';
|
||||
|
||||
// return
|
||||
echo $html;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* render_field_settings()
|
||||
*
|
||||
* 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' => __( 'Default Value', 'acf' ),
|
||||
'instructions' => __( 'Appears when creating a new post', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'default_value',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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' => __( 'Placeholder Text', 'acf' ),
|
||||
'instructions' => __( 'Appears within the input', 'acf' ),
|
||||
'type' => 'text',
|
||||
'name' => 'placeholder',
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* validate_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 ) {
|
||||
|
||||
// bail early if empty
|
||||
if ( empty( $value ) ) {
|
||||
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
if ( strpos( $value, '://' ) !== false ) {
|
||||
|
||||
// url
|
||||
|
||||
} elseif ( strpos( $value, '//' ) === 0 ) {
|
||||
|
||||
// protocol relative url
|
||||
|
||||
} else {
|
||||
|
||||
$valid = __( 'Value must be a valid URL', 'acf' );
|
||||
|
||||
}
|
||||
|
||||
// return
|
||||
return $valid;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Return the schema array for the REST API.
|
||||
*
|
||||
* @param array $field
|
||||
* @return array
|
||||
*/
|
||||
public function get_rest_schema( array $field ) {
|
||||
$schema = parent::get_rest_schema( $field );
|
||||
$schema['format'] = 'uri';
|
||||
|
||||
return $schema;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
||||
// initialize
|
||||
acf_register_field_type( 'acf_field_url' );
|
||||
|
||||
endif; // class_exists check
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user