Sync with upstream Ghost v6.27.0#63
Open
madewithlove-machine-user wants to merge 445 commits intomainfrom
Open
Sync with upstream Ghost v6.27.0#63madewithlove-machine-user wants to merge 445 commits intomainfrom
madewithlove-machine-user wants to merge 445 commits intomainfrom
Conversation
TryGhost#26869) ref https://linear.app/ghost/issue/HKG-1643/ The files upload endpoint accepted any file type without validation, unlike images and media which check extension and MIME type. With the move to a shared CDN domain, we don't want to upload files with executable content types. This commit adds: - An allowlist of supported file extensions (based on Ghost Pro data) - Extension-only validation middleware on the upload route - Content-type resolution that serves browser-renderable types (images, PDF, JSON, audio, video, fonts) with their natural type, overrides formats (HTML, JS, CSS, XML) to text/plain, and defaults everything else to application/octet-stream (forced download) - Users can zip unsupported file types as an escape hatch
ref https://linear.app/ghost/issue/BER-3414/ ## Summary - added a shared filter core for field definitions, field resolution, AST helpers, codecs, and NQL query compilation - moved the members list filter state, query translation, hydration, and bulk/export/search flows onto that shared core while keeping the existing `membersForward` rollout model unchanged - removed the legacy members filter config path and intentionally left the comments moderation runtime on its current implementation for follow-up work
no ref Iterative cleanup and improvements to the welcome email design customization modal (PRs TryGhost#26841, TryGhost#26842, TryGhost#26843). Fixes bugs found during review, removes dead code, adds missing functionality (image upload, Ghost badge toggle), and refactors the preview to be composable and visually consistent with the existing newsletter preview.
no ref
* Abstracted the translateCadence function to utils since we need it in
multiple places.
* Fixed two more places cadence wasn't wrapped for translations.
* Removed "{amountOff} off" string, since we are already using "{amount}
off" elsewhere.
Closes https://linear.app/ghost/issue/BER-3408/design-clean-up Minor changes to improve the visuals of the member import flow.
…a API (TryGhost#26837) closes https://linear.app/tryghost/issue/ONC-1553 - The `add()` method in `memberBREADService` passed the full `options` object (including `withRelated: ['labels', 'newsletters']`) to `setComplimentarySubscription()`. - When the Stripe customer had existing subscriptions, fetching related stripeSubscriptions with those options caused a "labels is not defined on the model" error on StripeCustomerSubscription models. - This fix uses `sharedOptions` (context + transacting only), matching the pattern already used for `linkStripeCustomer()`. --- ### Summary When creating a comped member via the Admin API with a `stripe_customer_id` pointing to a Stripe customer that has existing subscriptions, `setComplimentarySubscription()` received the full options object including `withRelated: ['labels', 'newsletters']`. Inside that method, `member.related('stripeSubscriptions').fetch(options)` attempted to eager-load `labels` on `StripeCustomerSubscription` models, which don't have that relation — throwing "labels is not defined on the model". ### Impact The bug's impact depends on the Stripe customer's existing subscriptions: - **Customer with a paid subscription + `comped: true`**: The comp conversion never runs. The member ends up with `paid` status instead of `comped`, and the API returns a 500. This is a real data issue — the member doesn't get their complimentary access. - **Customer with an existing comp subscription**: All database records are written correctly by `linkStripeCustomer()` before the error occurs, so the member is properly set up. However, the API still returns a 500 to the caller. - **Customer with no subscriptions**: The bug doesn't trigger because there are no `StripeCustomerSubscription` models to eager-load on. ### Fix Uses `sharedOptions` (only `context` + `transacting`) instead of the full `options` when calling `setComplimentarySubscription()` on line 406 of `member-bread-service.js`. This matches the pattern already established for the `linkStripeCustomer()` call on line 381. --------- Co-authored-by: Chris Raible <chris@ghost.org>
Closes https://linear.app/ghost/issue/BER-3451/make-sure-that-tier-names-in-the-table-truncate Tier names will now truncate and not break the layout of the table. | Before | After | |--------|--------| | <img width="504" height="331" alt="Screenshot 2026-03-19 at 14 14 45" src="https://github.com/user-attachments/assets/bced60d9-708a-4a21-a1c9-34341c309217" /> | <img width="452" height="335" alt="Screenshot 2026-03-19 at 14 14 26" src="https://github.com/user-attachments/assets/4495b68e-d25c-44ed-b8f0-2dd97172ab66" /> |
Closes https://linear.app/ghost/issue/BER-3452/use-sensible-operators-and-defaults-for-each-filter-type Makes sure we map to Ember for operators and improves Name and Email filters to use contains instead of is as a default for fuzzy searching.
The deploy-to-staging label was only checked inside the CI trigger_cd job which runs on push events. If a developer added the label after CI had already started, the deploy flag was missed and the CD pipeline ran as a dry run. This adds a dedicated workflow that fires on the label event itself (pull_request_target: labeled), waits for CI build artifacts to be ready, then dispatches to Ghost-Moya — the same pattern as the preview label. The existing trigger_cd label check is preserved so subsequent pushes to a labeled PR still auto-redeploy. Also adds CI-wait polling to the preview label workflow for consistency — previously it dispatched immediately on label addition, which could fail if CI hadn't finished pushing the GHCR image yet.
no refs This build artifact shouldn't be committed since it's generated as part of the build pipeline, but it wasn't included in `.gitignore`. This adds it to prevent anyone from accidentally committing it.
… format (TryGhost#26863) closes https://linear.app/ghost/issue/ONC-1560/re-unable-to-access-my-admin-site ## Summary - Bumps `@tryghost/image-transform` from 1.4.6 to 1.4.13, which upgrades Sharp from 0.34.2 to 0.34.5 - Adds `fontconfig` to the production Docker image (~7MB increase) ## Root Cause A customer uploaded an SVG favicon containing a `<text>` element. When Ghost tried to rasterize it to PNG (via the `/content/images/size/w256h256/format/png/` endpoint), Sharp's bundled librsvg needed fontconfig to resolve fonts for the text. Two problems: 1. **Sharp 0.34.2** (librsvg 2.60.0) **segfaults** when fontconfig is missing — killing the Ghost process instantly with no error log. Sharp 0.34.5 (librsvg 2.61.2) handles this gracefully. 2. **The production Docker image** (`node:22-bookworm-slim`) has no fontconfig installed, so even without the segfault, SVG `<text>` elements render as empty placeholders. This caused a **boot loop**: every page load triggered a favicon resize request → process crash → restart → crash again. ## Reproduction Confirmed segfault in a clean `node:22-bookworm-slim` container (same base as production): ``` $ docker run --rm node:22-bookworm-slim bash -c ' npm install sharp@0.34.2 && node -e " require(\"sharp\")(Buffer.from( \"<svg xmlns='http://www.w3.org/2000/svg'><text>A</text></svg>\" )).resize(256).png().toBuffer()"' Fontconfig error: Cannot load default config file: No such file: (null) Segmentation fault (exit 139) ``` Same test with `sharp@0.34.5` → succeeds (no segfault, but text renders as placeholder). Same test with `sharp@0.34.5` + `fontconfig` installed → succeeds with correct text rendering. ## Changes | Change | Why | |---|---| | Bump `@tryghost/image-transform` to 1.4.13 (Sharp 0.34.2 → 0.34.5) | Prevents segfault — librsvg 2.61.2 handles missing fontconfig gracefully instead of crashing | | Add `fontconfig` to `Dockerfile.production` runtime layer | Provides font resolution so SVG `<text>` elements render correctly (~7MB image size increase) | ## Test plan - [x] Verified Sharp 0.34.2 segfaults in `node:22-bookworm-slim` (no fontconfig) - [x] Verified Sharp 0.34.5 does not segfault in same environment - [x] Verified fontconfig survives the `build-essential` purge step in Dockerfile - [x] Verified correct SVG text rendering with fontconfig on staging preview - [x] Verified fontconfig adds ~7MB to production image size
no ref This scaffolding is needed before we can migrate over the browser tests to e2e.
The upstream Koenig packages have been migrated from JavaScript to TypeScript, which changes their module format and export structure. This update bumps all `@tryghost/kg-*` and `@tryghost/koenig-lexical` packages to their latest versions and adapts Ghost's codebase to work with the new builds: - Updated CJS `require()` calls to use `.default` where the TypeScript build uses default exports (`mobiledoc.js`, `json-to-html.js`, `email-renderer.js`, `markdown-renderer.js`, clean-basic-html util) - Fixed the `UnsplashSearchModal` `onImageInsert` prop to match the exported `InsertImagePayload` type from `kg-unsplash-selector` - Added `react/jsx-runtime` and `react-dom/server` as UMD globals in the Ember app route so Koenig UMD bundles resolve them at runtime - Increased test timeout for HTML conversion tests to accommodate slower first-run initialization of the new TypeScript-built packages Co-authored-by: Kevin Ansfield <kevin@lookingsideways.co.uk>
ref https://linear.app/ghost/issue/NY-1168/ - moved to single wrapper .hbs for emails (member welcome emails, newsletters); welcome emails brought into line with newsletters Ideally, we can use the same wrapper for all emailed content, leaving it to the consumer to adjust anything specific to the use case. This is a safer way to use the same styles to maintain behavior, and each 'component' (e.g. post header) should handle its own, compartmentalized behavior to not disrupt the whole. Transactional emails like the magic link do not use this currently, though it could be brought into this as we add further email customization options.
ref TryGhost/Ghost-CLI@8789d45 ref https://github.com/TryGhost/Ghost/actions/runs/23458645055/job/68254542127 ref https://github.com/TryGhost/Ghost/actions/runs/23458676095/job/68255159147 ref https://github.com/TryGhost/Ghost/actions/runs/23454981279/job/68242277911 Ghost-CLI was recently updated and requires a new Node version. We can remove some code from our CI job to achieve that.
refs https://linear.app/ghost/issue/ONC-1569/post-attribution-for-links-in-emails-seems-to-be-broken-on-pro closes https://linear.app/ghost/issue/ONC-1568/email-only-post-attribution-incorrectly-resolves-to-url-type-instead ## Problem Attribution for links in email-only posts does not correctly resolve to the post itself. For example, if a free member clicks a link in an email-only post they received, then upgrade to a paid membership within the same browser session, the newly created subscription should be attributed to the email only post. Currently though, the subscription would be attributed as a `url` and, depending on the link, the URL might be the `/email/:uuid` route of the post, or the Homepage. ## Root cause In `/ghost/core/core/server/services/member-attribution/url-translator.js`, Ghost had previously been filtering out email only posts, because the Post.findOne() query implicitly filters to only `published` posts, while an email-only post will have a status of `sent`. ## Fix Updated the query in the url-translator to filter for `status:[published,sent]` and `type:[post,page]`. With this change, the attribution correctly resolves to the `post` itself, rather than the generic `url`. There is also a change to the attribution builder to support this: since email only post's don't have a URL registered in the URL service, the `attribution_url` was being set to `null`. This adds a conditional to check if the post is email only, and if so, it sets the `attribution_url` to `/email/:uuid` for the post. Finally, it also updated the link on the members page to the post to point to the Post Analytics, rather than the post on the frontend. This change is made for regular `published` posts in addition to the `sent` posts for consistency. ### Files changed - **`url-translator.js`** — Added fallback `findOne` query with `status:sent` for email-only posts; added `/email/:uuid/` URL for sent posts - **`attribution-builder.js`** — Use `/email/:uuid/` URL when resolving attribution for email-only posts at read time
fixes https://linear.app/ghost/issue/BER-3447/add-global-search-next-to-filter-button-in-the-header Reintroduce the global search in the header, matching the Ember version of the members list
closes https://linear.app/ghost/issue/BER-3346/let-users-save-filtered-member-views Implemented the equivalent of post custom views for members on top of the existing hooks and state management we already had in place.
…26924) fixes https://linear.app/ghost/issue/BER-3464/prevent-sidebar-flicker-during-navigation-preference-updates Enabling the `keepPreviousData` flag ensures that query data won't cycle through `undefined` when the derived query re-evaluates.
…ryGhost#26778) closes [GVA-730](https://linear.app/ghost/issue/GVA-730/add-webhook-changes-behind-feature-flag) The `verificationFlow` feature flag now keeps the existing escalation email path as default while enabling a parallel webhook path through `VerificationTrigger` and `verification-webhook-service.ts`. This wires both strategies in `members/service.js` and adds tests to assert webhook payload behavior without regressing the legacy flow.
…#26891) closes https://linear.app/ghost/issue/BER-3441/ HTML-to-mobiledoc/lexical parse errors from `?source=html` requests are client input validation failures, not unexpected server errors. The explicit `sentry.captureException()` calls were reporting these to Sentry before re-throwing as `ValidationError` (422), causing excessive noise when integrations retry bad requests. The `ValidationError` alone is sufficient — clients get a proper 422 and Ghost's error middleware already knows not to report 4xx errors to Sentry.
no ref Some legacy sites incorrectly have object shaped shared views. This restores the previous fallback to [].
no ref - Added transistor labs flag to cardConfig via useFeatureFlag - Set visibilitySettings to 'none' to hide visibility panel in email context - Bumped @tryghost/koenig-lexical to 1.7.27
ref https://linear.app/ghost/issue/NY-1154/ - existing preview substitution was bolted-on to visibility gating, which was inappropriate; it is now its own step The intent of this change is to provide a pattern for subtituting content in the Preview pane in Admin > Post Editor. In this case, we substitute a user-specific iframe with a placeholder rather than using a real user's uuid and display a real user's content.
## Summary - migrate the portal donations browser coverage into top-level e2e as portal-support.test.ts - add the donation flow and page-object support needed to keep the new tests readable - remove the old ghost/core/test/e2e-browser/portal/donations.spec.js coverage ## Testing - cd e2e && yarn eslint helpers/pages/public/public-page.ts helpers/pages/stripe/fake-checkout-page.ts helpers/pages/portal/index.ts helpers/pages/portal/support-success-page.ts helpers/pages/portal/notification-page.ts helpers/playwright/flows/donations.ts helpers/playwright/flows/index.ts helpers/services/settings/settings-service.ts helpers/services/stripe/fake-stripe-server.ts tests/public/portal-support.test.ts - cd e2e && yarn test:types - cd /Users/slars/dev/ghost/Ghost/e2e && GHOST_E2E_SKIP_BUILD=1 yarn test tests/public/portal-support.test.ts
ref TryGhost#23361 Added two missing strings for the new retention offers. They were provided by a Pro customer.
no-issue
Static theme assets (/assets/*) and public assets (/public/*) were
always served from the origin, even when other content types like
images, media, and files already supported CDN base URLs. This meant
sites couldn't offload their heaviest cacheable resources to a
cookie-free CDN domain, hurting page load performance and increasing
request overhead from unnecessary session cookies.
Adding `urls:assets` completes the CDN story - sites can now serve all
static resources from a dedicated domain, matching the existing
pattern for `urls:image`, `urls:media`, and `urls:files`.
…ost#27197) ref https://linear.app/ghost/issue/BER-3484 After a gift is purchased, the `GiftService` sends a staff notification email to all admin / owner users with the purchaser info and amount
no ref - backfills empty i18n context hints in `context.json` - future PR will prevent empty hints from being added (TryGhost#27171)
ref TryGhost#1338 - Established the primitive composition layer, added primitive stories, and grouped Storybook navigation to prioritize primitives before higher-level abstractions.
The old pattern split the sentence "You've successfully subscribed to" into a fragment key with the site title appended outside the translated string. This meant translators couldn't reorder words around the site title. The new key uses @doist/react-interpolate to embed <strong> within a single translatable string, preserving existing translations.
no ref - We have CI checks to make sure that new i18n keys are added to context.json when they're generated, but there's no requirement to add any actual explanation for the key - This fixes that. When generate-context.js runs locally it will log a warning, but in CI it will error - This will apply to any i18n strings added from here on out - existing empty strings will be backfilled in TryGhost#27170
Closes https://linear.app/ghost/issue/DES-1339/tags-page-has-broken-togglegroup When the new tokens were added, surface-elevated was set to white which meant it wasn't indistinguishable from a white page/card/panel background. This tweaks adjusts its value to improve contrast. | Before | After | |--------|--------| | <img width="448" height="131" alt="Screenshot 2026-04-07 at 14 06 14" src="https://github.com/user-attachments/assets/54d878e7-29a5-4629-b088-bb00a2b51b43" /> | <img width="452" height="129" alt="Screenshot 2026-04-07 at 14 05 56" src="https://github.com/user-attachments/assets/ac85d433-ef73-4771-a035-cbcab41279e4" /> |
ref https://linear.app/ghost/issue/BER-3476 - added static UI for gift redemption for design team to continue with the UI, while engineers integrate with the backend. This uses mocked API responses that are temporary - the new page `#/portal/gift/redeem/<token>` is behind a feature flag: if flag is disabled, the gift redemption popup does not render
towards https://linear.app/ghost/issue/NY-1188 This change should have no user impact. It adds `welcome_email_automations` and `welcome_email_automated_emails` tables. These are split up from the existing `automated_emails` table with two additions in `welcome_email_automated_emails`: - `delay_days` - `next_welcome_email_automated_email_id` You may wish to review a diff between `automated_emails` and the new tables: ```diff diff --git a/j.js b/j.js index dded3c3..68070f4 100644 --- a/j.js +++ b/j.js @@ -1,8 +1,16 @@ -automated_emails: { +welcome_email_automations: { id: {type: 'string', maxlength: 24, nullable: false, primary: true}, status: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'inactive', validations: {isIn: [['active', 'inactive']]}}, name: {type: 'string', maxlength: 191, nullable: false, unique: true}, slug: {type: 'string', maxlength: 191, nullable: false, unique: true}, + created_at: {type: 'dateTime', nullable: false}, + updated_at: {type: 'dateTime', nullable: true} +}, +welcome_email_automated_emails: { + id: {type: 'string', maxlength: 24, nullable: false, primary: true}, + welcome_email_automation_id: {type: 'string', maxlength: 24, nullable: false, references: 'welcome_email_automations.id', constraintName: 'weae_automation_id_foreign', cascadeDelete: true}, + next_welcome_email_automated_email_id: {type: 'string', maxlength: 24, nullable: true, references: 'welcome_email_automated_emails.id', constraintName: 'weae_next_email_id_foreign', cascadeDelete: false}, + delay_days: {type: 'integer', nullable: false}, subject: {type: 'string', maxlength: 300, nullable: false}, lexical: {type: 'text', maxlength: 1000000000, fieldtype: 'long', nullable: true}, sender_name: {type: 'string', maxlength: 191, nullable: true}, @@ -10,9 +18,5 @@ automated_emails: { sender_reply_to: {type: 'string', maxlength: 191, nullable: true, validations: {isEmail: true}}, email_design_setting_id: {type: 'string', maxlength: 24, nullable: false, references: 'email_design_settings.id'}, created_at: {type: 'dateTime', nullable: false}, - updated_at: {type: 'dateTime', nullable: true}, - '@@indexes@@': [ - ['slug'], - ['status'] - ] + updated_at: {type: 'dateTime', nullable: true} }, ```
towards https://linear.app/ghost/issue/NY-1188 ref TryGhost#27183 We just added two new tables: `welcome_email_automations` and `welcome_email_automated_emails`. This adds dormant models for those, which are based on the existing `AutomatedEmail` model. **You may wish to review a diff of these with their associated `AutomatedEmail` counterpart, which will make these changes look much smaller.** For example, I ran these commands as part of self-review: ```sh vimdiff ghost/core/core/server/models/{automated-email,welcome-email-automation}.js vimdiff ghost/core/core/server/models/{automated-email,welcome-email-automated-email}.js vimdiff ghost/core/test/unit/server/models/{automated-email,welcome-email-automation}.test.js vimdiff ghost/core/test/unit/server/models/{automated-email,welcome-email-automated-email}.test.js ```
…bled (TryGhost#27191) closes https://linear.app/ghost/issue/NY-1197/use-design-settings-from-the-database-when-rendering-welcome-emails ## Summary - Updated the welcome email renderer to use custom design settings (background color, button style, header image, footer content, badge, etc.) from the database instead of hardcoded defaults - All new behavior is gated behind the `welcomeEmailsDesignCustomization` labs flag — existing welcome emails are unchanged when the flag is off - The service wrapper reinitializes when the labs flag changes, so toggling the flag takes effect without a restart ## Changes **Renderer** (`member-welcome-email-renderer.js`): - Reads `designSettings` and passes them through to `getEmailDesign()` (when flag is on) or uses hardcoded defaults (when flag is off) - Reuses `registerHelpers` and the newsletter styles partial for consistent rendering with newsletter emails - Passes header image, footer content, badge, and header title settings to the wrapper template **Service** (`service.js`): - Loads `emailDesignSetting` relation when fetching automated emails (flag-gated) - Caches design settings at load time alongside other email data - Wrapper class tracks labs flag state and reinitializes when it changes **Template** (`wrapper.hbs`): - Added `post-content-row` / `post-content` classes for newsletter-consistent content styling - Added conditional footer content, badge, and powered-by-Ghost sections
ref TryGhost#27087 ref https://linear.app/ghost/issue/PLA-18/ The above commit disabled the scheduling tests to patch a fix. In effect, we should never have the scheduler point to anything but an admin API endpoint. While the scheduler was kept flexible, at this point there doesn't seem to be a reason to not enforce more rigidity/safety. W/r to testing, it's difficult to test the full scheduling workflow. I've updated the tests to successfully emit the scheduler request - we don't ensure that the scheduler pushes a message back to Ghost, though we may be able to do that with a standalone SchedulerService in the future, or something of the like. Right now, Docker communication is difficult, and that's what caused the original issue.
closes https://linear.app/ghost/issue/NY-1164/add-ability-to-edit-sender-info-using-existing-verification-flow ## Summary Adds the ability for admins to customize sender name, email, and reply-to address for welcome emails, shared across both free and paid welcome email types. ## Changes ### Backend - New `PUT /automated_emails/senders/` endpoint to update `sender_name`, `sender_email`, and `sender_reply_to` across all welcome emails in a single call - New `PUT /automated_emails/verifications/` endpoint to verify pending email changes via single-use token (magic link) - `MemberWelcomeEmailService` now uses per-automated-email sender overrides when sending, falling back to newsletter/default settings - Email verification flow for `sender_reply_to` changes (uses existing `SingleUseTokenProvider`) - Test sends now also respect per-email sender overrides ### Frontend - New `useEditAutomatedEmailSenders` and `useVerifyAutomatedEmailSender` API hooks - `EmailPreview` component updated to show From/Reply-to in envelope header, with optional recipient/subject line visibility props - Member emails settings page handles `verifyEmail` query param on load, shows confirmation modal after successful verification ### Tests - E2E API tests for shared sender editing and token-based verification - Integration tests confirming sender overrides are applied when sending real and test welcome emails --------- Co-authored-by: Chris Raible <chris@ghost.org>
no issue - the `yarn.lock` file had become out of sync, causing it to update when running `yarn install` - this contains the up-to-date lockfile
This PR contains the following updates: | Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) | |---|---|---|---| | [human-number](https://redirect.github.com/Kikobeats/human-number) | [`2.0.8` → `2.0.9`](https://renovatebot.com/diffs/npm/human-number/2.0.8/2.0.9) |  |  | --- ### Release Notes <details> <summary>Kikobeats/human-number (human-number)</summary> ### [`v2.0.9`](https://redirect.github.com/Kikobeats/human-number/blob/HEAD/CHANGELOG.md#209-2026-04-03) [Compare Source](https://redirect.github.com/Kikobeats/human-number/compare/v2.0.8...v2.0.9) </details> --- ### Configuration 📅 **Schedule**: Branch creation - At any time (no schedule defined), Automerge - Only on Sunday and Saturday ( * * * * 0,6 ), Between 12:00 AM and 12:59 PM, only on Monday ( * 0-12 * * 1 ), Between 10:00 PM and 11:59 PM, Monday through Friday ( * 22-23 * * 1-5 ), Between 12:00 AM and 04:59 AM, Tuesday through Saturday ( * 0-4 * * 2-6 ) in timezone Etc/UTC. 🚦 **Automerge**: Enabled. ♻ **Rebasing**: Whenever PR is behind base branch, or you tick the rebase/retry checkbox. 🔕 **Ignore**: Close this PR and you won't be reminded about this update again. --- - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box --- This PR was generated by [Mend Renovate](https://mend.io/renovate/). View the [repository job log](https://developer.mend.io/github/TryGhost/Ghost). <!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xMDIuMTEiLCJ1cGRhdGVkSW5WZXIiOiI0My4xMDIuMTEiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbXX0=--> Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
…es (TryGhost#27185) towards https://linear.app/ghost/issue/NY-1188 ref TryGhost#27183 ref TryGhost#27184 Previous patches added new dormant tables and models. This change actually uses them. More specifically, this does a database migration to move `automated_emails` to `welcome_email_automations` and `welcome_email_automated_emails`. Then, it updates all relevant code to use those new tables. The old model is deleted, but the tables are not. (That's forthcoming.)
closes https://linear.app/ghost/issue/BER-3506/rework-feature-flagging-for-release Reworked `membersForward` to gate React rendering on `/members` instead of changing sidebar URLs. Added React support for `/members/import`, kept Ember fallback routes, prevented duplicate Ember rendering under the flag, and restored missing members access checks.
…#27205) ref https://linear.app/ghost/issue/BER-3484 The buyer now receives a transactional email with the gift redemption link, tier name, amount paid, cadence, and expiration date after a successful gift checkout. Follows the `comments-service` pattern with a dedicated `GiftEmailService` + `GiftEmailRenderer` and co-located `Handlebars` templates. Email delivery is best-effort (failures are logged but don't break the webhook handler)
ref https://linear.app/ghost/issue/ONC-1597/ - Webhook triggers now use `request-external` by default instead of `@tryghost/request` - Internal IP destinations can still be enabled with `security.allowWebhookInternalIPs` for self-hosted setups To allow webhooks to reach internal IP destinations, add to your Ghost config: ``` { "security": { "allowWebhookInternalIPs": true } } ``` Co-authored-by: Fabien O'Carroll <fabien@allou.is>
Closes https://linear.app/ghost/issue/DES-1309/welcome-emails-body-font-regression Koenig's styles were winning the specificity battle here. | Before | After | |--------|--------| | <img width="817" height="633" alt="Screenshot 2026-04-08 at 09 41 11" src="https://github.com/user-attachments/assets/a6d28510-af4a-418a-bb1d-34499b87fee4" /> | <img width="817" height="634" alt="Screenshot 2026-04-08 at 09 40 54" src="https://github.com/user-attachments/assets/a569a34e-fe6a-4070-851b-c6c175ad42d0" /> |
ref https://linear.app/ghost/issue/ONC-1595/ - shared path normalization across local storage reads and URL conversion so image path handling stays consistent
ref https://linear.app/ghost/issue/FEA-480/native-share-buttons-with-link-based-referral-param-for-attribution This PR adds a new small modal component to Portal that allows a reader to more easily share a post. It fires by adding #/share on any post link. The modal lets visitors copy the link to the post and share to top social platforms. --------- Co-authored-by: Troy Ciesco <tmciesco@gmail.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.
Syncing fork to upstream release
v6.27.0.