fix(core): RecentPosts widget links by slug and supports urlTemplate (#1332)#1899
fix(core): RecentPosts widget links by slug and supports urlTemplate (#1332)#1899swissky wants to merge 2 commits into
Conversation
…mdash-cms#1332) The widget hardcoded /posts/{post.id} — a ULID, which 404s against the default slug-based routes. Links now go through the shared buildLiveSearchResultUrl helper (slug with id fallback) and accept an optional urlTemplate prop with the same :collection/:id/:slug/:path tokens as LiveSearch routeMap, covering catch-all routing setups.
🦋 Changeset detectedLatest commit: 4a35b0d The changes in this PR will be included in the next version bump. This PR includes changesets to release 16 packages
Not sure what this means? Click here to learn what changesets are. Click here if you're a maintainer who wants to add another changeset to this PR |
@emdash-cms/admin
@emdash-cms/auth
@emdash-cms/auth-atproto
@emdash-cms/blocks
@emdash-cms/cloudflare
@emdash-cms/contentful-to-portable-text
emdash
create-emdash
@emdash-cms/gutenberg-to-portable-text
@emdash-cms/plugin-cli
@emdash-cms/plugin-types
@emdash-cms/registry-client
@emdash-cms/registry-lexicons
@emdash-cms/sandbox-workerd
@emdash-cms/x402
@emdash-cms/plugin-ai-moderation
@emdash-cms/plugin-atproto
@emdash-cms/plugin-audit-log
@emdash-cms/plugin-color
@emdash-cms/plugin-embeds
@emdash-cms/plugin-field-kit
@emdash-cms/plugin-forms
@emdash-cms/plugin-webhook-notifier
commit: |
There was a problem hiding this comment.
This PR takes the right approach to #1332: it fixes the core:recent-posts widget's hardcoded /posts/${id} link by routing it through the already-tested buildLiveSearchResultUrl helper, and it reuses the same :slug / :id / :path / :collection token vocabulary that LiveSearch's routeMap already uses. That's a clean, minimal change that matches the sibling component.
I read the widget code, the helper implementation and its unit tests, the widget registry (packages/core/src/widgets/components.ts), the admin widget form (packages/admin/src/components/Widgets.tsx), and the updated docs/changeset.
Headline finding: the new optional urlTemplate prop is declared on the Astro component but not added to the coreWidgetComponents registry in packages/core/src/widgets/components.ts. The admin UI renders prop fields from that registry (ComponentPropField iterates selectedComponent.props), so the prop is currently invisible to admin users. You also need to update the should return core widget components test in packages/core/tests/unit/widgets/widgets.test.ts to assert the prop exists.
Otherwise the change is solid: the helper coverage is already in place, the default /posts/{slug} behavior matches LiveSearch, and the changeset is appropriate.
| showThumbnails?: boolean; | ||
| showDate?: boolean; |
There was a problem hiding this comment.
[needs fixing] The new urlTemplate prop is declared on the component, but it is not registered in packages/core/src/widgets/components.ts under the core:recent-posts coreWidgetComponents entry. The admin UI builds the prop form from that registry (packages/admin/src/components/Widgets.tsx iterates selectedComponent.props), so this prop is currently invisible to admin users.
Add the prop definition there, e.g.:
urlTemplate: {
type: "string",
label: "URL template",
},Also update the should return core widget components test in packages/core/tests/unit/widgets/widgets.test.ts to assert that recentPosts?.props has the new urlTemplate property.
There was a problem hiding this comment.
Fixed in 4a35b0d — urlTemplate is now registered in coreWidgetComponents (type string, label "URL template (e.g. /blog/:slug)") so the admin prop form renders it, and the should return core widget components test asserts the new prop.
The admin widget form builds its inputs from coreWidgetComponents, so the prop was invisible to admin users without this registration.
What does this PR do?
Addresses the remaining half of #1332. The LiveSearch half was already fixed by #1387 (
routeMaptemplates); thecore:recent-postswidget still hardcoded its link as/posts/${post.id}— andpost.idis the ULID, not the slug, so the default link 404s against the standard/posts/[slug]routes even without catch-all routing.Changes:
buildLiveSearchResultUrlhelper: default stays/posts/{slug}(id fallback when a row has no slug), same behavior LiveSearch has.urlTemplateprop (passed via the widget'scomponentProps, e.g."/blog/:slug"or"/:slug"for catch-all sites) using the same:collection/:id/:slug/:pathtokens as LiveSearch'srouteMap— one template vocabulary for both components, per the issue's suggestion.No new helper, no new tests needed: the token interpolation and slug/id fallback are already covered by
tests/unit/components/live-search-routing.test.ts; the widget change is a thin wrapper over the tested helper.Type of change
Checklist
pnpm typecheckpassespnpm lintpassespnpm testpasses (or targeted tests for my change)pnpm formathas been runbuildLiveSearchResultUrlurlTemplateprop follows the maintainer-mergedrouteMappattern from [codex] Add LiveSearch route templates #1387 for the sibling componentAI-generated code disclosure
Screenshots / test output
n/a — link-shape change; before
/posts/01JXYZ…(404), after/posts/my-post-slug.