1414/**
1515 * Pulls the trailing `## FAQ` section (a `**Q: ...**` / `A: ...` pair per question) out of a
1616 * Markdown article body, so it can be rendered as an accordion and fed into JSON-LD separately
17- * from the rest of the body.
17+ * from the rest of the body. `question` and `answer` keep their Markdown (for rendering);
18+ * `questionText` and `answerText` are plain-text copies (for JSON-LD).
1819 */
1920final class FaqExtractor
2021{
2122 /**
22- * @return array{faq: list<array{question: string, answer: string}>, body: string}
23+ * @return array{
24+ * faq: list<array{question: string, answer: string, questionText: string, answerText: string}>,
25+ * body: string
26+ * }
2327 */
2428 public static function extract (string $ body ): array
2529 {
@@ -35,14 +39,24 @@ public static function extract(string $body): array
3539 PREG_SET_ORDER
3640 );
3741 foreach ($ matches as $ match ) {
42+ $ question = trim ($ match [1 ]);
43+ $ answer = trim (preg_replace ('/\s+/ ' , ' ' , $ match [2 ]) ?? '' );
44+
3845 $ faq [] = [
39- 'question ' => trim ($ match [1 ]),
40- 'answer ' => trim (preg_replace ('/\s+/ ' , ' ' , $ match [2 ]) ?? '' ),
46+ 'question ' => $ question ,
47+ 'answer ' => $ answer ,
48+ 'questionText ' => self ::toPlainText ($ question ),
49+ 'answerText ' => self ::toPlainText ($ answer ),
4150 ];
4251 }
4352
4453 $ body = trim ((string ) preg_replace ('/^## FAQ\s*$.*\z/ms ' , '' , $ body ));
4554
4655 return ['faq ' => $ faq , 'body ' => $ body ];
4756 }
57+
58+ private static function toPlainText (string $ markdown ): string
59+ {
60+ return preg_replace ('/(`+)(.+?)\1/ ' , '$2 ' , $ markdown ) ?? $ markdown ;
61+ }
4862}
0 commit comments