Skip to content

Fix #114: Add FAQ question blocks with configurable section grouping - #122

Merged
samdark merged 5 commits into
masterfrom
114-add-faq-question-blocks-with-configurable-section-grouping
Aug 2, 2026
Merged

Fix #114: Add FAQ question blocks with configurable section grouping#122
samdark merged 5 commits into
masterfrom
114-add-faq-question-blocks-with-configurable-section-grouping

Conversation

@samdark

@samdark samdark commented Jul 30, 2026

Copy link
Copy Markdown
Member

Closes #114.

Summary

  • parse strict per-entry faq_level grouping configuration
  • recognize titled ::: question containers outside code fences
  • render Markdown answers as semantic, no-JavaScript details/summary markup
  • support inline, page-end, and heading-level grouping in document order
  • handle longer fences and leave nested, malformed, and unclosed containers literal
  • run the two-pass processor in page and feed pipelines before TOC collection
  • add minimal-theme styling, user-facing docs, roadmap coverage, and a 100-question phpbench benchmark
  • document the decision not to emit FAQPage JSON-LD automatically

Validation

  • make test CLI_ARGS="tests/Unit/Processor/QuestionProcessorTest.php tests/Unit/Content/Parser/EntryParserTest.php tests/Unit/Processor/ContentProcessorPipelineConfigTest.php tests/Unit/Theme/MinimalThemeAssetsTest.php" (49 tests, 201 assertions)
  • make psalm
  • make composer-dependency-analyser
  • make bench BENCH_FILTER=QuestionProcessorBench
  • git diff --check

Benchmark result in this environment: 100 inline questions ~128.6µs; grouped by section ~152.5µs.

Summary by CodeRabbit

  • New Features

    • Added FAQ question blocks using [question] shortcodes.
    • Questions render as accessible, semantic expandable sections with escaped content.
    • Supports inline FAQs, end-of-page collections, and grouping by heading levels 1–6.
    • Preserves question order and safely handles malformed or nested syntax.
  • Style

    • Added Minimal theme styling for FAQ sections, question rows, summaries, and answers.
  • Documentation

    • Documented FAQ syntax, grouping configuration, behavior, and benchmarking coverage.

Copilot AI review requested due to automatic review settings July 30, 2026 06:47
@coderabbitai

coderabbitai Bot commented Jul 30, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

Changes

FAQ question blocks now support validated faq_level metadata, safe Markdown answer processing, inline rendering, page-end grouping, and heading-based grouping. Pipeline registration, tests, documentation, benchmarking, and Minimal theme styles were added.

FAQ question blocks

Layer / File(s) Summary
FAQ metadata contract
src/Content/Model/Entry.php, src/Content/Parser/EntryParser.php, tests/Unit/Content/Parser/EntryParserTest.php
Entry stores faqLevel. EntryParser accepts false, null, and levels 06, and rejects invalid values.
Question shortcode processing
src/Processor/Question/QuestionProcessor.php, tests/Unit/Processor/QuestionProcessorTest.php
QuestionProcessor preserves valid shortcodes through Markdown, ignores fenced code, handles malformed or nested syntax, and renders escaped semantic FAQ elements.
Content and feed pipeline integration
config/common/di/content-pipeline.php, tests/Unit/Processor/ContentProcessorPipelineConfigTest.php
The content and feed pipelines run QuestionProcessor at the configured processing stages. Tests verify processor ordering.
FAQ presentation and validation support
themes/minimal/assets/style.css, tests/Unit/Theme/MinimalThemeAssetsTest.php, benchmarks/QuestionProcessorBench.php, docs/benchmarking.md, docs/content.md, docs/plugins.md, roadmap.md
Minimal theme styles, benchmark coverage, documentation, and roadmap status describe and validate FAQ question behavior.

Estimated code review effort: 4 (Complex) | ~45 minutes

Sequence Diagram(s)

sequenceDiagram
  participant ContentProcessorPipeline
  participant QuestionProcessor
  participant MarkdownProcessor
  participant HTMLDocument
  ContentProcessorPipeline->>QuestionProcessor: preserve question shortcodes
  QuestionProcessor->>MarkdownProcessor: pass encoded question markers
  MarkdownProcessor->>QuestionProcessor: return Markdown-rendered content
  QuestionProcessor->>HTMLDocument: replace markers with FAQ details sections
Loading
🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 21.88% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed The implementation satisfies the coding objectives and acceptance criteria in issue [#114], including parsing, grouping, rendering, tests, documentation, and benchmarking.
Out of Scope Changes check ✅ Passed The code, tests, documentation, styling, roadmap entry, and benchmark changes directly support the objectives in issue [#114].
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the pull request's main change: adding FAQ question blocks with configurable section grouping.
✨ Finishing Touches 💡 1
📝 Generate docstrings 💡
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 114-add-faq-question-blocks-with-configurable-section-grouping

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds first-class support for ::: question FAQ blocks in YiiPress content, with per-entry configuration (faq_level) to keep questions inline or group them into semantic, no-JS <details>/<summary> FAQ sections. This integrates the processor into both page and feed pipelines prior to TOC collection, and updates the minimal theme, docs, tests, benchmarks, and roadmap accordingly.

Changes:

  • Introduce a two-pass QuestionProcessor that preserves question blocks pre-Markdown and renders/groups them post-Markdown.
  • Add faq_level parsing to entries (front matter → Entry::$faqLevel) and wire the processor into the DI content pipelines.
  • Add minimal theme styling, PHPUnit coverage, phpbench benchmark, and user-facing documentation.

Reviewed changes

Copilot reviewed 14 out of 14 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
themes/minimal/assets/style.css Adds minimal theme styling for .faq-section, .faq-question, and .faq-answer.
tests/Unit/Theme/MinimalThemeAssetsTest.php Verifies minimal theme CSS includes FAQ styles.
tests/Unit/Processor/QuestionProcessorTest.php Covers inline rendering, grouping modes, fence edge cases, and code-fence suppression.
tests/Unit/Processor/ContentProcessorPipelineConfigTest.php Ensures QuestionProcessor is registered in the expected pipeline positions (two-pass).
tests/Unit/Content/Parser/EntryParserTest.php Adds parsing/validation coverage for faq_level front matter.
src/Processor/Question/QuestionProcessor.php Implements preservation + post-Markdown rendering/grouping into <details>/<summary>.
src/Content/Parser/EntryParser.php Parses strict faq_level values and throws on invalid configs.
src/Content/Model/Entry.php Adds faqLevel field to the entry model and preserves it in withRedirectTo().
roadmap.md Checks off issue #114 as completed.
docs/plugins.md Documents ::: question usage, grouping behavior, and the JSON-LD decision.
docs/content.md Documents faq_level in front matter reference.
docs/benchmarking.md Lists QuestionProcessorBench.
config/common/di/content-pipeline.php Inserts QuestionProcessor into page + feed pipelines (two-pass, before TOC).
benchmarks/QuestionProcessorBench.php Adds a 100-question benchmark for inline vs section-grouped processing.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread src/Processor/Question/QuestionProcessor.php Outdated
samdark added 3 commits July 30, 2026 09:54
…n-blocks-with-configurable-section-grouping

# Conflicts:
#	docs/content.md
#	roadmap.md
#	src/Content/Model/Entry.php
#	src/Content/Parser/EntryParser.php
#	tests/Unit/Content/Parser/EntryParserTest.php

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🧹 Nitpick comments (2)
src/Processor/Question/QuestionProcessor.php (1)

43-43: 🚀 Performance & Scalability | 🔵 Trivial | 💤 Low value

Avoid allocating a lowercase copy for a case-insensitive substring check.

strtolower($content) copies the entire content string just to check for [question. Use stripos() instead to avoid the allocation, especially since this runs on the full rendered document on the second pipeline pass.

⚡ Proposed fix
-        if (!str_contains(strtolower($content), '[question')) {
+        if (stripos($content, '[question') === false) {
             return $content;
         }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/Processor/Question/QuestionProcessor.php` at line 43, Update the
substring check in QuestionProcessor to use stripos() for a case-insensitive
search of “[question” instead of lowercasing $content with strtolower().
Preserve the existing condition’s behavior for both matching and non-matching
content.
config/common/di/content-pipeline.php (1)

48-58: 📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

Document why QuestionProcessor runs at each of these two points.

The existing comments explain only CodeGroupProcessor's two-pass placement. Add a short comment noting that QuestionProcessor follows the same preserve-before-Markdown, render-after-later-processors pattern. This pipeline is order-sensitive, and a future reordering mistake would silently break FAQ rendering without a compile-time error.

📝 Proposed comment additions
             // Preserve code-group shortcode metadata before Markdown, then render it after syntax highlighting.
             Reference::to(CodeGroupProcessor::class),
+            // Preserve question shortcodes before Markdown; rendered below after the second code-group pass.
             Reference::to(QuestionProcessor::class),
             Reference::to(MarkdownProcessor::class),
             Reference::to(LatexMathProcessor::class),
             Reference::to(TagLinkProcessor::class),
             Reference::to(MermaidProcessor::class),
             Reference::to(SyntaxHighlightProcessor::class),
             // Complete the second code-group pass using the rendered, highlighted code blocks.
             Reference::to(CodeGroupProcessor::class),
+            // Render preserved question shortcodes into FAQ details markup.
             Reference::to(QuestionProcessor::class),
             Reference::to(TocProcessor::class),

Also applies to: 65-68

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@config/common/di/content-pipeline.php` around lines 48 - 58, Add concise
comments at both QuestionProcessor placements in the content pipeline,
explaining that its first pass preserves question metadata before Markdown and
its second pass renders it after the later processors. Keep the existing
CodeGroupProcessor comments and processor ordering unchanged.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@tests/Unit/Theme/MinimalThemeAssetsTest.php`:
- Around line 89-95: Add PHPUnit assertions in MinimalThemeAssetsTest covering
the remaining FAQ CSS rules: the .faq-question:last-child bottom border,
.faq-answer padding, and the first-child and last-child margin normalization
rules. Keep the existing FAQ style assertions and verify each expected
declaration is present in $css.

---

Nitpick comments:
In `@config/common/di/content-pipeline.php`:
- Around line 48-58: Add concise comments at both QuestionProcessor placements
in the content pipeline, explaining that its first pass preserves question
metadata before Markdown and its second pass renders it after the later
processors. Keep the existing CodeGroupProcessor comments and processor ordering
unchanged.

In `@src/Processor/Question/QuestionProcessor.php`:
- Line 43: Update the substring check in QuestionProcessor to use stripos() for
a case-insensitive search of “[question” instead of lowercasing $content with
strtolower(). Preserve the existing condition’s behavior for both matching and
non-matching content.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro Plus

Run ID: 0c371c47-9ae2-42a9-b40b-f6cf15f85ccb

📥 Commits

Reviewing files that changed from the base of the PR and between fde4694 and 0628908.

📒 Files selected for processing (14)
  • benchmarks/QuestionProcessorBench.php
  • config/common/di/content-pipeline.php
  • docs/benchmarking.md
  • docs/content.md
  • docs/plugins.md
  • roadmap.md
  • src/Content/Model/Entry.php
  • src/Content/Parser/EntryParser.php
  • src/Processor/Question/QuestionProcessor.php
  • tests/Unit/Content/Parser/EntryParserTest.php
  • tests/Unit/Processor/ContentProcessorPipelineConfigTest.php
  • tests/Unit/Processor/QuestionProcessorTest.php
  • tests/Unit/Theme/MinimalThemeAssetsTest.php
  • themes/minimal/assets/style.css

Comment thread tests/Unit/Theme/MinimalThemeAssetsTest.php

Copilot AI left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Copilot reviewed 14 out of 14 changed files in this pull request and generated no new comments.

Suppressed comments (1)

src/Processor/Question/QuestionProcessor.php:46

  • The PR description/issue motivation references Rapira-style ::: question containers, but this processor only recognizes [question ...]...[/question] shortcodes (see the [question detection and open-tag regex). This is a behavior/documentation mismatch that may confuse users expecting the documented Rapira syntax.

Either update the PR description/docs to explicitly state the supported syntax is [question], or add support for ::: question blocks (including tests and docs) if that syntax is still a requirement.

        if (str_contains($content, self::START_MARKER)) {
            return $this->renderQuestions($content, $entry->faqLevel);
        }
        if (stripos($content, '[question') === false) {
            return $content;
        }

@samdark samdark changed the title Add FAQ question blocks with configurable section grouping Fix #114: Add FAQ question blocks with configurable section grouping Aug 2, 2026
@samdark
samdark merged commit 092165a into master Aug 2, 2026
12 checks passed
@samdark
samdark deleted the 114-add-faq-question-blocks-with-configurable-section-grouping branch August 2, 2026 16:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add FAQ question blocks with configurable section grouping

2 participants