Detect cache when launching store (#48586)

* Remove duplicate

* Add is-coming-soon-page endpoint

* Render invalid cache warning

* Use meta tag instead

* Add url for debug purpose

* Use a different copy for the congrats page when the cache is still shown

* Clean up unused codes

* Guard the api with permission

* Add changefile(s) from automation for the following project(s): woocommerce

* Reuse $is_fse_theme

* Lint fixes

* Update 48586-update-48516-detect-cache-when-launching-store

* Add changefile(s) from automation for the following project(s): woocommerce

* Add changefile(s) from automation for the following project(s): woocommerce

* Update plugins/woocommerce/changelog/48586-update-48516-detect-cache-when-launching-store

Co-authored-by: Chi-Hsuan Huang <chihsuan.tw@gmail.com>

* Add changefile(s) from automation for the following project(s): woocommerce

* changed to js method

* Add changefile(s) from automation for the following project(s): @woocommerce/data, woocommerce

* empty commit to trigger CI

* Add changefile(s) from automation for the following project(s): @woocommerce/data, woocommerce

* empty commit to trigger CI

---------

Co-authored-by: github-actions <github-actions@github.com>
Co-authored-by: Chi-Hsuan Huang <chihsuan.tw@gmail.com>
Co-authored-by: rjchow <me@rjchow.com>
This commit is contained in:
Moon 2024-06-19 03:23:29 -07:00 committed by GitHub
parent efc9dc4c62
commit f95d8b240b
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 184 additions and 16 deletions

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Verify if the coming soon cache is displayed when launching the store and alerts the user if it is still present.

View File

@ -1,6 +1,6 @@
export type Settings = { export type Settings = {
[ key: string ]: unknown; [ key: string ]: unknown;
} & { } & { siteUrl?: string; shopUrl?: string } & {
general?: { general?: {
[ key: string ]: string; [ key: string ]: string;
}; };

View File

@ -29,12 +29,14 @@ export type CongratsProps = {
isWooExpress: boolean; isWooExpress: boolean;
completeSurvey: () => void; completeSurvey: () => void;
children?: React.ReactNode; children?: React.ReactNode;
siteIsShowingCachedContent: boolean;
}; };
export const Congrats = ( { export const Congrats = ( {
hasCompleteSurvey, hasCompleteSurvey,
isWooExpress, isWooExpress,
completeSurvey, completeSurvey,
siteIsShowingCachedContent,
children, children,
}: CongratsProps ) => { }: CongratsProps ) => {
const copyLink = __( 'Copy link', 'woocommerce' ); const copyLink = __( 'Copy link', 'woocommerce' );
@ -116,13 +118,39 @@ export const Congrats = ( {
</div> </div>
<div className="woocommerce-launch-store__congrats-content"> <div className="woocommerce-launch-store__congrats-content">
<h1 className="woocommerce-launch-store__congrats-heading"> <h1 className="woocommerce-launch-store__congrats-heading">
{ __( { siteIsShowingCachedContent
? __(
'Congratulations! Your store will launch soon',
'woocommerce'
)
: __(
'Congratulations! Your store is now live', 'Congratulations! Your store is now live',
'woocommerce' 'woocommerce'
) } ) }
</h1> </h1>
<h2 className="woocommerce-launch-store__congrats-subheading"> <h2 className="woocommerce-launch-store__congrats-subheading">
{ siteIsShowingCachedContent
? createInterpolateElement(
__(
'Itll be ready to view as soon as your <link></link> have updated. Please wait, or contact your web host to find out how to do this manually.',
'woocommerce'
),
{
link: (
<a
href="https://woocommerce.com/document/server-caches/"
target="_blank"
rel="noreferrer"
>
{ __( { __(
'server caches',
'woocommerce'
) }
</a>
),
}
)
: __(
"You've successfully launched your store and are ready to start selling! We can't wait to see your business grow.", "You've successfully launched your store and are ready to start selling! We can't wait to see your business grow.",
'woocommerce' 'woocommerce'
) } ) }

View File

@ -43,6 +43,9 @@ export const LaunchYourStoreSuccess = ( props: MainContentComponentProps ) => {
} }
isWooExpress={ isWooExpress() } isWooExpress={ isWooExpress() }
completeSurvey={ completeSurvey } completeSurvey={ completeSurvey }
siteIsShowingCachedContent={
props.context.siteIsShowingCachedContent
}
> >
<h2 className="woocommerce-launch-store__congrats-main-actions-title"> <h2 className="woocommerce-launch-store__congrats-main-actions-title">
{ __( "What's next?", 'woocommerce' ) } { __( "What's next?", 'woocommerce' ) }

View File

@ -99,6 +99,9 @@
letter-spacing: -0.1px; letter-spacing: -0.1px;
margin: 4px 0 0; margin: 4px 0 0;
max-width: 560px; max-width: 560px;
a {
text-decoration: none;
}
} }
.woocommerce-launch-store__congrats-main-actions-title { .woocommerce-launch-store__congrats-main-actions-title {

View File

@ -27,6 +27,7 @@ export type MainContentMachineContext = {
allTasklists: TaskListType[]; allTasklists: TaskListType[];
activePlugins: string[]; activePlugins: string[];
}; };
siteIsShowingCachedContent: boolean;
}; };
export type MainContentComponentProps = LaunchYourStoreComponentProps & { export type MainContentComponentProps = LaunchYourStoreComponentProps & {
@ -34,6 +35,7 @@ export type MainContentComponentProps = LaunchYourStoreComponentProps & {
}; };
export type MainContentMachineEvents = export type MainContentMachineEvents =
| { type: 'SHOW_LAUNCH_STORE_SUCCESS' } | { type: 'SHOW_LAUNCH_STORE_SUCCESS' }
| { type: 'SHOW_LAUNCH_STORE_PENDING_CACHE' }
| { type: 'EXTERNAL_URL_UPDATE' } | { type: 'EXTERNAL_URL_UPDATE' }
| { type: 'SHOW_LOADING' } | { type: 'SHOW_LOADING' }
| congratsEvents; | congratsEvents;
@ -54,6 +56,9 @@ export const mainContentMachine = setup( {
) => { ) => {
updateQueryParams( params ); updateQueryParams( params );
}, },
assignSiteCachedStatus: assign( {
siteIsShowingCachedContent: true,
} ),
}, },
guards: { guards: {
hasContentLocation: ( hasContentLocation: (
@ -78,6 +83,7 @@ export const mainContentMachine = setup( {
allTasklists: [], allTasklists: [],
activePlugins: [], activePlugins: [],
}, },
siteIsShowingCachedContent: false,
}, },
invoke: { invoke: {
id: 'contentQueryParamListener', id: 'contentQueryParamListener',
@ -149,6 +155,10 @@ export const mainContentMachine = setup( {
SHOW_LAUNCH_STORE_SUCCESS: { SHOW_LAUNCH_STORE_SUCCESS: {
target: '#launchStoreSuccess', target: '#launchStoreSuccess',
}, },
SHOW_LAUNCH_STORE_PENDING_CACHE: {
actions: [ 'assignSiteCachedStatus' ],
target: '#launchStoreSuccess',
},
SHOW_LOADING: { SHOW_LOADING: {
target: '#loading', target: '#loading',
}, },

View File

@ -9,12 +9,18 @@ import {
fromPromise, fromPromise,
assign, assign,
spawnChild, spawnChild,
enqueueActions,
} from 'xstate5'; } from 'xstate5';
import React from 'react'; import React from 'react';
import clsx from 'clsx'; import clsx from 'clsx';
import { getQuery, navigateTo } from '@woocommerce/navigation'; import { getQuery, navigateTo } from '@woocommerce/navigation';
import { OPTIONS_STORE_NAME, TaskListType, TaskType } from '@woocommerce/data'; import {
import { dispatch } from '@wordpress/data'; OPTIONS_STORE_NAME,
SETTINGS_STORE_NAME,
TaskListType,
TaskType,
} from '@woocommerce/data';
import { dispatch, resolveSelect } from '@wordpress/data';
import { recordEvent } from '@woocommerce/tracks'; import { recordEvent } from '@woocommerce/tracks';
import apiFetch from '@wordpress/api-fetch'; import apiFetch from '@wordpress/api-fetch';
@ -44,6 +50,7 @@ export type SidebarMachineContext = {
launchStoreError?: { launchStoreError?: {
message: string; message: string;
}; };
siteIsShowingCachedContent?: boolean;
}; };
export type SidebarComponentProps = LaunchYourStoreComponentProps & { export type SidebarComponentProps = LaunchYourStoreComponentProps & {
context: SidebarMachineContext; context: SidebarMachineContext;
@ -81,6 +88,64 @@ const getTestOrderCount = async () => {
return result.count; return result.count;
}; };
export const pageHasComingSoonMetaTag = async ( {
url,
}: {
url: string;
} ): Promise< boolean > => {
try {
const response = await fetch( url, {
method: 'GET',
credentials: 'omit',
cache: 'no-store',
} );
if ( ! response.ok ) {
throw new Error( `Failed to fetch ${ url }` );
}
const html = await response.text();
const parser = new DOMParser();
const doc = parser.parseFromString( html, 'text/html' );
const metaTag = doc.querySelector(
'meta[name="woo-coming-soon-page"]'
);
if ( metaTag ) {
return true;
}
return false;
} catch ( error ) {
throw new Error( `Error fetching ${ url }: ${ error }` );
}
};
const getSiteCachedStatus = async () => {
const settings = await resolveSelect( SETTINGS_STORE_NAME ).getSettings(
'wc_admin'
);
// if store URL exists, check both storeUrl and siteUrl otherwise only check siteUrl
// we want to check both because there's a chance that caching is especially disabled for woocommerce pages, e.g WPEngine
const requests = [] as Promise< boolean >[];
if ( settings?.shopUrl ) {
requests.push(
pageHasComingSoonMetaTag( {
url: settings.shopUrl,
} )
);
}
if ( settings?.siteUrl ) {
requests.push(
pageHasComingSoonMetaTag( {
url: settings.siteUrl,
} )
);
}
const results = await Promise.all( requests );
return results.some( ( result ) => result );
};
const deleteTestOrders = async ( { const deleteTestOrders = async ( {
input, input,
}: { }: {
@ -154,6 +219,10 @@ export const sidebarMachine = setup( {
( { context } ) => context.mainContentMachineRef, ( { context } ) => context.mainContentMachineRef,
{ type: 'SHOW_LAUNCH_STORE_SUCCESS' } { type: 'SHOW_LAUNCH_STORE_SUCCESS' }
), ),
showLaunchStorePendingCache: sendTo(
( { context } ) => context.mainContentMachineRef,
{ type: 'SHOW_LAUNCH_STORE_PENDING_CACHE' }
),
showLoadingPage: sendTo( showLoadingPage: sendTo(
( { context } ) => context.mainContentMachineRef, ( { context } ) => context.mainContentMachineRef,
{ type: 'SHOW_LOADING' } { type: 'SHOW_LOADING' }
@ -189,6 +258,11 @@ export const sidebarMachine = setup( {
success success
); );
}, },
recordStoreLaunchCachedContentDetected: () => {
recordEvent(
'launch_your_store_hub_store_launch_cached_content_detected'
);
},
}, },
guards: { guards: {
hasSidebarLocation: ( hasSidebarLocation: (
@ -203,11 +277,15 @@ export const sidebarMachine = setup( {
'woocommerce-payments' 'woocommerce-payments'
); );
}, },
siteIsShowingCachedContent: ( { context } ) => {
return !! context.siteIsShowingCachedContent;
},
}, },
actors: { actors: {
sidebarQueryParamListener, sidebarQueryParamListener,
getTasklist: fromPromise( getLysTasklist ), getTasklist: fromPromise( getLysTasklist ),
getTestOrderCount: fromPromise( getTestOrderCount ), getTestOrderCount: fromPromise( getTestOrderCount ),
getSiteCachedStatus: fromPromise( getSiteCachedStatus ),
updateLaunchStoreOptions: fromPromise( launchStoreAction ), updateLaunchStoreOptions: fromPromise( launchStoreAction ),
deleteTestOrders: fromPromise( deleteTestOrders ), deleteTestOrders: fromPromise( deleteTestOrders ),
fetchCongratsData, fetchCongratsData,
@ -317,13 +395,13 @@ export const sidebarMachine = setup( {
{ {
src: 'updateLaunchStoreOptions', src: 'updateLaunchStoreOptions',
onDone: { onDone: {
target: '#storeLaunchSuccessful',
actions: [ actions: [
{ {
type: 'recordStoreLaunchResults', type: 'recordStoreLaunchResults',
params: { success: true }, params: { success: true },
}, },
], ],
target: 'checkingForCachedContent',
}, },
onError: { onError: {
actions: [ actions: [
@ -360,6 +438,23 @@ export const sidebarMachine = setup( {
}, },
], ],
}, },
checkingForCachedContent: {
invoke: [
{
src: 'getSiteCachedStatus',
onDone: {
target: '#storeLaunchSuccessful',
actions: assign( {
siteIsShowingCachedContent: ( { event } ) =>
event.output,
} ),
},
onError: {
target: '#storeLaunchSuccessful',
},
},
],
},
}, },
}, },
storeLaunchSuccessful: { storeLaunchSuccessful: {
@ -373,7 +468,18 @@ export const sidebarMachine = setup( {
content: 'launch-store-success', content: 'launch-store-success',
}, },
}, },
{ type: 'showLaunchStoreSuccessPage' }, enqueueActions( ( { check, enqueue } ) => {
if ( check( 'siteIsShowingCachedContent' ) ) {
enqueue( {
type: 'showLaunchStorePendingCache',
} );
enqueue( {
type: 'recordStoreLaunchCachedContentDetected',
} );
return;
}
enqueue( { type: 'showLaunchStoreSuccessPage' } );
} ),
], ],
}, },
openExternalUrl: { openExternalUrl: {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: tweak
Verify if the coming soon cache is displayed when launching the store and alerts the user if it is still present.

View File

@ -52,17 +52,27 @@ class ComingSoonRequestHandler {
$coming_soon_template = get_query_template( 'coming-soon' ); $coming_soon_template = get_query_template( 'coming-soon' );
if ( ! wc_current_theme_is_fse_theme() && $this->coming_soon_helper->is_store_coming_soon() ) { $is_fse_theme = wc_current_theme_is_fse_theme();
$is_store_coming_soon = $this->coming_soon_helper->is_store_coming_soon();
if ( ! $is_fse_theme && $is_store_coming_soon ) {
get_header(); get_header();
} }
add_action(
'wp_head',
function () {
echo "<meta name='woo-coming-soon-page' content='yes'>";
}
);
include $coming_soon_template; include $coming_soon_template;
if ( ! wc_current_theme_is_fse_theme() && $this->coming_soon_helper->is_store_coming_soon() ) { if ( ! $is_fse_theme && $is_store_coming_soon ) {
get_footer(); get_footer();
} }
if ( wc_current_theme_is_fse_theme() ) { if ( $is_fse_theme ) {
// Since we've already rendered a template, return null to ensure no other template is rendered. // Since we've already rendered a template, return null to ensure no other template is rendered.
return null; return null;
} else { } else {