Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
4d96dbf
Refined visual design and copy of gift purchase confirmation email (#…
minimaluminium Apr 9, 2026
c92425f
Updated SDK Packages (#27290)
vershwal Apr 9, 2026
24a6081
Added tier and cadence to gift purchase staff notification email (#27…
minimaluminium Apr 9, 2026
0de511b
Update TryGhost test support packages (#27266)
renovate[bot] Apr 9, 2026
46c23fb
Update dependency @playwright/test to v1.59.1 (#27277)
renovate[bot] Apr 9, 2026
7c1b796
Update dependency lint-staged to v16 (#27285)
renovate[bot] Apr 9, 2026
4f95056
Update dependency lodash-es to v4.17.23 [SECURITY] (#27292)
renovate[bot] Apr 9, 2026
e45d470
Improve performance of core acceptance/legacy CI jobs (#27293)
acburdine Apr 9, 2026
9505bac
Fixed redundant CI runs on main branch pushes (#27295)
ErisDS Apr 9, 2026
71409d9
Update dependency storybook to v8.6.15 [SECURITY] (#27172)
renovate[bot] Apr 9, 2026
edb9bb7
Update dependency lodash to v4.17.23 [SECURITY] (#27296)
renovate[bot] Apr 9, 2026
0bb0912
Update dependency fs-extra to v11.3.4 (#27298)
renovate[bot] Apr 9, 2026
948a290
Update dependency gscan to v5.4.1 (#27299)
renovate[bot] Apr 9, 2026
e2cb757
Update dependency nwsapi to v2.2.23 (#27300)
renovate[bot] Apr 9, 2026
191095a
Update dependency globals to v17 (#27301)
renovate[bot] Apr 9, 2026
c6f98c7
Added optional share link in newsletter email templates (#26867)
peterzimon Apr 9, 2026
8901578
Added `show_header_icon` column to email design settings table (#27249)
cmraible Apr 9, 2026
905379e
Made `expires_at` on `gifts` non-nullable (#27312)
mike182uk Apr 9, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 4 additions & 25 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@ env:
${{ github.workspace }}/ghost/*/node_modules
${{ github.workspace }}/e2e/node_modules
~/.cache/ms-playwright/
NX_REJECT_UNKNOWN_LOCAL_CACHE: 0
NODE_VERSION: 22.18.0
# Disable v8-compile-cache to prevent intermittent V8 deserializer crashes
# when multiple parallel Nx workers race to read/write shared bytecode cache
Expand All @@ -31,7 +30,7 @@ env:
DISABLE_V8_COMPILE_CACHE: 1

concurrency:
group: ${{ github.head_ref || github.run_id }}
group: ${{ github.head_ref || github.ref }}
cancel-in-progress: true

jobs:
Expand Down Expand Up @@ -164,17 +163,6 @@ jobs:
echo "dep-cache" >> "$GITHUB_ENV"
echo "$EOF" >> "$GITHUB_ENV"

- name: Nx cache
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
id: cache_nx
with:
path: .nxcache
key: nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT }}
restore-keys: |
nx-Linux-${{ github.ref }}-${{ env.HEAD_COMMIT }}
nx-Linux-${{ github.ref }}
nx-Linux

- name: Check dependency cache
uses: actions/cache@668228422ae6a00e4ad889ee87cd7109ec5666a7 # v5
id: cache_dependencies
Expand Down Expand Up @@ -450,9 +438,6 @@ jobs:
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}

- name: Build TS packages
run: yarn nx run-many -t build --exclude=ghost-admin

- name: Set timezone (non-UTC)
uses: szenius/set-timezone@1f9716b0f7120e344f0c62bb7b1ee98819aefd42 # v2.0
with:
Expand All @@ -470,12 +455,10 @@ jobs:
echo "database__connection__password=root" >> $GITHUB_ENV

- name: E2E tests
working-directory: ghost/core
run: yarn test:ci:e2e
run: yarn nx run ghost:test:ci:e2e

- name: Integration tests
working-directory: ghost/core
run: yarn test:ci:integration
run: yarn nx run ghost:test:ci:integration

- uses: actions/upload-artifact@bbbca2ddaa5d8feaa63e36b76fdaad77386f024f # v7
if: matrix.node == env.NODE_VERSION && contains(matrix.env.DB, 'mysql')
Expand Down Expand Up @@ -540,9 +523,6 @@ jobs:
env:
DEPENDENCY_CACHE_KEY: ${{ needs.job_setup.outputs.dependency_cache_key }}

- name: Build TS packages
run: yarn nx run-many -t build --exclude=ghost-admin

- name: Set env vars (SQLite)
if: contains(matrix.env.DB, 'sqlite')
run: echo "database__connection__filename=/dev/shm/ghost-test.db" >> $GITHUB_ENV
Expand All @@ -555,8 +535,7 @@ jobs:
echo "database__connection__password=root" >> $GITHUB_ENV

- name: Legacy tests
working-directory: ghost/core
run: yarn test:ci:legacy
run: yarn nx run ghost:test:ci:legacy

- uses: tryghost/actions/actions/slack-build@0cbdcbeb9030f46b109d5e6e44c14933026d8ca5 # main
if: failure() && github.event_name == 'push' && github.ref == 'refs/heads/main'
Expand Down
2 changes: 1 addition & 1 deletion apps/activitypub/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"preview": "vite preview"
},
"devDependencies": {
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@testing-library/react": "14.3.1",
"@types/dompurify": "3.2.0",
"@types/jest": "29.5.14",
Expand Down
4 changes: 2 additions & 2 deletions apps/admin-x-design-system/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -48,14 +48,14 @@
"eslint-plugin-react-refresh": "0.4.24",
"eslint-plugin-tailwindcss": "4.0.0-beta.0",
"jsdom": "28.1.0",
"lodash-es": "4.17.21",
"lodash-es": "4.17.23",
"postcss": "8.5.6",
"postcss-import": "16.1.1",
"react": "18.3.1",
"react-dom": "18.3.1",
"rollup-plugin-node-builtins": "2.1.2",
"sinon": "18.0.1",
"storybook": "8.6.14",
"storybook": "8.6.15",
"tailwindcss": "4.2.1",
"typescript": "5.9.3",
"validator": "13.12.0",
Expand Down
10 changes: 5 additions & 5 deletions apps/admin-x-settings/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -40,22 +40,22 @@
},
"dependencies": {
"@codemirror/lang-html": "6.4.11",
"@tryghost/color-utils": "0.2.10",
"@tryghost/color-utils": "0.2.16",
"@tryghost/i18n": "0.0.0",
"@tryghost/kg-unsplash-selector": "0.3.24",
"@tryghost/limit-service": "1.4.1",
"@tryghost/limit-service": "1.5.2",
"@tryghost/nql": "0.12.10",
"@tryghost/timezone-data": "0.4.12",
"@tryghost/timezone-data": "0.4.18",
"react": "18.3.1",
"react-dom": "18.3.1",
"validator": "13.12.0"
},
"devDependencies": {
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@testing-library/react": "14.3.1",
"@tryghost/admin-x-design-system": "0.0.0",
"@tryghost/admin-x-framework": "0.0.0",
"@tryghost/custom-fonts": "1.0.2",
"@tryghost/custom-fonts": "1.0.8",
"@tryghost/shade": "0.0.0",
"@types/react": "18.3.28",
"@types/react-dom": "18.3.7",
Expand Down
2 changes: 1 addition & 1 deletion apps/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
"eslint-plugin-react-hooks": "5.2.0",
"eslint-plugin-react-refresh": "0.4.24",
"eslint-plugin-tailwindcss": "4.0.0-beta.0",
"globals": "16.5.0",
"globals": "17.4.0",
"jest-extended": "6.0.0",
"jsdom": "28.1.0",
"sirv": "3.0.2",
Expand Down
4 changes: 2 additions & 2 deletions apps/announcement-bar/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tryghost/announcement-bar",
"version": "1.1.14",
"version": "1.1.15",
"license": "MIT",
"repository": "https://github.com/TryGhost/Ghost",
"author": "Ghost Foundation",
Expand All @@ -14,7 +14,7 @@
"registry": "https://registry.npmjs.org/"
},
"dependencies": {
"@tryghost/content-api": "1.12.0",
"@tryghost/content-api": "1.12.6",
"react": "17.0.2",
"react-dom": "17.0.2"
},
Expand Down
4 changes: 2 additions & 2 deletions apps/comments-ui/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tryghost/comments-ui",
"version": "1.4.3",
"version": "1.4.4",
"license": "MIT",
"repository": "https://github.com/TryGhost/Ghost",
"author": "Ghost Foundation",
Expand Down Expand Up @@ -60,7 +60,7 @@
"react-string-replace": "1.1.1"
},
"devDependencies": {
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@testing-library/jest-dom": "5.17.0",
"@testing-library/react": "12.1.5",
"@testing-library/user-event": "14.6.1",
Expand Down
2 changes: 1 addition & 1 deletion apps/shade/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -92,7 +92,7 @@
"eslint-plugin-storybook": "10.3.3",
"eslint-plugin-tailwindcss": "4.0.0-beta.0",
"jsdom": "28.1.0",
"lodash-es": "4.17.21",
"lodash-es": "4.17.23",
"postcss": "8.5.6",
"rollup-plugin-node-builtins": "2.1.2",
"sinon": "18.0.1",
Expand Down
6 changes: 3 additions & 3 deletions apps/signup-form/package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@tryghost/signup-form",
"version": "0.3.10",
"version": "0.3.12",
"license": "MIT",
"repository": "https://github.com/TryGhost/Ghost",
"author": "Ghost Foundation",
Expand Down Expand Up @@ -35,7 +35,7 @@
"react-dom": "18.3.1"
},
"devDependencies": {
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@storybook/addon-essentials": "8.6.14",
"@storybook/addon-interactions": "8.6.14",
"@storybook/addon-links": "8.6.14",
Expand All @@ -59,7 +59,7 @@
"postcss-import": "16.1.1",
"prop-types": "15.8.1",
"rollup-plugin-node-builtins": "2.1.2",
"storybook": "8.6.14",
"storybook": "8.6.15",
"stylelint": "15.11.0",
"tailwindcss": "3.4.18",
"vite": "5.4.21",
Expand Down
2 changes: 1 addition & 1 deletion apps/stats/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@
},
"devDependencies": {
"@faker-js/faker": "9.9.0",
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@tanstack/react-query": "4.36.1",
"@testing-library/jest-dom": "5.17.0",
"@testing-library/react": "14.3.1",
Expand Down
2 changes: 1 addition & 1 deletion e2e/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@
"devDependencies": {
"@eslint/js": "9.37.0",
"@faker-js/faker": "8.4.1",
"@playwright/test": "1.58.2",
"@playwright/test": "1.59.1",
"@tryghost/debug": "0.1.40",
"@tryghost/logging": "2.5.5",
"@types/dockerode": "3.3.47",
Expand Down
14 changes: 7 additions & 7 deletions ghost/admin/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -45,18 +45,18 @@
"@sentry/integrations": "7.114.0",
"@sentry/replay": "7.116.0",
"@tryghost/admin-x-framework": "0.0.0",
"@tryghost/color-utils": "0.2.10",
"@tryghost/color-utils": "0.2.16",
"@tryghost/ember-promise-modals": "2.0.1",
"@tryghost/helpers": "1.1.97",
"@tryghost/helpers": "1.1.103",
"@tryghost/kg-clean-basic-html": "4.2.21",
"@tryghost/kg-converters": "1.1.20",
"@tryghost/koenig-lexical": "1.7.28",
"@tryghost/limit-service": "1.4.1",
"@tryghost/members-csv": "2.0.3",
"@tryghost/limit-service": "1.5.2",
"@tryghost/members-csv": "2.0.5",
"@tryghost/nql": "0.12.10",
"@tryghost/nql-lang": "0.6.4",
"@tryghost/string": "0.2.17",
"@tryghost/timezone-data": "0.4.12",
"@tryghost/string": "0.3.2",
"@tryghost/timezone-data": "0.4.18",
"animejs": "3.2.2",
"autoprefixer": "9.8.6",
"babel-plugin-transform-class-properties": "6.24.1",
Expand Down Expand Up @@ -124,7 +124,7 @@
"ember-truth-helpers": "3.1.1",
"eslint-plugin-babel": "5.3.1",
"flexsearch": "0.7.43",
"fs-extra": "11.3.0",
"fs-extra": "11.3.4",
"glob": "8.1.0",
"google-caja-bower": "https://github.com/acburdine/google-caja-bower#ghost",
"keymaster": "https://github.com/madrobby/keymaster.git",
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
const {createAddColumnMigration} = require('../../utils');

module.exports = createAddColumnMigration('email_design_settings', 'show_header_icon', {
type: 'boolean',
nullable: false,
defaultTo: true
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
const {createDropNullableMigration} = require('../../utils');

module.exports = createDropNullableMigration('gifts', 'expires_at');
3 changes: 2 additions & 1 deletion ghost/core/core/server/data/schema/schema.js
Original file line number Diff line number Diff line change
Expand Up @@ -1149,6 +1149,7 @@ module.exports = {
background_color: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'light'},
header_background_color: {type: 'string', maxlength: 50, nullable: false, defaultTo: 'transparent'},
header_image: {type: 'string', maxlength: 2000, nullable: true},
show_header_icon: {type: 'boolean', nullable: false, defaultTo: true},
show_header_title: {type: 'boolean', nullable: false, defaultTo: true},
footer_content: {type: 'text', maxlength: 1000000000, nullable: true},
button_color: {type: 'string', maxlength: 50, nullable: true, defaultTo: 'accent'},
Expand Down Expand Up @@ -1223,7 +1224,7 @@ module.exports = {
stripe_payment_intent_id: {type: 'string', maxlength: 255, nullable: false, unique: true},

consumes_at: {type: 'dateTime', nullable: true},
expires_at: {type: 'dateTime', nullable: true},
expires_at: {type: 'dateTime', nullable: false},

status: {
type: 'string', maxlength: 50, nullable: false, validations: {
Expand Down
1 change: 1 addition & 0 deletions ghost/core/core/server/models/email-design-setting.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const EmailDesignSetting = ghostBookshelf.Model.extend({
return {
background_color: 'light',
header_background_color: 'transparent',
show_header_icon: true,
show_header_title: true,
button_color: 'accent',
button_corners: 'rounded',
Expand Down
16 changes: 14 additions & 2 deletions ghost/core/core/server/services/email-service/email-renderer.js
Original file line number Diff line number Diff line change
Expand Up @@ -1031,6 +1031,10 @@ class EmailRenderer {
}

const postUrl = this.#getPostUrl(post);
const isPublicPost = post.get('visibility') === 'public';
const showShareButton = isPublicPost && newsletter.get('show_share_button');
const shareUrl = new URL(postUrl);
shareUrl.hash = '/share';

// Signup URL is the post url with a hash added to it
const signupUrl = new URL(postUrl);
Expand All @@ -1054,6 +1058,12 @@ class EmailRenderer {
commentUrl.hash = '#ghost-comments-root';

const hasEmailOnlyFlag = post.related('posts_meta')?.get('email_only') ?? false;
const hasFeedbackButtons = newsletter.get('feedback_enabled');
const showCommentCta = newsletter.get('show_comment_cta') && this.#settingsCache.get('comments_enabled') !== 'off' && !hasEmailOnlyFlag;
const feedbackButtonCount = (hasFeedbackButtons ? 2 : 0) + (showCommentCta ? 1 : 0) + (showShareButton ? 1 : 0);
const feedbackButtonCellWidth = feedbackButtonCount > 0
? `${(100 / feedbackButtonCount).toFixed(2).replace(/\.00$/, '')}%`
: null;

const latestPosts = [];
let latestPostsHasImages = false;
Expand Down Expand Up @@ -1114,6 +1124,7 @@ class EmailRenderer {
post: {
title: post.get('title'),
url: postUrl,
shareUrl: showShareButton ? shareUrl.href : null,
commentUrl: commentUrl.href,
authors,
publishedAt,
Expand All @@ -1129,7 +1140,7 @@ class EmailRenderer {
name: newsletter.get('name'),
showPostTitleSection: newsletter.get('show_post_title_section'),
showExcerpt: newsletter.get('show_excerpt'),
showCommentCta: newsletter.get('show_comment_cta') && this.#settingsCache.get('comments_enabled') !== 'off' && !hasEmailOnlyFlag,
showCommentCta,
showSubscriptionDetails: newsletter.get('show_subscription_details')
},

Expand Down Expand Up @@ -1200,10 +1211,11 @@ class EmailRenderer {
},

// Audience feedback
feedbackButtons: newsletter.get('feedback_enabled') ? {
feedbackButtons: hasFeedbackButtons ? {
likeHref: positiveLink,
dislikeHref: negativeLink
} : null,
feedbackButtonCellWidth,

// Paywall
paywall: addPaywall ? {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<td dir="ltr" valign="top" align="center" style="display: inline-block; vertical-align: top; font-family: inherit; text-align: center; padding: 0 4px 4px; cursor: pointer; width: 30%;">
<td dir="ltr" valign="top" align="center" style="display: inline-block; box-sizing: border-box; vertical-align: top; font-family: inherit; text-align: center; padding: 0 4px 4px; cursor: pointer; width: {{#if cellWidth}}{{cellWidth}}{{else}}30%{{/if}};">
<a href="{{href}}" target="_blank">
<img src={{iconUrl}} border="0" width={{width}} height={{height}} alt="{{buttonText}}">
<img src={{iconUrl}} border="0" width={{width}} height={{height}} alt="{{buttonText}}" {{#if iconClass}}class="{{iconClass}}"{{/if}}>
<p class="feedback-button-text">{{t buttonText}}</p>
{{!-- Button text possible values: {{t 'More like this'}} {{t 'Less like this'}} {{t 'Comment'}} --}}
{{!-- Button text possible values: {{t 'More like this'}} {{t 'Less like this'}} {{t 'Comment'}} {{t 'Share'}} --}}
</a>
</td>
</td>
Original file line number Diff line number Diff line change
Expand Up @@ -19,17 +19,20 @@

<!-- END MAIN CONTENT AREA -->

{{#if (or feedbackButtons newsletter.showCommentCta) }}
{{#if (or feedbackButtons newsletter.showCommentCta post.shareUrl) }}
<tr>
<td class="feedback-buttons-container" dir="ltr" width="100%" align="center">
<table class="feedback-buttons" role="presentation" border="0" cellpadding="0" cellspacing="0">
<tr>
{{#if feedbackButtons }}
{{> feedbackButton feedbackButtons href=feedbackButtons.likeHref buttonText='More like this' iconUrl="https://static.ghost.org/v5.0.0/images/more-like-this-mobile.png" width="42" height="42" }}
{{> feedbackButton feedbackButtons href=feedbackButtons.dislikeHref buttonText='Less like this' iconUrl="https://static.ghost.org/v5.0.0/images/less-like-this-mobile.png" width="42" height="42" }}
{{> feedbackButton feedbackButtons href=feedbackButtons.likeHref buttonText='More like this' iconUrl="https://static.ghost.org/v5.0.0/images/more-like-this-mobile.png" width="42" height="42" cellWidth=feedbackButtonCellWidth }}
{{> feedbackButton feedbackButtons href=feedbackButtons.dislikeHref buttonText='Less like this' iconUrl="https://static.ghost.org/v5.0.0/images/less-like-this-mobile.png" width="42" height="42" cellWidth=feedbackButtonCellWidth }}
{{/if}}
{{#if newsletter.showCommentCta}}
{{> feedbackButton href=post.commentUrl buttonText='Comment' iconUrl="https://static.ghost.org/v5.0.0/images/comment-mobile.png" width="42" height="42"}}
{{> feedbackButton href=post.commentUrl buttonText='Comment' iconUrl="https://static.ghost.org/v5.0.0/images/comment-mobile.png" width="42" height="42" cellWidth=feedbackButtonCellWidth }}
{{/if}}
{{#if post.shareUrl}}
{{> feedbackButton href=post.shareUrl buttonText='Share' iconUrl="https://static.ghost.org/v6.0.0/images/share-mobile.png" width="42" height="42" cellWidth=feedbackButtonCellWidth}}
{{/if}}
</tr>
</table>
Expand Down
Loading
Loading