Replace "Personalize Your Store" Task with "Choose Your Theme" (#40239)
* Update appearance task to choose a WP theme * Add changelog * Update redirect URL Redirects to the main theme screen. * Update plugins/woocommerce/src/Admin/Features/OnboardingTasks/Tasks/Appearance.php Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com> * Wrap URL in getAdminLink * Update position of task * Change title * Change redirect URL to be the site editor * Revert to original task name * Use inherited is_complete function * Use PHP-based action tracking * Fix lint issue --------- Co-authored-by: Ilyas Foo <foo.ilyas@gmail.com>
This commit is contained in:
parent
5bc0789921
commit
76b8042359
|
@ -1,431 +1,36 @@
|
|||
/**
|
||||
* External dependencies
|
||||
*/
|
||||
import { __ } from '@wordpress/i18n';
|
||||
import apiFetch from '@wordpress/api-fetch';
|
||||
import { Button, Card, CardBody } from '@wordpress/components';
|
||||
import { Component, Fragment } from '@wordpress/element';
|
||||
import { compose } from '@wordpress/compose';
|
||||
import { filter } from 'lodash';
|
||||
import { withDispatch, withSelect } from '@wordpress/data';
|
||||
|
||||
import { Stepper, TextControl, ImageUpload } from '@woocommerce/components';
|
||||
import {
|
||||
OPTIONS_STORE_NAME,
|
||||
ONBOARDING_STORE_NAME,
|
||||
WC_ADMIN_NAMESPACE,
|
||||
} from '@woocommerce/data';
|
||||
import { queueRecordEvent, recordEvent } from '@woocommerce/tracks';
|
||||
import React from 'react';
|
||||
import { WooOnboardingTaskListItem } from '@woocommerce/onboarding';
|
||||
import { registerPlugin } from '@wordpress/plugins';
|
||||
import { WooOnboardingTask } from '@woocommerce/onboarding';
|
||||
import { getAdminLink } from '@woocommerce/settings';
|
||||
|
||||
/**
|
||||
* Internal dependencies
|
||||
*/
|
||||
class Appearance extends Component {
|
||||
constructor( props ) {
|
||||
super( props );
|
||||
const { hasHomepage, hasProducts, supportCustomLogo } =
|
||||
props.task.additionalData;
|
||||
|
||||
this.stepVisibility = {
|
||||
homepage: ! hasHomepage,
|
||||
import: ! hasProducts,
|
||||
logo: supportCustomLogo,
|
||||
};
|
||||
|
||||
this.state = {
|
||||
isDirty: false,
|
||||
isPending: false,
|
||||
logo: null,
|
||||
stepIndex: 0,
|
||||
isUpdatingLogo: false,
|
||||
isUpdatingNotice: false,
|
||||
storeNoticeText: props.demoStoreNotice || '',
|
||||
};
|
||||
|
||||
this.completeStep = this.completeStep.bind( this );
|
||||
this.createHomepage = this.createHomepage.bind( this );
|
||||
this.importProducts = this.importProducts.bind( this );
|
||||
this.updateLogo = this.updateLogo.bind( this );
|
||||
this.updateNotice = this.updateNotice.bind( this );
|
||||
}
|
||||
|
||||
componentDidMount() {
|
||||
const { themeMods } = this.props.task.additionalData;
|
||||
|
||||
if ( themeMods && themeMods.custom_logo ) {
|
||||
/* eslint-disable react/no-did-mount-set-state */
|
||||
this.setState( { logo: { id: themeMods.custom_logo } } );
|
||||
/* eslint-enable react/no-did-mount-set-state */
|
||||
}
|
||||
}
|
||||
|
||||
componentDidUpdate( prevProps ) {
|
||||
const { isPending, logo } = this.state;
|
||||
const { demoStoreNotice } = this.props;
|
||||
|
||||
if ( logo && ! logo.url && ! isPending ) {
|
||||
/* eslint-disable react/no-did-update-set-state */
|
||||
this.setState( { isPending: true } );
|
||||
wp.media
|
||||
.attachment( logo.id )
|
||||
.fetch()
|
||||
.then( () => {
|
||||
const logoUrl = wp.media.attachment( logo.id ).get( 'url' );
|
||||
this.setState( {
|
||||
isPending: false,
|
||||
logo: { id: logo.id, url: logoUrl },
|
||||
} );
|
||||
} );
|
||||
/* eslint-enable react/no-did-update-set-state */
|
||||
}
|
||||
|
||||
if (
|
||||
demoStoreNotice &&
|
||||
prevProps.demoStoreNotice !== demoStoreNotice
|
||||
) {
|
||||
/* eslint-disable react/no-did-update-set-state */
|
||||
this.setState( {
|
||||
storeNoticeText: demoStoreNotice,
|
||||
} );
|
||||
/* eslint-enable react/no-did-update-set-state */
|
||||
}
|
||||
}
|
||||
|
||||
async completeStep() {
|
||||
const { stepIndex } = this.state;
|
||||
const { actionTask, onComplete } = this.props;
|
||||
const nextStep = this.getSteps()[ stepIndex + 1 ];
|
||||
|
||||
if ( nextStep ) {
|
||||
this.setState( { stepIndex: stepIndex + 1 } );
|
||||
} else {
|
||||
this.setState( { isPending: true } );
|
||||
await actionTask( 'appearance' );
|
||||
onComplete();
|
||||
}
|
||||
}
|
||||
|
||||
importProducts() {
|
||||
const { createNotice } = this.props;
|
||||
this.setState( { isPending: true } );
|
||||
|
||||
recordEvent( 'tasklist_appearance_import_demo', {} );
|
||||
|
||||
apiFetch( {
|
||||
path: `${ WC_ADMIN_NAMESPACE }/onboarding/tasks/import_sample_products`,
|
||||
method: 'POST',
|
||||
} )
|
||||
.then( ( result ) => {
|
||||
if ( result.failed && result.failed.length ) {
|
||||
createNotice(
|
||||
'error',
|
||||
__(
|
||||
'There was an error importing some of the sample products',
|
||||
'woocommerce'
|
||||
)
|
||||
);
|
||||
} else {
|
||||
createNotice(
|
||||
'success',
|
||||
__(
|
||||
'All sample products have been imported',
|
||||
'woocommerce'
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
this.setState( { isPending: false } );
|
||||
this.completeStep();
|
||||
} )
|
||||
.catch( ( { message } ) => {
|
||||
createNotice(
|
||||
'error',
|
||||
message ||
|
||||
__(
|
||||
'There was an error importing the sample products',
|
||||
'woocommerce'
|
||||
),
|
||||
{ __unstableHTML: true }
|
||||
);
|
||||
this.setState( { isPending: false } );
|
||||
} );
|
||||
}
|
||||
|
||||
createHomepage() {
|
||||
const { createNotice } = this.props;
|
||||
this.setState( { isPending: true } );
|
||||
|
||||
recordEvent( 'tasklist_appearance_create_homepage', {
|
||||
create_homepage: true,
|
||||
} );
|
||||
|
||||
apiFetch( {
|
||||
path: '/wc-admin/onboarding/tasks/create_homepage',
|
||||
method: 'POST',
|
||||
} )
|
||||
.then( ( response ) => {
|
||||
createNotice( response.status, response.message, {
|
||||
actions: response.edit_post_link
|
||||
? [
|
||||
{
|
||||
label: __( 'Customize', 'woocommerce' ),
|
||||
onClick: () => {
|
||||
queueRecordEvent(
|
||||
'tasklist_appearance_customize_homepage',
|
||||
{}
|
||||
);
|
||||
window.location = `${ response.edit_post_link }&wc_onboarding_active_task=appearance`;
|
||||
},
|
||||
},
|
||||
]
|
||||
: null,
|
||||
} );
|
||||
|
||||
this.setState( { isPending: false } );
|
||||
this.completeStep();
|
||||
} )
|
||||
.catch( ( error ) => {
|
||||
createNotice( 'error', error.message );
|
||||
this.setState( { isPending: false } );
|
||||
} );
|
||||
}
|
||||
|
||||
async updateLogo() {
|
||||
const { createNotice, task, updateOptions } = this.props;
|
||||
const { stylesheet, themeMods } = task.additionalData;
|
||||
const { logo } = this.state;
|
||||
const updatedThemeMods = {
|
||||
...themeMods,
|
||||
custom_logo: logo ? logo.id : null,
|
||||
};
|
||||
|
||||
recordEvent( 'tasklist_appearance_upload_logo' );
|
||||
|
||||
this.setState( { isUpdatingLogo: true } );
|
||||
const update = await updateOptions( {
|
||||
[ `theme_mods_${ stylesheet }` ]: updatedThemeMods,
|
||||
} );
|
||||
|
||||
if ( update.success ) {
|
||||
this.setState( { isUpdatingLogo: false } );
|
||||
createNotice(
|
||||
'success',
|
||||
__( 'Store logo updated successfully', 'woocommerce' )
|
||||
);
|
||||
this.completeStep();
|
||||
} else {
|
||||
createNotice( 'error', update.message );
|
||||
}
|
||||
}
|
||||
|
||||
async updateNotice() {
|
||||
const { createNotice, updateOptions } = this.props;
|
||||
const { storeNoticeText } = this.state;
|
||||
|
||||
recordEvent( 'tasklist_appearance_set_store_notice', {
|
||||
added_text: Boolean( storeNoticeText.length ),
|
||||
} );
|
||||
|
||||
this.setState( { isUpdatingNotice: true } );
|
||||
const update = await updateOptions( {
|
||||
woocommerce_demo_store: storeNoticeText.length ? 'yes' : 'no',
|
||||
woocommerce_demo_store_notice: storeNoticeText,
|
||||
} );
|
||||
|
||||
if ( update.success ) {
|
||||
this.setState( { isUpdatingNotice: false } );
|
||||
createNotice(
|
||||
'success',
|
||||
__(
|
||||
"🎨 Your store is looking great! Don't forget to continue personalizing it",
|
||||
'woocommerce'
|
||||
)
|
||||
);
|
||||
this.completeStep();
|
||||
} else {
|
||||
createNotice( 'error', update.message );
|
||||
}
|
||||
}
|
||||
|
||||
getSteps() {
|
||||
const { isDirty, isPending, logo, storeNoticeText, isUpdatingLogo } =
|
||||
this.state;
|
||||
|
||||
const steps = [
|
||||
{
|
||||
key: 'import',
|
||||
label: __( 'Import sample products', 'woocommerce' ),
|
||||
description: __(
|
||||
'We’ll add some products that will make it easier to see what your store looks like',
|
||||
'woocommerce'
|
||||
),
|
||||
content: (
|
||||
<Fragment>
|
||||
<Button
|
||||
onClick={ this.importProducts }
|
||||
isBusy={ isPending }
|
||||
isPrimary
|
||||
>
|
||||
{ __( 'Import products', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button onClick={ () => this.completeStep() }>
|
||||
{ __( 'Skip', 'woocommerce' ) }
|
||||
</Button>
|
||||
</Fragment>
|
||||
),
|
||||
visible: this.stepVisibility.import,
|
||||
},
|
||||
{
|
||||
key: 'homepage',
|
||||
label: __( 'Create a custom homepage', 'woocommerce' ),
|
||||
description: __(
|
||||
'Create a new homepage and customize it to suit your needs',
|
||||
'woocommerce'
|
||||
),
|
||||
content: (
|
||||
<Fragment>
|
||||
<Button
|
||||
isPrimary
|
||||
isBusy={ isPending }
|
||||
onClick={ this.createHomepage }
|
||||
>
|
||||
{ __( 'Create homepage', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button
|
||||
isTertiary
|
||||
onClick={ () => {
|
||||
recordEvent(
|
||||
'tasklist_appearance_create_homepage',
|
||||
{ create_homepage: false }
|
||||
);
|
||||
this.completeStep();
|
||||
} }
|
||||
>
|
||||
{ __( 'Skip', 'woocommerce' ) }
|
||||
</Button>
|
||||
</Fragment>
|
||||
),
|
||||
visible: this.stepVisibility.homepage,
|
||||
},
|
||||
{
|
||||
key: 'logo',
|
||||
label: __( 'Upload a logo', 'woocommerce' ),
|
||||
description: __(
|
||||
'Ensure your store is on-brand by adding your logo',
|
||||
'woocommerce'
|
||||
),
|
||||
content: isPending ? null : (
|
||||
<Fragment>
|
||||
<ImageUpload
|
||||
image={ logo }
|
||||
onChange={ ( image ) =>
|
||||
this.setState( { isDirty: true, logo: image } )
|
||||
}
|
||||
/>
|
||||
<Button
|
||||
disabled={ ! logo && ! isDirty }
|
||||
onClick={ this.updateLogo }
|
||||
isBusy={ isUpdatingLogo }
|
||||
isPrimary
|
||||
>
|
||||
{ __( 'Continue', 'woocommerce' ) }
|
||||
</Button>
|
||||
<Button
|
||||
isTertiary
|
||||
onClick={ () => this.completeStep() }
|
||||
>
|
||||
{ __( 'Skip', 'woocommerce' ) }
|
||||
</Button>
|
||||
</Fragment>
|
||||
),
|
||||
visible: this.stepVisibility.logo,
|
||||
},
|
||||
{
|
||||
key: 'notice',
|
||||
label: __( 'Set a store notice', 'woocommerce' ),
|
||||
description: __(
|
||||
'Optionally display a prominent notice across all pages of your store',
|
||||
'woocommerce'
|
||||
),
|
||||
content: (
|
||||
<Fragment>
|
||||
<TextControl
|
||||
label={ __( 'Store notice text', 'woocommerce' ) }
|
||||
placeholder={ __(
|
||||
'Store notice text',
|
||||
'woocommerce'
|
||||
) }
|
||||
value={ storeNoticeText }
|
||||
onChange={ ( value ) =>
|
||||
this.setState( { storeNoticeText: value } )
|
||||
}
|
||||
/>
|
||||
<Button onClick={ this.updateNotice } isPrimary>
|
||||
{ __( 'Complete task', 'woocommerce' ) }
|
||||
</Button>
|
||||
</Fragment>
|
||||
),
|
||||
visible: true,
|
||||
},
|
||||
];
|
||||
|
||||
return filter( steps, ( step ) => step.visible );
|
||||
}
|
||||
|
||||
render() {
|
||||
const { isPending, stepIndex, isUpdatingLogo, isUpdatingNotice } =
|
||||
this.state;
|
||||
const currentStep = this.getSteps()[ stepIndex ].key;
|
||||
|
||||
return (
|
||||
<div className="woocommerce-task-appearance">
|
||||
<Card className="woocommerce-task-card">
|
||||
<CardBody>
|
||||
<Stepper
|
||||
isPending={
|
||||
isUpdatingNotice || isUpdatingLogo || isPending
|
||||
}
|
||||
isVertical
|
||||
currentStep={ currentStep }
|
||||
steps={ this.getSteps() }
|
||||
/>
|
||||
</CardBody>
|
||||
</Card>
|
||||
</div>
|
||||
const useAppearanceClick = () => {
|
||||
const onClick = () => {
|
||||
window.location = getAdminLink(
|
||||
'theme-install.php?browse=block-themes'
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
const AppearanceWrapper = compose(
|
||||
withSelect( ( select ) => {
|
||||
const { getOption } = select( OPTIONS_STORE_NAME );
|
||||
return { onClick };
|
||||
};
|
||||
|
||||
return {
|
||||
demoStoreNotice: getOption( 'woocommerce_demo_store_notice' ),
|
||||
};
|
||||
} ),
|
||||
withDispatch( ( dispatch ) => {
|
||||
const { createNotice } = dispatch( 'core/notices' );
|
||||
const { updateOptions } = dispatch( OPTIONS_STORE_NAME );
|
||||
const { actionTask } = dispatch( ONBOARDING_STORE_NAME );
|
||||
|
||||
return {
|
||||
actionTask,
|
||||
createNotice,
|
||||
updateOptions,
|
||||
};
|
||||
} )
|
||||
)( Appearance );
|
||||
const AppearanceFill = () => {
|
||||
const { onClick } = useAppearanceClick();
|
||||
return (
|
||||
<WooOnboardingTaskListItem id="appearance">
|
||||
{ ( { defaultTaskItem: DefaultTaskItem } ) => (
|
||||
<DefaultTaskItem
|
||||
// Override task click so it doesn't navigate to a task component.
|
||||
onClick={ onClick }
|
||||
/>
|
||||
) }
|
||||
</WooOnboardingTaskListItem>
|
||||
);
|
||||
};
|
||||
|
||||
registerPlugin( 'wc-admin-onboarding-task-appearance', {
|
||||
scope: 'woocommerce-tasks',
|
||||
render: () => (
|
||||
<WooOnboardingTask id="appearance">
|
||||
{ ( { onComplete, task } ) => (
|
||||
<AppearanceWrapper onComplete={ onComplete } task={ task } />
|
||||
) }
|
||||
</WooOnboardingTask>
|
||||
),
|
||||
render: () => <AppearanceFill />,
|
||||
} );
|
||||
|
|
|
@ -0,0 +1,4 @@
|
|||
Significance: minor
|
||||
Type: update
|
||||
|
||||
Replace Personalize Your Store task with Choose Your Theme
|
|
@ -112,12 +112,12 @@ class TaskLists {
|
|||
'CustomizeStore',
|
||||
'StoreDetails',
|
||||
'Products',
|
||||
'Appearance',
|
||||
'WooCommercePayments',
|
||||
'Payments',
|
||||
'Tax',
|
||||
'Shipping',
|
||||
'Marketing',
|
||||
'Appearance',
|
||||
);
|
||||
|
||||
if ( Features::is_enabled( 'core-profiler' ) ) {
|
||||
|
|
|
@ -14,14 +14,12 @@ use Automattic\WooCommerce\Internal\Admin\WCAdminAssets;
|
|||
class Appearance extends Task {
|
||||
|
||||
/**
|
||||
* Constructor
|
||||
*
|
||||
* @param TaskList $task_list Parent task list.
|
||||
* Constructor.
|
||||
*/
|
||||
public function __construct( $task_list ) {
|
||||
parent::__construct( $task_list );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'add_media_scripts' ) );
|
||||
add_action( 'admin_enqueue_scripts', array( $this, 'possibly_add_return_notice_script' ) );
|
||||
public function __construct() {
|
||||
if ( ! $this->is_complete() ) {
|
||||
add_action( 'load-theme-install.php', array( $this, 'mark_actioned' ) );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -39,13 +37,7 @@ class Appearance extends Task {
|
|||
* @return string
|
||||
*/
|
||||
public function get_title() {
|
||||
if ( $this->get_parent_option( 'use_completed_title' ) === true ) {
|
||||
if ( $this->is_complete() ) {
|
||||
return __( 'You personalized your store', 'woocommerce' );
|
||||
}
|
||||
return __( 'Personalize your store', 'woocommerce' );
|
||||
}
|
||||
return __( 'Personalize my store', 'woocommerce' );
|
||||
return __( 'Choose your theme', 'woocommerce' );
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -55,7 +47,7 @@ class Appearance extends Task {
|
|||
*/
|
||||
public function get_content() {
|
||||
return __(
|
||||
'Add your logo, create a homepage, and start designing your store.',
|
||||
"Choose a theme that best fits your brand's look and feel, then make it your own. Change the colors, add your logo, and create pages.",
|
||||
'woocommerce'
|
||||
);
|
||||
}
|
||||
|
@ -70,68 +62,11 @@ class Appearance extends Task {
|
|||
}
|
||||
|
||||
/**
|
||||
* Addtional data.
|
||||
* Action label.
|
||||
*
|
||||
* @return array
|
||||
* @return string
|
||||
*/
|
||||
public function get_additional_data() {
|
||||
return array(
|
||||
'has_homepage' => self::has_homepage(),
|
||||
'has_products' => Products::has_products(),
|
||||
'stylesheet' => get_option( 'stylesheet' ),
|
||||
'theme_mods' => get_theme_mods(),
|
||||
'support_custom_logo' => false !== get_theme_support( 'custom-logo' ),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add media scripts for image uploader.
|
||||
*/
|
||||
public function add_media_scripts() {
|
||||
if ( ! PageController::is_admin_page() || ! $this->can_view() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
wp_enqueue_media();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Adds a return to task list notice when completing the task.
|
||||
*
|
||||
* @param string $hook Page hook.
|
||||
*/
|
||||
public function possibly_add_return_notice_script( $hook ) {
|
||||
global $post;
|
||||
|
||||
if ( $hook !== 'post.php' || $post->post_type !== 'page' ) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ( $this->is_complete() || ! $this->is_active() ) {
|
||||
return;
|
||||
}
|
||||
|
||||
WCAdminAssets::register_script( 'wp-admin-scripts', 'onboarding-homepage-notice', true );
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the site has a homepage set up.
|
||||
*/
|
||||
public static function has_homepage() {
|
||||
if ( get_option( 'classic-editor-replace' ) === 'classic' ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
$homepage_id = get_option( 'woocommerce_onboarding_homepage_post_id', false );
|
||||
|
||||
if ( ! $homepage_id ) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$post = get_post( $homepage_id );
|
||||
$completed = $post && $post->post_status === 'publish';
|
||||
|
||||
return $completed;
|
||||
public function get_action_label() {
|
||||
return __( 'Choose theme', 'woocommerce' );
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue