Add content reference blocks (ContentChooserBlock + ContentCardBlock)#1713
Open
mwvolo wants to merge 6 commits into
Open
Add content reference blocks (ContentChooserBlock + ContentCardBlock)#1713mwvolo wants to merge 6 commits into
mwvolo wants to merge 6 commits into
Conversation
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Unset overrides (title/image/excerpt) serialize as null so the frontend override ?? hydrated merge falls back to the referenced page's values. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Adds the content_card block to the shared content block list and the generated StreamField migration (0181_alter_rootpage_body). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Contributor
There was a problem hiding this comment.
Pull request overview
This PR adds a reusable “content reference” primitive for StreamField content in OpenStax CMS, allowing editors to create card-like blocks that reference other site pages (initially Books and News Articles) while emitting a lean API payload intended for frontend hydration.
Changes:
- Introduces
ContentChooserBlock(allowlistedPageChooserBlock) andContentCardBlock(reference + optional overrides) inpages/custom_blocks.py. - Registers the new
content_cardblock inBASE_CONTENT_BLOCKSand applies the generated StreamField migration. - Adds a focused test suite validating canonical reference shape, allowlist behavior, and override serialization expectations.
Reviewed changes
Copilot reviewed 4 out of 4 changed files in this pull request and generated 2 comments.
| File | Description |
|---|---|
| pages/custom_blocks.py | Adds the new content-reference blocks and API serialization logic for references/cards. |
| pages/models/constants.py | Registers content_card into the base StreamField block set. |
| pages/migrations/0181_alter_rootpage_body.py | Updates RootPage.body StreamField to include content_card. |
| pages/tests/test_content_reference.py | Adds tests covering canonical reference output, null-override contract, and registration. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
# Conflicts: # pages/migrations/0181_alter_rootpage_body.py
Resolves the duplicate 0181_alter_rootpage_body conflict with main (#1714). Keeps main's 0181 (big_number color) and renumbers the content_card StreamField change to 0182, depending on 0181. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What
Adds a native, reusable way for CMS editors to link a card (and other blocks) to another page on the site — a content-reference primitive plus a card that uses it. This is the CMS half of the work behind the structured card set (relates to CORE-2404, the blog card).
New blocks (
pages/custom_blocks.py)ContentChooserBlock— aPageChooserBlockrestricted to an allowlist (CONTENT_REFERENCE_TYPES=books.Book,news.NewsArticle). Emits a lean canonical reference:{id, type, slug, url, title}. URL resolves via.specific(same pattern asLinkBlock), so book links come out as the real frontend route (/details/books/<slug>), not the tree path.ContentCardBlock— aStructBlockwrapping the reference with optionaltitle/image/excerptoverrides.content_cardis registered inBASE_CONTENT_BLOCKS(with the generated StreamField migration0181_alter_rootpage_body).Why this shape: reference-and-hydrate
The CMS emits a lean reference + overrides only and embeds no page display data. The frontend (flex-pages renderer) hydrates fresh display data from the pages API by reference. This mirrors the pattern in flex-pages PR #14 (the os books block), avoids stale embedded snapshots, and means the existing
BookBlock/get_book_datapath is untouched — this change is purely additive.Unset-override contract: unset
title/image/excerptserialize asnull(not""/{}) so the frontendoverride ?? hydratedmerge falls back to the page's own values correctly.Scope
LinkBlock).ContentCardBlockcomponent) is a separate follow-on in theflex-pagesrepo.Testing
6 tests in
pages/tests/test_content_reference.py(canonical reference shape, the null-override contract for all three fields, allowlist enforcement, block registration). All passing.🤖 Generated with Claude Code