From d1d56cee6c75c69d249818e4905533b75b1e3004 Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Mon, 17 Nov 2025 16:51:27 -0500 Subject: [PATCH 1/6] Add Woo Hosted Plans stepper flow --- .../product-purchase-features-list/index.jsx | 4 + client/dashboard/utils/site-plan.ts | 4 + .../flows/woo-hosted-plans/README.md | 15 ++ .../flows/woo-hosted-plans/style.scss | 6 + .../woo-hosted-plans/woo-hosted-plans.ts | 133 ++++++++++++++++++ .../helpers/should-use-step-container-v2.ts | 2 + .../steps-repository/unified-plans/index.tsx | 10 +- .../unified-plans/unified-plans-step.tsx | 13 +- .../steps-repository/unified-plans/util.ts | 2 +- .../declarative-flow/registered-flows.ts | 7 + .../src/components/checkout-main-content.tsx | 1 + .../hooks/use-generate-action-hook.tsx | 6 +- .../components/TopBar/TopBar.tsx | 14 +- packages/onboarding/src/utils/flows.ts | 5 + .../src/components/plan-button/style.scss | 3 +- .../src/hooks/data-store/use-grid-plans.tsx | 7 + packages/plans-grid-next/src/types.ts | 1 + 17 files changed, 221 insertions(+), 12 deletions(-) create mode 100644 client/landing/stepper/declarative-flow/flows/woo-hosted-plans/README.md create mode 100644 client/landing/stepper/declarative-flow/flows/woo-hosted-plans/style.scss create mode 100644 client/landing/stepper/declarative-flow/flows/woo-hosted-plans/woo-hosted-plans.ts diff --git a/client/blocks/product-purchase-features-list/index.jsx b/client/blocks/product-purchase-features-list/index.jsx index d66e35eae6a6..c99d7240f53f 100644 --- a/client/blocks/product-purchase-features-list/index.jsx +++ b/client/blocks/product-purchase-features-list/index.jsx @@ -21,6 +21,8 @@ import { WPCOM_FEATURES_WORDADS, TYPE_WOOEXPRESS_MEDIUM, TYPE_WOOEXPRESS_SMALL, + TYPE_WOO_HOSTED_BASIC, + TYPE_WOO_HOSTED_PRO, TYPE_100_YEAR, TYPE_STARTER, } from '@automattic/calypso-products'; @@ -395,6 +397,8 @@ export class ProductPurchaseFeaturesList extends Component { [ TYPE_ECOMMERCE ]: () => this.getEcommerceFeatures(), [ TYPE_WOOEXPRESS_MEDIUM ]: () => this.getEcommerceFeatures(), [ TYPE_WOOEXPRESS_SMALL ]: () => this.getEcommerceFeatures(), + [ TYPE_WOO_HOSTED_BASIC ]: () => this.getEcommerceFeatures(), + [ TYPE_WOO_HOSTED_PRO ]: () => this.getEcommerceFeatures(), [ TYPE_BUSINESS ]: () => this.getBusinessFeatures(), [ TYPE_PREMIUM ]: () => this.getPremiumFeatures(), [ TYPE_PERSONAL ]: () => this.getPersonalFeatures(), diff --git a/client/dashboard/utils/site-plan.ts b/client/dashboard/utils/site-plan.ts index fcce34f7ad99..a9a3e1b4228b 100644 --- a/client/dashboard/utils/site-plan.ts +++ b/client/dashboard/utils/site-plan.ts @@ -129,6 +129,10 @@ export function useSitePlanManageURL( site: Site, purchase?: Purchase ) { return `https://agencies.automattic.com/sites/overview/${ site.slug }`; } + if ( isCommerceGarden( site ) ) { + return `${ protocol }//${ host }/setup/woo-hosted-plans?siteSlug=${ site.slug }`; + } + if ( site.plan?.is_free ) { return isCommerceGarden( site ) ? `${ protocol }//${ host }/plans/${ site.slug }` diff --git a/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/README.md b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/README.md new file mode 100644 index 000000000000..c334e4b5b18c --- /dev/null +++ b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/README.md @@ -0,0 +1,15 @@ +# woo-hosted flow + +## Testing instructions + +Please improve the instructions on how to test this flow. + +1. Go to /setup/woo-hosted-plans. + +## Owned by + +@michaeldcain + +## Context + + \ No newline at end of file diff --git a/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/style.scss b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/style.scss new file mode 100644 index 000000000000..db4f3a813de0 --- /dev/null +++ b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/style.scss @@ -0,0 +1,6 @@ +.is-section-stepper .woo-hosted-plans { + .step-container-v2__top-bar-wordpress-logo-wrapper, + .step-container-v2__top-bar-divider { + display: none; + } +} \ No newline at end of file diff --git a/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/woo-hosted-plans.ts b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/woo-hosted-plans.ts new file mode 100644 index 000000000000..1afc50fbef4c --- /dev/null +++ b/client/landing/stepper/declarative-flow/flows/woo-hosted-plans/woo-hosted-plans.ts @@ -0,0 +1,133 @@ +import { WOO_HOSTED_PLANS_FLOW } from '@automattic/onboarding'; +import { resolveSelect } from '@wordpress/data'; +import { __ } from '@wordpress/i18n'; +import { addQueryArgs } from '@wordpress/url'; +import { STEPS } from 'calypso/landing/stepper/declarative-flow/internals/steps'; +import { FlowV2, SubmitHandler } from 'calypso/landing/stepper/declarative-flow/internals/types'; +import { useQuery } from 'calypso/landing/stepper/hooks/use-query'; +import { SITE_STORE } from 'calypso/landing/stepper/stores'; +import { getCurrentQueryParams } from 'calypso/landing/stepper/utils/get-current-query-params'; +import { stepsWithRequiredLogin } from 'calypso/landing/stepper/utils/steps-with-required-login'; +import { isExternal } from 'calypso/lib/url'; +import './style.scss'; + +const BASE_STEPS = [ STEPS.UNIFIED_PLANS ]; + +/** + * Checks if the user has access to upgrade plans for the given site + */ +async function checkUserHasAccess(): Promise< boolean > { + // Get site slug or ID from query params + const queryParams = getCurrentQueryParams(); + const siteSlugFromQuery = queryParams.get( 'siteSlug' ); + const siteIdFromQuery = queryParams.get( 'siteId' ); + + const siteIdOrSlug = siteSlugFromQuery || siteIdFromQuery; + + if ( ! siteIdOrSlug ) { + return false; + } + + try { + const site = await resolveSelect( SITE_STORE ).getSite( siteIdOrSlug ); + + if ( ! site ) { + return false; + } + + // Check if user can manage the site using the capabilities from the site object + return site.capabilities?.manage_options === true; + } catch ( error ) { + return false; + } +} + +async function initialize() { + const hasAccess = await checkUserHasAccess(); + + if ( ! hasAccess ) { + window.location.assign( '/ciab/sites' ); + return false; + } + + return stepsWithRequiredLogin( BASE_STEPS ); +} + +const wooHostedPlansFlow: FlowV2< typeof initialize > = { + name: WOO_HOSTED_PLANS_FLOW, + title: __( 'Pick a plan for your store' ), + isSignupFlow: false, + __experimentalUseSessions: true, + __experimentalUseBuiltinAuth: true, + initialize, + + useStepsProps() { + const query = useQuery(); + const backTo = query.get( 'back_to' ) ?? query.get( 'cancel_to' ) ?? undefined; + + // Validate back_to to prevent open redirect - must not be external + const safeBackTo = backTo && ! isExternal( backTo ) ? backTo : '/ciab/sites'; + + return { + [ STEPS.UNIFIED_PLANS.slug ]: { + // This flag enables upgrade-specific behavior in PlansFeaturesMain + isStepperUpgradeFlow: true, + + // This is NOT a signup flow - use logged-in behavior for current plans + isInSignup: false, + + // Provide a custom back handler that goes to back_to or /ciab/sites + wrapperProps: { + goBack: () => { + window.location.assign( safeBackTo ); + }, + }, + + // Woo Hosted only supports monthly and yearly plans + displayedIntervals: [ 'monthly', 'yearly' ], + }, + }; + }, + + useStepNavigation() { + const query = useQuery(); + const siteSlug = query.get( 'siteSlug' ); + const redirectTo = query.get( 'redirect_to' ); + + const submit: SubmitHandler< typeof initialize > = ( submittedStep ) => { + const { slug, providedDependencies } = submittedStep; + + switch ( slug ) { + case STEPS.UNIFIED_PLANS.slug: { + // User selected plan, go directly to checkout + if ( providedDependencies?.cartItems && providedDependencies.cartItems.length > 0 ) { + const selectedPlan = providedDependencies.cartItems[ 0 ]?.product_slug; + if ( selectedPlan && siteSlug ) { + const checkoutUrl = `/checkout/${ encodeURIComponent( siteSlug ) }/${ selectedPlan }`; + const currentPath = window.location.href.replace( window.location.origin, '' ); + + // Build checkout URL with query params + // Note: Not using goToCheckout utility because it hardcodes signup=1 + // Checkout validates redirect_to to prevent open redirects + const finalUrl = addQueryArgs( checkoutUrl, { + redirect_to: redirectTo || '/ciab/sites', + cancel_to: currentPath, + } ); + + window.location.assign( finalUrl ); + } + return; + } + + // If no cart items, something went wrong - redirect to sites + window.location.assign( '/sites' ); + break; + } + } + }; + + return { submit }; + }, +}; + +export default wooHostedPlansFlow; diff --git a/client/landing/stepper/declarative-flow/helpers/should-use-step-container-v2.ts b/client/landing/stepper/declarative-flow/helpers/should-use-step-container-v2.ts index 03cde74cb438..e44f379b2921 100644 --- a/client/landing/stepper/declarative-flow/helpers/should-use-step-container-v2.ts +++ b/client/landing/stepper/declarative-flow/helpers/should-use-step-container-v2.ts @@ -7,6 +7,7 @@ import { ONBOARDING_UNIFIED_FLOW, DOMAIN_FLOW, PLAN_UPGRADE_FLOW, + WOO_HOSTED_PLANS_FLOW, } from '@automattic/onboarding'; const FLOWS_USING_STEP_CONTAINER_V2 = [ @@ -18,6 +19,7 @@ const FLOWS_USING_STEP_CONTAINER_V2 = [ ONBOARDING_UNIFIED_FLOW, DOMAIN_FLOW, PLAN_UPGRADE_FLOW, + WOO_HOSTED_PLANS_FLOW, ]; export const shouldUseStepContainerV2 = ( flow: string ) => { diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/index.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/index.tsx index 739e0cca5058..8ae1c3afa10e 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/index.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/index.tsx @@ -9,6 +9,7 @@ import { ONBOARDING_UNIFIED_FLOW, PLAN_UPGRADE_FLOW, START_WRITING_FLOW, + WOO_HOSTED_PLANS_FLOW, Step, useStepPersistedState, } from '@automattic/onboarding'; @@ -29,7 +30,7 @@ import { getTheme, getThemeType } from 'calypso/state/themes/selectors'; import { shouldUseStepContainerV2 } from '../../../helpers/should-use-step-container-v2'; import { playgroundPlansIntent } from '../playground/lib/plans'; import UnifiedPlansStep from './unified-plans-step'; -import { getIntervalType, getVisualSplitPlansIntent } from './util'; +import { getIntervalType, getVisualSplitPlansIntent, SupportedIntervalTypes } from './util'; import type { Step as StepType } from '../../types'; import type { PlansIntent } from '@automattic/plans-grid-next'; import type { MinimalRequestCartProduct } from '@automattic/shopping-cart'; @@ -73,6 +74,8 @@ function getPlansIntent( flowName: string | null ): PlansIntent | null { return 'plans-affiliate'; case PLAN_UPGRADE_FLOW: return 'plans-upgrade'; + case WOO_HOSTED_PLANS_FLOW: + return 'plans-woo-hosted'; default: return null; } @@ -90,6 +93,7 @@ const PlansStepAdaptor: StepType< { isInSignup?: boolean; isStepperUpgradeFlow?: boolean; selectedFeature?: string; + displayedIntervals?: SupportedIntervalTypes[]; wrapperProps?: { hideBack?: boolean; goBack?: () => void; @@ -98,7 +102,8 @@ const PlansStepAdaptor: StepType< { }; }; } > = ( props ) => { - const { isInSignup, isStepperUpgradeFlow, selectedFeature, wrapperProps } = props; + const { displayedIntervals, isInSignup, isStepperUpgradeFlow, selectedFeature, wrapperProps } = + props; const [ stepState, setStepState ] = useStepPersistedState< ProvidedDependencies >( 'plans-step' ); const siteSlug = useSiteSlug(); @@ -231,6 +236,7 @@ const PlansStepAdaptor: StepType< { onIntentChange={ handleIntentChange } onPlanIntervalUpdate={ onPlanIntervalUpdate } intervalType={ planInterval } + displayedIntervals={ displayedIntervals } wrapperProps={ { hideBack: wrapperProps?.hideBack ?? false, goBack: wrapperProps?.goBack ?? props.navigation.goBack, diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/unified-plans-step.tsx b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/unified-plans-step.tsx index 9453e9aaa693..120bd770f4a6 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/unified-plans-step.tsx +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/unified-plans-step.tsx @@ -403,9 +403,16 @@ function UnifiedPlansStep( { if ( intent === 'plans-wordpress-hosting' ) { return translate( 'Managed hosting without limits' ); - } else if ( intent === 'plans-website-builder' ) { + } + + if ( intent === 'plans-website-builder' ) { return translate( 'Create a beautiful WordPress website' ); } + + if ( intent === 'plans-woo-hosted' ) { + return translate( 'Select a plan to launch your store' ); + } + return translate( 'There’s a plan for you' ); }; @@ -455,6 +462,10 @@ function UnifiedPlansStep( { return null; // Use PlansFeaturesMain subheader for website-builder } + if ( intent === 'plans-woo-hosted' ) { + return translate( 'Your free trial ends soon - select a plan to keep your online store.' ); + } + if ( useEmailOnboardingSubheader ) { return translate( 'Add more features to your professional website with a plan. Or {{link}}start with email and a free site{{/link}}.', diff --git a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/util.ts b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/util.ts index 2b959a930c1e..da17254f5abe 100644 --- a/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/util.ts +++ b/client/landing/stepper/declarative-flow/internals/steps-repository/unified-plans/util.ts @@ -11,7 +11,7 @@ import { MinimalRequestCartProduct } from '@automattic/shopping-cart'; import { getPlanCartItem } from 'calypso/lib/cart-values/cart-items'; import { UnifiedPlansStepProps } from './unified-plans-step'; -type SupportedIntervalTypes = Extract< +export type SupportedIntervalTypes = Extract< UrlFriendlyTermType, 'monthly' | 'yearly' | '2yearly' | '3yearly' >; diff --git a/client/landing/stepper/declarative-flow/registered-flows.ts b/client/landing/stepper/declarative-flow/registered-flows.ts index edf2e78a5f5f..c0ac4d80e428 100644 --- a/client/landing/stepper/declarative-flow/registered-flows.ts +++ b/client/landing/stepper/declarative-flow/registered-flows.ts @@ -20,6 +20,7 @@ import { DOMAIN_AND_PLAN_FLOW, PLAN_UPGRADE_FLOW, FLEX_SITE_FLOW, + WOO_HOSTED_PLANS_FLOW, } from '@automattic/onboarding'; import type { Flow, FlowV2 } from '../declarative-flow/internals/types'; @@ -51,11 +52,17 @@ const availableFlows: Record< string, () => Promise< { default: FlowV2< any > } import( /* webpackChunkName: "ai-site-builder-spec-flow" */ './flows/ai-site-builder-spec/ai-site-builder-spec' ), + [ PLAN_UPGRADE_FLOW ]: () => import( /* webpackChunkName: "plan-upgrade-flow" */ './flows/plan-upgrade/plan-upgrade' ), [ FLEX_SITE_FLOW ]: () => import( /* webpackChunkName: "flex-site-flow" */ './flows/flex-site/flex-site' ), + + [ WOO_HOSTED_PLANS_FLOW ]: () => + import( + /* webpackChunkName: "woo-hosted-plans" */ './flows/woo-hosted-plans/woo-hosted-plans' + ), }; /** diff --git a/client/my-sites/checkout/src/components/checkout-main-content.tsx b/client/my-sites/checkout/src/components/checkout-main-content.tsx index 89c7a5819a27..47c72d1e9179 100644 --- a/client/my-sites/checkout/src/components/checkout-main-content.tsx +++ b/client/my-sites/checkout/src/components/checkout-main-content.tsx @@ -875,6 +875,7 @@ export default function CheckoutMainContent( { } + logo={ null } /> ); diff --git a/client/my-sites/plans-features-main/hooks/use-generate-action-hook.tsx b/client/my-sites/plans-features-main/hooks/use-generate-action-hook.tsx index a675bc3b192c..19ca44d787d0 100644 --- a/client/my-sites/plans-features-main/hooks/use-generate-action-hook.tsx +++ b/client/my-sites/plans-features-main/hooks/use-generate-action-hook.tsx @@ -406,8 +406,10 @@ function getLoggedInPlansAction( { } & UseActionHookProps ): GridAction { // Use plan type matching instead of exact slug matching for the 'plans-upgrade' intent. // This allows monthly/yearly versions of the same plan to be considered "current" + const isUpgradeFlow = + plansIntent && [ 'plans-upgrade', 'plans-woo-hosted' ].includes( plansIntent ); const current = - plansIntent === 'plans-upgrade' && sitePlanSlug + isUpgradeFlow && sitePlanSlug ? getPlanClass( sitePlanSlug ) === getPlanClass( planSlug ) : sitePlanSlug === planSlug; const isTrialPlan = @@ -448,7 +450,7 @@ function getLoggedInPlansAction( { // All actions for the current plan if ( current ) { // For the plans-upgrade intent, show "Your plan" as a non-clickable indicator - if ( plansIntent === 'plans-upgrade' ) { + if ( isUpgradeFlow ) { return { primary: { callback: () => {}, diff --git a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx index 45a55a68898e..39d6d696d6dd 100644 --- a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx +++ b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx @@ -7,7 +7,12 @@ import './style.scss'; export interface TopBarProps { leftElement?: ReactNode; rightElement?: ReactNode; + + /** + * Customize the TopBar logo, or pass `null` to hide the logo entirely. + */ logo?: ReactNode; + /** * Hide the WordPress wordmark when `compactLogo` is set. * Always show the WordPress logo instead. @@ -38,13 +43,12 @@ export const TopBar = ( { leftElement, rightElement, logo, compactLogo }: TopBar ); return (
- { logo ? logo : defaultLogo } + { logo || logo === null ? logo : defaultLogo } + + { logo !== null && leftElement &&
} { leftElement && ( - <> -
-
{ leftElement }
- +
{ leftElement }
) } { rightElement && (
{ rightElement }
diff --git a/packages/onboarding/src/utils/flows.ts b/packages/onboarding/src/utils/flows.ts index 63a821924f51..babdb9c499ef 100644 --- a/packages/onboarding/src/utils/flows.ts +++ b/packages/onboarding/src/utils/flows.ts @@ -40,6 +40,7 @@ export const AI_SITE_BUILDER_SPEC_FLOW = 'ai-site-builder-spec'; export const PLAYGROUND_FLOW = 'playground'; export const PLAN_UPGRADE_FLOW = 'plan-upgrade'; export const FLEX_SITE_FLOW = 'flex-site'; +export const WOO_HOSTED_PLANS_FLOW = 'woo-hosted-plans'; export const isNewsletterFlow = ( flowName: string | null | undefined ) => { return Boolean( flowName && NEWSLETTER_FLOW === flowName ); @@ -167,3 +168,7 @@ export const isPlaygroundFlow = ( flowName: string | null ) => { export const isDomainFlow = ( flowName: string | null ) => { return Boolean( flowName && [ DOMAIN_FLOW ].includes( flowName ) ); }; + +export const isWooHostedPlansFlow = ( flowName: string | null ) => { + return Boolean( flowName && [ WOO_HOSTED_PLANS_FLOW ].includes( flowName ) ); +}; diff --git a/packages/plans-grid-next/src/components/plan-button/style.scss b/packages/plans-grid-next/src/components/plan-button/style.scss index badc1aafeb4f..06032334a5ac 100644 --- a/packages/plans-grid-next/src/components/plan-button/style.scss +++ b/packages/plans-grid-next/src/components/plan-button/style.scss @@ -14,7 +14,8 @@ color: var(--color-text-inverted); } - &.is-free-plan { + &.is-free-plan, + &.is-woo-hosted-plan { background-color: var(--studio-wordpress-blue-50); &:focus { diff --git a/packages/plans-grid-next/src/hooks/data-store/use-grid-plans.tsx b/packages/plans-grid-next/src/hooks/data-store/use-grid-plans.tsx index cff76ccf8df4..23a62bf48a63 100644 --- a/packages/plans-grid-next/src/hooks/data-store/use-grid-plans.tsx +++ b/packages/plans-grid-next/src/hooks/data-store/use-grid-plans.tsx @@ -8,6 +8,8 @@ import { TYPE_PREMIUM, TYPE_WOOEXPRESS_MEDIUM, TYPE_WOOEXPRESS_SMALL, + TYPE_WOO_HOSTED_BASIC, + TYPE_WOO_HOSTED_PRO, getPlan, isBloggerPlan, applyTestFiltersToPlansList, @@ -142,6 +144,8 @@ export const usePlanTypesWithIntent = ( { ...( isEnterpriseAvailable ? [ TYPE_ENTERPRISE_GRID_WPCOM ] : [] ), TYPE_WOOEXPRESS_SMALL, TYPE_WOOEXPRESS_MEDIUM, + TYPE_WOO_HOSTED_BASIC, + TYPE_WOO_HOSTED_PRO, TYPE_P2_PLUS, ]; @@ -267,6 +271,9 @@ export const usePlanTypesWithIntent = ( { case 'plans-website-builder': planTypes = [ TYPE_FREE, TYPE_PERSONAL, TYPE_PREMIUM, TYPE_BUSINESS ]; break; + case 'plans-woo-hosted': + planTypes = [ TYPE_WOO_HOSTED_BASIC, TYPE_WOO_HOSTED_PRO ]; + break; default: planTypes = availablePlanTypes; } diff --git a/packages/plans-grid-next/src/types.ts b/packages/plans-grid-next/src/types.ts index 6c66de75dc29..8d10d3d58bf3 100644 --- a/packages/plans-grid-next/src/types.ts +++ b/packages/plans-grid-next/src/types.ts @@ -80,6 +80,7 @@ export type PlansIntent = | 'plans-upgrade' | 'plans-wordpress-hosting' | 'plans-website-builder' + | 'plans-woo-hosted' | 'default'; export interface PlanActionOverrides { From 5655f9466a2fd4c902c94cf2bc257b584528d305 Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Tue, 18 Nov 2025 11:27:40 -0500 Subject: [PATCH 2/6] Switch logo logic to a new hideLogo prop --- .../src/components/checkout-main-content.tsx | 2 +- .../components/TopBar/TopBar.tsx | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/client/my-sites/checkout/src/components/checkout-main-content.tsx b/client/my-sites/checkout/src/components/checkout-main-content.tsx index 47c72d1e9179..40bde7ef134a 100644 --- a/client/my-sites/checkout/src/components/checkout-main-content.tsx +++ b/client/my-sites/checkout/src/components/checkout-main-content.tsx @@ -875,7 +875,7 @@ export default function CheckoutMainContent( { } - logo={ null } + hideLogo /> ); diff --git a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx index 39d6d696d6dd..4adc9a30debc 100644 --- a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx +++ b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx @@ -20,9 +20,20 @@ export interface TopBarProps { * - Confirm with Design before changing functionality around this */ compactLogo?: 'always'; + + /** + * Hide the logo entirely. + */ + hideLogo?: boolean; } -export const TopBar = ( { leftElement, rightElement, logo, compactLogo }: TopBarProps ) => { +export const TopBar = ( { + leftElement, + rightElement, + logo, + compactLogo, + hideLogo = false, +}: TopBarProps ) => { const defaultLogo = (
- { logo || logo === null ? logo : defaultLogo } + { ! hideLogo && ( logo ?? defaultLogo ) } - { logo !== null && leftElement &&
} + { ! hideLogo && leftElement &&
} { leftElement && (
{ leftElement }
From 16678c7acda1fbd2acd5a159ba87f0ef20978420 Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Tue, 18 Nov 2025 12:37:48 -0500 Subject: [PATCH 3/6] Redirect to Woo Hosted upgrade flow for free plans --- client/dashboard/utils/site-plan.ts | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/client/dashboard/utils/site-plan.ts b/client/dashboard/utils/site-plan.ts index a9a3e1b4228b..35bb24f9a1e2 100644 --- a/client/dashboard/utils/site-plan.ts +++ b/client/dashboard/utils/site-plan.ts @@ -129,13 +129,9 @@ export function useSitePlanManageURL( site: Site, purchase?: Purchase ) { return `https://agencies.automattic.com/sites/overview/${ site.slug }`; } - if ( isCommerceGarden( site ) ) { - return `${ protocol }//${ host }/setup/woo-hosted-plans?siteSlug=${ site.slug }`; - } - if ( site.plan?.is_free ) { return isCommerceGarden( site ) - ? `${ protocol }//${ host }/plans/${ site.slug }` + ? `${ protocol }//${ host }/setup/woo-hosted-plans?siteSlug=${ site.slug }` : `${ protocol }//${ host }/setup/plan-upgrade?siteSlug=${ site.slug }`; } From 9efa21d99f2244f583fce7287d85992a6d52c148 Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Tue, 18 Nov 2025 15:04:52 -0500 Subject: [PATCH 4/6] Direct purchae upgrade to new flow --- .../me/billing-purchases/purchase-settings/index.tsx | 4 ++++ packages/api-core/src/upgrades/types.ts | 1 + 2 files changed, 5 insertions(+) diff --git a/client/dashboard/me/billing-purchases/purchase-settings/index.tsx b/client/dashboard/me/billing-purchases/purchase-settings/index.tsx index d70e3ac1079d..02488b9c26ef 100644 --- a/client/dashboard/me/billing-purchases/purchase-settings/index.tsx +++ b/client/dashboard/me/billing-purchases/purchase-settings/index.tsx @@ -124,6 +124,10 @@ function getUpgradeUrl( purchase: Purchase ): string | undefined { return `/plans/${ purchase.site_slug }`; } + if ( purchase.is_woo_hosted_product ) { + return `/setup/woo-hosted-plans?siteSlug=${ purchase.site_slug }`; + } + return getWpcomPlanGridUrl( purchase.site_slug ); } diff --git a/packages/api-core/src/upgrades/types.ts b/packages/api-core/src/upgrades/types.ts index 41efe3e78e66..c60e250d32b6 100644 --- a/packages/api-core/src/upgrades/types.ts +++ b/packages/api-core/src/upgrades/types.ts @@ -206,6 +206,7 @@ export interface Purchase { is_locked: boolean; is_plan: boolean; is_rechargable: boolean; + is_woo_hosted_product: boolean; /** * Determine if this is a kind of subscription that can currently be manually From 0e39803d7fd1001b3b7f949ff8f59a4daf15494d Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Tue, 18 Nov 2025 15:17:04 -0500 Subject: [PATCH 5/6] Add is_trial_plan to purhase type --- packages/api-core/src/upgrades/types.ts | 1 + 1 file changed, 1 insertion(+) diff --git a/packages/api-core/src/upgrades/types.ts b/packages/api-core/src/upgrades/types.ts index c60e250d32b6..415c07186c9c 100644 --- a/packages/api-core/src/upgrades/types.ts +++ b/packages/api-core/src/upgrades/types.ts @@ -193,6 +193,7 @@ export interface Purchase { */ is_domain_registration: boolean; + is_trial_plan: boolean; is_pending_registration: boolean; is_free_jetpack_stats_product: boolean; is_jetpack_backup_t1: boolean; From 649c7aabdde737d3da7cf40bb9457194d3ce5cac Mon Sep 17 00:00:00 2001 From: Michael Cain Date: Thu, 20 Nov 2025 10:52:49 -0500 Subject: [PATCH 6/6] Update logo type comment --- .../src/step-container-v2/components/TopBar/TopBar.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx index 4adc9a30debc..273a2b95d8d9 100644 --- a/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx +++ b/packages/onboarding/src/step-container-v2/components/TopBar/TopBar.tsx @@ -9,7 +9,8 @@ export interface TopBarProps { rightElement?: ReactNode; /** - * Customize the TopBar logo, or pass `null` to hide the logo entirely. + * Customize the TopBar logo. If this is not passed, the default logo will + * be used unless `hideLogo` is set. */ logo?: ReactNode;