fix(publish): wire entry SEO title and description into the published <head> - #419
Merged
Conversation
… <head>
`seoTitle` and `seoDescription` are fully-built post-type fields, declared
in the default field set, seeded by both migration paths, and editable in
the Content settings panel. Neither reached the published page. An entry's
`<title>` always showed its plain title, and no `<meta name="description">`
was emitted at all.
Give `publishPage` a `documentMeta` override consumed by
`buildDocumentMetaTags`. Both entry render paths read the row's authored
values with `readEntrySeoOverride` and pass them there, so publish and the
Content editor's Live mode stay in parity. The override outranks the
site-level metaTitle / metaDescription, because a per-entry value is the
more specific choice. A blank field is not an override and still falls
through.
The override deliberately never touches `page.title`. `publishPage` feeds
that to `buildPageFrame`, so it is also the `{page.title}` binding, and an
SEO value assigned there renders inside the page body. `page.title` keeps
the entry's own title for both title bindings.
Co-authored-by: Aaron Sachs <898627+asachs01@users.noreply.github.com>
4 tasks
mostafasadeghidev
added a commit
to mostafasadeghidev/Instatic
that referenced
this pull request
Aug 22, 2026
…ompose CoreBunch#419 landed while this sat open and rewrote the same function. It gives `buildDocumentMetaTags` a `documentMeta` override so a post-type entry's authored `seoTitle` / `seoDescription` reach the published `<head>`. That is a different feature from this branch's, not a replacement. CoreBunch#419 answers "this row has its own title"; this answers "every row of this template shares one pattern". An author wants whichever suits the site, and on most sites both: a handful of rows worth naming individually, the rest covered by `{currentEntry.name} | Acme`. So the two compose rather than pick a winner. The fallback chain is upstream's — override → metaTitle → page.title → site.name — and whatever wins is then interpolated against the render context. A row's authored SEO title may itself carry tokens, which neither branch offered alone. 418 publisher tests green, covering both sides. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
mostafasadeghidev
added a commit
to mostafasadeghidev/Instatic
that referenced
this pull request
Aug 22, 2026
Seven files collided, and six of them for a happy reason: CoreBunch#348 merged, so upstream now carries this stack's own loop-filter code. Those took upstream's copy — which is ours plus what review added on top of it: `isCellComparableField` and `withoutCellFilter`, field pickers that hide fields a cell condition cannot address, clearer operator labels, and a dual-dialect test. `cellFilterMatches` went with it; nothing imported it. The seventh is `render.ts`, where CoreBunch#419 gave `buildDocumentMetaTags` a `documentMeta` override so an entry's authored SEO title reaches the `<head>`. That answers "this row has its own title"; the stack's CoreBunch#337 answers "every row of this template shares one pattern". Both are wanted, so the fallback chain is upstream's and whatever wins is then interpolated against the render context — a row's authored SEO title may itself carry tokens, which neither side offered alone. The README's pending table drops CoreBunch#348 into the landed section. Verified: tsc, build and lint clean; publisher and templates 505/505; fork-stack-capabilities 12/12. The remaining noise is Windows temp-file locking in test teardown, which reproduces on an untouched upstream checkout. Co-Authored-By: Claude Opus 5 <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.
The bug
Creating a post while the entries list was still loading left a nameless row in the Content sidebar. The entry saved correctly and the editor showed its "Untitled" placeholder, but the sidebar row rendered with only an author and a status. The same click worked most of the time, because which request finished first decided the outcome.
The fix
createUntitledEntrystores "Untitled" on the server but hands the editor a copy whose title is blank, so the title field shows its placeholder.loadEntriesmerged that editor copy back into the list whenever an in-flight load resolved after the create. The workspace now keeps the stored row alongside the editor view and rebuilds the list from the stored one. An MCP save, where the selection genuinely is the newer row, still merges as before.Verification
New coverage at unit and browser level, registered as CONTENT-009. Both hold the list response until the create lands, and both fail without the fix.