Skip to content

Commit 74bdef0

Browse files
authored
Updated share button in newsletters to show on paid/member posts, and not show on email-only (TryGhost#27483)
no ref Some small tweaks to the visibility of the share button when it's toggled on for newsletters: - if it's a paid/members-only post, we want to show the share button. idea is that shares of that post can drive help drive conversion for more members - if it's an email-only newsletter, do _not_ show the share button. idea is an email-only newsletter isn't meant to be shared as a link
1 parent 82bc7b3 commit 74bdef0

3 files changed

Lines changed: 70 additions & 36 deletions

File tree

ghost/core/core/server/services/email-service/email-renderer.js

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1042,8 +1042,8 @@ class EmailRenderer {
10421042
}
10431043

10441044
const postUrl = this.#getPostUrl(post);
1045-
const isPublicPost = post.get('visibility') === 'public';
1046-
const showShareButton = isPublicPost && newsletter.get('show_share_button');
1045+
const hasEmailOnlyFlag = post.related('posts_meta')?.get('email_only') ?? false;
1046+
const showShareButton = newsletter.get('show_share_button') && !hasEmailOnlyFlag;
10471047
const shareUrl = new URL(postUrl);
10481048
shareUrl.hash = '/share';
10491049

@@ -1068,7 +1068,6 @@ class EmailRenderer {
10681068
const commentUrl = new URL(postUrl);
10691069
commentUrl.hash = '#ghost-comments-root';
10701070

1071-
const hasEmailOnlyFlag = post.related('posts_meta')?.get('email_only') ?? false;
10721071
const hasFeedbackButtons = newsletter.get('feedback_enabled');
10731072
const showCommentCta = newsletter.get('show_comment_cta') && this.#settingsCache.get('comments_enabled') !== 'off' && !hasEmailOnlyFlag;
10741073
const feedbackButtonCount = (hasFeedbackButtons ? 2 : 0) + (showCommentCta ? 1 : 0) + (showShareButton ? 1 : 0);

ghost/core/test/integration/services/email-service/batch-sending.test.js

Lines changed: 26 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -899,7 +899,29 @@ describe.skip('Batch sending tests', function () {
899899
await models.Newsletter.edit({show_comment_cta: true}, {id: defaultNewsletter.id});
900900
});
901901

902-
it('Shows share button when enabled in newsletter for public posts', async function () {
902+
it('Shows share button when enabled in newsletter for public, members, paid, and tiers posts', async function () {
903+
mockSetting('email_track_clicks', false); // Disable link replacement for this test
904+
905+
const defaultNewsletter = await getDefaultNewsletter();
906+
const originalShowShareButton = defaultNewsletter.get('show_share_button');
907+
await models.Newsletter.edit({show_share_button: true}, {id: defaultNewsletter.id});
908+
909+
try {
910+
for (const visibility of ['public', 'members', 'paid', 'tiers']) {
911+
const {html} = await sendEmail(agent, {
912+
title: `This is a test post title (${visibility})`,
913+
mobiledoc: mobileDocExample,
914+
visibility
915+
});
916+
917+
assert.match(html, /#\/share/, `Expected share button for "${visibility}" visibility`);
918+
}
919+
} finally {
920+
await models.Newsletter.edit({show_share_button: originalShowShareButton}, {id: defaultNewsletter.id});
921+
}
922+
});
923+
924+
it('Hides share button for email-only posts', async function () {
903925
mockSetting('email_track_clicks', false); // Disable link replacement for this test
904926

905927
const defaultNewsletter = await getDefaultNewsletter();
@@ -910,10 +932,11 @@ describe.skip('Batch sending tests', function () {
910932
const {html} = await sendEmail(agent, {
911933
title: 'This is a test post title',
912934
mobiledoc: mobileDocExample,
913-
visibility: 'public'
935+
visibility: 'members',
936+
email_only: true
914937
});
915938

916-
assert.match(html, /#\/share/);
939+
assert.doesNotMatch(html, /#\/share/);
917940
} finally {
918941
await models.Newsletter.edit({show_share_button: originalShowShareButton}, {id: defaultNewsletter.id});
919942
}

ghost/core/test/unit/server/services/email-service/email-renderer.test.js

Lines changed: 42 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1460,8 +1460,7 @@ describe('Email renderer', function () {
14601460
assert(response.html.includes('http://feedback-link.com/?score=0'));
14611461
});
14621462

1463-
it('includes share links for public posts', async function () {
1464-
const post = createModel(basePost);
1463+
it('includes share links for posts with public, members, paid, and tiers visibility', async function () {
14651464
const newsletter = createModel({
14661465
header_image: null,
14671466
name: 'Test Newsletter',
@@ -1473,21 +1472,33 @@ describe('Email renderer', function () {
14731472
const segment = null;
14741473
const options = {};
14751474

1476-
const response = await emailRenderer.renderBody(
1477-
post,
1478-
newsletter,
1479-
segment,
1480-
options
1481-
);
1475+
for (const visibility of ['public', 'members', 'paid', 'tiers']) {
1476+
const post = createModel({
1477+
...basePost,
1478+
visibility
1479+
});
14821480

1483-
assert(response.html.includes('href="http://example.com/#/share"'));
1484-
assert(response.html.includes('>Share</p>'));
1481+
const response = await emailRenderer.renderBody(
1482+
post,
1483+
newsletter,
1484+
segment,
1485+
options
1486+
);
1487+
1488+
assert(response.html.includes('href="http://example.com/#/share"'), `Expected share link for "${visibility}" visibility`);
1489+
assert(response.html.includes('>Share</p>'), `Expected share button text for "${visibility}" visibility`);
1490+
}
14851491
});
14861492

1487-
it('does not include share links for non-public posts', async function () {
1493+
it('does not include share links for email-only posts', async function () {
14881494
const post = createModel({
14891495
...basePost,
1490-
visibility: 'members'
1496+
posts_meta: createModel({
1497+
feature_image_alt: null,
1498+
feature_image_caption: null,
1499+
email_only: true
1500+
}),
1501+
loaded: ['posts_meta']
14911502
});
14921503
const newsletter = createModel({
14931504
header_image: null,
@@ -2606,18 +2617,21 @@ describe('Email renderer', function () {
26062617
assert.equal(data.post.publishedAt, '1 Jan 1970');
26072618
});
26082619

2609-
it('includes share URL for public posts', async function () {
2620+
it('includes share URL for posts with public, members, paid, and tiers visibility', async function () {
26102621
const html = '';
2611-
const post = createModel({
2612-
posts_meta: createModel({}),
2613-
loaded: ['posts_meta'],
2614-
visibility: 'public'
2615-
});
26162622
const newsletter = createModel({
26172623
show_share_button: true
26182624
});
2619-
const data = await emailRenderer.getTemplateData({post, newsletter, html, addPaywall: false});
2620-
assert.equal(data.post.shareUrl, 'http://example.com/#/share');
2625+
2626+
for (const visibility of ['public', 'members', 'paid', 'tiers']) {
2627+
const post = createModel({
2628+
posts_meta: createModel({}),
2629+
loaded: ['posts_meta'],
2630+
visibility
2631+
});
2632+
const data = await emailRenderer.getTemplateData({post, newsletter, html, addPaywall: false});
2633+
assert.equal(data.post.shareUrl, 'http://example.com/#/share', `Expected share URL for "${visibility}" visibility`);
2634+
}
26212635
});
26222636

26232637
it('calculates footer feedback button widths based on visible actions', async function () {
@@ -2653,21 +2667,19 @@ describe('Email renderer', function () {
26532667
assert.equal(data.post.shareUrl, null);
26542668
});
26552669

2656-
it('does not include share URL for non-public posts', async function () {
2670+
it('does not include share URL for email-only posts', async function () {
26572671
const html = '';
2672+
const post = createModel({
2673+
posts_meta: createModel({email_only: true}),
2674+
loaded: ['posts_meta'],
2675+
visibility: 'members'
2676+
});
26582677
const newsletter = createModel({
26592678
show_share_button: true
26602679
});
26612680

2662-
for (const visibility of ['members', 'paid', 'tiers']) {
2663-
const post = createModel({
2664-
posts_meta: createModel({}),
2665-
loaded: ['posts_meta'],
2666-
visibility
2667-
});
2668-
const data = await emailRenderer.getTemplateData({post, newsletter, html, addPaywall: false});
2669-
assert.equal(data.post.shareUrl, null, `Expected no share URL for "${visibility}" visibility`);
2670-
}
2681+
const data = await emailRenderer.getTemplateData({post, newsletter, html, addPaywall: false});
2682+
assert.equal(data.post.shareUrl, null);
26712683
});
26722684

26732685
it('show feature image if post has feature image', async function () {

0 commit comments

Comments
 (0)