* @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 = ''; } else { $field_value = $value_markup[0]; } } return $field_value; } /** * Format post_object field type * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_post_object( $value, $field, $post_id, $raw_value ) { $field_value = $value; $post_array = ! is_array( $value ) ? [ $value ] : $value; $post_array_markup = array_filter( array_map( function ( $post ) { return $this->get_post_link( $post ); }, $post_array ) ); if ( count( $post_array_markup ) === 0 ) { $field_value = ''; } else { if ( count( $post_array_markup ) > 1 ) { $field_value = ''; } else { $field_value = $post_array_markup[0]; } } return $field_value; } /** * Format relationship field type * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_relationship( $value, $field, $post_id, $raw_value ) { $field_value = $value; $post_array = ! is_array( $value ) ? [ $value ] : $value; $post_array_markup = array_filter( array_map( function ( $post ) { return $this->get_post_link( $post ); }, $post_array ) ); $field_value = count( $post_array_markup ) > 0 ? '' : ''; return $field_value; } /** * Format taxonomy field type * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_taxonomy( $value, $field, $post_id, $raw_value ) { $field_value = $value; $term_array = ! is_array( $value ) ? [ $value ] : $value; $term_array_markup = array_filter( array_map( function ( $term ) { if ( $term ) { return sprintf( '%2$s', get_term_link( $term ), get_term( $term )->name ); } else { return ''; } }, $term_array ) ); if ( count( $term_array_markup ) === 0 ) { $field_value = ''; } else { if ( count( $term_array_markup ) > 1 ) { $field_value = ''; } else { $field_value = $term_array_markup[0]; } } return $field_value; } /** * Format user field type * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_user( $value, $field, $post_id, $raw_value ) { $field_value = $value; $user_array = []; if ( is_array( $value ) ) { if ( isset( $value['display_name'] ) ) { // Return format as array and only 1 item. $user_array = [ $value ]; } else { $user_array = $value; } } else { $user_array = [ $value ]; } $user_array_markup = array_filter( array_map( function ( $user ) { $user_link = ''; $user_id = 0; $user_display_name = ''; if ( is_object( $user ) ) { $user_id = $user->ID; $user_display_name = $user->display_name ?? ''; } elseif ( is_numeric( $user ) ) { $user_object = get_userdata( $user ); if ( $user_object ) { $user_id = $user_object->ID; $user_display_name = $user_object->display_name ?? ''; } } elseif ( is_array( $user ) ) { $user_id = $user['ID'] ?? 0; $user_display_name = $user['display_name'] ?? ''; } if ( $user_id && $user_display_name ) { return sprintf( '%2$s', get_author_posts_url( $user_id ), $user_display_name ); } return ''; }, is_array( $user_array ) ? $user_array : [] ) ); if ( count( $user_array_markup ) === 0 ) { $field_value = ''; } else { if ( count( $user_array_markup ) > 1 ) { $field_value = ''; } else { $field_value = $user_array_markup[0]; } } return $field_value; } /** * Render a post as link * * @param int|WP_Post $post * @return string */ private function get_post_link( $post ) { if ( $post ) { $url = esc_url( get_permalink( $post ) ); return sprintf( '%2$s', $url, esc_html( get_the_title( $post ) ) ); } else { return ''; } } /** * Format datetime fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return mixed */ public function format_field_datetime( $value, $field, $post_id, $raw_value ) { $field_value = $value; if ( $value ) { $field_type = $field['type'] ?? ''; $rest_format = ''; $return_format = ''; if ( 'date_picker' === $field_type ) { $rest_format = 'Ymd'; $return_format = $field['return_format'] ?? ''; } elseif ( 'time_picker' === $field_type ) { $rest_format = 'H:i:s'; $return_format = $field['return_format'] ?? ''; } elseif ( 'date_time_picker' === $field_type ) { $rest_format = 'Y-m-d H:i:s'; $return_format = $field['return_format'] ?? ''; } if ( $rest_format && $return_format ) { $date = \DateTime::createFromFormat( $rest_format, $value ); if ( $date ) { $field_value = $date->format( $return_format ); } } } return $field_value; } /** * Format true_false fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_true_false( $value, $field, $post_id, $raw_value ) { $field_value = $value; $on_text = $field['ui_on_text'] ?? ''; $off_text = $field['ui_off_text'] ?? ''; if ( empty( $on_text ) && empty( $off_text ) ) { $on_text = _x( 'Yes', 'The display text for the "true" value of the true_false ACF field type', 'display-a-meta-field-as-block' ); $off_text = _x( 'No', 'The display text for the "false" value of the true_false ACF field type', 'display-a-meta-field-as-block' ); } if ( $value ) { $field_value = apply_filters( 'meta_field_block_acf_field_true_false_on_text', $on_text, $field, $value, $post_id ); } else { $field_value = apply_filters( 'meta_field_block_acf_field_true_false_off_text', $off_text, $field, $value, $post_id ); } return $field_value; } /** * Format checkbox fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_checkbox( $value, $field, $post_id, $raw_value ) { $field_value = $value; // Allow customizing the separator. $separator = apply_filters( 'meta_field_block_acf_field_choice_item_separator', ', ', $value, $field, $post_id ); if ( $value ) { if ( is_array( $value ) ) { $refine_value = array_filter( array_map( function ( $item ) { $return_value = ''; if ( $item ) { // Return format as both if ( is_array( $item ) ) { $return_value = $item['value'] ?? '' ? $item['value'] : ''; } else { $return_value = $item; } } return $return_value; }, $value ) ); if ( $refine_value ) { $field_value = '' . implode( '' . $separator . '', $refine_value ) . ''; } } } else { $field_value = ''; } return $field_value; } /** * Format radio fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_radio( $value, $field, $post_id, $raw_value ) { $field_value = $value; if ( $value ) { if ( is_array( $value ) ) { $field_value = $value['value'] ?? ''; } } else { $field_value = ''; } return $field_value; } /** * Format button group fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_button_group( $value, $field, $post_id, $raw_value ) { return $this->format_field_radio( $value, $field, $post_id, $raw_value ); } /** * Format select fields * * @param mixed $value * @param array $field * @param int $post_id * @param mixed $raw_value * @return string */ public function format_field_select( $value, $field, $post_id, $raw_value ) { $field_value = $value; // Allow customizing the separator. $separator = apply_filters( 'meta_field_block_acf_field_choice_item_separator', ', ', $value, $field, $post_id ); $value_array = []; if ( is_array( $value ) ) { // Single value but the return format is both. if ( isset( $value['value'] ) ) { // Return format as array and only 1 item. $value_array = [ $value ]; } else { $value_array = $value; } } else { $value_array = [ $value ]; } if ( $value_array ) { $refine_value = array_filter( array_map( function ( $item ) { $return_value = ''; if ( $item ) { // Return format as both if ( is_array( $item ) ) { $return_value = $item['value'] ?? '' ? $item['value'] : ''; } else { $return_value = $item; } } return $return_value; }, $value_array ) ); if ( $refine_value ) { $field_value = '' . implode( '' . $separator . '', $refine_value ) . ''; } } else { $field_value = ''; } return $field_value; } } endif;