questions( $post ), $post ); } public function build( \WP_Post $post ): array { $data = array( '@type' => 'FAQPage', '@id' => SchemaIds::faq_page( $post ), 'mainEntity' => $this->questions( $post ), ); /** * Filters the FAQPage schema node. * * @param array $data * @param \WP_Post $post */ return (array) apply_filters( 'acez_seo_faq_page', $data, $post ); } /** * @return array> */ private function questions( \WP_Post $post ): array { $blocks = parse_blocks( (string) $post->post_content ); $questions = array(); foreach ( $this->flatten_blocks( $blocks ) as $block ) { if ( 'core/details' !== ( $block['blockName'] ?? '' ) ) { continue; } $question = isset( $block['attrs']['summary'] ) ? wp_strip_all_tags( (string) $block['attrs']['summary'] ) : ''; $answer = $this->answer_text( $block ); if ( '' === $question || '' === $answer ) { continue; } $questions[] = array( '@type' => 'Question', 'name' => $question, 'acceptedAnswer' => array( '@type' => 'Answer', 'text' => $answer, ), ); } return $questions; } private function answer_text( array $block ): string { $html = render_block( $block ); // Strip the question element so it isn't duplicated // into the answer text — only the details' body content is the answer. $html = (string) preg_replace( '#]*>.*?#is', '', $html ); return trim( wp_strip_all_tags( $html ) ); } /** * @param array> $blocks * * @return array> */ private function flatten_blocks( array $blocks ): array { $flat = array(); foreach ( $blocks as $block ) { $flat[] = $block; if ( ! empty( $block['innerBlocks'] ) ) { $flat = array_merge( $flat, $this->flatten_blocks( $block['innerBlocks'] ) ); } } return $flat; } }