Merge branch 'trunk' into e2e/remove-obw-tests

This commit is contained in:
Jon Lane 2023-09-21 09:54:29 -07:00
commit 20c5be1235
168 changed files with 1801 additions and 643 deletions

View File

@ -1,5 +1,12 @@
== Changelog ==
= 8.1.1 2023-09-18 =
**WooCommerce**
* Fix - Do not send user meta data back in `woocommerce_get_customer_details` response. [#40221](https://github.com/woocommerce/woocommerce/pull/40221)
* Fix - Fix possible metadata duplication when HPOS is enabled. [#40148](https://github.com/woocommerce/woocommerce/pull/40148)
= 8.1.0 2023-09-12 =
**WooCommerce**

View File

@ -12,7 +12,7 @@ import { parse } from '@wordpress/blocks';
import { usePatterns, Pattern, PatternWithBlocks } from './use-patterns';
// TODO: It might be better to create an API endpoint to get the templates.
const LARGE_BUSINESS_TEMPLATES = {
export const LARGE_BUSINESS_TEMPLATES = {
template1: [
'a8c/cover-image-with-left-aligned-call-to-action',
'woocommerce-blocks/featured-products-5-item-grid',
@ -42,7 +42,7 @@ const LARGE_BUSINESS_TEMPLATES = {
],
};
const SMALL_MEDIUM_BUSINESS_TEMPLATES = {
export const SMALL_MEDIUM_BUSINESS_TEMPLATES = {
template1: [
'woocommerce-blocks/featured-products-fresh-and-tasty',
'woocommerce-blocks/testimonials-single',
@ -68,7 +68,16 @@ const SMALL_MEDIUM_BUSINESS_TEMPLATES = {
],
};
const getTemplatePatterns = (
const TEMPLATES = {
template1: LARGE_BUSINESS_TEMPLATES.template1,
template2: LARGE_BUSINESS_TEMPLATES.template2,
template3: LARGE_BUSINESS_TEMPLATES.template3,
template4: SMALL_MEDIUM_BUSINESS_TEMPLATES.template1,
template5: SMALL_MEDIUM_BUSINESS_TEMPLATES.template2,
template6: SMALL_MEDIUM_BUSINESS_TEMPLATES.template3,
};
export const getTemplatePatterns = (
template: string[],
patternsByName: Record< string, Pattern >
) =>
@ -88,27 +97,26 @@ const getTemplatePatterns = (
} )
.filter( ( pattern ) => pattern !== null ) as PatternWithBlocks[];
export const patternsToNameMap = ( blockPatterns: Pattern[] ) =>
blockPatterns.reduce(
( acc: Record< string, Pattern >, pattern: Pattern ) => {
acc[ pattern.name ] = pattern;
return acc;
},
{}
);
export const useHomeTemplates = () => {
// TODO: Get businessType from option
const businessType = 'SMB' as string;
const { blockPatterns, isLoading } = usePatterns();
const patternsByName = useMemo( () => {
return blockPatterns.reduce(
( acc: Record< string, Pattern >, pattern: Pattern ) => {
acc[ pattern.name ] = pattern;
return acc;
},
{}
);
}, [ blockPatterns ] );
const patternsByName = useMemo(
() => patternsToNameMap( blockPatterns ),
[ blockPatterns ]
);
const homeTemplates = useMemo( () => {
if ( isLoading ) return {};
const recommendedTemplates =
businessType === 'SMB'
? SMALL_MEDIUM_BUSINESS_TEMPLATES
: LARGE_BUSINESS_TEMPLATES;
const recommendedTemplates = TEMPLATES;
return Object.entries( recommendedTemplates ).reduce(
(

View File

@ -21,7 +21,8 @@ export const ColorPalette = () => {
gap={ 4 }
className="woocommerce-customize-store_color-palette-container"
>
{ COLOR_PALETTES.map( ( variation, index ) => (
{ /* TODO: Show 9 colors based on the AI recommendation */ }
{ COLOR_PALETTES.slice( 0, 9 ).map( ( variation, index ) => (
<VariationContainer key={ index } variation={ variation }>
<ColorPaletteVariationPreview title={ variation?.title } />
</VariationContainer>

View File

@ -14,6 +14,8 @@ import {
designWithAiStateMachineEvents,
FontPairing,
LookAndToneCompletionResponse,
Header,
Footer,
} from './types';
import { aiWizardClosedBeforeCompletionEvent } from './events';
import {
@ -110,6 +112,42 @@ const assignFontPairing = assign<
},
} );
const assignHeader = assign<
designWithAiStateMachineContext,
designWithAiStateMachineEvents
>( {
aiSuggestions: ( context, event: unknown ) => {
return {
...context.aiSuggestions,
header: (
event as {
data: {
response: Header;
};
}
).data.response.slug,
};
},
} );
const assignFooter = assign<
designWithAiStateMachineContext,
designWithAiStateMachineEvents
>( {
aiSuggestions: ( context, event: unknown ) => {
return {
...context.aiSuggestions,
footer: (
event as {
data: {
response: Footer;
};
}
).data.response.slug,
};
},
} );
const logAIAPIRequestError = () => {
// log AI API request error
// eslint-disable-next-line no-console
@ -178,6 +216,8 @@ export const actions = {
assignLookAndTone,
assignDefaultColorPalette,
assignFontPairing,
assignHeader,
assignFooter,
logAIAPIRequestError,
updateQueryStep,
recordTracksStepViewed,

View File

@ -0,0 +1,47 @@
/**
* External dependencies
*/
import { z } from 'zod';
const footerChoices = [
{
slug: 'woocommerce-blocks/footer-simple-menu-and-cart',
label: 'Footer with Simple Menu and Cart',
},
{
slug: 'woocommerce-blocks/footer-with-3-menus',
label: 'Footer with 3 Menus',
},
{
slug: 'woocommerce-blocks/footer-large',
label: 'Large Footer',
},
];
const allowedFooter: string[] = footerChoices.map( ( footer ) => footer.slug );
export const footerValidator = z.object( {
slug: z.string().refine( ( slug ) => allowedFooter.includes( slug ), {
message: 'Footer not part of allowed list',
} ),
} );
export const defaultFooter = {
queryId: 'default_footer',
// make sure version is updated every time the prompt is changed
version: '2023-09-19',
prompt: ( businessDescription: string, look: string, tone: string ) => {
return `
You are a WordPress theme expert. Analyse the following store description, merchant's chosen look and tone, and determine the most appropriate footer.
Respond only with one footer and only its JSON.
Chosen look and tone: ${ look } look, ${ tone } tone.
Business description: ${ businessDescription }
Footer to choose from:
${ JSON.stringify( footerChoices ) }
`;
},
responseValidation: footerValidator.parse,
};

View File

@ -0,0 +1,51 @@
/**
* External dependencies
*/
import { z } from 'zod';
const headerChoices = [
{
slug: 'woocommerce-blocks/header-essential',
label: 'Essential Header',
},
{
slug: 'woocommerce-blocks/header-centered-menu-with-search',
label: 'Centered Menu with search Header',
},
{
slug: 'woocommerce-blocks/header-minimal',
label: 'Minimal Header',
},
{
slug: 'woocommerce-blocks/header-large',
label: 'Large Header',
},
];
const allowedHeaders: string[] = headerChoices.map( ( header ) => header.slug );
export const headerValidator = z.object( {
slug: z.string().refine( ( slug ) => allowedHeaders.includes( slug ), {
message: 'Header not part of allowed list',
} ),
} );
export const defaultHeader = {
queryId: 'default_header',
// make sure version is updated every time the prompt is changed
version: '2023-09-19',
prompt: ( businessDescription: string, look: string, tone: string ) => {
return `
You are a WordPress theme expert. Analyse the following store description, merchant's chosen look and tone, and determine the most appropriate header.
Respond only with one header and only its JSON.
Chosen look and tone: ${ look } look, ${ tone } tone.
Business description: ${ businessDescription }
Headers to choose from:
${ JSON.stringify( headerChoices ) }
`;
},
responseValidation: headerValidator.parse,
};

View File

@ -1,3 +1,5 @@
export * from './colorChoices';
export * from './lookAndTone';
export * from './fontPairings';
export * from './header';
export * from './footer';

View File

@ -0,0 +1,47 @@
/**
* Internal dependencies
*/
import { footerValidator } from '..';
describe( 'footerValidator', () => {
it( 'should validate when footer is part of the allowed list', () => {
const validFooter = { slug: 'woocommerce-blocks/footer-large' };
expect( () => footerValidator.parse( validFooter ) ).not.toThrow();
} );
it( 'should not validate when footer is not part of the allowed list', () => {
const invalidFooter = {
slug: 'woocommerce-blocks/footer-large-invalid',
};
expect( () => footerValidator.parse( invalidFooter ) )
.toThrowErrorMatchingInlineSnapshot( `
"[
{
\\"code\\": \\"custom\\",
\\"message\\": \\"Footer not part of allowed list\\",
\\"path\\": [
\\"slug\\"
]
}
]"
` );
} );
it( 'should not validate when slug is not a string', () => {
const invalidType = { slug: 123 };
expect( () => footerValidator.parse( invalidType ) )
.toThrowErrorMatchingInlineSnapshot( `
"[
{
\\"code\\": \\"invalid_type\\",
\\"expected\\": \\"string\\",
\\"received\\": \\"number\\",
\\"path\\": [
\\"slug\\"
],
\\"message\\": \\"Expected string, received number\\"
}
]"
` );
} );
} );

View File

@ -0,0 +1,47 @@
/**
* Internal dependencies
*/
import { headerValidator } from '..';
describe( 'headerValidator', () => {
it( 'should validate when header is part of the allowed list', () => {
const validHeader = { slug: 'woocommerce-blocks/header-large' };
expect( () => headerValidator.parse( validHeader ) ).not.toThrow();
} );
it( 'should not validate when header is not part of the allowed list', () => {
const invalidHeader = {
slug: 'woocommerce-blocks/header-large-invalid',
};
expect( () => headerValidator.parse( invalidHeader ) )
.toThrowErrorMatchingInlineSnapshot( `
"[
{
\\"code\\": \\"custom\\",
\\"message\\": \\"Header not part of allowed list\\",
\\"path\\": [
\\"slug\\"
]
}
]"
` );
} );
it( 'should not validate when slug is not a string', () => {
const invalidType = { slug: 123 };
expect( () => headerValidator.parse( invalidType ) )
.toThrowErrorMatchingInlineSnapshot( `
"[
{
\\"code\\": \\"invalid_type\\",
\\"expected\\": \\"string\\",
\\"received\\": \\"number\\",
\\"path\\": [
\\"slug\\"
],
\\"message\\": \\"Expected string, received number\\"
}
]"
` );
} );
} );

View File

@ -1,16 +1,32 @@
/* eslint-disable @woocommerce/dependency-group */
/* eslint-disable @typescript-eslint/ban-ts-comment */
/**
* External dependencies
*/
import { __experimentalRequestJetpackToken as requestJetpackToken } from '@woocommerce/ai';
import apiFetch from '@wordpress/api-fetch';
import { recordEvent } from '@woocommerce/tracks';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { Sender, assign, createMachine } from 'xstate';
import { dispatch, resolveSelect } from '@wordpress/data';
// @ts-ignore No types for this exist yet.
import { store as coreStore } from '@wordpress/core-data';
// @ts-ignore No types for this exist yet.
import { mergeBaseAndUserConfigs } from '@wordpress/edit-site/build-module/components/global-styles/global-styles-provider';
/**
* Internal dependencies
*/
import { designWithAiStateMachineContext } from './types';
import { lookAndTone } from './prompts';
import { FONT_PAIRINGS } from '../assembler-hub/sidebar/global-styles/font-pairing-variations/constants';
import { COLOR_PALETTES } from '../assembler-hub/sidebar/global-styles/color-palette-variations/constants';
import {
patternsToNameMap,
getTemplatePatterns,
LARGE_BUSINESS_TEMPLATES,
SMALL_MEDIUM_BUSINESS_TEMPLATES,
} from '../assembler-hub/hooks/use-home-templates';
const browserPopstateHandler =
() => ( sendBack: Sender< { type: 'EXTERNAL_URL_UPDATE' } > ) => {
@ -192,8 +208,185 @@ export const queryAiEndpoint = createMachine(
}
);
export const updateStorePatterns = async (
context: designWithAiStateMachineContext
) => {
try {
// TODO: Probably move this to a more appropriate place with a check. We should set this when the user granted permissions during the onboarding phase.
await dispatch( OPTIONS_STORE_NAME ).updateOptions( {
woocommerce_blocks_allow_ai_connection: true,
} );
await apiFetch( {
path: '/wc/store/patterns',
method: 'POST',
data: {
business_description:
context.businessInfoDescription.descriptionText,
},
} );
} catch ( error ) {
recordEvent( 'customize_your_store_update_store_pattern_api_error', {
error: error instanceof Error ? error.message : 'unknown',
} );
throw error;
}
};
// Update the current global styles of theme
const updateGlobalStyles = async ( {
colorPaletteName = COLOR_PALETTES[ 0 ].title,
fontPairingName = FONT_PAIRINGS[ 0 ].title,
}: {
colorPaletteName: string;
fontPairingName: string;
} ) => {
const colorPalette = COLOR_PALETTES.find(
( palette ) => palette.title === colorPaletteName
);
const fontPairing = FONT_PAIRINGS.find(
( pairing ) => pairing.title === fontPairingName
);
const globalStylesId = await resolveSelect(
coreStore
// @ts-ignore No types for this exist yet.
).__experimentalGetCurrentGlobalStylesId();
// @ts-ignore No types for this exist yet.
const { saveEntityRecord } = dispatch( coreStore );
await saveEntityRecord(
'root',
'globalStyles',
{
id: globalStylesId,
styles: mergeBaseAndUserConfigs(
colorPalette?.styles || {},
fontPairing?.styles || {}
),
settings: mergeBaseAndUserConfigs(
colorPalette?.settings || {},
fontPairing?.settings || {}
),
},
{
throwOnError: true,
}
);
};
// Update the current theme template
const updateTemplate = async ( {
headerSlug,
businessSize,
homepageTemplateId,
footerSlug,
}: {
headerSlug: string;
businessSize: 'SMB' | 'LB';
homepageTemplateId:
| keyof typeof SMALL_MEDIUM_BUSINESS_TEMPLATES
| keyof typeof LARGE_BUSINESS_TEMPLATES;
footerSlug: string;
} ) => {
const patterns = ( await resolveSelect(
coreStore
// @ts-ignore No types for this exist yet.
).getBlockPatterns() ) as Pattern[];
const patternsByName = patternsToNameMap( patterns );
const headerPattern = patternsByName[ headerSlug ];
const footerPattern = patternsByName[ footerSlug ];
const homepageTemplate = getTemplatePatterns(
businessSize === 'SMB'
? SMALL_MEDIUM_BUSINESS_TEMPLATES[ homepageTemplateId ]
: LARGE_BUSINESS_TEMPLATES[ homepageTemplateId ],
patternsByName
);
const content = [ headerPattern, ...homepageTemplate, footerPattern ]
.filter( Boolean )
.map( ( pattern ) => pattern.content )
.join( '\n\n' );
const currentTemplate = await resolveSelect(
coreStore
// @ts-ignore No types for this exist yet.
).__experimentalGetTemplateForLink( '/' );
// @ts-ignore No types for this exist yet.
const { saveEntityRecord } = dispatch( coreStore );
await saveEntityRecord(
'postType',
currentTemplate.type,
{
id: currentTemplate.id,
content,
},
{
throwOnError: true,
}
);
};
export const assembleSite = async (
context: designWithAiStateMachineContext
) => {
try {
await updateGlobalStyles( {
colorPaletteName: context.aiSuggestions.defaultColorPalette.default,
fontPairingName: context.aiSuggestions.fontPairing,
} );
recordEvent( 'customize_your_store_ai_update_global_styles_success' );
} catch ( error ) {
// TODO handle error
// eslint-disable-next-line no-console
console.error( error );
recordEvent(
'customize_your_store_ai_update_global_styles_response_error',
{
error: error instanceof Error ? error.message : 'unknown',
}
);
}
try {
await updateTemplate( {
headerSlug: context.aiSuggestions.header,
// TODO: Get from context
businessSize: 'SMB',
homepageTemplateId: 'template1',
footerSlug: context.aiSuggestions.footer,
} );
recordEvent( 'customize_your_store_ai_update_template_success' );
} catch ( error ) {
// TODO handle error
// eslint-disable-next-line no-console
console.error( error );
recordEvent( 'customize_your_store_ai_update_template_response_error', {
error: error instanceof Error ? error.message : 'unknown',
} );
}
// @ts-ignore No types for this exist yet.
const { invalidateResolutionForStoreSelector } = dispatch( coreStore );
// Invalid the selectors so that the new template/style are used in assembler hub.
invalidateResolutionForStoreSelector( 'getEntityRecord' );
invalidateResolutionForStoreSelector(
'__experimentalGetCurrentGlobalStylesId'
);
invalidateResolutionForStoreSelector( '__experimentalGetTemplateForLink' );
};
export const services = {
getLookAndTone,
browserPopstateHandler,
queryAiEndpoint,
assembleSite,
updateStorePatterns,
};

View File

@ -11,6 +11,8 @@ import {
designWithAiStateMachineContext,
designWithAiStateMachineEvents,
FontPairing,
Header,
Footer,
ColorPaletteResponse,
} from './types';
import {
@ -21,7 +23,12 @@ import {
} from './pages';
import { actions } from './actions';
import { services } from './services';
import { defaultColorPalette, fontPairings } from './prompts';
import {
defaultColorPalette,
fontPairings,
defaultHeader,
defaultFooter,
} from './prompts';
export const hasStepInUrl = (
_ctx: unknown,
@ -72,6 +79,8 @@ export const designWithAiStateMachineDefinition = createMachine(
aiSuggestions: {
defaultColorPalette: {} as ColorPaletteResponse,
fontPairing: '' as FontPairing[ 'pair_name' ],
header: '' as Header[ 'slug' ],
footer: '' as Footer[ 'slug' ],
},
},
initial: 'navigate',
@ -273,48 +282,158 @@ export const designWithAiStateMachineDefinition = createMachine(
type: 'parallel',
states: {
chooseColorPairing: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...defaultColorPalette,
prompt: defaultColorPalette.prompt(
context.businessInfoDescription
.descriptionText,
context.lookAndFeel.choice,
context.toneOfVoice.choice
),
};
},
onDone: {
actions: [
'assignDefaultColorPalette',
],
initial: 'pending',
states: {
pending: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...defaultColorPalette,
prompt: defaultColorPalette.prompt(
context
.businessInfoDescription
.descriptionText,
context.lookAndFeel
.choice,
context.toneOfVoice
.choice
),
};
},
onDone: {
actions: [
'assignDefaultColorPalette',
],
target: 'success',
},
},
},
success: { type: 'final' },
},
},
chooseFontPairing: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...fontPairings,
prompt: fontPairings.prompt(
context.businessInfoDescription
.descriptionText,
context.lookAndFeel.choice,
context.toneOfVoice.choice
),
};
initial: 'pending',
states: {
pending: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...fontPairings,
prompt: fontPairings.prompt(
context
.businessInfoDescription
.descriptionText,
context.lookAndFeel
.choice,
context.toneOfVoice
.choice
),
};
},
onDone: {
actions: [
'assignFontPairing',
],
target: 'success',
},
},
},
onDone: {
actions: [ 'assignFontPairing' ],
success: { type: 'final' },
},
},
chooseHeader: {
initial: 'pending',
states: {
pending: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...defaultHeader,
prompt: defaultHeader.prompt(
context
.businessInfoDescription
.descriptionText,
context.lookAndFeel
.choice,
context.toneOfVoice
.choice
),
};
},
onDone: {
actions: [ 'assignHeader' ],
target: 'success',
},
},
},
success: { type: 'final' },
},
},
chooseFooter: {
initial: 'pending',
states: {
pending: {
invoke: {
src: 'queryAiEndpoint',
data: ( context ) => {
return {
...defaultFooter,
prompt: defaultFooter.prompt(
context
.businessInfoDescription
.descriptionText,
context.lookAndFeel
.choice,
context.toneOfVoice
.choice
),
};
},
onDone: {
actions: [ 'assignFooter' ],
target: 'success',
},
},
},
success: { type: 'final' },
},
},
updateStorePatterns: {
initial: 'pending',
states: {
pending: {
invoke: {
src: 'updateStorePatterns',
onDone: {
target: 'success',
},
onError: {
// TODO: handle error
target: 'success',
},
},
},
success: { type: 'final' },
},
},
},
onDone: 'postApiCallLoader',
},
postApiCallLoader: {
invoke: {
src: 'assembleSite',
onDone: {
actions: [
sendParent( () => ( {
type: 'THEME_SUGGESTED',
} ) ),
],
},
},
},
postApiCallLoader: {},
},
},
},

View File

@ -19,6 +19,13 @@ jest.mock( '@woocommerce/ai', () => ( {
jest.mock( '@wordpress/api-fetch', () => jest.fn() );
jest.mock(
'@wordpress/edit-site/build-module/components/global-styles/global-styles-provider',
() => ( {
mergeBaseAndUserConfigs: jest.fn(),
} )
);
describe( 'getCompletion', () => {
beforeEach( () => {
jest.clearAllMocks();

View File

@ -7,8 +7,10 @@ import { z } from 'zod';
*/
import {
colorPaletteValidator,
colorPaletteResponseValidator,
fontChoiceValidator,
headerValidator,
footerValidator,
colorPaletteResponseValidator,
} from './prompts';
export type designWithAiStateMachineContext = {
@ -24,6 +26,8 @@ export type designWithAiStateMachineContext = {
aiSuggestions: {
defaultColorPalette: ColorPaletteResponse;
fontPairing: FontPairing[ 'pair_name' ];
header: Header[ 'slug' ];
footer: Footer[ 'slug' ];
};
// If we require more data from options, previously provided core profiler details,
// we can retrieve them in preBusinessInfoDescription and then assign them here
@ -60,3 +64,7 @@ export type ColorPaletteResponse = z.infer<
>;
export type FontPairing = z.infer< typeof fontChoiceValidator >;
export type Header = z.infer< typeof headerValidator >;
export type Footer = z.infer< typeof footerValidator >;

View File

@ -4,7 +4,11 @@
import { Sender, createMachine } from 'xstate';
import { useEffect, useMemo, useState } from '@wordpress/element';
import { useMachine, useSelector } from '@xstate/react';
import { getQuery, updateQueryString } from '@woocommerce/navigation';
import {
getNewPath,
getQuery,
updateQueryString,
} from '@woocommerce/navigation';
import { OPTIONS_STORE_NAME } from '@woocommerce/data';
import { dispatch } from '@wordpress/data';
@ -59,6 +63,10 @@ const updateQueryStep = (
}
};
const redirectToWooHome = () => {
window.location.href = getNewPath( {}, '/', {} );
};
const markTaskComplete = async () => {
return dispatch( OPTIONS_STORE_NAME ).updateOptions( {
woocommerce_admin_customize_store_completed: 'yes',
@ -78,6 +86,7 @@ const browserPopstateHandler =
export const machineActions = {
updateQueryStep,
redirectToWooHome,
};
export const customizeStoreStateMachineActions = {
@ -184,7 +193,7 @@ export const customizeStoreStateMachineDefinition = createMachine( {
target: 'assemblerHub',
},
CLICKED_ON_BREADCRUMB: {
target: 'backToHomescreen',
actions: 'redirectToWooHome',
},
SELECTED_NEW_THEME: {
target: 'appearanceTask',
@ -263,11 +272,10 @@ export const customizeStoreStateMachineDefinition = createMachine( {
},
on: {
GO_BACK_TO_HOME: {
target: 'backToHomescreen',
actions: 'redirectToWooHome',
},
},
},
backToHomescreen: {},
appearanceTask: {},
},
} );

View File

@ -1,4 +0,0 @@
Significance: minor
Type: fix
Avoid a fatal error on the order received page if the order ID is not for a valid order.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add tags (or general taxonomy ) block

View File

@ -1,4 +0,0 @@
Significance: major
Type: update
Update the simple product template implementation to use the product form template API.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add support for slug auto generation to the create attribute endpoint

View File

@ -1,4 +0,0 @@
Significance: minor
Type: update
Update intro screen for the new Customize Your Store task

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add AI wizard business info step for Customize Your Store task

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add sidebar to customize your store task.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add component to Customize Your Store task.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: fix
Add Variation options section back to the product blocks template

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Create a plugin to enable Variations feature #40027

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add has_price param to the variations REST API query.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add variable product experiment

View File

@ -1,4 +0,0 @@
Significance: minor
Type: update
Update Remote Inbox Notifications to add in and !in comparison operators for comparing values against arrays

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add Tracks events to Appearance > Themes screen

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Persist CYS AI assembled site

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add after_add_block and after_remove block hooks to the block template API.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add woocommerce_block_template_register action.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Call wc store patterns API to update patterns for CYS

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store assembler hub

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Implement customize store assembler hub - logo feature

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store assembler hub onboarding tour

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store AI wizard call for best colour palette suggestions.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store AI wizard call for color palette suggestion

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Implemented loader design for Customize your store - Design with AI

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store AI wizard call for font pairing suggestion

View File

@ -1,4 +1,4 @@
Significance: minor
Type: add
Add customize store - fonts
Add cys ai header/footer

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add track events to customize store AI wizard

View File

@ -1,4 +0,0 @@
Significance: minor
Type: update
Added xstate scaffolding for AI Wizard in customize your store feature

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add tracks to CYS assembler-hub and hide pages sidebar screen

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store color palettes

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add customize store transitional screen

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add track events to customize store transitional page

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Added URL navigation support to customize-store feature

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add a filter to OrdersTableQuery to allow overriding of HPOS queries.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add filter woocommerce_hpos_enable_sync_on_read to disable sync on read with HPOS sync enabled.

View File

@ -1,4 +0,0 @@
Significance: major
Type: enhancement
Enable HPOS by default for new installs.

View File

@ -1,5 +0,0 @@
Significance: patch
Type: dev
Comment: Update CONTRIBUTING.md file to include instructions on how adding unit, API and E2E tests when applicable.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Made ai completion for look and tone more robust and added tracks

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add new e2e test to cover My Account Addresses section

View File

@ -1,4 +0,0 @@
Significance: patch
Type: add
Add new e2e test for Shopper My Account Downloads section

View File

@ -1,5 +0,0 @@
Significance: patch
Type: dev
Comment: Adds regression test for https://github.com/woocommerce/woocommerce/pull/40221.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: tweak
Add order property to every block in SimpleProductTemplate

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add ability to remove blocks from templates.

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Adds new action hook `woocommerce_pay_order_before_payment` to the `checkout/form-pay.php` template.

View File

@ -1,5 +0,0 @@
Significance: patch
Type: add
Comment: Updated perf test and workflow for extra site

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Fix for a couple of flaky API tests on daily runs

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Run a full reset on API daily test site

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Fixes and enables API test suite to run on daily CI run against alternate host

View File

@ -1,5 +0,0 @@
Significance: patch
Type: dev
Comment: Bump PHP version where it was missed in #39820.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Bump required PHP version to 7.4

View File

@ -1,4 +0,0 @@
Significance: minor
Type: dev
Add notice to "track inventory" toggle #40011

View File

@ -1,4 +0,0 @@
Significance: minor
Type: dev
Add some basic E2E tests for Assembler Hub

View File

@ -1,4 +0,0 @@
Significance: minor
Type: add
Add header customization to the Assembler Hub

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Added documentation for the Core Profiler

View File

@ -1,4 +0,0 @@
Significance: minor
Type: dev
Refactored core profiler loader to be more generalizable and moved to @woocommerce/onboarding

View File

@ -1,4 +0,0 @@
Significance: minor
Type: dev
Cleanup: remove the unused is_feature_visible and show_feature methods.

View File

@ -1,5 +0,0 @@
Significance: patch
Type: tweak
Comment: This change only tweaks a few comments.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Add new E2E test covering shopper product page and make Product-related tests granular (separated test files)

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Add job to post Slack summary of plugin test results in "Smoke test daily" workflow.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Fix flakiness around the `Turn off the new product form` menu item.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Remove "WP Latest-2" from release tests.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Adds test to check required fields on checkout

View File

@ -1,4 +0,0 @@
Significance: patch
Type: dev
Updates Playwright from 1.33 to 1.37.1

View File

@ -1,4 +0,0 @@
Significance: major
Type: update
We have completely redesigned the In-app Marketplace.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Eliminate an unnecessary redirect when the geo hash isalready set to the correct value.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Display search results subtitle in HPOS list table view.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
[HPOS] Modify query to have less characters before the `FROM` keyword.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix minor layout shift in the core profiler.

View File

@ -1,4 +0,0 @@
Significance: major
Type: fix
Remove use of woocommerce-page class within WooCommerce Admin pages, replaced with woocommerce-admin-page.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Properly convert local time date queries to UTC in the HPOS datastore.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix a bug where updating store location doesn't update store currency.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: update
Update use of preventLeavingProductForm with new function changes.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
FIx WC Admin pages are empty for WP 6.2 and below.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: tweak
Adds an informative tooltip to the Account Details section of the Direct Bank Transfer settings.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix cached refund not deleted when the refund is deleted with HPOS active

View File

@ -1,4 +0,0 @@
Significance: patch
Type: enhancement
Add CLI commands to enable or disable HPOS.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Remove COT enable requirement from sync and verify command.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Avoid string<>int comparison in products bought query to avoid results with customer_id = 0.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix CYS `__experimentalReapplyBlockTypeFilters` is not a function

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix customize your store task header button

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Addressed visual tweaks for CYS in response to feedback from 12th Sept

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
Fix customize store white screen bug in WP 6.3

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
[HPOS] Support deleting metadata just by meta id.

View File

@ -1,5 +0,0 @@
Significance: patch
Type: tweak
Comment: Just a typo fix.

View File

@ -1,4 +0,0 @@
Significance: patch
Type: fix
[HPOS]Fix duplicate meta handling by passing meta_value|unique in post calls

Some files were not shown because too many files have changed in this diff Show More