Repository navigation
feat(blocks): preview real post data in post-* edits inside a query loop - #507
Conversation
…uery loop Pipes the resolved first post from `useQueryPreview` through the `artisanpack/query` block's `BlockContextProvider` so inner `post-title` / `post-date` / `post-excerpt` / `post-author` / `post-featured-image` block edits render the actual post's data in the editor canvas instead of placeholder labels. The data flow: - `WpEntityResource` adds a `_preview` envelope (formatted date, author name/avatar/url/bio, featured-image url/alt/dimensions) alongside the existing WP REST shape. Mirrors the `_resolved*` keys the server-side `PostResolver` stamps for the front end. - `mapWpEntityToPost` extracts `_preview` into `QueryPreviewPost`. - `query/edit.tsx` adds `artisanpack/postPreview` to its `BlockContextProvider` value carrying the first matched post. - Each post-* `block.json` declares `artisanpack/postPreview` in `usesContext`. - `createEntityPlaceholderEdit` accepts a `fromQueryPreview(post)` extractor with priority: stamped `_resolvedX` → context post → placeholder. Also drops `supports.inserter: false` on `artisanpack/post-author` so it can be inserted into a query loop alongside the other post-* blocks. Upstream hides it because `core/post-author` is deprecated in favor of `post-author-name` + `post-author-biography` + `avatar`, none of which the fork ships yet — see #506 for the follow-up to fork the rest of the WP theme catalog. Closes #483
|
No actionable comments were generated in the recent review. 🎉 ℹ️ Recent review info⚙️ Run configurationConfiguration used: Path: .coderabbit.yaml Review profile: CHILL Plan: Pro Run ID: 📒 Files selected for processing (1)
🚧 Files skipped from review as they are similar to previous changes (1)
📝 WalkthroughWalkthroughBackend responses include an editor ChangesQuery Preview Support
Sequence Diagram(s)sequenceDiagram
participant Post as Post Model
participant API as WpEntityResource
participant Hook as useQueryPreview
participant Context as BlockContextProvider
participant Block as PostTitleEdit
participant Renderer as EntityPlaceholderRenderer
Post->>API: model with author, published_at, featured media
API->>API: build _preview (dateFormatted, author, featuredImage)
API->>Hook: response { _preview }
Hook->>Hook: mapPreviewAuthor / mapPreviewFeaturedImage
Hook->>Context: artisanpack/postPreview = QueryPreviewPost
Context->>Block: context.artisanpack/postPreview
Block->>Block: fromQueryPreview(post)
Block->>Renderer: EntityPreviewValue (text/image)
Renderer->>Renderer: renderResolved or fallback placeholder
Estimated code review effort🎯 3 (Moderate) | ⏱️ ~25 minutes Possibly related issues
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✏️ Tip: You can configure your own custom pre-merge checks in the settings. ✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Comment |
There was a problem hiding this comment.
🧹 Nitpick comments (1)
src/Http/Resources/Adapters/CmsFramework/WpEntityResource.php (1)
190-203: ⚡ Quick winAdd defensive
try/catcharoundapGetMedia()/apGetMediaUrl()infeaturedImageEnvelope()
function_exists()only prevents “helper missing” fatals; if either helper throws, the exception will bubble out oftoArray()(viapreviewEnvelope()→featuredImageEnvelope()) and fail the whole response for that resource. This mirrors the defensivetry/catchalready used inrelationIds(). Media-library helpers are documented to return empty/null for missing/not-found media, but a catch keeps the editor resilient if a host helper implementation throws unexpectedly.🛡️ Proposed fix to isolate helper failures
if ( function_exists( 'apGetMediaUrl' ) ) { - $resolved = apGetMediaUrl( $mediaId, 'full' ); - $url = is_string( $resolved ) ? $resolved : ''; + try { + $resolved = apGetMediaUrl( $mediaId, 'full' ); + $url = is_string( $resolved ) ? $resolved : ''; + } catch ( Throwable ) { + $url = ''; + } } if ( function_exists( 'apGetMedia' ) ) { - $media = apGetMedia( $mediaId ); - - if ( is_object( $media ) ) { - $alt = isset( $media->alt_text ) && is_scalar( $media->alt_text ) ? (string) $media->alt_text : ''; - $width = isset( $media->width ) && is_numeric( $media->width ) ? (int) $media->width : 0; - $height = isset( $media->height ) && is_numeric( $media->height ) ? (int) $media->height : 0; - } + try { + $media = apGetMedia( $mediaId ); + + if ( is_object( $media ) ) { + $alt = isset( $media->alt_text ) && is_scalar( $media->alt_text ) ? (string) $media->alt_text : ''; + $width = isset( $media->width ) && is_numeric( $media->width ) ? (int) $media->width : 0; + $height = isset( $media->height ) && is_numeric( $media->height ) ? (int) $media->height : 0; + } + } catch ( Throwable ) { + $alt = ''; + $width = 0; + $height = 0; + } }🤖 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/Http/Resources/Adapters/CmsFramework/WpEntityResource.php` around lines 190 - 203, Wrap the calls to apGetMediaUrl() and apGetMedia() inside a defensive try/catch within featuredImageEnvelope() so any exception from those helpers does not bubble out of toArray()/previewEnvelope(); specifically, enclose the existing function_exists(...) blocks that call apGetMediaUrl($mediaId, 'full') and apGetMedia($mediaId) in a try block, catch Throwable, and on catch leave $url/$media/$alt/$width/$height set to their safe defaults (and optionally log the error), mirroring the defensive pattern used in relationIds().
🤖 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.
Nitpick comments:
In `@src/Http/Resources/Adapters/CmsFramework/WpEntityResource.php`:
- Around line 190-203: Wrap the calls to apGetMediaUrl() and apGetMedia() inside
a defensive try/catch within featuredImageEnvelope() so any exception from those
helpers does not bubble out of toArray()/previewEnvelope(); specifically,
enclose the existing function_exists(...) blocks that call
apGetMediaUrl($mediaId, 'full') and apGetMedia($mediaId) in a try block, catch
Throwable, and on catch leave $url/$media/$alt/$width/$height set to their safe
defaults (and optionally log the error), mirroring the defensive pattern used in
relationIds().
ℹ️ Review info
⚙️ Run configuration
Configuration used: Path: .coderabbit.yaml
Review profile: CHILL
Plan: Pro
Run ID: 93232791-1b19-42ad-8c08-19a3d222dd7f
📒 Files selected for processing (19)
resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-query-preview.test.tsxresources/js/visual-editor/blocks/_shared/entity-placeholder-edit.tsxresources/js/visual-editor/blocks/post-author/block.jsonresources/js/visual-editor/blocks/post-author/edit.tsxresources/js/visual-editor/blocks/post-author/upstream-state.jsonresources/js/visual-editor/blocks/post-date/block.jsonresources/js/visual-editor/blocks/post-date/edit.tsxresources/js/visual-editor/blocks/post-excerpt/block.jsonresources/js/visual-editor/blocks/post-excerpt/edit.tsxresources/js/visual-editor/blocks/post-featured-image/block.jsonresources/js/visual-editor/blocks/post-featured-image/edit.tsxresources/js/visual-editor/blocks/post-title/block.jsonresources/js/visual-editor/blocks/post-title/edit.tsxresources/js/visual-editor/blocks/query/edit.tsxresources/js/visual-editor/editor/__tests__/use-query-preview.test.tsxresources/js/visual-editor/editor/use-query-preview.tssrc/Http/Resources/Adapters/CmsFramework/WpEntityResource.phptests/Feature/VisualEditor/QueryResolve/QueryResolveControllerTest.phptests/Unit/VisualEditor/Resources/WpEntityResourcePreviewTest.php
Wrap the `apGetMediaUrl()` / `apGetMedia()` calls in `featuredImageEnvelope()` in defensive `try/catch` blocks so a host helper implementation that throws cannot bubble out of `toArray()` and break the entire response. Mirrors the defensive pattern `relationIds()` already uses in the same file.
Description
When an
artisanpack/queryblock is in the editor anduseQueryPreviewhas resolved at least one matching post, this PR pipes that first post through the existingBlockContextProviderso innerpost-title/post-date/post-excerpt/post-author/post-featured-imageblock edits render the actual post's data in the canvas instead of the static placeholder labels ("Post Title", "Post Date", …) they used to show.Closes: #483
Type of Change
Related Issue
Issue: #483
Motivation and Context
The Phase I5 entity cluster (#413) shipped these post-* blocks with a deliberate-shortcut edit that rendered a static label, because the post editor's
@wordpress/core-datashim does not expose entity data. The front end resolves correctly (theQueryInlinerstamps_resolved*attributes), but inside anartisanpack/queryloop the canvas just showed placeholders, making it look like the query was empty or broken when it was actually working.The fix follows the constraint in the issue: no new core-data shim requirements — the data flows through the
BlockContextProvider→postIdpath the query block already establishes, extended with anartisanpack/postPreviewkey carrying the resolved first post.Changes Made
Server (PHP):
WpEntityResourceadds a_previewenvelope alongside the existing WP REST shape:dateFormatted,author(name / bio / url / avatarUrl),featuredImage(url / alt / width / height). Mirrors the_resolved*keysPostResolverstamps for the front-end renderers so editor canvas and front end agree.Client (TS/TSX):
QueryPreviewPostgainsdateFormatted;mapWpEntityToPostextracts the_previewenvelope.query/edit.tsx'sBlockContextProvidernow carries{ postType, postId, 'artisanpack/postPreview': firstPost | null }.block.jsonfiles declareartisanpack/postPreviewinusesContext.createEntityPlaceholderEditaccepts afromQueryPreview(post)extractor. Priority: stamped_resolvedXattribute → context post → labelled placeholder.post-author/block.jsondropssupports.inserter: falseso the block can be inserted alongside the others — upstream hides it becausecore/post-authoris deprecated in favor ofpost-author-name+post-author-biography+avatar, none of which the fork ships yet. Tracked as a follow-up in Fork remaining WP theme-category blocks (post-author-name, post-comments-*, query-pagination-*, etc.) #506. The divergence is documented inupstream-state.json.How Has This Been Tested?
Testing Environment:
Tests Performed:
_previewenvelope mapping.WpEntityResource_previewenvelope and 1 new feature test asserting the query/resolve endpoint surfaces it.npm run verify:parity— all 89 blocks registered across Blade / React / Vue renderers.npm run build), deployeddist/editor/*into thejmwd-keystone-cmshost app'spublic/visual-editor/, and manually verified in the browser:artisanpack/queryblock with two matching posts → innerpost-title,post-date,post-excerpt,post-author, andpost-featured-imageblocks all preview the first matched post's real data.post-titleoutside a query loop → falls back to the labelled placeholder.PreviewBanneralready announces this) and is handled on the front end byQueryInliner.Accessibility Tests Run
alton featured-image previews is read)currentColordashed border + 0.55 opacity, unchanged from existing helper)Details: The change is read-only preview content — no new interactive surfaces. The placeholder-vs-resolved path is purely about which string/image the existing block wrapper renders.
Tests Added
Test details:
resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-query-preview.test.tsx— 17 tests covering attribute-vs-context priority, placeholder fallback, image-kind rendering, non-object context guard, per-block extractors, theblock.jsonusesContextdeclaration, and the post-author insertability flag.tests/Unit/VisualEditor/Resources/WpEntityResourcePreviewTest.php— 5 tests covering the null envelope, the author envelope withbio/urlanddescription/websitefallbacks, thedateFormattedfield, and the featured-image envelope short-circuiting when media-library helpers aren't bound.resources/js/visual-editor/editor/__tests__/use-query-preview.test.tsx— 3 new cases for_previewextraction, omitted-extras nulling, and url-less featured-image dropping.tests/Feature/VisualEditor/QueryResolve/QueryResolveControllerTest.php— 1 new case asserting the_previewenvelope structure on resolved posts.Documentation
Documentation details:
WpEntityResource::previewEnvelope/authorEnvelope/featuredImageEnvelope/formattedDatecarry full PHPDoc explaining themapWpEntityToPost()consumer contract.createEntityPlaceholderEdit's file-level docblock +EntityPreviewValue/EntityPlaceholderConfiginterface comments document the attribute → context → placeholder priority.edit.tsxcarries an updated header comment noting the new fallback step.post-author/upstream-state.jsondocuments the deliberatesupports.inserterdivergence.Screenshots
Pre-#483: every post-* block in the query loop showed "Post Title" / "Post Date" / etc. placeholder labels.
Post-#483: the same blocks show the first matched post's actual title, date, excerpt, author name, and featured image.
Pre-Submission Checklist
release/1.0— addressed the one minor finding (defensive image url guard); pass 2 cleanSummary by CodeRabbit
New Features
Tests