extract_acf_html( $post );
if ( ! empty( trim( wp_strip_all_tags( $acf ) ) ) ) {
$parts[] = $acf;
}
$parts = array_values( array_filter( array_unique( $parts ) ) );
return implode( "\n\n
\n\n", $parts );
}
/**
* Extract generic content-like HTML from ACF values.
*
* @param \WP_Post $post Post object.
*
* @return string
*/
protected function extract_acf_html( \WP_Post $post ) {
if ( ! function_exists( 'get_fields' ) ) {
return '';
}
$values = get_fields( $post->ID );
if ( ! is_array( $values ) || empty( $values ) ) {
return '';
}
$parts = $this->flatten_values_to_html( $values );
return implode( "\n\n", $parts );
}
/**
* Flatten nested values into content HTML.
*
* @param array $values Value tree.
* @param int $depth Current depth.
*
* @return array
*/
protected function flatten_values_to_html( array $values, int $depth = 0 ) {
if ( $depth > 6 || $this->is_form_data_structure( $values ) ) {
return [];
}
$parts = [];
foreach ( $values as $key => $value ) {
if ( is_string( $key ) ) {
if ( str_starts_with( $key, '_' ) || $this->is_config_field_name( $key ) ) {
continue;
}
}
if ( is_string( $value ) ) {
$value = trim( $value );
if ( '' === $value || $this->is_config_value( $value ) || $this->looks_like_source_artifact( $value ) ) {
continue;
}
$clean = wp_strip_all_tags( $value );
if ( strlen( $clean ) < 4 ) {
continue;
}
$parts[] = wp_strip_all_tags( $value ) !== $value
? $value
: '' . esc_html( $value ) . '
';
continue;
}
if ( is_array( $value ) ) {
if ( isset( $value['url'] ) && is_string( $value['url'] ) ) {
if ( $this->is_image_array( $value ) ) {
$alt = ! empty( $value['alt'] ) ? $value['alt'] : '';
$parts[] = '
';
} else {
$title = ! empty( $value['title'] ) ? $value['title'] : $value['url'];
$parts[] = '' . esc_html( $title ) . '
';
}
continue;
}
$parts = array_merge( $parts, $this->flatten_values_to_html( $value, $depth + 1 ) );
}
}
return $parts;
}
/**
* Determine whether an array looks like form configuration.
*
* @param array $data Candidate array.
*
* @return bool
*/
protected function is_form_data_structure( array $data ) {
$keys = [ 'fields', 'notifications', 'confirmations', 'form_id', 'button', '_wpcf7', '_wpcf7_unit_tag' ];
$hits = 0;
foreach ( $keys as $key ) {
if ( array_key_exists( $key, $data ) ) {
++$hits;
}
}
return $hits >= 2;
}
/**
* Determine whether a field name is layout/configuration rather than content.
*
* @param string $name Field name.
*
* @return bool
*/
protected function is_config_field_name( string $name ) {
$name = strtolower( $name );
$patterns = [ 'background', 'alignment', 'layout', 'color', 'colour', 'theme', 'style', 'variant', 'spacing', 'padding', 'margin', 'width', 'height', 'visibility', 'animation', 'transition', 'class', 'id', 'anchor' ];
foreach ( $patterns as $pattern ) {
if ( false !== strpos( $name, $pattern ) ) {
return true;
}
}
return false;
}
/**
* Determine whether a string looks like config/UI data rather than content.
*
* @param string $value Candidate string.
*
* @return bool
*/
protected function is_config_value( string $value ) {
$lower = strtolower( trim( $value ) );
if ( '' === $lower || ' ' === $lower ) {
return true;
}
if ( preg_match( '/^(left|right|center|top|bottom|dark|light|small|medium|large|yes|no|true|false|primary|secondary)$/', $lower ) ) {
return true;
}
if ( preg_match( '/^#[a-f0-9]{3,8}$/i', $value ) === 1 ) {
return true;
}
return $this->is_machine_token( $lower );
}
/**
* Determine whether a string looks like unresolved source text rather than content.
*
* @param string $value Candidate string.
*
* @return bool
*/
protected function looks_like_source_artifact( string $value ) {
if ( preg_match( '//i', $value ) ) {
return true;
}
if ( preg_match( '/["\'](?:className|layout|metadata|anchor|align|fontSize|backgroundColor|textColor|style)["\']\s*:/i', $value ) ) {
return true;
}
return preg_match( '/^@(?:extends|section|yield|include|php|while|foreach|if)\b/i', ltrim( $value ) ) === 1;
}
/**
* Determine whether a string looks like a machine token rather than content.
*
* @param string $value Candidate value.
*
* @return bool
*/
protected function is_machine_token( string $value ) {
if ( strlen( $value ) < 5 || strlen( $value ) > 48 ) {
return false;
}
if ( preg_match( '/\s/', $value ) || preg_match( '/[A-Z]/', $value ) ) {
return false;
}
if ( false === strpos( $value, '-' ) && false === strpos( $value, '_' ) ) {
return false;
}
return preg_match( '/^[a-z0-9_-]+$/', $value ) === 1;
}
/**
* Determine whether an associative array represents an image.
*
* @param array $value Value array.
*
* @return bool
*/
protected function is_image_array( array $value ) {
if ( isset( $value['mime_type'] ) || isset( $value['sizes'] ) ) {
return true;
}
if ( isset( $value['width'] ) && isset( $value['height'] ) ) {
return true;
}
if ( isset( $value['url'] ) && is_string( $value['url'] ) ) {
return preg_match( '/\.(jpe?g|png|gif|webp|svg|bmp|ico|avif)(\?.*)?$/i', $value['url'] ) === 1;
}
return false;
}
}