Skip to content

Conversation

@madewithlove-machine-user

Syncing fork to upstream release v6.11.0.

9larsons and others added 30 commits December 1, 2025 20:43
ref https://linear.app/ghost/issue/NY-736/
ref https://linear.app/ghost/issue/NY-738/
- removed UTM dropdown from Web tab (stats and posts apps)
- added stats filter component (behind UTM labs flag)
- wired up new filters, updated endpoints to support all values
- added filter sync logic between Web and Locations tabs for Audience
filters

It became clear that UTMs require a different approach when wanting to
analyze the data. Rather than seeing which values were used for a
specific page, it could often be more instructive to see where the user
went *when* they arrived with a certain set of values, as UTM fields are
all about identifying how users got to a particular site (e.g. ad or
email campaign).

We removed the old dropdown from the Web tab and created new filters
that allow you to search and filter via Post, Source, Audience, and the
various UTMs, as well as combine filters. For now, it's a more naive
search with support for a single value and 'is equal to' logic. We'll
look to expand this as we explore more use cases. We're less interested
in allowing a full data slicer and want to be more intentional about
providing what's sensible within the context.
no ref

When trying to run e2e tests locally, the Tinybird container was
sufficiently slow such that the script failed. I've added a retry
mechanism to improve resiliency.
ref
TryGhost@cc4eee9

We changed the UTM implementation and didn't disconnect the tests. I
need to look in to why this didn't block the ref'd commit/PR merge. I'm
skipping these tests as we'll be coming back through and want to cover
similar cases.
ref https://linear.app/ghost/issue/PRO-1538

The PutObjectCommand doesn't play well with streams on GCS as
there are some incompatibilities with signatures.

By using `readFile` we can pull the whole file into a buffer in memory
and upload it in a single chunk - which fixes the errors. This does
increase the memory footprint with larger files, but it unblocks e2e
testing for now, we're working on a chunked multi-part upload which
will supercede this.
ref https://linear.app/ghost/issue/NY-722/migrate-ghost-codebase-to-kebab-case-file-naming-convention

* Renamed all files to match to kebab-case format
* Added ESLint kebab-case rule
* To match our working agreement on filenames in Ghost repo
ref TryGhost/Ghost-Release#122

- having a prefix allows our release script to ignore failed steps when deciding if commit status is green and makes status clearer for anyone viewing job status in GitHub
ref https://linear.app/ghost/issue/NY-722/migrate-ghost-codebase-to-kebab-case-file-naming-convention

* Renamed folders to match to kebab-case format
* To match better our working agreement on filenames in Ghost repo
Changelog for v2.56.1 -> 2.56.2:
  - Updated i18n translations
  - [Auto-submit OTC code when all 6 digits are pasted or
typed](TryGhost@56ea3fffde)
refs https://linear.app/ghost/issue/BER-3077/improve-e2e-testing-integration

The yarn dev:forward analytics integration was incomplete. These changes ensure
we're properly configuring the necessary environment variables.
no ref

We have had a lot of iterations on development setup for our
analytics/Tinybird configuration. We've recently improved the `yarn
dev:analytics` script with some other improvements to the `yarn dev`
script (in the form of dev:forward for now). This PR cleans up all the
various ways of generating tests data with the intended flow being:

- `yarn dev:analytics` to spin up dev server(s), including Tinybird
local
- `yarn data:analytics:generate` to build data based on the Ghost db
content; this could be seeded with `yarn reset:data` or our
data-generator script
- `yarn data:analytics:clear` to reset the data in Tinybird (truncates
the db)
ref https://linear.app/ghost/issue/NY-787/
- added Koenig editor to welcome emails modal

This editor allows the user to manipulate the content of the email.
However, this isn't wired up to anything while we're waiting for the
persistence changes to be merged.
ref
https://linear.app/ghost/issue/NY-770/create-a-database-migration-to-add-automated-emails-table

## What

This PR adds a new table to Ghost's database, called `automated_emails`.
It also adds a new Claude Code "skill," which provides Claude Code with
instructions on how to create a database migration using the slimer CLI
tool.

## Why

We are working on adding welcome emails for new members to Ghost.
Currently Ghost can be configured to send a welcome email to members as
soon as they sign up, but the content of the welcome email is hardcoded.

Our next step is to allow users to update the content in the welcome
email, including the subject and body of the email. This table is where
we'll store the content of the welcome email, and any other future
automated emails we may add to Ghost.
ref https://linear.app/ghost/issue/NY-771

This model enables CRUD operations on the automated_emails table, which
will store customizable welcome email content for new members. Includes
URL transformation for the lexical field to handle __GHOST_URL__
placeholders consistently with other models like posts.
… outbox (TryGhost#25521)

ref https://linear.app/ghost/issue/NY-805

- this makes it so the welcome emails job works similar to the email
analytics job, in that it just emits a `StartMemberWelcomeEmailJobEvent`
- The `MemberWelcomeEmailsService` subscribes to that event and then
processes the outbox
- This had a positive improvement on CPU utilization, most
visible/useful for app servers running many Ghost instances;
TryGhost#25534 will further improve it by
randomizing when the job starts for each instance
ref https://linear.app/ghost/issue/PRO-1538

- GCS doesn't support AWS streaming signature format, causing uploads to
fail with SignatureDoesNotMatch. This can be fixed by using buffer
instead of stream for uploads. But this will cause memory issues for
large files
- This commit implements a multipart upload for files > 10MB(Configurable)
- Small files (<10MB): Use buffer upload (fs.readFile)
- Large files (≥10MB): Use S3 multipart upload API for memory
efficiency. Multipart uploads read file in 10MB chunks, keeping RAM
usage constant
- Added automatic cleanup with AbortMultipartUpload on errors
- Multipart upload is S3-standard and works with both AWS S3 and GCS
ref TryGhost#23361

The German locale was lacking a couple of translations (mostly phrases
related to the new verification code for member logins). As a native
German speaker and freelance dev with German clients, it made sense for
me to add these translations to the Ghost repo, so that everyone could
profit from it.

---------

Co-authored-by: Cathy Sarisky <42299862+cathysarisky@users.noreply.github.com>
ref https://linear.app/ghost/issue/BER-3096

We observed a lot of flakiness when running multiple workers on a single
CI e2e test runner. This change-set makes test worker counts depend on
an environment variable, and sets that variable to 1 on CI which reduces
the worker count.

In order to maintain CI test run durations, we increased the shards in
the e2e matrix to 4.
…5596)

ref https://linear.app/ghost/issue/NY-693/
- updated middleware to pass through query/search params with path

With web analytics data, we need to pass through query parameters like `utm_campaign`. This is true of other parts of Ghost, though to a lesser extent (e.g. click tracking).
)

ref https://linear.app/ghost/issue/NY-799/
- removed naive 'outlier' logic from summations

Our YTD and monthly summaries were excluding days of high traffic
(>10k). I don't recall why this check was in here, and it's not
something we should have.
ref no-issue

- Ghost redirects paths not ending with `/`. This avoids the redirect.
* Fixed member signup test that was failing on welcome email when member signs up
* The solution was to use blog title as a from name, instead of generic Ghost name that was used before
ref https://linear.app/ghost/issue/BER-3070

This PR re-introduces the network app notification badge to the new
sidebar. It displays conditionally when count > 0 and the network app
isn't open, matching the previous Ember behaviour.
…5599)

ref https://app.incident.io/ghost/incidents/220
ref TryGhost#25590

- during incident INC-120, we noticed duplicate requests to the
ActivityPub site registration endpoint (`./ghost/activitypub/v1/site`)
on Ghost (Pro)
- Ghost (Pro) redirects requests without a trailing slash to the
trailing slash version. Adding the trailing slash in the code avoids the
unnecessary redirect
…TryGhost#25605)

ref https://linear.app/ghost/issue/NY-377/

For various reasons, we had a few different implementations of the
'member sources is disabled'. This commit unifies them to a common
component.

Because we need to use framework and shade, we had to duplicate the
component. This will be remediated when we eventually combine these
apps.
Changelog for v2.56.2 -> 2.56.3:
  - Updated i18n translations
ibalosh and others added 28 commits December 18, 2025 14:58
- Added checks for replies and show more replies
- Added check comments, sort comments by newest, oldest, load more
- Added comments factory
no issue

- using `undefined` creates `EMPTY` values instead of `NULL` meaning our API queries to fetch top-level comments fail to find any comments
no ref

We have a couple snapshot tests that are dependent on the real date
(e.g. 2026) that are failing on main/branches since the new year. These
tests are now stubbed.
)

ref https://linear.app/ghost/issue/ONC-1165/
fixes TryGhost#24963
- ghost_head falls back to first listed collection when there's
multiple, non-index collections in routes.yaml

Previously, ghost_head would generate an empty href="" attribute in the
RSS meta tag when routes.yaml contained multiple collections but none at
the root path (/), causing broken feed discovery.

Logic for the rss link tag in ghost_head is now:
- Index collection (/) if it exists and has RSS enabled
- Single collection's RSS if only one collection exists
- First collection with RSS enabled when multiple collections exist
- null if no collections have RSS enabled
ref TryGhost#23361

Words and phrases in Portuguese have been added.

---


Co-authored-by: Cathy Sarisky <42299862+cathysarisky@users.noreply.github.com>
)

ref TryGhost/ActivityPub#1487

Added ActivityPub routing and HMR support for external domains
closes https://linear.app/ghost/issue/NY-804

- The settings UI allows publishers to enable and configure a paid
welcome email (with a flag enabled), but Ghost doesn't actually send the
welcome emails for new paid members.
- This adds the functionality to send the paid welcome emails for newly
created paid members, and members upgrading from a free account to a
paid plan.
ref https://linear.app/ghost/issue/BER-3095

- Extracted the public files code from the middleware to the router.
This avoids route comparison on every requests Ghost receives.
no issue

- problem: users are entering invalid values like "English" for publication locale
- solution: replaced text input with a new SelectWithOther component to prevent invalid locale entries. Users can select from 64 predefined locales or enter custom BCP 47 compliant codes via "Other" option.

Implementation details:
- Added SelectWithOther component to admin-x-design-system that provides
a dropdown with an "Other..." option that switches to a text input
- Added locale validation utility with support for BCP 47 language tags
- Added LOCALE_DATA to @tryghost/i18n with human-readable labels
- Created ESM entry point for i18n to support admin-x apps imports
- Added comprehensive unit and E2E tests
Changelog for v1.2.6 -> 1.3.0:
- [Added comment permalinks support behind alpha labs flag](TryGhost@3df0e8c3f7)
…host#25790)

This reverts commit 15bd6a4.

The automatic publish failed due to an invalid "repository" field in
apps/comments-ui/package.json. Reverting so we can fix and then
re-release.
…ost#25792)

no issue

npm with trusted publisher setup requires the `repository` field to
match provenance, when set to a git/ssh URL publishing results in an
error such as:

```
 Failed to validate repository information: package.json: "repository.url" is "git+ssh://git@github.com/TryGhost/comments-ui.git", expected to match "https://github.com/TryGhost/Ghost" from provenance
```
Changelog for v1.2.6 -> 1.3.0:
- [Added comment permalinks support behind alpha labs flag](3df0e8c)
ref TryGhost#25794

- switched to version that includes comment permalink support
closes https://linear.app/ghost/issue/NY-788

- Adds the ability to send a test of member welcome emails in a similar
manner to email previews on posts
- Includes brute protection on the endpoint, same as for posts. It's
(currently) also in the same bucket as posts (i.e. if you send 10 test
welcome emails and then try to send a post email preview you'd get rate
limited)
- Utilizes edit permissions for `sendTestEmail` - where edit and
sendTestEmail can be pretty distinct on posts depending the permissions
of the staff user, in the case of member welcome emails the concepts are
pretty tightly coupled (and only admins have permission anyway)
…host#25788)

closes https://linear.app/ghost/issue/NY-861

- if the Ghost site doesn't have Stripe connected, we shouldn't show the
toggle/editor for paid member welcome emails
- This PR shows the option if Stripe is connected, hides it if it isn't
- We shouldn't need to worry about checking this elsewhere (i.e. in the
outbox logic) because a paid member can't sign up if Stripe isn't
connected
This PR contains the following updates:

| Package | Update | Change |
|---|---|---|
| ghost/traffic-analytics | patch | `1.0.23` → `1.0.25` |

---

### 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 ) in timezone Etc/UTC.

🚦 **Automerge**: Disabled by config. Please merge this manually once you
are satisfied.

♻ **Rebasing**: Never, 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:eyJjcmVhdGVkSW5WZXIiOiI0Mi42OS4xIiwidXBkYXRlZEluVmVyIjoiNDIuNjkuMSIsInRhcmdldEJyYW5jaCI6Im1haW4iLCJsYWJlbHMiOltdfQ==-->

Co-authored-by: renovate[bot] <29139614+renovate[bot]@users.noreply.github.com>
no issue

- Pingomatic is a legacy blog ping service that notified external services
when posts were published. It is no longer relevant for modern SEO or
content distribution
- The service was disabled by default and added unnecessary complexity to
the codebase
ref https://linear.app/ghost/issue/BER-3132

- The `require('@tryghost/errors')` adds 50-100ms on boot time, this is
due to the package's own initialization and `require()`. Since it's not
needed at boot, it can be moved inside the `beforeSend` function.
…gth (TryGhost#25798)

ref https://linear.app/ghost/issue/FEA-479/

Gmail and other email clients will clip an email when it exceeds a certain size (typically ~100KB), hiding content and potentially breaking layouts. To help avoid this we've added warnings to indicate your email is close to the clipping limit.

When a post's email reaches 100kb or more, a warning will be shown in the following areas:
- bottom right corner of the editor
- email preview screen
- publishing flow

This is a warning only and has no impact on the email or ability to publish.
ref https://linear.app/ghost/issue/BER-3150/

Previously the session creation endpoint accepted a `skipEmailVerification` property with an intended purpose of allowing the 2FA flow to be bypassed in the login immediately following a password reset, reducing friction in the UX considering a password reset is only possible via email and therefore considered already email-verified. Although Ghost's Admin client followed the expected usage and only used the property on the password reset authentication, the basic nature of the property meant anyone could manually add it to a session creation API request to bypass 2FA.

- removed `skipEmailVerification` implementation
- updated `/authentication/password_reset/` endpoint to generate an OTP after successful reset and return it as an `emailVerificationToken` property in the response
- updated `/session` endpoint to accept a `token` property alongside the username/password, and mark the session as verified if the `token` contains a valid OTP
- updated Admin client's password reset flow to use `emailVerificationToken` and `token` respectively to bypass 2FA when creating a session after password reset

This updated flow removes the blanket 2FA bypass by requiring a valid OTP which can only be obtained via the normal email path after unverified sign-in or a successful password reset.

Credit:

Sho Odagiri
GMO Cybersecurity by Ierae, Inc.
)

Validated postId as an ObjectID before using it in database queries. This ensures we are not passing arbitrary SQL strings and limits the postId variable to a string format we expect.

- Extracted postId parsing to separate getPostIdFromFilter method
- Used ObjectID ValueObject for type safety and validation
- Added unit tests for the extraction method

Credit:

Sho Odagiri
GMO Cybersecurity by Ierae, Inc.
ref https://linear.app/ghost/issue/BER-3159/

- a malicious staff user could craft URLs for media assets in a post that could potentially access/exfiltrate data from internal URLS when run through the media inliner
- switching the request library used by `ExternalMediaInliner` to our restricted `externalRequest` library blocks any requests to servers that resolve to an internal IP block, limiting any SSRF exfiltration to publicly served data

Credit:

Sho Odagiri
GMO Cybersecurity by Ierae, Inc.
…ryGhost#25805)

refs TryGhost#23585

The staff token blocklist checked for `/db/` and `/users/owner/` with trailing slashes, but Express routes accept both `/db` and `/db/`. Requests without the trailing slash bypassed the security check entirely, allowing staff tokens to delete all content or transfer site ownership.

Co-authored-by: Fabien O'Carroll <fabien@allou.is>

Credit:

Sho Odagiri
GMO Cybersecurity by Ierae, Inc.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.