Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Plans: Enable term savings price display - as a grid feature #96357

Merged
merged 5 commits into from
Nov 25, 2024

Conversation

chriskmnds
Copy link
Contributor

@chriskmnds chriskmnds commented Nov 13, 2024

Related to https://github.com/Automattic/martech/issues/3403, #96174

Proposed Changes

Enables the term savings price display as a grid feature that can be enabled/disabled, as needed. This is now behind a feature flag.

  • See media below
  • It applies to all the grid terms - from yearly onward.
  • It takes lower precedence than intro offers and coupon discounts (so if an intro offer exists, then that discount variation will display instead)

Media

Screenshot 2024-11-15 at 3 57 16 PM

Caveats

The interplay with introductory offers and coupon/promos may create ambiguity/confusion, as the pricing discounts are based off different origins -> intro offers are a comparison between standard plan price and discounted plan price, for term saving the comparison is between two separate plans (the current term's and the lower terms). These two living next to each other in the grid:

Screenshot 2024-11-15 at 3 49 39 PM

Also see comment below regarding the validity of this display/UI if everything appears as discounted in the grid (TLDR will this nullify the presence of a promo/intro offer?): #96357 (comment)

Why are these changes being made?

Part of addressing https://github.com/Automattic/martech/issues/3403

TODO

Testing Instructions

  • Go to /plans/:site?flags=plans/term-savings-price-display and /start/plans?flags=plans/term-savings-price-display
  • Ensure for yearly and above the savings are displayed as per media above
  • Try the same with a coupon (need to find one) or active intro offer (need to mock/code it) and ensure those discounts render instead for the respective plans

Pre-merge Checklist

  • Has the general commit checklist been followed? (PCYsg-hS-p2)
  • 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)?
  • 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)?
  • For changes affecting Jetpack: Have we added the "[Status] Needs Privacy Updates" label if this pull request changes what data or activity we track or use (p4TIVU-aUh-p2)?

@chriskmnds chriskmnds self-assigned this Nov 13, 2024
@chriskmnds chriskmnds requested a review from jeyip November 13, 2024 16:35
@matticbot matticbot added the [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. label Nov 13, 2024
@matticbot
Copy link
Contributor

matticbot commented Nov 13, 2024

This PR modifies the release build for the following Calypso Apps:

For info about this notification, see here: PCYsg-OT6-p2

  • notifications

To test WordPress.com changes, run install-plugin.sh $pluginSlug update/plans-grid-term-savings-price-display on your sandbox.

@matticbot
Copy link
Contributor

matticbot commented Nov 13, 2024

Here is how your PR affects size of JS and CSS bundles shipped to the user's browser:

Sections (~353 bytes added 📈 [gzipped])

name                  parsed_size           gzip_size
update-design-flow        +1605 B  (+0.1%)     +353 B  (+0.1%)
plugins                   +1605 B  (+0.0%)     +353 B  (+0.0%)
plans                     +1605 B  (+0.1%)     +353 B  (+0.1%)
link-in-bio-tld-flow      +1605 B  (+0.1%)     +353 B  (+0.1%)
jetpack-app               +1605 B  (+0.4%)     +353 B  (+0.3%)

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 (~353 bytes added 📈 [gzipped])

name                                             parsed_size           gzip_size
async-load-signup-steps-plans-theme-preselected      +1605 B  (+0.4%)     +353 B  (+0.3%)
async-load-signup-steps-plans                        +1605 B  (+0.4%)     +353 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.

@chriskmnds chriskmnds marked this pull request as ready for review November 15, 2024 14:27
@chriskmnds chriskmnds requested a review from a team as a code owner November 15, 2024 14:27
@jeyip
Copy link
Contributor

jeyip commented Nov 15, 2024

Context for anyone following along:

We've had discussions in slack. It revolved around how to display various discounts and promotions alongside the multi-year plan discounts in the plans grid. Key points:

  • There's a concern about two points of potential confusion when displaying different types of discounts (e.g., intro offers, coupons, multi-year savings).
    1. The original, crossed out price we're showing for multi-year plans will refer to a lower term plan product. The original, crossed out price for annual plans and monthly plans, will, however, only refer to the same plan's original price.
    2. We don't currently elaborate on multiple price reductions to a single product in the plans grid ( ex. coupon applied to a promotion ). How would we like to handle the situation for multi-year plans?
  • We discussed possible solutions, but we're currently exploring them more deeply this PR

@jeyip
Copy link
Contributor

jeyip commented Nov 15, 2024

Spinning things up and testing

Edit: Apologies I wasn't able to get to this on Friday. Planning to review thoroughly and test in 4 hours at 4:00PM PST

Edit 2: Testing now

@jeyip
Copy link
Contributor

jeyip commented Nov 18, 2024

Testing

Requirements

For each of the flows listed below:

  • Ensure for yearly and above the savings are displayed as per media above
  • Can still purchase multi-year plans, annual plans, and monthly plans
  • Try the same with a coupon ( Ex. federate 25 ) or active intro offer (need to mock/code it) and ensure those discounts render instead for the respective plans in the features + comparison grid

Features Grid
Screenshot 2024-11-17 at 20 13 13

Comparison Grid
Screenshot 2024-11-17 at 20 19 16

Flows:

  • /start
  • /plans

Browsers

  • Chrome

Notes

Seems to test well given the caveats described in the PR description. I'm going to touch base with Isa to confirm his thoughts. I'm also going to code review what we have more thoroughly after dinner tonight

Copy link
Contributor

@jeyip jeyip left a comment

Choose a reason for hiding this comment

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

Non-blocking / Nitpick:

I noticed that selecting storage add-ons removes the savings label and crossed out header pricing for annual plans, and presents the pricing as non-discounted.

Apologies if I didn't communicate this clearly, but for the purpose of the emphasize longer plans experiment, James, Isa and I had decided to disable updates to header pricing when storage add-ons are selected for annual plans.

More context in p1726619377025979/1724962428.022989-slack-C07ABDFQEMS.

I haven't taken a close look since it's late here, but if it ends up being a pain in the butt to implement, I'm happy to take care of disabling the storage add-on header pricing updates in a follow-up PR when I'm online 🙂

Copy link
Contributor

@jeyip jeyip left a comment

Choose a reason for hiding this comment

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

Code looks reasonable 😎 Thanks for tackling all of this @chriskmnds -- your help is super appreciated!

Copy link
Contributor

@jeyip jeyip left a comment

Choose a reason for hiding this comment

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

+1 from me, but let me check with Isa about caveats tomorrow morning

@chriskmnds
Copy link
Contributor Author

Thanks for reviewing @jeyip

Non-blocking / Nitpick:

I noticed that selecting storage add-ons removes the savings label and crossed out header pricing for annual plans, and presents the pricing as non-discounted.

Hmm we should probably fix this (irrespective of what functionality we wire for the experiment). Ideally, those should still work the same. I'll take a look and circle back.

Apologies if I didn't communicate this clearly, but for the purpose of the emphasize longer plans experiment, James, Isa and I had decided to disable updates to header pricing when storage add-ons are selected for annual plans.

More context in p1726619377025979/1724962428.022989-slack-C07ABDFQEMS.

I haven't taken a close look since it's late here, but if it ends up being a pain in the butt to implement, I'm happy to take care of disabling the storage add-on header pricing updates in a follow-up PR when I'm online 🙂

No problem. We can focus on that separately, either in the plumbing PR (#96174), or separately (e.g. a PR "Plans: Make storage selection reflection in header price optional" - and what a title! 😆 )

@jeyip
Copy link
Contributor

jeyip commented Nov 18, 2024

I reached out to Isa about the caveats, but it looks like he's on a plane traveling until tomorrow morning. We can leave this PR as is until he gets back to us. I'll get started on fixing storage add-on behavior in the meantime 🙂

@jeyip jeyip added DO NOT MERGE and removed [Status] Needs Review The PR is ready for review. This also triggers e2e canary tests and wp-desktop tests automatically. labels Nov 18, 2024
@jeyip
Copy link
Contributor

jeyip commented Nov 19, 2024

We can focus on that separately, either in the plumbing PR (#96174), or separately (e.g. a PR "Plans: Make storage selection reflection in header price optional" - and what a title! 😆 )

lol. All of that for such a small PR. It's perfect 😆

I have some changes locally that I can push up for discussion shortly

Edit: Plans: Make storage selection reflection in header price optional. I branched off of your refactor cleanups in #96492

@chriskmnds
Copy link
Contributor Author

@jeyip concerning:

Non-blocking / Nitpick:

I noticed that selecting storage add-ons removes the savings label and crossed out header pricing for annual plans, and presents the pricing as non-discounted.

I investigated, and I think this is fine. Technically speaking, there are no savings from monthly once you account for the storage add-on selection (you oay more per month), hence why it resolves to not showing the crossout/savings price.

Screenshot 2024-11-19 at 10 31 32 AM

We can focus on that separately, either in the plumbing PR (#96174), or separately (e.g. a PR "Plans: Make storage selection reflection in header price optional" - and what a title! 😆 )

lol. All of that for such a small PR. It's perfect 😆

I have some changes locally that I can push up for discussion shortly

Edit: Plans: Make storage selection reflection in header price optional. I branched off of your refactor cleanups in #96492

Gold! 😆 I'll drop a review a little later

@chriskmnds chriskmnds force-pushed the update/plans-grid-term-savings-price-display branch from 3511344 to 021e5d8 Compare November 19, 2024 08:36
@chriskmnds
Copy link
Contributor Author

Context for anyone following along:

We've had discussions in slack. It revolved around how to display various discounts and promotions alongside the multi-year plan discounts in the plans grid. Key points:

  • There's a concern about two points of potential confusion when displaying different types of discounts (e.g., intro offers, coupons, multi-year savings).

    1. The original, crossed out price we're showing for multi-year plans will refer to a lower term plan product. The original, crossed out price for annual plans and monthly plans, will, however, only refer to the same plan's original price.
    2. We don't currently elaborate on multiple price reductions to a single product in the plans grid ( ex. coupon applied to a promotion ). How would we like to handle the situation for multi-year plans?
  • We discussed possible solutions, but we're currently exploring them more deeply this PR

@jeremy it's not just the confusion, but also how this "term savings" display literally almost nullifies the presence of a "special offer" next to it. As a user, I think I'd fail to be drawn into the promo or intro offer in a grid that looks like:

Screenshot 2024-11-15 at 3 49 39 PM

and as a product/developer I'd be frustrated if I want to encode a promo offer in a grid where everything is presented discounted this way. Ideally, you'd want these to stand out.

^ I think this is far more important to address before shipping anything. Even if it means, we disable the term savings display in the presence of another discount. Ultimately, if the results will not have production validity, then not sure the experiment data would even be worth studying. If you agree, can you please raise this in the discussion thread (feel free to link back to this comment - I'm not sure where to do this as we don't have a "feedback requested" post, right?).

@jeyip
Copy link
Contributor

jeyip commented Nov 19, 2024

I investigated, and I think this is fine. Technically speaking, there are no savings from monthly once you account for the storage add-on selection (you oay more per month), hence why it resolves to not showing the crossout/savings price.

Good observation. Summarizing to make sure I understand correctly...We define the original ( crossed out ) price to be a certain amount, and the monthly plan + storage add-on price exceeds that crossed out amount when we account for the additional costs.

My first reaction was actually one of confusion. Removing the label and crossed out price made me believe that there was no longer any price reduction being applied. There is, however, still a discount for the annual plan. It's just that, in proportion to the total cost at checkout alongside the storage add-on, the overall savings are quite small.

I'll read more about the original motivation for disabling header price updates with storage add-ons about right and get back to you when I revisit everything again. 🤔

@jeremy it's not just the confusion, but also how this "term savings" display literally almost nullifies the presence of a "special offer" next to it. As a user, I think I'd fail to be drawn into the promo or intro offer in a grid that looks like:

Ah we're on the same page. When I call out "multiple price reductions on a single product", I had this problem in mind. Clearly outlining multiple price reductions would, in my head, possibly be a way for users to differentiate between the offers. I prefer the way you raise it though, because it frames the problem itself more clearly without prescribing a solution

and as a product/developer I'd be frustrated if I want to encode a promo offer in a grid where everything is presented discounted this way. Ideally, you'd want these to stand out.

Hmmm... I hadn't considered the product/dev audience in this way. Makes sense 👍

^ I think this is far more important to address before shipping anything. Even if it means, we disable the term savings display in the presence of another discount.

Quick question -- what are your thoughts on simply not showing the discount label at all for term savings and only showing crossed out original pricing? I feel like, in that case, we could still convey price savings without nullifying the effect of the "special offer" labels.

Ultimately, if the results will not have production validity, then not sure the experiment data would even be worth studying.

So this is one thing I'm trying to pin down. I remember there being discussion in the past of primarily using this work to inform the dotcom packaging overhaul. It's one of the things I'd like to confirm with Isa is still the case because it does affect our focus on production validity. After chatting with James about the history of pro-rated pricing and how that came to be, I believe your intuition around raising the question of production validity to be correct. Let's figure out a production valid state to avoid a situation where a confusing experience is pushed out because of a successful experiment ( lemme know if you wanna talk more about this ).

If you agree, can you please raise this in the discussion thread (feel free to link back to this comment - I'm not sure where to do this as we don't have a "feedback requested" post, right?).

Either way, in my eyes, it doesn't hurt to raise this with a broader audience at this point. Yeah I'm happy to take care it before I sign off tonight 🙂

@chriskmnds
Copy link
Contributor Author

chriskmnds commented Nov 20, 2024

@jeyip

Quick question -- what are your thoughts on simply not showing the discount label at all for term savings and only showing crossed out original pricing? I feel like, in that case, we could still convey price savings without nullifying the effect of the "special offer" labels.

Would it not be a little cryptic to have a bunch of crossed out prices without explanation? If we expect user to work it out on their own, I feel that's worse 🤷

After chatting with James about the history of pro-rated pricing and how that came to be, I believe your intuition around raising the question of production validity to be correct. Let's figure out a production valid state to avoid a situation where a confusing experience is pushed out because of a successful experiment ( lemme know if you wanna talk more about this ).

I think it's same scenario I've seen play out elsewhere e.g. we run experiment to figure out "user reaction", but ignore the long term validity of the environment/state we using for it. In my mind, unless the experiment runs within a realistic, future proof state, then the results are not realistic to speak of. It's like running a marketing campaign that is short-lived (in this case, advertising the "term savings". In a previous case, advertising the "return/refund period".).

^ OR maybe not. maybe different scenarios. don't read too much into the above 😬

@jeyip
Copy link
Contributor

jeyip commented Nov 21, 2024

Would it not be a little cryptic to have a bunch of crossed out prices without explanation? If we expect user to work it out on their own, I feel that's worse 🤷

Gave it more thought and agree here. I think your proposal to disable long term plan savings if coupons / promotions are present is the most reasonable way forward 👍

I think it's same scenario I've seen play out elsewhere e.g. we run experiment to figure out "user reaction", but ignore the long term validity of the environment/state we using for it. In my mind, unless the experiment runs within a realistic, future proof state, then the results are not realistic to speak of. It's like running a marketing campaign that is short-lived (in this case, advertising the "term savings". In a previous case, advertising the "return/refund period".).

^ OR maybe not. maybe different scenarios. don't read too much into the above 😬

If both you and James have similar first impressions, I trust the intuition of both of your experiences 🙂

@chriskmnds chriskmnds force-pushed the update/plans-grid-term-savings-price-display branch from 021e5d8 to 67bd5de Compare November 25, 2024 09:14
@chriskmnds chriskmnds merged commit a2013c3 into trunk Nov 25, 2024
12 of 13 checks passed
@chriskmnds chriskmnds deleted the update/plans-grid-term-savings-price-display branch November 25, 2024 09:38
@a8ci18n
Copy link

a8ci18n commented Nov 25, 2024

This Pull Request is now available for translation here: https://translate.wordpress.com/deliverables/17018080

Some locales (Hebrew, Japanese) have been temporarily machine-translated due to translator availability. All other translations are usually ready within a few days. Untranslated and machine-translated strings will be sent for translation next Monday and are expected to be completed by the following Friday.

Thank you @chriskmnds for including a screenshot in the description! This is really helpful for our translators.

@a8ci18n
Copy link

a8ci18n commented Dec 1, 2024

Translation for this Pull Request has now been finished.

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.

4 participants