Merge branch 'trunk' into hpos/end-at-support

This commit is contained in:
Vedanshu Jain 2023-03-29 13:24:02 +05:30
commit 792bf6fc85
78 changed files with 644 additions and 148 deletions

View File

@ -20,7 +20,7 @@ jobs:
uses: actions/checkout@v3
- name: Install prerequisites
run: |
npm install -g pnpm
npm install -g pnpm@7
npm -g i @wordpress/env@5.1.0
pnpm install --filter code-analyzer --filter cli-core
- name: Run analyzer

View File

@ -0,0 +1,3 @@
// Import the default config file and expose it in the project root.
// Useful for editor integrations.
module.exports = require( '@wordpress/prettier-config' );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Move ProductMVPFeedbackModal to @woocommerce/product-editor

View File

@ -4,5 +4,4 @@ export * from './customer-effort-score-tracks';
export * from './customer-effort-score-tracks-container';
export * from './customer-feedback-simple';
export * from './customer-feedback-modal';
export * from './product-mvp-feedback-modal';
export * from './feedback-modal';

View File

@ -1,5 +1,4 @@
@import 'components/customer-feedback-simple/customer-feedback-simple.scss';
@import 'components/product-mvp-feedback-modal/product-mvp-feedback-modal.scss';
@import 'components/feedback-modal/feedback-modal.scss';
.woocommerce-customer-effort-score__selection {

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add variable_product_tour_shown to UserPreferences type.

View File

@ -25,6 +25,7 @@ export type UserPreferences = {
[ key: string ]: number;
};
taxes_report_columns?: string;
variable_product_tour_shown?: string;
variations_report_columns?: string;
};

View File

@ -53,7 +53,7 @@
},
"scripts": {
"turbo:build": "./bin/build.sh && pnpm run clean && pnpm run compile",
"prepare": "pnpm run build",
"prepack": "pnpm run build",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"clean": "rm -rf ./build ./build-module",
"compile": "e2e-builds",

View File

@ -69,7 +69,7 @@
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"clean": "rm -rf ./build ./build-module",
"compile": "e2e-builds",
"prepare": "pnpm run build",
"prepack": "pnpm run build",
"docker:up": "./bin/docker-compose.sh up",
"docker:wait": "bash ./bin/wait-for-build.sh",
"docker:down": "./bin/docker-compose.sh down",

View File

@ -51,7 +51,7 @@
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"clean": "rm -rf ./build ./build-module",
"compile": "e2e-builds",
"prepare": "pnpm run build",
"prepack": "pnpm run build",
"lint": "eslint src --ext=js,ts,tsx",
"lint:fix": "eslint src --ext=js,ts,tsx --fix"
},

View File

@ -105,7 +105,7 @@ class {{slugPascalCase}}_Blocks_Integration implements IntegrationInterface {
$style_url = plugins_url( $style_path, __FILE__ );
wp_enqueue_style(
'{{slug}}-blocks-integration',
'{{slug}}-checkout-newsletter-subscription-block',
$style_url,
[],
$this->get_file_version( $style_path )

View File

@ -0,0 +1,27 @@
# This file is for unifying the coding style for different editors and IDEs
# editorconfig.org
# WordPress Coding Standards
# https://make.wordpress.org/core/handbook/coding-standards/
root = true
[*]
charset = utf-8
end_of_line = lf
indent_size = 4
tab_width = 4
indent_style = tab
insert_final_newline = true
trim_trailing_whitespace = true
[*.txt]
trim_trailing_whitespace = false
[*.{md,json,yml}]
trim_trailing_whitespace = false
indent_style = space
indent_size = 2
[*.json]
indent_style = tab

View File

@ -0,0 +1 @@
16.13.2

View File

@ -0,0 +1,14 @@
{
"phpVersion": null,
"core": null,
"plugins": [
"https://downloads.wordpress.org/plugin/woocommerce.latest-stable.zip",
"https://downloads.wordpress.org/plugin/woo-gutenberg-products-block.latest-stable.zip",
"."
],
"config": {
"JETPACK_AUTOLOAD_DEV": true,
"WP_DEBUG": true,
"SCRIPT_DEBUG": true
}
}

View File

@ -3,12 +3,29 @@
This is a template to be used with `@wordpress/create-block` to create a WooCommerce Blocks extension starting point.
## Installation
From your `plugins` directory run:
```
```sh
npx @wordpress/create-block -t @woocommerce/extend-cart-checkout-block your_extension_name
```
When this has completed, go to your WordPress plugins page and activate the plugin.
Add some items to your cart and visit the Checkout block, notice there is additional data on the block that this
template has added.
Add some items to your cart and visit the Checkout block, notice there is additional data on the block that this template has added.
### Installing `wp-prettier` (optional)
WooCommerce Blocks uses `wp-prettier` to format the JS files. If you want to use `wp-prettier`, you will need to run the following command:
```sh
nvm use && npm i --D "prettier@npm:wp-prettier@latest"
```
### Installing `wp-env` (optional)
`wp-env` lets you easily set up a local WordPress environment for building and testing your extension. If you want to use `wp-env`, you will need to run the following command:
```sh
nvm use && npm i -D @wordpress/env && npm set-script wp-env "wp-env"
```

View File

@ -0,0 +1,10 @@
Significance: patch
Type: update
This patch includes the following changes:
- Add `prettier:npm:wp-prettier@2.6.2`
- Add `.wp-env`
- Add `.nvmrc`
- Correct CSS handle of newsletter subscription block
- Correct metadata category of newsletter subscription block

View File

@ -4,6 +4,8 @@ module.exports = {
npmDevDependencies: [
'@woocommerce/dependency-extraction-webpack-plugin',
'@woocommerce/eslint-plugin',
'@wordpress/prettier-config',
'@wordpress/scripts',
],
},
};

View File

@ -3,7 +3,7 @@
"name": "{{slug}}/checkout-newsletter-subscription",
"version": "2.0.0",
"title": "Newsletter Subscription!",
"category": "{{slug}}",
"category": "woocommerce",
"description": "Adds a newsletter subscription checkbox to the checkout.",
"supports": {
"html": false,

View File

@ -61,8 +61,7 @@ module.exports = {
// Add code here to prepend to all .scss/.sass files.
return (
'@import "_colors"; ' +
content
'@import "colors"; ' + content
);
},
},

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Content lock all blocks in the product editor

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Move CES-related components to @woocommerce/product-editor

View File

@ -29,11 +29,14 @@
},
"dependencies": {
"@types/lodash": "^4.14.179",
"@types/prop-types": "^15.7.4",
"@types/wordpress__blocks": "^11.0.7",
"@woocommerce/admin-layout": "workspace:*",
"@woocommerce/components": "workspace:*",
"@woocommerce/currency": "workspace:*",
"@woocommerce/customer-effort-score": "workspace:*",
"@woocommerce/data": "workspace:^4.1.0",
"@woocommerce/experimental": "workspace:*",
"@woocommerce/navigation": "workspace:^8.1.0",
"@woocommerce/number": "workspace:*",
"@woocommerce/settings": "^1.0.0",
@ -56,6 +59,7 @@
"@wordpress/url": "wp-6.0",
"classnames": "^2.3.1",
"lodash": "^4.17.21",
"prop-types": "^15.8.1",
"react-router-dom": "^6.3.0"
},
"devDependencies": {

View File

@ -9,7 +9,8 @@
"textdomain": "default",
"attributes": {
"name": {
"type": "string"
"type": "string",
"__experimentalRole": "content"
}
},
"supports": {

View File

@ -17,6 +17,10 @@
},
"label": {
"type": "string"
},
"content": {
"type": "string",
"__experimentalRole": "content"
}
},
"supports": {

View File

@ -19,3 +19,6 @@ export {
BlockIcon as __experimentalBlockIcon,
BlockIconProps,
} from './block-icon';
export { ProductMVPCESFooter as __experimentalProductMVPCESFooter } from './product-mvp-ces-footer';
export { ProductMVPFeedbackModal as __experimentalProductMVPFeedbackModal } from './product-mvp-feedback-modal';
export { ProductMVPFeedbackModalContainer as __experimentalProductMVPFeedbackModalContainer } from './product-mvp-feedback-modal-container';

View File

@ -9,7 +9,8 @@
"textdomain": "default",
"attributes": {
"name": {
"type": "string"
"type": "string",
"__experimentalRole": "content"
},
"label": {
"type": "string"

View File

@ -0,0 +1 @@
export * from './product-mvp-ces-footer';

View File

@ -4,6 +4,7 @@
import { __ } from '@wordpress/i18n';
import { Button } from '@wordpress/components';
import { useDispatch, useSelect } from '@wordpress/data';
import { createElement, Fragment } from '@wordpress/element';
import { closeSmall } from '@wordpress/icons';
import { WooFooterItem } from '@woocommerce/admin-layout';
import { Pill } from '@woocommerce/components';
@ -17,12 +18,10 @@ import { OPTIONS_STORE_NAME } from '@woocommerce/data';
/**
* Internal dependencies
*/
import './product-mvp-ces-footer.scss';
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
'woocommerce_ces_product_mvp_ces_action';
export const NEW_PRODUCT_MANAGEMENT =
'woocommerce_new_product_management_enabled';
import {
PRODUCT_MVP_CES_ACTION_OPTION_NAME,
NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME,
} from '../../constants';
export const ProductMVPCESFooter: React.FC = () => {
const { showCesModal, showProductMVPFeedbackModal } =
@ -107,7 +106,7 @@ export const ProductMVPCESFooter: React.FC = () => {
[ PRODUCT_MVP_CES_ACTION_OPTION_NAME ]: 'hide',
} );
updateOptions( {
[ NEW_PRODUCT_MANAGEMENT ]: 'no',
[ NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME ]: 'no',
} );
showProductMVPFeedbackModal();
};

View File

@ -0,0 +1 @@
export * from './product-mvp-feedback-modal-container';

View File

@ -2,15 +2,18 @@
* External dependencies
*/
import { useDispatch, useSelect } from '@wordpress/data';
import {
ProductMVPFeedbackModal,
STORE_KEY,
} from '@woocommerce/customer-effort-score';
import { createElement } from '@wordpress/element';
import { STORE_KEY } from '@woocommerce/customer-effort-score';
import { recordEvent } from '@woocommerce/tracks';
import { getAdminLink } from '@woocommerce/settings';
import { useFormContext } from '@woocommerce/components';
import { Product } from '@woocommerce/data';
/**
* Internal dependencies
*/
import { ProductMVPFeedbackModal } from '../product-mvp-feedback-modal';
export const ProductMVPFeedbackModalContainer: React.FC< {
productId?: number;
} > = ( { productId: _productId } ) => {

View File

@ -4,14 +4,10 @@
import { createElement, Fragment, useState } from '@wordpress/element';
import PropTypes from 'prop-types';
import { CheckboxControl, TextareaControl } from '@wordpress/components';
import { FeedbackModal } from '@woocommerce/customer-effort-score';
import { Text } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
*/
import { FeedbackModal } from '../feedback-modal';
/**
* Provides a modal requesting customer feedback.
*

View File

@ -21,7 +21,10 @@
"multiple": true,
"reusable": false,
"inserter": false,
"lock": false
"lock": false,
"__experimentalToolbar": false
},
"usesContext": [ "selectedTab" ]
"usesContext": [ "selectedTab" ],
"editorStyle": "file:./editor.css",
"templateLock": "contentOnly"
}

View File

@ -1,9 +1,9 @@
/**
* External dependencies
*/
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import classnames from 'classnames';
import { createElement } from '@wordpress/element';
import { InnerBlocks, useBlockProps } from '@wordpress/block-editor';
import type { BlockAttributes } from '@wordpress/blocks';
/**
@ -39,7 +39,9 @@ export function Edit( {
role="tabpanel"
className={ classes }
>
<InnerBlocks templateLock="all" />
{ /* eslint-disable-next-line @typescript-eslint/ban-ts-comment */ }
{ /* @ts-ignore Content only template locking does exist for this property. */ }
<InnerBlocks templateLock="contentOnly" />
</div>
</div>
);

View File

@ -2,4 +2,9 @@
&:not(.is-selected) {
display: none;
}
}
// Remove the Gutenberg selected outline.
.wp-block-woocommerce-product-tab:after {
display: none;
}

View File

@ -1,3 +1,8 @@
export const PRODUCT_MVP_CES_ACTION_OPTION_NAME =
'woocommerce_ces_product_mvp_ces_action';
export const NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME =
'woocommerce_new_product_management_enabled';
export const NUMBERS_AND_ALLOWED_CHARS = '[^-0-9%s1%s2]';
export const NUMBERS_AND_DECIMAL_SEPARATOR = '[^-\\d\\%s]+';
export const ONLY_ONE_DECIMAL_SEPARATOR = '[%s](?=%s*[%s])';

View File

@ -1,3 +1,4 @@
export { useProductHelper as __experimentalUseProductHelper } from './use-product-helper';
export { useProductMVPCESFooter as __experimentalUseProductMVPCESFooter } from './use-product-mvp-ces-footer';
export { useVariationsOrder as __experimentalUseVariationsOrder } from './use-variations-order';
export { useCurrencyInputProps as __experimentalUseCurrencyInputProps } from './use-currency-input-props';

View File

@ -0,0 +1 @@
export * from './use-product-mvp-ces-footer';

View File

@ -7,7 +7,7 @@ import { OPTIONS_STORE_NAME } from '@woocommerce/data';
/**
* Internal dependencies
*/
import { PRODUCT_MVP_CES_ACTION_OPTION_NAME } from './product-mvp-ces-footer';
import { PRODUCT_MVP_CES_ACTION_OPTION_NAME } from '../../constants';
async function isProductMVPCESHidden(): Promise< boolean > {
const productCESAction: string = await resolveSelect(

View File

@ -1,5 +1,9 @@
export * from './components';
export { DETAILS_SECTION_ID, TAB_GENERAL_ID } from './constants';
export {
DETAILS_SECTION_ID,
NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME,
TAB_GENERAL_ID,
} from './constants';
/**
* Utils

View File

@ -9,3 +9,5 @@
@import 'components/tab/style.scss';
@import 'components/tabs/style.scss';
@import 'components/details-summary-block/style.scss';
@import 'components/product-mvp-ces-footer/style.scss';
@import 'components/product-mvp-feedback-modal/style.scss';

View File

@ -0,0 +1,121 @@
/**
* External dependencies
*/
import { useEffect, useState } from '@wordpress/element';
import { __ } from '@wordpress/i18n';
import { TourKit, TourKitTypes } from '@woocommerce/components';
import { useUserPreferences } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
function getStepName(
steps: TourKitTypes.WooStep[],
currentStepIndex: number
) {
return steps[ currentStepIndex ]?.meta?.name;
}
export const VariableProductTour = () => {
const [ isTourOpen, setIsTourOpen ] = useState( false );
const { updateUserPreferences, variable_product_tour_shown: hasShownTour } =
useUserPreferences();
const config: TourKitTypes.WooConfig = {
steps: [
{
referenceElements: {
desktop: '.attribute_tab',
},
focusElement: {
desktop: '.attribute_tab',
},
meta: {
name: 'attributes',
heading: __( 'Start by adding attributes', 'woocommerce' ),
descriptions: {
desktop: __(
'Add attributes like size and color for customers to choose from on the product page. We will use them to generate product variations.',
'woocommerce'
),
},
primaryButton: {
text: __( 'Got it', 'woocommerce' ),
},
},
},
],
options: {
// WooTourKit does not handle merging of default options properly,
// so we need to duplicate the effects options here.
effects: {
spotlight: {
interactivity: {
enabled: true,
rootElementSelector: '#wpwrap',
},
},
arrowIndicator: true,
liveResize: {
mutation: true,
resize: true,
rootElementSelector: '#wpwrap',
},
},
},
closeHandler: ( steps, currentStepIndex ) => {
updateUserPreferences( { variable_product_tour_shown: 'yes' } );
setIsTourOpen( false );
if ( currentStepIndex === steps.length - 1 ) {
recordEvent( 'variable_product_tour_completed', {
step: getStepName(
steps as TourKitTypes.WooStep[],
currentStepIndex
),
} );
} else {
recordEvent( 'variable_product_tour_dismissed', {
step: getStepName(
steps as TourKitTypes.WooStep[],
currentStepIndex
),
} );
}
},
};
// show the tour when the product type is changed to variable
useEffect( () => {
const productTypeSelect = document.querySelector(
'#product-type'
) as HTMLSelectElement;
if ( hasShownTour === 'yes' || ! productTypeSelect ) {
return;
}
function handleProductTypeChange() {
if ( productTypeSelect.value === 'variable' ) {
setIsTourOpen( true );
recordEvent( 'variable_product_tour_started', {
step: getStepName( config.steps, 0 ),
} );
}
}
productTypeSelect.addEventListener( 'change', handleProductTypeChange );
return () => {
productTypeSelect.removeEventListener(
'change',
handleProductTypeChange
);
};
} );
if ( ! isTourOpen ) {
return null;
}
return <TourKit config={ config } />;
};

View File

@ -10,12 +10,12 @@ import {
ALLOW_TRACKING_OPTION_NAME,
STORE_KEY as CES_STORE_KEY,
} from '@woocommerce/customer-effort-score';
import { NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME } from '@woocommerce/product-editor';
/**
* Internal dependencies
*/
import { ClassicEditorIcon } from '../../images/classic-editor-icon';
import { NEW_PRODUCT_MANAGEMENT } from '~/customer-effort-score-tracks/product-mvp-ces-footer';
export const ClassicEditorMenuItem = ( {
onClose,
@ -57,7 +57,7 @@ export const ClassicEditorMenuItem = ( {
onClick={ () => {
if ( allowTracking ) {
updateOptions( {
[ NEW_PRODUCT_MANAGEMENT ]: 'no',
[ NEW_PRODUCT_MANAGEMENT_ENABLED_OPTION_NAME ]: 'no',
} );
showProductMVPFeedbackModal();
onClose();

View File

@ -1,7 +1,10 @@
/**
* External dependencies
*/
import { __experimentalWooProductMoreMenuItem as WooProductMoreMenuItem } from '@woocommerce/product-editor';
import {
__experimentalProductMVPFeedbackModalContainer as ProductMVPFeedbackModalContainer,
__experimentalWooProductMoreMenuItem as WooProductMoreMenuItem,
} from '@woocommerce/product-editor';
import { registerPlugin } from '@wordpress/plugins';
import { WooHeaderItem } from '@woocommerce/admin-layout';
@ -13,7 +16,6 @@ import { useEntityProp } from '@wordpress/core-data';
/**
* Internal dependencies
*/
import { ProductMVPFeedbackModalContainer } from '~/customer-effort-score-tracks/product-mvp-feedback-modal-container';
import {
FeedbackMenuItem,
ClassicEditorMenuItem,

View File

@ -1,8 +1,10 @@
/**
* Internal dependencies
* External dependencies
*/
import { ProductMVPCESFooter } from '~/customer-effort-score-tracks/product-mvp-ces-footer';
import { ProductMVPFeedbackModalContainer } from '~/customer-effort-score-tracks/product-mvp-feedback-modal-container';
import {
__experimentalProductMVPCESFooter as ProductMVPCESFooter,
__experimentalProductMVPFeedbackModalContainer as ProductMVPFeedbackModalContainer,
} from '@woocommerce/product-editor';
export const ProductFormFooter: React.FC = () => {
return (

View File

@ -17,6 +17,7 @@ import { useCustomerEffortScoreExitPageTracker } from '@woocommerce/customer-eff
import {
preventLeavingProductForm,
__experimentalUseProductHelper as useProductHelper,
__experimentalUseProductMVPCESFooter as useProductMVPCESFooter,
} from '@woocommerce/product-editor';
import { Product } from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
@ -31,7 +32,6 @@ import { store } from '@wordpress/viewport';
* Internal dependencies
*/
import './product-form-actions.scss';
import { useProductMVPCESFooter } from '~/customer-effort-score-tracks/use-product-mvp-ces-footer';
export const ProductFormActions: React.FC = () => {
const {

View File

@ -29,15 +29,6 @@ jest.mock( '@wordpress/data', () => ( {
useSelect: jest.fn().mockReturnValue( { productCESAction: 'hide' } ),
} ) );
jest.mock( '@woocommerce/tracks', () => ( { recordEvent: jest.fn() } ) );
jest.mock(
'~/customer-effort-score-tracks/use-product-mvp-ces-footer',
() => ( {
useProductMVPCESFooter: () => ( {
onPublish: onPublishCES,
onSaveDraft: onDraftCES,
} ),
} )
);
jest.mock( '@woocommerce/admin-layout', () => ( {
WooHeaderItem: ( props: { children: () => React.ReactElement } ) => (
<Fragment { ...props }>{ props.children() }</Fragment>
@ -51,6 +42,10 @@ jest.mock( '@woocommerce/product-editor', () => {
copyProductWithStatus,
deleteProductAndRedirect,
} ),
__experimentalUseProductMVPCESFooter: () => ( {
onPublish: onPublishCES,
onSaveDraft: onDraftCES,
} ),
};
} );
jest.mock( '@woocommerce/navigation', () => ( {

View File

@ -1,9 +1,13 @@
/**
* External dependencies
*/
import { __experimentalUseProductMVPCESFooter as useProductMVPCESFooter } from '@woocommerce/product-editor';
/**
* Internal dependencies
*/
import { ProductTour } from './product-tour';
import { ProductTourModal } from './product-tour-modal';
import { useProductMVPCESFooter } from '~/customer-effort-score-tracks/use-product-mvp-ces-footer';
import { useProductTour } from './use-product-tour';
export const ProductTourContainer: React.FC = () => {

View File

@ -0,0 +1,13 @@
/**
* External dependencies
*/
import { render } from '@wordpress/element';
/**
* Internal dependencies
*/
import { VariableProductTour } from '../../guided-tours/variable-product-tour';
const root = document.createElement( 'div' );
root.setAttribute( 'id', 'variable-product-tour-root' );
render( <VariableProductTour />, document.body.appendChild( root ) );

View File

@ -20,12 +20,7 @@
"~/*": [ "*" ]
},
"rootDir": "client",
"typeRoots": [
"./client/typings",
"./node_modules/@types"
]
"typeRoots": [ "./client/typings", "./node_modules/@types" ]
},
"include": [
"./client/**/*"
]
"include": [ "./client/**/*" ]
}

View File

@ -65,6 +65,7 @@ const wpAdminScripts = [
'settings-tracking',
'order-tracking',
'product-import-tracking',
'variable-product-tour',
];
const getEntryPoints = () => {
const entryPoints = {

View File

@ -0,0 +1,4 @@
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
<path fill-rule="evenodd" clip-rule="evenodd" d="M2.83337 4.66674C2.83337 3.65422 3.65419 2.8334 4.66671 2.8334H6.83337V3.8334H4.66671C4.20647 3.8334 3.83337 4.2065 3.83337 4.66674V11.3334C3.83337 11.7936 4.20647 12.1667 4.66671 12.1667H11.3334C11.7936 12.1667 12.1667 11.7936 12.1667 11.3334V8.90748H13.1667V11.3334C13.1667 12.3459 12.3459 13.1667 11.3334 13.1667H4.66671C3.65419 13.1667 2.83337 12.3459 2.83337 11.3334V4.66674Z" fill="#1B71B1"/>
<path fill-rule="evenodd" clip-rule="evenodd" d="M12.4156 3.01306L9.93204 3.02428L9.92752 2.02429L14.1325 2.00529L14.0964 6.19525L13.0965 6.18665L13.1177 3.72518L8.86104 7.9818L8.15393 7.27469L12.4156 3.01306Z" fill="#1B71B1"/>
</svg>

After

Width:  |  Height:  |  Size: 779 B

View File

@ -1,8 +1,8 @@
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_4183_170650" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="3" y="3" width="71" height="71">
<path fill-rule="evenodd" clip-rule="evenodd" d="M21.6663 21.6663H34.333L23.333 3.33301L3.33301 36.6663H21.6663V21.6663ZM73.333 56.6663C73.333 65.8697 65.8697 73.333 56.6663 73.333C47.463 73.333 39.9997 65.8697 39.9997 56.6663C39.9997 47.463 47.463 39.9997 56.6663 39.9997C65.8697 39.9997 73.333 47.463 73.333 56.6663ZM53.333 26.6663V35.283C44.0563 36.7263 36.7263 44.0563 35.283 53.333H26.6663V26.6663H53.333Z" fill="white"/>
<mask id="mask0_210_31040" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="6" y="10" width="68" height="60">
<path fill-rule="evenodd" clip-rule="evenodd" d="M53.3332 20H66.6665C70.3484 20 73.3332 22.9848 73.3332 26.6667V63.3333C73.3332 67.0152 70.3484 70 66.6665 70H13.3332C9.65127 70 6.6665 67.0152 6.6665 63.3333V26.6667C6.6665 22.9848 9.65127 20 13.3332 20H26.6665V10H53.3332V20ZM39.9998 20C41.8408 20 43.3332 21.4924 43.3332 23.3333C43.3332 25.1743 41.8408 26.6667 39.9998 26.6667C38.1589 26.6667 36.6665 25.1743 36.6665 23.3333C36.6665 21.4924 38.1589 20 39.9998 20ZM19.9998 46.6667H59.9998V56.6667H19.9998V46.6667ZM33.3332 16.6667H46.6665V33.3333H33.3332V16.6667ZM13.3332 63.3333H66.6665V33.3333H53.3332C53.3332 37.0152 50.3484 40 46.6665 40H33.3332C29.6513 40 26.6665 37.0152 26.6665 33.3333H13.3332V63.3333Z" fill="white"/>
</mask>
<g mask="url(#mask0_4183_170650)">
<g mask="url(#mask0_210_31040)">
<rect width="80" height="80" fill="#DCDCDE"/>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 744 B

After

Width:  |  Height:  |  Size: 1.0 KiB

View File

@ -0,0 +1,8 @@
<svg width="80" height="80" viewBox="0 0 80 80" fill="none" xmlns="http://www.w3.org/2000/svg">
<mask id="mask0_211_34197" style="mask-type:luminance" maskUnits="userSpaceOnUse" x="6" y="6" width="68" height="68">
<path fill-rule="evenodd" clip-rule="evenodd" d="M73.3333 40C73.3333 21.59 58.41 6.66667 40 6.66667C21.59 6.66667 6.66663 21.59 6.66663 40C6.66663 58.41 21.59 73.3333 40 73.3333C58.41 73.3333 73.3333 58.41 73.3333 40ZM40 13.3333C25.2966 13.3333 13.3333 25.2967 13.3333 40C13.3333 54.7033 25.2966 66.6667 40 66.6667C54.7033 66.6667 66.6666 54.7033 66.6666 40C66.6666 25.2967 54.7033 13.3333 40 13.3333ZM43.3333 30V23.3333H36.6666V30H43.3333ZM43.3333 36.6667V56.6667H36.6666V36.6667H43.3333Z" fill="white"/>
</mask>
<g mask="url(#mask0_211_34197)">
<rect width="80" height="80" fill="#DCDCDE"/>
</g>
</svg>

After

Width:  |  Height:  |  Size: 819 B

View File

@ -0,0 +1,4 @@
Significance: minor
Type: enhancement
Show tour when product type is changed to variable.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
fixed bug where adjust_download_permissions was being scheduled on variable products without downloadable variations

View File

@ -0,0 +1,4 @@
Significance: minor
Type: dev
Move components to @woocommerce/product-editor

View File

@ -0,0 +1,4 @@
Significance: patch
Type: tweak
Changed label for button to add a new global attribute value from the product screen.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: tweak
Update style of product attributes tab empty state.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Remove multichannel marketing info from WC Tracker

View File

@ -0,0 +1,4 @@
Significance: minor
Type: enhancement
Show info message when on variations tab and no attributes have been assigned to product.

View File

@ -1016,33 +1016,74 @@
margin: 1px;
}
}
.add-attributes-container {
box-sizing: border-box;
display: flex;
align-items: center;
padding: 32px 0;
height: 360px;
a {
text-decoration: none;
&[target="_blank"]::after {
content: url('../images/icons/external-link.svg');
margin-left: 2px;
vertical-align: sub;
}
}
.add-attributes-message {
display: flex;
flex-direction: column;
align-items: center;
gap: 24px;
width: 100%;
p {
width: 90%;
max-width: 544px;
font-size: 14px;
line-height: 18px;
text-align: center;
}
}
}
}
#product_attributes {
.add-global-attribute-container {
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 32px 0px;
gap: 24px;
height: 360px;
@media screen and ( max-width: 782px ) {
button {
vertical-align: top;
}
}
p {
width: 90%;
max-width: 544px;
font-size: 14px;
line-height: 18px;
text-align: center;
}
&.hidden {
display: none;
}
.message {
box-sizing: border-box;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
padding: 32px 0px;
gap: 24px;
flex: 1;
@media screen and ( max-width: 782px ) {
button {
vertical-align: top;
}
}
p {
width: 90%;
max-width: 544px;
font-size: 14px;
line-height: 18px;
text-align: center;
}
}
}
.toolbar-top {
.button,

View File

@ -836,6 +836,18 @@ jQuery( function ( $ ) {
} );
} );
// Go to attributes tab when clicking on link in variations message
$( document.body ).on(
'click',
'#variable_product_options .add-attributes-message a[href="#product_attributes"]',
function () {
$(
'#woocommerce-product-data .attribute_tab a[href="#product_attributes"]'
).trigger( 'click' );
return false;
}
);
// Uploading files.
var downloadable_file_frame;
var file_path_field;

View File

@ -38,6 +38,7 @@ class WC_Admin_Pointers {
switch ( $screen->id ) {
case 'product':
$this->create_product_tutorial();
$this->create_variable_product_tutorial();
break;
case 'woocommerce_page_wc-addons':
$this->create_wc_addons_tutorial();
@ -64,6 +65,17 @@ class WC_Admin_Pointers {
WCAdminAssets::register_script( 'wp-admin-scripts', 'product-tour', true );
}
/**
* Pointers for creating a variable product.
*/
public function create_variable_product_tutorial() {
if ( ! current_user_can( 'manage_options' ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
return;
}
WCAdminAssets::register_script( 'wp-admin-scripts', 'variable-product-tour', true );
}
/**
* Pointers for accessing In-App Marketplace.
*/

View File

@ -169,6 +169,16 @@ class WC_Meta_Box_Product_Data {
return true === $attribute->get_variation();
}
/**
* Filter callback for finding non-variation attributes.
*
* @param WC_Product_Attribute $attribute Product attribute.
* @return bool
*/
private static function filter_non_variation_attributes( $attribute ) {
return false === $attribute->get_variation();
}
/**
* Show options for the variable product type.
*/
@ -176,12 +186,14 @@ class WC_Meta_Box_Product_Data {
global $post, $wpdb, $product_object;
/* phpcs:disable WooCommerce.Commenting.CommentHooks.MissingHookComment */
$variation_attributes = array_filter( $product_object->get_attributes(), array( __CLASS__, 'filter_variation_attributes' ) );
$default_attributes = $product_object->get_default_attributes();
$variations_count = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_count', $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'product_variation' AND post_status IN ('publish', 'private')", $post->ID ) ), $post->ID ) );
$variations_per_page = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_per_page', 15 ) );
$variations_total_pages = ceil( $variations_count / $variations_per_page );
$modal_title = get_bloginfo( 'name' ) . __( ' says', 'woocommerce' );
$global_attributes_count = count( wc_get_attribute_taxonomies() );
$variation_attributes = array_filter( $product_object->get_attributes(), array( __CLASS__, 'filter_variation_attributes' ) );
$non_variation_attributes_count = count( array_filter( $product_object->get_attributes(), array( __CLASS__, 'filter_non_variation_attributes' ) ) );
$default_attributes = $product_object->get_default_attributes();
$variations_count = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_count', $wpdb->get_var( $wpdb->prepare( "SELECT COUNT(ID) FROM $wpdb->posts WHERE post_parent = %d AND post_type = 'product_variation' AND post_status IN ('publish', 'private')", $post->ID ) ), $post->ID ) );
$variations_per_page = absint( apply_filters( 'woocommerce_admin_meta_boxes_variations_per_page', 15 ) );
$variations_total_pages = ceil( $variations_count / $variations_per_page );
$modal_title = get_bloginfo( 'name' ) . __( ' says', 'woocommerce' );
/* phpcs: enable */
include __DIR__ . '/views/html-product-data-variations.php';

View File

@ -64,7 +64,7 @@ if ( ! defined( 'ABSPATH' ) ) {
</select>
<button class="button plus select_all_attributes"><?php esc_html_e( 'Select all', 'woocommerce' ); ?></button>
<button class="button minus select_no_attributes"><?php esc_html_e( 'Select none', 'woocommerce' ); ?></button>
<button class="button fr plus add_new_attribute"><?php esc_html_e( 'Add new', 'woocommerce' ); ?></button>
<button class="button fr plus add_new_attribute"><?php esc_html_e( 'Create value', 'woocommerce' ); ?></button>
<?php
}

View File

@ -22,20 +22,22 @@ $icon_url = WC_ADMIN_IMAGES_FOLDER_URL . '/icons/global-a
<div id="product_attributes" class="panel wc-metaboxes-wrapper hidden">
<div class="toolbar toolbar-top <?php echo $is_add_global_attribute_visible ? ' expand-close-hidden' : ''; ?>">
<div class="add-global-attribute-container<?php echo $is_add_global_attribute_visible ? '' : ' hidden'; ?>">
<img src="<?php echo esc_url( $icon_url ); ?>" />
<p>
<?php
esc_html_e(
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
'woocommerce'
);
?>
</p>
<div>
<button type="button" class="button add_custom_attribute"><?php esc_html_e( 'Create new attribute', 'woocommerce' ); ?></button>
<select class="wc-attribute-search" data-placeholder="<?php esc_attr_e( 'Add existing attribute', 'woocommerce' ); ?>" data-minimum-input-length="0">
<div class="actions">
<button type="button" class="button add_custom_attribute"><?php esc_html_e( 'Add new', 'woocommerce' ); ?></button>
<select class="wc-attribute-search" data-placeholder="<?php esc_attr_e( 'Add existing', 'woocommerce' ); ?>" data-minimum-input-length="0">
</select>
</div>
<div class="message">
<img src="<?php echo esc_url( $icon_url ); ?>" />
<p>
<?php
esc_html_e(
'Add descriptive pieces of information that customers can use to search for this product on your store, such as “Material” or “Brand”.',
'woocommerce'
);
?>
</p>
</div>
</div>
<div class="add-attribute-container<?php echo $is_add_global_attribute_visible ? ' hidden' : ' '; ?>">
<?php

View File

@ -8,11 +8,33 @@
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$add_attributes_icon_url = WC_ADMIN_IMAGES_FOLDER_URL . '/icons/info.svg';
?>
<div id="variable_product_options" class="panel wc-metaboxes-wrapper hidden">
<div id="variable_product_options_inner">
<?php if ( ! count( $variation_attributes ) ) : ?>
<?php if ( ! count( $variation_attributes ) && ( ( $global_attributes_count > 0 ) || ( $non_variation_attributes_count > 0 ) ) ) : ?>
<div class="add-attributes-container">
<div class="add-attributes-message">
<img src="<?php echo esc_url( $add_attributes_icon_url ); ?>" />
<p>
<?php
echo wp_kses_post(
sprintf(
/* translators: %1$s: url for attributes tab, %2$s: url for variable product documentation */
__( 'Add some attributes in the <a href="%1$s">Attributes</a> tab to generate variations. Make sure to check the <b>Used for variations</b> box. <a href="%2$s" target="_blank" rel="noreferrer">Learn more</a>', 'woocommerce' ),
esc_url( '#product_attributes' ),
esc_url( 'https://woocommerce.com/document/variable-product/' )
)
);
?>
</p>
</div>
</div>
<?php elseif ( ! count( $variation_attributes ) ) : ?>
<div id="message" class="inline notice woocommerce-message">
<p>

View File

@ -696,7 +696,6 @@ class WC_Tracker {
'hpos_transactions_enabled' => get_option( 'woocommerce_use_db_transactions_for_custom_orders_table_data_sync' ),
'hpos_transactions_level' => get_option( 'woocommerce_db_transactions_isolation_level_for_custom_orders_table_data_sync' ),
'show_marketplace_suggestions' => get_option( 'woocommerce_show_marketplace_suggestions' ),
'multichannel_marketing_enabled' => get_option( 'woocommerce_multichannel_marketing_enabled' ),
);
}

View File

@ -103,7 +103,13 @@ class WCAdminUser {
* @return array Fields to expose over the WP user endpoint.
*/
public function get_user_data_fields() {
return apply_filters( 'woocommerce_admin_get_user_data_fields', array() );
/**
* Filter user data fields exposed over the WordPress user endpoint.
*
* @since 4.0.0
* @param array $fields Array of fields to expose over the WP user endpoint.
*/
return apply_filters( 'woocommerce_admin_get_user_data_fields', array( 'variable_product_tour_shown' ) );
}
/**

View File

@ -44,6 +44,19 @@ class DownloadPermissionsAdjuster {
return;
}
$are_any_children_downloadable = false;
foreach ( $children_ids as $child_id ) {
$child = wc_get_product( $child_id );
if ( $child && $child->is_downloadable() ) {
$are_any_children_downloadable = true;
break;
}
}
if ( ! $product->is_downloadable() && ! $are_any_children_downloadable ) {
return;
}
$scheduled_action_args = array( $product->get_id() );
$already_scheduled_actions =

View File

@ -40,6 +40,32 @@ test.describe( 'Add New Variable Product Page', () => {
await api.post( 'products/batch', { delete: ids } );
} );
test( 'shows the variable product tour', async ( { page } ) => {
await page.goto( 'wp-admin/post-new.php?post_type=product' );
await page.selectOption( '#product-type', 'variable', { force: true } );
// because of the way that the tour is dynamically positioned,
// Playwright can't automatically scroll the button into view,
// so we will manually scroll the attributes tab into view,
// which will cause the tour to be scrolled into view as well
await page
.locator( '.attribute_tab' )
.getByRole( 'link', { name: 'Attributes' } )
.scrollIntoViewIfNeeded();
// dismiss the variable product tour
await page
.getByRole( 'button', { name: 'Got it' } )
.click( { force: true } );
// wait for the tour's dismissal to be saved
await page.waitForResponse(
( response ) =>
response.url().includes( '/users/' ) &&
response.status() === 200
);
} );
test( 'can create product, attributes and variations, edit variations and delete variations', async ( {
page,
} ) => {
@ -54,10 +80,18 @@ test.describe( 'Add New Variable Product Page', () => {
if ( i > 0 ) {
await page.click( 'button.add_attribute' );
}
await page.waitForSelector( `input[name="attribute_names[${ i }]"]` );
await page.waitForSelector(
`input[name="attribute_names[${ i }]"]`
);
await page.locator( `input[name="attribute_names[${ i }]"]` ).first().type( `attr #${ i + 1 }` );
await page.locator( `textarea[name="attribute_values[${ i }]"]` ).first().type( 'val1 | val2' );
await page
.locator( `input[name="attribute_names[${ i }]"]` )
.first()
.type( `attr #${ i + 1 }` );
await page
.locator( `textarea[name="attribute_values[${ i }]"]` )
.first()
.type( 'val1 | val2' );
}
await page.click( 'text=Save attributes' );
// wait for the attributes to be saved
@ -167,10 +201,11 @@ test.describe( 'Add New Variable Product Page', () => {
} );
const variationsCount = await page.$$( '.woocommerce_variation' );
await expect( variationsCount ).toHaveLength( 0 );
} );
test( 'can manually add a variation, manage stock levels, set variation defaults and remove a variation', async ( { page } ) => {
test( 'can manually add a variation, manage stock levels, set variation defaults and remove a variation', async ( {
page,
} ) => {
await page.goto( 'wp-admin/post-new.php?post_type=product' );
await page.fill( '#title', manualVariableProduct );
await page.selectOption( '#product-type', 'variable', { force: true } );
@ -180,10 +215,18 @@ test.describe( 'Add New Variable Product Page', () => {
if ( i > 0 ) {
await page.click( 'button.add_attribute' );
}
await page.waitForSelector( `input[name="attribute_names[${ i }]"]` );
await page.waitForSelector(
`input[name="attribute_names[${ i }]"]`
);
await page.locator( `input[name="attribute_names[${ i }]"]` ).first().type( `attr #${ i + 1 }` );
await page.locator( `textarea[name="attribute_values[${ i }]"]` ).first().type( 'val1 | val2' );
await page
.locator( `input[name="attribute_names[${ i }]"]` )
.first()
.type( `attr #${ i + 1 }` );
await page
.locator( `textarea[name="attribute_values[${ i }]"]` )
.first()
.type( 'val1 | val2' );
}
await page.click( 'text=Save attributes' );
// wait for the attributes to be saved
@ -289,6 +332,8 @@ test.describe( 'Add New Variable Product Page', () => {
page.on( 'dialog', ( dialog ) => dialog.accept() );
await page.hover( '.woocommerce_variation' );
await page.click( '.remove_variation.delete' );
await expect( page.locator( '.woocommerce_variation' ) ).toHaveCount( 0 );
await expect( page.locator( '.woocommerce_variation' ) ).toHaveCount(
0
);
} );
} );

View File

@ -102,7 +102,7 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
)
);
$product = ProductHelper::create_variation_product();
$product = $this->create_downloadable_variation_product();
$this->sut->maybe_schedule_adjust_download_permissions( $product );
$expected_get_scheduled_actions_args = array(
@ -135,7 +135,7 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
)
);
$product = ProductHelper::create_variation_product();
$product = $this->create_downloadable_variation_product();
$this->sut->maybe_schedule_adjust_download_permissions( $product );
$expected_get_scheduled_actions_args = array(
@ -168,6 +168,7 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
$parent_download_id = current( $product->get_downloads() )->get_id();
$child = wc_get_product( current( $product->get_children() ) );
$child->set_downloadable( true );
$child->set_downloads( array( $download ) );
$child->save();
$child_download_id = current( $child->get_downloads() )->get_id();
@ -222,6 +223,7 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
$parent_download_id = current( $product->get_downloads() )->get_id();
$child = wc_get_product( current( $product->get_children() ) );
$child->set_downloadable( true );
$child->set_downloads( array( $download ) );
$child->save();
$child_download_id = current( $child->get_downloads() )->get_id();
@ -278,6 +280,7 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
$parent_download_id = current( $product->get_downloads() )->get_id();
$child = wc_get_product( current( $product->get_children() ) );
$child->set_downloadable( true );
$child->set_downloads( array( $download ) );
$child->save();
$child_download_id = current( $child->get_downloads() )->get_id();
@ -359,4 +362,20 @@ class DownloadPermissionsAdjusterTest extends \WC_Unit_Test_Case {
return $data_store;
}
/**
* Creates a variable product with a downloadable variation. No downloads are added.
*
* @return \WC_Product A product.
*/
private function create_downloadable_variation_product() {
$product = ProductHelper::create_variation_product();
$child = wc_get_product( current( $product->get_children() ) );
$child->set_downloadable( true );
$child->save();
return $product;
}
}

View File

@ -1418,6 +1418,7 @@ importers:
'@testing-library/user-event': ^13.5.0
'@types/jest': ^27.4.1
'@types/lodash': ^4.14.179
'@types/prop-types': ^15.7.4
'@types/react': ^17.0.2
'@types/testing-library__jest-dom': ^5.14.3
'@types/wordpress__block-editor': ^7.0.0
@ -1432,8 +1433,10 @@ importers:
'@woocommerce/admin-layout': workspace:*
'@woocommerce/components': workspace:*
'@woocommerce/currency': workspace:*
'@woocommerce/customer-effort-score': workspace:*
'@woocommerce/data': workspace:^4.1.0
'@woocommerce/eslint-plugin': workspace:*
'@woocommerce/experimental': workspace:*
'@woocommerce/internal-js-tests': workspace:*
'@woocommerce/internal-style-build': workspace:*
'@woocommerce/navigation': workspace:^8.1.0
@ -1466,6 +1469,7 @@ importers:
lodash: ^4.17.21
postcss: ^8.4.7
postcss-loader: ^4.3.0
prop-types: ^15.8.1
react: ^17.0.2
react-dom: ^17.0.2
react-hooks^8.0.1: link:@testing-library/react-hooks^8.0.1
@ -1478,11 +1482,14 @@ importers:
webpack-cli: ^3.3.12
dependencies:
'@types/lodash': 4.14.184
'@types/prop-types': 15.7.5
'@types/wordpress__blocks': 11.0.7_sfoxds7t5ydpegc3knd667wn6m
'@woocommerce/admin-layout': link:../admin-layout
'@woocommerce/components': link:../components
'@woocommerce/currency': link:../currency
'@woocommerce/customer-effort-score': link:../customer-effort-score
'@woocommerce/data': link:../data
'@woocommerce/experimental': link:../experimental
'@woocommerce/navigation': link:../navigation
'@woocommerce/number': link:../number
'@woocommerce/settings': 1.0.0
@ -1505,6 +1512,7 @@ importers:
'@wordpress/url': 3.7.1
classnames: 2.3.1
lodash: 4.17.21
prop-types: 15.8.1
react-router-dom: 6.3.0_sfoxds7t5ydpegc3knd667wn6m
devDependencies:
'@babel/core': 7.21.3
@ -16608,21 +16616,21 @@ packages:
'@emotion/styled': 11.8.1_6t3indjc5ssefvr44gr3wo2uqu
'@emotion/utils': 1.0.0
'@use-gesture/react': 10.2.10_react@17.0.2
'@wordpress/a11y': 3.6.1
'@wordpress/a11y': 3.28.0
'@wordpress/compose': 5.4.1_react@17.0.2
'@wordpress/date': 4.6.1
'@wordpress/deprecated': 3.6.1
'@wordpress/dom': 3.6.1
'@wordpress/date': 4.28.0
'@wordpress/deprecated': 3.28.0
'@wordpress/dom': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/escape-html': 2.28.0
'@wordpress/hooks': 3.6.1
'@wordpress/hooks': 3.28.0
'@wordpress/i18n': 4.6.1
'@wordpress/icons': 8.2.3
'@wordpress/is-shallow-equal': 4.28.0
'@wordpress/keycodes': 3.6.1
'@wordpress/primitives': 3.4.1
'@wordpress/rich-text': 5.4.2_react@17.0.2
'@wordpress/warning': 2.6.1
'@wordpress/keycodes': 3.28.0
'@wordpress/primitives': 3.26.0
'@wordpress/rich-text': 5.17.0_react@17.0.2
'@wordpress/warning': 2.28.0
classnames: 2.3.1
colord: 2.9.2
dom-scroll-into-view: 1.2.1
@ -17088,11 +17096,11 @@ packages:
'@babel/runtime': 7.21.0
'@types/lodash': 4.14.184
'@types/mousetrap': 1.6.9
'@wordpress/deprecated': 3.6.1
'@wordpress/dom': 3.6.1
'@wordpress/deprecated': 3.28.0
'@wordpress/dom': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/is-shallow-equal': 4.28.0
'@wordpress/keycodes': 3.6.1
'@wordpress/keycodes': 3.28.0
'@wordpress/priority-queue': 2.28.0
clipboard: 2.0.10
lodash: 4.17.21
@ -17128,10 +17136,10 @@ packages:
react: ^17.0.0
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/api-fetch': 6.3.1
'@wordpress/api-fetch': 6.25.0
'@wordpress/blocks': 11.18.0_react@17.0.2
'@wordpress/data': 6.6.1_react@17.0.2
'@wordpress/deprecated': 3.6.1
'@wordpress/deprecated': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/html-entities': 3.6.1
'@wordpress/i18n': 4.6.1
@ -17271,7 +17279,7 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/compose': 5.4.1_react@17.0.2
'@wordpress/deprecated': 3.6.1
'@wordpress/deprecated': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/is-shallow-equal': 4.28.0
'@wordpress/priority-queue': 2.28.0
@ -17386,6 +17394,7 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/hooks': 3.6.1
dev: false
/@wordpress/dom-ready/3.28.0:
resolution: {integrity: sha512-PFFAnuPUouV0uSDZN6G/B8yksybtxzS/6H53OZJEA3h3EsNCicKRMGSowkumvLwXA23HV0K2Kht6JuS+bDECzA==}
@ -17419,6 +17428,7 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
lodash: 4.17.21
dev: false
/@wordpress/e2e-test-utils/3.0.0_ddjhsfu4aotkh3cuzmpsln6ywq:
resolution: {integrity: sha512-XMdR8DeKyDQRF5jKeUlOzP4pTRtoJuOLsNZRLUFUvnrs9y/7/hH17VmPbWp3TJGvV/eGKzO4+D+wJTsP9nJmIw==}
@ -17485,28 +17495,28 @@ packages:
react-dom: ^17.0.0
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/a11y': 3.6.1
'@wordpress/api-fetch': 6.3.1
'@wordpress/a11y': 3.28.0
'@wordpress/api-fetch': 6.25.0
'@wordpress/block-editor': 8.6.0_eqi5qhcxfphl6j3pngzexvnehi
'@wordpress/blocks': 11.18.0_react@17.0.2
'@wordpress/components': 19.8.5_eqi5qhcxfphl6j3pngzexvnehi
'@wordpress/compose': 5.4.1_react@17.0.2
'@wordpress/core-data': 4.4.5_react@17.0.2
'@wordpress/data': 6.6.1_react@17.0.2
'@wordpress/date': 4.6.1
'@wordpress/deprecated': 3.6.1
'@wordpress/date': 4.28.0
'@wordpress/deprecated': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/hooks': 3.6.1
'@wordpress/hooks': 3.28.0
'@wordpress/html-entities': 3.6.1
'@wordpress/i18n': 4.6.1
'@wordpress/icons': 8.2.3
'@wordpress/keyboard-shortcuts': 3.4.1_react@17.0.2
'@wordpress/keycodes': 3.6.1
'@wordpress/keycodes': 3.28.0
'@wordpress/media-utils': 3.4.1
'@wordpress/notices': 3.6.1_react@17.0.2
'@wordpress/notices': 3.28.0_react@17.0.2
'@wordpress/preferences': 1.3.0_eqi5qhcxfphl6j3pngzexvnehi
'@wordpress/reusable-blocks': 3.17.0_mtk4wljkd5jimhszw4p7nnxuzm
'@wordpress/rich-text': 5.4.2_react@17.0.2
'@wordpress/rich-text': 5.17.0_react@17.0.2
'@wordpress/server-side-render': 3.17.0_mtk4wljkd5jimhszw4p7nnxuzm
'@wordpress/url': 3.7.1
'@wordpress/wordcount': 3.28.0
@ -17807,6 +17817,7 @@ packages:
engines: {node: '>=12'}
dependencies:
'@babel/runtime': 7.21.0
dev: false
/@wordpress/html-entities/3.28.0:
resolution: {integrity: sha512-UAaU6au8UTrSkowkV33pE/EvdPov2mA9W51vh6t88KsJPzt4171EzIchGnQuzt04HuZLdLyWy2A+7JCOSbfhBA==}
@ -17865,7 +17876,7 @@ packages:
hasBin: true
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/hooks': 3.6.1
'@wordpress/hooks': 3.28.0
gettext-parser: 1.4.0
lodash: 4.17.21
memize: 1.1.0
@ -17887,7 +17898,7 @@ packages:
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/element': 4.4.1
'@wordpress/primitives': 3.4.1
'@wordpress/primitives': 3.26.0
dev: false
/@wordpress/icons/8.4.0:
@ -17915,17 +17926,17 @@ packages:
react-dom: ^17.0.0
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/a11y': 3.6.1
'@wordpress/a11y': 3.28.0
'@wordpress/components': 19.8.5_eqi5qhcxfphl6j3pngzexvnehi
'@wordpress/compose': 5.4.1_react@17.0.2
'@wordpress/data': 6.6.1_react@17.0.2
'@wordpress/deprecated': 3.6.1
'@wordpress/deprecated': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/i18n': 4.6.1
'@wordpress/icons': 8.2.3
'@wordpress/plugins': 4.4.3_react@17.0.2
'@wordpress/preferences': 1.3.0_eqi5qhcxfphl6j3pngzexvnehi
'@wordpress/viewport': 4.4.1_react@17.0.2
'@wordpress/viewport': 4.17.0_react@17.0.2
classnames: 2.3.1
lodash: 4.17.21
react: 17.0.2
@ -18109,7 +18120,7 @@ packages:
'@babel/runtime': 7.21.0
'@wordpress/data': 6.6.1_react@17.0.2
'@wordpress/element': 4.4.1
'@wordpress/keycodes': 3.6.1
'@wordpress/keycodes': 3.28.0
lodash: 4.17.21
react: 17.0.2
rememo: 3.0.0
@ -18146,13 +18157,14 @@ packages:
'@babel/runtime': 7.21.0
'@wordpress/i18n': 4.6.1
lodash: 4.17.21
dev: false
/@wordpress/media-utils/3.4.1:
resolution: {integrity: sha512-WNAaMqqw6Eqy61KTWBy1NlgXSZH82Cm2SPVbz0v6yhJ4ktJmSRFm7Fd4mTMFS/L7NKTxwo+DFqEHlTGKj3lyzQ==}
engines: {node: '>=12'}
dependencies:
'@babel/runtime': 7.21.0
'@wordpress/api-fetch': 6.3.1
'@wordpress/api-fetch': 6.25.0
'@wordpress/blob': 3.28.0
'@wordpress/element': 4.4.1
'@wordpress/i18n': 4.6.1
@ -18209,7 +18221,7 @@ packages:
'@babel/runtime': 7.21.0
'@wordpress/compose': 5.4.1_react@17.0.2
'@wordpress/element': 4.4.1
'@wordpress/hooks': 3.6.1
'@wordpress/hooks': 3.28.0
'@wordpress/icons': 8.2.3
lodash: 4.17.21
memize: 1.1.0

View File

@ -18,7 +18,9 @@
"src/**/*.ts",
"src/**/*.tsx",
"src/**/*.php",
"includes/**/*.php"
"includes/**/*.php",
"webpack.config.js",
"tsconfig.json"
],
"outputs": [
"dist/**",
@ -77,7 +79,9 @@
"client/**/*.jsx",
"client/**/*.ts",
"client/**/*.tsx",
"client/**/*.scss"
"client/**/*.scss",
"webpack.config.js",
"tsconfig.json"
],
"outputMode": "new-only"
},