Skip to content

feat(blocks): preview live entity values in site-* and post-* edits - #508

Merged
ViewFromTheBox merged 2 commits into
release/1.0from
feature/481-show-live-entity-values-in-editor
May 30, 2026
Merged

ViewFromTheBox merged 2 commits into
release/1.0from
feature/481-show-live-entity-values-in-editor

Conversation

@ViewFromTheBox

@ViewFromTheBox ViewFromTheBox commented May 30, 2026 •

Copy link
Copy Markdown
Member

Description

Adds two new fallback paths to createEntityPlaceholderEdit so the artisanpack/site-* and artisanpack/post-* blocks preview real values in the editor canvas. The Phase I5 entity-cluster fork (#413) rendered them as generic placeholder chips because @wordpress/core-data is backed by the V1 shim that doesn't expose the site or current-page entity. The existing #483 query-loop preview path is left intact.

Closes: #481

Type of Change

  • Enhancement (improves existing functionality)

Related Issue

Issue: #481

Motivation and Context

Authors building a page template (or any non-loop layout) couldn't see real site title / logo / tagline or the page's actual title / excerpt / date / author / featured image in the canvas — only labelled placeholder chips. This closes the parity gap between the editor canvas and the rendered front end for the entity display blocks.

Changes Made

  • New ArtisanPackUI\VisualEditor\Resources\SiteMetaResolver reading apGetSetting('site.*') with a config('artisanpack.visual-editor.site_meta') fallback (mirrors the renderer-blade sibling so visual-editor stands alone).
  • New SiteController exposing the singleton site-meta envelope at GET /visual-editor/api/site/{id} (id segment is a sentinel — always returns the same record).
  • New root/__unstableBase entity in DEFAULT_ENTITIES plus a SITE_ENTITY_ID = 'self' export so consumers can useEntityRecord('root', '__unstableBase', SITE_ENTITY_ID).
  • createEntityPlaceholderEdit extended with fromPostEntity / fromSiteEntity extractor options backed by useEntityRecord. Priority chain: stamped _resolved* → artisanpack/postPreview query-loop context (Editor preview: show real post data in post-* block edits instead of placeholder labels #483) → live post entity (from postId/postType block context) → live site entity → placeholder label.
  • New readEntityString helper handles the {raw, rendered} envelope shape returned by useEntityRecord (unflattened) as well as the flattened raw string from getEditedEntityRecord.
  • Each site-{title,tagline,logo} and post-{title,excerpt,date,author,featured-image} edit wires its extractor against the relevant fields (title, excerpt, _preview.dateFormatted, _preview.author.name, _preview.featuredImage, logoUrl).

How Has This Been Tested?

Testing Environment:

  • Operating System: macOS (Darwin 25.5.0)
  • Browser: Chrome — verified in the keystone-cms host app at ~/Herd/jmwd-keystone-cms after npm run build + sync:visual-editor
  • PHP Version: 8.4.3
  • Project Version: visual-editor release/1.0

Tests Performed:

  1. Site- blocks* — inserted Site Title / Tagline / Logo blocks at the page level → previewed live configured values instead of the placeholder chip.
  2. Post- blocks (page-level)* — edited an existing Page, inserted Post Title / Excerpt / Date / Author / Featured Image blocks at the top level → showed the page's real title / excerpt / F j, Y date / author name / featured image.
  3. Query-loop case — confirmed the existing artisanpack/postPreview block-context preview still wins inside a Query loop (no regression to Editor preview: show real post data in post-* block edits instead of placeholder labels #483).
  4. Empty-config fallback — with no source populated, blocks fall back to the clearly-labelled placeholder.

Accessibility Tests Run

  • Color contrast verified (no UI surfaces added — preview rendering uses the same DOM the front-end renderer emits)

Details: This change only affects the editor canvas preview; the front-end rendered markup is unchanged. The preview reuses the existing useBlockProps() wrapper and the same DOM nesting the previous placeholder used, so editor a11y is unchanged. No new toolbar / inspector controls were added.

Tests Added

  • Unit tests added/updated
  • Integration tests added/updated
  • All tests passing

Test details:

  • tests/Feature/VisualEditor/SiteControllerTest.php — 4 feature tests covering the configured-meta envelope, empty-config fallback, sentinel-id behaviour, and auth gate.
  • resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx — 20 vitest tests covering each post-* and site-* block's live-entity read path, the { raw, rendered } shape handling, the priority order vs. stamped _resolved* + query-preview context, and edge cases (missing context, malformed postId, empty entity values).
  • resources/js/visual-editor/vendor/__tests__/core-data-shim.test.tsx — updated the entity-registry assertion to include the new root|__unstableBase entry.

Full suite: 684 PHP tests + 1508 JS tests all passing.

Documentation

  • Inline code documentation added

Documentation details: All new public surfaces (SiteMetaResolver, SiteController, SITE_ENTITY_ID, the new EntityPlaceholderConfig options, readEntityString, the new live-entity hooks) have PHPDoc / TSDoc blocks. The createEntityPlaceholderEdit module header documents the new 5-level resolution priority chain.

Pre-Submission Checklist

  • Followed contributing guidelines
  • Checked for other open PRs for same update
  • Code passes all tests
  • Code follows project style guide
  • Self-review completed
  • Comments added for complex code
  • No new warnings generated

Summary by CodeRabbit

  • New Features

    • Live entity previews expanded to cover post title, author, date, excerpt, featured image, site title, tagline, and logo.
    • Editor now fetches singleton site metadata via a new visual-editor API endpoint so site title/description/logo surface as previewable values.
  • Tests

    • Comprehensive tests added for live entity preview rendering and shim behavior, including singleton site responses and cross-test isolation.

Review Change Stack

The Phase I5 entity-cluster fork (#413) rendered the artisanpack/site-*
and artisanpack/post-* blocks as crash-free but generic placeholder
chips in the editor canvas because @wordpress/core-data was backed by
the V1 shim that didn't expose the site or current-page entity.

This adds two new fallback paths to createEntityPlaceholderEdit so
those blocks preview real values in the canvas, while keeping the
existing #483 query-loop path intact:

- A singleton root/__unstableBase site-meta entity, served by a new
  GET /visual-editor/api/site/{id} endpoint backed by a new
  ArtisanPackUI\VisualEditor\Resources\SiteMetaResolver that reads
  from apGetSetting('site.*') with a config('artisanpack.visual-editor
  .site_meta') fallback. site-title / site-tagline / site-logo edits
  read the live record via useEntityRecord and preview its title /
  description / logoUrl.
- A live post-entity read via useEntityRecord('postType', postType,
  postId), keyed off the postId/postType block context the editor
  stamps on the canvas (editor-app.tsx). post-title / post-excerpt /
  post-date / post-author / post-featured-image edits surface the
  active page's actual title / excerpt / formatted date / author name
  / featured image when placed outside a query loop.

Priority order in the edit helper: stamped _resolved* attribute >
artisanpack/postPreview query-loop context (#483) > live post entity
(#481) > live site entity (#481) > placeholder label.

Closes #481
@coderabbitai

coderabbitai Bot commented May 30, 2026 •

Copy link
Copy Markdown

No actionable comments were generated in the recent review. 🎉

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 2b3988de-a854-4b18-bb28-97a4a4782136

📥 Commits

Reviewing files that changed from the base of the PR and between 0cb600c and 36b1014.

📒 Files selected for processing (3)
  • resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx
  • src/Http/Controllers/SiteController.php
  • src/Resources/SiteMetaResolver.php
🚧 Files skipped from review as they are similar to previous changes (3)
  • resources/js/visual-editor/blocks/_shared/tests/entity-placeholder-live-entity.test.tsx
  • src/Http/Controllers/SiteController.php
  • src/Resources/SiteMetaResolver.php

📝 Walkthrough

Walkthrough

This PR implements live entity preview rendering for visual editor blocks. It adds a singleton site-meta API endpoint backed by SiteMetaResolver, extends the core-data shim with a site entity and SITE_ENTITY_ID, introduces live entity fetch/extract hooks and readEntityString, and updates post-/site- placeholder editors plus tests to prefer stamped resolved attributes, then query-preview, then live entity values, then placeholders.

Changes

Live Entity Preview

Layer / File(s) Summary
Core-data shim: Singleton site-meta entity
resources/js/visual-editor/vendor/core-data-shim.ts, resources/js/visual-editor/vendor/__tests__/core-data-shim.test.tsx
Added `root
API endpoint: Site metadata resolver and controller
routes/api.php, src/Http/Controllers/SiteController.php, src/Resources/SiteMetaResolver.php, tests/Feature/VisualEditor/SiteControllerTest.php
Added SiteMetaResolver (resolve/flush/lookup/lookupId/resolveMediaUrl/coerceString), SiteController::show shaping WP REST–style singleton response, GET /site/{id} route, and feature tests for shape, empty/null handling, singleton semantics, and auth.
Entity placeholder framework: Live entity extraction
resources/js/visual-editor/blocks/_shared/entity-placeholder-edit.tsx
Added PostEntityRecord and SiteEntityRecord types, readEntityString helper, hooks useLivePostEntityValue/useLiveSiteEntityValue, and config options fromPostEntity/fromSiteEntity; integrated live entity values into preview resolution priority.
Block implementations: Post entity previews
resources/js/visual-editor/blocks/post-title/edit.tsx, resources/js/visual-editor/blocks/post-author/edit.tsx, resources/js/visual-editor/blocks/post-date/edit.tsx, resources/js/visual-editor/blocks/post-excerpt/edit.tsx, resources/js/visual-editor/blocks/post-featured-image/edit.tsx
Each block adds a fromPostEntity extractor to read live entity fields (title, _preview.author.name, _preview.dateFormatted/date, excerpt, _preview.featuredImage) and return preview payload or null.
Block implementations: Site entity previews
resources/js/visual-editor/blocks/site-title/edit.tsx, resources/js/visual-editor/blocks/site-tagline/edit.tsx, resources/js/visual-editor/blocks/site-logo/edit.tsx
Each block adds a fromSiteEntity extractor to read singleton site fields (title, description, logoUrl) and return text or image payloads when non-empty.
Integration tests: Live entity preview validation
resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx
New Vitest/RTL suite with shim fetch control, store reset/invalidate between tests, seeding helpers, post-* and site-* groups validating precedence, raw/rendered/_preview handling, malformed context, and placeholder fallbacks.

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related issues

  • #481: Directly implements the live entity preview feature requested there (post/site live previews, shim/site endpoint, extractors, tests).
  • #483: Related acceptance criteria for showing real post/site data in edit block previews and precedence rules.

Possibly related PRs

Poem

🐰 In editor meadows I hop and peep,

live titles and logos wake from sleep,
shim and resolver hum in tune,
previews bloom before the afternoon,
a tiny hop for editor delight.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 66.67% 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
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The PR title clearly and concisely describes the main change: adding live entity value previews to site and post blocks in the editor.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feature/481-show-live-entity-values-in-editor

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ESLint

If the error stems from missing dependencies, add them to the package.json file. For unrecoverable errors (e.g., due to private dependencies), disable the tool in the CodeRabbit configuration.

ESLint skipped: no ESLint configuration detected in root package.json. To enable, add eslint to devDependencies.


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

@ViewFromTheBox ViewFromTheBox moved this from Backlog to In Review in ArtisanPack UI Overview May 30, 2026
@ViewFromTheBox
ViewFromTheBox marked this pull request as ready for review May 30, 2026 23:45

@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/Http/Controllers/SiteController.php (1)

50-50: 💤 Low value

Simplify type hint to match route constraint.

The route constraint [A-Za-z0-9_-]+ ensures the $id parameter is always a string. The int|string union type is broader than necessary and could mislead readers about the actual runtime type.

♻️ Proposed refinement
-public function show( int|string $id ): JsonResponse
+public function show( string $id ): JsonResponse
🤖 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/Controllers/SiteController.php` at line 50, The show method's union
type hint int|string is broader than the route guarantee; update the
SiteController::show method signature to accept only string (change int|string
$id to string $id) and adjust any internal logic in show that assumes numeric
$id (e.g., casting or strict type checks) so it operates on a string input to
match the route constraint [A-Za-z0-9_-]+.
resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx (1)

79-93: ⚡ Quick win

Fix object spread order to prevent id parameter override.

In both helper functions, the current spread order { id, ...record } allows the record parameter to override the explicit id argument. While current test cases don't pass id in the record, this pattern could cause subtle bugs if future tests do. Reversing the spread order ensures the parameter always takes precedence.

♻️ Proposed fix
 function seedPostEntity(
     postType: 'post' | 'page',
     id: number,
     record: Record<string, unknown>,
 ): void {
     coreDispatch().receiveEntityRecords('postType', postType, [
-        { id, ...record },
+        { ...record, id },
     ]);
 }

 function seedSiteEntity(record: Record<string, unknown>): void {
     coreDispatch().receiveEntityRecords('root', '__unstableBase', [
-        { id: SITE_ENTITY_ID, ...record },
+        { ...record, id: SITE_ENTITY_ID },
     ]);
 }
🤖 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
`@resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx`
around lines 79 - 93, The seedPostEntity and seedSiteEntity helpers use object
spread in the order { id, ...record } which lets record.id override the explicit
id argument; change the spread order in seedPostEntity and seedSiteEntity to
merge record first and then id (i.e., ensure the explicit id takes precedence by
using record spread before id) so the passed id parameter cannot be overridden
by properties in record.
🤖 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 `@src/Resources/SiteMetaResolver.php`:
- Around line 130-139: The call to apGetMediaUrl() in resolveMediaUrl currently
can throw and crash requests; wrap the apGetMediaUrl($id) invocation in a
try-catch that catches \Throwable (or \Exception) and returns '' on error,
preserving the existing string return type; in the catch block optionally log or
trigger_error the exception using any available logger (or error_log) so
failures are recorded but do not propagate. Ensure resolveMediaUrl( ?int $id )
still returns '' when $id is null, when apGetMediaUrl is unavailable, or when an
exception is thrown.

---

Nitpick comments:
In
`@resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx`:
- Around line 79-93: The seedPostEntity and seedSiteEntity helpers use object
spread in the order { id, ...record } which lets record.id override the explicit
id argument; change the spread order in seedPostEntity and seedSiteEntity to
merge record first and then id (i.e., ensure the explicit id takes precedence by
using record spread before id) so the passed id parameter cannot be overridden
by properties in record.

In `@src/Http/Controllers/SiteController.php`:
- Line 50: The show method's union type hint int|string is broader than the
route guarantee; update the SiteController::show method signature to accept only
string (change int|string $id to string $id) and adjust any internal logic in
show that assumes numeric $id (e.g., casting or strict type checks) so it
operates on a string input to match the route constraint [A-Za-z0-9_-]+.
🪄 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: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: e9bf02c6-c06f-4bfe-bbce-12328958698e

📥 Commits

Reviewing files that changed from the base of the PR and between 476b698 and 0cb600c.

📒 Files selected for processing (16)
  • resources/js/visual-editor/blocks/_shared/__tests__/entity-placeholder-live-entity.test.tsx
  • resources/js/visual-editor/blocks/_shared/entity-placeholder-edit.tsx
  • resources/js/visual-editor/blocks/post-author/edit.tsx
  • resources/js/visual-editor/blocks/post-date/edit.tsx
  • resources/js/visual-editor/blocks/post-excerpt/edit.tsx
  • resources/js/visual-editor/blocks/post-featured-image/edit.tsx
  • resources/js/visual-editor/blocks/post-title/edit.tsx
  • resources/js/visual-editor/blocks/site-logo/edit.tsx
  • resources/js/visual-editor/blocks/site-tagline/edit.tsx
  • resources/js/visual-editor/blocks/site-title/edit.tsx
  • resources/js/visual-editor/vendor/__tests__/core-data-shim.test.tsx
  • resources/js/visual-editor/vendor/core-data-shim.ts
  • routes/api.php
  • src/Http/Controllers/SiteController.php
  • src/Resources/SiteMetaResolver.php
  • tests/Feature/VisualEditor/SiteControllerTest.php

Comment thread src/Resources/SiteMetaResolver.php
- Wrap apGetMediaUrl() in try/catch in SiteMetaResolver so a host
  media-library helper that throws doesn't crash the editor's
  site-meta fetch. Mirrors the defensive pattern in
  WpEntityResource::featuredImageEnvelope().
- Tighten SiteController::show signature from int|string to string —
  the {id} route is constrained to [A-Za-z0-9_-]+, so Laravel never
  hands the controller a numeric value.
- Reverse the spread order in the test seeders so an explicit `id`
  argument always wins over any `id` a future test might pass
  inside the record payload.
@ViewFromTheBox
ViewFromTheBox merged commit 1033a50 into release/1.0 May 30, 2026
4 checks passed
@github-project-automation github-project-automation Bot moved this from In Review to Done in ArtisanPack UI Overview May 30, 2026
@ViewFromTheBox
ViewFromTheBox deleted the feature/481-show-live-entity-values-in-editor branch May 30, 2026 23:57
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Development

Successfully merging this pull request may close these issues.

Show live entity values in the editor for the artisanpack/post-* and artisanpack/site-* forks

1 participant