label for the given post type — text-like and image * fields only by default (the kinds our template variable and OG * fallback can meaningfully resolve). Pass `$types` to narrow this to a * different subset (e.g. Pro's content allowlist wants prose-only: * text/textarea/wysiwyg, not email/url/number/image) without every * caller re-walking ACF's own field-group API itself. * * @param string[]|null $types * * @return array */ public static function field_names( string $post_type, ?array $types = null ): array { if ( ! self::is_active() || ! function_exists( 'acf_get_fields' ) ) { return array(); } $usable_types = $types ?? array( 'text', 'textarea', 'wysiwyg', 'email', 'url', 'number', 'image' ); $fields = array(); foreach ( (array) acf_get_field_groups( array( 'post_type' => $post_type ) ) as $group ) { foreach ( (array) acf_get_fields( $group ) as $field ) { if ( ! is_array( $field ) ) { continue; } $name = (string) ( $field['name'] ?? '' ); $type = (string) ( $field['type'] ?? '' ); if ( '' !== $name && in_array( $type, $usable_types, true ) ) { $fields[ $name ] = (string) ( $field['label'] ?? $name ); } } } return $fields; } /** * Repeater fields for the given post type, each with its own * sub-fields — a repeater's rows aren't scalar (each is * `array`), so this is deliberately a * separate method from `field_names()` rather than an extra entry * in its `$usable_types` list; mixing the two shapes into one flat * `field => label` map would break every existing scalar caller. * Used by Pro's ACF-repeater → FAQPage/HowTo mapping (M30). * * @return array}> */ public static function repeater_fields( string $post_type ): array { if ( ! self::is_active() || ! function_exists( 'acf_get_fields' ) ) { return array(); } $repeaters = array(); foreach ( (array) acf_get_field_groups( array( 'post_type' => $post_type ) ) as $group ) { foreach ( (array) acf_get_fields( $group ) as $field ) { if ( ! is_array( $field ) || 'repeater' !== ( $field['type'] ?? '' ) ) { continue; } $name = (string) ( $field['name'] ?? '' ); if ( '' === $name ) { continue; } $sub_fields = array(); foreach ( (array) ( $field['sub_fields'] ?? array() ) as $sub_field ) { if ( ! is_array( $sub_field ) ) { continue; } $sub_name = (string) ( $sub_field['name'] ?? '' ); if ( '' !== $sub_name ) { $sub_fields[ $sub_name ] = (string) ( $sub_field['label'] ?? $sub_name ); } } $repeaters[ $name ] = array( 'label' => (string) ( $field['label'] ?? $name ), 'sub_fields' => $sub_fields, ); } } return $repeaters; } }