Skip to content

[pull] main from TryGhost:main - #1515

Merged
pull[bot] merged 11 commits into
code:mainfrom
TryGhost:main
Sep 25, 2026
Merged

pull[bot] merged 11 commits into
code:mainfrom
TryGhost:main

Conversation

@pull

@pull pull Bot commented Sep 25, 2026 •

Copy link
Copy Markdown

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

acburdine and others added 11 commits September 25, 2026 02:58
no ref

v4 and v5 were ESM-only, which blocked earlier upgrade attempts; v6 ships a CommonJS build again. v6 replaced extract()'s fetch-options argument with a fetcher function, which lets oEmbed provider requests go through request-external's SSRF protection instead of the library's own HTTP client. A new externalRequest.fetch wraps the Got instance in a fetch-compatible API for this.

The extractOembed helper passes the abort signal and Ghost's own user agent (the same allowlisting reason as 571eb68), validates provider data with a loose Zod schema, and strips the `method` field v6 adds so card payloads stay unchanged. The version now lives in the pnpm catalog. v6's stricter scheme matching resolves bare youtube.com URLs through the www fallback, so the YouTube live-URL tests now expect the www form.
no ref

Cleanup: members, labels, offers, tiers, settings, integrations, themes and the dashboard moved to React.
)

no ref

The e2e page object for the React post editor could only reach five settings fields. This gives it the whole sidebar, the header and the feature image, so browser specs for the sidebar can be written as a sequence of gestures without touching the page object again.
no ref

Deleting a single post (`DELETE /posts/:id/`) keeps its `emails` and `email_recipients` rows. Bulk deleting posts (`DELETE /posts/?filter=...`, which also works for a single post) deleted the email along with its batches, recipients, recipient failures and spam complaint events, and nulled `suppressions.email_id`.

The two paths disagreed without a reason: `emails.post_id` has no foreign key, so nothing requires the email to go with the post. The deletion came in with the original bulk destroy API (#16587) as clean-up, and single delete has always left the email in place.

It matters because the `emails` host limit counts sends from `emails.email_count`, so bulk deleting sent posts reset a site's usage for the period. Bulk delete now matches single delete and keeps the email data.

**Tests**
- New `test/e2e-api/admin/posts-delete-email-data.test.ts` covers both paths: the email row and `email_count`, its batches, recipients, recipient failures, spam complaint events and linked suppression all survive deleting a sent post. The bulk case fails on `main`.
- `posts-bulk.test.js` (18) and posts unit tests (87) still pass.

**Side effect:** bulk-deleted sent posts now leave orphaned email rows, the same as single deletes already do.
ref https://linear.app/ghost/issue/PLA-408

The Cmd-K modal stays mounted after it closes and kept its last term, so the search index queries stayed active while search was closed. Every later save that invalidated posts, pages, tags or staff then re-downloaded those lists in the background. After opening a post from search, for example, each editor autosave re-fetched up to 10,000 posts plus all tags.
no ref

The React editor builds its session in a `useState` initializer, which StrictMode runs twice in development and discards one result without `dispose()`. That is only safe while construction starts nothing. This is now tested.
)

no ref

The verification trigger counts members added in the last 30 days, but a member's created event is deleted with the member. A site could add members, send them a newsletter, then delete them (or change their addresses) and repeat, emailing far more people than it ever kept as members without the trigger or the member limit noticing.

Newsletter recipients are kept after a member is deleted, so before each newsletter send the trigger now counts recent recipients whose address no longer belongs to a member, and starts verification once that passes `hostSettings.emailVerification.removedRecipientsThreshold`. Matching on address catches changed emails as well as deletions.

The check only runs on unverified sites that set the threshold, skips the recipients query when the site hasn't sent that many emails in the window, and stops counting at the threshold, so large sites don't pay for it.
…30986)

no ref

The embed renderer is now deployed to `public.ghostembeds.com`, so sites
no longer need to opt in to isolating embed card previews from Admin's
origin.

- defaults `security.embedPreviewUrl` to
`https://public.ghostembeds.com/`
- sites can still point at another renderer, or set it to `""` to
restore same-origin previews (editors treat an empty value as unset)
- config API snapshot updated for the new key
no ref

Expanded test coverage for the Access sections in the React Editor sidebar.
no ref

`pnpm reset:data` and related scripts were failing when we removed the build step from `pnpm dev`, meaning fresh worktrees/clones could fail or use dated built files. This resolves that.
@pull pull Bot locked and limited conversation to collaborators Sep 25, 2026
@pull pull Bot added the ⤵️ pull label Sep 25, 2026
@pull
pull Bot merged commit 75e2b7d into code:main Sep 25, 2026
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants