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

Live Preview: Add the upgrade notice for Premium and Woo themes #83630

Merged
merged 12 commits into from
Nov 30, 2023
1 change: 1 addition & 0 deletions apps/wpcom-block-editor/src/wpcom/editor.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
@import "./features/use-classic-block-guide";
@import "./features/live-preview/upgrade-notice";

.blog-onboarding-hide {
.components-external-link, // "Connect an account" link in Jetpack sidebar
Expand Down
126 changes: 0 additions & 126 deletions apps/wpcom-block-editor/src/wpcom/features/live-preview.tsx

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
import {
FEATURE_WOOP,
WPCOM_FEATURES_ATOMIC,
WPCOM_FEATURES_PREMIUM_THEMES,
PLAN_PREMIUM,
PLAN_BUSINESS,
} from '@automattic/calypso-products';
import { getCalypsoUrl } from '@automattic/calypso-url';
import { useEffect, useState, useCallback } from 'react';
import wpcom from 'calypso/lib/wp';
import { PREMIUM_THEME, WOOCOMMERCE_THEME } from '../utils';
import { usePreviewingTheme } from './use-previewing-theme';
import type { SiteDetails } from '@automattic/data-stores';

const checkNeedUpgrade = ( {
site,
previewingThemeType,
}: {
site?: SiteDetails;
previewingThemeType?: string;
} ) => {
const activeFeatures = site?.plan?.features?.active;
if ( ! activeFeatures ) {
return false;
}

/**
* This logic is extracted from `client/state/themes/selectors/can-use-theme.js`.
*/
const canUseWooCommerceTheme =
previewingThemeType === WOOCOMMERCE_THEME &&
[ WPCOM_FEATURES_PREMIUM_THEMES, FEATURE_WOOP, WPCOM_FEATURES_ATOMIC ].every( ( feature ) =>
activeFeatures.includes( feature )
);
if ( canUseWooCommerceTheme ) {
return false;
}
const canUsePremiumTheme =
previewingThemeType === PREMIUM_THEME &&
activeFeatures.includes( WPCOM_FEATURES_PREMIUM_THEMES );
if ( canUsePremiumTheme ) {
return false;
}

return true;
};

export const useCanPreviewButNeedUpgrade = ( {
previewingTheme,
}: {
previewingTheme: ReturnType< typeof usePreviewingTheme >;
} ) => {
const [ canPreviewButNeedUpgrade, setCanPreviewButNeedUpgrade ] = useState( false );
const [ siteSlug, setSiteSlug ] = useState< string | undefined >();

/**
* Get the theme and site info to decide whether the user needs to upgrade the plan.
*/
useEffect( () => {
/**
* Currently, Live Preview only supports upgrades for WooCommerce and Premium themes.
*/
if ( previewingTheme.type !== WOOCOMMERCE_THEME && previewingTheme.type !== PREMIUM_THEME ) {
setCanPreviewButNeedUpgrade( false );
return;
}

wpcom.req
.get( `/sites/${ window._currentSiteId }`, { apiVersion: '1.2' } )
.then( ( site: any ) => {
let parsedUrl;
try {
parsedUrl = new URL( site.URL );
const { hostname } = parsedUrl;
setSiteSlug( hostname );
} catch {
// Invalid URL
}
return site;
} )
// eslint-disable-next-line @typescript-eslint/no-explicit-any
.then( ( site: any ) => {
if ( ! checkNeedUpgrade( { site, previewingThemeType: previewingTheme.type } ) ) {
setCanPreviewButNeedUpgrade( false );
return;
}
setCanPreviewButNeedUpgrade( true );
} )
.catch( () => {
// do nothing
} );
}, [ previewingTheme.type, setCanPreviewButNeedUpgrade, setSiteSlug ] );

const upgradePlan = useCallback( () => {
const generateCheckoutUrl = ( plan: string ) => {
const locationHref = window.location.href;
let url = locationHref;
try {
/**
* If the site has a custom domain, change the hostname to a custom domain.
* This allows the checkout to redirect back to the custom domain.
* @see `client/my-sites/checkout/src/hooks/use-valid-checkout-back-url.ts`
*/
if ( siteSlug ) {
const parsedUrl = new URL( locationHref );
parsedUrl.hostname = siteSlug;
url = parsedUrl.toString();
}
} catch ( error ) {
// Do nothing.
}
return `${ getCalypsoUrl() }/checkout/${
window._currentSiteId
}/${ plan }?redirect_to=${ encodeURIComponent( url ) }&checkoutBackUrl=${ encodeURIComponent(
url
) }`;
};
const link =
previewingTheme.type === WOOCOMMERCE_THEME
? /**
* For a WooCommerce theme, the users should have the Business plan or higher,
* AND the WooCommerce plugin has to be installed.
*/
generateCheckoutUrl( PLAN_BUSINESS )
: // For a Premium theme, the users should have the Premium plan or higher.
generateCheckoutUrl( PLAN_PREMIUM );
window.location.href = link;

// TODO: Add the track event.
}, [ previewingTheme.type, siteSlug ] );

return {
canPreviewButNeedUpgrade,
upgradePlan,
};
};
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
import { useEffect, useState } from 'react';
import wpcom from 'calypso/lib/wp';
import { currentlyPreviewingTheme, PREMIUM_THEME, WOOCOMMERCE_THEME } from '../utils';
import type { Theme } from 'calypso/types';

/**
* Get the theme type.
* This only support WooCommerce and Premium themes.
*/
const getThemeType = ( theme?: Theme ) => {
const theme_software_set = theme?.taxonomies?.theme_software_set;
const isWooCommerceTheme = theme_software_set && theme_software_set.length > 0;
Copy link
Contributor

Choose a reason for hiding this comment

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

I think a theme is a WooCommerce theme if it has woo-on-plans in the software sets, can you double check?

Copy link
Member Author

@okmttdhr okmttdhr Nov 27, 2023

Choose a reason for hiding this comment

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

You seem to be right (I might look into deeper a bit).
The getThemeType selector

if ( doesThemeBundleSoftwareSet( state, themeId ) ) {
return WOOCOMMERCE_THEME;
}
is using the same logic (as I extracted the logic from here), so It'd be nice to fix it as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

The getThemeType was first introduced in #75396 (and then extracted as a selector in #77550).
I believe we are not purposely using doesThemeBundleSoftwareSet for the WOOCOMMERCE_THEME condition. 🙂 I'll address this in another PR so that it checks woo-on-plans (e.g.,

const themeHasWooCommerce = selectedDesign?.software_sets?.find(
( set ) => set.slug === 'woo-on-plans'
);
,
const is_bundled_with_woo_commerce = ( design.software_sets || [] ).some(
( { slug } ) => slug === 'woo-on-plans'
);
). @fushar @Automattic/t-rex

Copy link
Contributor

Choose a reason for hiding this comment

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

getThemeType is being refactored in a different way in https://github.com/Automattic/wp-calypso/pull/84483/files#diff-136055987b5718b1aa6eb57c3cda1dad677dd540def25ff13f9985936cb14019 I haven't dug into it yet but it looks like it is using the concept of "bundled theme" rather than specific woo/sensei theme types

if ( isWooCommerceTheme ) {
return WOOCOMMERCE_THEME;
}
const themeStylesheet = theme?.stylesheet;
const isPremiumTheme = themeStylesheet && themeStylesheet.startsWith( 'premium/' );
if ( isPremiumTheme ) {
return PREMIUM_THEME;
}
return undefined;
};

export const usePreviewingTheme = () => {
const previewingThemeSlug = currentlyPreviewingTheme();
const previewingThemeId =
( previewingThemeSlug as string )?.split( '/' )?.[ 1 ] || previewingThemeSlug;
const [ previewingThemeName, setPreviewingThemeName ] = useState< string >(
previewingThemeSlug as string
);
const [ previewingThemeType, setPreviewingThemeType ] = useState< string >();
const previewingThemeTypeDisplay =
previewingThemeType === WOOCOMMERCE_THEME ? 'WooCommerce' : 'Premium';

useEffect( () => {
wpcom.req
.get( `/themes/${ previewingThemeId }`, { apiVersion: '1.2' } )
.then( ( theme: Theme ) => {
const name = theme?.name;
if ( name ) {
setPreviewingThemeName( name );
}
return theme;
} )
.then( ( theme: Theme ) => {
const type = getThemeType( theme );
if ( ! type ) {
return;
}
setPreviewingThemeType( type );
} )
.catch( () => {
// do nothing
} );
return;
}, [ previewingThemeId ] );

return {
name: previewingThemeName,
type: previewingThemeType,
typeDisplay: previewingThemeTypeDisplay,
};
};
Loading
Loading