Merge branch 'trunk' into update/webpack-config

This commit is contained in:
Chi-Hsuan Huang 2022-04-15 13:48:20 +08:00 committed by GitHub
commit f6282eefdc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
92 changed files with 830 additions and 1405 deletions

View File

@ -41,9 +41,8 @@ If you have questions about the process to contribute code or want to discuss de
- Make sure to write good and detailed commit messages (see [this post](https://chris.beams.io/posts/git-commit/) for more on this) and follow all the applicable sections of the pull request template.
- Please avoid modifying the changelog directly or updating the .pot files. These will be updated by the WooCommerce team.
If you are contributing code to the (Javascript-driven) WooCommerce Admin project or to Gutenberg blocks, note that these are developed in external packages.
If you are contributing code to the (Javascript-driven) Gutenberg blocks, note that it's developed in an external package.
- [WooCommerce Admin](https://github.com/woocommerce/woocommerce-admin)
- [Blocks](https://github.com/woocommerce/woocommerce-gutenberg-products-block)
## Feature Requests 🚀

View File

@ -36,13 +36,13 @@ To create a new package, add a new folder to `/packages`, containing…
"author": "Automattic",
"license": "GPL-2.0-or-later",
"keywords": [ "wordpress", "woocommerce" ],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/[_YOUR_PACKAGE_]/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/main/packages/[_YOUR_PACKAGE_]/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -4,6 +4,8 @@
- Update test for payment task. #32467
- Increase timeout threshold for payment task. #32605
# 1.0.0
- Add returned type annotations and remove unused vars. #8020

View File

@ -3,10 +3,10 @@
"version": "1.0.0",
"author": "Automattic",
"description": "E2E tests for the new WooCommerce interface.",
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/admin-e2e-tests/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/admin-e2e-tests/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"keywords": [
"woocommerce",

View File

@ -21,8 +21,10 @@ export class PaymentsSetup extends BasePage {
await waitForElementByText( 'h1', 'Set up payments' );
}
async closeHelpModal(): Promise< void > {
await this.clickButtonWithText( 'Got it' );
async possiblyCloseHelpModal(): Promise< void > {
try {
await this.clickButtonWithText( 'Got it' );
} catch ( e ) {}
}
async showOtherPaymentMethods(): Promise< void > {
@ -32,6 +34,7 @@ export class PaymentsSetup extends BasePage {
`${ selector }[aria-expanded=false]`
);
await toggleButton?.click();
await waitForElementByText( 'h2', 'Offline payment methods' );
}
async goToPaymentMethodSetup(

View File

@ -48,12 +48,13 @@ const testAdminPaymentSetupTask = () => {
it( 'Can visit the payment setup task from the homescreen if the setup wizard has been skipped', async () => {
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.closeHelpModal();
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
} );
it( 'Saving valid bank account transfer details enables the payment method', async () => {
it.skip( 'Saving valid bank account transfer details enables the payment method', async () => {
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.goToPaymentMethodSetup( 'bacs' );
await bankTransferSetup.saveAccountDetails( {
accountNumber: '1234',
@ -63,23 +64,25 @@ const testAdminPaymentSetupTask = () => {
iban: '12 3456 7890',
swiftCode: 'ABBA',
} );
await waitForTimeout( 1000 );
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'bacs' ) ).toBe(
true
);
await homeScreen.navigate();
} );
it( 'Enabling cash on delivery enables the payment method', async () => {
it.skip( 'Enabling cash on delivery enables the payment method', async () => {
await settings.cleanPaymentMethods();
await homeScreen.navigate();
await homeScreen.isDisplayed();
await waitForTimeout( 1000 );
await homeScreen.clickOnTaskList( 'Set up payments' );
await paymentsSetup.possiblyCloseHelpModal();
await paymentsSetup.isDisplayed();
await paymentsSetup.showOtherPaymentMethods();
await waitForTimeout( 500 );
await paymentsSetup.enableCashOnDelivery();
await waitForTimeout( 1000 );
await waitForTimeout( 1500 );
expect( await settings.paymentMethodIsEnabled( 'cod' ) ).toBe(
true
);

View File

@ -3,6 +3,7 @@
- Fix documentation for `TableCard` component
- Update dependency `@wordpress/hooks` to ^3.5.0
- Update dependency `@wordpress/icons` to ^8.1.0
- Add `className` prop for Pill component. #32605
# 10.0.0
- Replace deprecated wp.compose.withState with wp.element.useState. #8338

View File

@ -9,13 +9,13 @@
"woocommerce",
"components"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/components/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/components/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -124,7 +124,7 @@ const config = {
};
```
`type`: A string Autocompleter type used by the [Search Component](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/components/src/search).
`type`: A string Autocompleter type used by the [Search Component](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/components/src/search).
`getLabels`: A function returning a Promise resolving to an array of objects with `id` and `label` properties.
### Date

View File

@ -2,16 +2,17 @@
* External dependencies
*/
import { createElement } from '@wordpress/element';
import classnames from 'classnames';
/**
* Internal dependencies
*/
import { Text } from '../experimental';
export function Pill( { children } ) {
export function Pill( { children, className } ) {
return (
<Text
className="woocommerce-pill"
className={ classnames( 'woocommerce-pill', className ) }
variant="caption"
as="span"
size="12"

View File

@ -9,13 +9,13 @@
"woocommerce",
"csv"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/csv-export/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/csv-export/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -9,13 +9,13 @@
"woocommerce",
"currency"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/currency/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/currency/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/customer-effort-score/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/customer-effort-score/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -9,13 +9,13 @@
"woocommerce",
"data"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/data/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/data/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -9,13 +9,13 @@
"woocommerce",
"date"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/date/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/date/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/dependency-extraction-webpack-plugin/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "src/index.js",
"dependencies": {

View File

@ -10,14 +10,14 @@
"eslint",
"plugin"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/eslint-plugin/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/eslint-plugin/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"url": "https://github.com/woocommerce/woocommerce.git",
"directory": "packages/eslint-plugin"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"files": [
"configs",

View File

@ -9,13 +9,13 @@
"woocommerce",
"experimental"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/experimental/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/experimental/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -10,13 +10,13 @@
"abtest",
"explat"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/explat/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/explat/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -4,14 +4,14 @@
"description": "JavaScript test tooling.",
"author": "Automattic",
"license": "GPL-2.0-or-later",
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/js-tests/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/js-tests/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"url": "https://github.com/woocommerce/woocommerce.git",
"directory": "packages/js-tests"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"private": true,
"main": "build/util/index.js",

View File

@ -9,13 +9,13 @@
"woocommerce",
"navigation"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/navigation/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/navigation/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/number/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/number/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -9,13 +9,13 @@
"woocommerce",
"onboarding"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/onboarding/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/onboarding/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -8,13 +8,13 @@
"wordpress",
"woocommerce"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/style-build/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/style-build/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "index.js",
"dependencies": {

View File

@ -9,13 +9,13 @@
"woocommerce",
"tracks"
],
"homepage": "https://github.com/woocommerce/woocommerce-admin/tree/main/packages/tracks/README.md",
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/tracks/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git"
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce-admin/issues"
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",

View File

@ -1,57 +0,0 @@
name: 'Daily E2E Tests'
on:
schedule:
- cron: '0 0 * * *'
jobs:
e2e-tests:
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
wordpress: ['https://wordpress.org/latest.zip', 'https://wordpress.org/nightly-builds/wordpress-latest.zip']
woocommerce: ['https://downloads.wordpress.org/plugin/woocommerce.zip', 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip']
exclude:
- {'wordpress': 'https://wordpress.org/nightly-builds/wordpress-latest.zip', 'woocommerce': 'https://github.com/woocommerce/woocommerce/releases/download/nightly/woocommerce-trunk-nightly.zip'}
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Install PHP dependencies
run: |
composer install --no-dev
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
composer require wp-cli/i18n-command
pnpm run build:feature-config
pnpm run build
- name: Setup wp-env
env:
WP_ENV_CONFIG: '{ core: "${{ matrix.wordpress }}", plugins: [ ".", "${{ matrix.woocommerce }}" ] }'
run: |
pnpm -g i @wordpress/env
printf '%s\n' "$WP_ENV_CONFIG" > .wp-env-override.json
WP_ENV_TESTS_PORT=8084 wp-env start
wp-env run tests-cli "wp post create --post_type=page --post_status=publish --post_title='Ready' --post_content='E2E-tests.'"
- name: Test
env:
WC_E2E_SCREENSHOTS: 1
run: |
pnpm exec wc-e2e test:e2e
- name: Archive e2e test screenshots
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: e2e-screenshots
path: tests/e2e/screenshots
if-no-files-found: ignore
retention-days: 5

View File

@ -1,40 +0,0 @@
name: 'Daily PHP Tests'
on:
schedule:
- cron: '0 0 * * *'
jobs:
daily-test-php:
name: "Test PHP"
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
wordpress: ['latest', 'nightly']
woocommerce: ['latest', 'nightly']
exclude:
- {'wordpress': 'nightly', 'woocommerce': 'nightly'}
steps:
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
pnpm run build:feature-config
composer install --no-dev
shell: bash
- name: Run the PHP unit tests
env:
WP_VERSION: ${{ matrix.wordpress }}
WC_VERSION: ${{ matrix.woocommerce }}
run: pnpm run test:php
shell: bash

View File

@ -1,50 +0,0 @@
name: E2E tests
on: [pull_request]
jobs:
e2e-tests:
runs-on: ubuntu-18.04
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: '7.3'
- name: Install PHP dependencies
run: |
composer self-update 2.0.6
composer i
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build and run E2E Tests
env:
WC_E2E_SCREENSHOTS: 1
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
WP_VERSION: '5.8.0'
run: |
composer require wp-cli/i18n-command
pnpm run build
pnpm run e2e:docker-up
sleep 10
pnpm exec wc-e2e test:e2e
- name: Archive e2e test screenshots
if: ${{ always() }}
uses: actions/upload-artifact@v2
with:
name: e2e-screenshots
path: tests/e2e/screenshots
if-no-files-found: ignore
retention-days: 5

View File

@ -1,33 +0,0 @@
name: Publish docs
on:
push:
branches:
- main
jobs:
deploy:
runs-on: ubuntu-18.04
steps:
- uses: actions/checkout@v2
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Build
run: |
pnpm run build
pnpm run docs
- name: Deploy docs
uses: peaceiris/actions-gh-pages@v3
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_branch: gh-pages
publish_dir: ./docs

View File

@ -1,25 +0,0 @@
name: Lint the PHP
on: [pull_request]
jobs:
lint-php:
runs-on: ubuntu-latest
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Determine changed files
id: changed-files
uses: wyrihaximus/github-action-files-in-commit@v1.0
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: 7.3
- name: Lint the PHP
env:
CHANGED_FILES: ${{ steps.changed-files.outputs.files }}
run: bin/phpcs.sh
shell: bash

View File

@ -1,87 +0,0 @@
name: Run PHP unit tests
on: [pull_request]
jobs:
test-php:
env:
WP_CORE_DIR: '/tmp/wordpress'
COMPOSER_DEV: 1
runs-on: ubuntu-18.04
strategy:
fail-fast: false
matrix:
php: ['7.1', '7.2', '7.3']
wordpress: ['5.4', '5.6']
woocommerce: ['4.8.0', '4.9.1']
phpunit: ['7.5.20']
composer: ['2.0.6']
include:
- php: '7.0'
wordpress: '5.6'
woocommerce: 'latest'
phpunit: '6.5.9'
composer: '1.10.19'
- php: '7.0'
wordpress: '5.6'
woocommerce: '4.9.1'
phpunit: '6.5.9'
composer: '2.0.6'
- php: '8.0'
wordpress: '5.6'
woocommerce: '5.1.0'
phpunit: '7.5.20'
composer: '2.0.6'
steps:
- name: Cancel Previous Runs
uses: styfle/cancel-workflow-action@0.7.0
with:
access_token: ${{ github.token }}
- name: Check out repository code
uses: actions/checkout@v2
- name: Setup PHP
uses: shivammathur/setup-php@2.9.0
with:
php-version: ${{matrix.php}}
tools: phpunit:${{matrix.phpunit}}
extensions: mysqli
- name: Setup Node.js
uses: actions/setup-node@v2-beta
with:
node-version: '14'
- name: Install PNPM and install dependencies
uses: pnpm/action-setup@v2.2.1
with:
version: ^6.24.2
run_install: true
- name: Set up the tests
env:
WP_VERSION: ${{matrix.wordpress}}
WC_VERSION: ${{matrix.woocommerce}}
PHP_UNIT: ${{matrix.phpunit}}
COMPOSER_VERSION: ${{matrix.composer}}
run: |
sudo /etc/init.d/mysql start
bash bin/ci/gh-install-wp-tests.sh wc_admin_test root 'root' localhost
cd "$WP_CORE_DIR/wp-content/plugins/woocommerce-admin/"
pnpm run build:feature-config
composer install
node --version
pnpm --version
timedatectl
- name: Add PHP8 Compatibility.
run: |
if [ "$(php -r "echo version_compare(PHP_VERSION,'8.0','>=');")" ]; then
cd "$WP_CORE_DIR/wp-content/plugins/woocommerce-admin/"
composer install
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
unzip -d /tmp/phpunit-7.5-fork /tmp/phpunit-7.5-fork.zip
composer bin phpunit config --unset platform
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
rm -rf ./vendor/phpunit/
composer dump-autoload
fi
- name: Run the PHP unit tests
run: bin/phpunit.sh
shell: bash

View File

@ -1,120 +1,13 @@
# WooCommerce Admin
This is a feature plugin for a modern, javascript-driven WooCommerce Admin experience.
## Prerequisites
[WordPress 5.6 or greater](https://wordpress.org/download/) and [WooCommerce 5.7.0 or greater](https://wordpress.org/plugins/woocommerce/) should be installed prior to activating the WooCommerce Admin feature plugin.
For better debugging, it's also recommended you add `define( 'SCRIPT_DEBUG', true );` to your wp-config. This will load the unminified version of all libraries, and specifically the development build of React.
This is a javascript-driven, React-based admin interface for WooCommerce.
## Development
After cloning the repo, install dependencies:
- `pnpm install` to install JavaScript dependencies.
- `composer install` to gather PHP dependencies.
Now you can build the files using one of these commands:
- `pnpm run build` : Build a production version
- `pnpm run dev` : Build a development version
- `pnpm start` : Build a development version, watch files for changes
- `pnpm run build:release` : Build a WordPress plugin ZIP file (`woocommerce-admin.zip` will be created in the repository root)
- `DRY_RUN=1 pnpm run build:release` : Builds a Wordpress plugin ZIP **without** pushing it to Github and creating a release.
For more helper scripts [see here](./CONTRIBUTING.md#helper-scripts)
For some debugging tools/help [see here](./CONTRIBUTING.md#debugging)
For local development setup using Docker [see here](./docker/wc-admin-wp-env/README.md)
### Typescript
The `npm run ts:check` command will check your TypeScript files for errors, and has been added to `.vscode/tasks.json`.
Running this task in vscode will highlight the errors in your editor file navigator.
If you allow the `npm run ts:check:watch` command to run automatically as configured, it will run in the background and pick up any errors as you save the files.
Note: Even if you don't run this task, the IDE uses its language server to pick up type errors in files that are open. This is only necessary for picking up errors
across the entire repository even when they haven't been opened in the IDE.
### Testing
#### End-to-end tests
Tests live in `./tests/e2e`. An existing build is required prior running, please refer to the section above for steps. E2E tests use the `@woocommerce/e2e-environment` package which hosts a Docker container for testing, by default the container can be accessed at `http://localhost:8084`
All the commands from `@woocommerce/e2e-environment` can be run through `pnpm exec`.
```
# Set up the e2e environment
pnpm i
pnpm exec wc-e2e docker:up
```
Run tests using:
```
pnpm exec wc-e2e test:e2e-dev
```
or in headless mode:
```
pnpm exec wc-e2e test:e2e
```
Run a single test by adding the path to the file name:
```
pnpm exec wc-e2e test:e2e-dev tests/e2e/specs/activate-and-setup/complete-onboarding-wizard.test.ts
```
### Documentation
There is documentation in 2 forms available in the repo. A static set of documentation supported by docsify and also a Storybook containing component documentation for `@woocommerce/components`.
To view the docsify docs locally you can do:
```
pnpm install
cd docs
pnpm exec docsify serve
```
When deployed the docsify docs also host an embedded version of the storybook docs. To generate that and test it locally in docsify you'll need to run:
```
pnpm install
pnpm run docs
cd docs
pnpm exec docsify serve
```
Then navigate to `Components` from the left hand menu in the docs.
If you would like to view the storybook docs hosted standalone, then you can run:
```
pnpm install
pnpm run storybook
```
If you would like to view the storybook docs in right-to-left styling, you can run this instead:
```
pnpm install
pnpm run storybook-rtl
```
Please refer to the [WooCommerce Admin Development](https://github.com/woocommerce/woocommerce/wiki/How-to-set-up-WooCommerce-development-environment#wooCommerce-admin-development)
## End-to-end tests
Please refer to the [WooCommerce End to End Tests](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md)
## Common Issues
If you're encountering any issue setting things up, chances are we have been there too. Please have a look at our [wiki](https://github.com/woocommerce/woocommerce-admin/wiki/Common-Issues) for a list of common problems.
## Privacy
If you have enabled WooCommerce usage tracking ( option `woocommerce_allow_tracking` ) then, in addition to the tracking described in https://woocommerce.com/usage-tracking/, this plugin also sends information about the actions that site administrators perform to Automattic - see https://automattic.com/privacy/#information-we-collect-automatically for more information.
## Contributing
There are many ways to contribute reporting bugs, adding translations, feature suggestions and fixing bugs. For full details, please see [CONTRIBUTING.md](./CONTRIBUTING.md)
If you're encountering any issue setting things up, chances are we have been there too. Please have a look at our [wiki](https://github.com/woocommerce/woocommerce/wiki/Common-Issues) for a list of common problems.

View File

@ -5,12 +5,12 @@ Scaffold a modern JavaScript WordPress plugin with WooCommerce tooling.
## Includes
- [wp-scripts](https://github.com/WordPress/gutenberg/tree/master/packages/scripts)
- [WooCommerce Dependency Extraction Webpack Plugin](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/dependency-extraction-webpack-plugin)
- [WooCommerce ESLint Plugin with WordPress Prettier](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/eslint-plugin)
- [WooCommerce Dependency Extraction Webpack Plugin](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/dependency-extraction-webpack-plugin)
- [WooCommerce ESLint Plugin with WordPress Prettier](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/eslint-plugin)
### Usage
At the root of a [WooCommerce Admin](https://github.com/woocommerce/woocommerce-admin) installation, run the create extension command.
At the root of a [WooCommerce Admin](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-admin) installation, run the create extension command.
```
pnpm run create-wc-extension

View File

@ -2,13 +2,13 @@
* External dependencies
*/
import { __ } from '@wordpress/i18n';
import { COUNTRIES_STORE_NAME, Country } from '@woocommerce/data';
import { COUNTRIES_STORE_NAME, Country, Locale } from '@woocommerce/data';
import { decodeEntities } from '@wordpress/html-entities';
import { escapeRegExp } from 'lodash';
import { escapeRegExp, has } from 'lodash';
import { useEffect, useMemo, useState, useRef } from '@wordpress/element';
import { SelectControl, TextControl } from '@woocommerce/components';
import { Spinner } from '@wordpress/components';
import { useSelect } from '@wordpress/data';
import { useSelect, select as wpDataSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -21,10 +21,24 @@ const storeAddressFields = [
'city',
'countryState',
'postCode',
];
] as const;
type Option = { key: string; label: string };
/**
* Type guard to ensure that the specified locale object has a .required property
*
* @param fieldName field of Locale
* @param locale unknown object to be checked
* @return Boolean indicating if locale has a .required property
*/
const isLocaleRecord = (
fieldName: keyof Locale,
locale: unknown
): locale is Record< keyof Locale, { required: boolean } > => {
return !! locale && has( locale, `${ fieldName }.required` );
};
/**
* Check if a given address field is required for the locale.
*
@ -33,11 +47,11 @@ type Option = { key: string; label: string };
* @return {boolean} Field requirement.
*/
export function isAddressFieldRequired(
fieldName: string,
locale: unknown = {}
fieldName: keyof Locale,
locale: Locale = {}
): boolean {
if ( locale[ fieldName ]?.hasOwnProperty( 'required' ) ) {
return locale[ fieldName ]?.required as boolean;
if ( isLocaleRecord( fieldName, locale ) ) {
return locale[ fieldName ].required;
}
if ( fieldName === 'address_2' ) {
@ -53,18 +67,19 @@ export function isAddressFieldRequired(
* @param {Object} locale The store locale.
* @return {Function} Validator function.
*/
export function getStoreAddressValidator( locale = {} ) {
export function getStoreAddressValidator( locale: Locale = {} ) {
/**
* Form validator.
*
* @param {Object} values Keyed values of all fields in the form.
* @return {Object} Key value of fields and error messages, { myField: 'This field is required' }
*/
return ( values ) => {
return (
values: Record< typeof storeAddressFields[ number ], string >
) => {
const errors: {
[ key: string ]: string;
} = {};
if (
isAddressFieldRequired( 'address_1', locale ) &&
! values.addressLine1.trim().length
@ -100,30 +115,33 @@ export function getStoreAddressValidator( locale = {} ) {
* @return {Object} Select options, { value: 'US:GA', label: 'United States - Georgia' }
*/
export function getCountryStateOptions( countries: Country[] ) {
const countryStateOptions = countries.reduce( ( acc, country ) => {
if ( ! country.states.length ) {
acc.push( {
key: country.code,
label: decodeEntities( country.name ),
const countryStateOptions = countries.reduce(
( acc: Option[], country ) => {
if ( ! country.states.length ) {
acc.push( {
key: country.code,
label: decodeEntities( country.name ),
} );
return acc;
}
const countryStates = country.states.map( ( state ) => {
return {
key: country.code + ':' + state.code,
label:
decodeEntities( country.name ) +
' — ' +
decodeEntities( state.name ),
};
} );
acc.push( ...countryStates );
return acc;
}
const countryStates = country.states.map( ( state ) => {
return {
key: country.code + ':' + state.code,
label:
decodeEntities( country.name ) +
' — ' +
decodeEntities( state.name ),
};
} );
acc.push( ...countryStates );
return acc;
}, [] );
},
[]
);
return countryStateOptions;
}
@ -195,9 +213,7 @@ export function useGetCountryStateAutofill(
): JSX.Element {
const [ autofillCountry, setAutofillCountry ] = useState( '' );
const [ autofillState, setAutofillState ] = useState( '' );
const isAutofillChange: {
current: boolean;
} = useRef();
const isAutofillChange = useRef< boolean >();
// Sync the autofill fields on first render and the countryState value changes.
useEffect( () => {
@ -242,7 +258,7 @@ export function useGetCountryStateAutofill(
const isCountryAbbreviation = autofillCountry.length < 3;
const isStateAbbreviation =
autofillState.length < 3 && !! autofillState.match( /^[\w]+$/ );
let filteredOptions = [];
let filteredOptions: Option[] = [];
if ( autofillCountry.length && autofillState.length ) {
filteredOptions = options.filter( ( option ) =>
@ -337,7 +353,7 @@ export function StoreAddress( {
hasFinishedResolution,
countries,
loadingCountries,
} = useSelect( ( select ) => {
} = useSelect( ( select: typeof wpDataSelect ) => {
const {
getLocale,
getCountries,

View File

@ -7,7 +7,11 @@ import { render, fireEvent } from '@testing-library/react';
/**
* Internal dependencies
*/
import { useGetCountryStateAutofill, getStateFilter } from '../store-address';
import {
isAddressFieldRequired,
useGetCountryStateAutofill,
getStateFilter,
} from '../store-address';
const AutofillWrapper = ( { options, value, onChange } ) => {
const [ values, setValues ] = useState( { countryState: value || '' } );
@ -211,3 +215,28 @@ describe( 'getStateFilter', () => {
}
);
} );
describe( 'isAddressFieldRequired', () => {
it( 'should return true if fieldName is not a key in locale', () => {
expect( isAddressFieldRequired( 'address_1', { foo: 'bar' } ) ).toBe(
true
);
} );
it( 'should return true if locale object marks it as required', () => {
expect(
isAddressFieldRequired( 'address_1', {
address_1: { required: true },
} )
).toBe( true );
} );
it( 'should return false if locale object marks it as not required', () => {
expect(
isAddressFieldRequired( 'address_1', {
address_1: { required: false },
} )
).toBe( false );
} );
it( 'should return false if fieldName is address_2', () => {
expect( isAddressFieldRequired( 'address_2', {} ) ).toBe( false );
} );
} );

View File

@ -6,7 +6,9 @@ import { useEffect, useLayoutEffect, useRef } from '@wordpress/element';
import classnames from 'classnames';
import { decodeEntities } from '@wordpress/html-entities';
import { getSetting } from '@woocommerce/settings';
import { ONBOARDING_STORE_NAME } from '@woocommerce/data';
import { Text, useSlot } from '@woocommerce/experimental';
import { useSelect } from '@wordpress/data';
/**
* Internal dependencies
@ -93,12 +95,18 @@ export const Header = ( { sections, isEmbedded = false, query } ) => {
}
}, [ isEmbedded, sections, siteTitle ] );
const tasksReminderFeature =
window.wcAdminFeatures[ 'tasklist-setup-experiment-1' ];
const { hasTasksReminderFeature } = useSelect( ( select ) => {
const taskLists = select( ONBOARDING_STORE_NAME ).getTaskLists();
return {
hasTasksReminderFeature: taskLists.some(
( list ) => list.id === 'setup_experiment_1'
),
};
} );
return (
<div className={ className } ref={ headerElement }>
{ tasksReminderFeature && (
{ hasTasksReminderFeature && (
<TasksReminderBar
pageTitle={ pageTitle }
updateBodyMargin={ updateBodyMargin }

View File

@ -49,5 +49,6 @@ $progress-complete-color: #007cba;
.woocommerce-card__menu {
position: absolute;
right: 0;
top: 7px;
}
}

View File

@ -76,7 +76,7 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
return __( 'You are almost there', 'woocommerce' );
}, [ completedCount, hasVisitedTasks ] );
if ( loading || completedCount === tasksCount ) {
if ( loading ) {
return null;
}
@ -90,22 +90,26 @@ export const ProgressHeader: React.FC< ProgressHeaderProps > = ( {
<h1 className="woocommerce-task-progress-header__title">
{ progressTitle }
</h1>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
{ completedCount !== tasksCount ? (
<>
<p>
{ sprintf(
/* translators: 1: completed tasks, 2: total tasks */
__(
'Follow these steps to start selling quickly. %1$d out of %2$d complete.',
'woocommerce'
),
completedCount,
tasksCount
) }
</p>
<progress
className="woocommerce-task-progress-header__progress-bar"
max={ tasksCount }
value={ completedCount || 0 }
/>
</>
) : null }
</div>
</div>
);

View File

@ -25,6 +25,7 @@ export const Action = ( {
onSetUp = () => {},
onSetupCallback,
setupButtonText = __( 'Get started', 'woocommerce' ),
externalLink = null,
} ) => {
const [ isBusy, setIsBusy ] = useState( false );
@ -41,6 +42,11 @@ export const Action = ( {
selected: getPluginTrackKey( id ),
} );
if ( ! hasPlugins && externalLink ) {
window.location.href = externalLink;
return;
}
if ( onSetupCallback ) {
setIsBusy( true );
await new Promise( onSetupCallback )
@ -84,17 +90,19 @@ export const Action = ( {
</Button>
);
const EnableButton = () => (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
if ( ! hasSetup ) {
if ( ! isEnabled ) {
return (
<Button
className={ classes }
isSecondary
onClick={ () => markConfigured( id ) }
>
{ __( 'Enable', 'woocommerce' ) }
</Button>
);
return <EnableButton />;
}
return <ManageButton />;
@ -110,6 +118,10 @@ export const Action = ( {
}
if ( ! needsSetup ) {
if ( ! isEnabled ) {
return <EnableButton />;
}
return <ManageButton />;
}

View File

@ -4,8 +4,10 @@
import classnames from 'classnames';
import { Fragment } from '@wordpress/element';
import { CardBody, CardMedia, CardDivider } from '@wordpress/components';
import { RecommendedRibbon, SetupRequired } from '@woocommerce/onboarding';
import { SetupRequired } from '@woocommerce/onboarding';
import { Pill } from '@woocommerce/components';
import { Text, useSlot } from '@woocommerce/experimental';
import { __ } from '@wordpress/i18n';
/**
* Internal dependencies
@ -15,7 +17,7 @@ import './List.scss';
export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
const {
image,
image_72x72: image72x72,
content,
id,
plugins = [],
@ -27,6 +29,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
requiredSettings,
settingsUrl: manageUrl,
is_local_partner: isLocalPartner,
external_link: externalLink,
} = paymentGateway;
const connectSlot = useSlot(
@ -39,9 +42,9 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
Boolean( setupSlot?.fills?.length );
const hasSetup = Boolean(
plugins.length || requiredSettings.length || hasFills
plugins.length || requiredSettings.length || hasFills || externalLink
);
const showRecommendedRibbon = isRecommended && needsSetup;
const showRecommended = isRecommended && needsSetup;
const classes = classnames(
'woocommerce-task-payment',
@ -57,14 +60,20 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
className={ classes }
>
<CardMedia isBorderless>
<img src={ image } alt={ title } />
<img src={ image72x72 } alt={ title } />
</CardMedia>
<div className="woocommerce-task-payment__description">
{ showRecommendedRibbon && (
<RecommendedRibbon isLocalPartner={ isLocalPartner } />
) }
<Text as="h3" className="woocommerce-task-payment__title">
{ title }
<span>{ title }</span>
{ showRecommended && (
<Pill
className={ ! isLocalPartner && 'pill-green' }
>
{ isLocalPartner
? __( 'Local Partner', 'woocommerce' )
: __( 'Recommended', 'woocommerce' ) }
</Pill>
) }
{ isInstalled && needsSetup && !! plugins.length && (
<SetupRequired />
) }
@ -85,6 +94,7 @@ export const Item = ( { isRecommended, markConfigured, paymentGateway } ) => {
isRecommended={ isRecommended }
isLoading={ loading }
markConfigured={ markConfigured }
externalLink={ externalLink }
/>
</div>
</CardBody>

View File

@ -42,6 +42,15 @@
color: $studio-gray-80;
margin-top: 0;
margin-bottom: $gap-smaller;
.woocommerce-pill {
margin-left: 8px;
&.pill-green {
color: #008a20;
border-color: #008a20;
}
}
}
.woocommerce-task-payment__content {

View File

@ -138,7 +138,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
expect( queryByText( 'Recommended' ) ).not.toBeInTheDocument();
} );
it( 'should display Manage button if not enabled and does have setup', () => {
it( 'should display Manage button if enabled and does have setup', () => {
const props = {
...defaultProps,
paymentGateways: [
@ -180,6 +180,7 @@ describe( 'PaymentGatewaySuggestions > List', () => {
...mockGateway,
plugins: [ 'nope' ],
needsSetup: false,
enabled: true,
},
],
};

View File

@ -7,12 +7,14 @@ import {
OPTIONS_STORE_NAME,
ONBOARDING_STORE_NAME,
PAYMENT_GATEWAYS_STORE_NAME,
SETTINGS_STORE_NAME,
} from '@woocommerce/data';
import { recordEvent } from '@woocommerce/tracks';
import { useMemo, useCallback, useEffect } from '@wordpress/element';
import { registerPlugin } from '@wordpress/plugins';
import { WooOnboardingTask } from '@woocommerce/onboarding';
import { getNewPath } from '@woocommerce/navigation';
import { getAdminLink } from '@woocommerce/settings';
import { Button } from '@wordpress/components';
import ExternalIcon from 'gridicons/dist/external';
@ -24,15 +26,25 @@ import { Setup, Placeholder as SetupPlaceholder } from './components/Setup';
import { Toggle } from './components/Toggle/Toggle';
import { WCPaySuggestion } from './components/WCPay';
import { getPluginSlug } from '~/utils';
import { getCountryCode } from '~/dashboard/utils';
import './plugins/Bacs';
import './payment-gateway-suggestions.scss';
const SEE_MORE_LINK =
'https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations';
const comparePaymentGatewaysByPriority = ( a, b ) =>
a.recommendation_priority - b.recommendation_priority;
const isGatewayWCPay = ( gateway ) =>
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments';
const isGatewayOtherCategory = ( gateway, countryCode ) =>
gateway.category_other &&
gateway.category_other.indexOf( countryCode ) !== -1;
const isGatewayAdditionalCategory = ( gateway, countryCode ) =>
gateway.category_additional &&
gateway.category_additional.indexOf( countryCode ) !== -1;
export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
const { updatePaymentGateway } = useDispatch( PAYMENT_GATEWAYS_STORE_NAME );
const {
@ -40,7 +52,10 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions,
installedPaymentGateways,
isResolving,
countryCode,
} = useSelect( ( select ) => {
const { getSettings } = select( SETTINGS_STORE_NAME );
const { general: settings = {} } = getSettings( 'general' );
return {
getPaymentGateway: select( PAYMENT_GATEWAYS_STORE_NAME )
.getPaymentGateway,
@ -54,6 +69,7 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
paymentGatewaySuggestions: select(
ONBOARDING_STORE_NAME
).getPaymentGatewaySuggestions(),
countryCode: getCountryCode( settings.woocommerce_default_country ),
};
}, [] );
@ -185,6 +201,27 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
return gateway;
}, [ isResolving, query, paymentGateways ] );
const isWCPayOrOtherCategoryDoneSetup = useMemo( () => {
for ( const [ , gateway ] of paymentGateways.entries() ) {
if ( ! gateway.installed || gateway.needsSetup ) {
continue;
}
if ( isGatewayWCPay( gateway ) ) {
return true;
}
if ( isGatewayOtherCategory( gateway, countryCode ) ) {
return true;
}
}
return false;
}, [ countryCode, paymentGateways ] );
const isWCPaySupported =
Array.from( paymentGateways.values() ).findIndex( isGatewayWCPay ) !==
-1;
const [ wcPayGateway, offlineGateways, additionalGateways ] = useMemo(
() =>
Array.from( paymentGateways.values() )
@ -206,14 +243,32 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
// WCPay is handled separately when not installed and configured
if (
gateway.plugins?.length === 1 &&
gateway.plugins[ 0 ] === 'woocommerce-payments' &&
isGatewayWCPay( gateway ) &&
! ( gateway.installed && ! gateway.needsSetup )
) {
wcPay.push( gateway );
} else if ( gateway.is_offline ) {
offline.push( gateway );
} else {
} else if ( gateway.enabled ) {
// Enabled gateways should be ignored.
} else if ( isWCPayOrOtherCategoryDoneSetup ) {
// If WCPay or "other" gateway is enabled in an WCPay-eligible country, only
// allow to list "additional" gateways.
if (
isGatewayAdditionalCategory(
gateway,
countryCode
)
) {
additional.push( gateway );
}
} else if ( ! isWCPaySupported ) {
// When WCPay-ineligible, just show all gateways.
additional.push( gateway );
} else if (
isGatewayOtherCategory( gateway, countryCode )
) {
// When nothing is set up and eligible for WCPay, only show "other" gateways.
additional.push( gateway );
}
@ -221,11 +276,14 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
},
[ [], [], [] ]
),
[ paymentGateways ]
[
countryCode,
isWCPaySupported,
isWCPayOrOtherCategoryDoneSetup,
paymentGateways,
]
);
const isEligibleWCPay = !! wcPayGateway.length;
const trackSeeMore = () => {
recordEvent( 'tasklist_payment_see_more', {} );
};
@ -254,23 +312,26 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
const additionalSection = !! additionalGateways.length && (
<List
heading={
isEligibleWCPay
? null
: __( 'Choose a payment provider', 'woocommerce' )
! wcPayGateway.length &&
__( 'Choose a payment provider', 'woocommerce' )
}
recommendation={ recommendation }
paymentGateways={ additionalGateways }
markConfigured={ markConfigured }
footerLink={
<Button
href={ SEE_MORE_LINK }
target="_blank"
onClick={ trackSeeMore }
isTertiary
>
{ __( 'See more', 'woocommerce' ) }
<ExternalIcon size={ 18 } />
</Button>
! isWCPayOrOtherCategoryDoneSetup && (
<Button
href={ getAdminLink(
'admin.php?page=wc-addons&section=payment-gateways'
) }
target="_blank"
onClick={ trackSeeMore }
isTertiary
>
{ __( 'See more', 'woocommerce' ) }
<ExternalIcon size={ 18 } />
</Button>
)
}
></List>
);
@ -288,7 +349,7 @@ export const PaymentGatewaySuggestions = ( { onComplete, query } ) => {
<div className="woocommerce-task-payments">
{ ! paymentGateways.size && <ListPlaceholder /> }
{ isEligibleWCPay ? (
{ wcPayGateway.length ? (
<>
<WCPaySuggestion paymentGateway={ wcPayGateway[ 0 ] } />
<Toggle

View File

@ -46,6 +46,10 @@
.components-card__divider:last-child {
display: none;
}
.woocommerce-task-payment-wcpay {
margin-bottom: 0;
}
}
// @todo This can be migrated into the PaymentMethod component once the payment-gateway-suggestions feature is enabled.

View File

@ -31,6 +31,8 @@ const paymentGatewaySuggestions = [
plugins: [ 'woocommerce-gateway-stripe' ],
is_visible: true,
recommendation_priority: 3,
category_other: [ 'US' ],
category_additional: [],
},
{
id: 'ppcp-gateway',
@ -41,6 +43,8 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce/assets/images/paypal.png',
plugins: [ 'woocommerce-paypal-payments' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
{
id: 'cod',
@ -82,6 +86,8 @@ const paymentGatewaySuggestions = [
'http://localhost:8888/wp-content/plugins/woocommerce-admin/images/onboarding/eway.png',
plugins: [ 'woocommerce-gateway-eway' ],
is_visible: true,
category_other: [ 'US' ],
category_additional: [ 'US' ],
},
];
@ -140,7 +146,7 @@ describe( 'PaymentGatewaySuggestions', () => {
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title'
'.woocommerce-task-payment__title > span:first-child'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
@ -212,6 +218,49 @@ describe( 'PaymentGatewaySuggestions', () => {
expect( getByText( 'Finish setup' ) ).toBeInTheDocument();
} );
test( 'should show "category_additional" gateways only after WCPay is set up', () => {
const onComplete = jest.fn();
const query = {};
useSelect.mockImplementation( () => ( {
isResolving: false,
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [
{
id: 'woocommerce_payments',
title: 'WooCommerce Payments',
plugins: [ 'woocommerce-payments' ],
is_visible: true,
needs_setup: false,
},
],
countryCode: 'US',
} ) );
const { container } = render(
<PaymentGatewaySuggestions
onComplete={ onComplete }
query={ query }
/>
);
const paymentTitleElements = container.querySelectorAll(
'.woocommerce-task-payment__title'
);
const paymentTitles = Array.from( paymentTitleElements ).map(
( e ) => e.textContent
);
expect( paymentTitles ).toEqual( [
'PayPal Payments',
'Eway',
'Cash on delivery',
'Direct bank transfer',
] );
} );
test( 'should record event correctly when finish setup is clicked', () => {
const onComplete = jest.fn();
const query = {};
@ -254,6 +303,7 @@ describe( 'PaymentGatewaySuggestions', () => {
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
@ -266,13 +316,16 @@ describe( 'PaymentGatewaySuggestions', () => {
fireEvent.click( screen.getByText( 'Other payment methods' ) );
// By default it's hidden, so when toggle it shows.
expect( recordEvent ).toHaveBeenCalledWith(
// Second call after "tasklist_payments_options".
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [
'tasklist_payment_show_toggle',
{
toggle: 'show',
payment_method_count: paymentGatewaySuggestions.length - 1, // Minus one for WCPay since it's not counted in "other payment methods".
}
);
},
] );
} );
test( 'should record event correctly when see more is clicked', () => {
@ -283,6 +336,7 @@ describe( 'PaymentGatewaySuggestions', () => {
getPaymentGateway: jest.fn(),
paymentGatewaySuggestions,
installedPaymentGateways: [],
countryCode: 'US',
} ) );
render(
@ -294,10 +348,8 @@ describe( 'PaymentGatewaySuggestions', () => {
fireEvent.click( screen.getByText( 'Other payment methods' ) );
fireEvent.click( screen.getByText( 'See more' ) );
expect( recordEvent ).toHaveBeenCalledWith(
'tasklist_payment_see_more',
{}
);
expect(
recordEvent.mock.calls[ recordEvent.mock.calls.length - 1 ]
).toEqual( [ 'tasklist_payment_see_more', {} ] );
} );
} );

View File

@ -14,6 +14,7 @@ import { getAdminLink } from '@woocommerce/settings';
import { close as closeIcon } from '@wordpress/icons';
import interpolateComponents from '@automattic/interpolate-components';
import { useEffect } from '@wordpress/element';
import { getQuery } from '@woocommerce/navigation';
/**
* Internal dependencies
@ -27,7 +28,7 @@ type ReminderBarProps = {
};
type ReminderTextProps = {
remainingCount: number;
remainingCount: number | null;
};
const REMINDER_BAR_HIDDEN_OPTION = 'woocommerce_task_list_reminder_bar_hidden';
@ -66,7 +67,6 @@ const ReminderText: React.FC< ReminderTextProps > = ( { remainingCount } ) => {
export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
taskListId = 'setup_experiment_1',
pageTitle,
updateBodyMargin,
} ) => {
const { updateOptions } = useDispatch( OPTIONS_STORE_NAME );
@ -119,13 +119,18 @@ export const TasksReminderBar: React.FC< ReminderBarProps > = ( {
};
} );
const isHomescreen =
getQuery().page && getQuery().page === 'wc-admin' && ! getQuery().path;
const isActiveTaskPage = Boolean( getQuery().wc_onboarding_active_task );
const hideReminderBar =
loading ||
taskListHidden ||
taskListComplete ||
reminderBarHidden ||
completedTasksCount === 0 ||
[ 'Home', 'Shipping', 'Tax', 'Payments' ].includes( pageTitle );
isHomescreen ||
isActiveTaskPage;
useEffect( () => {
updateBodyMargin();

View File

@ -23,6 +23,7 @@ import { SectionedTaskList } from '../two-column-tasks/sectioned-task-list';
import TwoColumnTaskListPlaceholder from '../two-column-tasks/placeholder';
import '../two-column-tasks/style.scss';
import { getAdminSetting } from '~/utils/admin-settings';
import { SectionedTaskListPlaceholder } from '~/two-column-tasks/sectioned-task-list-placeholder';
export type TasksProps = {
query: { task?: string };
@ -45,6 +46,8 @@ function getTaskListPlaceholderComponent(
switch ( taskListId ) {
case 'setup_experiment_1':
return TwoColumnTaskListPlaceholder;
case 'setup_experiment_2':
return SectionedTaskListPlaceholder;
default:
return TasksPlaceholder;
}

View File

@ -0,0 +1,75 @@
/**
* Internal dependencies
*/
import './style.scss';
type TasksPlaceholderProps = {
numTasks?: number;
query: {
task?: string;
};
};
const SectionedTaskListPlaceholder: React.FC< TasksPlaceholderProps > = (
props
) => {
const { numTasks = 3 } = props;
return (
<div
className={
'woocommerce-task-dashboard__container woocommerce-sectioned-task-list'
}
>
<div className="components-card is-size-large woocommerce-task-card woocommerce-homescreen-card is-loading ">
<div className="components-card__header is-size-medium">
<div className="wooocommerce-task-card__header">
<div className="is-placeholder"> </div>
</div>
</div>
<ul className="woocommerce-experimental-list">
{ Array.from( new Array( numTasks ) ).map( ( v, i ) => (
<li
tabIndex={ i }
key={ i }
className="woocommerce-experimental-list__item woocommerce-task-list__item"
>
<div className="woocommerce-task-list__item-before">
<div className="is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
</li>
) ) }
</ul>
</div>
<div className="is-loading components-panel__body woocommerce-task-card">
<div className="components-panel__body-title">
<div className="components-button components-panel__body-toggle">
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-after">
<div className="is-placeholder"></div>
</div>
</div>
</div>
</div>
<div className="is-loading components-panel__body woocommerce-task-card">
<div className="components-panel__body-title">
<div className="components-button components-panel__body-toggle">
<div className="woocommerce-task-list__item-text">
<div className="components-truncate components-text is-placeholder"></div>
</div>
<div className="woocommerce-task-list__item-after">
<div className="is-placeholder"></div>
</div>
</div>
</div>
</div>
</div>
);
};
export { SectionedTaskListPlaceholder };

View File

@ -63,7 +63,9 @@
pointer-events: none;
}
&:not(.is-complete) .woocommerce-task-list__item-before .woocommerce-task__icon {
&:not(.is-complete)
.woocommerce-task-list__item-before
.woocommerce-task__icon {
border-color: $gray-300;
}
}
@ -89,4 +91,31 @@
}
}
}
> .is-loading {
border: none;
margin-bottom: 8px;
.woocommerce-task-list__item .woocommerce-task-list__item-before {
padding: 0 0 0 $gap-large;
}
&.components-panel__body .components-panel__body-title .woocommerce-task-list__item-text {
width: 50%;
.is-placeholder {
width: 100%;
}
}
&.components-panel__body .woocommerce-task-list__item-after {
margin-left: $gap;
.is-placeholder {
height: 24px;
width: 24px;
border-radius: 50%;
}
}
}
}

View File

@ -35,7 +35,7 @@ const PanelBodyWithUpdatedType = PanelBody as React.ComponentType< PanelBodyProp
export const SectionedTaskList: React.FC< TaskListProps > = ( {
query,
id,
eventName,
eventPrefix,
tasks,
keepCompletedTaskList,
isComplete,
@ -66,7 +66,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
return;
}
recordEvent( `${ eventName }_view`, {
recordEvent( `${ eventPrefix }view`, {
number_tasks: visibleTasks.length,
store_connected: profileItems.wccom_connected,
} );
@ -122,7 +122,7 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
}
const trackClick = ( task: TaskType ) => {
recordEvent( `${ eventName }_click`, {
recordEvent( `${ eventPrefix }_click`, {
task_name: task.id,
} );
};
@ -182,10 +182,34 @@ export const SectionedTaskList: React.FC< TaskListProps > = ( {
opened={ openPanel === section.id }
onToggle={ ( isOpen: boolean ) => {
if ( ! isOpen && openPanel === section.id ) {
recordEvent(
`${ eventPrefix }section_closed`,
{
id: section.id,
all: true,
}
);
setOpenPanel( null );
} else {
if ( openPanel ) {
recordEvent(
`${ eventPrefix }section_closed`,
{
id: openPanel,
all: false,
}
);
}
setOpenPanel( section.id );
}
if ( isOpen ) {
recordEvent(
`${ eventPrefix }section_opened`,
{
id: section.id,
}
);
}
} }
initialOpen={ false }
>

View File

@ -1,35 +1,9 @@
# WooCommerce Admin
This is a feature plugin for a modern, javascript-driven WooCommerce Admin experience.
## Prerequisites
[WordPress 5.4 or greater](https://wordpress.org/download/) and [WooCommerce 4.8.0 or greater](https://wordpress.org/plugins/woocommerce/) should be installed prior to activating the WooCommerce Admin feature plugin.
For better debugging, it's also recommended you add `define( 'SCRIPT_DEBUG', true );` to your wp-config. This will load the unminified version of all libraries, and specifically the development build of React.
## Development
After cloning the repo, install dependencies:
- `pnpm install` to install JavaScript dependencies.
- `composer install` to gather PHP dependencies.
Now you can build the files using one of these commands:
- `pnpm run build` : Build a production version
- `pnpm run dev` : Build a development version
- `pnpm start` : Build a development version, watch files for changes
- `pnpm run build:release` : Build a WordPress plugin ZIP file (`woocommerce-admin.zip` will be created in the repository root)
For more helper scripts [see here](./CONTRIBUTING.md#helper-scripts)
For some debugging tools/help [see here](./CONTRIBUTING.md#debugging)
## Privacy
If you have enabled WooCommerce usage tracking ( option `woocommerce_allow_tracking` ) then, in addition to the tracking described in https://woocommerce.com/usage-tracking/, this plugin also sends information about the actions that site administrators perform to Automattic - see https://automattic.com/privacy/#information-we-collect-automatically for more information.
## Contributing
There are many ways to contribute reporting bugs, adding translations, feature suggestions and fixing bugs. For full details, please see [CONTRIBUTING.md](./CONTRIBUTING.md)
- [CSS Structure](stylesheets.md)
- [Data](data.md)
- [Examples](examples/)
- [Features](features/)
- [Layout](layout.md)
- [Page Controller](page-controller.md)
- [woocommerce.com](woocommerce.com/)

View File

@ -1,7 +0,0 @@
- [Overview](/)
- [Components](components/)
- [Features](features/)
- [Data](data)
- [Layout](layout)
- [CSS Structure](stylesheets)
- [Examples](examples/)

View File

@ -1 +0,0 @@
[storybook](storybook/index.html ':include :type=iframe width=100% height=100%')

View File

@ -1,7 +1,7 @@
Data
====
WooCommerce Admin data stores implement the [`SqlQuery` class](https://github.com/woocommerce/woocommerce-admin/blob/main/src/API/Reports/SqlQuery.php).
WooCommerce Admin data stores implement the [`SqlQuery` class](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Admin/API/Reports/SqlQuery.php).
### SqlQuery Class
@ -81,4 +81,4 @@ function my_custom_product_stats( $clauses ) {
$clauses[] = ', SUM( sample_column ) as sample_total';
return $clauses;
}
```
```

View File

@ -1,5 +0,0 @@
* [Home](/)
* [Examples](examples/)
* [Activity Panel Inbox](examples/activity-panel-inbox.md)

View File

@ -13,10 +13,10 @@ pnpm install
Build the example extension by running the pnpm script and passing the example name.
```bash
pnpm run example -- --ext=<example>
WC_EXT=<example> pnpm nx example woocommerce-admin
```
Go to your WordPress installation's plugins page and activate the plugin. WooCommerce Analytics reports will now reflect the changes made by the example extension.
Include the output plugin in your `.wp-env.json` and `.wp-env.override.json` and restart the WordPress instance. WooCommerce Analytics reports will now reflect the changes made by the example extension.
You can make changes to Javascript and PHP files in the example and see changes reflected upon refresh.

View File

@ -10,13 +10,11 @@ const woocommerceAdminConfig = require( path.resolve(
) );
const MiniCssExtractPlugin = require( 'mini-css-extract-plugin' );
const extArg = process.argv.find( ( arg ) => arg.startsWith( '--ext=' ) );
if ( ! extArg ) {
if ( ! process.env.WC_EXT ) {
throw new Error( 'Please provide an extension.' );
}
const extension = extArg.slice( 6 );
const extension = process.env.WC_EXT;
const extensionPath = path.join( __dirname, `${ extension }/js/index.js` );
if ( ! fs.existsSync( extensionPath ) ) {
@ -33,7 +31,7 @@ const webpackConfig = {
output: {
filename: '[name]/dist/index.js',
path: path.resolve( __dirname ),
libraryTarget: 'this',
libraryTarget: 'window',
},
externals: woocommerceAdminConfig.externals,
module: {
@ -89,12 +87,17 @@ const webpackConfig = {
},
},
plugins: [
new CopyWebpackPlugin( [
{
from: path.join( __dirname, `${ extension }/` ),
to: path.resolve( __dirname, `../../../../${ extension }/` ),
},
] ),
new CopyWebpackPlugin( {
patterns: [
{
from: path.join( __dirname, `${ extension }/` ),
to: path.resolve(
__dirname,
`../../../../${ extension }/`
),
},
],
} ),
new MiniCssExtractPlugin( {
filename: '[name]/dist/style.css',
} ),

View File

@ -1,6 +0,0 @@
* [Home](/)
* [Features](features/)
* [Feature Flags](features/feature-flags.md)
* [Onboarding](features/onboarding.md)

View File

@ -1,14 +1,14 @@
# Feature Flags
Features inside the `woocommerce-admin` repository can be in various states of completeness. In addition to the development copy of `woocommerce-admin`, feature plugin versions are bundled, and code is merged to WooCommerce core. To provide a way for improved control over how these features are released in these different environments, `woocommerce-admin` has a system for feature flags.
Features inside the `woocommerce` repository can be in various states of completeness. To provide a way for improved control over how these features are released in these different environments, `woocommerce` has a system for feature flags.
We currently support the following environments:
| Environment | Description |
|-------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| development | Development - All features should be enabled in development. These flags are also used in both JS and PHP tests. Ran using `pnpm start`. |
| plugin | Plugin - A packaged release of the featured plugin, for GitHub WordPress.org. Ran using `pnpm run-script build:release`. | |
| core | Core - assets/files ready and stable enough for core merge. Ran using `pnpm pack`. (@todo update this with publish command).
| development | Development - All features should be enabled in development. These flags are also used in both JS and PHP tests. Ran using `pnpm start`. | |
| core | Core - assets/files ready and stable enough. Ran using `pnpm build` & `pnpm pack`.
## Adding a new flag
@ -16,16 +16,6 @@ We currently support the following environments:
Flags can be added to the files located in the `config/` directory. Make sure to add a flag for each environment and explicitly set the flag to false.
Please add new feature flags alphabetically so they are easy to find.
## Building custom plugin builds
Sometimes it is useful to create a test zip of a plugin, separate from the released WordPress.org version. This makes internal testing easier for non developers, removing the requirment of using Git and NPM commands. These releases are usually uploaded to GitHub releases as a pre release.
You can use the `build:release` command with the `--slug` and `--features` arguments to create a custom build. Base feature flags will be pulled from `config/plugin.json` and your additional changes are overlaid on top. When the build is complete, a `woocommerce-admin-$slug.zip` file will be generated.
For example, to create a `woocommerce-admin-onboarding.zip` build by enabling onboarding in addition to the feature flags defined in `config/plugin.json`, you would run:
`pnpm run build:release -- --slug onboarding --features '{"onboarding":true}'`.
## Basic Use - Client
The `window.wcAdminFeatures` constant is a global variable containing the feature flags.

View File

@ -8,9 +8,9 @@ This API will allow you to add in your own items to the navigation and register
This feature is hidden behind a feature flag and can be turned on or off by visiting WooCommerce -> Settngs -> Advanced -> Features and checking the box next to the `Navigation` option. It can also by controlled programmatically by setting the option `woocommerce_navigation_enable` to `yes` or `no`.
The fastest way to get started is by creating an example plugin from WooCommerce Admin. Inside your `woocommerce-admin` directory, enter the following command:
The fastest way to get started is by creating an example plugin from WooCommerce Admin. Enter the following command:
`pnpm run example -- --ext=add-navigation-items`
`WC_EXT=add-navigation-items pnpm nx example woocommerce-admin`
This will create a new plugin that covers various features of the navigation and helps to register some intial items and categories within the new navigation menu. After running the command above, you can make edits directly to the files at `docs/examples/extensions/add-navigation-items` and they will be built and copied to your `wp-content/add-navigation-items` folder on save.

View File

@ -35,7 +35,7 @@ To power the new onboarding flow client side, new REST API endpoints have been i
* `woocommerce_admin_onboarding_plugins_whitelist` filters the list of plugins that can installed & activated via onboarding. This acts as a whitelist so only certain plugins can be used via the `/wc-admin/onboarding/profile/install` and `/wc-admin/onboarding/profile/activate` endpoints.
* `woocommerce_admin_onboarding_themes` filters the themes displayed in the profile wizard.
* `woocommerce_admin_onboarding_jetpack_connect_redirect_url` filters the Jetpack connection redirect URL outlined in the Jetpack connection section below.
* `woocommerce_admin_onboarding_task_list` filters the list of tasks on the task list dashboard. This allows extensions to add new tasks. See [the extension docs](https://github.com/woocommerce/woocommerce-admin/tree/42015d17a919e8f9e54ba75869c50b04b8dc9241/docs/examples/extensions) for an example of how to do this.
* `woocommerce_admin_onboarding_task_list` filters the list of tasks on the task list dashboard. This allows extensions to add new tasks. See [the extension docs](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-admin/docs/examples/extensions) for an example of how to do this.
* `woocommerce_rest_onboarding_profile_collection_params` filters the collection parameters for requests to `/wc-admin/onboarding/profile`.
* `woocommerce_rest_onboarding_profile_object_query` filters the query arguments for requests to `/wc-admin/onboarding/profile`.
* `woocommerce_rest_onboarding_prepare_onboarding_profile` filters the response for requests to `/wc-admin/onboarding/profile`.
@ -48,7 +48,7 @@ A few new WordPress options have been introduced to store information and settin
* `woocommerce_task_list_hidden_lists`. This option houses the task lists that have been hidden from view by the user.
* `woocommerce_task_list_welcome_modal_dismissed`. This option is used to show a congratulations modal during the transition between the profile wizard and task list.
We also use existing options from WooCommerce Core or extensions like WooCommerce Shipping & Tax or Stripe. The list below may not be complete, as new tasks are introduced, but you can generally find usage of these by searching for the [getOptions selector](https://github.com/woocommerce/woocommerce-admin/search?q=getOptions&unscoped_q=getOptions).
We also use existing options from WooCommerce Core or extensions like WooCommerce Shipping & Tax or Stripe. The list below may not be complete, as new tasks are introduced, but you can generally find usage of these by searching for the [getOptions selector](https://github.com/woocommerce/woocommerce/search?q=getOptions&unscoped_q=getOptions).
* `woocommerce_setup_jetpack_opted_in` and `wc_connect_options` are both used to control Jetpack's Terms of Service opt-in, which is necessary to set for a user during the connection process, so that they can use services like automated tax rates.
* `woocommerce_allow_tracking` is used to control Tracks opt-in, allowing us to gather usage data from WooCommerce Admin and WooCommerce core.
@ -59,7 +59,7 @@ We also use existing options from WooCommerce Core or extensions like WooCommerc
During the profile wizard, merchants can select paid product type extensions (like WooCommerce Memberships) or a paid theme. To make installation easier and to finish purchasing, it is necessary to make a [WooCommerce.com connection](https://woocommerce.com/document/managing-woocommerce-com-subscriptions/). We also prompt users to connect on the task list if they chose extensions in the profile wizard, but did not finish connecting.
To make the connection from the new onboarding experience possible, we build our own connection endpoints [/wc-admin/plugins/request-wccom-connect](https://github.com/woocommerce/woocommerce-admin/blob/61b771c2643c24334ea062ab3521073beaf50019/src/API/OnboardingPlugins.php#L298-L355) and [/wc-admin/plugins/finish-wccom-connect](https://github.com/woocommerce/woocommerce-admin/blob/61b771c2643c24334ea062ab3521073beaf50019/src/API/OnboardingPlugins.php#L357-L417).
To make the connection from the new onboarding experience possible, we build our own connection endpoints [/wc-admin/plugins/request-wccom-connect](https://github.com/woocommerce/woocommerce/blob/feba6a8dcd55d4f5c7edc05478369c76df082293/plugins/woocommerce/src/Admin/API/Plugins.php#L419-L476) and [/wc-admin/plugins/finish-wccom-connect](https://github.com/woocommerce/woocommerce/blob/feba6a8dcd55d4f5c7edc05478369c76df082293/plugins/woocommerce/src/Admin/API/Plugins.php#L478-L538).
Both of these endpoints use WooCommerce Core's `WC_Helper_API` directly. The main difference with our connection (compared to the connection on the subscriptions page) is the addition of two additional query string parameters:
@ -72,7 +72,7 @@ To disconnect from WooCommerce.com, go to `WooCommerce > Extensions > WooCommerc
Using Jetpack & WooCommerce Shipping & Tax allows us to offer additional features to new WooCommerce users as well as simplify parts of the setup process. For example, we can do automated tax calculations for certain countries, significantly simplifying the tax task. To make this work, the user needs to be connected to a WordPress.com account. This also means development and testing of these features needs to be done on a Jetpack connected site. Search the MGS & the Feld Guide for additional resources on testing Jetpack with local setups.
We have a special Jetpack connection flow designed specifically for WooCommerce onboarding, so that the user feels that they are connecting as part of a cohesive experience. To access this flow, we have a custom Jetpack connection endpoint [/wc-admin/plugins/connect-jetpack](https://github.com/woocommerce/woocommerce-admin/blob/61b771c2643c24334ea062ab3521073beaf50019/src/API/OnboardingPlugins.php#L273-L296).
We have a special Jetpack connection flow designed specifically for WooCommerce onboarding, so that the user feels that they are connecting as part of a cohesive experience. To access this flow, we have a custom Jetpack connection endpoint [/wc-admin/plugins/connect-jetpack](https://github.com/woocommerce/woocommerce/blob/feba6a8dcd55d4f5c7edc05478369c76df082293/plugins/woocommerce/src/Admin/API/Plugins.php#L395-L417).
We use Jetpack's `build_connect_url` function directly, but add the following two query parameters:
@ -110,14 +110,3 @@ Logic for the Calypso flows are gated behind two separate [Calypso feature flags
### Testing
If you are running the development version of WooCommerce Admin, and have [`WP_DEBUG`](https://codex.wordpress.org/WP_DEBUG) set to `true`, two Calypso connection buttons are displayed under the `WooCommerce > Settings > Help > Setup Wizard` menu, making it easier to access and test the flows.
## Building the onboarding feature plugin
The `onboarding` feature flag is enabled in the main WooCommerce Admin plugin build. That means the published version of the plugin on WordPress.org contains the onboarding feature, but it is visually off by default. See the "enable onboarding" section above.
Sometimes, it may be necessary to generate a separate build of the plugin between public releases for internal testing or debugging. This can be done using the [building custom plugin builds](https://github.com/woocommerce/woocommerce-admin/blob/main/docs/feature-flags.md#building-custom-plugin-builds) feature of our build system.
* Switch to the latest `main` branch and pull down any changes
* Run `pnpm run build:release -- --slug onboarding --features '{"onboarding":true}'`
* A special `woocommerce-admin-onboarding.zip` release will be generated, containing the latest onboarding code
* Make sure to follow the directions in the "enabling onboarding" section above to properly use the build

View File

@ -8,9 +8,9 @@ After merchants click on a recommendation, plugins from this source will then wa
Gateway suggestions are retreived from a REST API and can be added via a remote JSON data source or filtered with the `woocommerce_admin_payment_gateway_suggestion_specs` filter.
To quickly get started with an example plugin, run the following from your `woocommerce-admin` directory:
To quickly get started with an example plugin, run the following:
`pnpm run example -- --ext=payment-gateway-suggestions`
`WC_EXT=payment-gateway-suggestions pnpm nx example woocommerce-admin`
This will create a new plugin that when activated will add two new gateway suggestions. The first is a simple gateway demonstrating how configuration fields can be pulled from the gateway class to create a configuration form. The second gateway shows a more customized approach via SlotFill.
@ -41,7 +41,7 @@ The data source schema defines the recommended payment gateways and required plu
]
```
The specs use the [rule processor](https://github.com/woocommerce/woocommerce-admin/blob/main/src/RemoteInboxNotifications/README.md#rule) to determine if a gateway should be shown using the `is_visible` property.
The specs use the [rule processor](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/src/Admin/RemoteInboxNotifications#rule) to determine if a gateway should be shown using the `is_visible` property.
## Payment Gateway Configs
@ -64,13 +64,13 @@ By default, the client will generate a payment gateway setup form from the setti
### WooPaymentGatewayConfigure
To customize the configuration form used in the payment setup, you can use [WooPaymentGatewayConfigure](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/onboarding/src/components/WooPaymentGatewayConfigure).
To customize the configuration form used in the payment setup, you can use [WooPaymentGatewayConfigure](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/onboarding/src/components/WooPaymentGatewayConfigure).
This will leave the default gateway installation and stepper in place, but allow the form to be customized as needed.
### WooPaymentGatewaySetup
To completely override the stepper and default installation behavior, the gateway can be SlotFilled using [WooPaymentGatewaySetup](https://github.com/woocommerce/woocommerce-admin/tree/main/packages/onboarding/src/components/WooPaymentGatewaySetup).
To completely override the stepper and default installation behavior, the gateway can be SlotFilled using [WooPaymentGatewaySetup](https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/onboarding/src/components/WooPaymentGatewaySetup).
## Post install setup

View File

@ -1,70 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<title>WooCommerce Admin</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1" />
<meta name="description" content="Description" />
<meta
name="viewport"
content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0"
/>
<!-- Theme: Simple -->
<link
rel="stylesheet"
href="https://unpkg.com/docsify-themeable/dist/css/theme-simple.css"
/>
<!-- Customization -->
<style>
:root {
--theme-color: #7f54b3;
}
.markdown-section h1 code,
.markdown-section h2 code,
.markdown-section h3 code,
.markdown-section h4 code {
/* Code font is slightly larger-scale than heading font, so we'll size it accordingly. */
font-size: 0.9em;
}
/* custom css for the components page */
[data-page='components/README.md'] .markdown-section {
max-width: 100%;
height: 100vh;
}
[data-page='components/README.md'] iframe {
border: none;
outline: none;
height: 100%;
width: 100%;
}
</style>
<!-- Global site tag (gtag.js) - Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id=G-8KCYZ2CYMS"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-8KCYZ2CYMS', {
'content_group' : 'WooCommerce Admin Docs',
});
</script>
</head>
<body>
<div id="app"></div>
<script>
window.$docsify = {
name: 'WooCommerce Admin',
repo: 'https://github.com/woocommerce/woocommerce-admin',
loadSidebar: true,
subMaxLevel: 3,
search: 'auto',
};
</script>
<script src="https://unpkg.com/docsify/lib/docsify.min.js"></script>
<script src="https://unpkg.com/docsify/lib/plugins/search.min.js"></script>
<script src="https://unpkg.com/docsify-themeable"></script>
</body>
</html>

View File

@ -181,6 +181,6 @@ addFilter( 'woocommerce_admin_pages_list', 'my-namespace', ( pages ) => {
### Further Reading
- Check out the [`PageController`](../src/PageController.php) class.
- See how we're [connecting existing WooCommerce pages](../includes/page-controller-functions.php).
- See how we're [registering Analytics Reports](../src/Features/Analytics.php).
- Check out the [`PageController`](../woocommerce/src/Admin/PageController.php) class.
- See how we're [connecting existing WooCommerce pages](../woocommerce/includes/react-admin/page-controller-functions.php).
- See how we're [registering Analytics Reports](../woocommerce/src/Internal/Admin/Analytics.php).

View File

@ -8,65 +8,4 @@
## Naming: Component classes
To avoid class name collisions between elements of the woo app and to the enclosing WordPress dashboard, class names **must** adhere to the following guidelines:
Any default export of a folder's `index.js` **must** be prefixed with `woocommerce-` followed by the directory name in which it resides:
```
.woocommerce-[ directory name ]
```
(Example: `.woocommerce-card` from `components/card/index.js`)
For any descendant of the top-level (`index.js`) element, prefix using the top-level element's class name separated by two underscores:
```
.woocommerce-[ directory name ]__[ descendant description ]
```
(Example: `.woocommerce-card__title`, or `.woocommerce-ellipsis-menu__item`)
For optional variations of an element or its descendants, you may use a modifier class, but you **must not** apply styles to the modifier class directly; only as an additional selector to the element to which the modifier applies:
```
.woocommerce-[ directory name ].is-[ modifier description ]
.woocommerce-[ directory name ]__[ descendant description ].is-[ modifier description ]
```
(Example: `.woocommerce-ellipsis-menu__item.is-active` )
In all of the above cases, except in separating the top-level element from its descendants, you **must** use dash delimiters when expressing multiple terms of a name. You can use `.is-*` or `.has-*` to describe element states.
You may observe that these conventions adhere closely to the [BEM (Blocks, Elements, Modifiers)](http://getbem.com/introduction/) CSS methodology, with minor adjustments to the application of modifiers.
## Naming: Layout classes
All layout classes use the `.woocommerce-layout__` prefix:
```
.woocommerce-layout__[ section ]
```
(Example: `.woocommerce-layout__activity-panel` )
If the section has children elements, prefix a description with the section class name:
```
.woocommerce-layout__[ section ]-[ descendant description ]
```
(Example: `.woocommerce-layout__activity-panel-title` )
## Naming: Dashboard classes
All dashboard components use the `.woocommerce-dashboard__` prefix:
```
.woocommerce-dashboard__[ section ]
```
(Example: `.woocommerce-dashboard__widget` )
## Naming: Analytics classes
All analytics components use the `.woocommerce-analytics__` prefix.
Please refer to [CSS SASS coding guidelines and naming conventions](https://github.com/woocommerce/woocommerce/wiki/CSS-SASS-coding-guidelines-and-naming-conventions)

View File

@ -1,6 +1,6 @@
# WooCommerce Admin
The WooCommerce Admin plugin is where the next iteration of the administrative experience for WooCommerce is being developed. The project is being built on top of the modern JavaScript packages that are being released from the [core WordPress editor project](https://github.com/wordpress/gutenberg). By building with these `@wordpress/components` - WooCommerce Admin seeks to create a cohesive experience with the latest WordPress core design system, and to deliver a fast and modern set of tools to manage one's WooCommerce Store with.
The WooCommerce Admin is where the next iteration of the administrative experience for WooCommerce is being developed. The project is being built on top of the modern JavaScript packages that are being released from the [core WordPress editor project](https://github.com/wordpress/gutenberg). By building with these `@wordpress/components` - WooCommerce Admin seeks to create a cohesive experience with the latest WordPress core design system, and to deliver a fast and modern set of tools to manage one's WooCommerce Store with.
Currently, development efforts have been focused on two primary areas:
@ -10,7 +10,7 @@ Currently, development efforts have been focused on two primary areas:
## Analytics
With WooCommerce Admin installed, a new Analytics menu item is created in the wp-admin menu system. This menu item, and the reports contained insde of it are available to all wp-admin users that have the `view_woocommerce_reports` capability, so per a standard WooCommerce install this would give `shop_manager`s and `administrator`s access to the reports.
With WooCommerce installed, a new Analytics menu item is created in the wp-admin menu system. This menu item, and the reports contained insde of it are available to all wp-admin users that have the `view_woocommerce_reports` capability, so per a standard WooCommerce install this would give `shop_manager`s and `administrator`s access to the reports.
Each report is quite unique with its own set of filtering options and chart types. To learn more about each individual report, please view the pages below:

View File

@ -2,7 +2,7 @@
The Orders Report provides insight about your store's orders.
By default, orders with non-excluded statuses are listed by order date descending. Excluded statuses can be edited on the [Settings page](https://github.com/woocommerce/woocommerce-admin/blob/main/docs/woocommerce.com/analytics-settings.md#excluded-statuses)
By default, orders with non-excluded statuses are listed by order date descending. Excluded statuses can be edited on the [Settings page](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-admin/docs/woocommerce.com/analytics-settings.md#excluded-statuses)
Refunded orders cannot be excluded from the orders report. Refunded orders have two rows in the report: one for the date of the original order and one for the date of refund.

View File

@ -11,7 +11,7 @@
"scripts": {
"analyze": "cross-env NODE_ENV=production ANALYZE=true webpack",
"prebuild": "pnpm run install-if-deps-outdated",
"build": "pnpm run build:feature-config && cross-env NODE_ENV=production webpack",
"build": "WC_ADMIN_PHASE=core pnpm run build:feature-config && cross-env NODE_ENV=production WC_ADMIN_PHASE=core webpack",
"build-storybook": "build-storybook -c ./storybook/.storybook",
"build:feature-config": "php ../woocommerce/bin/generate-feature-config.php",
"build:packages": "cross-env NODE_ENV=production pnpm run:packages -- build",
@ -21,7 +21,6 @@
"create-wc-extension": "node ./bin/starter-pack/starter-pack.js",
"predev": "pnpm run -s install-if-deps-outdated",
"dev": "cross-env WC_ADMIN_PHASE=development pnpm run build:feature-config && cross-env WC_ADMIN_PHASE=development pnpm run build:packages && cross-env WC_ADMIN_PHASE=development webpack",
"docs": "./bin/import-wp-css-storybook.sh && BABEL_ENV=storybook STORYBOOK=true pnpm exec build-storybook -c storybook/.storybook -o ./docs/components/storybook",
"example": "webpack --config docs/examples/extensions/examples.config.js --watch",
"preinstall": "npx only-allow pnpm",
"install-if-deps-outdated": "node bin/install-if-deps-outdated.js",
@ -199,7 +198,6 @@
"copy-webpack-plugin": "^10.2.4",
"cross-env": "^7.0.3",
"css-loader": "^6.7.0",
"docsify-cli": "^4.4.3",
"eslint": "^8.10.0",
"eslint-import-resolver-typescript": "^2.5.0",
"eslint-import-resolver-webpack": "^0.13.2",

View File

@ -62,6 +62,7 @@ const getEntryPoints = () => {
return entryPoints;
};
// WordPress.orgs translation infrastructure ignores files named “.min.js” so we need to name our JS files without min when releasing the plugin.
const outputSuffix = WC_ADMIN_PHASE === 'core' ? '' : '.min';
const webpackConfig = {
@ -175,10 +176,9 @@ const webpackConfig = {
// TODO: Partially replace with __webpack_get_script_filename__ in app with Webpack 5.x.
// The CSS chunk portion will need to remain, as it originates in MiniCssExtractPlugin.
new AsyncChunkSrcVersionParameterPlugin(),
// Generate unminified files to load the unminified version when `define( 'SCRIPT_DEBUG', true );` is set in wp-config.
// This is also required to publish human readeable code in the deployed "plugin".
// See https://developer.wordpress.org/plugins/wordpress-org/detailed-plugin-guidelines/#4-code-must-be-mostly-human-readable
WC_ADMIN_PHASE !== 'core' &&
// We only want to generate unminified files in the development phase.
WC_ADMIN_PHASE === 'development' &&
// Generate unminified files to load the unminified version when `define( 'SCRIPT_DEBUG', true );` is set in wp-config.
new UnminifyWebpackPlugin( {
test: /\.js($|\?)/i,
mainEntry: 'app/index.min.js',
@ -194,7 +194,11 @@ const webpackConfig = {
},
};
if ( webpackConfig.mode !== 'production' && WC_ADMIN_PHASE !== 'core' ) {
// Use the source map if we're in development mode, .
if (
webpackConfig.mode === 'development' ||
WC_ADMIN_PHASE === 'development'
) {
webpackConfig.devtool = process.env.SOURCEMAP || 'source-map';
}

View File

@ -8,14 +8,13 @@
/**
* Get phase for feature flags
* - development: All features should be enabled in development.
* - plugin: For the standalone feature plugin, for GitHub and WordPress.org.
* - core: Stable features for WooCommerce core merge.
*/
$phase = getenv( 'WC_ADMIN_PHASE' );
if ( ! in_array( $phase, array( 'development', 'plugin', 'core' ), true ) ) {
$phase = 'plugin'; // Default to plugin when running `pnpm run build`.
if ( ! in_array( $phase, array( 'development', 'core' ), true ) ) {
$phase = 'core'; // Default to core when running `pnpm run build`.
}
$config_json = file_get_contents( __DIR__ . '/../client/admin/config/' . $phase . '.json' );
$config = json_decode( $config_json );

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Remove Pinterest extension from OBW #32626

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fixing bug in which tasks reminder bar was displayed on product screens

View File

@ -0,0 +1,4 @@
Significance: minor
Type: fix
Added a temporary filter to patch the WCA JS packages i18n json files #32603

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Don't include draft orders in reports

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Pass `WC_ADMIN_PHASE=core` to build commands & remove "plugin" env

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Revert back menu position to floats as string for WP compatibility.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Update payment gateway logic in payment task

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
Update payment method link to the internal extension marketplace

View File

@ -20,8 +20,6 @@
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
"wc-pay-welcome-page": true
}
}

View File

@ -20,8 +20,6 @@
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
"wc-pay-welcome-page": true
}
}

View File

@ -1,27 +0,0 @@
{
"features": {
"activity-panels": true,
"analytics": true,
"coupons": true,
"customer-effort-score-tracks": true,
"homescreen": true,
"marketing": true,
"minified-js": true,
"mobile-app-banner": true,
"navigation": true,
"onboarding": true,
"onboarding-tasks": true,
"remote-inbox-notifications": true,
"remote-free-extensions": true,
"payment-gateway-suggestions": true,
"settings": false,
"shipping-label-banner": true,
"subscriptions": true,
"store-alerts": true,
"transient-notices": true,
"wc-pay-promotion": true,
"wc-pay-welcome-page": true,
"tasklist-setup-experiment-1": false,
"tasklist-setup-experiment-2": false
}
}

View File

@ -61,7 +61,7 @@ class WC_Admin_Menus {
$menu[] = array( '', 'read', 'separator-woocommerce', '', 'wp-menu-separator woocommerce' ); // WPCS: override ok.
}
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'edit_others_shop_orders', 'woocommerce', null, $woocommerce_icon, 55 );
add_menu_page( __( 'WooCommerce', 'woocommerce' ), __( 'WooCommerce', 'woocommerce' ), 'edit_others_shop_orders', 'woocommerce', null, $woocommerce_icon, '55.5' );
add_submenu_page( 'edit.php?post_type=product', __( 'Attributes', 'woocommerce' ), __( 'Attributes', 'woocommerce' ), 'manage_product_terms', 'product_attributes', array( $this, 'attributes_page' ) );
}
@ -73,7 +73,7 @@ class WC_Admin_Menus {
if ( self::can_view_woocommerce_menu_item() ) {
add_submenu_page( 'woocommerce', __( 'Reports', 'woocommerce' ), __( 'Reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ) );
} else {
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), 'dashicons-chart-bar', 56 );
add_menu_page( __( 'Sales reports', 'woocommerce' ), __( 'Sales reports', 'woocommerce' ), 'view_woocommerce_reports', 'wc-reports', array( $this, 'reports_page' ), 'dashicons-chart-bar', '55.6' );
}
}

View File

@ -209,13 +209,13 @@ class WC_Settings_Payment_Gateways extends WC_Settings_Page {
* See https://github.com/woocommerce/woocommerce/issues/32130 for more details.
*/
if ( WooCommercePayments::is_supported() ) {
$columns_count = count( $columns );
$columns_count = count( $columns );
$link_text = __( 'Other payment methods', 'woocommerce' );
$external_link_icon = '<svg style="margin-left: 4px" class="gridicon gridicons-external needs-offset" height="18" width="18" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"><g><path d="M19 13v6a2 2 0 01-2 2H5a2 2 0 01-2-2V7a2 2 0 012-2h6v2H5v12h12v-6h2zM13 3v2h4.586l-7.793 7.793 1.414 1.414L19 6.414V11h2V3h-8z"></path></g></svg>';
echo '<tr>';
// phpcs:ignore -- ignoring the error since the value is harded.
echo "<td style='border-top: 1px solid #c3c4c7; background-color: #fff' colspan='{$columns_count}'>";
echo "<a id='settings-other-payment-methods' href='https://woocommerce.com/product-category/woocommerce-extensions/payment-gateways/?utm_source=payments_recommendations' target='_blank' class='components-button is-tertiary'>";
echo "<a id='settings-other-payment-methods' href='" . esc_url( admin_url( 'admin.php?page=wc-addons&section=payment-gateways' ) ) . "' target='_blank' class='components-button is-tertiary'>";
// phpcs:ignore
echo $link_text;
// phpcs:ignore

View File

@ -15,7 +15,7 @@
"preinstall": "npx only-allow pnpm",
"build": "./bin/build-zip.sh",
"build:feature-config": "php bin/generate-feature-config.php",
"build:core": "pnpm run build:feature-config && pnpm nx build woocommerce-admin && pnpm nx build woocommerce-legacy-assets && pnpm run makepot",
"build:core": "WC_ADMIN_PHASE=core pnpm run build:feature-config && pnpm nx build woocommerce-admin && pnpm nx build woocommerce-legacy-assets && pnpm run makepot",
"build:zip": "pnpm run build",
"lint:js": "eslint assets/js --ext=js",
"docker:down": "pnpx wc-e2e docker:down",

View File

@ -397,7 +397,6 @@ class OnboardingProfile extends \WC_REST_Data_Controller {
'creative-mail-by-constant-contact',
'facebook-for-woocommerce',
'google-listings-and-ads',
'pinterest-for-woocommerce',
'mailpoet',
),
'type' => 'string',

View File

@ -577,7 +577,7 @@ class DataStore extends SqlQuery {
*/
protected static function get_excluded_report_order_statuses() {
$excluded_statuses = \WC_Admin_Settings::get_option( 'woocommerce_excluded_report_order_statuses', array( 'pending', 'failed', 'cancelled' ) );
$excluded_statuses = array_merge( array( 'trash' ), array_map( 'esc_sql', $excluded_statuses ) );
$excluded_statuses = array_merge( array( 'auto-draft', 'trash' ), array_map( 'esc_sql', $excluded_statuses ) );
return apply_filters( 'woocommerce_analytics_excluded_order_statuses', $excluded_statuses );
}

View File

@ -73,6 +73,33 @@ class TaskLists {
add_filter( 'woocommerce_admin_shared_settings', array( __CLASS__, 'task_list_preloaded_settings' ), 20 );
}
/**
* Check if an experiment is the treatment or control.
*
* @param string $name Name prefix of experiment.
* @return bool
*/
public static function is_experiment_treatment( $name ) {
$anon_id = isset( $_COOKIE['tk_ai'] ) ? sanitize_text_field( wp_unslash( $_COOKIE['tk_ai'] ) ) : '';
$allow_tracking = 'yes' === get_option( 'woocommerce_allow_tracking' );
$abtest = new \WooCommerce\Admin\Experimental_Abtest(
$anon_id,
'woocommerce',
$allow_tracking
);
$date = new \DateTime();
$date->setTimeZone( new \DateTimeZone( 'UTC' ) );
$experiment_name = sprintf(
'%s_%s_%s',
$name,
$date->format( 'Y' ),
$date->format( 'm' )
);
return $abtest->get_variation( $experiment_name ) === 'treatment';
}
/**
* Initialize default lists.
*/
@ -93,7 +120,8 @@ class TaskLists {
'Appearance',
),
'event_prefix' => 'tasklist_',
'visible' => ! Features::is_enabled( 'tasklist-setup-experiment-1' ) && ! Features::is_enabled( 'tasklist-setup-experiment-2' ),
'visible' => ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' )
&& ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_2' ),
)
);
@ -117,7 +145,7 @@ class TaskLists {
'options' => array(
'use_completed_title' => true,
),
'visible' => Features::is_enabled( 'tasklist-setup-experiment-1' ),
'visible' => self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' ),
)
);
@ -138,7 +166,8 @@ class TaskLists {
'Appearance',
),
'event_prefix' => 'tasklist_',
'visible' => Features::is_enabled( 'tasklist-setup-experiment-2' ),
'visible' => self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_2' )
&& ! self::is_experiment_treatment( 'woocommerce_tasklist_setup_experiment_1' ),
'options' => array(
'use_completed_title' => true,
),

View File

@ -25,161 +25,114 @@ class DefaultPaymentGateways {
'id' => 'payfast',
'title' => __( 'PayFast', 'woocommerce' ),
'content' => __( 'The PayFast extension for WooCommerce enables you to accept payments by Credit Card and EFT via one of South Africas most popular payment gateways. No setup fees or monthly subscription costs. Selecting this extension will configure your store to use South African rands as the selected currency.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/payfast.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payfast.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/payfast.png',
'plugins' => array( 'woocommerce-payfast-gateway' ),
'is_visible' => array(
(object) array(
'type' => 'base_location_country',
'value' => 'ZA',
'operation' => '=',
),
self::get_rules_for_countries( array( 'ZA', 'GH', 'NG' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'ZA', 'GH', 'NG' ),
'category_additional' => array(),
),
array(
'id' => 'stripe',
'title' => __( ' Stripe', 'woocommerce' ),
'content' => __( 'Accept debit and credit cards in 135+ currencies, methods such as Alipay, and one-touch checkout with Apple Pay.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/stripe.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/stripe.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/stripe.png',
'plugins' => array( 'woocommerce-gateway-stripe' ),
'is_visible' => array(
// https://stripe.com/global.
self::get_rules_for_countries(
array(
'AU',
'AT',
'BE',
'BG',
'BR',
'CA',
'CY',
'CZ',
'DK',
'EE',
'FI',
'FR',
'DE',
'GR',
'HK',
'IN',
'IE',
'IT',
'JP',
'LV',
'LT',
'LU',
'MY',
'MT',
'MX',
'NL',
'NZ',
'NO',
'PL',
'PT',
'RO',
'SG',
'SK',
'SI',
'ES',
'SE',
'CH',
'GB',
'US',
'PR',
)
array( 'AU', 'AT', 'BE', 'BG', 'BR', 'CA', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HK', 'IN', 'IE', 'IT', 'JP', 'LV', 'LT', 'LU', 'MY', 'MT', 'MX', 'NL', 'NZ', 'NO', 'PL', 'PT', 'RO', 'SG', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB', 'US', 'PR', 'HU', 'SL', 'ID', 'MY', 'SI', 'PR' )
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'AU', 'AT', 'BE', 'BG', 'BR', 'CA', 'CY', 'CZ', 'DK', 'EE', 'FI', 'FR', 'DE', 'GR', 'HK', 'IN', 'IE', 'IT', 'JP', 'LV', 'LT', 'LU', 'MY', 'MT', 'MX', 'NL', 'NZ', 'NO', 'PL', 'PT', 'RO', 'SG', 'SK', 'SI', 'ES', 'SE', 'CH', 'GB', 'US', 'PR', 'HU', 'SL', 'ID', 'MY', 'SI', 'PR' ),
'category_additional' => array(),
'recommendation_priority' => 3,
),
array(
'id' => 'paystack',
'title' => __( 'Paystack', 'woocommerce' ),
'content' => __( 'Paystack helps African merchants accept one-time and recurring payments online with a modern, safe, and secure payment gateway.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/paystack.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/paystack.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/paystack.png',
'plugins' => array( 'woo-paystack' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'ZA', 'GH', 'NG' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'ZA', 'GH', 'NG' ),
'category_additional' => array(),
),
array(
'id' => 'kco',
'title' => __( 'Klarna Checkout', 'woocommerce' ),
'content' => __( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/klarna.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/klarna-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/klarna.png',
'plugins' => array( 'klarna-checkout-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'SE', 'FI', 'NO' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'SE', 'FI', 'NO' ),
'category_additional' => array(),
),
array(
'id' => 'klarna_payments',
'title' => __( 'Klarna Payments', 'woocommerce' ),
'content' => __( 'Choose the payment that you want, pay now, pay later or slice it. No credit card numbers, no passwords, no worries.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/klarna.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/klarna-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/klarna.png',
'plugins' => array( 'klarna-payments-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries(
array(
'DK',
'DE',
'AT',
'NL',
'CH',
'BE',
'SP',
'PL',
'FR',
'IT',
'GB',
)
array( 'US', 'CA', 'DK', 'DE', 'AT', 'NL', 'CH', 'BE', 'SP', 'PL', 'FR', 'IT', 'GB', 'ES', 'FI', 'NO', 'SE', 'ES', 'FI', 'NO', 'SE' )
),
self::get_rules_for_cbd( false ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA', 'DK', 'DE', 'AT', 'NL', 'CH', 'BE', 'SP', 'PL', 'FR', 'IT', 'GB', 'ES', 'FI', 'NO', 'SE', 'ES', 'FI', 'NO', 'SE' ),
),
array(
'id' => 'mollie_wc_gateway_banktransfer',
'title' => __( 'Mollie', 'woocommerce' ),
'content' => __( 'Effortless payments by Mollie: Offer global and local payment methods, get onboarded in minutes, and supported in your language.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/mollie.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/mollie.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/mollie.png',
'plugins' => array( 'mollie-payments-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries(
array(
'FR',
'DE',
'GB',
'AT',
'CH',
'ES',
'IT',
'PL',
'FI',
'NL',
'BE',
)
array( 'FR', 'DE', 'GB', 'AT', 'CH', 'ES', 'IT', 'PL', 'FI', 'NL', 'BE' )
),
),
'category_other' => array( 'FR', 'DE', 'GB', 'AT', 'CH', 'ES', 'IT', 'PL', 'FI', 'NL', 'BE' ),
'category_additional' => array(),
),
array(
'id' => 'woo-mercado-pago-custom',
'title' => __( 'Mercado Pago Checkout Pro & Custom', 'woocommerce' ),
'content' => __( 'Accept credit and debit cards, offline (cash or bank transfer) and logged-in payments with money in Mercado Pago. Safe and secure payments with the leading payment processor in LATAM.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/mercadopago.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/mercadopago.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/mercadopago.png',
'plugins' => array( 'woocommerce-mercadopago' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ) ),
),
'recommendation_priority' => 2,
'is_local_partner' => true,
'category_other' => array( 'AR', 'BR', 'CL', 'CO', 'MX', 'PE', 'UY' ),
'category_additional' => array(),
),
array(
'id' => 'ppcp-gateway',
'title' => __( 'PayPal Payments', 'woocommerce' ),
'content' => __( "Safe and secure payments using credit cards or your customer's PayPal account.", 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/paypal.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/paypal.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/paypal.png',
'plugins' => array( 'woocommerce-paypal-payments' ),
'is_visible' => array(
(object) array(
@ -189,12 +142,15 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'US', 'CA', 'AT', 'BE', 'BG', 'HR', 'CH', 'CY', 'CZ', 'DK', 'EE', 'ES', 'FI', 'FR', 'DE', 'GB', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SL', 'SE', 'MX', 'BR', 'AR', 'CL', 'CO', 'EC', 'PE', 'UY', 'VE', 'AU', 'NZ', 'HK', 'JP', 'SG', 'CN', 'ID', 'ZA', 'NG', 'GH' ),
'category_additional' => array( 'US', 'CA', 'AT', 'BE', 'BG', 'HR', 'CH', 'CY', 'CZ', 'DK', 'EE', 'ES', 'FI', 'FR', 'DE', 'GB', 'GR', 'HU', 'IE', 'IT', 'LV', 'LT', 'LU', 'MT', 'NL', 'NO', 'PL', 'PT', 'RO', 'SK', 'SL', 'SE', 'MX', 'BR', 'AR', 'CL', 'CO', 'EC', 'PE', 'UY', 'VE', 'AU', 'NZ', 'HK', 'JP', 'SG', 'CN', 'ID', 'IN', 'ZA', 'NG', 'GH' ),
),
array(
'id' => 'cod',
'title' => __( 'Cash on delivery', 'woocommerce' ),
'content' => __( 'Take payments in cash upon delivery.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/cod.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/cod.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/cod.png',
'is_visible' => array(
self::get_rules_for_cbd( false ),
),
@ -204,7 +160,8 @@ class DefaultPaymentGateways {
'id' => 'bacs',
'title' => __( 'Direct bank transfer', 'woocommerce' ),
'content' => __( 'Take payments via bank transfer.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/bacs.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/bacs.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/bacs.png',
'is_visible' => array(
self::get_rules_for_cbd( false ),
),
@ -218,6 +175,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies. Track cash flow and manage recurring revenue directly from your stores dashboard - with no setup costs or monthly fees.',
'is_visible' => array(
@ -260,6 +218,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies. Track cash flow and manage recurring revenue directly from your stores dashboard - with no setup costs or monthly fees.',
'is_visible' => array(
@ -294,6 +253,7 @@ class DefaultPaymentGateways {
'woocommerce'
),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/wcpay.svg',
'plugins' => array( 'woocommerce-payments' ),
'description' => 'With WooCommerce Payments, you can securely accept major cards, Apple Pay, and payments in over 100 currencies with no setup costs or monthly fees and you can now accept in-person payments with the Woo mobile app.',
'is_visible' => array(
@ -324,7 +284,8 @@ class DefaultPaymentGateways {
'id' => 'razorpay',
'title' => __( 'Razorpay', 'woocommerce' ),
'content' => __( 'The official Razorpay extension for WooCommerce allows you to accept credit cards, debit cards, netbanking, wallet, and UPI payments.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/razorpay.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/razorpay.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/razorpay.png',
'plugins' => array( 'woo-razorpay' ),
'is_visible' => array(
(object) array(
@ -334,12 +295,15 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'IN' ),
'category_additional' => array(),
),
array(
'id' => 'payubiz',
'title' => __( 'PayU for WooCommerce', 'woocommerce' ),
'content' => __( 'Enable PayUs exclusive plugin for WooCommerce to start accepting payments in 100+ payment methods available in India including credit cards, debit cards, UPI, & more!', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/payu.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/payu.svg',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/payu.png',
'plugins' => array( 'payu-india' ),
'is_visible' => array(
(object) array(
@ -349,23 +313,29 @@ class DefaultPaymentGateways {
),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'IN' ),
'category_additional' => array(),
),
array(
'id' => 'eway',
'title' => __( 'Eway', 'woocommerce' ),
'content' => __( 'The Eway extension for WooCommerce allows you to take credit card payments directly on your store without redirecting your customers to a third party site to make payment.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/eway.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/onboarding/eway.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/eway.png',
'plugins' => array( 'woocommerce-gateway-eway' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'AU', 'NZ' ) ),
self::get_rules_for_cbd( false ),
),
'category_other' => array( 'AU', 'NZ' ),
'category_additional' => array(),
),
array(
'id' => 'square_credit_card',
'title' => __( 'Square', 'woocommerce' ),
'content' => __( 'Securely accept credit and debit cards with one low rate, no surprise fees (custom rates available). Sell online and in store and track sales and inventory in one place.', 'woocommerce' ),
'image' => WC()->plugin_url() . '/assets/images/payment_methods/72x72/square.png',
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/square-black.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/square.png',
'plugins' => array( 'woocommerce-square' ),
'is_visible' => array(
(object) array(
@ -376,12 +346,54 @@ class DefaultPaymentGateways {
self::get_rules_for_cbd( true ),
),
array(
self::get_rules_for_countries( array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES' ) ),
self::get_rules_for_countries( array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES', 'FI' ) ),
self::get_rules_for_selling_venues( array( 'brick-mortar', 'brick-mortar-other' ) ),
),
),
),
),
'category_other' => array( 'US', 'CA', 'JP', 'GB', 'AU', 'IE', 'FR', 'ES', 'FI' ),
'category_additional' => array(),
),
array(
'id' => 'afterpay',
'title' => __( 'Afterpay', 'woocommerce' ),
'content' => __( 'Afterpay allows customers to receive products immediately and pay for purchases over four installments, always interest-free.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/afterpay.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/afterpay.png',
'plugins' => array( 'afterpay-gateway-for-woocommerce' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
array(
'id' => 'amazon_payments_advanced',
'title' => __( 'Amazon Pay', 'woocommerce' ),
'content' => __( 'Enable a familiar, fast checkout for hundreds of millions of active Amazon customers globally.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/amazonpay.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/amazonpay.png',
'plugins' => array( 'woocommerce-gateway-amazon-payments-advanced' ),
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
array(
'id' => 'affirm',
'title' => __( 'Affirm', 'woocommerce' ),
'content' => __( 'Affirms tailored Buy Now Pay Later programs remove price as a barrier, turning browsers into buyers, increasing average order value, and expanding your customer base.', 'woocommerce' ),
'image' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/affirm.png',
'image_72x72' => WC_ADMIN_IMAGES_FOLDER_URL . '/payment_methods/72x72/affirm.png',
'plugins' => array(),
'external_link' => 'https://woocommerce.com/products/woocommerce-gateway-affirm',
'is_visible' => array(
self::get_rules_for_countries( array( 'US', 'CA' ) ),
),
'category_other' => array(),
'category_additional' => array( 'US', 'CA' ),
),
);
}

View File

@ -36,7 +36,6 @@ class DefaultFreeExtensions {
'plugins' => [
self::get_plugin( 'mailpoet' ),
self::get_plugin( 'google-listings-and-ads' ),
self::get_plugin( 'pinterest-for-woocommerce' ),
],
],
[
@ -53,7 +52,7 @@ class DefaultFreeExtensions {
'title' => __( 'Grow your store', 'woocommerce' ),
'plugins' => [
self::get_plugin( 'google-listings-and-ads:alt' ),
self::get_plugin( 'pinterest-for-woocommerce:alt' ),
self::get_plugin( 'pinterest-for-woocommerce' ),
],
],
];
@ -100,30 +99,7 @@ class DefaultFreeExtensions {
'manage_url' => 'admin.php?page=wc-admin&path=%2Fgoogle%2Fstart',
'is_built_by_wc' => true,
],
'pinterest-for-woocommerce' => [
'name' => __( 'Pinterest for WooCommerce', 'woocommerce' ),
'description' => sprintf(
/* translators: 1: opening product link tag. 2: closing link tag */
__( 'Inspire shoppers with %1$sPinterest for WooCommerce%2$s', 'woocommerce' ),
'<a href="https://woocommerce.com/products/pinterest-for-woocommerce" target="_blank">',
'</a>'
),
'image_url' => plugins_url( '/assets/images/onboarding/pinterest.png', WC_PLUGIN_FILE ),
'manage_url' => 'admin.php?page=pinterest-for-woocommerce',
'is_visible' => [
[
'type' => 'not',
'operand' => [
[
'type' => 'plugins_activated',
'plugins' => [ 'pinterest-for-woocommerce' ],
],
],
],
],
'is_built_by_wc' => false,
],
'pinterest-for-woocommerce:alt' => [
'pinterest-for-woocommerce' => [
'name' => __( 'Pinterest for WooCommerce', 'woocommerce' ),
'description' => __( 'Get your products in front of Pinterest users searching for ideas and things to buy. Get started with Pinterest and make your entire product catalog browsable.', 'woocommerce' ),
'image_url' => plugins_url( '/assets/images/onboarding/pinterest.png', WC_PLUGIN_FILE ),

View File

@ -43,8 +43,40 @@ class Translations {
// Handler for WooCommerce and WooCommerce Admin plugin activation.
add_action( 'woocommerce_activated_plugin', array( $this, 'potentially_generate_translation_strings' ) );
add_action( 'activated_plugin', array( $this, 'potentially_generate_translation_strings' ) );
// Adding this filter to adjust the path after woocommerce-admin was merged into woocommerce core.
// Remove after the translations strings have been updated to the new path (probably woocommerce 6.6).
add_filter( 'load_script_textdomain_relative_path', array( $this, 'adjust_script_path' ), 10, 2 );
}
/**
* This filter is temporarily used to produce the correct i18n paths as they were moved in WC 6.5.
*
* @param string $relative Relative path to the script.
* @param string $src The script's source URL.
*/
public function adjust_script_path( $relative, $src ) {
// only rewrite the path if the translation file is from the old woocommerce-admin dist folder.
if ( false === strpos( $relative, 'assets/client/admin' ) ) {
return $relative;
}
// translation filenames are always based on the unminified path.
if ( substr( $relative, -7 ) === '.min.js' ) {
$relative = substr( $relative, 0, -7 ) . '.js';
}
$file_base = 'woocommerce-' . determine_locale(); // e.g woocommerce-fr_FR.
$md5_filename = $file_base . '-' . md5( $relative ) . '.json';
$languages_path = WP_LANG_DIR . '/plugins/'; // get path to translations folder.
if ( ! is_readable( $languages_path . $md5_filename ) ) {
return str_replace( 'assets/client/admin', 'packages/woocommerce-admin/dist', $relative );
} else {
return $relative;
}
}
/**
* Generate a filename to cache translations from JS chunks.
*
@ -101,8 +133,13 @@ class Translations {
// Only combine "app" files (not scripts registered with WP).
if (
// paths for woocommerce < 6.5. can be removed from 6.6 onwards or when i18n json file names are updated.
false === strpos( $reference_file, 'dist/chunks/' ) &&
false === strpos( $reference_file, 'dist/app/index.js' )
false === strpos( $reference_file, 'dist/app/index.js' ) &&
// paths for woocommerce >= 6.5 (post-merge of woocommerce-admin).
false === strpos( $reference_file, 'assets/admin/app/index.js' ) &&
false === strpos( $reference_file, 'assets/admin/chunks/' )
) {
continue;
}

View File

@ -1274,7 +1274,6 @@ importers:
cross-env: ^7.0.3
css-loader: ^6.7.0
debug: ^4.3.3
docsify-cli: ^4.4.3
dompurify: ^2.3.6
eslint: ^8.10.0
eslint-import-resolver-typescript: ^2.5.0
@ -1473,7 +1472,6 @@ importers:
copy-webpack-plugin: 10.2.4_webpack@5.70.0
cross-env: 7.0.3
css-loader: 6.7.1_webpack@5.70.0
docsify-cli: 4.4.4
eslint: 8.11.0
eslint-import-resolver-typescript: 2.5.0_fe22d862ffeecaee86c93a006d59e41e
eslint-import-resolver-webpack: 0.13.2_bac363bc2c2f46a65300020741b6cf5e
@ -8592,7 +8590,7 @@ packages:
react-refresh: 0.11.0
schema-utils: 3.1.1
source-map: 0.7.3
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/@pmmmwh/react-refresh-webpack-plugin/0.5.1_92cb4b81c6b9f71cf92f0bdb85e4210c:
@ -8786,11 +8784,6 @@ packages:
lodash.merge: 4.6.2
postcss: 5.2.18
/@sindresorhus/is/0.14.0:
resolution: {integrity: sha512-9NET910DNaIPngYnLLPeg+Ogzqsi9uM4mSboU5y6p8S5DzMTVEsJZrawi+BoDNUVBa2DhJqQYUFvMDfgU062LQ==}
engines: {node: '>=6'}
dev: true
/@sindresorhus/is/4.6.0:
resolution: {integrity: sha512-t09vSN3MdfsyCHoFcTRCH/iUtG7OJ0CsjzB8cjAmKc/va/kIgeDI/TxsigdncE/4be734m0cvIYwNaV4i2XqAw==}
engines: {node: '>=10'}
@ -8980,7 +8973,7 @@ packages:
peerDependencies:
'@storybook/addon-actions': '*'
dependencies:
'@storybook/addon-actions': 6.4.19_react-dom@17.0.2+react@17.0.2
'@storybook/addon-actions': 6.4.19
global: 4.4.0
dev: true
@ -11293,7 +11286,7 @@ packages:
react-docgen-typescript: 2.2.2_typescript@4.6.2
tslib: 2.3.1
typescript: 4.6.2
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
transitivePeerDependencies:
- supports-color
dev: true
@ -11816,13 +11809,6 @@ packages:
- supports-color
dev: true
/@szmarczak/http-timer/1.1.2:
resolution: {integrity: sha512-XIB2XbzHTN6ieIjfIMV9hlVcfPU26s2vafYWQcZHWXHOxiaRZYEDKEwdl129Zyg50+foYV2jCgtrqSA6qNuNSA==}
engines: {node: '>=6'}
dependencies:
defer-to-connect: 1.1.3
dev: true
/@szmarczak/http-timer/4.0.6:
resolution: {integrity: sha512-4BAffykYOgO+5nzBWYwE3W90sBgLJoUPRWWcL8wlyiM8IB8ipJz3UMJ9KXQd1RKQXpKp8Tutn80HZtWsu2u76w==}
engines: {node: '>=10'}
@ -17098,20 +17084,6 @@ packages:
widest-line: 2.0.1
dev: true
/boxen/4.2.0:
resolution: {integrity: sha512-eB4uT9RGzg2odpER62bBwSLvUeGC+WbRjjyyFhGsKnc8wp/m0+hQsMUvUe3H2V0D5vw0nBdO1hCJoZo5mKeuIQ==}
engines: {node: '>=8'}
dependencies:
ansi-align: 3.0.1
camelcase: 5.3.1
chalk: 3.0.0
cli-boxes: 2.2.1
string-width: 4.2.3
term-size: 2.2.1
type-fest: 0.8.1
widest-line: 3.1.0
dev: true
/boxen/5.1.2:
resolution: {integrity: sha512-9gYgQKXx+1nP8mP7CzFyaUARhg7D3n1dF/FnErWmu9l6JvGpNUN278h0aSb+QjoiKSWG+iZ3uHrcqk0qrY9RQQ==}
engines: {node: '>=10'}
@ -17448,19 +17420,6 @@ packages:
engines: {node: '>=10.6.0'}
dev: false
/cacheable-request/6.1.0:
resolution: {integrity: sha512-Oj3cAGPCqOZX7Rz64Uny2GYAZNliQSqfbePrgAQ1wKAihYmCUnraBtJtKcGR4xz7wF+LoJC+ssFZvv5BgF9Igg==}
engines: {node: '>=8'}
dependencies:
clone-response: 1.0.2
get-stream: 5.2.0
http-cache-semantics: 4.1.0
keyv: 3.1.0
lowercase-keys: 2.0.0
normalize-url: 4.5.1
responselike: 1.0.2
dev: true
/cacheable-request/7.0.2:
resolution: {integrity: sha512-pouW8/FmiPQbuGpkXQ9BAPv/Mo5xDGANgSNXzTzJ8DrKGuXOssM4wIQRjfanNRh3Yu5cfYPvcorqbhg2KIJtew==}
engines: {node: '>=8'}
@ -18059,6 +18018,7 @@ packages:
resolution: {integrity: sha1-0dyXOSAxTfZ/vrlCI7TuNQI56Ws=}
dependencies:
mimic-response: 1.0.1
dev: false
/clone-stats/1.0.0:
resolution: {integrity: sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=}
@ -18376,37 +18336,11 @@ packages:
xdg-basedir: 3.0.0
dev: true
/configstore/5.0.1:
resolution: {integrity: sha512-aMKprgk5YhBNyH25hj8wGt2+D52Sw1DRRIzqBwLp2Ya9mFmY8KPvvtvmna8SxVR9JMZ4kzMD68N22vlaRpkeFA==}
engines: {node: '>=8'}
dependencies:
dot-prop: 5.3.0
graceful-fs: 4.2.9
make-dir: 3.1.0
unique-string: 2.0.0
write-file-atomic: 3.0.3
xdg-basedir: 4.0.0
dev: true
/connect-history-api-fallback/1.6.0:
resolution: {integrity: sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==}
engines: {node: '>=0.8'}
dev: true
/connect-livereload/0.6.1:
resolution: {integrity: sha512-3R0kMOdL7CjJpU66fzAkCe6HNtd3AavCS4m+uW4KtJjrdGPT0SQEZieAYd+cm+lJoBznNQ4lqipYWkhBMgk00g==}
dev: true
/connect/3.7.0:
resolution: {integrity: sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==}
engines: {node: '>= 0.10.0'}
dependencies:
debug: 2.6.9
finalhandler: 1.1.2
parseurl: 1.3.3
utils-merge: 1.0.1
dev: true
/console-browserify/1.2.0:
resolution: {integrity: sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==}
dev: true
@ -18731,11 +18665,6 @@ packages:
engines: {node: '>=4'}
dev: true
/crypto-random-string/2.0.0:
resolution: {integrity: sha512-v1plID3y9r/lPhviJ1wrXpLeyUIGAZ2SHNYTEapm7/8A9nLPoyvVp3RK/EPFqn5kEznyWgYZNsRtYYIWbuG8KA==}
engines: {node: '>=8'}
dev: true
/css-color-function/1.3.3:
resolution: {integrity: sha1-jtJMLAIFBzM5+voAS8jBQfzLKC4=}
dependencies:
@ -19393,13 +19322,6 @@ packages:
resolution: {integrity: sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=}
engines: {node: '>=0.10'}
/decompress-response/3.3.0:
resolution: {integrity: sha1-gKTdMjdIOEv6JICDYirt7Jgq3/M=}
engines: {node: '>=4'}
dependencies:
mimic-response: 1.0.1
dev: true
/decompress-response/6.0.0:
resolution: {integrity: sha512-aW35yZM6Bb/4oJlZncMH2LCoZtJXTRxES17vE3hoRiowU2kWHaJKFkSBDnDR+cm9J+9QhXmREyIfv0pji9ejCQ==}
engines: {node: '>=10'}
@ -19473,10 +19395,6 @@ packages:
dependencies:
clone: 1.0.4
/defer-to-connect/1.1.3:
resolution: {integrity: sha512-0ISdNousHvZT2EiFlZeZAHBUvSxmKswVCEf8hW7KWgG4a8MVEu/3Vb6uWYozkjylyCxe0JBIiRB1jV45S70WVQ==}
dev: true
/defer-to-connect/2.0.1:
resolution: {integrity: sha512-4tvttepXG1VaYGrRibk5EwJd1t4udunSOVMdLSAL6mId1ix438oPwPZMALY41FCijukO1L0twNcGsdzS7dHgDg==}
engines: {node: '>=10'}
@ -19706,62 +19624,6 @@ packages:
buffer-indexof: 1.1.1
dev: true
/docsify-cli/4.4.4:
resolution: {integrity: sha512-NAZgg6b0BsDuq/Pe+P19Qb2J1d+ZVbS0eGkeCNxyu4F9/CQSsRqZqAvPJ9/0I+BCHn4sgftA2jluqhQVzKzrSA==}
engines: {node: '>= 10', npm: '>= 6'}
hasBin: true
dependencies:
chalk: 2.4.2
connect: 3.7.0
connect-history-api-fallback: 1.6.0
connect-livereload: 0.6.1
cp-file: 7.0.0
docsify: 4.12.2
docsify-server-renderer: 4.12.2
enquirer: 2.3.6
fs-extra: 8.1.0
get-port: 5.1.1
livereload: 0.9.3
lru-cache: 5.1.1
open: 6.4.0
serve-static: 1.14.1
update-notifier: 4.1.3
yargonaut: 1.1.4
yargs: 15.4.1
transitivePeerDependencies:
- bufferutil
- encoding
- supports-color
- utf-8-validate
dev: true
/docsify-server-renderer/4.12.2:
resolution: {integrity: sha512-/sCq0U0iGvc8mNN6VC5SeodiHUsA98rMsMFYXtQbWsS/jWArkSee8ATlH5KzGDJ/zjf9QOFrkjoanHCNaFWiPQ==}
dependencies:
debug: 4.3.3
docsify: 4.12.2
dompurify: 2.3.6
node-fetch: 2.6.7
resolve-pathname: 3.0.0
transitivePeerDependencies:
- encoding
- supports-color
dev: true
/docsify/4.12.2:
resolution: {integrity: sha512-hpRez5upcvkYigT2zD8P5kH5t9HpSWL8yn/ZU/g04/WfAfxVNW6CPUVOOF1EsQUDxTRuyNTFOb6uUv+tPij3tg==}
requiresBuild: true
dependencies:
dompurify: 2.3.6
marked: 1.2.9
medium-zoom: 1.0.6
opencollective-postinstall: 2.0.3
prismjs: 1.27.0
strip-indent: 3.0.0
tinydate: 1.3.0
tweezer.js: 1.5.0
dev: true
/doctrine/2.1.0:
resolution: {integrity: sha512-35mSku4ZXK0vfCuHEDAwt55dg2jNajHZ1odvF+8SSr82EsZY4QmXfuWso8oEd8zRhVObSN18aM0CjSdoBX7zIw==}
engines: {node: '>=0.10.0'}
@ -19853,6 +19715,7 @@ packages:
/dompurify/2.3.6:
resolution: {integrity: sha512-OFP2u/3T1R5CEgWCEONuJ1a5+MFKnOYpkywpUSxv/dj1LeBT1erK+JwM7zK0ROy2BRhqVCf0LRw/kHqKuMkVGg==}
dev: false
/domutils/1.7.0:
resolution: {integrity: sha512-Lgd2XcJ/NjEw+7tFvfKxOzCYKZsdct5lczQ2ZaQY8Djz7pfAD3Gbp8ySJWtreII/vDlMVmxwa6pHmdxIYgttDg==}
@ -20391,11 +20254,6 @@ packages:
resolution: {integrity: sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==}
engines: {node: '>=6'}
/escape-goat/2.1.1:
resolution: {integrity: sha512-8/uIhbG12Csjy2JEW7D9pHbreaVaS/OpN3ycnyvElTdwM5n6GY6W6e2IPemfvGZeUMqZ9A/3GqIZMgKnBhAw/Q==}
engines: {node: '>=8'}
dev: true
/escape-html/1.0.3:
resolution: {integrity: sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=}
dev: true
@ -22284,11 +22142,6 @@ packages:
resolution: {integrity: sha512-0btnI/H8f2pavGMN8w40mlSKOfTK2SVJmBfBeVIj3kNw0swwgzyRq0d5TJVOwodFmtvpPeWPN/MCcfuWF0Ezbw==}
dev: true
/figlet/1.5.2:
resolution: {integrity: sha512-WOn21V8AhyE1QqVfPIVxe3tupJacq1xGkPTB4iagT6o+P2cAgEOOwIxMftr4+ZCTI6d551ij9j61DFr0nsP2uQ==}
engines: {node: '>= 0.4.0'}
dev: true
/figures/1.7.0:
resolution: {integrity: sha1-y+Hjr/zxzUS4DK3+0o3Hk6lwHS4=}
engines: {node: '>=0.10.0'}
@ -22331,7 +22184,7 @@ packages:
dependencies:
loader-utils: 2.0.2
schema-utils: 3.1.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/file-loader/6.2.0_webpack@5.64.1:
@ -23099,11 +22952,6 @@ packages:
resolution: {integrity: sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==}
engines: {node: '>=8.0.0'}
/get-port/5.1.1:
resolution: {integrity: sha512-g/Q1aTSDOxFpchXC4i8ZWvxA1lnPqx/JHqcpIw0/LX9T8x/GBbi6YnlN5nhaKIFkT8oFsscUKgDJYxfwfS6QsQ==}
engines: {node: '>=8'}
dev: true
/get-stdin/4.0.1:
resolution: {integrity: sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=}
engines: {node: '>=0.10.0'}
@ -23306,13 +23154,6 @@ packages:
ini: 1.3.8
dev: true
/global-dirs/2.1.0:
resolution: {integrity: sha512-MG6kdOUh/xBnyo9cJFeIKkLEc1AyFq42QTU4XiX51i2NEdxLxLWXIjEjmqKeSuKR7pAZjTqUVoT2b2huxVLgYQ==}
engines: {node: '>=8'}
dependencies:
ini: 1.3.7
dev: true
/global-modules/0.2.3:
resolution: {integrity: sha1-6lo77ULG1s6ZWk+KEmm12uIjgo0=}
engines: {node: '>=0.10.0'}
@ -23541,23 +23382,6 @@ packages:
url-parse-lax: 1.0.0
dev: true
/got/9.6.0:
resolution: {integrity: sha512-R7eWptXuGYxwijs0eV+v3o6+XH1IqVK8dJOEecQfTmkncw9AV4dcw/Dhxi8MdlqPthxxpZyizMzyg8RTmEsG+Q==}
engines: {node: '>=8.6'}
dependencies:
'@sindresorhus/is': 0.14.0
'@szmarczak/http-timer': 1.1.2
cacheable-request: 6.1.0
decompress-response: 3.3.0
duplexer3: 0.1.4
get-stream: 4.1.0
lowercase-keys: 1.0.1
mimic-response: 1.0.1
p-cancelable: 1.1.0
to-readable-stream: 1.0.0
url-parse-lax: 3.0.0
dev: true
/graceful-fs/4.2.8:
resolution: {integrity: sha512-qkIilPUYcNhJpd33n0GBXTB1MMPp14TxEsEs0pTrsSVucApsYzW5V+Q8Qxhik6KU3evy+qkAAowTByymK0avdg==}
@ -23933,11 +23757,6 @@ packages:
is-number: 3.0.0
kind-of: 4.0.0
/has-yarn/2.1.0:
resolution: {integrity: sha512-UqBRqi4ju7T+TqGNdqAO0PaSVGsDGJUBQvk9eUWNGRY1CFGDzYhLWoM7JQEemnlvVcv/YEmc2wNW8BC24EnUsw==}
engines: {node: '>=8'}
dev: true
/has/1.0.3:
resolution: {integrity: sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==}
engines: {node: '>= 0.4.0'}
@ -24205,7 +24024,7 @@ packages:
pretty-error: 2.1.2
tapable: 1.1.3
util.promisify: 1.0.0
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/html-webpack-plugin/5.5.0_webpack@5.70.0:
@ -24645,10 +24464,6 @@ packages:
/inherits/2.0.4:
resolution: {integrity: sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==}
/ini/1.3.7:
resolution: {integrity: sha512-iKpRpXP+CrP2jyrxvg1kMUpXDyRUFDWurxbnVT1vQPx+Wz9uCYsMIqYuSBLV+PAaZG/d7kRLKRFc9oDMsH+mFQ==}
dev: true
/ini/1.3.8:
resolution: {integrity: sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==}
@ -25096,14 +24911,6 @@ packages:
is-path-inside: 1.0.1
dev: true
/is-installed-globally/0.3.2:
resolution: {integrity: sha512-wZ8x1js7Ia0kecP/CHM/3ABkAmujX7WPvQk6uu3Fly/Mk44pySulQpnHG46OMjHGXApINnV4QhY3SWnECO2z5g==}
engines: {node: '>=8'}
dependencies:
global-dirs: 2.1.0
is-path-inside: 3.0.3
dev: true
/is-interactive/1.0.0:
resolution: {integrity: sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==}
engines: {node: '>=8'}
@ -25143,11 +24950,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/is-npm/4.0.0:
resolution: {integrity: sha512-96ECIfh9xtDDlPylNPXhzjsykHsMJZ18ASpaWzQyBr4YRTcVjUvzaHayDAES2oU/3KpljhHUjtSRNiDwi0F0ig==}
engines: {node: '>=8'}
dev: true
/is-number-object/1.0.6:
resolution: {integrity: sha512-bEVOqiRcvo3zO1+G2lVMy+gkkEm9Yh7cDMRusKKu5ZJKPUYSJwICTKZrNKHA2EbSP0Tu0+6B/emsYNHZyn6K8g==}
engines: {node: '>= 0.4'}
@ -25388,10 +25190,6 @@ packages:
dependencies:
is-docker: 2.2.1
/is-yarn-global/0.3.0:
resolution: {integrity: sha512-VjSeb/lHmkoyd8ryPVIKvOCn4D1koMqY+vqyjjUfc3xyKtP4dYOxM44sZrnqQSzSds3xyOrUTLTC9LVCVgLngw==}
dev: true
/is/3.3.0:
resolution: {integrity: sha512-nW24QBoPcFGGHJGUwnfpI7Yc5CdqWNdsyHQszVE/z2pKHXzh7FZ5GWhJqSyaQ9wMkQnsTx+kAI8bHlCX4tKdbg==}
dev: false
@ -27878,10 +27676,6 @@ packages:
engines: {node: '>=4'}
hasBin: true
/json-buffer/3.0.0:
resolution: {integrity: sha1-Wx85evx11ne96Lz8Dkfh+aPZqJg=}
dev: true
/json-buffer/3.0.1:
resolution: {integrity: sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==}
dev: false
@ -27987,12 +27781,6 @@ packages:
resolution: {integrity: sha512-X00TokkRIDotUIf3EV4xUm6ELc/IkqhS/vPSHdWnsM5y0HoNMfEqrazizI7g78lpHvnRSRt/PFfKtRqJCOGIuQ==}
dev: true
/keyv/3.1.0:
resolution: {integrity: sha512-9ykJ/46SN/9KPM/sichzQ7OvXyGDYKGTaDlKMGCAlg2UK8KRy4jb0d8sFc+0Tt0YYnThq8X2RZgCg74RPxgcVA==}
dependencies:
json-buffer: 3.0.0
dev: true
/keyv/4.1.1:
resolution: {integrity: sha512-tGv1yP6snQVDSM4X6yxrv2zzq/EvpW+oYiUz6aueW1u9CtS8RzUQYxxmFwgZlO2jSgCxQbchhxaqXXp2hnKGpQ==}
dependencies:
@ -28066,13 +27854,6 @@ packages:
package-json: 4.0.1
dev: true
/latest-version/5.1.0:
resolution: {integrity: sha512-weT+r0kTkRQdCdYCNtkMwWXQTMEswKrFBkm4ckQOMVhhqhIMI1UT2hMj+1iigIhgSZm5gTmrRXBNoGUgaTY1xA==}
engines: {node: '>=8'}
dependencies:
package-json: 6.5.0
dev: true
/lazy-cache/0.2.7:
resolution: {integrity: sha1-f+3fLctu23fRHvHRF6tf/fCrG2U=}
engines: {node: '>=0.10.0'}
@ -28237,24 +28018,6 @@ packages:
resolution: {integrity: sha512-XPQH8Z2GDP/Hwz2PCDrh2mth4yFejwA1OZ/81Ti3LgKyhDcEjsSsqFWZojHG0va/duGd+WyosY7eXLDoOyqcPw==}
dev: true
/livereload-js/3.3.3:
resolution: {integrity: sha512-a7Jipme3XIBIryJluWP5LQrEAvhobDPyScBe+q+MYwxBiMT2Ck7msy4tAdF8TAa33FMdJqX4guP81Yhiu6BkmQ==}
dev: true
/livereload/0.9.3:
resolution: {integrity: sha512-q7Z71n3i4X0R9xthAryBdNGVGAO2R5X+/xXpmKeuPMrteg+W2U8VusTKV3YiJbXZwKsOlFlHe+go6uSNjfxrZw==}
engines: {node: '>=8.0.0'}
hasBin: true
dependencies:
chokidar: 3.5.3
livereload-js: 3.3.3
opts: 2.0.2
ws: 7.5.5
transitivePeerDependencies:
- bufferutil
- utf-8-validate
dev: true
/load-json-file/1.1.0:
resolution: {integrity: sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=}
engines: {node: '>=0.10.0'}
@ -28573,6 +28336,7 @@ packages:
/lowercase-keys/2.0.0:
resolution: {integrity: sha512-tqNXrS78oMOE73NMxK4EMLQsQowWf8jKooH9g7xPavRT706R6bkQJ6DY2Te7QukaZsulxa30wQ7bk0pm4XiHmA==}
engines: {node: '>=8'}
dev: false
/lowlight/1.20.0:
resolution: {integrity: sha512-8Ktj+prEb1RoCPkEOrPMYUN/nCggB7qAWe3a7OpMjWQkh3l2RD5wKRQ+o8Q8YuI9RG/xs95waaI/E6ym/7NsTw==}
@ -28803,12 +28567,6 @@ packages:
hasBin: true
dev: true
/marked/1.2.9:
resolution: {integrity: sha512-H8lIX2SvyitGX+TRdtS06m1jHMijKN/XjfH6Ooii9fvxMlh8QdqBfBDkGUpMWH2kQNrtixjzYUa3SH8ROTgRRw==}
engines: {node: '>= 8.16.2'}
hasBin: true
dev: true
/mathml-tag-names/2.1.3:
resolution: {integrity: sha512-APMBEanjybaPzUrfqU0IMU5I0AswKMH7k8OTLs0vvV4KZpExkTkY87nR/zpbuTPj+gARop7aGUbl11pnDfW6xg==}
dev: true
@ -28908,10 +28666,6 @@ packages:
engines: {node: '>= 0.6'}
dev: true
/medium-zoom/1.0.6:
resolution: {integrity: sha512-UdiUWfvz9fZMg1pzf4dcuqA0W079o0mpqbTnOz5ip4VGYX96QjmbM+OgOU/0uOzAytxC0Ny4z+VcYQnhdifimg==}
dev: true
/mem-fs-editor/9.4.0_mem-fs@2.2.1:
resolution: {integrity: sha512-HSSOLSVRrsDdui9I6i96dDtG+oAez/4EB2g4cjSrNhgNQ3M+L57/+22NuPdORSoxvOHjIg/xeOE+C0wwF91D2g==}
engines: {node: '>=12.10.0'}
@ -29188,6 +28942,7 @@ packages:
/mimic-response/1.0.1:
resolution: {integrity: sha512-j5EctnkH7amfV/q5Hgmoal1g2QHFJRraOtmx0JpIqkxhBhI/lJSl1nMpQ45hVarwNETOoWEimndZ4QK0RHxuxQ==}
engines: {node: '>=4'}
dev: false
/mimic-response/3.1.0:
resolution: {integrity: sha512-z0yWI+4FDrrweS8Zmt4Ej5HdJmky15+L2e6Wgn3+iK5fWzb6T3fhNFq2+MeTRb064c6Wr4N/wv0DzQTjNzHNGQ==}
@ -29871,11 +29626,6 @@ packages:
resolution: {integrity: sha512-U+JJi7duF1o+u2pynbp2zXDW2/PADgC30f0GsHZtRh+HOcXHnw137TrNlyxxRvWW5fjKd3bcLHPxofWuCjaeZg==}
engines: {node: '>=6'}
/normalize-url/4.5.1:
resolution: {integrity: sha512-9UZCFRHQdNrfTpGg8+1INIg93B6zE0aXMVFkw1WFwvO4SlZywU6aLg5Of0Ap/PgcbSw4LNxvMWXMeugwMCX0AA==}
engines: {node: '>=8'}
dev: true
/normalize-url/6.1.0:
resolution: {integrity: sha512-DlL+XwOy3NxAQ8xuC0okPgK46iuVNAK01YN7RueYBqqFeGsBjV9XmCAzAdgt+667bCl5kPh9EqKKDwnaPG1I7A==}
engines: {node: '>=10'}
@ -30260,13 +30010,6 @@ packages:
dependencies:
mimic-fn: 2.1.0
/open/6.4.0:
resolution: {integrity: sha512-IFenVPgF70fSm1keSd2iDBIDIBZkroLeuffXq+wKTzTJlBpesFWojV9lb8mzOfaAzM1sr7HQHuO0vtV0zYekGg==}
engines: {node: '>=8'}
dependencies:
is-wsl: 1.1.0
dev: true
/open/7.4.2:
resolution: {integrity: sha512-MVHddDVweXZF3awtlAS+6pgKLlm/JgxZ90+/NBurBoQctVOOB/zDdVjcyPzQ+0laDGbsWgrRkflI65sQeOgT9Q==}
engines: {node: '>=8'}
@ -30284,11 +30027,6 @@ packages:
is-wsl: 2.2.0
dev: true
/opencollective-postinstall/2.0.3:
resolution: {integrity: sha512-8AV/sCtuzUeTo8gQK5qDZzARrulB3egtLzFgteqB2tcT4Mw7B8Kt7JcDHmltjz6FOAHsvTevk70gZEbhM4ZS9Q==}
hasBin: true
dev: true
/opener/1.5.2:
resolution: {integrity: sha512-ur5UIdyw5Y7yEj9wLzhqXiy6GZ3Mwx0yGI+5sMn2r0N0v3cKJvUmFH5yPP+WXh9e0xfyzyJX95D8l088DNFj7A==}
hasBin: true
@ -30324,10 +30062,6 @@ packages:
word-wrap: 1.2.3
dev: true
/opts/2.0.2:
resolution: {integrity: sha512-k41FwbcLnlgnFh69f4qdUfvDQ+5vaSDnVPFI/y5XuhKRq97EnVVneO9F1ESVCdiVu4fCS2L8usX3mU331hB7pg==}
dev: true
/ora/5.4.1:
resolution: {integrity: sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==}
engines: {node: '>=10'}
@ -30380,11 +30114,6 @@ packages:
p-map: 2.1.0
dev: true
/p-cancelable/1.1.0:
resolution: {integrity: sha512-s73XxOZ4zpt1edZYZzvhqFa6uvQc1vwUa0K0BdtIZgQMAJj9IbebH+JkgKZc9h+B05PKHLOTl4ajG1BmNrVZlw==}
engines: {node: '>=6'}
dev: true
/p-cancelable/2.1.1:
resolution: {integrity: sha512-BZOr3nRQHOntUjTrH8+Lh54smKHoHyur8We1V8DSMVrl5A2malOOwuJRnKRDjSnkoeBh4at6BwEnb5I7Jl31wg==}
engines: {node: '>=8'}
@ -30544,16 +30273,6 @@ packages:
semver: 5.7.1
dev: true
/package-json/6.5.0:
resolution: {integrity: sha512-k3bdm2n25tkyxcjSKzB5x8kfVxlMdgsbPr0GkZcwHsLpba6cBjqCt1KlcChKEvxHIcTB1FVMuwoijZ26xex5MQ==}
engines: {node: '>=8'}
dependencies:
got: 9.6.0
registry-auth-token: 4.2.1
registry-url: 5.1.0
semver: 6.3.0
dev: true
/pacote/12.0.3:
resolution: {integrity: sha512-CdYEl03JDrRO3x18uHjBYA9TyoW8gy+ThVcypcDkxPtKlw76e4ejhYB6i9lJ+/cebbjpqPW/CijjqxwDTts8Ow==}
engines: {node: ^12.13.0 || ^14.15.0 || >=16}
@ -30617,11 +30336,6 @@ packages:
dependencies:
callsites: 3.1.0
/parent-require/1.0.0:
resolution: {integrity: sha1-dGoWdjgIOoYLDu9nMssn7UbDKXc=}
engines: {node: '>= 0.4.0'}
dev: true
/parse-asn1/5.1.6:
resolution: {integrity: sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==}
dependencies:
@ -31288,7 +31002,7 @@ packages:
postcss: 7.0.39
schema-utils: 3.1.1
semver: 7.3.5
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/postcss-loader/6.2.0_postcss@8.3.0+webpack@5.64.1:
@ -32280,11 +31994,6 @@ packages:
engines: {node: '>=0.10.0'}
dev: true
/prepend-http/2.0.0:
resolution: {integrity: sha1-6SQ0v6XqjBn0HN/UAddBo8gZ2Jc=}
engines: {node: '>=4'}
dev: true
/prettier-linter-helpers/1.0.0:
resolution: {integrity: sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==}
engines: {node: '>=6.0.0'}
@ -32544,13 +32253,6 @@ packages:
resolution: {integrity: sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==}
engines: {node: '>=6'}
/pupa/2.1.1:
resolution: {integrity: sha512-l1jNAspIBSFqbT+y+5FosojNpVpF94nlI+wDUpqP9enwOTfHx9f0gh5nB96vl+6yTpsJsypeNrwfzPrKuHB41A==}
engines: {node: '>=8'}
dependencies:
escape-goat: 2.1.1
dev: true
/puppeteer-core/1.12.2:
resolution: {integrity: sha512-M+atMV5e+MwJdR+OwQVZ1xqAIwh3Ou4nUxNuf334GwpcLG+LDj5BwIph4J9y8YAViByRtWGL+uF8qX2Ggzb+Fg==}
engines: {node: '>=6.4.0'}
@ -32761,7 +32463,7 @@ packages:
dependencies:
loader-utils: 2.0.2
schema-utils: 3.1.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/raw-loader/4.0.2_webpack@5.64.1:
@ -33993,13 +33695,6 @@ packages:
safe-buffer: 5.2.1
dev: true
/registry-auth-token/4.2.1:
resolution: {integrity: sha512-6gkSb4U6aWJB4SF2ZvLb76yCBjcvufXBqvvEx1HbmKPkutswjW1xNVRY0+daljIYRbogN7O0etYSlbiaEQyMyw==}
engines: {node: '>=6.0.0'}
dependencies:
rc: 1.2.8
dev: true
/registry-url/3.1.0:
resolution: {integrity: sha1-PU74cPc93h138M+aOBQyRE4XSUI=}
engines: {node: '>=0.10.0'}
@ -34007,13 +33702,6 @@ packages:
rc: 1.2.8
dev: true
/registry-url/5.1.0:
resolution: {integrity: sha512-8acYXXTI0AkQv6RAOjE3vOaIXZkT9wo4LOFbBKYQEEnnMNBpKqdUrI6S4NT0KPIo/WVvJ5tE/X5LF/TQUf0ekw==}
engines: {node: '>=8'}
dependencies:
rc: 1.2.8
dev: true
/regjsgen/0.5.2:
resolution: {integrity: sha512-OFFT3MfrH90xIW8OOSyUrk6QHD5E9JOTeGodiJeBS3J6IwlgzJMNE/1bZklWz5oTg+9dCMyEetclvCVXOPoN3A==}
@ -34332,6 +34020,7 @@ packages:
/resolve-pathname/3.0.0:
resolution: {integrity: sha512-C7rARubxI8bXFNB/hqcp/4iUeIXJhJZvFPFPiSPRnhU5UPxzMFIl+2E6yY6c4k9giDJAhtV+enfA+G89N6Csng==}
dev: false
/resolve-url/0.2.1:
resolution: {integrity: sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=}
@ -34357,12 +34046,6 @@ packages:
is-core-module: 2.8.0
path-parse: 1.0.7
/responselike/1.0.2:
resolution: {integrity: sha1-kYcg7ztjHFZCvgaPFa3lpG9Loec=}
dependencies:
lowercase-keys: 1.0.1
dev: true
/responselike/2.0.0:
resolution: {integrity: sha512-xH48u3FTB9VsZw7R+vvgaKeLKzT6jOogbQhEe/jewwnZgzPcnyWui2Av6JpoYZF/91uueC+lqhWqeURw5/qhCw==}
dependencies:
@ -34853,13 +34536,6 @@ packages:
semver: 5.7.1
dev: true
/semver-diff/3.1.1:
resolution: {integrity: sha512-GX0Ix/CJcHyB8c4ykpHGIAvLyOwOobtM/8d+TQkAd81/bEjgPHrfba41Vpesr7jX/t8Uh+R3EX9eAS5be+jQYg==}
engines: {node: '>=8'}
dependencies:
semver: 6.3.0
dev: true
/semver/5.7.1:
resolution: {integrity: sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ==}
hasBin: true
@ -35743,7 +35419,7 @@ packages:
dependencies:
loader-utils: 2.0.2
schema-utils: 2.7.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/style-loader/2.0.0_webpack@5.70.0:
@ -36409,11 +36085,6 @@ packages:
execa: 0.7.0
dev: true
/term-size/2.2.1:
resolution: {integrity: sha512-wK0Ri4fOGjv/XPy8SBHZChl8CM7uMc5VML7SqiQ0zG7+J5Vr+RMQDoHa2CNT6KHUnTGIXH34UDMkPzAUyapBZg==}
engines: {node: '>=8'}
dev: true
/terminal-link/2.1.1:
resolution: {integrity: sha512-un0FmiRUQNr5PJqy9kP7c40F5BOfpGlYTrxonDChEZB7pzZxRNp/bt+ymiy9/npwXya9KH99nJ/GXFIiUkYGFQ==}
engines: {node: '>=8'}
@ -36489,7 +36160,7 @@ packages:
serialize-javascript: 5.0.1
source-map: 0.6.1
terser: 5.10.0_acorn@7.4.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
webpack-sources: 1.4.3
transitivePeerDependencies:
- acorn
@ -36509,7 +36180,7 @@ packages:
serialize-javascript: 5.0.1
source-map: 0.6.1
terser: 5.10.0
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
webpack-sources: 1.4.3
transitivePeerDependencies:
- acorn
@ -36813,11 +36484,6 @@ packages:
resolution: {integrity: sha512-lBN9zLN/oAf68o3zNXYrdCt1kP8WsiGW8Oo2ka41b2IM5JL/S1CTyX1rW0mb/zSuJun0ZUrDxx4sqvYS2FWzPA==}
dev: false
/tinydate/1.3.0:
resolution: {integrity: sha512-7cR8rLy2QhYHpsBDBVYnnWXm8uRTr38RoZakFSW7Bs7PzfMPNZthuMLkwqZv7MTu8lhQ91cOFYS5a7iFj2oR3w==}
engines: {node: '>=4'}
dev: true
/title-case/1.1.2:
resolution: {integrity: sha1-+uSmrlRr+iLQg6DuqRCkDRLtT1o=}
dependencies:
@ -36867,11 +36533,6 @@ packages:
dependencies:
kind-of: 3.2.2
/to-readable-stream/1.0.0:
resolution: {integrity: sha512-Iq25XBt6zD5npPhlLVXGFN3/gyR2/qODcKNNyTMd4vbm39HUaOiAM4PMq0eMVC/Tkxz+Zjdsc55g9yyz+Yq00Q==}
engines: {node: '>=6'}
dev: true
/to-regex-range/2.1.1:
resolution: {integrity: sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=}
engines: {node: '>=0.10.0'}
@ -37280,10 +36941,6 @@ packages:
/tweetnacl/0.14.5:
resolution: {integrity: sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=}
/tweezer.js/1.5.0:
resolution: {integrity: sha512-aSiJz7rGWNAQq7hjMK9ZYDuEawXupcCWgl3woQQSoDP2Oh8O4srWb/uO1PzzHIsrPEOqrjJ2sUb9FERfzuBabQ==}
dev: true
/type-check/0.3.2:
resolution: {integrity: sha1-WITKtRLPHTVeP7eE8wgEsrUg23I=}
engines: {node: '>= 0.8.0'}
@ -37519,13 +37176,6 @@ packages:
crypto-random-string: 1.0.0
dev: true
/unique-string/2.0.0:
resolution: {integrity: sha512-uNaeirEPvpZWSgzwsPGtU2zVSTrn/8L5q/IexZmH0eH6SA73CmAA5U4GwORTxQAZs95TAXLNqeLoPPNO5gZfWg==}
engines: {node: '>=8'}
dependencies:
crypto-random-string: 2.0.0
dev: true
/unist-builder/2.0.3:
resolution: {integrity: sha512-f98yt5pnlMWlzP539tPc4grGMsFaQQlP/vM396b00jngsiINumNmsY8rkXjfoi1c6QaM8nQ3vaGDuoKWbe/1Uw==}
dev: true
@ -37665,25 +37315,6 @@ packages:
xdg-basedir: 3.0.0
dev: true
/update-notifier/4.1.3:
resolution: {integrity: sha512-Yld6Z0RyCYGB6ckIjffGOSOmHXj1gMeE7aROz4MG+XMkmixBX4jUngrGXNYz7wPKBmtoD4MnBa2Anu7RSKht/A==}
engines: {node: '>=8'}
dependencies:
boxen: 4.2.0
chalk: 3.0.0
configstore: 5.0.1
has-yarn: 2.1.0
import-lazy: 2.1.0
is-ci: 2.0.0
is-installed-globally: 0.3.2
is-npm: 4.0.0
is-yarn-global: 0.3.0
latest-version: 5.1.0
pupa: 2.1.1
semver-diff: 3.1.1
xdg-basedir: 4.0.0
dev: true
/upper-case-first/1.1.2:
resolution: {integrity: sha1-XXm+3P8UQZUY/S7bCgUHybaFkRU=}
dependencies:
@ -37754,7 +37385,7 @@ packages:
loader-utils: 2.0.2
mime-types: 2.1.34
schema-utils: 3.1.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/url-parse-lax/1.0.0:
@ -37764,13 +37395,6 @@ packages:
prepend-http: 1.0.4
dev: true
/url-parse-lax/3.0.0:
resolution: {integrity: sha1-FrXK/Afb42dsGxmZF3gj1lA6yww=}
engines: {node: '>=4'}
dependencies:
prepend-http: 2.0.0
dev: true
/url/0.10.3:
resolution: {integrity: sha1-Ah5NnHcF8hu/N9A861h2dAJ3TGQ=}
dependencies:
@ -38302,7 +37926,7 @@ packages:
mime: 2.5.2
mkdirp: 0.5.5
range-parser: 1.2.1
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
webpack-log: 2.0.0
dev: true
@ -38385,7 +38009,7 @@ packages:
peerDependencies:
webpack: ^2.0.0 || ^3.0.0 || ^4.0.0
dependencies:
webpack: 4.46.0_webpack-cli@4.9.2
webpack: 4.46.0_webpack-cli@3.3.12
dev: true
/webpack-fix-style-only-entries/0.6.1:
@ -38569,7 +38193,7 @@ packages:
tapable: 1.1.3
terser-webpack-plugin: 1.4.5_webpack@4.46.0
watchpack: 1.7.5
webpack-cli: 3.3.12_webpack@4.46.0
webpack-cli: 3.3.12_webpack@5.70.0
webpack-sources: 1.4.3
dev: true
@ -39078,11 +38702,6 @@ packages:
engines: {node: '>=4'}
dev: true
/xdg-basedir/4.0.0:
resolution: {integrity: sha512-PSNhEJDejZYV7h50BohL09Er9VaIefr2LMAf3OEmpCkjOi34eYyQYAXUTjEQtZJTKcF0E2UKTh+osDLsgNim9Q==}
engines: {node: '>=8'}
dev: true
/xml-name-validator/3.0.0:
resolution: {integrity: sha512-A5CUptxDsvxKJEU3yO6DuWBSJz/qizqzJKOMIfUJHETbBw/sFaDxgd6fxm1ewUaM0jZ444Fc5vC5ROYurg/4Pw==}
@ -39140,14 +38759,6 @@ packages:
resolution: {integrity: sha512-r3vXyErRCYJ7wg28yvBY5VSoAF8ZvlcW9/BwUzEtUsjvX/DKs24dIkuwjtuprwJJHsbyUbLApepYTR1BN4uHrg==}
engines: {node: '>= 6'}
/yargonaut/1.1.4:
resolution: {integrity: sha512-rHgFmbgXAAzl+1nngqOcwEljqHGG9uUZoPjsdZEs1w5JW9RXYzrSvH/u70C1JE5qFi0qjsdhnUX/dJRpWqitSA==}
dependencies:
chalk: 1.1.3
figlet: 1.5.2
parent-require: 1.0.0
dev: true
/yargs-parser/13.1.2:
resolution: {integrity: sha512-3lbsNRf/j+A4QuSZfDRA7HRSfWrzO0YjqTJd5kjAq37Zep1CEgaYmrH9Q3GwPiB9cHyd1Y1UwggGhJGoxipbzg==}
dependencies: