Skip to content

Updated email renderer to label gift members in newsletter footer#27481

Merged
mike182uk merged 2 commits into
mainfrom
BER-3479-update-getMemberStatusText
Apr 21, 2026
Merged

Updated email renderer to label gift members in newsletter footer#27481
mike182uk merged 2 commits into
mainfrom
BER-3479-update-getMemberStatusText

Conversation

@mike182uk
Copy link
Copy Markdown
Member

ref https://linear.app/ghost/issue/BER-3479

  • gift is a distinct member status introduced by the Gift Subscriptions project, semantically different from comped
  • before this change, gift members fell through the implicit comped branch in getMemberStatusText and rendered as "Your subscription will expire on {date}." in the newsletter subscription-details footer
  • added a new giftExpires message key rendering "Your gift subscription will expire on {date}." and propagated the string to ghost/i18n across all locales

ref https://linear.app/ghost/issue/BER-3479

- `gift` is a distinct member status introduced by the Gift Subscriptions project, semantically different from `comped`
- before this change, gift members fell through the implicit comped branch in `getMemberStatusText` and rendered as `"Your subscription will expire on {date}.`" in the newsletter subscription-details footer
- added a new `giftExpires` message key rendering "Your gift subscription will expire on {date}." and propagated the string to `ghost/i18n` across all locales
@coderabbitai
Copy link
Copy Markdown
Contributor

coderabbitai Bot commented Apr 21, 2026

Walkthrough

This change adds support for a new 'gift' member status to the email renderer service. A localized message template is introduced to communicate subscription expiration dates for gift members. The member status type definition is extended to recognize 'gift' as a valid status, and the getMemberStatusText method is updated to extract and format the expiration date from the first tier's expiry_at field. The formatted date is incorporated into the message before being returned. A corresponding unit test is added to validate the behavior with a gift member containing an expiration date.

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately reflects the main change: adding distinct messaging for gift members in the newsletter footer with a new 'giftExpires' message key.
Description check ✅ Passed The description clearly explains the context, problem, and solution: distinguishing gift member status with a new localized message key instead of falling through to comped logic.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch BER-3479-update-getMemberStatusText

Warning

There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure.

🔧 ast-grep (0.42.1)
ghost/core/test/unit/server/services/email-service/email-renderer.test.js

Comment @coderabbitai help to get the list of available commands and usage tips.

complimentaryExpires: t('Your subscription will expire on {date}.'),
complimentaryInfinite: ''
complimentaryInfinite: '',
giftExpires: t('Your gift subscription will expire on {date}.')
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In Portal, we render Your subscription will expire on {date} (no "gift" subscription). Could do the same here and reuse the existing translations?

We can always add new translations after copy review if necessary

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated in 49703dd

Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In `@ghost/core/core/server/services/email-service/email-renderer.js`:
- Line 45: The giftExpires translation key currently reuses complimentary
wording; update the value for giftExpires in email-renderer.js to use
gift-specific copy (e.g., "Your gift subscription will expire on {date}.") so
gift members are explicitly labeled as gift subscribers; locate the translations
object containing giftExpires and replace the existing string with the new
gift-specific wording.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: CHILL

Plan: Pro

Run ID: 093cedc4-fae9-4ed8-87f2-18090e7a9671

📥 Commits

Reviewing files that changed from the base of the PR and between b907693 and 49703dd.

📒 Files selected for processing (2)
  • ghost/core/core/server/services/email-service/email-renderer.js
  • ghost/core/test/unit/server/services/email-service/email-renderer.test.js
✅ Files skipped from review due to trivial changes (1)
  • ghost/core/test/unit/server/services/email-service/email-renderer.test.js

complimentaryExpires: t('Your subscription will expire on {date}.'),
complimentaryInfinite: ''
complimentaryInfinite: '',
giftExpires: t('Your subscription will expire on {date}.')
Copy link
Copy Markdown
Contributor

@coderabbitai coderabbitai Bot Apr 21, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major

Use gift-specific copy for giftExpires.

Line 45 currently reuses the complimentary wording, so gift members won’t be explicitly labeled as gift subscribers. This misses the PR’s stated behavior change.

Proposed fix
-        giftExpires: t('Your subscription will expire on {date}.')
+        giftExpires: t('Your gift subscription will expire on {date}.')
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
giftExpires: t('Your subscription will expire on {date}.')
giftExpires: t('Your gift subscription will expire on {date}.')
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@ghost/core/core/server/services/email-service/email-renderer.js` at line 45,
The giftExpires translation key currently reuses complimentary wording; update
the value for giftExpires in email-renderer.js to use gift-specific copy (e.g.,
"Your gift subscription will expire on {date}.") so gift members are explicitly
labeled as gift subscribers; locate the translations object containing
giftExpires and replace the existing string with the new gift-specific wording.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This was by design - see #27481 (comment)

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
gh api repos/TryGhost/Ghost/pulls/comments/3117061753 --jq '{body: .body, user: .user.login, path: .path, line: .line}'

Length of output: 331


@mike182uk, understood — thanks for the context. The intentional parity with Portal's wording ("Your subscription will expire on {date}") makes sense, and reusing the existing translation avoids premature i18n churn before a copy review signs off on gift-specific messaging. I'll withdraw this concern.

( ˘͜ˬ˘ )


✏️ Learnings added
Learnt from: mike182uk
Repo: TryGhost/Ghost PR: 27481
File: ghost/core/core/server/services/email-service/email-renderer.js:45-45
Timestamp: 2026-04-21T12:27:55.799Z
Learning: In TryGhost/Ghost (email-renderer.js), the `giftExpires` message key in `messages.subscriptionStatus` intentionally reuses the same string as `complimentaryExpires` ("Your subscription will expire on {date}.") for parity with Portal's rendering. Gift-specific copy ("Your gift subscription will expire on {date}.") was deliberately deferred pending copy review. Do not flag this as a bug or suggest changing the wording without confirming a copy review has approved gift-specific messaging.

Note: Learnings are effective only in the context of similar code segments. To apply general coding guidelines, please configure review instructions. You can manage existing learnings in the app.


🧠 Learnings used
Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 25791
File: ghost/core/core/server/api/endpoints/member-comment-ban.js:64-68
Timestamp: 2026-01-08T10:26:38.700Z
Learning: In the Ghost API, endpoints rely on the serialization layer to prepare frame.data[docName] as a non-empty array before query() executes. Endpoints access frame.data[docName][0] directly (e.g., frame.data.comment_bans[0], frame.data.members[0], frame.data.posts[0]) without per-endpoint validation. This pattern is common across API endpoints. When maintaining or creating endpoints, avoid duplicating validation for frame.data[docName] and ensure the serializer guarantees the shape and non-emptiness. If you add a new endpoint that uses this frame.data[docName], follow the same assumption and avoid redundant checks unless there's a documented exception.

Learnt from: rob-ghost
Repo: TryGhost/Ghost PR: 26219
File: ghost/core/test/e2e-api/members-comments/comments.test.js:939-983
Timestamp: 2026-02-04T15:58:09.124Z
Learning: In Ghost core tests and code that interact with the Ghost comments API, count.replies is a backward-compatible alias for count.total_replies (all descendants via parent_id) and does not represent direct replies. The new field count.direct_replies returns tree-native direct reply counts. Reviewers should verify any code paths, tests, or API surface areas that rely on count.replies are preserved for compatibility, and consider updating or adding tests to cover count.direct_replies for direct counts. When updating or adding tests, ensure behavior is documented and that any assertions reflect the distinction between total (including descendants) and direct reply counts to avoid regressions in API consumer expectations.

Learnt from: vershwal
Repo: TryGhost/Ghost PR: 27290
File: ghost/core/package.json:76-77
Timestamp: 2026-04-09T09:44:26.783Z
Learning: In the TryGhost/Ghost monorepo, treat `tryghost/admin-api-schema` as the single abstraction layer over AJV version differences. Do not raise code review findings for AJV-internal error field changes (e.g., `dataPath` → `instancePath` between AJV v6 and v8) when evaluating Ghost consumer code. The consumer-facing error contract for this package (`ValidationError` with `message`, `property`, `errorDetails`) is expected to remain stable, and Ghost wrapper code should not inspect raw AJV error objects—so review should focus on the stable `ValidationError` shape rather than AJV internals.

@sonarqubecloud
Copy link
Copy Markdown

@mike182uk mike182uk merged commit 82bc7b3 into main Apr 21, 2026
43 checks passed
@mike182uk mike182uk deleted the BER-3479-update-getMemberStatusText branch April 21, 2026 15:06
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants