wp-calypso
wp-calypso copied to clipboard
Move details about refund policies for cart items to `CheckoutTerms`
Proposed Changes
A while back, in #63489, we added more detailed info to the checkout page about refund windows for different types of cart items. That change sparked a discussion about whether this was really the best way to display those details and we concluded that no, CheckoutTerms
(i.e. just above the Pay now
button) would be a better placement.
This PR removes the detailed info about refund windows from WPCheckoutOrderSummary
and adds a new RefundPolicies
component that replaces DomainRefundPolicy
and renders in CheckoutTerms
. RefundPolicies
displays information about refund windows for all refundable product types.
In WPCheckoutOrderSummary
(i.e. the right sidebar), we display just the string Money back guarantee
(when applicable).
I tried to make it so that we don't unnecessarily repeat information in the checkout and so that we can easily tweak our messaging for different product types. Initially, I had separate RefundPolicy
types for add-ons, Google Workspace, Titan and plans, but later boiled it down to a more succinct set of messages. I'm definitely open to discuss whether we should tweak this and also whether the strings themselves need any adjustments.
Products | Before | After |
---|---|---|
Free domain, Premium plan and Titan mailbox with introductory offer | ![]() |
![]() |
DIFM Lite | ![]() |
![]() |
Testing Instructions
We want to test with a few different types of products, so bear with me.
- Go to
/start/onboarding-with-email
- Add a domain, a mailbox and a plan and proceed to checkout
- Ensure that a
Money back guarantee
row is visible in the right sidebar - Ensure that the following two text rows are visible in
CheckoutTerms
: 4.1.You understand that refunds are limited to 14 days after purchase or renewal for products with yearly subscriptions.
4.2.You understand that domain name refunds are limited to 96 hours after registration. Refunds of paid plans will deduct the standard cost of any domain name registered within a plan.
- Complete checkout
- Navigate to
/setup?siteSlug=<site_slug>
- Check the
Hire a professional to design my website
checkbox and proceed all the way to checkout - Ensure that no
Money back guarantee
row is visible in the right sidebar - Ensure that no information about refunds is visible in
CheckoutTerms
- Empty the cart
- Set up the mailbox you bought earlier and then click
Renew now
on the email management page - Ensure that a
Money back guarantee
row is visible in the right sidebar - Ensure that the following text row is visible in
CheckoutTerms
:You understand that refunds are limited to 14 days after purchase or renewal for products with yearly subscriptions.
Pre-merge Checklist
- [x] Have you written new tests for your changes?
- [ ] Have you tested the feature in Simple (P9HQHe-k8-p2), Atomic (P9HQHe-jW-p2), and self-hosted Jetpack sites (PCYsg-g6b-p2)?
- [x] Have you checked for TypeScript, React or other console errors?
- [ ] Have you used memoizing on expensive computations? More info in Memoizing with create-selector and Using memoizing selectors and Our Approach to Data
- [ ] Have we added the "[Status] String Freeze" label as soon as any new strings were ready for translation (p4TIVU-5Jq-p2)?
Related to #
Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:
Sections (~459 bytes added 📈 [gzipped])
name parsed_size gzip_size
checkout +4744 B (+0.3%) +726 B (+0.2%)
site-purchases -242 B (-0.0%) -65 B (-0.0%)
signup -242 B (-0.1%) -61 B (-0.1%)
purchases -242 B (-0.0%) -65 B (-0.0%)
plugins -242 B (-0.0%) -71 B (-0.0%)
plans -242 B (-0.0%) -65 B (-0.0%)
marketplace -242 B (-0.0%) -66 B (-0.0%)
jetpack-connect -242 B (-0.0%) -65 B (-0.0%)
jetpack-cloud-pricing -242 B (-0.0%) -65 B (-0.0%)
email -242 B (-0.0%) -66 B (-0.0%)
domains -242 B (-0.0%) -70 B (-0.0%)
accept-invite -242 B (-0.1%) -61 B (-0.1%)
Sections contain code specific for a given set of routes. Is downloaded and parsed only when a particular route is navigated to.
Async-loaded Components (~721 bytes added 📈 [gzipped])
name parsed_size gzip_size
async-load-calypso-my-sites-checkout-modal +4967 B (+0.5%) +782 B (+0.3%)
async-load-calypso-blocks-editor-checkout-modal +4725 B (+0.5%) +721 B (+0.3%)
async-load-calypso-my-sites-current-site-stale-cart-items-notice -242 B (-0.3%) -61 B (-0.3%)
React components that are loaded lazily, when a certain part of UI is displayed for the first time.
Legend
What is parsed and gzip size?
Parsed Size: Uncompressed size of the JS and CSS files. This much code needs to be parsed and stored in memory. Gzip Size: Compressed size of the JS and CSS files. This much data needs to be downloaded over network.
Generated by performance advisor bot at iscalypsofastyet.com.
"Money back guarantee" on its own (with no time period) seems very vague to me. As a customer, I would personally be distracted by this and wonder if it's too good to be true or there's a catch somewhere. (Yes, the details are further down, but people won't tend to look at those.)
If the goal is to reduce the amount of text from what's there now, could you consider having a single "X day money-back guarantee" line instead (where X is the shortest refund window among all the products in the cart)? Or maybe modify that for the common case of a plan + domain to mention both refund windows in one line in that specific case... but even then it would be a lot simpler than the current text.
Also, a couple issues I found while testing this.
1. All of the new text is missing for two-year plans or one-time purchases.
Two-year plan:
One-time purchase (premium theme):
2. When renewing a plan and domain at the same time, the combination of the two bullet points makes it sound like the refund window for the domain subscription will be 14 days rather than 96 hours (since the first bullet point talks about renewals and the second doesn't):
Thanks for the review @DavidRothstein!
First, regarding your points 1 and 2.
- I have addressed the problem with biennial products and paid premium themes.
- I feel like this could be addressed by improving the copy. I had a stab at this by bringing back dedicated
RefundPolicy
s for the different plan terms (as opposed to usingGenericMonthly
/GenericYearly
). See screenshots below for result.
"Money back guarantee" on its own (with no time period) seems very vague to me.
This string was previously the fallback for when we couldn't determine a single refund window for the products in the cart. I agree that it's quite vague though, so this would be a good time to reevaluate it!
I tried a new implementation based on your suggestions. Here's a summary:
- Revert to displaying
(n)-day money back guarantee
if there is just one refund policy in the cart. - Prioritise plans in a way so that users who are purchasing a plan with a bundled domain see
(n)-day money back guarantee for plan
in the sidebar. - For more complex scenarios, we fall back to the string
Limited money back guarantee
. I thought this was better than using the lowest refund window, because that can be misleading in cases with complex combinations of products.
Here are updated screenshots that illustrate what the user sees with different combinations of products.
Products | Before | After |
---|---|---|
Paid theme | ![]() |
![]() |
Plan, bundled domain and free professional email trial | ![]() |
![]() |
Plan, bundled domain and paid domain | ![]() |
![]() |
Thanks -- overall it looks a lot better.
This string was previously the fallback for when we couldn't determine a single refund window for the products in the cart. I agree that it's quite vague though, so this would be a good time to reevaluate it!
I did see that "Money back guarantee" was already in the code, but as far as I can tell, it actually only shows up currently when the refund window is 0 days for a particular product? Based on how the code is called here:
https://github.com/Automattic/wp-calypso/blob/150e0f8fa838dbdef556a34f9d44fb65dc13be96/client/my-sites/checkout/composite-checkout/components/wp-checkout-order-summary.tsx#L225
and then how the fallback gets used here:
https://github.com/Automattic/wp-calypso/blob/150e0f8fa838dbdef556a34f9d44fb65dc13be96/client/my-sites/checkout/composite-checkout/lib/get-refund-text.ts#L17
In other words, it seems to be displayed for non-refundable products, which exactly when there is no money-back guarantee at all :frowning_face: So definitely worth revising all this!
Prioritise plans in a way so that users who are purchasing a plan with a bundled domain see
(n)-day money back guarantee for plan
in the sidebar.
Is that clear enough, though? The plan is the only thing they're actually paying money for, so based on that, I would expect to get all my money back if cancelling within n
(i.e. 14) days. However, if they cancel after 4 days, they won't actually get all their money back.
For more complex scenarios, we fall back to the string
Limited money back guarantee
. I thought this was better than using the lowest refund window, because that can be misleading in cases with complex combinations of products.
I see what you're saying, just not sure "Limited" is totally clear. For what it's worth, the reason I suggested using the lowest refund window is that it actually does represent the money-back guarantee period for the total price they are paying -- and this text is shown right above the total price in their shopping cart. So if they want to get all their money back, that's the refund window that matters (even if it's also true that they can get some of their money back beyond that).
FYI, I saw this when purchasing a yearly plan and add-on at the same time (it's not wrong, but the text on the left is repetitive and the text on the right definitely could have said "14 days"):
The plan is the only thing they're actually paying money for, so based on that, I would expect to get all my money back if cancelling within n (i.e. 14) days. However, if they cancel after 4 days, they won't actually get all their money back.
Fair point. I've changed it so that when there are multiple refund windows in the cart, we display {{ shortestRefundWindow }}-day _full_ money back guarantee
.
If we want a single row in WPCheckoutOrderSummary
, this seems like a pretty well-measured approach. It could work to display one row about the domain and another one about the plan, but that might start to conflate the checkout summary with the checkout terms again.
the text on the left is repetitive
Plans without a bundled domain and add-ons now share the same refund policy again, which should be an improvement in your test case.
I've also tweaked the messaging for plan+domain bundles into a single row that says e.g. You understand that domain name refunds are limited to 96 hours after registration and yearly plan refunds are limited to 14 days after purchase. Refunds of paid plans will deduct the standard cost of any domain name registered within a plan.
We can tweak that string, but it seems beneficial to talk about the domain and the plan in a single row, given how intertwined they are when they are sold as a bundle.
the text on the right definitely could have said "14 days"
Good point! I've updated the logic here.
Below are screenshots from the current state of things:
Products | Before | After |
---|---|---|
Personal plan and add-on | ![]() |
![]() |
Plan, bundled domain and free professional email trial | ![]() |
![]() |
Plan, bundled domain and paid domain | ![]() |
![]() |
Regarding the "4-day Money back guarantee" message, since that's specific to domains and the MBG policy for domains is under review at the moment, we (Nomado) wonder if it might be better to remove the reference to this in the sidebar completely.
After discussing with Nomado, I opted to change back the checkout summary to display n-day money back guarantee for plan
when the user has a plan+domain bundle in their cart.
I still think "14 day money back guarantee for plan" is confusing here, because if these users cancel their purchase between 4-14 days, they won't actually get all the money back that they spent on the plan.
There are a number of other ways we could communicate this. My suggestion of "4 day money-back guarantee" is still valid (we could remove that sentences from domain purchases as requested, without having to remove it from plan purchases that also include a free domain). Or else use something like "14 day money-back guarantee (minus domain registration costs)"?
That said, I do also see that this is effectively a preexisting issue. So if we don't want to address it here, it's OK I suppose, but in that case can we preserve the exact wording we have already? In other words, instead of seeing this when purchasing a plan and free domain:
Just keep it like this (the current behavior):
It's much more clear to continue mentioning the specific plan name (and we should be as clear as possible if other aspects of it are potentially misleading).
As for renewals, I'm seeing the following when trying to renew a plan and domain (using the latest version of the pull request):
That looks wrong -- I think the "for [plan]" wording is needed in this case also, since the 14 days doesn't apply to everything that is being renewed.
14 day money-back guarantee (minus domain registration costs)
Initially I thought this was quite verbose, but I came around to liking it. It's accurate and hopefully accommodates the conflicting desires here.
As for renewals, I'm seeing the following when trying to renew a plan and domain.
I made a number of changes to the checkout summary to try and account for all the different scenarios. I wasn't able to add a plan and a domain renewal to my cart at the same time, but I'd appreciate if you could take another look @DavidRothstein.
Here's another set of screenshots with the current state of the checkout summary. @delputnam if you could also take a quick look at these, that'd be great!
Products | Screenshot |
---|---|
Monthly plan, domain, add-on | ![]() |
Yearly plan, domain, add-on | ![]() |
Yearly plan, domain | ![]() |
Paid domain | ![]() |
Summarizing the logic in the checkout summary as it currently stands.
The product combinations from my latest set of screenshots will still generate the same text, but I have added a case specifically for monthly plans+paid domains (case 6).
- If the cart contains no refundable products, display nothing
- If the cart contains only domain registrations/renewals, display nothing
- If the cart contains any non-refundable products, display
Partial money back guarantee
- If there is a single refund window in the cart AND there is a plan+free domain bundle, display
%(days)d-day money back guarantee (minus domain registration costs)
- If there is a single refund window in the cart and no plan+domain bundle, display
%(days)d-day money back guarantee
- If there is a monthly plan+paid domain "bundle" in the cart, display
%(days)d-day money back guarantee for %(planName)s
- If there are multiple refund windows in the cart, display
Minimum %(days)d-day money back guarantee
My guess is that the majority of checkouts will be covered by cases 2, 4 or 5. 6 is probably also not an uncommon scenario, which is why I added a case specifically for that. 3 seems like a fairly uncommon scenario, but I find it important to set user assumptions correctly for that case.
It looks mostly good to me, thanks!
Personally, I would say that phrases like "Partial money back guarantee" and "Minimum X-day money back guarantee" are muddying the waters, and distracting the user by having them try to figure out what it means... For the first, I would just remove the sentence entirely (don't say anything about a money back guarantee if some products in the cart are non-refundable), and for the second, I'd still consider just removing "Minimum", but you could also go with "X-day full money back guarantee" (like you had at one point before)?
To be honest, my "minus domain registration costs" suggestion could potentially have a similar problem (of making the user think too much)...
Who should do a final review of all the wording changes here? (I think these kinds of changes can typically have a real impact on sales, in one direction or the other.)
Regarding renewals, I tested a plan and domain renewal by putting one in the shopping cart, backing out, and then putting the other in the shopping cart (after previously buying them using PCYsg-IA-p2) -- a real user would typically use a link in a billing email to renew both at the same time, but for testing purposes my way should be fine. Results look correct to me:
One more thing: Looking at the above screenshot, would it be better if the third informational bullet point on the left said "You understand that refunds are limited to 14 days after purchase or renewal for non-domain products with yearly subscriptions" instead (emphasis added)? Without that it almost seems like the third and fourth bullet points contradict each other (given that domain renewals are billed yearly).
Given that we've increased the scope here with Nomado's request, my preference would be to reduce the overall impact of this PR in order to get it shipped. This should hopefully also help isolate the potential impact on conversions by not tweaking the knobs where we don't have to.
With that goal in mind, I took up these suggested changes from you @DavidRothstein:
- If there are any non-refundable products in cart, display nothing (instead of
Partial money back guarantee
) - Revert checkout summary string for plan bundles to
n-day money back guarantee for {{ planName }}
- Include
[...] non-domain [...]
in the generic refund policy details
Regarding renewals, it seems I just somehow misunderstood the test case, thinking that one product was supposed to be a renewal and the other one was not 🤷♂️ In any case, to fully accommodate Nomado, I made an adjustment specifically for plan+domain renewals so that this combination now also displays n-day money back guarantee for {{ planName }}
.
Who should do a final review of all the wording changes here?
I pinged about this here p1664785491379129/1664348103.018689-slack-C0117V2PCAE
For easier overview, here's another summary of the logic in the checkout summary:
- If the cart contains no refundable products, display nothing
- If the cart contains only domain registrations/renewals, display nothing
- If the cart contains any non-refundable products, display nothing
- If there is a single refund window in the cart AND there is a plan+free domain bundle, display
%(days)d-day money back guarantee for %(planName)s
- If there is a single refund window in the cart and no plan+domain bundle, display
%(days)d-day money back guarantee
- If there is a monthly plan+paid domain "bundle" in the cart, display
%(days)d-day money back guarantee for %(planName)s
- If the cart contains only a plan renewal and a domain renewal, display
%(days)d-day money back guarantee for %(planName)s
- If there are multiple refund windows in the cart, display
%(days)d-day full money back guarantee
That logic seems pretty solid to me now (although I didn't test most of it).
I did test the renewal case again, and it looks to me like the latest version is displaying some text in the Terms that shouldn't be there?
I'm seeing this for a yearly plan renewal, which looks wrong:
And this for a yearly plan+domain renewal (which also looks wrong -- seems to be showing the new purchase text for domains, with the regular renewal text for domains in the bullet point underneath it):
Also noticed that when using a free domain credit (after previously buying a plan), one of the lines in the Terms is no longer there. This is the "before" screenshot showing the line that went missing:
I suspect removing it was intentional, but I do wonder if including it originally was supposed to be some kind of attempt to communicate the "...Refunds of paid plans will deduct the standard cost of any domain name registered within a plan" idea that is shown in other scenarios. (These users might otherwise see no message anywhere that is relevant to how their use of the free domain credit affects a potential refund of their plan later on.)
Thanks for your keen eyes, @DavidRothstein! I've addressed the issue you pointed out where plan/domain renewals would display the wrong text in the checkout terms.
As for the refund terms for bundled domains purchased separately from a paid plan, I've added a specific case for this that shows the following text (a string that's already used on the checkout page today):
You understand that {{refundsSupportPage}}domain name refunds{{/refundsSupportPage}} are limited to 96 hours after registration. Refunds of paid plans will deduct the standard cost of any domain name registered within a plan.
This policy and the DomainNameRegistration
refund policy are mutually exclusive. Here's a screenshot from the checkout page with one bundled domain and one paid domain in the cart:
Only had time for a quick look (and am AFK tomorrow) but it looks great to me -- thanks!
This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/7568760
Thank you @fredrikekelund for including a screenshot in the description! This is really helpful for our translators.
Translation for this Pull Request has now been finished.
I found a couple relatively minor problems here and created followups for them:
- https://github.com/Automattic/wp-calypso/issues/69142
- https://github.com/Automattic/payments-shilling/issues/1167
Also a followup for the (preexisting) issue regarding the implication that you can get all your money back within 14 days for a plan purchased with a free domain:
- https://github.com/Automattic/payments-shilling/issues/1168