- Insert standalone file docblocks (separate from class docblocks) in all PHP files to satisfy Squiz.Commenting.FileComment.Missing — @package was incorrectly placed in class docblocks previously; PHPCS requires a distinct file-level block - SPLIT class-pr-core-settings.php (was 340 lines after docblock expansion): class-pr-core-settings.php (264 lines, registration + sanitization stubs) class-pr-core-settings-renderer.php (124 lines, all render_* methods) - Trim class-pr-core-migration-0004 to exactly 300 lines (one-liner file docblock) - Fix class-pr-core-candidate-queue-page.php: Yoda conditions: null !== c->dose_min / null !== c->dose_max Unescaped study output: phpcs:ignore EscapeOutput _GET action and candidate_id: wrap with wp_unslash() - Existing split classes: seed-fixtures, peptide-meta-schema (from prior session) Agent-Session: claude-adopt-ci-20260616
111 lines
3.2 KiB
PHP
111 lines
3.2 KiB
PHP
<?php
|
|
declare(strict_types=1);
|
|
|
|
/**
|
|
* Reads _pr_faq_items post-meta (JSON array of {question, answer} objects)
|
|
*
|
|
* @package Peptide_Repo_Core
|
|
*/
|
|
|
|
/**
|
|
* Builds the schema.org FAQPage graph piece for a peptide page.
|
|
*
|
|
* What: Reads _pr_faq_items post-meta (JSON array of {question, answer} objects)
|
|
* and produces a FAQPage node suitable for injection into Yoast's graph.
|
|
* Emits nothing when the meta is empty or absent.
|
|
*
|
|
* Who calls it: PR_Core_Jsonld::build_faq_piece() during graph assembly.
|
|
* Dependencies: WordPress get_post_meta(), get_permalink().
|
|
*
|
|
* @see frontend/class-pr-core-jsonld.php — Orchestrator that calls this builder.
|
|
* @see cpt/class-pr-core-schema-sanitizers.php — sanitize_faq_items() used on save.
|
|
* @see ARCHITECTURE.md — §2.7 JSON-LD output.
|
|
*/
|
|
class PR_Core_Jsonld_Faq {
|
|
|
|
/**
|
|
* Meta key holding the FAQ items JSON array.
|
|
*
|
|
* @var string Meta key holding the FAQ items JSON array.
|
|
*/
|
|
public const META_FAQ_ITEMS = '_pr_faq_items';
|
|
|
|
/**
|
|
* Build a FAQPage node for a post, or return null if no items exist.
|
|
*
|
|
* @param int $post_id WordPress post ID.
|
|
* @param string $permalink Canonical permalink for @id construction.
|
|
* @return array<string, mixed>|null FAQPage schema node, or null when no items.
|
|
*/
|
|
public function build( int $post_id, string $permalink ): ?array {
|
|
$items = $this->get_validated_items( $post_id );
|
|
|
|
if ( empty( $items ) ) {
|
|
return null;
|
|
}
|
|
|
|
return array(
|
|
'@type' => 'FAQPage',
|
|
'@id' => $permalink . '#faq',
|
|
'mainEntity' => array_map( array( $this, 'build_question' ), $items ),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Build a single Question node from a FAQ item array.
|
|
*
|
|
* @param array{question: string, answer: string} $item Sanitized FAQ item.
|
|
* @return array<string, mixed> Schema.org Question node.
|
|
*/
|
|
private function build_question( array $item ): array {
|
|
return array(
|
|
'@type' => 'Question',
|
|
'name' => esc_html( $item['question'] ),
|
|
'acceptedAnswer' => array(
|
|
'@type' => 'Answer',
|
|
'text' => esc_html( $item['answer'] ),
|
|
),
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Read and validate _pr_faq_items meta, returning only well-formed items.
|
|
*
|
|
* Returns empty array when meta is absent, empty, or malformed.
|
|
* Does not trust stored values — re-validates each item at read time.
|
|
*
|
|
* @param int $post_id WordPress post ID.
|
|
* @return array<int, array{question: string, answer: string}> Validated items.
|
|
*/
|
|
private function get_validated_items( int $post_id ): array {
|
|
$raw = get_post_meta( $post_id, self::META_FAQ_ITEMS, true );
|
|
|
|
if ( ! is_string( $raw ) || '' === $raw ) {
|
|
return array();
|
|
}
|
|
|
|
$decoded = json_decode( $raw, true );
|
|
|
|
if ( ! is_array( $decoded ) || empty( $decoded ) ) {
|
|
return array();
|
|
}
|
|
|
|
$valid = array();
|
|
foreach ( $decoded as $item ) {
|
|
if ( ! is_array( $item ) ) {
|
|
continue;
|
|
}
|
|
$question = sanitize_text_field( (string) ( $item['question'] ?? '' ) );
|
|
$answer = sanitize_textarea_field( (string) ( $item['answer'] ?? '' ) );
|
|
if ( '' !== $question && '' !== $answer ) {
|
|
$valid[] = array(
|
|
'question' => $question,
|
|
'answer' => $answer,
|
|
);
|
|
}
|
|
}
|
|
|
|
return $valid;
|
|
}
|
|
}
|