* @copyright Copyright (c) 2023, Phi Phan
*/
namespace MetaFieldBlock;
// Exit if accessed directly.
defined( 'ABSPATH' ) || exit;
if ( ! class_exists( ACFFields::class ) ) :
/**
* The ACFFields class.
*/
class ACFFields extends CoreComponent {
/**
* Run main hooks
*
* @return void
*/
public function run() {
// Don't format fields for rest.
add_filter( 'acf/settings/rest_api_format', [ $this, 'api_format' ] );
// Format special fields for rest.
add_filter( 'acf/rest/format_value_for_rest', [ $this, 'format_value_for_rest' ], 10, 4 );
}
/**
* Don't format fields for rest by default
*
* @return string
*/
public function api_format() {
return 'light';
}
/**
* Filter the formatted value for a given field.
*
* @param mixed $value_formatted The formatted value.
* @param string|int $post_id The post ID of the current object.
* @param array $field The field array.
* @param mixed $raw_value The raw/unformatted value.
* @param string $format The format applied to the field value.
*
* @return mixed
*/
public function format_value_for_rest( $value_formatted, $post_id, $field, $raw_value ) {
$simple_value_formatted = $this->render_field( $value_formatted, $post_id, $field, $raw_value );
$rest_formatted_value = [
'simple_value_formatted' => $simple_value_formatted,
'value_formatted' => $value_formatted,
'value' => $raw_value,
'field' => $field,
];
return apply_filters(
'meta_field_block_acf_field_format_value_for_rest',
$rest_formatted_value,
$post_id
);
}
/**
* Get field value for front end by object id and field name.
*
* @param string $field_name
* @param int/string $object_id
* @param string $object_type
*
* @return mixed
*/
public function get_field_value( $field_name, $object_id, $object_type = '' ) {
// Get the id with object type.
if ( $object_type && ! in_array( $object_type, [ 'post', 'term', 'user' ], true ) ) {
$object_id_with_type = $object_type;
} else {
$object_id_with_type = in_array( $object_type, [ 'term', 'user' ], true ) ? $object_type . '_' . $object_id : $object_id;
}
$field_object = get_field_object( $field_name, $object_id_with_type, false, true );
if ( ! $field_object ) {
// Field key cache.
$cache_key = 'field_key_' . $field_name;
// Get field key.
$field_key = wp_cache_get( $cache_key, 'mfb' );
if ( $field_key === false ) {
$field_key = $this->get_field_key( $field_name, $object_id_with_type );
// Update cache.
if ( ! empty( $field_key ) ) {
wp_cache_set( $cache_key, $field_key, 'mfb' );
}
}
if ( $field_key ) {
$field_object = get_field_object( $field_key, $object_id_with_type, false, true );
}
if ( ! $field_object ) {
// Get a dummy field.
$field_object = acf_get_valid_field(
array(
'name' => $field_name,
'key' => '',
'type' => '',
)
);
// Get value for field.
$field_object['value'] = acf_get_value( $object_id_with_type, $field_object );
}
}
// Field with raw value.
$field = $field_object;
// Get raw value first.
$raw_value = $field_object['value'] ?? '';
// Format it.
$field_object['value'] = acf_format_value( $raw_value, $object_id_with_type, $field_object );
return [
'value' => $this->render_field( $field_object['value'] ?? '', $object_id, $field_object, $raw_value, $object_type ),
'field' => $field,
];
}
/**
* Get field key by name.
*
* @param string $field_name
* @param int/string $object_id
*
* @return boolean|string
*/
private function get_field_key( $field_name, $object_id ) {
$fields = $this->get_all_fields();
$filtered_fields = array_filter(
$fields,
function ( $field_value ) use ( $field_name ) {
return $field_name === $field_value['name'] ?? '';
}
);
switch ( count( $filtered_fields ) ) {
case 0:
return false;
case 1:
return current( $filtered_fields )['key'] ?? '';
}
// More than 1 items.
$field_groups_ids = array();
$field_groups = acf_get_field_groups(
array(
'post_id' => $object_id,
)
);
foreach ( $field_groups as $field_group ) {
$field_groups_ids[] = $field_group['ID'];
}
// Check if field is part of one of the field groups, return the first one.
foreach ( $filtered_fields as $field ) {
if ( in_array( $field['parent'] ?? 0, $field_groups_ids, true ) ) {
return $field['key'] ?? '';
}
}
return false;
}
/**
* Get all ACF fields
*
* @return array
*/
private function get_all_fields() {
// Try cache.
$cache_key = 'get_all_acf_fields';
$fields = wp_cache_get( $cache_key, 'mfb' );
if ( $fields === false ) {
// Query posts.
$posts = get_posts(
array(
'posts_per_page' => -1,
'post_type' => 'acf-field',
'orderby' => 'menu_order',
'order' => 'ASC',
'suppress_filters' => true, // DO NOT allow third-party to modify the query.
'cache_results' => true,
'update_post_meta_cache' => false,
'update_post_term_cache' => false,
'post_status' => array( 'publish' ),
)
);
// Loop over posts and populate array of fields.
$fields = array();
foreach ( $posts as $post ) {
// Unserialize post_content.
$field = (array) maybe_unserialize( $post->post_content );
// Update attributes.
$field['ID'] = $post->ID;
$field['key'] = $post->post_name;
$field['label'] = $post->post_title;
$field['name'] = $post->post_excerpt;
$field['menu_order'] = $post->menu_order;
$field['parent'] = $post->post_parent;
$fields[] = $field;
}
// Update cache.
if ( ! empty( $fields ) ) {
wp_cache_set( $cache_key, $fields, 'mfb' );
}
}
// Return fields.
return $fields;
}
/**
* Render the field
*
* @param object $value
* @param mixed $object_id
* @param array $field
* @param mixed $raw_value
* @param string $object_type
* @return void
*/
public function render_field( $value, $object_id, $field, $raw_value, $object_type = '' ) {
// Get the value for rendering.
$field_value = $this->render_acf_field( $value, $object_id, $field, $raw_value );
return apply_filters( 'meta_field_block_get_acf_field', $field_value, $object_id, $field, $raw_value, $object_type );
}
/**
* Display value for ACF fields
*
* @param mixed $value
* @param int $post_id
* @param array $field
* @param array $raw_value
* @return string
*/
public function render_acf_field( $value, $post_id, $field, $raw_value ) {
$field_value = $value;
$field_type = $field['type'] ?? '';
if ( $field_type ) { // Not flexible item.
$format_func = 'format_field_' . $field_type;
if ( is_callable( [ $this, $format_func ] ) ) {
$field_value = $this->{$format_func}( $value, $field, $post_id, $raw_value );
} else {
if ( in_array( $field_type, [ 'date_picker', 'time_picker', 'date_time_picker' ], true ) ) {
$field_value = $this->format_field_datetime( $value, $field, $post_id, $raw_value );
}
}
$field_value = is_array( $field_value ) || is_object( $field_value ) ? '' . __( 'This data type is not supported! Please contact the author for help.', 'display-a-meta-field-as-block' ) . '
' : $field_value;
}
return $field_value;
}
/**
* Format image field type
*
* @param mixed $value
* @param array $field
* @param int $post_id
* @param mixed $raw_value
* @return string
*/
public function format_field_image( $value, $field, $post_id, $raw_value ) {
$field_value = $value;
if ( $value ) {
if ( is_numeric( $value ) || is_array( $value ) ) {
$image_id = is_numeric( $value ) ? $value : ( is_array( $value ) ? ( $value['ID'] ?? 0 ) : 0 );
} else {
$image_id = $raw_value;
}
$image_size = $field['preview_size'] ?? 'full';
if ( $image_id ) {
$field_value = wp_get_attachment_image( $image_id, $image_size );
}
}
return $field_value;
}
/**
* Format link field type
*
* @param mixed $value
* @param array $field
* @param int $post_id
* @param mixed $raw_value
* @return string
*/
public function format_field_link( $value, $field, $post_id, $raw_value ) {
$field_value = $value;
if ( $value ) {
if ( ! is_array( $value ) ) {
$value = $raw_value;
}
if ( is_array( $value ) ) {
$value = wp_parse_args(
$value,
[
'title' => '',
'url' => '',
'target' => '',
]
);
if ( empty( $value['url'] ) ) {
$field_value = '';
} else {
$value['title'] = ! empty( $value['title'] ) ? $value['title'] : $value['url'];
$rel = '_blank' === $value['target'] ? ' rel="noreferrer noopener"' : '';
$field_value = sprintf( '%2$s', $value['url'], $value['title'], $value['target'], $rel );
}
}
}
return $field_value;
}
/**
* Format page_link field type
*
* @param mixed $value
* @param array $field
* @param int $post_id
* @param mixed $raw_value
* @return string
*/
public function format_field_page_link( $value, $field, $post_id, $raw_value ) {
$field_value = $value;
$value = ! is_array( $raw_value ) ? [ $raw_value ] : $raw_value;
$value_markup = array_filter(
array_map(
function ( $item ) {
if ( is_numeric( $item ) ) {
return $this->get_post_link( $item );
} elseif ( $item ) {
return sprintf( '%1$s', $item );
}
return '';
},
$value
)
);
if ( count( $value_markup ) === 0 ) {
$field_value = '';
} else {
if ( count( $value_markup ) > 1 ) {
$field_value = '