ACF Pro: Upgrade from free, add Documents repeater field with download buttons
This commit is contained in:
@@ -0,0 +1,98 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Blocks;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* The core ACF Blocks binding class.
|
||||
*/
|
||||
class Bindings {
|
||||
/**
|
||||
* Block Bindings constructor.
|
||||
*/
|
||||
public function __construct() {
|
||||
// Final check we're on WP 6.5 or newer.
|
||||
if ( ! function_exists( 'register_block_bindings_source' ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
add_action( 'acf/init', array( $this, 'register_binding_sources' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Hooked to acf/init, register our binding sources.
|
||||
*/
|
||||
public function register_binding_sources() {
|
||||
if ( acf_get_setting( 'enable_block_bindings' ) ) {
|
||||
register_block_bindings_source(
|
||||
'acf/field',
|
||||
array(
|
||||
'label' => _x( 'ACF Fields', 'The core ACF block binding source name for fields on the current page', 'acf' ),
|
||||
'get_value_callback' => array( $this, 'get_value' ),
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle returing the block binding value for an ACF meta value.
|
||||
*
|
||||
* @since 6.2.8
|
||||
*
|
||||
* @param array $source_attrs An array of the source attributes requested.
|
||||
* @param \WP_Block $block_instance The block instance.
|
||||
* @param string $attribute_name The block's bound attribute name.
|
||||
* @return string|null The block binding value or an empty string on failure.
|
||||
*/
|
||||
public function get_value( array $source_attrs, \WP_Block $block_instance, string $attribute_name ) {
|
||||
if ( ! isset( $source_attrs['key'] ) || ! is_string( $source_attrs['key'] ) ) {
|
||||
$value = '';
|
||||
} else {
|
||||
$field = get_field_object( $source_attrs['key'], false, true, true, true );
|
||||
|
||||
if ( ! $field ) {
|
||||
return '';
|
||||
}
|
||||
|
||||
if ( ! acf_field_type_supports( $field['type'], 'bindings', true ) ) {
|
||||
if ( is_preview() ) {
|
||||
return apply_filters( 'acf/bindings/field_not_supported_message', '[' . esc_html__( 'The requested ACF field type does not support output in Block Bindings or the ACF shortcode.', 'acf' ) . ']' );
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
if ( isset( $field['allow_in_bindings'] ) && ! $field['allow_in_bindings'] ) {
|
||||
if ( is_preview() ) {
|
||||
return apply_filters( 'acf/bindings/field_not_allowed_message', '[' . esc_html__( 'The requested ACF field is not allowed to be output in bindings or the ACF Shortcode.', 'acf' ) . ']' );
|
||||
} else {
|
||||
return '';
|
||||
}
|
||||
}
|
||||
|
||||
$value = $field['value'];
|
||||
|
||||
if ( is_array( $value ) ) {
|
||||
$value = implode( ', ', $value );
|
||||
}
|
||||
|
||||
// If we're not a scalar we'd throw an error, so return early for safety.
|
||||
if ( ! is_scalar( $value ) ) {
|
||||
$value = null;
|
||||
}
|
||||
}
|
||||
|
||||
return apply_filters( 'acf/blocks/binding_value', $value, $source_attrs, $block_instance, $attribute_name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,2 @@
|
||||
<?php
|
||||
// There are many ways to WordPress.
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to comment meta.
|
||||
*/
|
||||
class Comment extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'comment';
|
||||
}
|
||||
@@ -0,0 +1,189 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* The MetaType base class.
|
||||
*/
|
||||
class MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = '';
|
||||
|
||||
/**
|
||||
* The prefix to use for ACF reference keys/hidden meta.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $reference_prefix = '_';
|
||||
|
||||
/**
|
||||
* Constructs the location.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
public function __construct() {
|
||||
$this->register();
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers the meta location with ACF, so it can be used by
|
||||
* various CRUD helper functions.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function register() {
|
||||
if ( empty( $this->location_type ) ) {
|
||||
return;
|
||||
}
|
||||
|
||||
$store = acf_get_store( 'acf-meta-locations' );
|
||||
|
||||
if ( ! $store ) {
|
||||
$store = acf_register_store( 'acf-meta-locations' );
|
||||
}
|
||||
|
||||
$store->set( $this->location_type, get_class( $this ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all ACF meta for the provided object ID.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get meta from.
|
||||
* @return array
|
||||
*/
|
||||
public function get_meta( $object_id = 0 ): array {
|
||||
$meta = array();
|
||||
$all_meta = get_metadata( $this->location_type, $object_id );
|
||||
|
||||
if ( $all_meta ) {
|
||||
foreach ( $all_meta as $key => $value ) {
|
||||
// If a reference exists for this value, add it to the meta array.
|
||||
if ( isset( $all_meta[ $this->reference_prefix . $key ] ) ) {
|
||||
$meta[ $key ] = $value[0];
|
||||
$meta[ $this->reference_prefix . $key ] = $all_meta[ $this->reference_prefix . $key ][0];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Unserialize results and return.
|
||||
return array_map( 'acf_maybe_unserialize', $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_value( $object_id = 0, array $field = array() ) {
|
||||
$meta = get_metadata( $this->location_type, $object_id, $field['name'] );
|
||||
return $meta[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference key for the provided field name.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get the reference key from.
|
||||
* @param string $field_name The name of the field to get the reference for.
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_reference( $object_id = 0, $field_name = '' ) {
|
||||
$reference = get_metadata( $this->location_type, $object_id, $this->reference_prefix . $field_name );
|
||||
return $reference[0] ?? null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object ID with the provided meta array.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $meta The metadata to save to the object.
|
||||
* @return void
|
||||
*/
|
||||
public function update_meta( $object_id = 0, array $meta = array() ) {
|
||||
// Slash data. WP expects all data to be slashed and will unslash it (fixes '\' character issues).
|
||||
$meta = wp_slash( $meta );
|
||||
|
||||
foreach ( $meta as $name => $value ) {
|
||||
update_metadata( $this->location_type, $object_id, $name, $value );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a field value in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @param mixed $value The metadata value.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_value( $object_id = 0, array $field = array(), $value = '' ) {
|
||||
return update_metadata( $this->location_type, $object_id, $field['name'], $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a reference key in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to update the reference for.
|
||||
* @param string $value The value of the reference key.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_reference( $object_id = 0, string $field_name = '', string $value = '' ) {
|
||||
return update_metadata( $this->location_type, $object_id, $this->reference_prefix . $field_name, $value );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_value( $object_id = 0, array $field = array() ): bool {
|
||||
return delete_metadata( $this->location_type, $object_id, $field['name'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a reference key from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to delete the reference from.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_reference( $object_id = 0, string $field_name = '' ): bool {
|
||||
return delete_metadata( $this->location_type, $object_id, $this->reference_prefix . $field_name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,151 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to options.
|
||||
*/
|
||||
class Option extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'option';
|
||||
|
||||
/**
|
||||
* Retrieves all ACF meta for the provided object ID.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get meta from.
|
||||
* @return array
|
||||
*/
|
||||
public function get_meta( $object_id = 0 ): array {
|
||||
$all_meta = acf_get_option_meta( $object_id );
|
||||
$meta = array();
|
||||
|
||||
foreach ( $all_meta as $key => $value ) {
|
||||
// If a reference exists for this value, add it to the meta array.
|
||||
if ( isset( $all_meta[ $this->reference_prefix . $key ] ) ) {
|
||||
$meta[ $key ] = $value[0];
|
||||
$meta[ $this->reference_prefix . $key ] = $all_meta[ $this->reference_prefix . $key ][0];
|
||||
}
|
||||
}
|
||||
|
||||
// Return results.
|
||||
return $meta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_value( $object_id = 0, array $field = array() ) {
|
||||
return get_option( $object_id . '_' . $field['name'], null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference key for the provided field name.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get the reference key from.
|
||||
* @param string $field_name The name of the field to get the reference for.
|
||||
* @return string|boolean
|
||||
*/
|
||||
public function get_reference( $object_id = '', $field_name = '' ) {
|
||||
return get_option( $this->reference_prefix . $object_id . '_' . $field_name, null );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object ID with the provided meta array.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $meta The metadata to save to the object.
|
||||
* @return void
|
||||
*/
|
||||
public function update_meta( $object_id = 0, array $meta = array() ) {
|
||||
$autoload = (bool) acf_get_setting( 'autoload' );
|
||||
|
||||
foreach ( $meta as $name => $value ) {
|
||||
$value = wp_unslash( $value );
|
||||
update_option( $object_id . '_' . $name, $value, $autoload );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a field value in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @param mixed $value The metadata value.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_value( $object_id = 0, array $field = array(), $value = '' ) {
|
||||
$value = wp_unslash( $value );
|
||||
$autoload = (bool) acf_get_setting( 'autoload' );
|
||||
|
||||
return update_option( $object_id . '_' . $field['name'], $value, $autoload );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a reference key in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to update the reference for.
|
||||
* @param string $value The value of the reference key.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_reference( $object_id = 0, string $field_name = '', string $value = '' ) {
|
||||
$autoload = (bool) acf_get_setting( 'autoload' );
|
||||
return update_option( $this->reference_prefix . $object_id . '_' . $field_name, $value, $autoload );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_value( $object_id = 0, array $field = array() ): bool {
|
||||
return delete_option( $object_id . '_' . $field['name'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a reference key from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to delete the reference from.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_reference( $object_id = 0, string $field_name = '' ): bool {
|
||||
return delete_option( $this->reference_prefix . $object_id . '_' . $field_name );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to standard post meta.
|
||||
*/
|
||||
class Post extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'post';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to term meta.
|
||||
*/
|
||||
class Term extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'term';
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Meta;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to user meta.
|
||||
*/
|
||||
class User extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'user';
|
||||
}
|
||||
+325
@@ -0,0 +1,325 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Pro\Fields\FlexibleContent;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Layout {
|
||||
|
||||
/**
|
||||
* The Flexible Content field the layout belongs to.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $field;
|
||||
|
||||
/**
|
||||
* The layout being rendered.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $layout;
|
||||
|
||||
/**
|
||||
* The order of the layout.
|
||||
*
|
||||
* @var integer|string
|
||||
*/
|
||||
private $order;
|
||||
|
||||
/**
|
||||
* The value of the layout.
|
||||
*
|
||||
* @var mixed
|
||||
*/
|
||||
private $value;
|
||||
|
||||
/**
|
||||
* The input prefix.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $prefix;
|
||||
|
||||
/**
|
||||
* If the layout is disabled.
|
||||
*
|
||||
* @var boolean
|
||||
*/
|
||||
private $disabled;
|
||||
|
||||
/**
|
||||
* If the layout has been renamed, the new name of the layout.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
private $renamed;
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @param array $field The Flexible Content field the layout belongs to.
|
||||
* @param array $layout The layout to render.
|
||||
* @param integer|string $order The order of the layout.
|
||||
* @param mixed $value The value of the layout.
|
||||
* @param boolean $disabled If the layout is disabled.
|
||||
* @param string $renamed If the layout has been renamed, the new name of the layout.
|
||||
*/
|
||||
public function __construct( $field, $layout, $order, $value, $disabled = false, $renamed = '' ) {
|
||||
$this->field = $field;
|
||||
$this->layout = $layout;
|
||||
$this->order = $order;
|
||||
$this->value = $value;
|
||||
$this->disabled = $disabled;
|
||||
$this->renamed = $renamed;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the layout.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
$id = 'row-' . $this->order;
|
||||
$class = 'layout';
|
||||
|
||||
if ( 'acfcloneindex' === $this->order ) {
|
||||
$id = 'acfcloneindex';
|
||||
$class .= ' acf-clone';
|
||||
}
|
||||
|
||||
$this->prefix = $this->field['name'] . '[' . $id . ']';
|
||||
|
||||
$div_attrs = array(
|
||||
'class' => $class,
|
||||
'data-id' => $id,
|
||||
'data-layout' => $this->layout['name'],
|
||||
'data-label' => $this->layout['label'],
|
||||
'data-min' => $this->layout['min'],
|
||||
'data-max' => $this->layout['max'],
|
||||
'data-enabled' => $this->disabled ? 0 : 1,
|
||||
'data-renamed' => empty( $this->renamed ) ? 0 : 1,
|
||||
);
|
||||
|
||||
echo '<div ' . acf_esc_attrs( $div_attrs ) . '>'; // Layout wrapper div.
|
||||
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'name' => $this->prefix . '[acf_fc_layout]',
|
||||
'value' => $this->layout['name'],
|
||||
)
|
||||
);
|
||||
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => 'acf-fc-layout-disabled',
|
||||
'name' => $this->prefix . '[acf_fc_layout_disabled]',
|
||||
'value' => $this->disabled ? 1 : 0,
|
||||
)
|
||||
);
|
||||
|
||||
acf_hidden_input(
|
||||
array(
|
||||
'class' => 'acf-fc-layout-custom-label',
|
||||
'name' => $this->prefix . '[acf_fc_layout_custom_label]',
|
||||
'value' => $this->renamed,
|
||||
)
|
||||
);
|
||||
|
||||
$this->action_buttons();
|
||||
|
||||
if ( ! empty( $this->layout['sub_fields'] ) ) {
|
||||
if ( 'table' === $this->layout['display'] ) {
|
||||
$this->render_as_table();
|
||||
} else {
|
||||
$this->render_as_div();
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>'; // End layout wrapper div.
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a layout as a table.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_as_table() {
|
||||
$sub_fields = $this->layout['sub_fields'];
|
||||
?>
|
||||
<table class="acf-table">
|
||||
<thead>
|
||||
<tr>
|
||||
<?php
|
||||
foreach ( $sub_fields as $sub_field ) {
|
||||
// Set prefix to generate correct "for" attribute on <label>.
|
||||
$sub_field['prefix'] = $this->prefix;
|
||||
|
||||
// Prepare field (allow sub fields to be removed).
|
||||
$sub_field = acf_prepare_field( $sub_field );
|
||||
if ( ! $sub_field ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$th_attrs = array(
|
||||
'class' => 'acf-th',
|
||||
'data-name' => $sub_field['_name'],
|
||||
'data-type' => $sub_field['type'],
|
||||
'data-key' => $sub_field['key'],
|
||||
);
|
||||
|
||||
if ( $sub_field['wrapper']['width'] ) {
|
||||
$th_attrs['data-width'] = $sub_field['wrapper']['width'];
|
||||
$th_attrs['style'] = 'width: ' . $sub_field['wrapper']['width'] . '%;';
|
||||
}
|
||||
|
||||
echo '<th ' . acf_esc_attrs( $th_attrs ) . '>';
|
||||
acf_render_field_label( $sub_field );
|
||||
acf_render_field_instructions( $sub_field );
|
||||
echo '</th>';
|
||||
}
|
||||
?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr><?php $this->sub_fields(); ?></tr>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders a layout as a div.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function render_as_div() {
|
||||
$class = 'acf-fields';
|
||||
|
||||
if ( 'row' === $this->layout['display'] ) {
|
||||
$class .= ' -left';
|
||||
}
|
||||
|
||||
echo '<div class="' . esc_attr( $class ) . '">';
|
||||
$this->sub_fields();
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the layout actions (Add, Duplicate, Rename).
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function action_buttons() {
|
||||
$title = $this->get_title();
|
||||
$order = is_numeric( $this->order ) ? $this->order + 1 : 0;
|
||||
?>
|
||||
<div class="acf-fc-layout-actions-wrap">
|
||||
<div class="acf-fc-layout-handle" title="<?php esc_attr_e( 'Drag to reorder', 'acf' ); ?>" data-name="collapse-layout">
|
||||
<span class="acf-fc-layout-order"><?php echo (int) $order; ?></span>
|
||||
<span class="acf-fc-layout-draggable-icon"></span>
|
||||
<span class="acf-fc-layout-title">
|
||||
<?php echo ! empty( $this->renamed ) ? esc_html( $this->renamed ) : $title; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped earlier in function. ?>
|
||||
</span>
|
||||
<span class="acf-fc-layout-original-title">
|
||||
(<?php echo $title; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped earlier in function. ?>)
|
||||
</span>
|
||||
<span class="acf-layout-disabled"><?php esc_html_e( 'Disabled', 'acf' ); ?></span>
|
||||
</div>
|
||||
<div class="acf-fc-layout-controls">
|
||||
<a class="acf-js-tooltip" href="#" data-name="add-layout" data-context="layout" title="<?php esc_attr( $this->field['button_label'] ); ?>"><span class="acf-icon -plus-alt "></span></a>
|
||||
<a class="acf-js-tooltip" href="#" data-name="duplicate-layout" title="<?php esc_attr_e( 'Duplicate', 'acf' ); ?>"><span class="acf-icon -duplicate-alt"></span></a>
|
||||
<a class="acf-js-tooltip" href="#" data-name="remove-layout" title="<?php esc_attr_e( 'Delete', 'acf' ); ?>"><span class="acf-icon -trash-alt"></span></a>
|
||||
<a class="acf-js-tooltip" aria-haspopup="menu" href="#" data-name="more-layout-actions" title="<?php esc_attr_e( 'More layout actions...', 'acf' ); ?>"><span class="acf-icon -more-actions"></span></a>
|
||||
<div class="acf-layout-collapse">
|
||||
<a class="acf-icon -collapse -clear" href="#" data-name="collapse-layout" aria-label="<?php esc_attr_e( 'Toggle layout', 'acf' ); ?>"></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the subfields for a layout.
|
||||
*
|
||||
* @since 6.5
|
||||
* @return void
|
||||
*/
|
||||
private function sub_fields() {
|
||||
foreach ( $this->layout['sub_fields'] as $sub_field ) {
|
||||
|
||||
// add value
|
||||
if ( isset( $this->value[ $sub_field['key'] ] ) ) {
|
||||
|
||||
// this is a normal value
|
||||
$sub_field['value'] = $this->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'] = $this->prefix;
|
||||
|
||||
// Render the input.
|
||||
$el = 'table' === $this->layout['display'] ? 'td' : 'div';
|
||||
acf_render_field_wrap( $sub_field, $el );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the filtered layout title.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
$rows = array();
|
||||
$rows[ $this->order ] = $this->value;
|
||||
|
||||
acf_add_loop(
|
||||
array(
|
||||
'selector' => $this->field['name'],
|
||||
'name' => $this->field['name'],
|
||||
'value' => $rows,
|
||||
'field' => $this->field,
|
||||
'i' => $this->order,
|
||||
'post_id' => 0,
|
||||
)
|
||||
);
|
||||
|
||||
// Make the title filterable.
|
||||
$title = esc_html( $this->layout['label'] );
|
||||
$title = apply_filters( 'acf/fields/flexible_content/layout_title', $title, $this->field, $this->layout, $this->order );
|
||||
$title = apply_filters( 'acf/fields/flexible_content/layout_title/name=' . $this->field['_name'], $title, $this->field, $this->layout, $this->order );
|
||||
$title = apply_filters( 'acf/fields/flexible_content/layout_title/key=' . $this->field['key'], $title, $this->field, $this->layout, $this->order );
|
||||
$title = acf_esc_html( $title );
|
||||
|
||||
acf_remove_loop();
|
||||
reset_rows(); // TODO: Make sure this is actually where this should go if needed at all.
|
||||
|
||||
return $title;
|
||||
}
|
||||
}
|
||||
+271
@@ -0,0 +1,271 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Pro\Fields\FlexibleContent;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
class Render {
|
||||
|
||||
/**
|
||||
* The main field array used to render the Flexible Content field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $field;
|
||||
|
||||
/**
|
||||
* An array of layouts used by the Flexible Content field.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $layouts;
|
||||
|
||||
/**
|
||||
* An array of meta for the layouts being rendered.
|
||||
*
|
||||
* @var array
|
||||
*/
|
||||
private $layout_meta;
|
||||
|
||||
/**
|
||||
* Constructs the class.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @param array $field The flexible content field being rendered.
|
||||
* @param array $layout_meta An array of meta for the layouts being rendered.
|
||||
* @return void
|
||||
*/
|
||||
public function __construct( $field, $layout_meta ) {
|
||||
$this->field = $field;
|
||||
$this->layout_meta = $layout_meta;
|
||||
$this->setup();
|
||||
}
|
||||
|
||||
/**
|
||||
* Prepares the field for rendering.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function setup() {
|
||||
$layouts = array();
|
||||
|
||||
if ( ! empty( $this->field['layouts'] ) ) {
|
||||
foreach ( $this->field['layouts'] as $layout ) {
|
||||
$layouts[ $layout['name'] ] = $layout;
|
||||
}
|
||||
}
|
||||
|
||||
$this->layouts = $layouts;
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the Flexible Content field.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function render() {
|
||||
$div_attrs = array(
|
||||
'class' => 'acf-flexible-content',
|
||||
'data-min' => $this->field['min'],
|
||||
'data-max' => $this->field['max'],
|
||||
'data-button-label' => $this->field['button_label'],
|
||||
);
|
||||
|
||||
if ( empty( $this->field['value'] ) ) {
|
||||
$div_attrs['class'] .= ' -empty';
|
||||
}
|
||||
|
||||
echo '<div ' . acf_esc_attrs( $div_attrs ) . '>'; // Main wrapper div.
|
||||
|
||||
acf_hidden_input( array( 'name' => $this->field['name'] ) );
|
||||
|
||||
$this->actions( 'top' );
|
||||
$this->no_value_message();
|
||||
$this->clones();
|
||||
$this->layouts();
|
||||
$this->actions( 'bottom' );
|
||||
$this->add_layout_menu();
|
||||
$this->more_layout_actions();
|
||||
|
||||
echo '</div>'; // End main wrapper div.
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the no value message.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function no_value_message() {
|
||||
// translators: %s the button label used for adding a new layout.
|
||||
$no_value_message = __( 'Click the "%s" button below to start creating your layout', 'acf' );
|
||||
$no_value_message = apply_filters( 'acf/fields/flexible_content/no_value_message', $no_value_message, $this->field );
|
||||
$no_value_message = sprintf( $no_value_message, $this->field['button_label'] );
|
||||
|
||||
echo '<div class="no-value-message">' . acf_esc_html( $no_value_message ) . '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the ACF clone indexes for the layouts.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function clones() {
|
||||
echo '<div class="clones">';
|
||||
|
||||
if ( ! empty( $this->layouts ) ) {
|
||||
foreach ( $this->layouts as $layout ) {
|
||||
$clone = new Layout( $this->field, $layout, 'acfcloneindex', array() );
|
||||
$clone->render();
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the layouts for a Flexible Content field.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function layouts() {
|
||||
echo '<div class="values">';
|
||||
|
||||
$disabled_layouts = ! empty( $this->layout_meta['disabled'] ) ? $this->layout_meta['disabled'] : array();
|
||||
$renamed_layouts = ! empty( $this->layout_meta['renamed'] ) ? $this->layout_meta['renamed'] : array();
|
||||
|
||||
if ( ! empty( $this->field['value'] ) ) {
|
||||
foreach ( $this->field['value'] as $order => $value ) {
|
||||
if ( ! is_array( $value ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( empty( $this->layouts[ $value['acf_fc_layout'] ] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$layout = new Layout(
|
||||
$this->field,
|
||||
$this->layouts[ $value['acf_fc_layout'] ],
|
||||
$order,
|
||||
$value,
|
||||
in_array( $order, $disabled_layouts, true ),
|
||||
! empty( $renamed_layouts[ $order ] ) ? $renamed_layouts[ $order ] : '',
|
||||
);
|
||||
|
||||
$layout->render();
|
||||
}
|
||||
}
|
||||
|
||||
echo '</div>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders top-level actions for the Flexible Content field.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @param string $which The location of the actions, either 'top' or 'bottom'.
|
||||
* @return void
|
||||
*/
|
||||
private function actions( string $which = '' ) {
|
||||
if ( 'top' === $which ) {
|
||||
?>
|
||||
<div class="acf-actions acf-fc-top-actions">
|
||||
<button class="acf-btn acf-btn-clear acf-fc-expand-all">
|
||||
<?php esc_html_e( 'Expand All', 'acf' ); ?>
|
||||
</button>
|
||||
<button class="acf-btn acf-btn-clear acf-fc-collapse-all">
|
||||
<?php esc_html_e( 'Collapse All', 'acf' ); ?>
|
||||
</button>
|
||||
<span class="acf-separator"></span>
|
||||
<a class="acf-button button button-primary" href="#" data-name="add-layout" data-context="top-actions">
|
||||
<i class="acf-icon -plus small"></i>
|
||||
<?php echo acf_esc_html( $this->field['button_label'] ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
} else {
|
||||
?>
|
||||
<div class="acf-actions">
|
||||
<a class="acf-button button button-primary" href="#" data-name="add-layout" data-context="bottom-actions">
|
||||
<i class="acf-icon -plus small"></i>
|
||||
<?php echo acf_esc_html( $this->field['button_label'] ); ?>
|
||||
</a>
|
||||
</div>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the dropdown menu to add more layouts.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function add_layout_menu() {
|
||||
echo '<script type="text-html" class="tmpl-popup"><ul>';
|
||||
foreach ( $this->layouts as $layout ) {
|
||||
$safe_label = acf_esc_html( $layout['label'] );
|
||||
$atts = array(
|
||||
'href' => '#',
|
||||
'data-layout' => $layout['name'],
|
||||
'data-min' => $layout['min'],
|
||||
'data-max' => $layout['max'],
|
||||
'title' => $safe_label,
|
||||
);
|
||||
printf( '<li><a %s>%s</a></li>', acf_esc_attrs( $atts ), $safe_label ); //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- escaped above.
|
||||
}
|
||||
echo '</ul></script>';
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the dropdown menu for additional layout actions.
|
||||
*
|
||||
* @since 6.5
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
private function more_layout_actions() {
|
||||
?>
|
||||
<script type="text-html" class="tmpl-more-layout-actions">
|
||||
<ul role="menu" tabindex="-1">
|
||||
<li>
|
||||
<a class="acf-rename-layout" data-action="rename-layout" href="#" role="menuitem">
|
||||
<?php esc_html_e( 'Rename', 'acf' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
<li>
|
||||
<a class="acf-toggle-layout disable" data-action="toggle-layout" href="#" role="menuitem">
|
||||
<?php esc_html_e( 'Disable', 'acf' ); ?>
|
||||
</a>
|
||||
<a class="acf-toggle-layout enable" data-action="toggle-layout" href="#" role="menuitem">
|
||||
<?php esc_html_e( 'Enable', 'acf' ); ?>
|
||||
</a>
|
||||
</li>
|
||||
</ul>
|
||||
</script>
|
||||
<?php
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,216 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Pro\Forms;
|
||||
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* Adds ACF metaboxes to the new WooCommerce order screen.
|
||||
*/
|
||||
class WC_Order {
|
||||
|
||||
/**
|
||||
* Constructs the ACF_Form_WC_Order class.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'load-woocommerce_page_wc-orders', array( $this, 'initialize' ) );
|
||||
add_action( 'load-woocommerce_page_wc-orders--shop_subscription', array( $this, 'initialize' ) );
|
||||
add_action( 'woocommerce_update_order', array( $this, 'save_order' ), 10, 1 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Enqueues ACF scripts on the WooCommerce order page and
|
||||
* registers actions specific to that page.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function initialize() {
|
||||
acf_enqueue_scripts( array( 'uploader' => true ) );
|
||||
add_action( 'add_meta_boxes', array( $this, 'add_meta_boxes' ), 10, 2 );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds ACF metaboxes to the WooCommerce Order pages.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param string $post_type The current post type.
|
||||
* @param \WP_Post $post The WP_Post object or the WC_Order object.
|
||||
* @return void
|
||||
*/
|
||||
public function add_meta_boxes( $post_type, $post ) {
|
||||
// Storage for localized postboxes.
|
||||
$postboxes = array();
|
||||
|
||||
$location = 'shop_order';
|
||||
$order = ( $post instanceof \WP_Post ) ? wc_get_order( $post->ID ) : $post;
|
||||
$screen = $this->is_hpos_enabled() ? wc_get_page_screen_id( 'shop-order' ) : 'shop_order';
|
||||
|
||||
if ( $order instanceof \WC_Subscription ) {
|
||||
$location = 'shop_subscription';
|
||||
$screen = function_exists( 'wcs_get_page_screen_id' ) ? wcs_get_page_screen_id( 'shop_subscription' ) : 'shop_subscription';
|
||||
}
|
||||
|
||||
// Get field groups for this screen.
|
||||
$field_groups = acf_get_field_groups(
|
||||
array(
|
||||
'post_id' => $order->get_id(),
|
||||
'post_type' => $location,
|
||||
)
|
||||
);
|
||||
|
||||
// Loop over field groups.
|
||||
if ( $field_groups ) {
|
||||
foreach ( $field_groups as $field_group ) {
|
||||
$id = "acf-{$field_group['key']}"; // acf-group_123
|
||||
$context = $field_group['position']; // normal, side, acf_after_title
|
||||
$priority = 'core'; // high, core, default, low
|
||||
|
||||
// Allow field groups assigned to after title to still be rendered.
|
||||
if ( 'acf_after_title' === $context ) {
|
||||
$context = 'normal';
|
||||
}
|
||||
|
||||
/**
|
||||
* Filters the metabox priority.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param string $priority The metabox priority (high, core, default, low).
|
||||
* @param array $field_group The field group array.
|
||||
*/
|
||||
$priority = apply_filters( 'acf/input/meta_box_priority', $priority, $field_group );
|
||||
|
||||
// Localize data
|
||||
$postboxes[] = array(
|
||||
'id' => $id,
|
||||
'key' => $field_group['key'],
|
||||
'style' => $field_group['style'],
|
||||
'label' => $field_group['label_placement'],
|
||||
'edit' => acf_get_field_group_edit_link( $field_group['ID'] ),
|
||||
);
|
||||
|
||||
// Add the meta box.
|
||||
add_meta_box(
|
||||
$id,
|
||||
acf_esc_html( acf_get_field_group_title( $field_group ) ),
|
||||
array( $this, 'render_meta_box' ),
|
||||
$screen,
|
||||
$context,
|
||||
$priority,
|
||||
array( 'field_group' => $field_group )
|
||||
);
|
||||
}
|
||||
|
||||
// Localize postboxes.
|
||||
acf_localize_data(
|
||||
array(
|
||||
'postboxes' => $postboxes,
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
// Removes the WordPress core "Custom Fields" meta box.
|
||||
if ( acf_get_setting( 'remove_wp_meta_box' ) ) {
|
||||
remove_meta_box( 'order_custom', $screen, 'normal' );
|
||||
}
|
||||
|
||||
// Add hidden input fields.
|
||||
add_action( 'order_edit_form_top', array( $this, 'order_edit_form_top' ) );
|
||||
|
||||
/**
|
||||
* Fires after metaboxes have been added.
|
||||
*
|
||||
* @date 13/12/18
|
||||
* @since 5.8.0
|
||||
*
|
||||
* @param string $post_type The post type.
|
||||
* @param \WP_Post $post The post being edited.
|
||||
* @param array $field_groups The field groups added.
|
||||
*/
|
||||
do_action( 'acf/add_meta_boxes', $post_type, $post, $field_groups );
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders hidden fields.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param \WC_Order $order The WooCommerce order object.
|
||||
* @return void
|
||||
*/
|
||||
public function order_edit_form_top( $order ) {
|
||||
// Render post data.
|
||||
acf_form_data(
|
||||
array(
|
||||
'screen' => 'post',
|
||||
'post_id' => 'woo_order_' . $order->get_id(),
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Renders the ACF metabox HTML.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param \WP_Post|\WC_Order $post_or_order Can be a standard \WP_Post object or the \WC_Order object.
|
||||
* @param array $metabox The add_meta_box() args.
|
||||
* @return void
|
||||
*/
|
||||
public function render_meta_box( $post_or_order, $metabox ) {
|
||||
$order = ( $post_or_order instanceof \WP_Post ) ? wc_get_order( $post_or_order->ID ) : $post_or_order;
|
||||
$field_group = $metabox['args']['field_group'];
|
||||
|
||||
// Render fields.
|
||||
$fields = acf_get_fields( $field_group );
|
||||
acf_render_fields( $fields, 'woo_order_' . $order->get_id(), 'div', $field_group['instruction_placement'] );
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if WooCommerce HPOS is enabled.
|
||||
*
|
||||
* @since 6.4.2
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function is_hpos_enabled(): bool {
|
||||
if ( class_exists( '\Automattic\WooCommerce\Utilities\OrderUtil' ) && OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves ACF fields to the current order.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer $order_id The order ID.
|
||||
* @return void
|
||||
*/
|
||||
public function save_order( int $order_id ) {
|
||||
// Bail if not using HPOS to prevent a double-save.
|
||||
if ( ! $this->is_hpos_enabled() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Remove the action to prevent an infinite loop via $order->save().
|
||||
remove_action( 'woocommerce_update_order', array( $this, 'save_order' ), 10 );
|
||||
acf_save_post( 'woo_order_' . $order_id );
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,239 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Pro\Meta;
|
||||
|
||||
use ACF\Meta\MetaLocation;
|
||||
use Automattic\WooCommerce\Utilities\OrderUtil;
|
||||
|
||||
/**
|
||||
* A class to add support for saving to WooCommerce order meta.
|
||||
*/
|
||||
class WooOrder extends MetaLocation {
|
||||
|
||||
/**
|
||||
* The unique slug/name of the meta location.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $location_type = 'woo_order';
|
||||
|
||||
/**
|
||||
* Constructs the location.
|
||||
*
|
||||
* @since 6.4
|
||||
*/
|
||||
public function __construct() {
|
||||
add_filter( 'acf/decode_post_id', array( $this, 'decode_woo_order_id' ), 10, 2 );
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks numerical post IDs to see if they belong to a WC order.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param array $decoded The decoded post ID props.
|
||||
* @param integer|string $post_id The original post ID.
|
||||
* @return array
|
||||
*/
|
||||
public function decode_woo_order_id( $decoded, $post_id ) {
|
||||
// Bail if not a standard numeric post ID.
|
||||
if ( ! is_numeric( $post_id ) || empty( $decoded['type'] ) || 'post' !== $decoded['type'] ) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
// Bail if HPOS isn't enabled (traditional ACF meta methods work otherwise).
|
||||
if ( ! method_exists( OrderUtil::class, 'custom_orders_table_usage_is_enabled' ) ||
|
||||
! OrderUtil::custom_orders_table_usage_is_enabled() ) {
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
if ( 'shop_order_placehold' === get_post_type( $post_id ) ) {
|
||||
$decoded['type'] = 'woo_order';
|
||||
}
|
||||
|
||||
return $decoded;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves all ACF meta for the provided object ID.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get meta from.
|
||||
* @return array
|
||||
*/
|
||||
public function get_meta( $object_id = 0 ): array {
|
||||
$meta = array();
|
||||
$order = wc_get_order( $object_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
return $meta;
|
||||
}
|
||||
|
||||
$all_meta = $order->get_meta_data();
|
||||
$field_names = wp_list_pluck( $all_meta, 'key' );
|
||||
$field_values = wp_list_pluck( $all_meta, 'value' );
|
||||
|
||||
foreach ( $field_names as $key => $field_name ) {
|
||||
$reference = $this->reference_prefix . $field_name;
|
||||
$reference_key = array_search( $reference, $field_names, true );
|
||||
|
||||
if ( false !== $reference_key ) {
|
||||
$meta[ $field_name ] = $field_values[ $key ];
|
||||
$meta[ $reference ] = $field_values[ $reference_key ];
|
||||
}
|
||||
}
|
||||
|
||||
// Unserialize results and return.
|
||||
return array_map( 'acf_maybe_unserialize', $meta );
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return mixed
|
||||
*/
|
||||
public function get_value( $object_id = 0, array $field = array() ) {
|
||||
$order = wc_get_order( $object_id );
|
||||
|
||||
if ( ! $order || ! $order->meta_exists( $field['name'] ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $order->get_meta( $field['name'], true, 'edit' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets a reference key for the provided field name.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object to get the reference key from.
|
||||
* @param string $field_name The name of the field to get the reference for.
|
||||
* @return string|null
|
||||
*/
|
||||
public function get_reference( $object_id = 0, $field_name = '' ) {
|
||||
$order = wc_get_order( $object_id );
|
||||
$key = $this->reference_prefix . $field_name;
|
||||
|
||||
if ( ! $order || ! $order->meta_exists( $key ) ) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $order->get_meta( $key, true, 'edit' );
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates an object ID with the provided meta array.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $meta The metadata to save to the object.
|
||||
* @return void
|
||||
*/
|
||||
public function update_meta( $object_id = 0, array $meta = array() ) {
|
||||
$order = wc_get_order( $object_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ( $meta as $name => $value ) {
|
||||
$value = wp_unslash( $value );
|
||||
$order->update_meta_data( $name, $value );
|
||||
}
|
||||
|
||||
$order->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a field value in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @param mixed $value The metadata value.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_value( $object_id = 0, array $field = array(), $value = '' ) {
|
||||
$order = wc_get_order( $object_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$value = wp_unslash( $value );
|
||||
|
||||
$order->update_meta_data( $this->reference_prefix . $field['name'], $field['key'] );
|
||||
$order->update_meta_data( $field['name'], $value );
|
||||
|
||||
return $order->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates a reference key in the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to update the reference for.
|
||||
* @param string $value The value of the reference key.
|
||||
* @return integer|boolean
|
||||
*/
|
||||
public function update_reference( $object_id = 0, string $field_name = '', string $value = '' ) {
|
||||
// Updated in update_value().
|
||||
return true;
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a field value from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param array $field The field array.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_value( $object_id = 0, array $field = array() ): bool {
|
||||
$order = wc_get_order( $object_id );
|
||||
|
||||
if ( ! $order ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$order->delete_meta_data( $this->reference_prefix . $field['name'] );
|
||||
$order->delete_meta_data( $field['name'] );
|
||||
|
||||
return $order->save();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes a reference key from the database.
|
||||
*
|
||||
* @since 6.4
|
||||
*
|
||||
* @param integer|string $object_id The ID of the object the metadata is for.
|
||||
* @param string $field_name The name of the field to delete the reference from.
|
||||
* @return boolean
|
||||
*/
|
||||
public function delete_reference( $object_id = 0, string $field_name = '' ): bool {
|
||||
// Deleted in delete_value().
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,797 @@
|
||||
<?php
|
||||
/**
|
||||
* @package ACF
|
||||
* @author WP Engine
|
||||
*
|
||||
* © 2025 Advanced Custom Fields (ACF®). All rights reserved.
|
||||
* "ACF" is a trademark of WP Engine.
|
||||
* Licensed under the GNU General Public License v2 or later.
|
||||
* https://www.gnu.org/licenses/gpl-2.0.html
|
||||
*/
|
||||
|
||||
namespace ACF\Site_Health;
|
||||
|
||||
// Exit if accessed directly.
|
||||
defined( 'ABSPATH' ) || exit;
|
||||
|
||||
/**
|
||||
* The ACF Site Health class responsible for populating ACF debug information in WordPress Site Health.
|
||||
*/
|
||||
class Site_Health {
|
||||
/**
|
||||
* The option name used to store site health data.
|
||||
*
|
||||
* @var string
|
||||
*/
|
||||
public string $option_name = 'acf_site_health';
|
||||
|
||||
/**
|
||||
* Constructs the ACF_Site_Health class.
|
||||
*
|
||||
* @since 6.3
|
||||
*/
|
||||
public function __construct() {
|
||||
add_action( 'debug_information', array( $this, 'render_tab_content' ) );
|
||||
add_action( 'acf_update_site_health_data', array( $this, 'update_site_health_data' ) );
|
||||
|
||||
if ( ! wp_next_scheduled( 'acf_update_site_health_data' ) ) {
|
||||
wp_schedule_event( time(), 'weekly', 'acf_update_site_health_data' );
|
||||
}
|
||||
|
||||
// ACF events.
|
||||
add_action( 'acf/first_activated', array( $this, 'add_activation_event' ) );
|
||||
add_action( 'acf/activated_pro', array( $this, 'add_activation_event' ) );
|
||||
add_filter( 'acf/pre_update_field_group', array( $this, 'pre_update_acf_internal_cpt' ) );
|
||||
add_filter( 'acf/pre_update_post_type', array( $this, 'pre_update_acf_internal_cpt' ) );
|
||||
add_filter( 'acf/pre_update_taxonomy', array( $this, 'pre_update_acf_internal_cpt' ) );
|
||||
add_filter( 'acf/pre_update_ui_options_page', array( $this, 'pre_update_acf_internal_cpt' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the stored site health information.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_site_health(): array {
|
||||
$site_health = get_option( $this->option_name, '' );
|
||||
|
||||
if ( is_string( $site_health ) ) {
|
||||
$site_health = json_decode( $site_health, true );
|
||||
}
|
||||
|
||||
return is_array( $site_health ) ? $site_health : array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Updates the site health information.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $data An array of site health information to update.
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_site_health( array $data = array() ): bool {
|
||||
return update_option( $this->option_name, wp_json_encode( $data ), false );
|
||||
}
|
||||
|
||||
/**
|
||||
* Stores debug data in the ACF site health option.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $data Data to update with (optional).
|
||||
* @return boolean
|
||||
*/
|
||||
public function update_site_health_data( array $data = array() ): bool {
|
||||
if ( wp_doing_cron() ) {
|
||||
// Bootstrap wp-admin, as WP_Cron doesn't do this for us.
|
||||
require_once trailingslashit( ABSPATH ) . 'wp-admin/includes/admin.php';
|
||||
}
|
||||
|
||||
$site_health = $this->get_site_health();
|
||||
$values = ! empty( $data ) ? $data : $this->get_site_health_values();
|
||||
$updated = array();
|
||||
|
||||
if ( ! empty( $values ) ) {
|
||||
foreach ( $values as $key => $value ) {
|
||||
$updated[ $key ] = $value['debug'] ?? $value['value'];
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $site_health as $key => $value ) {
|
||||
if ( 'event_' === substr( $key, 0, 6 ) ) {
|
||||
$updated[ $key ] = $value;
|
||||
}
|
||||
}
|
||||
|
||||
$updated['last_updated'] = time();
|
||||
|
||||
return $this->update_site_health( $updated );
|
||||
}
|
||||
|
||||
/**
|
||||
* Pushes an event to the ACF site health option.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param string $event_name The name of the event to push.
|
||||
* @return boolean
|
||||
*/
|
||||
public function add_site_health_event( string $event_name = '' ): bool {
|
||||
$site_health = $this->get_site_health();
|
||||
|
||||
// Allow using action/filter hooks to set events.
|
||||
if ( empty( $event_name ) ) {
|
||||
$current_filter = current_filter();
|
||||
|
||||
if ( strpos( $current_filter, 'acf/' ) !== false ) {
|
||||
$event_name = str_replace( 'acf/', '', $current_filter );
|
||||
}
|
||||
}
|
||||
|
||||
// Bail if this event was already stored.
|
||||
if ( empty( $event_name ) || ! empty( $site_health[ 'event_' . $event_name ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$time = time();
|
||||
|
||||
$site_health[ 'event_' . $event_name ] = $time;
|
||||
$site_health['last_updated'] = $time;
|
||||
|
||||
return $this->update_site_health( $site_health );
|
||||
}
|
||||
|
||||
/**
|
||||
* Logs activation events for free/pro.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return boolean
|
||||
*/
|
||||
public function add_activation_event() {
|
||||
$event_name = 'first_activated';
|
||||
|
||||
if ( acf_is_pro() ) {
|
||||
$event_name = 'first_activated_pro';
|
||||
|
||||
if ( 'acf/first_activated' !== current_filter() ) {
|
||||
$site_health = $this->get_site_health();
|
||||
|
||||
/**
|
||||
* We already have an event for when pro was first activated,
|
||||
* so we don't need to log an additional event here.
|
||||
*/
|
||||
if ( ! empty( $site_health[ 'event_' . $event_name ] ) ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$event_name = 'activated_pro';
|
||||
}
|
||||
}
|
||||
|
||||
return $this->add_site_health_event( $event_name );
|
||||
}
|
||||
|
||||
/**
|
||||
* Adds events when ACF internal post types are created.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $post The post about to be updated.
|
||||
* @return array
|
||||
*/
|
||||
public function pre_update_acf_internal_cpt( array $post = array() ): array {
|
||||
if ( empty( $post['key'] ) ) {
|
||||
return $post;
|
||||
}
|
||||
|
||||
$post_type = acf_determine_internal_post_type( $post['key'] );
|
||||
|
||||
if ( $post_type ) {
|
||||
$posts = acf_get_internal_post_type_posts( $post_type );
|
||||
|
||||
if ( empty( $posts ) ) {
|
||||
$post_type = str_replace(
|
||||
array(
|
||||
'acf-',
|
||||
'-',
|
||||
),
|
||||
array(
|
||||
'',
|
||||
'_',
|
||||
),
|
||||
$post_type
|
||||
);
|
||||
$this->add_site_health_event( 'first_created_' . $post_type );
|
||||
}
|
||||
}
|
||||
|
||||
return $post;
|
||||
}
|
||||
|
||||
/**
|
||||
* Appends the ACF section to the "Info" tab of the WordPress Site Health screen.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @param array $debug_info The current debug info for site health.
|
||||
* @return array The debug info appended with the ACF section.
|
||||
*/
|
||||
public function render_tab_content( array $debug_info ): array {
|
||||
$data = $this->get_site_health_values();
|
||||
|
||||
$this->update_site_health_data( $data );
|
||||
|
||||
// Unset values we don't want to display yet.
|
||||
$fields_to_unset = array(
|
||||
'wp_version',
|
||||
'mysql_version',
|
||||
'is_multisite',
|
||||
'active_theme',
|
||||
'parent_theme',
|
||||
'active_plugins',
|
||||
'number_of_fields_by_type',
|
||||
'number_of_third_party_fields_by_type',
|
||||
'field_groups_with_single_block_rule',
|
||||
'field_groups_with_multiple_block_rules',
|
||||
'field_groups_with_blocks_and_other_rules',
|
||||
'all_location_rules',
|
||||
);
|
||||
|
||||
foreach ( $fields_to_unset as $field ) {
|
||||
if ( isset( $data[ $field ] ) ) {
|
||||
unset( $data[ $field ] );
|
||||
}
|
||||
}
|
||||
|
||||
foreach ( $data as $key => $value ) {
|
||||
if ( 'event_' === substr( $key, 0, 6 ) ) {
|
||||
unset( $data[ $key ] );
|
||||
}
|
||||
}
|
||||
|
||||
$debug_info['acf'] = array(
|
||||
'label' => __( 'ACF', 'acf' ),
|
||||
'description' => __( 'This section contains debug information about your ACF configuration which can be useful to provide to support.', 'acf' ),
|
||||
'fields' => $data,
|
||||
);
|
||||
|
||||
return $debug_info;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the values for all data in the ACF site health section.
|
||||
*
|
||||
* @since 6.3
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function get_site_health_values(): array {
|
||||
global $wpdb;
|
||||
|
||||
$fields = array();
|
||||
$is_pro = acf_is_pro();
|
||||
$license = $is_pro ? acf_pro_get_license() : array();
|
||||
$license_status = $is_pro ? acf_pro_get_license_status() : array();
|
||||
$field_groups = acf_get_field_groups();
|
||||
$post_types = acf_get_post_types();
|
||||
$taxonomies = acf_get_taxonomies();
|
||||
|
||||
$yes = __( 'Yes', 'acf' );
|
||||
$no = __( 'No', 'acf' );
|
||||
|
||||
$fields['version'] = array(
|
||||
'label' => __( 'Plugin Version', 'acf' ),
|
||||
'value' => defined( 'ACF_VERSION' ) ? ACF_VERSION : '',
|
||||
);
|
||||
|
||||
$fields['plugin_type'] = array(
|
||||
'label' => __( 'Plugin Type', 'acf' ),
|
||||
'value' => $is_pro ? __( 'PRO', 'acf' ) : __( 'Free', 'acf' ),
|
||||
'debug' => $is_pro ? 'PRO' : 'Free',
|
||||
);
|
||||
|
||||
$fields['update_source'] = array(
|
||||
'label' => __( 'Update Source', 'acf' ),
|
||||
'value' => apply_filters( 'acf/site_health/update_source', __( 'wordpress.org', 'acf' ) ),
|
||||
);
|
||||
|
||||
if ( $is_pro ) {
|
||||
$fields['activated'] = array(
|
||||
'label' => __( 'License Activated', 'acf' ),
|
||||
'value' => ! empty( $license ) ? $yes : $no,
|
||||
'debug' => ! empty( $license ),
|
||||
);
|
||||
|
||||
$fields['activated_url'] = array(
|
||||
'label' => __( 'Licensed URL', 'acf' ),
|
||||
'value' => ! empty( $license['url'] ) ? $license['url'] : '',
|
||||
);
|
||||
|
||||
$fields['license_type'] = array(
|
||||
'label' => __( 'License Type', 'acf' ),
|
||||
'value' => $license_status['name'],
|
||||
);
|
||||
|
||||
$fields['license_status'] = array(
|
||||
'label' => __( 'License Status', 'acf' ),
|
||||
'value' => $license_status['status'],
|
||||
);
|
||||
|
||||
$expiry = ! empty( $license_status['expiry'] ) ? $license_status['expiry'] : '';
|
||||
$format = get_option( 'date_format', 'F j, Y' );
|
||||
|
||||
$fields['subscription_expires'] = array(
|
||||
'label' => __( 'Subscription Expiry Date', 'acf' ),
|
||||
'value' => is_numeric( $expiry ) ? date_i18n( $format, $expiry ) : '',
|
||||
'debug' => $expiry,
|
||||
);
|
||||
}
|
||||
|
||||
$fields['wp_version'] = array(
|
||||
'label' => __( 'WordPress Version', 'acf' ),
|
||||
'value' => get_bloginfo( 'version' ),
|
||||
);
|
||||
|
||||
$fields['mysql_version'] = array(
|
||||
'label' => __( 'MySQL Version', 'acf' ),
|
||||
'value' => $wpdb->db_server_info(),
|
||||
);
|
||||
|
||||
$fields['is_multisite'] = array(
|
||||
'label' => __( 'Is Multisite', 'acf' ),
|
||||
'value' => is_multisite() ? __( 'Yes', 'acf' ) : __( 'No', 'acf' ),
|
||||
'debug' => is_multisite(),
|
||||
);
|
||||
|
||||
$active_theme = wp_get_theme();
|
||||
$parent_theme = $active_theme->parent();
|
||||
|
||||
$fields['active_theme'] = array(
|
||||
'label' => __( 'Active Theme', 'acf' ),
|
||||
'value' => array(
|
||||
'name' => $active_theme->get( 'Name' ),
|
||||
'version' => $active_theme->get( 'Version' ),
|
||||
'theme_uri' => $active_theme->get( 'ThemeURI' ),
|
||||
'stylesheet' => $active_theme->get( 'Stylesheet' ),
|
||||
),
|
||||
);
|
||||
|
||||
if ( $parent_theme ) {
|
||||
$fields['parent_theme'] = array(
|
||||
'label' => __( 'Parent Theme', 'acf' ),
|
||||
'value' => array(
|
||||
'name' => $parent_theme->get( 'Name' ),
|
||||
'version' => $parent_theme->get( 'Version' ),
|
||||
'theme_uri' => $parent_theme->get( 'ThemeURI' ),
|
||||
'stylesheet' => $parent_theme->get( 'Stylesheet' ),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
$active_plugins = array();
|
||||
$plugins = get_plugins();
|
||||
|
||||
foreach ( $plugins as $plugin_path => $plugin ) {
|
||||
if ( ! is_plugin_active( $plugin_path ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$active_plugins[ $plugin_path ] = array(
|
||||
'name' => $plugin['Name'],
|
||||
'version' => $plugin['Version'],
|
||||
'plugin_uri' => empty( $plugin['PluginURI'] ) ? '' : $plugin['PluginURI'],
|
||||
);
|
||||
}
|
||||
|
||||
$fields['active_plugins'] = array(
|
||||
'label' => __( 'Active Plugins', 'acf' ),
|
||||
'value' => $active_plugins,
|
||||
);
|
||||
|
||||
$ui_field_groups = array_filter(
|
||||
$field_groups,
|
||||
function ( $field_group ) {
|
||||
return empty( $field_group['local'] );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['ui_field_groups'] = array(
|
||||
'label' => __( 'Registered Field Groups (UI)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $ui_field_groups ) ),
|
||||
);
|
||||
|
||||
$php_field_groups = array_filter(
|
||||
$field_groups,
|
||||
function ( $field_group ) {
|
||||
return ! empty( $field_group['local'] ) && 'PHP' === $field_group['local'];
|
||||
}
|
||||
);
|
||||
|
||||
$fields['php_field_groups'] = array(
|
||||
'label' => __( 'Registered Field Groups (PHP)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $php_field_groups ) ),
|
||||
);
|
||||
|
||||
$json_field_groups = array_filter(
|
||||
$field_groups,
|
||||
function ( $field_group ) {
|
||||
return ! empty( $field_group['local'] ) && 'json' === $field_group['local'];
|
||||
}
|
||||
);
|
||||
|
||||
$fields['json_field_groups'] = array(
|
||||
'label' => __( 'Registered Field Groups (JSON)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $json_field_groups ) ),
|
||||
);
|
||||
|
||||
$rest_field_groups = array_filter(
|
||||
$field_groups,
|
||||
function ( $field_group ) {
|
||||
return ! empty( $field_group['show_in_rest'] );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['rest_field_groups'] = array(
|
||||
'label' => __( 'Field Groups Enabled for REST API', 'acf' ),
|
||||
'value' => number_format_i18n( count( $rest_field_groups ) ),
|
||||
);
|
||||
|
||||
$graphql_field_groups = array_filter(
|
||||
$field_groups,
|
||||
function ( $field_group ) {
|
||||
return ! empty( $field_group['show_in_graphql'] );
|
||||
}
|
||||
);
|
||||
|
||||
if ( is_plugin_active( 'wpgraphql-acf/wpgraphql-acf.php' ) ) {
|
||||
$fields['graphql_field_groups'] = array(
|
||||
'label' => __( 'Field Groups Enabled for GraphQL', 'acf' ),
|
||||
'value' => number_format_i18n( count( $graphql_field_groups ) ),
|
||||
);
|
||||
}
|
||||
|
||||
$all_fields = array();
|
||||
$object_types = array();
|
||||
$all_rules = array();
|
||||
|
||||
foreach ( $field_groups as $field_group ) {
|
||||
$all_fields = array_merge( $all_fields, acf_get_fields( $field_group ) );
|
||||
|
||||
foreach ( $field_group['location'] as $rules ) {
|
||||
foreach ( $rules as $rule ) {
|
||||
if ( empty( $rule['param'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$operator = ! empty( $rule['operator'] ) ? $rule['operator'] : '';
|
||||
$value = ! empty( $rule['value'] ) ? $rule['value'] : '';
|
||||
$all_rules[] = $rule['param'] . $operator . $value;
|
||||
|
||||
if ( ! $is_pro ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$location = acf_get_location_type( $rule['param'] );
|
||||
if ( ! $location ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$location_type = $location->get_object_type( $rule );
|
||||
$object_types[ $field_group['key'] ][] = $location_type;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$fields['all_location_rules'] = array(
|
||||
'label' => __( 'All Location Rules', 'acf' ),
|
||||
'value' => array_values( array_unique( $all_rules ) ),
|
||||
);
|
||||
|
||||
if ( $is_pro ) {
|
||||
$field_groups_with_single_block_rule = 0;
|
||||
$field_groups_with_multiple_block_rules = 0;
|
||||
$field_groups_with_blocks_and_other_rules = 0;
|
||||
|
||||
foreach ( $object_types as $types ) {
|
||||
$num_types = array_count_values( $types );
|
||||
|
||||
// Bail if no block location rules.
|
||||
if ( empty( $num_types['block'] ) ) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( count( $num_types ) === 1 ) {
|
||||
// Field group is only assigned to blocks.
|
||||
if ( $num_types['block'] === 1 ) {
|
||||
++$field_groups_with_single_block_rule;
|
||||
} else {
|
||||
++$field_groups_with_multiple_block_rules;
|
||||
}
|
||||
} else {
|
||||
// Field group is assigned to blocks & other stuff.
|
||||
++$field_groups_with_blocks_and_other_rules;
|
||||
}
|
||||
}
|
||||
|
||||
$fields['field_groups_with_single_block_rule'] = array(
|
||||
'label' => __( 'Number of Field Groups with a Single Block Location', 'acf' ),
|
||||
'value' => number_format_i18n( $field_groups_with_single_block_rule ),
|
||||
);
|
||||
|
||||
$fields['field_groups_with_multiple_block_rules'] = array(
|
||||
'label' => __( 'Number of Field Groups with Multiple Block Locations', 'acf' ),
|
||||
'value' => number_format_i18n( $field_groups_with_multiple_block_rules ),
|
||||
);
|
||||
|
||||
$fields['field_groups_with_blocks_and_other_rules'] = array(
|
||||
'label' => __( 'Number of Field Groups with Blocks and Other Locations', 'acf' ),
|
||||
'value' => number_format_i18n( $field_groups_with_blocks_and_other_rules ),
|
||||
);
|
||||
}
|
||||
|
||||
$fields_by_type = array();
|
||||
$third_party_fields_by_type = array();
|
||||
$core_field_types = array_keys( acf_get_field_types() );
|
||||
|
||||
foreach ( $all_fields as $field ) {
|
||||
if ( in_array( $field['type'], $core_field_types, true ) ) {
|
||||
if ( ! isset( $fields_by_type[ $field['type'] ] ) ) {
|
||||
$fields_by_type[ $field['type'] ] = 0;
|
||||
}
|
||||
|
||||
++$fields_by_type[ $field['type'] ];
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! isset( $third_party_fields_by_type[ $field['type'] ] ) ) {
|
||||
$third_party_fields_by_type[ $field['type'] ] = 0;
|
||||
}
|
||||
|
||||
++$third_party_fields_by_type[ $field['type'] ];
|
||||
}
|
||||
|
||||
$fields['number_of_fields_by_type'] = array(
|
||||
'label' => __( 'Number of Fields by Field Type', 'acf' ),
|
||||
'value' => $fields_by_type,
|
||||
);
|
||||
|
||||
$fields['number_of_third_party_fields_by_type'] = array(
|
||||
'label' => __( 'Number of Third Party Fields by Field Type', 'acf' ),
|
||||
'value' => $third_party_fields_by_type,
|
||||
);
|
||||
|
||||
$enable_post_types = acf_get_setting( 'enable_post_types' );
|
||||
|
||||
$fields['post_types_enabled'] = array(
|
||||
'label' => __( 'Post Types and Taxonomies Enabled', 'acf' ),
|
||||
'value' => $enable_post_types ? $yes : $no,
|
||||
'debug' => $enable_post_types,
|
||||
);
|
||||
|
||||
$ui_post_types = array_filter(
|
||||
$post_types,
|
||||
function ( $post_type ) {
|
||||
return empty( $post_type['local'] );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['ui_post_types'] = array(
|
||||
'label' => __( 'Registered Post Types (UI)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $ui_post_types ) ),
|
||||
);
|
||||
|
||||
$json_post_types = array_filter(
|
||||
$post_types,
|
||||
function ( $post_type ) {
|
||||
return ! empty( $post_type['local'] ) && 'json' === $post_type['local'];
|
||||
}
|
||||
);
|
||||
|
||||
$fields['json_post_types'] = array(
|
||||
'label' => __( 'Registered Post Types (JSON)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $json_post_types ) ),
|
||||
);
|
||||
|
||||
$ui_taxonomies = array_filter(
|
||||
$taxonomies,
|
||||
function ( $taxonomy ) {
|
||||
return empty( $taxonomy['local'] );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['ui_taxonomies'] = array(
|
||||
'label' => __( 'Registered Taxonomies (UI)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $ui_taxonomies ) ),
|
||||
);
|
||||
|
||||
$json_taxonomies = array_filter(
|
||||
$taxonomies,
|
||||
function ( $taxonomy ) {
|
||||
return ! empty( $taxonomy['local'] ) && 'json' === $taxonomy['local'];
|
||||
}
|
||||
);
|
||||
|
||||
$fields['json_taxonomies'] = array(
|
||||
'label' => __( 'Registered Taxonomies (JSON)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $json_taxonomies ) ),
|
||||
);
|
||||
|
||||
if ( $is_pro ) {
|
||||
$enable_options_pages_ui = acf_get_setting( 'enable_options_pages_ui' );
|
||||
|
||||
$fields['ui_options_pages_enabled'] = array(
|
||||
'label' => __( 'Options Pages UI Enabled', 'acf' ),
|
||||
'value' => $enable_options_pages_ui ? $yes : $no,
|
||||
'debug' => $enable_options_pages_ui,
|
||||
);
|
||||
|
||||
$options_pages = acf_get_options_pages();
|
||||
$ui_options_pages = array();
|
||||
|
||||
if ( empty( $options_pages ) || ! is_array( $options_pages ) ) {
|
||||
$options_pages = array();
|
||||
}
|
||||
|
||||
if ( $enable_options_pages_ui ) {
|
||||
$ui_options_pages = acf_get_ui_options_pages();
|
||||
|
||||
$ui_options_pages_in_ui = array_filter(
|
||||
$ui_options_pages,
|
||||
function ( $ui_options_page ) {
|
||||
return empty( $ui_options_page['local'] );
|
||||
}
|
||||
);
|
||||
|
||||
$json_options_pages = array_filter(
|
||||
$ui_options_pages,
|
||||
function ( $ui_options_page ) {
|
||||
return ! empty( $ui_options_page['local'] );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['ui_options_pages'] = array(
|
||||
'label' => __( 'Registered Options Pages (UI)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $ui_options_pages_in_ui ) ),
|
||||
);
|
||||
|
||||
$fields['json_options_pages'] = array(
|
||||
'label' => __( 'Registered Options Pages (JSON)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $json_options_pages ) ),
|
||||
);
|
||||
}
|
||||
|
||||
$ui_options_page_slugs = array_column( $ui_options_pages, 'menu_slug' );
|
||||
$php_options_pages = array_filter(
|
||||
$options_pages,
|
||||
function ( $options_page ) use ( $ui_options_page_slugs ) {
|
||||
return ! in_array( $options_page['menu_slug'], $ui_options_page_slugs, true );
|
||||
}
|
||||
);
|
||||
|
||||
$fields['php_options_pages'] = array(
|
||||
'label' => __( 'Registered Options Pages (PHP)', 'acf' ),
|
||||
'value' => number_format_i18n( count( $php_options_pages ) ),
|
||||
);
|
||||
}
|
||||
|
||||
$rest_api_format = acf_get_setting( 'rest_api_format' );
|
||||
|
||||
$fields['rest_api_format'] = array(
|
||||
'label' => __( 'REST API Format', 'acf' ),
|
||||
'value' => 'standard' === $rest_api_format ? __( 'Standard', 'acf' ) : __( 'Light', 'acf' ),
|
||||
'debug' => $rest_api_format,
|
||||
);
|
||||
|
||||
if ( $is_pro ) {
|
||||
$fields['registered_acf_blocks'] = array(
|
||||
'label' => __( 'Registered ACF Blocks', 'acf' ),
|
||||
'value' => number_format_i18n( acf_pro_get_registered_block_count() ),
|
||||
);
|
||||
|
||||
$blocks = acf_get_block_types();
|
||||
$block_api_versions = array();
|
||||
$acf_block_versions = array();
|
||||
$blocks_using_post_meta = 0;
|
||||
|
||||
foreach ( $blocks as $block ) {
|
||||
if ( ! isset( $block_api_versions[ 'v' . $block['api_version'] ] ) ) {
|
||||
$block_api_versions[ 'v' . $block['api_version'] ] = 0;
|
||||
}
|
||||
|
||||
if ( ! isset( $acf_block_versions[ 'v' . $block['acf_block_version'] ] ) ) {
|
||||
$acf_block_versions[ 'v' . $block['acf_block_version'] ] = 0;
|
||||
}
|
||||
|
||||
if ( ! empty( $block['use_post_meta'] ) ) {
|
||||
++$blocks_using_post_meta;
|
||||
}
|
||||
|
||||
++$block_api_versions[ 'v' . $block['api_version'] ];
|
||||
++$acf_block_versions[ 'v' . $block['acf_block_version'] ];
|
||||
}
|
||||
|
||||
$fields['blocks_per_api_version'] = array(
|
||||
'label' => __( 'Blocks Per API Version', 'acf' ),
|
||||
'value' => $block_api_versions,
|
||||
);
|
||||
|
||||
$fields['blocks_per_acf_block_version'] = array(
|
||||
'label' => __( 'Blocks Per ACF Block Version', 'acf' ),
|
||||
'value' => $acf_block_versions,
|
||||
);
|
||||
|
||||
$fields['blocks_using_post_meta'] = array(
|
||||
'label' => __( 'Blocks Using Post Meta', 'acf' ),
|
||||
'value' => number_format_i18n( $blocks_using_post_meta ),
|
||||
);
|
||||
|
||||
$preload_blocks = acf_get_setting( 'preload_blocks' );
|
||||
|
||||
$fields['preload_blocks'] = array(
|
||||
'label' => __( 'Block Preloading Enabled', 'acf' ),
|
||||
'value' => ! empty( $preload_blocks ) ? $yes : $no,
|
||||
'debug' => $preload_blocks,
|
||||
);
|
||||
}
|
||||
|
||||
$show_admin = acf_get_setting( 'show_admin' );
|
||||
|
||||
$fields['admin_ui_enabled'] = array(
|
||||
'label' => __( 'Admin UI Enabled', 'acf' ),
|
||||
'value' => $show_admin ? $yes : $no,
|
||||
'debug' => $show_admin,
|
||||
);
|
||||
|
||||
$field_type_modal_enabled = apply_filters( 'acf/field_group/enable_field_browser', true );
|
||||
|
||||
$fields['field_type-modal_enabled'] = array(
|
||||
'label' => __( 'Field Type Modal Enabled', 'acf' ),
|
||||
'value' => ! empty( $field_type_modal_enabled ) ? $yes : $no,
|
||||
'debug' => $field_type_modal_enabled,
|
||||
);
|
||||
|
||||
$field_settings_tabs_enabled = apply_filters( 'acf/field_group/disable_field_settings_tabs', false );
|
||||
|
||||
$fields['field_settings_tabs_enabled'] = array(
|
||||
'label' => __( 'Field Settings Tabs Enabled', 'acf' ),
|
||||
'value' => empty( $field_settings_tabs_enabled ) ? $yes : $no,
|
||||
'debug' => $field_settings_tabs_enabled,
|
||||
);
|
||||
|
||||
$shortcode_enabled = acf_get_setting( 'enable_shortcode' );
|
||||
|
||||
$fields['shortcode_enabled'] = array(
|
||||
'label' => __( 'Shortcode Enabled', 'acf' ),
|
||||
'value' => ! empty( $shortcode_enabled ) ? $yes : $no,
|
||||
'debug' => $shortcode_enabled,
|
||||
);
|
||||
|
||||
$fields['registered_acf_forms'] = array(
|
||||
'label' => __( 'Registered ACF Forms', 'acf' ),
|
||||
'value' => number_format_i18n( count( acf_get_forms() ) ),
|
||||
);
|
||||
|
||||
$local_json = acf_get_instance( 'ACF_Local_JSON' );
|
||||
$save_paths = $local_json->get_save_paths();
|
||||
$load_paths = $local_json->get_load_paths();
|
||||
|
||||
$fields['json_save_paths'] = array(
|
||||
'label' => __( 'JSON Save Paths', 'acf' ),
|
||||
'value' => number_format_i18n( count( $save_paths ) ),
|
||||
'debug' => count( $save_paths ),
|
||||
);
|
||||
|
||||
$fields['json_load_paths'] = array(
|
||||
'label' => __( 'JSON Load Paths', 'acf' ),
|
||||
'value' => number_format_i18n( count( $load_paths ) ),
|
||||
'debug' => count( $load_paths ),
|
||||
);
|
||||
|
||||
return $fields;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user