Merge branch 'trunk' into patch-7

This commit is contained in:
Seghir Nadir 2024-09-18 14:16:25 +02:00 committed by GitHub
commit eeb262e3ea
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2930 changed files with 104367 additions and 127288 deletions

View File

@ -0,0 +1,78 @@
# How to update
## Source code
This action is extracted and bundled version of the following:
Repository: https://github.com/WordPress/gutenberg/tree/trunk/packages/report-flaky-tests
Commit ID: ce803384250671d01fde6c7d6d2aa83075fcc726
## How to build
After checking out the repository, navigate to packages/report-flaky-tests and do some modifications:
### package.json file
Add the following dependency: `"ts-loader": "^9.5.1",`.
### tsconfig.json file
The file context should be updated to following state:
```
{
"$schema": "https://json.schemastore.org/tsconfig.json",
"extends": "../../tsconfig.base.json",
"compilerOptions": {
"outDir": "dist",
"target": "es6",
"module": "commonjs",
"esModuleInterop": true,
"moduleResolution": "node",
"declarationDir": "build-types",
"rootDir": "src",
"emitDeclarationOnly": false,
},
"include": [ "src/**/*" ],
"exclude": [ "src/__tests__/**/*", "src/__fixtures__/**/*" ]
}
```
### webpack.config.js file
The file should be added with the following content:
```
const path = require( 'path' );
const buildMode = process.env.NODE_ENV || 'production';
module.exports = {
entry: './src/index.ts',
target: 'node',
mode: buildMode,
module: {
rules: [
{
test: /\.tsx?$/,
use: 'ts-loader',
exclude: /node_modules/,
},
],
},
resolve: {
extensions: [ '.tsx', '.ts', '.js' ],
},
plugins: [],
output: {
filename: 'index.js',
path: path.resolve( __dirname, 'dist' ),
clean: true,
},
};
```
### Build
Run `webpack --config webpack.config.js` (don't forget about `npm install` before that).
Use the generated files under `packages/report-flaky-tests/dist` to update the bundled distribution in this repository.

View File

@ -22,14 +22,14 @@ inputs:
runs:
using: 'composite'
steps:
- name: 'Read PNPM Version'
id: 'read-pnpm-version'
shell: 'bash'
run: 'echo "version=$(./.github/actions/setup-woocommerce-monorepo/scripts/read-pnpm-version.sh package.json)" >> $GITHUB_OUTPUT'
- name: 'Setup PNPM'
uses: 'pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d'
with:
version: ${{ steps.read-pnpm-version.outputs.version }}
# Next step is rudimentary - fixes a know composite action bug during post-actions:
# Error: Index was out of range. Must be non-negative and less than the size of the collection.
- name: 'Read PNPM version'
id: 'read-pnpm-version'
shell: 'bash'
run: 'echo "version=$(pnpm --version)" >> $GITHUB_OUTPUT'
- name: 'Setup Node'
uses: 'actions/setup-node@8f152de45cc393bb48ce5d89d36b731f54556e65'
with:

View File

@ -1,9 +0,0 @@
#!/usr/bin/env bash
PACKAGE_FILE=$1
if [[ -z "$PACKAGE_FILE" ]]; then
echo "Usage: $0 <package.json>"
exit 1
fi
awk -F'"' '/"pnpm": ".+"/{ print $4; exit; }' $PACKAGE_FILE

View File

@ -17,9 +17,9 @@ when:
- woo-fse
- author:
teamIs:
- vortex
- flux
ignore:
nameIs:
assign:
teams:
- vortex
- flux

View File

@ -31,24 +31,25 @@
- team: vortex
"packages/js/components/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"packages/js/csv-export/**/*":
- team: mothra
- team: woo-fse
"packages/js/currency/**/*":
- team: mothra
- team: woo-fse
"packages/js/customer-effort-score/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"packages/js/data/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"packages/js/date/**/*":
- team: mothra
- team: woo-fse
"packages/js/dependency-extraction-webpack-plugin/**/*":
- team: vortex
@ -57,26 +58,27 @@
- team: vortex
"packages/js/experimental/**/*":
- team: mothra
- team: woo-fse
"packages/js/explat/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"packages/js/navigation/**/*":
- team: mothra
- team: woo-fse
"packages/js/number/**/*":
- team: mothra
- team: woo-fse
"packages/js/onboarding/**/*":
- team: ghidorah
"packages/js/product-editor/**/*":
- team: mothra
- team: woo-fse
"packages/js/tracks/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"plugins/woocommerce/**/*":
- team: proton
@ -89,7 +91,7 @@
- team: proton
"plugins/woocommerce/src/Admin/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"plugins/woocommerce/src/Blocks/**/*":
@ -97,7 +99,7 @@
- team: woo-fse
"plugins/woocommerce/src/Internal/Admin/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"plugins/woocommerce/src/StoreApi/**/*":
@ -105,7 +107,7 @@
- team: woo-fse
"plugins/woocommerce-admin/**/*":
- team: mothra
- team: woo-fse
- team: ghidorah
"plugins/woocommerce-blocks/**/*":

View File

@ -31,7 +31,7 @@ jobs:
run: unzip plugins/woocommerce/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

View File

@ -16,7 +16,8 @@ on:
type: string
concurrency:
group: '${{ github.workflow }}-${{ github.ref }}'
# Cancel concurrent jobs but not for push event. For push use the run_id to have a unique group.
group: ci-${{ github.event_name == 'push' && github.run_id || github.event_name }}-${{ github.ref }}-${{ inputs.trigger }}
cancel-in-progress: true
env:
@ -38,16 +39,20 @@ jobs:
- uses: 'actions/checkout@v4'
name: 'Checkout'
with:
fetch-depth: 0
- uses: './.github/actions/setup-woocommerce-monorepo'
name: 'Setup Monorepo'
with:
php-version: false # We don't want to waste time installing PHP since we aren't using it in this job.
# If 'base_ref' is available, the 'Build Matrix' step requires non-shallow git-history to identify changed files.
fetch-depth: ${{ ( ( github.base_ref && '0' ) || '1' ) }}
- name: 'Setup PNPM'
uses: 'pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d'
- uses: actions/github-script@v7
name: 'Build Matrix'
id: 'project-jobs'
with:
script: |
// Intended behaviour of the jobs generation:
// - PRs: run CI jobs aiming PRs and filter out jobs based on the content changes
// - Pushes: run CI jobs aiming pushes without filtering based on the content changes
// github.base_ref is only available for pull_request events
let baseRef = ${{ toJson( github.base_ref ) }};
if ( baseRef ) {
baseRef = `--base-ref origin/${ baseRef }`;
@ -71,6 +76,12 @@ jobs:
githubEvent = trigger;
}
// `pre-release` should trigger `release-checks`, but without a 'tag' ref.
// This will run all release-checks against the branch the workflow targeted, instead of a release artifact.
if ( trigger === 'pre-release' ) {
githubEvent = 'release-checks';
}
const child_process = require( 'node:child_process' );
child_process.execSync( `pnpm utils ci-jobs ${ baseRef } --event ${ githubEvent }` );
@ -87,7 +98,8 @@ jobs:
- uses: 'actions/checkout@v4'
name: 'Checkout'
with:
fetch-depth: 0
# the WooCommerce plugin package uses phpcs-changed for linting, which requires non-shallow git-history.
fetch-depth: ${{ ( ( matrix.projectName == '@woocommerce/plugin-woocommerce' && '0' ) || '1' ) }}
- uses: './.github/actions/setup-woocommerce-monorepo'
name: 'Setup Monorepo'
@ -138,37 +150,92 @@ jobs:
env: ${{ matrix.testEnv.envVars }}
run: 'pnpm --filter="${{ matrix.projectName }}" ${{ matrix.testEnv.start }}'
- name: 'Get commit message'
id: 'get_commit_message'
- name: 'Determine BuildKite Analytics Message'
env:
HEAD_COMMIT_MESSAGE: ${{ github.event.head_commit.message }}
PR_TITLE: ${{ github.event.pull_request.title }}
run: |
if [[ "${{ github.event_name }}" == "push" ]]; then
COMMIT_MESSAGE=`echo "$HEAD_COMMIT_MESSAGE" | head -1`
MESSAGE=`echo "$HEAD_COMMIT_MESSAGE" | head -1`
elif [[ "${{ github.event_name }}" == "pull_request" ]]; then
COMMIT_MESSAGE="$PR_TITLE"
MESSAGE="$PR_TITLE"
else
COMMIT_MESSAGE="${{ github.event_name }}"
MESSAGE="${{ github.event_name }}"
fi
echo "COMMIT_MESSAGE=$COMMIT_MESSAGE" >> "$GITHUB_OUTPUT"
echo "BUILDKITE_ANALYTICS_MESSAGE=$MESSAGE" >> "$GITHUB_ENV"
shell: bash
- name: 'Run tests (${{ matrix.testType }})'
env:
E2E_ENV_KEY: ${{ secrets.E2E_ENV_KEY }}
BUILDKITE_ANALYTICS_TOKEN: ${{ secrets.BUILDKITE_CORE_E2E_TOKEN }}
BUILDKITE_ANALYTICS_MESSAGE: ${{ steps.get_commit_message.outputs.COMMIT_MESSAGE }}
CODEVITALS_PROJECT_TOKEN: ${{ secrets.CODEVITALS_PROJECT_TOKEN }} # required by Metrics tests
run: 'pnpm --filter="${{ matrix.projectName }}" ${{ matrix.command }}'
- name: 'Resolve artifacts path'
if: ${{ always() && matrix.report.resultsPath != '' }}
# Blocks e2e use a relative path which is not supported by actions/upload-artifact@v4
# https://github.com/actions/upload-artifact/issues/176
env:
ARTIFACTS_PATH: '${{ matrix.projectPath }}/${{ matrix.report.resultsPath }}'
run: echo "ARTIFACTS_PATH=$(realpath $ARTIFACTS_PATH)" >> $GITHUB_ENV
run: |
# first runs will probably not have the directory, so we need to create it so that realpath doesn't fail
mkdir -p $ARTIFACTS_PATH
echo "ARTIFACTS_PATH=$(realpath $ARTIFACTS_PATH)" >> $GITHUB_ENV
- name: 'Download Playwright last run info'
id: 'download-last-run-info'
if: ${{ always() && matrix.report.resultsPath != '' && matrix.testType == 'e2e' }}
uses: actions/download-artifact@v4
with:
pattern: 'last-run__${{ strategy.job-index }}'
- name: 'Run tests (${{ matrix.testType }})'
env:
E2E_ENV_KEY: ${{ secrets.E2E_ENV_KEY }}
BUILDKITE_ANALYTICS_TOKEN: ${{ secrets.BUILDKITE_CORE_E2E_TOKEN }}
CODEVITALS_PROJECT_TOKEN: ${{ secrets.CODEVITALS_PROJECT_TOKEN }} # required by Metrics tests
LAST_FAILED_RUN: ${{ vars.LAST_FAILED_RUN }}
run: |
lastRunFile="${{ steps.download-last-run-info.outputs.download-path }}/last-run__${{ strategy.job-index }}/.last-run.json"
lastRunFileDest="$ARTIFACTS_PATH/.last-run.json"
if [ -f "$lastRunFile" ]; then
echo "Found last run info file: \"$lastRunFile\""
echo "Moving to destination: \"$lastRunFileDest\""
mkdir -p "$ARTIFACTS_PATH"
mv "$lastRunFile" "$lastRunFileDest"
else
echo "No last run info file found. Searched for: \"$lastRunFile\""
fi
lastRunFlag=""
if [ -f "$lastRunFileDest" ]; then
# Playwright last run info is available, parse the file and check if there are failed tests
cat "$lastRunFileDest"
failedTests=$(jq '.failedTests | length' "$lastRunFileDest")
# Only if there are failed tests, we want to use the --last-failed flag.
# The run will fail if we're using the flag and there are no failed tests.
if [ "$failedTests" -gt 0 ]; then
if [ "$LAST_FAILED_RUN" == "1" ]; then
echo "Found failed tests, running only failed tests"
# Add shard 1/1 to override the default shard value. No tests will run for shards > 1.
# The clean way would be to replace the shard flag from the command, but this also works.
lastRunFlag="--last-failed --shard=1/1"
else
echo "Found failed tests, but LAST_FAILED_RUN is switched off. Running all tests."
fi
else
echo "No failed tests found, running all tests"
fi
fi
# Finally, run the tests
pnpm --filter="${{ matrix.projectName }}" ${{ matrix.command }} $lastRunFlag
- name: 'Upload Playwright last run info'
# always upload the last run info, even if the test run passed
if: ${{ always() && matrix.report.resultsPath != '' }}
uses: actions/upload-artifact@v4
with:
name: 'last-run__${{ strategy.job-index }}'
path: '${{ env.ARTIFACTS_PATH }}/.last-run.json'
if-no-files-found: ignore
overwrite: true
- name: 'Upload artifacts'
if: ${{ always() && matrix.report.resultsPath != '' }}
@ -183,15 +250,6 @@ jobs:
name: flaky-tests-${{ strategy.job-index }}
path: ${{ env.ARTIFACTS_PATH }}/flaky-tests
if-no-files-found: ignore
- name: 'Archive metrics results'
if: ${{ success() && startsWith(matrix.name, 'Metrics') }} # this seems too fragile, we should update the reporting path and use the generic upload step above
uses: actions/upload-artifact@v4
env:
WP_ARTIFACTS_PATH: ${{ github.workspace }}/artifacts
with:
name: metrics-results
path: ${{ env.WP_ARTIFACTS_PATH }}/*.performance-results*.json
evaluate-project-jobs:
# In order to add a required status check we need a consistent job that we can grab onto.
@ -241,10 +299,8 @@ jobs:
- uses: 'actions/checkout@v4'
name: 'Checkout'
- uses: './.github/actions/setup-woocommerce-monorepo'
name: 'Setup Monorepo'
with:
php-version: false
- name: 'Setup PNPM'
uses: 'pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d'
- name: 'Send messages for failed jobs'
env:

View File

@ -4,23 +4,25 @@ on:
- cron: '0 0 * * *' # Run at 12 AM UTC.
workflow_dispatch:
permissions: {}
env:
SOURCE_REF: trunk
TARGET_REF: nightly
RELEASE_ID: 25945111
permissions: { }
jobs:
build:
if: github.repository_owner == 'woocommerce'
name: Nightly builds
strategy:
fail-fast: false
matrix:
build: [trunk]
runs-on: ubuntu-20.04
permissions:
contents: write
steps:
- uses: actions/checkout@v3
- uses: actions/checkout@v4
with:
ref: ${{ matrix.build }}
ref: ${{ env.SOURCE_REF }}
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
@ -31,26 +33,31 @@ jobs:
working-directory: plugins/woocommerce
run: bash bin/build-zip.sh
- name: Deploy nightly build
uses: WebFreak001/deploy-nightly@v1.1.0
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
- name: Upload nightly build
uses: WebFreak001/deploy-nightly@46ecbabd7fad70d3e7d2c97fe8cd54e7a52e215b #v3.2.0
with:
upload_url: https://uploads.github.com/repos/${{ github.repository }}/releases/25945111/assets{?name,label}
release_id: 25945111
token: ${{ secrets.GITHUB_TOKEN }}
upload_url: https://uploads.github.com/repos/${{ github.repository }}/releases/${{ env.RELEASE_ID }}/assets{?name,label}
release_id: ${{ env.RELEASE_ID }}
asset_path: plugins/woocommerce/woocommerce.zip
asset_name: woocommerce-${{ matrix.build }}-nightly.zip
asset_name: woocommerce-${{ env.SOURCE_REF }}-nightly.zip
asset_content_type: application/zip
max_releases: 1
update:
name: Update nightly tag commit ref
runs-on: ubuntu-20.04
permissions:
contents: write
steps:
- name: Update nightly tag
uses: richardsimko/github-tag-action@v1.0.5
- name: Update nightly tag commit ref
uses: actions/github-script@v7
with:
tag_name: nightly
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const sourceRef = process.env.SOURCE_REF;
const targetRef = process.env.TARGET_REF;
const branchData = await github.rest.repos.getBranch({
...context.repo,
branch: sourceRef,
});
await github.rest.git.updateRef({
...context.repo,
ref: `tags/${ targetRef }`,
sha: branchData.data.commit.sha,
});

View File

@ -41,9 +41,7 @@ jobs:
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
with:
# Both install and build are handled by compressed-size-action.
install: false
build: false
php-version: false
pull-package-deps: '@woocommerce/plugin-woocommerce'
- uses: preactjs/compressed-size-action@f780fd104362cfce9e118f9198df2ee37d12946c
@ -52,7 +50,7 @@ jobs:
with:
repo-token: '${{ secrets.GITHUB_TOKEN }}'
pattern: './{packages/js/!(*e2e*|*internal*|*test*|*plugin*|*create*),plugins/woocommerce-blocks}/{build,build-style}/**/*.{js,css}'
install-script: 'pnpm install --filter="@woocommerce/plugin-woocommerce..." --frozen-lockfile --config.dedupe-peer-dependents=false'
install-script: 'pnpm install --filter="@woocommerce/plugin-woocommerce..." --frozen-lockfile --config.dedupe-peer-dependents=false --ignore-scripts'
build-script: '--filter="@woocommerce/plugin-woocommerce" build'
clean-script: '--if-present buildclean'
minimum-change-threshold: 100

View File

@ -0,0 +1,102 @@
name: Performance metrics
on:
pull_request:
paths:
- 'plugins/woocommerce/composer.*'
- 'plugins/woocommerce/client/admin/config/**'
- 'plugins/woocommerce/includes/**'
- 'plugins/woocommerce/lib/**'
- 'plugins/woocommerce/patterns/**'
- 'plugins/woocommerce/src/**'
- 'plugins/woocommerce/templates/**'
- 'plugins/woocommerce/tests/metrics/**'
- 'plugins/woocommerce/.wp-env.json'
- '.github/workflows/pr-assess-performance.yml'
concurrency:
group: ${{ github.workflow }}-${{ github.event_name == 'pull_request' && github.head_ref || github.sha }}
cancel-in-progress: true
env:
WP_ARTIFACTS_PATH: ${{ github.workspace }}/tools/compare-perf/artifacts/
jobs:
benchmark:
name: Evaluate performance metrics
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
name: Checkout (${{ github.event_name == 'pull_request' && github.head_ref || github.sha }})
with:
fetch-depth: 0
- uses: ./.github/actions/setup-woocommerce-monorepo
name: Install Monorepo
with:
install: '@woocommerce/plugin-woocommerce...'
build: '@woocommerce/plugin-woocommerce'
build-type: 'full'
pull-playwright-cache: true
pull-package-deps: '@woocommerce/plugin-woocommerce'
#TODO: Inject WordPress version as per plugin requirements (relying to defaults currently).
- name: Start Test Environment
run: |
pnpm --filter="@woocommerce/plugin-woocommerce" test:e2e:install &
pnpm --filter="@woocommerce/plugin-woocommerce" env:test
# TODO: cache results if pushed to trunk
- name: Measure performance (@${{ github.sha }})
run: |
RESULTS_ID="editor_${{ github.sha }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics editor
RESULTS_ID="product-editor_${{ github.sha }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics product-editor
# In alignment with .github/workflows/scripts/run-metrics.sh, we should checkout 3d7d7f02017383937f1a4158d433d0e5d44b3dc9
# as baseline. But to avoid switching branches in 'Analyze results' step, we pick 55f855a2e6d769b5ae44305b2772eb30d3e721df
# which introduced reporting mode for the perf utility.
- name: Checkout (55f855a2e6d769b5ae44305b2772eb30d3e721df@trunk, further references as 'baseline')
run: |
git reset --hard && git checkout 55f855a2e6d769b5ae44305b2772eb30d3e721df
echo "WC_TRUNK_SHA=55f855a2e6d769b5ae44305b2772eb30d3e721df" >> $GITHUB_ENV
# Artifacts download/upload would be more reliable, but we couldn't make it working...
- uses: actions/cache@ab5e6d0c87105b4c9c2047343972218f562e4319
name: Cache measurements (baseline)
with:
path: tools/compare-perf/artifacts/*_${{ env.WC_TRUNK_SHA }}_*
key: ${{ runner.os }}-woocommerce-performance-measures-${{ env.WC_TRUNK_SHA }}
- name: Verify cached measurements (baseline)
run: |
if test -n "$(find tools/compare-perf/artifacts/ -maxdepth 1 -name '*_${{ env.WC_TRUNK_SHA }}_*' -print -quit)"
then
echo "WC_MEASURE_BASELINE=no" >> $GITHUB_ENV
else
ls -l tools/compare-perf/artifacts/
echo "Triggering baseline benchmarking"
echo "WC_MEASURE_BASELINE=yes" >> $GITHUB_ENV
fi
- name: Build (baseline)
if: ${{ env.WC_MEASURE_BASELINE == 'yes' }}
run: |
git clean -n -d -X ./packages ./plugins | grep -v vendor | grep -v node_modules | sed -e 's/Would remove //g' | tr '\n' '\0' | xargs -0 rm -r
pnpm install --filter='@woocommerce/plugin-woocommerce...' --frozen-lockfile --config.dedupe-peer-dependents=false
pnpm --filter='@woocommerce/plugin-woocommerce' build
#TODO: is baseline Wordpress version changes, restart environment targeting it.
- name: Measure performance (@${{ env.WC_TRUNK_SHA }})
if: ${{ env.WC_MEASURE_BASELINE == 'yes' }}
run: |
RESULTS_ID="editor_${{ env.WC_TRUNK_SHA }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics editor
RESULTS_ID="product-editor_${{ env.WC_TRUNK_SHA }}_round-1" pnpm --filter="@woocommerce/plugin-woocommerce" test:metrics product-editor
- name: Analyze results
run: |
pnpm install --filter='compare-perf...' --frozen-lockfile --config.dedupe-peer-dependents=false
pnpm --filter="compare-perf" run compare compare-performance ${{ github.sha }} ${{ env.WC_TRUNK_SHA }} --tests-branch ${{ github.sha }} --skip-benchmarking
# TODO: Publish to CodeVitals (see .github/workflows/scripts/run-metrics.sh) if pushed to trunk

View File

@ -3,6 +3,7 @@ on:
pull_request:
paths:
- 'plugins/woocommerce/**'
- '!plugins/woocommerce/templates/templates/**'
jobs:
analyze:
name: 'Analyze Branch Changes'
@ -26,7 +27,7 @@ jobs:
GIT_CLONE_PROTECTION_ACTIVE: false
run: |
HEAD_REF=$(git rev-parse HEAD)
exclude="plugins/woocommerce/tests plugins/woocommerce-admin/tests plugins/woocommerce-blocks/tests"
exclude="plugins/woocommerce/tests plugins/woocommerce/templates/templates plugins/woocommerce-admin/tests plugins/woocommerce-blocks/tests"
version=$(pnpm analyzer major-minor "$HEAD_REF" "plugins/woocommerce/woocommerce.php" | tail -n 1)
pnpm analyzer "$HEAD_REF" $version -o "github" -e $exclude
- uses: 'actions/github-script@v6'

View File

@ -38,9 +38,7 @@ jobs:
docs/docs-manifest.json
- name: Setup PNPM
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
version: '8.6.7'
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
- name: Setup Node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c

View File

@ -31,7 +31,6 @@ jobs:
issues: write
pull-requests: write
outputs:
pnpmVersion: ${{ steps.read-pnpm-version.outputs.version }}
isTodayAcceleratedFreeze: ${{ steps.get-versions.outputs.isTodayAcceleratedFreeze }}
isTodayMonthlyFreeze: ${{ steps.get-versions.outputs.isTodayMonthlyFreeze }}
acceleratedVersion: ${{ steps.get-versions.outputs.acceleratedVersion }}
@ -47,18 +46,8 @@ jobs:
with:
fetch-depth: 0
- name: Read PNPM Version
id: read-pnpm-version
shell: bash
run: |
version=$(./.github/actions/setup-woocommerce-monorepo/scripts/read-pnpm-version.sh package.json)
echo "version=$version" >> $GITHUB_OUTPUT
echo "PNPM Version: $version"
- name: Setup PNPM
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
version: ${{ steps.read-pnpm-version.outputs.version }}
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
- name: Setup Node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
@ -149,9 +138,7 @@ jobs:
fetch-depth: 0
- name: Setup PNPM
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
version: ${{ needs.code-freeze-prep.outputs.pnpmVersion }}
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
- name: Setup Node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
@ -199,7 +186,7 @@ jobs:
run: bash bin/build-zip.sh
- name: Upload the zip file as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -229,7 +216,7 @@ jobs:
run: bash bin/build-zip.sh
- name: Upload the zip file as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -244,7 +231,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayMonthlyFreeze == 'yes' }}
steps:
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -275,9 +262,7 @@ jobs:
fetch-depth: 0
- name: Setup PNPM
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
version: ${{ needs.code-freeze-prep.outputs.pnpmVersion }}
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
- name: Setup Node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
@ -294,7 +279,7 @@ jobs:
working-directory: tools/monorepo-utils
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -315,7 +300,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayAcceleratedFreeze == 'yes' }}
steps:
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -346,9 +331,7 @@ jobs:
fetch-depth: 0
- name: Setup PNPM
uses: pnpm/action-setup@fe02b34f77f8bc703788d5817da081398fad5dd2
with:
version: ${{ needs.code-freeze-prep.outputs.pnpmVersion }}
uses: pnpm/action-setup@a3252b78c470c02df07e9d59298aecedc3ccdd6d
- name: Setup Node
uses: actions/setup-node@64ed1c7eab4cce3362f8c340dee64e5eaeef8f7c
@ -365,7 +348,7 @@ jobs:
working-directory: tools/monorepo-utils
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -386,7 +369,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayMonthlyFreeze == 'yes' }}
steps:
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -397,7 +380,7 @@ jobs:
run: unzip ${{ steps.download.outputs.download-path }}/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -412,7 +395,7 @@ jobs:
if: ${{ needs.code-freeze-prep.outputs.isTodayAcceleratedFreeze == 'yes' }}
steps:
- id: download
uses: actions/download-artifact@v3
uses: actions/download-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:
@ -423,7 +406,7 @@ jobs:
run: unzip ${{ steps.download.outputs.download-path }}/woocommerce.zip -d zipfile
- name: Upload the zip file as an artifact
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
with:

View File

@ -20,14 +20,10 @@ jobs:
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
with:
install: '@woocommerce/plugin-woocommerce'
build: '@woocommerce/plugin-woocommerce'
install: '@woocommerce/plugin-woocommerce-beta-tester...'
build: '@woocommerce/plugin-woocommerce-beta-tester...'
pull-package-deps: '@woocommerce/plugin-woocommerce-beta-tester'
- name: Lint
working-directory: plugins/woocommerce-beta-tester
run: composer run phpcs
- name: Build WooCommerce Beta Tester Zip
working-directory: plugins/woocommerce-beta-tester
run: pnpm build:zip

View File

@ -2,30 +2,49 @@
set -eo pipefail
function title() {
echo -e "\n\033[1m$1\033[0m"
}
if [[ -z "$GITHUB_EVENT_NAME" ]]; then
echo "::error::GITHUB_EVENT_NAME must be set"
exit 1
fi
title "Installing NVM"
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.39.1/install.sh | bash > /dev/null
export NVM_DIR="$HOME/.nvm"
[ -s "$NVM_DIR/nvm.sh" ] && \. "$NVM_DIR/nvm.sh"
echo "Installed version: $(nvm -v)"
title "Installing dependencies"
pnpm install --frozen-lockfile --filter="compare-perf" > /dev/null
if [[ "$GITHUB_EVENT_NAME" == "pull_request" ]]; then
echo "Comparing performance with trunk"
title "Comparing performance with trunk"
pnpm --filter="compare-perf" run compare perf $GITHUB_SHA trunk --tests-branch $GITHUB_SHA
elif [[ "$GITHUB_EVENT_NAME" == "push" ]]; then
echo "Comparing performance with base branch"
# The base hash used here need to be a commit that is compatible with the current WP version
# The current one is 19f3d0884617d7ecdcf37664f648a51e2987cada
# it needs to be updated every time it becomes unsupported by the current wp-env (WP version).
# It is used as a base comparison point to avoid fluctuation in the performance metrics.
title "Comparing performance with base branch"
WP_VERSION=$(awk -F ': ' '/^Tested up to/{print $2}' readme.txt)
# Updating the WP version used for performance jobs means theres a high
# chance that the reference commit used for performance test stability
# becomes incompatible with the WP version. So, every time the "Tested up
# to" flag is updated in the readme.txt, we also have to update the
# reference commit below (BASE_SHA). The new reference needs to meet the
# following requirements:
# - Be compatible with the new WP version used in the “Tested up to” flag.
# - Be tracked on https://www.codevitals.run/project/woo for all existing
# metrics.
BASE_SHA=3d7d7f02017383937f1a4158d433d0e5d44b3dc9
echo "WP_VERSION: $WP_VERSION"
IFS=. read -ra WP_VERSION_ARRAY <<< "$WP_VERSION"
WP_MAJOR="${WP_VERSION_ARRAY[0]}.${WP_VERSION_ARRAY[1]}"
pnpm --filter="compare-perf" run compare perf $GITHUB_SHA 19f3d0884617d7ecdcf37664f648a51e2987cada --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR"
pnpm --filter="compare-perf" run compare perf $GITHUB_SHA $BASE_SHA --tests-branch $GITHUB_SHA --wp-version "$WP_MAJOR"
echo "Publish results to CodeVitals"
title "Publish results to CodeVitals"
COMMITTED_AT=$(git show -s $GITHUB_SHA --format="%cI")
pnpm --filter="compare-perf" run log $CODEVITALS_PROJECT_TOKEN trunk $GITHUB_SHA 19f3d0884617d7ecdcf37664f648a51e2987cada $COMMITTED_AT
pnpm --filter="compare-perf" run log $CODEVITALS_PROJECT_TOKEN trunk $GITHUB_SHA $BASE_SHA $COMMITTED_AT
else
echo "Unsupported event: $GITHUB_EVENT_NAME"
fi

View File

@ -1,45 +1,51 @@
name: 'Process stale needs-feedback issues'
on:
schedule:
- cron: '21 0 * * *'
schedule:
- cron: '21 0 * * *'
workflow_dispatch:
permissions: {}
permissions: { }
jobs:
stale:
runs-on: ubuntu-20.04
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Scan issues
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "As a part of this repository's maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 7 days with no activity this issue will be automatically be closed."
close-issue-message: 'This issue was closed because it has been 14 days with no activity.'
operations-per-run: 140
days-before-stale: -1
days-before-close: -1
days-before-issue-stale: 7
days-before-issue-close: 7
stale-issue-label: 'status: stale'
stale-pr-label: 'status: stale'
exempt-issue-labels: 'type: enhancement'
only-issue-labels: 'needs: author feedback'
close-issue-label: "status: can't reproduce"
ascending: true
- name: Close Stale Flaky Test Issues
uses: actions/stale@v9.0.0
with:
only-labels: 'metric: flaky e2e test, team: Vortex'
days-before-stale: 5
days-before-close: 2
stale-issue-label: 'metric: stale flaky e2e test report'
stale-issue-message: 'This test may have been a one-time failure. It will be auto-closed if no further activity occurs within the next 2 days.'
close-issue-message: 'Auto-closed due to inactivity. Please re-open if you believe this issue is still valid.'
close-issue-reason: 'not_planned'
remove-stale-when-updated: true
exempt-all-assignees: true
enable-statistics: true
stale:
runs-on: ubuntu-20.04
permissions:
contents: read
issues: write
pull-requests: write
steps:
- name: Scan issues
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-issue-message: "As a part of this repository's maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 7 days with no activity this issue will be automatically be closed."
close-issue-message: 'This issue was closed because it has been 14 days with no activity.'
operations-per-run: 140
days-before-stale: -1
days-before-close: -1
days-before-issue-stale: 7
days-before-issue-close: 7
stale-issue-label: 'status: stale'
stale-pr-label: 'status: stale'
exempt-issue-labels: 'type: enhancement'
only-issue-labels: 'needs: author feedback'
close-issue-label: "status: can't reproduce"
ascending: true
- name: Process Stale Flaky Test Issues
uses: actions/stale@v9.0.0
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
only-issue-labels: 'metric: flaky e2e test'
days-before-stale: -1
days-before-close: -1
days-before-issue-stale: 5
days-before-issue-close: 2
stale-issue-label: 'status: stale'
stale-issue-message: 'This issue is being marked as stale due to inactivity. It will be auto-closed if no further activity occurs within the next 2 days.'
close-issue-message: 'Auto-closed due to inactivity. Please re-open if you believe this issue is still valid.'
close-issue-reason: 'not_planned'
remove-stale-when-updated: true
exempt-all-assignees: false
enable-statistics: true
ascending: true
operations-per-run: 120

36
.github/workflows/storybook-pages.yml vendored Normal file
View File

@ -0,0 +1,36 @@
name: Storybook GitHub Pages
on:
schedule:
- cron: '30 2 * * *'
workflow_dispatch:
permissions:
contents: write
jobs:
deploy:
runs-on: ubuntu-latest
if: ${{ github.repository == 'woocommerce/woocommerce' }}
steps:
- name: Checkout
uses: actions/checkout@692973e3d937129bcbf40652eb9f2f61becf3332 # v4.1.7
with:
ref: trunk
fetch-depth: 0
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
with:
install: true
- name: Build Storybook
run: pnpm --filter='@woocommerce/storybook' build-storybook --quiet
- name: Deploy
uses: peaceiris/actions-gh-pages@4f9cc6602d3f66b9c108549d475ec49e8ef4d45e # v4.0.0
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
publish_dir: ./tools/storybook/storybook-static
force_orphan: true

View File

@ -59,8 +59,8 @@ jobs:
<${{ github.event.pull_request.html_url }}|${{ github.event.pull_request.title }}>
*Labels:* ${{ join(github.event.pull_request.labels.*.name, ', ') }}
*Monthly Release Milestone:* <${{ github.event.pull_request.milestone.html_url }}|${{ github.event.pull_request.milestone.title }}> (Release Date: ${{ env.MILESTONE_DATE }})
*WooAF (weekly) Timeline: this PR can be tested from:* ${{ env.TEST_DATE_MESSAGE }}
Please visit the <#${{ secrets.WOO_CORE_RELEASES_SLACK_CHANNEL }}> to obtain the latest WooAF build for testing.
Please check the Milestone above and test using the latest <https://github.com/woocommerce/woocommerce/releases|pre-release build>.
If a pre-release build for the stated Milestone does not exist, please use the Nightly build.
slack-optional-unfurl_links: false
slack-optional-unfurl_media: false

View File

@ -4,14 +4,35 @@ on:
workflow_dispatch:
inputs:
trigger:
description: 'Event name. It will be used to filter the jobs to run in ci.yml. It can be anything, as long as the job you want to run has this event configured in the `events` list. Example: daily-checks, pull_request, on-demand, etc.'
type: choice
description: 'Event name: it will be used to filter the jobs to run in ci.yml.'
required: true
default: ''
options:
- push
- daily-checks
- pre-release
- on-demand
- custom
default: on-demand
custom-trigger:
type: string
description: 'Custom event name: In case the `Event name` choice is `custom`, this field is required.'
required: false
jobs:
validate-input:
runs-on: ubuntu-latest
steps:
- name: 'Validate input'
run: |
if [ "${{ inputs.trigger }}" == "custom" ] && [ -z "${{ inputs.custom-trigger }}" ]; then
echo "Custom event name is required when event name choice `custom`."
exit 1
fi
run-tests:
name: 'Run tests'
uses: ./.github/workflows/ci.yml
with:
trigger: ${{ inputs.trigger }}
trigger: ${{ inputs.trigger == 'custom' && inputs.custom-trigger || inputs.trigger }}
secrets: inherit

30
.husky/post-checkout Executable file
View File

@ -0,0 +1,30 @@
#!/usr/bin/env bash
. "$(dirname "$0")/_/husky.sh"
# The hook documentation: https://git-scm.com/docs/githooks.html#_post_checkout
CHECKOUT_TYPE=$3
HEAD_NEW=$2
HEAD_PREVIOUS=$1
whiteColoured='\033[0m'
orangeColoured='\033[1;33m'
# '1' is a branch checkout
if [ "$CHECKOUT_TYPE" = '1' ]; then
# Prompt about pnpm versions mismatch when switching between branches.
currentPnpmVersion=$( ( command -v pnpm > /dev/null && pnpm -v 2>/dev/null ) || echo 'n/a' )
targetPnpmVersion=$( grep packageManager package.json | sed -nr 's/.+packageManager.+pnpm@([[:digit:].]+).+/\1/p' )
if [ "$currentPnpmVersion" != "$targetPnpmVersion" ]; then
printf "${orangeColoured}pnpm versions mismatch: in use '$currentPnpmVersion', needed '$targetPnpmVersion'. If you are working on something in this branch, here are some hints on how to solve this:\n"
printf "${orangeColoured}* actualize environment: 'nvm use && pnpm -v' (the most common case)\n"
printf "${orangeColoured}* install: 'npm install -g pnpm@$targetPnpmVersion'\n"
fi
# Auto-refresh dependencies when switching between branches.
changedManifests=$( ( git diff --name-only $HEAD_NEW $HEAD_PREVIOUS | grep -E '(package.json|pnpm-lock.yaml|pnpm-workspace.yaml|composer.json|composer.lock)$' ) || echo '' )
if [ -n "$changedManifests" ]; then
printf "${whiteColoured}The following file(s) in the new branch differs from the original one, dependencies might need to be refreshed:\n"
printf "${whiteColoured} %s\n" $changedManifests
printf "${orangeColoured}If you are working on something in this branch, ensure to refresh dependencies with 'pnpm install --frozen-lockfile'\n"
fi
fi

View File

@ -1,4 +1,12 @@
#!/bin/sh
#!/usr/bin/env bash
. "$(dirname "$0")/_/husky.sh"
pnpm install --frozen-lockfile
# The hook documentation: https://git-scm.com/docs/githooks.html#_post_merge
changedManifests=$( ( git diff --name-only HEAD ORIG_HEAD | grep -E '(package.json|pnpm-lock.yaml|pnpm-workspace.yaml|composer.json|composer.lock)$' ) || echo '' )
if [ -n "$changedManifests" ]; then
printf "It was a change in the following file(s) - refreshing dependencies:\n"
printf " %s\n" $changedManifests
pnpm install --frozen-lockfile
fi

View File

@ -3,8 +3,8 @@
"MD003": { "style": "atx" },
"MD007": { "indent": 4 },
"MD013": { "line_length": 9999 },
"MD024": { "allow_different_nesting": true },
"MD033": { "allowed_elements": ["video"] },
"MD024": { "siblings_only": true },
"MD033": { "allowed_elements": [ "video" ] },
"no-hard-tabs": false,
"whitespace": false
}

2
.npmrc
View File

@ -1,3 +1,5 @@
; adding this as npm 7 automatically installs peer dependencies but pnpm does not
auto-install-peers=true
strict-peer-dependencies=false
; See https://github.com/pnpm/pnpm/pull/8363 (we adding the setting now, to not miss when migrating to pnpm 9.7+)
manage-package-manager-versions=true

View File

@ -12,7 +12,7 @@
"dependencies": [
"pnpm"
],
"pinVersion": "^9.1.0",
"pinVersion": "9.1.3",
"packages": [
"**"
]
@ -88,7 +88,8 @@
"webpack*"
],
"packages": [
"@woocommerce/block-library"
"@woocommerce/block-library",
"@woocommerce/storybook"
],
"isIgnored": true
},
@ -172,7 +173,7 @@
"packages": [
"**"
],
"pinVersion": "^1.45.1"
"pinVersion": "^1.46.1"
},
{
"dependencies": [
@ -199,7 +200,10 @@
"@wordpress/viewport",
"@wordpress/interface",
"@wordpress/router",
"@wordpress/edit-site"
"@wordpress/edit-site",
"@wordpress/private-apis",
"@wordpress/dataviews",
"@wordpress/icons"
],
"packages": [
"@woocommerce/block-templates",
@ -244,7 +248,7 @@
"@woocommerce/block-library",
"**"
],
"pinVersion": "^9.7.0"
"pinVersion": "^10.1.0"
},
{
"dependencies": [
@ -253,7 +257,7 @@
"packages": [
"**"
],
"pinVersion": "wp-6.4"
"pinVersion": "wp-6.6"
},
{
"dependencies": [

View File

@ -1 +1,14 @@
/.github/ @woocommerce/atlas
# Monorepo CI and package managers manifests.
/.github/ @woocommerce/flux
**/composer.json @woocommerce/flux
**/package.json @woocommerce/flux
# Monorepo tooling folders.
/bin/ @woocommerce/flux
/tools/ @woocommerce/flux
/packages/js/eslint-plugin/ @woocommerce/flux
/packages/js/dependency-extraction-webpack-plugin/ @woocommerce/flux
# Files in root of repository
/.* @woocommerce/flux
/*.* @woocommerce/flux

View File

@ -4,7 +4,7 @@ This document aims to provide as much context as possible to aid in the developm
## Getting Started
Please refer to [the Getting Started section of the `README.md`](README.md#getting-started) for a general-purpose guide on getting started. The rest of this document will assume that you've installed all of the prequisites and setup described there.
Please refer to [the Getting Started section of the `README.md`](README.md#getting-started) for a general-purpose guide on getting started. The rest of this document will assume that you've installed all of the prerequisites and setup described there.
### Plugin, Package, and Tool Filtering

View File

@ -20,8 +20,8 @@ To get up and running within the WooCommerce Monorepo, you will need to make sur
Once you've installed all of the prerequisites, you can run the following commands to get everything working.
```bash
# Ensure that you're using the correct version of Node
nvm use
# Ensure that correct version of Node is installed and being used
nvm install
# Install the PHP and Composer dependencies for all of the plugins, packages, and tools
pnpm install
# Build all of the plugins, packages, and tools in the monorepo

View File

@ -1,5 +1,591 @@
== Changelog ==
= 9.3.1 2024-09-12 =
* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
= 9.3.0 2024-09-10 =
**WooCommerce**
* Enhancement - Add query params masking to remote logger [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
* Update - Added more paths to remote logger query param whitelist [#51108](https://github.com/woocommerce/woocommerce/pull/51108)
* Fix - Revert update to React 18 in Checkout block. [#51289](https://github.com/woocommerce/woocommerce/pull/51289)
* Fix - Add check to ensure themes API is safe [#51081](https://github.com/woocommerce/woocommerce/pull/51081)
* Fix - CYS - Remove usage of `prepare_item_for_response` function in `Images` endpoint. [#50923](https://github.com/woocommerce/woocommerce/pull/50923)
* Fix - Add ability for a screen reader to announce the current tab on a single product page. [#50373](https://github.com/woocommerce/woocommerce/pull/50373)
* Fix - Add a label to the product pagination for the woocommerce pagination [#49924](https://github.com/woocommerce/woocommerce/pull/49924)
* Fix - Add aria-current to the current link in My Account side nav [#49800](https://github.com/woocommerce/woocommerce/pull/49800)
* Fix - Add aria-label on View order button to aid in accessibility for screen readers [#49424](https://github.com/woocommerce/woocommerce/pull/49424)
* Fix - Add CSS outline for site visibility badge keyboard accessibility [#50794](https://github.com/woocommerce/woocommerce/pull/50794)
* Fix - Add scope attribute and aria-label to the product attributes table [#49768](https://github.com/woocommerce/woocommerce/pull/49768)
* Fix - Add to Cart with Options - Fix translation when used inside the Single Product block. [#50628](https://github.com/woocommerce/woocommerce/pull/50628)
* Fix - Allow verified parameter to be set by REST API request [#50525](https://github.com/woocommerce/woocommerce/pull/50525)
* Fix - Avoid PHP warnings if `add-to-cart.php` template does not pass `aria-describedby_text` [#48969](https://github.com/woocommerce/woocommerce/pull/48969)
* Fix - Cart block: Strip HTML tags and decode HTML entities in quantity change notifications. [#50541](https://github.com/woocommerce/woocommerce/pull/50541)
* Fix - Changed from using React.render to React.createRoot for marketing coupons as it has been deprecated since React 18 [#48832](https://github.com/woocommerce/woocommerce/pull/48832)
* Fix - Changed from using React.render to React.createRoot for payment methods promotion, shipping settings region zone as it has been deprecated since React 18 [#48835](https://github.com/woocommerce/woocommerce/pull/48835)
* Fix - Changed from using React.render to React.createRoot for print shipping banner as it has been deprecated since React 18 [#48831](https://github.com/woocommerce/woocommerce/pull/48831)
* Fix - Changed from using React.render to React.createRoot for product-usage-notice-modal as it has been deprecated since React 18 [#50765](https://github.com/woocommerce/woocommerce/pull/50765)
* Fix - Changed from using React.render to React.createRoot for wc addon tour as it has been deprecated since React 18 [#48833](https://github.com/woocommerce/woocommerce/pull/48833)
* Fix - Changed from using React.render to React.createRoot for WCAdmin uses as it has been deprecated since React 18 [#48785](https://github.com/woocommerce/woocommerce/pull/48785)
* Fix - Changed instances of prime marks inappropriately used when apostrophes are supposed to be used for some parts of WC Admin JS/TS/TSX files [#50776](https://github.com/woocommerce/woocommerce/pull/50776)
* Fix - Clear product unique ID (`global_unique_id`) when duplicating products. [#50629](https://github.com/woocommerce/woocommerce/pull/50629)
* Fix - Compatibility Layer: fix 'woocommerce_before_single_product_summary' hook position. [#50392](https://github.com/woocommerce/woocommerce/pull/50392)
* Fix - CYS - Improve the error when a request fails due to permissions [#50211](https://github.com/woocommerce/woocommerce/pull/50211)
* Fix - CYS - Update the "show_on_front" setting to "posts" to avoid overriding the "page" template. [#50083](https://github.com/woocommerce/woocommerce/pull/50083)
* Fix - CYS: disable zoom out on fonts/color pairs iframe [#50498](https://github.com/woocommerce/woocommerce/pull/50498)
* Fix - CYS: Fix auto scroll when a new block is added. [#50431](https://github.com/woocommerce/woocommerce/pull/50431)
* Fix - CYS: Improve opt in flow [#50529](https://github.com/woocommerce/woocommerce/pull/50529)
* Fix - Display address card for virtual products if shopper's address is known [#50127](https://github.com/woocommerce/woocommerce/pull/50127)
* Fix - Enable skipped E2E tests for attributes #50143 [#50143](https://github.com/woocommerce/woocommerce/pull/50143)
* Fix - Ensure coupon errors are visible on block checkout when invalid coupons are removed. [#50412](https://github.com/woocommerce/woocommerce/pull/50412)
* Fix - Ensure low and no stock email notification routine is triggered whenever product stock changes [#49583](https://github.com/woocommerce/woocommerce/pull/49583)
* Fix - Ensure session object is initialized before attempting to get chosen shipping methods [#50774](https://github.com/woocommerce/woocommerce/pull/50774)
* Fix - Ensure that the orders REST endpoint behaves the same as the UI when updating an order to remove a line item. [#50606](https://github.com/woocommerce/woocommerce/pull/50606)
* Fix - Featured Product: Fix variable product Selection dropdown #50633 [#50633](https://github.com/woocommerce/woocommerce/pull/50633)
* Fix - Fix "Product Meta" translations - Register the block server side. [#50625](https://github.com/woocommerce/woocommerce/pull/50625)
* Fix - Fix: ensure the global product object is always ready for compatibility layer by disabling default render routine of Product Templates inner blocks. [#49971](https://github.com/woocommerce/woocommerce/pull/49971)
* Fix - Fix activating the installed subscription when the user has multiple active licenses for the same product. [#49803](https://github.com/woocommerce/woocommerce/pull/49803)
* Fix - Fix address heading level on My Account page. [#49764](https://github.com/woocommerce/woocommerce/pull/49764)
* Fix - Fix an admin bar CSS positioning bug in WordPress.com on mobile [#50709](https://github.com/woocommerce/woocommerce/pull/50709)
* Fix - Fix cart shortcode updates when not used on the main cart page. [#50524](https://github.com/woocommerce/woocommerce/pull/50524)
* Fix - Fix core profiler checkbox vertical alignment and border color [#50151](https://github.com/woocommerce/woocommerce/pull/50151)
* Fix - Fix core profiler set up my store button and TOS are too close to each other [#50579](https://github.com/woocommerce/woocommerce/pull/50579)
* Fix - Fix e2e Google for WooCommerce strict mode violation error [#50189](https://github.com/woocommerce/woocommerce/pull/50189)
* Fix - Fixed Core Profiler's sticky footer button problem [#50727](https://github.com/woocommerce/woocommerce/pull/50727)
* Fix - Fixed placeholders in the classic cart shipping calculator to update with country selection. [#49684](https://github.com/woocommerce/woocommerce/pull/49684)
* Fix - Fixes a bug where some express payment buttons weren't being rendered correctly [#49304](https://github.com/woocommerce/woocommerce/pull/49304)
* Fix - Fix extensionCartUpdates to surface generic error messages, and include documentation for the error handling. [#49762](https://github.com/woocommerce/woocommerce/pull/49762)
* Fix - Fix focus order on checkout block page. [#49649](https://github.com/woocommerce/woocommerce/pull/49649)
* Fix - Fix navigation badge decreases when installing extension in "Grow your business task" [#50584](https://github.com/woocommerce/woocommerce/pull/50584)
* Fix - Fix page titles of the cart and checkout page when using blocks and FSE themes. [#49986](https://github.com/woocommerce/woocommerce/pull/49986)
* Fix - Fix rescheduling of actions that are blocked by other delayed actions [#50082](https://github.com/woocommerce/woocommerce/pull/50082)
* Fix - Fix the "Add payment methods" link in LYS congrat screen redirects to a blank page [#50609](https://github.com/woocommerce/woocommerce/pull/50609)
* Fix - Fix translation - Avoid registering blocks in the wrong context. [#50615](https://github.com/woocommerce/woocommerce/pull/50615)
* Fix - Fix `Product meta` console error. [#50680](https://github.com/woocommerce/woocommerce/pull/50680)
* Fix - Fix `store-title` endpoint - Pass default value to `get_option`. [#50673](https://github.com/woocommerce/woocommerce/pull/50673)
* Fix - Hide save changes button in main payments screen [#50064](https://github.com/woocommerce/woocommerce/pull/50064)
* Fix - In Remote Specs, treat empty arrays as valid cached values so individual engines can return default values. [#50521](https://github.com/woocommerce/woocommerce/pull/50521)
* Fix - Keep focus on shipping option input once selected [#49360](https://github.com/woocommerce/woocommerce/pull/49360)
* Fix - Make the matching variations alert a live region [#50132](https://github.com/woocommerce/woocommerce/pull/50132)
* Fix - Only count published products in productCount [#50503](https://github.com/woocommerce/woocommerce/pull/50503)
* Fix - Prevent fatal error if NULL is provided in array_search under Jetpack Stats [#50696](https://github.com/woocommerce/woocommerce/pull/50696)
* Fix - Prevent Store API orders being placed with empty state [#50028](https://github.com/woocommerce/woocommerce/pull/50028)
* Fix - Prevent sync-on-read from affecting results of HPOS diff CLI tool. [#49726](https://github.com/woocommerce/woocommerce/pull/49726)
* Fix - Product Collection: Fix max price query to include prices less or equal to the given max value. [#49917](https://github.com/woocommerce/woocommerce/pull/49917)
* Fix - Product Collection: fix the preview if used in Products by specific Category or Tag [#49889](https://github.com/woocommerce/woocommerce/pull/49889)
* Fix - Product Price block: prevent price amounts from breaking into multiple lines [#50660](https://github.com/woocommerce/woocommerce/pull/50660)
* Fix - Properly detect active plugins in multisite WP installations. [#50417](https://github.com/woocommerce/woocommerce/pull/50417)
* Fix - Reduce error noise in the user profile screen, by removing the requirement for custom fields to have a class attribute. [#48079](https://github.com/woocommerce/woocommerce/pull/48079)
* Fix - Remove Active Shipping Zones check for displaying shipping calculator on the Cart Page. [#49214](https://github.com/woocommerce/woocommerce/pull/49214)
* Fix - Single product block - Fix translation for title and description in edit mode. [#50599](https://github.com/woocommerce/woocommerce/pull/50599)
* Fix - Store API: Do not resume pending orders--create a new order instead [#50531](https://github.com/woocommerce/woocommerce/pull/50531)
* Fix - Transform labels in shipping zone region selector to decode html entities [#50694](https://github.com/woocommerce/woocommerce/pull/50694)
* Fix - Treat post_type=product as a shop page. [#50567](https://github.com/woocommerce/woocommerce/pull/50567)
* Fix - Update product order status colors to ensure accessible color contrasts [#49934](https://github.com/woocommerce/woocommerce/pull/49934)
* Add - Add an additional field for the email settings that sets the footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
* Add - Add blueprint behind a feature flag for testing purposes. [#49763](https://github.com/woocommerce/woocommerce/pull/49763)
* Add - Add field for the email footer text color [#49648](https://github.com/woocommerce/woocommerce/pull/49648)
* Add - Add function to clear system status theme info cache [#50803](https://github.com/woocommerce/woocommerce/pull/50803)
* Add - Add methods required by extensions to control product feature usage based on subscription status. [#50218](https://github.com/woocommerce/woocommerce/pull/50218)
* Add - Add parameter to avoid attempting to create the logs directory if it doesn't exist [#49766](https://github.com/woocommerce/woocommerce/pull/49766)
* Add - Add Pattern button to no blocks view on the CYS assembler [#49981](https://github.com/woocommerce/woocommerce/pull/49981)
* Add - Add reactified main payments screen [#49972](https://github.com/woocommerce/woocommerce/pull/49972)
* Add - Add reactify-classic-payments-settings feature flag [#49966](https://github.com/woocommerce/woocommerce/pull/49966)
* Add - Add tracks for WordPress Importer/Export pages. [#50769](https://github.com/woocommerce/woocommerce/pull/50769)
* Add - Add `FilteredGetDataTrait`, `OrderAwareControllerTrait`, and `StatsDataStoreTrait` for extension developers to reuse while creating custom Analytics [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
* Add - Implement server-side remote error logging [#49599](https://github.com/woocommerce/woocommerce/pull/49599)
* Add - Inform screen reader users when mini cart updates [#48295](https://github.com/woocommerce/woocommerce/pull/48295)
* Add - Integrate JS remote logging package in WooCommerce Admin [#50134](https://github.com/woocommerce/woocommerce/pull/50134)
* Add - Product Collection: emit the JS event when PC block is rendered [#50166](https://github.com/woocommerce/woocommerce/pull/50166)
* Add - Product Collection: Enable Context-Aware Previews by Adding `usesReference` to `registerProductCollection` [#49796](https://github.com/woocommerce/woocommerce/pull/49796)
* Add - Track frequency of unhandled JS errors with MC Stats [#50155](https://github.com/woocommerce/woocommerce/pull/50155)
* Add - Use MC Stats for PHP fatal error counting [#49658](https://github.com/woocommerce/woocommerce/pull/49658)
* Add - [E2E tests]: Add product description using the block editor #50232 [#50232](https://github.com/woocommerce/woocommerce/pull/50232)
* Update - Update WooCommerce Shipping Promo Banner to install the latest version of WooCommerce Shipping instead of WCS&T. [#50970](https://github.com/woocommerce/woocommerce/pull/50970)
* Update - Add abbreviations for fields GTIN, UPC, EAN, OR ISBN [#50042](https://github.com/woocommerce/woocommerce/pull/50042)
* Update - Add additional fields to new product editor e2e tests. [#50241](https://github.com/woocommerce/woocommerce/pull/50241)
* Update - Add confirmation prompt for site visibility settings when changing from live to coming soon mode [#50759](https://github.com/woocommerce/woocommerce/pull/50759)
* Update - Add pattern validation for global_unique_id [#50501](https://github.com/woocommerce/woocommerce/pull/50501)
* Update - Add remote logger as a log handler to wc logger [#50430](https://github.com/woocommerce/woocommerce/pull/50430)
* Update - Add request_uri prop to remote logging data [#50671](https://github.com/woocommerce/woocommerce/pull/50671)
* Update - Add woocommerce_coming_soon option for all sites [#50581](https://github.com/woocommerce/woocommerce/pull/50581)
* Update - Comment: Fix typos in documentation. [#50282](https://github.com/woocommerce/woocommerce/pull/50282)
* Update - CYS - Add tests for the Full Composability feature. [#49748](https://github.com/woocommerce/woocommerce/pull/49748)
* Update - CYS - Run appropriate tests depending on the WordPress version. [#50016](https://github.com/woocommerce/woocommerce/pull/50016)
* Update - CYS - Update icon and text colors in the assembler. [#50478](https://github.com/woocommerce/woocommerce/pull/50478)
* Update - CYS: Improve opt-in flow fonts. [#50086](https://github.com/woocommerce/woocommerce/pull/50086)
* Update - CYS: Improve opt-in flow patterns. [#50080](https://github.com/woocommerce/woocommerce/pull/50080)
* Update - CYS: Improve tracking survey [#50196](https://github.com/woocommerce/woocommerce/pull/50196)
* Update - CYS: Improve tracking survey [#50354](https://github.com/woocommerce/woocommerce/pull/50354)
* Update - CYS: Update the tracking URL to the external Fiverr link in sidebar of the **Add your logo** screen. [#50753](https://github.com/woocommerce/woocommerce/pull/50753)
* Update - Enable remote logging feature flag [#50351](https://github.com/woocommerce/woocommerce/pull/50351)
* Update - feat: add `aria-required` attributes to WC form fields [#48371](https://github.com/woocommerce/woocommerce/pull/48371)
* Update - Fixed log-out link behavior so that redirects work, and so that security nonces are automatically added to link in navigation menus. [#49605](https://github.com/woocommerce/woocommerce/pull/49605)
* Update - Migrate LYS user meta [#50664](https://github.com/woocommerce/woocommerce/pull/50664)
* Update - Move marketing task to things to do next task list [#50487](https://github.com/woocommerce/woocommerce/pull/50487)
* Update - Move site visibility badge to admin bar. [#50775](https://github.com/woocommerce/woocommerce/pull/50775)
* Update - Remove "Need help?" modal from onboarding [#47812](https://github.com/woocommerce/woocommerce/pull/47812)
* Update - Remove all links from the CYS sidebars [#50414](https://github.com/woocommerce/woocommerce/pull/50414)
* Update - Remove remote API call from marketing task [#50479](https://github.com/woocommerce/woocommerce/pull/50479)
* Update - Remove WooCommerce Navigation client side feature and deprecate PHP classes. [#50190](https://github.com/woocommerce/woocommerce/pull/50190)
* Update - Renamed columns inside In-App Marketplace > My subscriptions and added action to turn auto-renewal on for a subscription [#49985](https://github.com/woocommerce/woocommerce/pull/49985)
* Update - Rename woocommerce_is_store_page to woocommerce_is_extension_store_page [#50771](https://github.com/woocommerce/woocommerce/pull/50771)
* Update - Reverting the new `buttonAttributes` API. This will be included in a later release [#50763](https://github.com/woocommerce/woocommerce/pull/50763)
* Update - Revert the Zoom Out feature for the CYS experience [#50535](https://github.com/woocommerce/woocommerce/pull/50535)
* Update - Show expiring and expired notices to active and unconnected subscriptions [#50383](https://github.com/woocommerce/woocommerce/pull/50383)
* Update - Store API: Remove the need for nonces when using cart tokens. Remove deprecated X-WC-Store-API-Nonce header. [#50025](https://github.com/woocommerce/woocommerce/pull/50025)
* Update - Strip HTML tags from aria-label in wc_help_tip function [#50103](https://github.com/woocommerce/woocommerce/pull/50103)
* Update - Text adjustments on shipping zones settings page [#50136](https://github.com/woocommerce/woocommerce/pull/50136)
* Update - Update AdditionalPayments task to use default payment gateways [#50674](https://github.com/woocommerce/woocommerce/pull/50674)
* Update - Update add product task button section UI [#50580](https://github.com/woocommerce/woocommerce/pull/50580)
* Update - Update all blocks to use API Version 3. [#48720](https://github.com/woocommerce/woocommerce/pull/48720)
* Update - Update Blueprint settings layout. [#50724](https://github.com/woocommerce/woocommerce/pull/50724)
* Update - Update core profiler continue button container on extension screen [#50582](https://github.com/woocommerce/woocommerce/pull/50582)
* Update - Update Store Alert actions to have unique keys. [#50424](https://github.com/woocommerce/woocommerce/pull/50424)
* Update - Update WooCommercePayments task is_supported to use default suggestions [#50585](https://github.com/woocommerce/woocommerce/pull/50585)
* Update - Enhance CSV path and upload handling in product import [#51344](https://github.com/woocommerce/woocommerce/pull/51344)
* Dev - Execute test env setup on host instead of wp-env container [#51021](https://github.com/woocommerce/woocommerce/pull/51021)
* Dev - Added code docs with examples to the Analytics classes [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
* Dev - Add lost password e2e tests [#50611](https://github.com/woocommerce/woocommerce/pull/50611)
* Dev - Add unit tests for the product_add_publish track. [#49916](https://github.com/woocommerce/woocommerce/pull/49916)
* Dev - CI: introduce PHPUnit tests sharding. [#50084](https://github.com/woocommerce/woocommerce/pull/50084)
* Dev - CI: minor speed boost of wp-env startup. [#50445](https://github.com/woocommerce/woocommerce/pull/50445)
* Dev - CI: speedup assets size verification job execution time. [#50178](https://github.com/woocommerce/woocommerce/pull/50178)
* Dev - CI: Use a single shard when re-running failed tests in CI [#50492](https://github.com/woocommerce/woocommerce/pull/50492)
* Dev - CI config: update changes list to include more paths [#50399](https://github.com/woocommerce/woocommerce/pull/50399)
* Dev - Clean up unused images [#50516](https://github.com/woocommerce/woocommerce/pull/50516)
* Dev - CYS - Document possible Intro pages [#50171](https://github.com/woocommerce/woocommerce/pull/50171)
* Dev - CYS - Move the "ai/patterns" endpoint to woocommerce admin API. [#50372](https://github.com/woocommerce/woocommerce/pull/50372)
* Dev - CYS - Move the "ai/store-info" endpoint to woocommerce admin API [#50363](https://github.com/woocommerce/woocommerce/pull/50363)
* Dev - CYS - Move the ai/business-description endpoint to woocommerce admin API [#50359](https://github.com/woocommerce/woocommerce/pull/50359)
* Dev - CYS - Move the ai/store-title endpoint to woocommerce admin API [#50352](https://github.com/woocommerce/woocommerce/pull/50352)
* Dev - CYS - Move the `ai/images` endpoint to woocommerce admin API [#50365](https://github.com/woocommerce/woocommerce/pull/50365)
* Dev - CYS - Move the `ai/product` endpoint to woocommerce admin API. [#50393](https://github.com/woocommerce/woocommerce/pull/50393)
* Dev - CYS: add E2E tests for fonts installation. [#50210](https://github.com/woocommerce/woocommerce/pull/50210)
* Dev - E2E tests: add a flaky test reporter for Core e2e tests [#50259](https://github.com/woocommerce/woocommerce/pull/50259)
* Dev - E2E tests: add an option to skip the env setup script running before test execution [#50620](https://github.com/woocommerce/woocommerce/pull/50620)
* Dev - E2E tests: add buildkite-test-collector for blocks e2e tests [#50642](https://github.com/woocommerce/woocommerce/pull/50642)
* Dev - E2E tests: add environment reporter [#49988](https://github.com/woocommerce/woocommerce/pull/49988)
* Dev - E2E tests: add hpos-disabled env and tagged tests with hpos tag [#50448](https://github.com/woocommerce/woocommerce/pull/50448)
* Dev - E2E tests: fixed broken logo picker tests [#50473](https://github.com/woocommerce/woocommerce/pull/50473)
* Dev - E2E tests: fix flakiness in page-loads customer page test [#50559](https://github.com/woocommerce/woocommerce/pull/50559)
* Dev - E2E tests: fix flakiness in product attributes test [#50485](https://github.com/woocommerce/woocommerce/pull/50485)
* Dev - E2E tests: removed Github reporter [#50256](https://github.com/woocommerce/woocommerce/pull/50256)
* Dev - E2E tests: Removed unnecessary pause in the test [#50043](https://github.com/woocommerce/woocommerce/pull/50043)
* Dev - E2E tests for verifying approve, spam and reply to product reviews. [#50060](https://github.com/woocommerce/woocommerce/pull/50060)
* Dev - Fix E2E tests SKU field id #49729 [#49729](https://github.com/woocommerce/woocommerce/pull/49729)
* Dev - Fixes a flaky product variations e2e test [#50807](https://github.com/woocommerce/woocommerce/pull/50807)
* Dev - Fix Metrics CI job [#50214](https://github.com/woocommerce/woocommerce/pull/50214)
* Dev - Fix optional param in PHPdoc for `WC_Admin_Marketplace_Promotions` to generate code-reference w/o warnings [#50732](https://github.com/woocommerce/woocommerce/pull/50732)
* Dev - Fix the Metrics job by adding a missing NVM install step [#50482](https://github.com/woocommerce/woocommerce/pull/50482)
* Dev - Make the Metrics tests use utilities provided by the updated @wordpress/e2e-test-utils-playwright package. [#50626](https://github.com/woocommerce/woocommerce/pull/50626)
* Dev - Mark ReportTable tableData prop as not required [#50816](https://github.com/woocommerce/woocommerce/pull/50816)
* Dev - Monorepo: enable new linting rules for PHP (PSR-4 naming, Strict types declaration). [#49438](https://github.com/woocommerce/woocommerce/pull/49438)
* Dev - Monorepo: tweak Webpack loaders paths filtering for better build perfromance. [#49714](https://github.com/woocommerce/woocommerce/pull/49714)
* Dev - move block theme docs to docs site folder [#50638](https://github.com/woocommerce/woocommerce/pull/50638)
* Dev - move part of checkout docs to main docs folder [#49984](https://github.com/woocommerce/woocommerce/pull/49984)
* Dev - Move `ReportError` to `@woocommerce/components` as `AnalyticsError` [#50108](https://github.com/woocommerce/woocommerce/pull/50108)
* Dev - moving product collection docs to main docs folder [#50368](https://github.com/woocommerce/woocommerce/pull/50368)
* Dev - Reduce duplicated code in Analytics controllers, unify their behavior and API. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
* Dev - Reduce the amount of duplicated code in Analytics `DataStore`s. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
* Dev - Removed defaultProps from React functional components since they will be deprecated for React 19 [#50266](https://github.com/woocommerce/woocommerce/pull/50266)
* Dev - Removed directive to disable woocommerce_coming_soon in e2e tests so that we get better test coverage [#50344](https://github.com/woocommerce/woocommerce/pull/50344)
* Dev - Render a React placeholder for offline and WooCommerce Payments settings sections [#50008](https://github.com/woocommerce/woocommerce/pull/50008)
* Dev - Replace `Automattic\WooCommerce\Admin\API\Reports\*\Query` classes with a single `GenericQuery` class. [#49425](https://github.com/woocommerce/woocommerce/pull/49425)
* Dev - Switch `render()` to `createRoot().render()` to use React 18 features. [#48843](https://github.com/woocommerce/woocommerce/pull/48843)
* Dev - Tests: moved api core tests as a suite in e2e-pw [#50024](https://github.com/woocommerce/woocommerce/pull/50024)
* Dev - Tweak the lost password e2e logic [#50666](https://github.com/woocommerce/woocommerce/pull/50666)
* Dev - Update @wordpress/e2e-test-utils-playwright core dependency to wp-6.6 [#50274](https://github.com/woocommerce/woocommerce/pull/50274)
* Dev - Updated e2e tests docs to clarify the use of environments [#50530](https://github.com/woocommerce/woocommerce/pull/50530)
* Dev - Updated the workflow prompting for testing instructions to only run once (preventing double comments) [#50034](https://github.com/woocommerce/woocommerce/pull/50034)
* Dev - Update E2E tests for linked list and variation creation with new component changes. [#50128](https://github.com/woocommerce/woocommerce/pull/50128)
* Dev - Update lys e2e tests to test with both classic and block themes [#50657](https://github.com/woocommerce/woocommerce/pull/50657)
* Dev - Update Playwright to 1.46.1 from 1.45.1 [#50772](https://github.com/woocommerce/woocommerce/pull/50772)
* Dev - Update WP version to 6.6 in Blocks wp-env config. [#49704](https://github.com/woocommerce/woocommerce/pull/49704)
* Dev - Use stricter text selector on test [#50848](https://github.com/woocommerce/woocommerce/pull/50848)
* Dev - [Filter Products by Price]: Update view when changing the min/max value #50651 [#50651](https://github.com/woocommerce/woocommerce/pull/50651)
* Tweak - Disable remote logging feature by default [#51312](https://github.com/woocommerce/woocommerce/pull/51312)
* Tweak - Add GTIN in structured data [#50087](https://github.com/woocommerce/woocommerce/pull/50087)
* Tweak - Add link to title, remove link from a description, minor copy changes to site visibility settings page [#50781](https://github.com/woocommerce/woocommerce/pull/50781)
* Tweak - Add the `woocommerce_should_clear_cart_after_payment` filter to influence whether the cart should be cleared after payment. [#44515](https://github.com/woocommerce/woocommerce/pull/44515)
* Tweak - allows the quantity selector on block cart page to render as readonly when editable is false [#49450](https://github.com/woocommerce/woocommerce/pull/49450)
* Tweak - Bump Jetpack COnnection, Jetpack Constants and a8c MC Stats [#50471](https://github.com/woocommerce/woocommerce/pull/50471)
* Tweak - Extract the checkbox list option logic into its own component [#50566](https://github.com/woocommerce/woocommerce/pull/50566)
* Tweak - Make `geolocation_ajax_get_location_hash` case-insensitive, to reduce the number of cache misses. [#45439](https://github.com/woocommerce/woocommerce/pull/45439)
* Tweak - Optimize large image files [#50517](https://github.com/woocommerce/woocommerce/pull/50517)
* Tweak - Product Collection: fix the PHP deprecated warning [#50661](https://github.com/woocommerce/woocommerce/pull/50661)
* Tweak - Reduce core profiler sticky footer height [#50788](https://github.com/woocommerce/woocommerce/pull/50788)
* Tweak - Remove colon from product data meta box checkboxes [#50619](https://github.com/woocommerce/woocommerce/pull/50619)
* Tweak - Remove the code related to the automatic Products (Beta) -> Product Collection upgrade. [#50440](https://github.com/woocommerce/woocommerce/pull/50440)
* Tweak - Set timeout to 2 seconds for helper product-usage-notice-rules endpoint request [#50821](https://github.com/woocommerce/woocommerce/pull/50821)
* Tweak - Update size of site visibility badge. [#50792](https://github.com/woocommerce/woocommerce/pull/50792)
* Tweak - Vertically center product meta elements [#50826](https://github.com/woocommerce/woocommerce/pull/50826)
* Performance - Cache order dates in options for performance. [#50066](https://github.com/woocommerce/woocommerce/pull/50066)
* Performance - Compress pattern placeholder image assets [#50405](https://github.com/woocommerce/woocommerce/pull/50405)
* Performance - Improve performance of maybe_assign_default_product_cat by only dropping cache and term recounting if changes were made in the database [#50006](https://github.com/woocommerce/woocommerce/pull/50006)
* Performance - Improve setup_tasks_remaining performance [#50655](https://github.com/woocommerce/woocommerce/pull/50655)
* Enhancement - Add a filter to override the SKU database lock. [#49755](https://github.com/woocommerce/woocommerce/pull/49755)
* Enhancement - Add email type to Checkout block email field. [#48611](https://github.com/woocommerce/woocommerce/pull/48611)
* Enhancement - Add filter `woocommerce_is_store_page` to modify whether Coming Soon mode considers a URL a store page or not. [#50174](https://github.com/woocommerce/woocommerce/pull/50174)
* Enhancement - Add username in email reset-password link [#49737](https://github.com/woocommerce/woocommerce/pull/49737)
* Enhancement - CYS: improve CTA [#50278](https://github.com/woocommerce/woocommerce/pull/50278)
* Enhancement - Ensure `wccomHelper` data is only loaded on the Extensions page where it's needed. [#49758](https://github.com/woocommerce/woocommerce/pull/49758)
* Enhancement - Fixed minor issues in the developer documentation recently added by public resources team [#50845](https://github.com/woocommerce/woocommerce/pull/50845)
* Enhancement - Hide zoomed product images for screen readers. [#50003](https://github.com/woocommerce/woocommerce/pull/50003)
* Enhancement - Improve hover style on product tabs when using the Minimal style in the Product Details block [#50605](https://github.com/woocommerce/woocommerce/pull/50605)
* Enhancement - Make screen readers announce notice messages once page loads. [#50061](https://github.com/woocommerce/woocommerce/pull/50061)
* Enhancement - Refactor: Migrate the All Products block to API version 3 [#50203](https://github.com/woocommerce/woocommerce/pull/50203)
* Enhancement - Remove opacity from the hover style of the mini cart button [#50240](https://github.com/woocommerce/woocommerce/pull/50240)
* Enhancement - Use standard link color in legal disclaimers on core profiler [#50830](https://github.com/woocommerce/woocommerce/pull/50830)
= 9.2.3 2024-08-26 =
**WooCommerce**
* Fix - Ensure translation is fully loaded for certain parts of Checkout block. [#50892](https://github.com/woocommerce/woocommerce/pull/50892)
= 9.2.2 2024-08-22 =
**WooCommerce**
* Fix - Revert PR#48731 to address possible issues with plugins using WC's bundled select2 package. [#50854](https://github.com/woocommerce/woocommerce/pull/50854)
* Fix - Partially revert PR#48709 as it could cause issues for some users of the REST API system_status endpoint. [#50881](https://github.com/woocommerce/woocommerce/pull/50881)
= 9.2.1 2024-08-21 =
**WooCommerce**
* Fix - Revert turning of AccessiblePrivateMethods::_accessible_private_methods into a static property because it caused fatal errors in some edge cases. [#50809](https://github.com/woocommerce/woocommerce/pull/50809)
= 9.2.0 2024-08-20 =
**WooCommerce**
* Update - Enhanced sanitization in `@woocommerce/currency`. [#50802](https://github.com/woocommerce/woocommerce/pull/50802)
* Fix - Hardening against XSS by leveraging HTML API for adding block attribute data. [#50801](https://github.com/woocommerce/woocommerce/pull/50801)
* Fix - Prevent downloads of digitial products after partial refund. [#50804](https://github.com/woocommerce/woocommerce/pull/50804)
* Add - Adds support for tracking downloads when a partial (ranged) request is made. [#50805](https://github.com/woocommerce/woocommerce/pull/50805)
* Update - Turn AccessiblePrivateMethods::_accessible_private_methods into a static property. [#50806](https://github.com/woocommerce/woocommerce/pull/50806)
* Fix - Correct label of shipping dimensions length field. [#50180](https://github.com/woocommerce/woocommerce/pull/50180)
* Fix - Allow new accounts to set new password even if logged in. [#50700](https://github.com/woocommerce/woocommerce/pull/50700)
* Fix - Remove global_unique_id from interface and add warning in case it is not implemented [#50685](https://github.com/woocommerce/woocommerce/pull/50685)
* Fix - CYS: avoid to enqueue Jetpack scripts [#50679](https://github.com/woocommerce/woocommerce/pull/50679)
* Fix - Clear product unique ID (`global_unique_id`) when duplicating products. [#50629](https://github.com/woocommerce/woocommerce/pull/50629)
* Fix - Resolved an issue that caused the page title and content text to display in the incorrect order on the Order Confirmation page. [#50592](https://github.com/woocommerce/woocommerce/pull/50592)
* Fix - Customer Account - Maintain the size of the icon in smaller screens. [#50410](https://github.com/woocommerce/woocommerce/pull/50410)
* Fix - Accessibility: Prevent shipping losing focus when making selections during checkout. [#48370](https://github.com/woocommerce/woocommerce/pull/48370)
* Fix - Add aria-label to mini-cart button on first render to improve accessibility [#48329](https://github.com/woocommerce/woocommerce/pull/48329)
* Fix - Add missing script dependencies to product variation generation script. [#49595](https://github.com/woocommerce/woocommerce/pull/49595)
* Fix - Address timing issue with React 18 when unregistering blocks and add missing dependency to editor bootstrapping code. [#49642](https://github.com/woocommerce/woocommerce/pull/49642)
* Fix - Add the "Customer account" block into the "Minimal Header" to fix the spacing. [#49893](https://github.com/woocommerce/woocommerce/pull/49893)
* Fix - Avoid Product Search Results block template to fall back to the Product Catalog template from the theme [#48887](https://github.com/woocommerce/woocommerce/pull/48887)
* Fix - Changed from using React.render to React.createRoot for product editor areas as it has been deprecated since React 18 [#48834](https://github.com/woocommerce/woocommerce/pull/48834)
* Fix - Check if parent product exists when creating attribute lookup data for variations [#49474](https://github.com/woocommerce/woocommerce/pull/49474)
* Fix - Check if there's an actual session available inside wc_clear_cart_after_payment [#45821](https://github.com/woocommerce/woocommerce/pull/45821)
* Fix - Comment: Update db_version variable and use it to prevent adding global_unique_id when the lookup table was not yet updated [#49472](https://github.com/woocommerce/woocommerce/pull/49472)
* Fix - Correctly escape the HTML when linking customer orders. [#49195](https://github.com/woocommerce/woocommerce/pull/49195)
* Fix - CSY - Fix intro banner copy for existing themes [#49787](https://github.com/woocommerce/woocommerce/pull/49787)
* Fix - CYS - Fix marking the CYS task as completed only by accessing the Intro page. [#49374](https://github.com/woocommerce/woocommerce/pull/49374)
* Fix - CYS - Remove the site title block length from the "Large Header" and the "Centered Menu Header". [#48671](https://github.com/woocommerce/woocommerce/pull/48671)
* Fix - CYS: Disable readonly mode only when full composability feature flag is enabled. [#48752](https://github.com/woocommerce/woocommerce/pull/48752)
* Fix - CYS: Ensure that the button in the Intro page redirects to the Customizer when a classic theme is enabled. [#49804](https://github.com/woocommerce/woocommerce/pull/49804)
* Fix - CYS: fix: Assembler follows admin color schema. [#49159](https://github.com/woocommerce/woocommerce/pull/49159)
* Fix - CYS: fix arrow welcome tour [#49607](https://github.com/woocommerce/woocommerce/pull/49607)
* Fix - CYS: Fix border width pattern preview. [#49753](https://github.com/woocommerce/woocommerce/pull/49753)
* Fix - CYS: Fix button background on Featured Category Cover image [#49659](https://github.com/woocommerce/woocommerce/pull/49659)
* Fix - CYS: fix drag to resize bar [#49657](https://github.com/woocommerce/woocommerce/pull/49657)
* Fix - CYS: fix flickering effect. [#48767](https://github.com/woocommerce/woocommerce/pull/48767)
* Fix - CYS: fix logic to disable click on the no block placeholder [#48722](https://github.com/woocommerce/woocommerce/pull/48722)
* Fix - CYS: Fix no block placeholder style. [#49673](https://github.com/woocommerce/woocommerce/pull/49673)
* Fix - CYS: Fix pattern rendering issues [#49041](https://github.com/woocommerce/woocommerce/pull/49041)
* Fix - CYS: fix pattern wrapped twice by group blocks [#48712](https://github.com/woocommerce/woocommerce/pull/48712)
* Fix - CYS: fix selected header/footer pattern [#49788](https://github.com/woocommerce/woocommerce/pull/49788)
* Fix - CYS: fix shuffle feature logic. [#49153](https://github.com/woocommerce/woocommerce/pull/49153)
* Fix - CYS: fix the default intro pattern. [#49082](https://github.com/woocommerce/woocommerce/pull/49082)
* Fix - CYS: Fix the tooltip overlap with the pattern. [#49700](https://github.com/woocommerce/woocommerce/pull/49700)
* Fix - CYS: fix toolbar position after the site preview resizes [#49028](https://github.com/woocommerce/woocommerce/pull/49028)
* Fix - CYS: hide button to resize the image [#48714](https://github.com/woocommerce/woocommerce/pull/48714)
* Fix - CYS: Hide shuffle button when only one pattern is available [#49790](https://github.com/woocommerce/woocommerce/pull/49790)
* Fix - CYS: not enable PTK features on WordPress 6.5. [#49591](https://github.com/woocommerce/woocommerce/pull/49591)
* Fix - CYS: open Intro panel when user clicks on Design your homepage [#49005](https://github.com/woocommerce/woocommerce/pull/49005)
* Fix - CYS: Remove not necessary placeholder on homepage sidebar. [#49705](https://github.com/woocommerce/woocommerce/pull/49705)
* Fix - CYS: show default TT4 fonts pair. [#49675](https://github.com/woocommerce/woocommerce/pull/49675)
* Fix - CYS: show logo when the header is updated. [#49681](https://github.com/woocommerce/woocommerce/pull/49681)
* Fix - Display "View store" button text by default in the toolbar. [#48690](https://github.com/woocommerce/woocommerce/pull/48690)
* Fix - Display admin notice of expired and expiring Woo subscription when the product
is connected / activated on the site. [#49717](https://github.com/woocommerce/woocommerce/pull/49717)
* Fix - Do not set the `tk_ai` tracking cookie if tracking is disabled. [#47863](https://github.com/woocommerce/woocommerce/pull/47863)
* Fix - Ensure the second address line input appears when using autofill [#49730](https://github.com/woocommerce/woocommerce/pull/49730)
* Fix - Ensure the Store API recalculates cart totals prior to running validation hooks. [#49455](https://github.com/woocommerce/woocommerce/pull/49455)
* Fix - Exclude simple products from variations reports by default. [#49244](https://github.com/woocommerce/woocommerce/pull/49244)
* Fix - Failure to fetch the country list no longer blocks users in the profiler. [#49519](https://github.com/woocommerce/woocommerce/pull/49519)
* Fix - Fetch site cache status correctly if directly navigating to LYS Success page, and some refactoring [#48710](https://github.com/woocommerce/woocommerce/pull/48710)
* Fix - Fix: Make woocommerce/product-price available in the Single Product template [#49906](https://github.com/woocommerce/woocommerce/pull/49906)
* Fix - Fix a bug where woocommerce removes the current-menu-item class. [#45095](https://github.com/woocommerce/woocommerce/pull/45095)
* Fix - Fix add product task to create template first and simplify logic [#49631](https://github.com/woocommerce/woocommerce/pull/49631)
* Fix - Fix add zone button flinching and vertical centering [#48869](https://github.com/woocommerce/woocommerce/pull/48869)
* Fix - Fix Analytics - Tax Report Pagination [#49562](https://github.com/woocommerce/woocommerce/pull/49562)
* Fix - Fix confusing messages prompting switch to classic templates [#48717](https://github.com/woocommerce/woocommerce/pull/48717)
* Fix - Fix default shipping selection when changing between pickup and shipping on block checkout. [#49718](https://github.com/woocommerce/woocommerce/pull/49718)
* Fix - Fixed "woocommerce_new_order" triggering on checkout blocks page visit. [#47422](https://github.com/woocommerce/woocommerce/pull/47422)
* Fix - Fixed a bug causing account email not to be taken in consideration for coupon validation when a customer has a different billing email set. [#48488](https://github.com/woocommerce/woocommerce/pull/48488)
* Fix - Fixed a bug that would cause incorrect pricing at checkout for very large amounts. [#49361](https://github.com/woocommerce/woocommerce/pull/49361)
* Fix - Fixed a bug where the close button is not visible on the mini cart when viewed on a mobile device [#48769](https://github.com/woocommerce/woocommerce/pull/48769)
* Fix - Fixed horizontal and vertical layout overflows on LYS success page [#49127](https://github.com/woocommerce/woocommerce/pull/49127)
* Fix - Fix fatal error in order reports when parent order doesn't exist [#49006](https://github.com/woocommerce/woocommerce/pull/49006)
* Fix - Fix get_options deprecated notice when viewing Analytics > Orders [#49092](https://github.com/woocommerce/woocommerce/pull/49092)
* Fix - Fix Order Count inconsistency between stats and reports [#49283](https://github.com/woocommerce/woocommerce/pull/49283)
* Fix - Fix sidebar attribute control in Products by Attribute block [#49351](https://github.com/woocommerce/woocommerce/pull/49351)
* Fix - Fix site coming soon page heading color [#49129](https://github.com/woocommerce/woocommerce/pull/49129)
* Fix - Fix Task List - Reminder bar close button styling [#49532](https://github.com/woocommerce/woocommerce/pull/49532)
* Fix - Fix the mini cart items not being visible when zoomed in [#48384](https://github.com/woocommerce/woocommerce/pull/48384)
* Fix - Fix the namespace of the RestApiControllerBase class [#49333](https://github.com/woocommerce/woocommerce/pull/49333)
* Fix - Fix the undefined array key "name" warning in ComingSoonRequestHandler.php when the font name is not set [#49795](https://github.com/woocommerce/woocommerce/pull/49795)
* Fix - Fix variation name in analytics variations report [#49440](https://github.com/woocommerce/woocommerce/pull/49440)
* Fix - Issue fixed where tags are overlapping divider line in "Filter by product category". [#48756](https://github.com/woocommerce/woocommerce/pull/48756)
* Fix - Made coupon fields during block checkout stack on smaller screen sizes [#48623](https://github.com/woocommerce/woocommerce/pull/48623)
* Fix - Make sure the correct block template file is used in the Site Editor for templates with fallback [#48621](https://github.com/woocommerce/woocommerce/pull/48621)
* Fix - Make the edit/delete actions of shipping/products in manual orders accessible [#48238](https://github.com/woocommerce/woocommerce/pull/48238)
* Fix - Make the Leaderboards on the Analytics > Dashboard page use consistent currency and number formatting across the page, and perceive the currency setting comes from the relevant filter. [#49097](https://github.com/woocommerce/woocommerce/pull/49097)
* Fix - Narrowed scope of block theme notice templates so other template overrides are unaffected [#48686](https://github.com/woocommerce/woocommerce/pull/48686)
* Fix - Prevent a warning showing when using the Shipping Address Calculator in combination with the additional checkout fields API [#49685](https://github.com/woocommerce/woocommerce/pull/49685)
* Fix - Prevent download permissions metabox from being toggled when toggling individual permission details. [#49022](https://github.com/woocommerce/woocommerce/pull/49022)
* Fix - Prevent possible type error in BatchProcessingController. [#49728](https://github.com/woocommerce/woocommerce/pull/49728)
* Fix - Prevent product editor styles loading on non wc-admin pages [#49170](https://github.com/woocommerce/woocommerce/pull/49170)
* Fix - Product Collection: allow custom collections to hide all of the filter controls, not only some of them [#49713](https://github.com/woocommerce/woocommerce/pull/49713)
* Fix - Product Collection: Fix alignment of the first item in Grid layout for WP 6.6 [#49096](https://github.com/woocommerce/woocommerce/pull/49096)
* Fix - Product Collection: Fix the Preview badge's corner radius [#48856](https://github.com/woocommerce/woocommerce/pull/48856)
* Fix - Product Collection: Show "Sync with current query" option only in archive templates where it makes sense [#48917](https://github.com/woocommerce/woocommerce/pull/48917)
* Fix - Product Fitlers: Bring back pattern [#49601](https://github.com/woocommerce/woocommerce/pull/49601)
* Fix - Product rating - Inherit the color of the star when no ratings [#49678](https://github.com/woocommerce/woocommerce/pull/49678)
* Fix - Provide more informative errors if a refund cannot be requested via the REST API, due to plugin conflicts. [#47918](https://github.com/woocommerce/woocommerce/pull/47918)
* Fix - Redirect the lost password page to edit account while logged in. [#49670](https://github.com/woocommerce/woocommerce/pull/49670)
* Fix - Removes several side effects in the code bases that caused translations to be loaded too early. [#47113](https://github.com/woocommerce/woocommerce/pull/47113)
* Fix - Remove strong tags from patterns [#49901](https://github.com/woocommerce/woocommerce/pull/49901)
* Fix - Replace the red CSS color with the $red SASS variable in WooCommerce legacy elements [#48742](https://github.com/woocommerce/woocommerce/pull/48742)
* Fix - Resolved issues with new order hook triggers during transitions to and from draft statuses. [#49098](https://github.com/woocommerce/woocommerce/pull/49098)
* Fix - Set coming soon preview body aspect ratio to 1/1 to fix broken template [#49749](https://github.com/woocommerce/woocommerce/pull/49749)
* Fix - Show variations only for the selected product's variations [#49470](https://github.com/woocommerce/woocommerce/pull/49470)
* Fix - Tooltips message is now selected based on the order status instead of the label of the order status, which would break if the current WordPress language was not English. Also passes the order object to the woocommerce_get_order_status_labels filter to allow for more personalized tooltips. [#49812](https://github.com/woocommerce/woocommerce/pull/49812)
* Fix - Update allowed statuses in legacy payment handler for checkout block. [#48788](https://github.com/woocommerce/woocommerce/pull/48788)
* Add - Use UTM parameters to link Tracks events from connect notice CTA and successful site connection [#50126](https://github.com/woocommerce/woocommerce/pull/50126)
* Add - Add a generic function to determine remote logging eligibility [#49371](https://github.com/woocommerce/woocommerce/pull/49371)
* Add - Add a rest api to manage the product custom fields [#48504](https://github.com/woocommerce/woocommerce/pull/48504)
* Add - Add column `global_unique_id` to `wc_product_meta_lookup` table
Add global_unique_id field to product and product variations [#49472](https://github.com/woocommerce/woocommerce/pull/49472)
* Add - Added notice to the order confirmation page for new accounts instructing them to change the default password. [#48673](https://github.com/woocommerce/woocommerce/pull/48673)
* Add - Add global unique ID field to the classic product editor [#49312](https://github.com/woocommerce/woocommerce/pull/49312)
* Add - Add placeholder options and validation to checkout country and state select inputs. [#49616](https://github.com/woocommerce/woocommerce/pull/49616)
* Add - Add Refresh Remote Inbox Notifications and Delete Remote Notification Tools [#48961](https://github.com/woocommerce/woocommerce/pull/48961)
* Add - Add some robots.txt rules about directories created by WooCommerce [#49432](https://github.com/woocommerce/woocommerce/pull/49432)
* Add - Adds product usage notice [#47697](https://github.com/woocommerce/woocommerce/pull/47697)
* Add - Add support to run e2e tests against WPCOM website. [#49403](https://github.com/woocommerce/woocommerce/pull/49403)
* Add - Add UTM parameters to missing payment method notice links. [#49621](https://github.com/woocommerce/woocommerce/pull/49621)
* Add - Add validation for `__experimentalRegisterProductCollection` arguments [#48141](https://github.com/woocommerce/woocommerce/pull/48141)
* Add - CYS: add badge that informs how many patterns have been inserted from each category. [#48668](https://github.com/woocommerce/woocommerce/pull/48668)
* Add - CYS: Add default patterns. [#48839](https://github.com/woocommerce/woocommerce/pull/48839)
* Add - CYS: Add Tracking for Fiverr Logo Maker CTA [#49783](https://github.com/woocommerce/woocommerce/pull/49783)
* Add - CYS: Enable the PTK feature. [#49565](https://github.com/woocommerce/woocommerce/pull/49565)
* Add - Expose __experimentalRegisterProductCollection in @woocommerce/blocks-registry Package [#48141](https://github.com/woocommerce/woocommerce/pull/48141)
* Add - Improvements in the handling of feature compatibility for plugins [#48169](https://github.com/woocommerce/woocommerce/pull/48169)
* Add - Product Collection: Rename "Sync with current query" option to "Use page context" and make it working in non-archive context as well [#49627](https://github.com/woocommerce/woocommerce/pull/49627)
* Update - Add pattern validation for global_unique_id [#50501](https://github.com/woocommerce/woocommerce/pull/50501)
* Update - Clear global_unique_id when restoring a product that doesn't have an unique id [#50496](https://github.com/woocommerce/woocommerce/pull/50496)
* Update - Use admin password reset on admin login screen [#50200](https://github.com/woocommerce/woocommerce/pull/50200)
* Update - Prevent creation of password-protected coupons. [#50236](https://github.com/woocommerce/woocommerce/pull/50236)
* Update - Add a link to the Theming docs from the blockified templates README.md file [#48538](https://github.com/woocommerce/woocommerce/pull/48538)
* Update - Add a new icon style to the "Customer Account" block. [#48979](https://github.com/woocommerce/woocommerce/pull/48979)
* Update - Adds setting to control the visibility of product count in Mini cart block [#48545](https://github.com/woocommerce/woocommerce/pull/48545)
* Update - Add tracking for enable auto renew links on notices [#49710](https://github.com/woocommerce/woocommerce/pull/49710)
* Update - Add UTM parameters to subscription renewal notice links. [#49645](https://github.com/woocommerce/woocommerce/pull/49645)
* Update - Adjust input field height and input label text size. [#49636](https://github.com/woocommerce/woocommerce/pull/49636)
* Update - Adjust top margin of the coupon code in the Cart and Checkout blocks. [#49603](https://github.com/woocommerce/woocommerce/pull/49603)
* Update - CYS - Add borders to footer and header patterns on the assembler. [#49299](https://github.com/woocommerce/woocommerce/pull/49299)
* Update - CYS - Add missing patterns to their categories for the assembler [#49154](https://github.com/woocommerce/woocommerce/pull/49154)
* Update - CYS - Add tracking events to pattern features. [#49556](https://github.com/woocommerce/woocommerce/pull/49556)
* Update - CYS - Disable the Full Composability for CYS AI flows [#49290](https://github.com/woocommerce/woocommerce/pull/49290)
* Update - CYS - Fetch patterns from the private dotcom patterns category instead of from the default source site. [#49007](https://github.com/woocommerce/woocommerce/pull/49007)
* Update - CYS - Fetch patterns from the WooCommerce PTK source site. [#48492](https://github.com/woocommerce/woocommerce/pull/48492)
* Update - CYS - Filter out patterns with external dependencies. [#48618](https://github.com/woocommerce/woocommerce/pull/48618)
* Update - CYS - Fix CSS spacing issues in the assembler. [#49232](https://github.com/woocommerce/woocommerce/pull/49232)
* Update - CYS - Fix dark patterns buttons color. [#49181](https://github.com/woocommerce/woocommerce/pull/49181)
* Update - CYS - Fix the column spacing for the "Four Image Grid Content Left" pattern [#49669](https://github.com/woocommerce/woocommerce/pull/49669)
* Update - CYS - Fix the font size of the "DON'T HAVE A LOGO YET?" title. [#49231](https://github.com/woocommerce/woocommerce/pull/49231)
* Update - CYS - Fix the intro cards size to match the designs. [#49297](https://github.com/woocommerce/woocommerce/pull/49297)
* Update - CYS - Fix the pattern preview border color on hover and for inserted patterns. [#49206](https://github.com/woocommerce/woocommerce/pull/49206)
* Update - CYS - Improve margins for CYS core patterns. [#49196](https://github.com/woocommerce/woocommerce/pull/49196)
* Update - CYS - Improve the designs of the Intro page bottom cards. [#48983](https://github.com/woocommerce/woocommerce/pull/48983)
* Update - CYS - Include the dotcom patterns from the "Reviews" category. [#49140](https://github.com/woocommerce/woocommerce/pull/49140)
* Update - CYS - Make some titles bold on CYS patterns. [#49151](https://github.com/woocommerce/woocommerce/pull/49151)
* Update - CYS - Make the patterns content translatable for patterns in the dictionary. [#49633](https://github.com/woocommerce/woocommerce/pull/49633)
* Update - CYS - Register PTK "Testimonials" patterns as "Reviews" [#48674](https://github.com/woocommerce/woocommerce/pull/48674)
* Update - CYS - Remove non-default patterns and register them from the PTK. Update margins. [#49101](https://github.com/woocommerce/woocommerce/pull/49101)
* Update - CYS - Schedule the `fetch_patterns` actions only once every hour. [#49754](https://github.com/woocommerce/woocommerce/pull/49754)
* Update - CYS - Update pattern categories and its descriptions. [#48665](https://github.com/woocommerce/woocommerce/pull/48665)
* Update - CYS - Update pattern toolbar delete button copy to `Delete`. [#49295](https://github.com/woocommerce/woocommerce/pull/49295)
* Update - CYS - Update the full composability layout styles [#49303](https://github.com/woocommerce/woocommerce/pull/49303)
* Update - CYS - Update the intro pages for different type of themes. [#49910](https://github.com/woocommerce/woocommerce/pull/49910)
* Update - CYS: Add the proper tracking string to the external Fiverr link in sidebar of the **Add your logo** screen. [#49745](https://github.com/woocommerce/woocommerce/pull/49745)
* Update - CYS: Add `rel="noreferrer"` to External Fiverr Link in sidebar of **Add your logo** screen. [#49314](https://github.com/woocommerce/woocommerce/pull/49314)
* Update - CYS: Improve Block Toolbar logic. [#48799](https://github.com/woocommerce/woocommerce/pull/48799)
* Update - CYS: improve copy no blocks placeholder. [#49030](https://github.com/woocommerce/woocommerce/pull/49030)
* Update - CYS: Improve patterns order [#49204](https://github.com/woocommerce/woocommerce/pull/49204)
* Update - CYS: no highlight the pattern when it is added. [#48802](https://github.com/woocommerce/woocommerce/pull/48802)
* Update - CYS: Remove margin last pattern preview [#49767](https://github.com/woocommerce/woocommerce/pull/49767)
* Update - CYS: Remove not necessary patterns. [#48750](https://github.com/woocommerce/woocommerce/pull/48750)
* Update - CYS: Revisit sidebar layout. [#48803](https://github.com/woocommerce/woocommerce/pull/48803)
* Update - CYS: Update Block Toolbar Position [#48662](https://github.com/woocommerce/woocommerce/pull/48662)
* Update - CYS: Update icon used by the "Customer account" block into header patterns [#49133](https://github.com/woocommerce/woocommerce/pull/49133)
* Update - CYS: Update sidebar homepage copy [#48882](https://github.com/woocommerce/woocommerce/pull/48882)
* Update - CYS: Update verbiage in the CTA to our Fiverr Logo Maker landing page. [#48987](https://github.com/woocommerce/woocommerce/pull/48987)
* Update - CYS: when the footer/header is clicked, the border color is blue. [#48765](https://github.com/woocommerce/woocommerce/pull/48765)
* Update - Deprecate and create new coming soon block version [#49786](https://github.com/woocommerce/woocommerce/pull/49786)
* Update - E2E: check the `Add` button when creating product variations in the new Product Editor [#48928](https://github.com/woocommerce/woocommerce/pull/48928)
* Update - E2E: in the new Product Editor app, update how to detect when global attributes are loaded. [#48915](https://github.com/woocommerce/woocommerce/pull/48915)
* Update - E2E: remove UI check when creating attribute global terms [#48934](https://github.com/woocommerce/woocommerce/pull/48934)
* Update - Ensure expiration-related modal is shown to the installed Woo subscriptions [#49747](https://github.com/woocommerce/woocommerce/pull/49747)
* Update - Ensures the product ID is valid when interacting with product variations via the REST API. [#48804](https://github.com/woocommerce/woocommerce/pull/48804)
* Update - Ensure that active plugins shown in the System Status api endpoint actually exist [#48709](https://github.com/woocommerce/woocommerce/pull/48709)
* Update - Ensuring product creation with unique sku for concurrent requests [#47476](https://github.com/woocommerce/woocommerce/pull/47476)
* Update - Fix: Show preview label only when Product Collection block is selected [#48795](https://github.com/woocommerce/woocommerce/pull/48795)
* Update - Fix Classic Template block registration on WP 6.6 [#48730](https://github.com/woocommerce/woocommerce/pull/48730)
* Update - Fix typo on Congratulations screen [#49233](https://github.com/woocommerce/woocommerce/pull/49233)
* Update - Hide account creation options not relevent to block checkout when using block checkout. [#49389](https://github.com/woocommerce/woocommerce/pull/49389)
* Update - Improve rendering of order list table on mobile. [#49592](https://github.com/woocommerce/woocommerce/pull/49592)
* Update - Improve the handling of the deprecated WC()->api property [#48884](https://github.com/woocommerce/woocommerce/pull/48884)
* Update - Make proceed to order button non sticky when zoom level is bigger than 100% [#48391](https://github.com/woocommerce/woocommerce/pull/48391)
* Update - Make Single Product gallery thumbnail images sharper by defining a srcset [#49112](https://github.com/woocommerce/woocommerce/pull/49112)
* Update - Migrate the cart and checkout block's state, country and custom field input to a native select [#48180](https://github.com/woocommerce/woocommerce/pull/48180)
* Update - Move remote logger to `./src` and improve `fetch_latest_woocommerce_version()` logic [#49639](https://github.com/woocommerce/woocommerce/pull/49639)
* Update - Optimize the method that gets the downloads count for a given download [#49008](https://github.com/woocommerce/woocommerce/pull/49008)
* Update - preparing checkout blocks docs for dev docs site [#49010](https://github.com/woocommerce/woocommerce/pull/49010)
* Update - Product Collection: revert renaming "Sync with current query" option [#49907](https://github.com/woocommerce/woocommerce/pull/49907)
* Update - Product Editor: improve E2E tests. Test the `+3 More` item label in the Organization tab [#48891](https://github.com/woocommerce/woocommerce/pull/48891)
* Update - Product Editor: restore and fix E2E test that creates product variations [#48725](https://github.com/woocommerce/woocommerce/pull/48725)
* Update - Product Editor: restore Product (local) Attributes E2E test [#48871](https://github.com/woocommerce/woocommerce/pull/48871)
* Update - Product Editor: update create product variations E2E test [#48627](https://github.com/woocommerce/woocommerce/pull/48627)
* Update - Redesigned the Product Collection block's insertion journey. [#48911](https://github.com/woocommerce/woocommerce/pull/48911)
* Update - Remove Jetpack copy experiment from core profiler [#49452](https://github.com/woocommerce/woocommerce/pull/49452)
* Update - Remove the hooked blocks feature gate and replace with wc_hooked_blocks_version option [#49302](https://github.com/woocommerce/woocommerce/pull/49302)
* Update - Replace the "Customer account" line logo. [#49666](https://github.com/woocommerce/woocommerce/pull/49666)
* Update - Return HTTP 404 for REST API requests involving non-existing tax class. [#48579](https://github.com/woocommerce/woocommerce/pull/48579)
* Update - Return HTTP 404 when accessing non-existent webhooks via REST API. [#48729](https://github.com/woocommerce/woocommerce/pull/48729)
* Update - Return HTTP 404 when trying to read or delete a non-existent product review. [#48726](https://github.com/woocommerce/woocommerce/pull/48726)
* Update - Run full e2e tests suite against Pressable and WPCOM websites. [#49597](https://github.com/woocommerce/woocommerce/pull/49597)
* Update - Update content for usage tracking modal for CYS experience [#49911](https://github.com/woocommerce/woocommerce/pull/49911)
* Update - Updated account settings descriptions for added clarity [#48556](https://github.com/woocommerce/woocommerce/pull/48556)
* Update - Update Jetpack's new SSO classes and methods to prevent deprecation notice. [#49752](https://github.com/woocommerce/woocommerce/pull/49752)
* Update - Update required and tested up to WP versions for the WordPress 6.6 release. [#49619](https://github.com/woocommerce/woocommerce/pull/49619)
* Update - Update Settings to disable Save button unless modifications are made. [#47444](https://github.com/woocommerce/woocommerce/pull/47444)
* Update - Update shipping method setup modal copy if the block-based local pickup is enabled [#48529](https://github.com/woocommerce/woocommerce/pull/48529)
* Update - Update Store Alert styles [#49174](https://github.com/woocommerce/woocommerce/pull/49174)
* Update - Update Store Alert widths to match main body [#48487](https://github.com/woocommerce/woocommerce/pull/48487)
* Update - Update the "Customer Account" block icon for the line style. [#49401](https://github.com/woocommerce/woocommerce/pull/49401)
* Update - Update the CYS opt-in messaging [#49894](https://github.com/woocommerce/woocommerce/pull/49894)
* Update - Update the footer section in "Add products" task [#49782](https://github.com/woocommerce/woocommerce/pull/49782)
* Update - Update WC Tasks in the WC Home. Rename to WooCommerce marketplace, add new browse marketplace, remove connect to woocomerce.com from inbox [#48128](https://github.com/woocommerce/woocommerce/pull/48128)
* Update - Utilize the new shared component to showcase WooPayments payment method logos. [#49300](https://github.com/woocommerce/woocommerce/pull/49300)
* Dev - Add Allure to Blocks e2e tests [#49228](https://github.com/woocommerce/woocommerce/pull/49228)
* Dev - Add daily checks for core e2e with PHP 8.1 and WP latest-1 [#48929](https://github.com/woocommerce/woocommerce/pull/48929)
* Dev - Add hook to customize the rendered receipt template [#48872](https://github.com/woocommerce/woocommerce/pull/48872)
* Dev - Add new CI workflow to trigger tests on demand. [#49674](https://github.com/woocommerce/woocommerce/pull/49674)
* Dev - Add support for e2e testing against external sites in CI [#49017](https://github.com/woocommerce/woocommerce/pull/49017)
* Dev - Another attempt to stabilize flaky Product Collection E2E tests. [#49638](https://github.com/woocommerce/woocommerce/pull/49638)
* Dev - Blocks E2E: Fix a flaky Product Collection test where accidental multiple edits occur and break the template saving step. [#49590](https://github.com/woocommerce/woocommerce/pull/49590)
* Dev - Blocks E2E: Fix DB snapshot removal step in setup script. [#49677](https://github.com/woocommerce/woocommerce/pull/49677)
* Dev - Build: speedup dependencies installation by disabling composer optimize autoloading by default. [#48980](https://github.com/woocommerce/woocommerce/pull/48980)
* Dev - CI: buffix for linting missing strict types directive. [#49015](https://github.com/woocommerce/woocommerce/pull/49015)
* Dev - CI: cleanup CI related command after fixing jobs matrix generation. [#49330](https://github.com/woocommerce/woocommerce/pull/49330)
* Dev - CI: code style fixes to pass linting in updated CI environment. [#49020](https://github.com/woocommerce/woocommerce/pull/49020)
* Dev - CI: improve flacky tests reporting job execution time. [#49665](https://github.com/woocommerce/woocommerce/pull/49665)
* Dev - CI: Re-group PHPUnit jobs. [#49443](https://github.com/woocommerce/woocommerce/pull/49443)
* Dev - CI: reduce running time for PHPUnit related jobs. [#49193](https://github.com/woocommerce/woocommerce/pull/49193)
* Dev - CI: tuning deps caching for playwright. [#49081](https://github.com/woocommerce/woocommerce/pull/49081)
* Dev - CI config: update changes lists to include wp-env config [#49626](https://github.com/woocommerce/woocommerce/pull/49626)
* Dev - Clean up unused files in plugins/woocommerce-blocks [#49319](https://github.com/woocommerce/woocommerce/pull/49319)
* Dev - Create a separate JS cart and checkout JavaScript bundle to improve performance. [#48010](https://github.com/woocommerce/woocommerce/pull/48010)
* Dev - CYS - Fix the "test_fetch_patterns_should_register_testimonials_category_as_reviews" tests. [#48719](https://github.com/woocommerce/woocommerce/pull/48719)
* Dev - Dropping select2 and point it to SelectWoo [#48731](https://github.com/woocommerce/woocommerce/pull/48731)
* Dev - E2E: enable slow tests reporting for blocks E2E tests. [#49367](https://github.com/woocommerce/woocommerce/pull/49367)
* Dev - E2E tests: fix basic spec for multiple environments [#49609](https://github.com/woocommerce/woocommerce/pull/49609)
* Dev - E2E tests: fix failing settings-tax e2e test [#48792](https://github.com/woocommerce/woocommerce/pull/48792)
* Dev - E2E tests: Fix flaky account email receiving test [#48957](https://github.com/woocommerce/woocommerce/pull/48957)
* Dev - E2E tests: Fix flaky connect to Woo.com test [#48926](https://github.com/woocommerce/woocommerce/pull/48926)
* Dev - E2E tests: Fix flaky filling regular price in the inventory tab [#49226](https://github.com/woocommerce/woocommerce/pull/49226)
* Dev - E2E tests: Fix flaky filling SKU field and CYS footer [#49191](https://github.com/woocommerce/woocommerce/pull/49191)
* Dev - E2E tests: Fix flaky Gutenberg, WC Services tests [#48916](https://github.com/woocommerce/woocommerce/pull/48916)
* Dev - E2E tests: Fix flaky Gutenberg tests [#48896](https://github.com/woocommerce/woocommerce/pull/48896)
* Dev - E2E tests: Fix flaky Gutenberg tests [#49548](https://github.com/woocommerce/woocommerce/pull/49548)
* Dev - E2E tests: Fix flaky logo picker waiting for response tests [#49451](https://github.com/woocommerce/woocommerce/pull/49451)
* Dev - E2E tests: Fix flaky merchant filling sku field in the new editor [#49134](https://github.com/woocommerce/woocommerce/pull/49134)
* Dev - E2E tests: Fix flaky merchant tests [#49381](https://github.com/woocommerce/woocommerce/pull/49381)
* Dev - E2E tests: Fix merchant settings general test [#48907](https://github.com/woocommerce/woocommerce/pull/48907)
* Dev - E2E tests: fix shopper checkout block test [#49596](https://github.com/woocommerce/woocommerce/pull/49596)
* Dev - E2E tests: fix some tests for WP 6.6 [#49634](https://github.com/woocommerce/woocommerce/pull/49634)
* Dev - E2E tests: tag different envs in e2e test suite to run in workflows [#48715](https://github.com/woocommerce/woocommerce/pull/48715)
* Dev - Final sanity check to make sure attributes are done saving [#48737](https://github.com/woocommerce/woocommerce/pull/48737)
* Dev - Fix broken syntax in e2e-guidelines.md. [#49018](https://github.com/woocommerce/woocommerce/pull/49018)
* Dev - Fix flaky orphaned refund test [#49741](https://github.com/woocommerce/woocommerce/pull/49741)
* Dev - Hide product filters overlay template part experimental feature from public release [#49564](https://github.com/woocommerce/woocommerce/pull/49564)
* Dev - In blocks codebase, export SITE_CURRENCY property with properties matching typescript definitions. [#48727](https://github.com/woocommerce/woocommerce/pull/48727)
* Dev - Lint new PHP files for strict types directive [#48943](https://github.com/woocommerce/woocommerce/pull/48943)
* Dev - Minor tooling tweaks (zip compression level, composer invocation) [#48857](https://github.com/woocommerce/woocommerce/pull/48857)
* Dev - Monorepo: enable Jest and babel-loader caching. [#49656](https://github.com/woocommerce/woocommerce/pull/49656)
* Dev - Monorepo: fix side-effects of setting strict mode for linting script. [#49436](https://github.com/woocommerce/woocommerce/pull/49436)
* Dev - Monorepo: minor tweaks in zip building script (use frozen lock file when installing dependecies). [#49640](https://github.com/woocommerce/woocommerce/pull/49640)
* Dev - Monorepo: refine approach to patching dependecies in favour of built-in pnpm functionality. [#49892](https://github.com/woocommerce/woocommerce/pull/49892)
* Dev - Monorepo: set strict mode for linting script. [#49366](https://github.com/woocommerce/woocommerce/pull/49366)
* Dev - Monorepo: tweak patching dependencies for better Webpack perfromance. [#49703](https://github.com/woocommerce/woocommerce/pull/49703)
* Dev - Move buildkite-test-collector to devDependencies [#49051](https://github.com/woocommerce/woocommerce/pull/49051)
* Dev - move docs out of main folder until subcategories are ready [#49354](https://github.com/woocommerce/woocommerce/pull/49354)
* Dev - Product Collection: add tracking for block usage [#46466](https://github.com/woocommerce/woocommerce/pull/46466)
* Dev - Remove performance tests from PR checks (leave on push to trunk) [#48927](https://github.com/woocommerce/woocommerce/pull/48927)
* Dev - Switch `render()` to `createRoot().render()` to use React 18 features. [#48858](https://github.com/woocommerce/woocommerce/pull/48858)
* Dev - Tests: pin wp-env core version to 6.5 (temporary until tests are fixed to pass with 6.6) [#49620](https://github.com/woocommerce/woocommerce/pull/49620)
* Dev - Tweaks related to caching Composer dependecies and Playwright downloads in CI. [#48865](https://github.com/woocommerce/woocommerce/pull/48865)
* Dev - Update Action Scheduler to 3.8.1 [#49483](https://github.com/woocommerce/woocommerce/pull/49483)
* Dev - Update a few e2e tests failing on the daily run [#49313](https://github.com/woocommerce/woocommerce/pull/49313)
* Dev - Update all values to be random so that retries don't fail on assertions [#48734](https://github.com/woocommerce/woocommerce/pull/48734)
* Dev - Updated CodeSniffer configuration to address conflicting rules. [#49183](https://github.com/woocommerce/woocommerce/pull/49183)
* Dev - Update Playwright from 1.44 to 1.45 [#49202](https://github.com/woocommerce/woocommerce/pull/49202)
* Tweak - Add admin_install_timestamp in WC_Tracker [#50076](https://github.com/woocommerce/woocommerce/pull/50076)
* Tweak - Add $wpdb->esc_like to the search criteria when searching for a product custom field name [#48949](https://github.com/woocommerce/woocommerce/pull/48949)
* Tweak - Add the initially installed WooCommerce version to the wp_options table [#49139](https://github.com/woocommerce/woocommerce/pull/49139)
* Tweak - Change CLIRunner namespace for better PSR compatibility. [#49390](https://github.com/woocommerce/woocommerce/pull/49390)
* Tweak - Equalize data in Order export with data in Client side CSV export [#49356](https://github.com/woocommerce/woocommerce/pull/49356)
* Tweak - Exclude coming soon patterns from block inserter [#48821](https://github.com/woocommerce/woocommerce/pull/48821)
* Tweak - Fix tip block syntax in register-product-collection.md [#49785](https://github.com/woocommerce/woocommerce/pull/49785)
* Tweak - Get tax line label instead of name in StoreAPI Order endpoint. [#48445](https://github.com/woocommerce/woocommerce/pull/48445)
* Tweak - Improve checks when offering to remove test orders [#49032](https://github.com/woocommerce/woocommerce/pull/49032)
* Tweak - Initialize BlockTemplatesController for block themes only. [#48905](https://github.com/woocommerce/woocommerce/pull/48905)
* Tweak - Product Collection: flatten telemetry query filters data to json string [#49680](https://github.com/woocommerce/woocommerce/pull/49680)
* Tweak - Remove enctype from verify email form [#48859](https://github.com/woocommerce/woocommerce/pull/48859)
* Tweak - Remove unneeded IE styling as IE is no longer supported [#49027](https://github.com/woocommerce/woocommerce/pull/49027)
* Tweak - Rename Google Listings and Ads with Google for WooCommerce [#47614](https://github.com/woocommerce/woocommerce/pull/47614)
* Tweak - Show Guest when there is no Customer name [#49594](https://github.com/woocommerce/woocommerce/pull/49594)
* Tweak - Trigger doing_it_wrong() when using HPOS query args for CPT order queries. [#47457](https://github.com/woocommerce/woocommerce/pull/47457)
* Tweak - Update text to Content right with image left pattern [#49792](https://github.com/woocommerce/woocommerce/pull/49792)
* Tweak - Update the "API enabled" entry in the System Status Report to clarify that it pertains to the Legacy REST API. [#48878](https://github.com/woocommerce/woocommerce/pull/48878)
* Tweak - Add placeholder options and validation to all checkout select inputs. [#49929](https://github.com/woocommerce/woocommerce/pull/49929)
* Performance - Load REST API namespaces only when needed. [#47704](https://github.com/woocommerce/woocommerce/pull/47704)
* Performance - Reduced number of recalculations on Store API cart routes [#48944](https://github.com/woocommerce/woocommerce/pull/48944)
* Enhancement - Add address title to edit/add buttons on My Account page [#49171](https://github.com/woocommerce/woocommerce/pull/49171)
* Enhancement - Added password field to block checkout (when enabled in settings) for new accounts to set a custom password. [#48985](https://github.com/woocommerce/woocommerce/pull/48985)
* Enhancement - Add required indication to login forms [#48743](https://github.com/woocommerce/woocommerce/pull/48743)
* Enhancement - Add scope attributes to the order table on My Account [#49201](https://github.com/woocommerce/woocommerce/pull/49201)
* Enhancement - Add strength meter to block checkout password field. [#49164](https://github.com/woocommerce/woocommerce/pull/49164)
* Enhancement - Allow blocks with parents in the "woocommerce" namespace to be added to the Checkout block without requiring them to be added to the "__experimental_woocommerce_blocks_add_data_attributes_to_block" hook. [#48543](https://github.com/woocommerce/woocommerce/pull/48543)
* Enhancement - Convert edit address link to a button on checkout [#49471](https://github.com/woocommerce/woocommerce/pull/49471)
* Enhancement - CYS: make the entire shuffle section clickable. [#48889](https://github.com/woocommerce/woocommerce/pull/48889)
* Enhancement - CYS: Remove iframe animation [#48941](https://github.com/woocommerce/woocommerce/pull/48941)
* Enhancement - Made the "return to cart" link (in the checkout block) hidden by default. [#48762](https://github.com/woocommerce/woocommerce/pull/48762)
* Enhancement - Provide the location context within the Product Collection block context [#44145](https://github.com/woocommerce/woocommerce/pull/44145)
* Enhancement - Updated block checkout and Store API stock handling so stock is only reserved when attempting payment for an order. [#49446](https://github.com/woocommerce/woocommerce/pull/49446)
= 9.1.4 2024-07-26 =
**WooCommerce**
@ -8,7 +594,6 @@
* Fix - Hardening against XSS via the Product Button unescaped attribute. [#50010](https://github.com/woocommerce/woocommerce/pull/50010)
* Fix - Enhance escaping for block attributes. [#50015](https://github.com/woocommerce/woocommerce/pull/50015)
= 9.1.2 2024-07-12 =
**WooCommerce**
@ -5901,12 +6486,12 @@
* Dev - Revert work done in #4857 for automated shipping after OBW is completed #5971
* Add - Welcome modal when coming from Calypso #6004
* Enhancement - Add an a/b experiment for installing free business features #5786
* Dev - Add `onChangeCallback` feature to the wc-admin `<Form>` component #5786
* Dev - Add `onChangeCallback` feature to the wc-admin `<Form>` component #5786
* Fix - Generate JSON translation chunks on plugin activation #6028
* Dev - Add merchant email notifications #5922
* Dev - Add merchant email notifications #5922
* Add - Email note to add first product. #6024
* Add - Note for users coming from Calypso. #6030
* Enhancement - Add an "unread" indicator to inbox messages. #6047
* Enhancement - Add an "unread" indicator to inbox messages. #6047
* Add - Manage activity from home screen inbox message. #6072
= 4.9.5 2022-03-10 =
@ -6709,7 +7294,7 @@
* Fix - The WCPay method not appearing as recommended sometimes #4345
* Fix - Removed URLSearchParams method #4501
* Fix - REST API collections schema. #4484
* Fix - null issue in wpNavMenuClassChange #4513 🎉 gradosevic
* Fix - null issue in wpNavMenuClassChange #4513 🎉 gradosevic
* Fix - RTL stylesheet loading for split code chunks. #4542
* Fix - Don't show store location step in tax and shipping tasks if the address has already been provided #4507
* Fix - Check for enabled methods before payment task completion #4530
@ -6851,7 +7436,7 @@
* Dev - Fixed failing unit tests. #105
**WooCommerce Admin 1.2.3**
* Enhancement - Add onboarding payments note #4157
* Enhancement - Add onboarding payments note #4157
* Enhancement - Marketing Inbox Note #4030
* Performance - Use Route based code splitting to reduce bundle size #4094
* Performance - trim down inbox note API request. #3977
@ -7262,7 +7847,7 @@
* Dev - Add a filter `woocommerce_ajax_add_order_item_validation` to allow validations in `add_order_item` function. #24518
* Dev - Use `wc_get_cart_url` instead of `wc_get_page_permalink( 'cart' )` because former has a filter `woocommerce_get_cart_url` to allow customization. #24530
* Dev - New `woocommerce_product_after_tabs` action hook added. #24694
* Dev - Enable append hashes on custom events (like ajax requests) #24665
* Dev - Enable append hashes on custom events (like ajax requests) #24665
* Dev - Introduced `woocommerce_order_get_formatted_billing_address` and `woocommerce_order_get_formatted_shipping_address` filters. #24677
* Dev - WC_Abstract_Order::recalculate_coupons() is public now. #24740
* Dev - Added 'applied_coupon' trigger to checkout.js. #24406
@ -7375,7 +7960,7 @@
* Tweak - Update the generate username setting description label to reflect how the username is actually generated. #23911
* Tweak - OBW: Adjust plugin highlight container sizes to avoid overlap. #23997
* Tweak - Round tax amounts late when the round at subtotal level setting is enabled to reduce rounding errors. #24024
* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058
* Tweak - OBW: Now includes WooCommerce Admin as a recommended plugin. #24058
* Template - Review and update all template files escaping. #23460
* Template - Remove mention of shipping section from the checkout/form-login.php template as shipping is not always a requirement for an order. #23941
* Template - Add new filter `woocommerce_before_thankyou` to the checkout/thankyou.php template. #23538
@ -8047,7 +8632,7 @@
* Fix - Fix warning when using logger instance in woocommerce_logging_class filter. #21448
* Fix - Use uppercase "ID" when sorting product queries by ID. #21461
* Fix - Consistently escape the gateway ID in the checkout payment method template. #21439
* Fix - Avoid treating HTTP 301 and 302 codes as failures for webhooks. #21491
* Fix - Avoid treating HTTP 301 and 302 codes as failures for webhooks. #21491
* Fix - Add address_1 to shipping packages info in WC_Cart:: get_shipping_packages to make it work correctly in address formatting functions. #21493
* Fix - Don't fire two of the same action when saving shipping settings. #21494
* Fix - Remove double condition for address line 2 in `WC_Countries::get_default_address_fields`. #20629
@ -8359,7 +8944,7 @@
* Fix - Delete orphaned variations after product import. #19378
* Fix - Ensure API credentials exist before defining PayPal refund support. #19380
* Fix - Force word-wrapping in the log viewer to prevent layout-breaking long lines. #19503
* Fix - Removes permission checks that were preventing webhooks from displaying properly when no post object existed. #19508
* Fix - Removes permission checks that were preventing webhooks from displaying properly when no post object existed. #19508
* Fix - Empty cart after completing PayPal payment. #19509
* Fix - Strip tags on aria-labels in Add to Cart template to prevent broken HTML. #19522
* Fix - Update post_modified date when saving products and variations but no other product data. #19595
@ -8381,7 +8966,7 @@
* Fix - WC API should not try to create a product image when creating a product variation if an empty image is passed. #19971
* Fix - Force settings API settings to autoload by default. #19998
* Fix - Cart html5 validation events when using keyboard. #20001
* Fix - Don't show stock status fields in external product quick-edit. #20005
* Fix - Don't show stock status fields in external product quick-edit. #20005
* Fix - Prevent an infinite loop if 2 grouped products are linked. #20020
* Fix - Switch stock_status when manage stock gets changed to prevent being out of stock if stock quantity is > 0. #20021
* Fix - When duplicating variation, set the date to null. #20083
@ -8643,7 +9228,7 @@
* Fix - is_visible should ensure product is is not trashed before returning true.
* Fix - Return packages with no rates back to the cart so the shipping calculator is displayed even when the current country is not shippable.
* Fix - Merge session and persistent carts when both exists after login.
* Fix - Remove "wc_error" query string after login.
* Fix - Remove "wc_error" query string after login.
* Fix - Allow woocommerce_form_field() have 'custom_attributes' equal 0.
* Fix - Bulk actions in status logs table.
* Fix - Exclude add-to-cart from pagination links.
@ -8684,19 +9269,19 @@
* Fix - Removed class within class in admin meta boxes HTML.
* Fix - Fixed wrong `flex-control-nav` selector scope in `add-to-cart-variation.js`
* Fix - Allow variations to be added to cart from query string.
* Fix - Use `add_filter` for `comment_feed_where` hook.
* Fix - Use `add_filter` for `comment_feed_where` hook.
* Fix - Change nocache_headers hook firing in the cache helper.
* Fix - Coupon min/max spend based on displayed subtotal.
* Fix - Fix event propagation on click in setup wizard and improve validation.
* Fix - API - Change how line items are saved in API so calculations are correct.
* Tweak - Hide downloads from admin emails.
* Tweak - Hide downloads from admin emails.
* Tweak - Set placeholder for variation lxwxh field to that of the parent.
* Tweak - Improve the Add Payment Methods display so buttons are not shown when no payment methods support the feature.
* Localization - Update NJ tax rate.
* Localization - Add Belarusian ruble BYN.
= 3.2.3 - 2017-11-02 =
* Fix - Fixed a conflict with some slider plugins due to sanitization of archive/term descriptions.
* Fix - Fixed a conflict with some slider plugins due to sanitization of archive/term descriptions.
* Fix - Fixed a flexslider bug when there is only 1 image on the product page (no gallery).
* Fix - Prevent potential notices when someone extends product tabs wrongly.
* Fix - Fixed display of shipping calculator under some conditions.

View File

@ -3,7 +3,7 @@
"MD003": { "style": "atx" },
"MD007": { "indent": 4 },
"MD013": { "line_length": 9999 },
"MD024": { "allow_different_nesting": true },
"MD024": { "siblings_only": true },
"MD033": { "allowed_elements": ["video"] },
"MD035": false,
"MD041": false,

View File

@ -0,0 +1,5 @@
---
category_title: Block Theme Development
category_slug: block-theme-development
post_title: Block theme development
---

View File

@ -0,0 +1,84 @@
---
post_title: Cart and checkout blocks theming
menu_title: Cart and Checkout Blocks Theming
tags: reference
---
> [!IMPORTANT]
> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_.
## Buttons
WC Blocks introduces the button component, it differs from a generic `button` in that it has some default styles to make it correctly fit in the Blocks design.
![Button screenshot](https://user-images.githubusercontent.com/3616980/86381945-e6fd6c00-bc8d-11ea-8811-7e546bea69b9.png)
Themes can still style them to match theme colors or styles as follows:
```css
.wc-block-components-button {
background-color: #d5502f;
color: #fff;
/* More rules can be added to modify the border, shadow, etc. */
}
/* It might be needed to modify the hover, focus, active and disabled states too */
```
![Button screenshot with custom styles](https://user-images.githubusercontent.com/3616980/86381505-b6b5cd80-bc8d-11ea-8ceb-cfbe84b411d4.png)
Notice the button component doesn't have the `.button` class name. So themes that wrote some styles for buttons might want to apply some (or all) of those styles to the button component as well.
## Mobile submit container
In small viewports, the Cart block displays the _Proceed to Checkout_ button inside a container fixed at the bottom of the screen.
![Submit container screenshot](https://user-images.githubusercontent.com/3616980/86382876-393e8d00-bc8e-11ea-8d0b-e4e347ea4773.png)
By default, the container has a white background so it plays well with the button component default colors. Themes that want to apply the same background color as the rest of the page can do it with the following code snippet:
```css
.wc-block-cart__submit-container {
background-color: #f9f4ee;
}
```
Take into consideration the container has a top box shadow that might not play well with some dark background colors. If needed, it can be modified directly setting the `color` property (internally, shadow color uses `currentColor`, so it honors the `color` property):
```css
.wc-block-cart__submit-container::before {
color: rgba( 214, 209, 203, 0.5 );
}
```
Alternatively, themes can override the `box-shadow` property completely:
```css
.wc-block-cart__submit-container::before {
box-shadow: 0 -10px 20px 10px rgba( 214, 209, 203, 0.5 );
}
```
![Submit container screenshot with custom styles](https://user-images.githubusercontent.com/3616980/86382693-27f58080-bc8e-11ea-894e-de378af3e2bb.png)
## Item quantity badge
The item quantity badge is the number that appears next to the image in the _Order summary_ section of the _Checkout_ block sidebar.
![Order summary screenshot](https://user-images.githubusercontent.com/3616980/83862844-c8559500-a722-11ea-9653-2fc8bcd544d2.png)
By default, it uses a combination of black and white borders and shadows so it has enough contrast with themes with light and dark backgrounds. Themes can modify the colors with their own palette with a single CSS selector and four properties. For example:
```css
.wc-block-components-order-summary-item__quantity {
background-color: #f9f4ee;
border-color: #4b3918;
box-shadow: 0 0 0 2px #f9f4ee;
color: #4b3918;
}
```
![Order summary screenshot with custom styles for the item quantity badge](https://user-images.githubusercontent.com/3616980/83863109-2e421c80-a723-11ea-9bf7-2033a96cf5b2.png)

View File

@ -0,0 +1,72 @@
---
post_title: CSS styling for themes
menu_title: CSS Styling for Themes
tags: reference
---
## Block and component class names
> [!IMPORTANT]
> We strongly discourage writing CSS code based on existing block class names and prioritize using global styles when possible. We especially discourage writing CSS selectors that rely on a specific block being a descendant of another one, as users can move blocks around freely, so they are prone to breaking. Similar to WordPress itself, we consider the HTML structure within components, blocks, and block templates to be "private", and subject to further change in the future, so using CSS to target the internals of a block or a block template is _not recommended or supported_.
WooCommerce Blocks follows BEM for class names, as [stated in our coding guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/contributors/coding-guidelines.md). All classes start with one of these two prefixes:
* `.wc-block-`: class names specific to a single block.
* `.wc-block-components-`: class names specific to a component. The component might be reused by different blocks.
The combination of block class names and component class names allows themes to style each component either globally or only in specific blocks. As an example, you could style all prices to be italics with:
```css
/* This will apply to all block prices */
.wc-block-components-formatted-money-amount {
font-style: italic;
}
```
But if you only wanted to make it italic in the Checkout block, that could be done adding the block selector:
```css
/* This will apply to prices in the checkout block */
.wc-block-checkout .wc-block-components-formatted-money-amount {
font-style: italic;
}
```
**Note:** for backwards compatibility, some components might have class names with both prefixes (ie: `wc-block-sort-select` and `wc-block-components-sort-select`). In those cases, the class name with `.wc-block-` prefix is deprecated and shouldn't be used in new code. It will be removed in future versions. If an element has both classes always style the one with `.wc-block-components-` prefix.
## Container query class names
Some of our components have responsive classes depending on the container width. The reason to use these classes instead of CSS media queries is to adapt to the container where the block is added (CSS media queries only allow reacting to viewport sizes).
Those classes are:
Container width | Class name
----------------|------------
\&gt;700px | `is-large`
521px-700px | `is-medium`
401px-520px | `is-small`
&lt;=400px | `is-mobile`
As an example, if we wanted to do the Checkout font size 10% larger when the container has a width of 521px or wider, we could do so with this code:
```css
.wc-block-checkout.is-medium,
.wc-block-checkout.is-large {
font-size: 1.1em;
}
```
## WC Blocks _vs._ theme style conflicts for semantic elements
WooCommerce Blocks uses HTML elements according to their semantic meaning, not their default layout. That means that some times blocks might use an anchor link (`&lt;a&gt;`) but display it as a button. Or the other way around, a `&lt;button&gt;` might be displayed as a text link. Similarly, headings might be displayed as regular text.
In these cases, Blocks include some CSS resets to undo most default styles introduced by themes. A `&lt;button&gt;` that is displayed as a text link will probably have resets for the background, border, etc. That will solve most conflicts out-of-the-box but in some occasions those CSS resets might not have effect if the theme has a specific CSS selector with higher specificity. When that happens, we really encourage theme developers to decrease their selectors specificity so Blocks styles have preference, if that's not possible, themes can write CSS resets on top.
## Hidden elements
WC Blocks use the [`hidden` HTML attribute](https://developer.mozilla.org/en-US/docs/Web/HTML/Global_attributes/hidden) to hide some elements from the UI so they are not displayed in screens neither read by assistive technologies. If your theme has some generic styles that tweak the CSS display property of blocks elements (ie: `div { display: block; }`), make sure you correctly handle the hidden attribute: `div[hidden] { display: none; }`.
## Legacy classes from WooCommerce (.price, .star-rating, .button...)
WooCommerce Blocks avoids using legacy unprefixed classes as much as possible. However, you might find some of them that have been added for backwards compatibility. We still encourage themes to use the prefixed classes when possible, this avoids conflicts with other plugins, the editor, etc.

View File

@ -0,0 +1,85 @@
---
post_title: Theming for Woo blocks
menu_title: Theming for Woo Blocks
tags: reference
---
This page includes documentation about theming WooCommerce blocks and block themes.
**Note:** this document assumes some previous knowledge about block theme development and some WordPress concepts. If you are completely new to block theme development, please check [Develop Your First Low-Code Block Theme](https://learn.wordpress.org/course/develop-your-first-low-code-block-theme/)
to learn about block theme development, and explore
the [Create Block Theme plugin](https://wordpress.org/plugins/create-block-theme/) tool when you're ready to create a
new theme.
## General concepts
### Block templates
WooCommerce comes with several [block templates](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/templates/templates/blockified) by default. Those are:
- Single Product (`single-product.html`)
- Product Catalog (`archive-product.html`)
- Products by Category (`taxonomy-product_cat.html`)
- Products by Tag (`taxonomy-product_tag.html`)
- Products by Attribute (`taxonomy-product_attribute.html`)
- Product Search Results (`product-search-results.html`)
- Page: Coming soon (`page-coming-soon.html`)
- Page: Cart (`page-cart.html`)
- Page: Checkout (`page-checkout.html`)
- Order Confirmation (`order-confirmation.html`)
Block themes can customize those templates in the following ways:
- It's possible to override the templates by creating a file with the same file name under the `/templates` folder. For example, if a block theme contains a `wp-content/themes/yourtheme/templates/single-product.html` template, it will take priority over the WooCommerce default Single Product template.
- Products by Category, Products by Tag and Products by Attribute templates fall back to the Product Catalog template. In other words, if a theme provides an `archive-product.html` template but doesn't provide a `taxonomy-product_cat.html` template, the Products by Category template will use the `archive-product.html` template. Same for the Products by Tag and Products by Attribute templates.
- It's possible to create templates for specific products and taxonomies. For example, if the theme provides a template with file name of `single-product-cap.html`, that template will be used when rendering the product with slug `cap`. Similarly, themes can provide specific taxonomy templates: `taxonomy-product_cat-clothing.html` would be used in the product category with slug `clothing`.
- Always keep in mind users can make modifications to the templates provided by the theme via the Site Editor.
### Block template parts
WooCommerce also comes with two specific [block template parts](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/templates/parts):
- Mini-Cart (`mini-cart.html`): used inside the Mini-Cart block drawer.
- Checkout header (`checkout-header.html`): used as the header in the Checkout template.
Similarly to the templates, they can be overridden by themes by adding a file with the same file name under the `/parts` folder.
### Global styles
WooCommerce blocks rely on [global styles](https://developer.wordpress.org/themes/global-settings-and-styles/styles/) for their styling. Global styles can be defined by themes via `theme.json` or by users via Appearance > Editor > Styles and offer several advantages over plain CSS:
- Better performance, as only the required CSS is printed into the page, reducing the bundle size to render a page.
- Can be easily customized by users via the UI.
- Gracefully handle conflicts between plugins and themes.
- Are not affected by markup or class name updates into individual blocks or components.
- Don't depend on a specific nesting order of blocks: users can freely move blocks around without styles breaking.
#### Example
For example, let's imagine you are building a theme and would like to customize the Product Price block styles, you can do so by adding these properties in your `theme.json`:
```JSON
"styles": {
"blocks": {
"woocommerce/product-price": {
"color": {
"background": "#00cc00",
"text": "#fff"
},
"typography": {
"fontStyle": "italic",
"fontWeight": "700"
}
}
...
}
...
}
```
Before | After
------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
<img src="https://github.com/woocommerce/woocommerce/assets/3616980/fbc11b83-f47b-4b25-bdeb-df798b251cce" width="210" alt="Product Collection block showing the Product Price block with default styles" /> | <img src="https://github.com/woocommerce/woocommerce/assets/3616980/c9730445-b9df-4e96-8204-a10896ac2c5a" width="210" alt="Product Collection block showing the Product Price styled with background and text colors and italic and bold typography" /> <!-- markdownlint-disable-line no-inline-html -->
You can find more [documentation on global styles](https://developer.wordpress.org/themes/global-settings-and-styles/styles/) in developer.wordpress.org. You can also find the [list of WooCommerce blocks and their names in the docs](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/block-references/block-references.md).

View File

@ -1,6 +1,6 @@
---
post_title: How to add a custom field to simple and variable products
menu_title: Add custom fields to products
menu_title: Add Custom Fields to Products
tags: how-to
---
@ -59,7 +59,7 @@ For our Woo extension, we'll be appending our field right at the end with `wooco
Let's get started with creating a new class which will hold the code for the field. Add a new file with the name `class-product-fields.php` to the `/includes/admin/` folder. Within the class, we add our namespace, an abort if anyone tries to call the file directly and a \_\_construct method which calls the `hooks()` method:
```php
<?php
&lt;?php
namespace WooProductField\Admin;
@ -68,7 +68,7 @@ defined( 'ABSPATH' ) || exit;
class ProductFields {
public function __construct() {
$this->hooks();
$this-&gt;hooks();
}
private function hooks() {}
@ -93,19 +93,19 @@ With the class set up and being called, we can create a function to add the cust
```php
public function add_field() {
global $product_object;
?>
<div class="inventory_new_stock_information options_group show_if_simple show_if_variable">
<?php woocommerce_wp_text_input(
?&gt;
&lt;div class="inventory_new_stock_information options_group show_if_simple show_if_variable"&gt;
&lt;?php woocommerce_wp_text_input(
array(
'id' => '_new_stock_information',
'label' => __( 'New Stock', 'woo_product_field' ),
'description' => __( 'Information shown in store', 'woo_product_field' ),
'desc_tip' => true,
'value' => $product_object->get_meta( '_new_stock_information' )
'id' =&gt; '_new_stock_information',
'label' =&gt; __( 'New Stock', 'woo_product_field' ),
'description' =&gt; __( 'Information shown in store', 'woo_product_field' ),
'desc_tip' =&gt; true,
'value' =&gt; $product_object-&gt;get_meta( '_new_stock_information' )
)
); ?>
</div>
<?php
); ?&gt;
&lt;/div&gt;
&lt;?php
}
```
@ -119,8 +119,8 @@ Now that we have our field, we need to save it. For this, we can hook into wooco
public function save_field( $post_id, $post ) {
if ( isset( $_POST['_new_stock_information'] ) ) {
$product = wc_get_product( intval( $post_id ) );
$product->update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'] ) );
$product->save_meta_data();
$product-&gt;update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'] ) );
$product-&gt;save_meta_data();
}
}
```
@ -142,12 +142,12 @@ If we add data and save the product, then the new meta data is inserted into the
At this point you have a working extension that saves a custom field for a product as product meta.
Showing the field in the store
If we want to display the new field in our store, then we can do this with the `get_meta()` method of the Woo product class: `$product->get_meta( '\_new_stock_information' )`
If we want to display the new field in our store, then we can do this with the `get_meta()` method of the Woo product class: `$product-&gt;get_meta( '\_new_stock_information' )`
Let's get started by creating a new file /includes/class-product.php. You may have noticed that this is outside the `/admin/` folder as this code will run in the front. So when we set up the class, we also adjust the namespace accordingly:
```php
<?php
&lt;?php
namespace WooProductField;
@ -155,7 +155,7 @@ defined( 'ABSPATH' ) || exit;
class Product {
public function __construct() {
$this->hooks();
$this-&gt;hooks();
}
private function hooks() { }
@ -190,9 +190,9 @@ In our function we output the stock information with the [appropriate escape fun
```php
public function add_stock_info() {
global $product;
?>
<p><?php echo esc_html( $product->get_meta( '_new_stock_information' ) ); ?> </p>
<?php
?&gt;
&lt;p&gt;&lt;?php echo esc_html( $product-&gt;get_meta( '_new_stock_information' ) ); ?&gt; &lt;/p&gt;
&lt;?php
}
```
@ -223,14 +223,14 @@ The setup is very similar to simple products, the main difference is that we nee
```php
public function add_variation_field( $loop, $variation_data, $variation ) {
$variation_product = wc_get_product( $variation->ID );
$variation_product = wc_get_product( $variation-&gt;ID );
woocommerce_wp_text_input(
array(
'id' => '\_new_stock_information' . '[' . $loop . ']',
'label' => \_\_( 'New Stock Information', 'woo_product_field' ),
'wrapper_class' => 'form-row form-row-full',
'value' => $variation_product->get_meta( '\_new_stock_information' )
'id' =&gt; '\_new_stock_information' . '[' . $loop . ']',
'label' =&gt; \_\_( 'New Stock Information', 'woo_product_field' ),
'wrapper_class' =&gt; 'form-row form-row-full',
'value' =&gt; $variation_product-&gt;get_meta( '\_new_stock_information' )
)
);
}
@ -242,8 +242,8 @@ For saving we use:
public function save_variation_field( $variation_id, $i ) {
if ( isset( $_POST['_new_stock_information'][$i] ) ) {
$variation_product = wc_get_product( $variation_id );
$variation_product->update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'][$i] ) );
$variation_product->save_meta_data();
$variation_product-&gt;update_meta_data( '_new_stock_information', sanitize_text_field( $_POST['_new_stock_information'][$i] ) );
$variation_product-&gt;save_meta_data();
}
}
```
@ -254,4 +254,4 @@ Displaying the variation in the front store works a bit differently for variable
## How to find hooks?
Everyone will have their own preferred way, but for me, the quickest way is to look in the WooCommere plugin code. The code for each data section can be found in `/woocommerce/includes/admin/meta-boxes/views`. To view how the inventory section is handled check the `html-product-data-inventory.php` file, and for variations take a look at `html-variation-admin.php`.
Everyone will have their own preferred way, but for me, the quickest way is to look in the WooCommerce plugin code. The code for each data section can be found in `/woocommerce/includes/admin/meta-boxes/views`. To view how the inventory section is handled check the `html-product-data-inventory.php` file, and for variations take a look at `html-variation-admin.php`.

File diff suppressed because it is too large Load Diff

View File

@ -85,7 +85,7 @@ return (pass);
}
# Block access to php admin pages via website
if (req.url ~ "^/phpmyadmin/.*$" || req.url ~ "^/phppgadmin/.*$" || req.url ~ "^/server-status.*$") {
error 403 "For security reasons, this URL is only accesible using localhost (127.0.0.1) as the hostname";
error 403 "For security reasons, this URL is only accessible using localhost (127.0.0.1) as the hostname";
}
Add this to vcl_fetch:

View File

@ -0,0 +1,5 @@
---
category_title: Cart and Checkout Blocks
category_slug: cart-and-checkout-blocks
post_title: Cart and Checkout blocks - Extensibility
---

View File

@ -0,0 +1,725 @@
---
post_title: Cart and Checkout - Additional checkout fields
menu_title: Additional Checkout Fields
tags: reference
---
A common use-case for developers and merchants is to add a new field to the Checkout form to collect additional data about a customer or their order.
This document will outline the steps an extension should take to register some additional checkout fields.
## Available field locations
Additional checkout fields can be registered in three different places:
- Contact information
- Addresses (Shipping **and** Billing)
- Order information
A field can only be shown in one location, it is not possible to render the same field in multiple locations in the same registration.
### Contact information
The contact information section currently renders at the top of the form. It contains the `email` field and any other additional fields.
![Showing the contact information section with two fields rendered, email and an additional checkout field (optional)](https://github.com/woocommerce/woocommerce/assets/5656702/097c2596-c629-4eab-9604-577ee7a14cfe)
Fields rendered here will be saved to the shopper's account. They will be visible and editable render in the shopper's "Account details" section.
### Address
The "Address" section currently contains a form for the shipping address and the billing address. Additional checkout fields can be registered to appear within these forms.
![The shipping address form showing the additional checkout field at the bottom](https://github.com/woocommerce/woocommerce/assets/5656702/746d280f-3354-4d37-a78a-a2518eb0e5de)
Fields registered here will be saved to both the customer _and_ the order, so returning customers won't need to refill those values again.
If a field is registered in the `address` location it will appear in both the shipping **and** the billing address. It is not possible to have the field in only one of the addresses.
You will also end up collecting two values for this field, one for shipping and one for billing.
### Order information
As part of the additional checkout fields feature, the checkout block has a new inner block called the "Order information block".
This block is used to render fields that aren't part of the contact information or address information, for example it may be a "How did you hear about us" field or a "Gift message" field.
Fields rendered here will be saved to the order. They will not be part of the customer's saved address or account information. New orders will not have any previously used values pre-filled.
![The order information section containing an additional checkout field](https://github.com/woocommerce/woocommerce/assets/5656702/295b3048-a22a-4225-96b0-6b0371a7cd5f)
By default, this block will render as the last step in the Checkout form, however it can be moved using the Gutenberg block controls in the editor.
![The order information block in the post editor"](https://github.com/woocommerce/woocommerce/assets/5656702/05a3d7d9-b3af-4445-9318-443ae2c4d7d8)
## Accessing values
Additional fields are saved to individual meta keys in both the customer meta and order meta, you can access them using helper methods, or using the meta keys directly, we recommend using the helper methods, as they're less likely to change, can handle future migrations, and will support future enhancements (e.g. reading from different locations).
For address fields, two values are saved: one for shipping, and one for billing. If the customer has selected 'Use same address for billing` then the values will be the same, but still saved independently of each other.
For contact and order fields, only one value is saved per field.
### Helper methods
`CheckoutFields` provides a function to access values from both customers and orders, it's are `get_field_from_object`.
To access a customer billing and/or shipping value:
```php
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
$field_id = 'my-plugin-namespace/my-field';
$customer = wc()->customer; // Or new WC_Customer( $id )
$checkout_fields = Package::container()->get( CheckoutFields::class );
$my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' );
$my_customer_shipping_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'shipping' );
```
To access an order field:
```php
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
$field_id = 'my-plugin-namespace/my-field';
$order = wc_get_order( 1234 );
$checkout_fields = Package::container()->get( CheckoutFields::class );
$my_order_billing_field = $checkout_fields->get_field_from_object( $field_id, $order, 'billing' );
$my_order_shipping_field = $checkout_fields->get_field_from_object( $field_id, $order, 'shipping' );
```
After an order is placed, the data saved to the customer and the data saved to the order will be the same. Customers can change the values for _future_ orders, or from within their My Account page. If you're looking at a customer value at a specific point in time (i.e. when the order was placed), access it from the order object, if you're looking for the most up to date value regardless, access it from the customer object.
#### Guest customers
When a guest customer places an order with additional fields, those fields will be saved to its session, so as long as the customer still has a valid session going, the values will always be there.
#### Logged-in customers
For logged-in customers, the value is only persisted once they place an order. Accessing a logged-in customer object during the place order lifecycle will return null or stale data.
If you're at a place order hook, doing this will return previous data (not the currently inserted one):
```php
$customer = new WC_Customer( $order->customer_id ); // Or new WC_Customer( 1234 )
$my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' );
```
Instead, always access the latest data if you want to run some extra validation/data-moving:
```php
$customer = wc()->customer // This will return the current customer with its session.
$my_customer_billing_field = $checkout_fields->get_field_from_object( $field_id, $customer, 'billing' );
```
#### Accessing all fields
You can use `get_all_fields_from_object` to access all additional fields saved to an order or a customer.
```php
use Automattic\WooCommerce\Blocks\Package;
use Automattic\WooCommerce\Blocks\Domain\Services\CheckoutFields;
$order = wc_get_order( 1234 );
$checkout_fields = Package::container()->get( CheckoutFields::class );
$order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing' );
$order_additional_shipping_fields = $checkout_fields->get_all_fields_from_object( $order, 'shipping' );
$order_other_additional_fields = $checkout_fields->get_all_fields_from_object( $order, 'other' ); // Contact and Order are saved in the same place under the additional group.
```
This will return an array of all values, it will only include fields currently registered, if you want to include fields no longer registered, you can pass a third `true` parameter.
```php
$order = wc_get_order( 1234 );
$checkout_fields = Package::container()->get( CheckoutFields::class );
$order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing' ); // array( 'my-plugin-namespace/my-field' => 'my-value' );
$order_additional_billing_fields = $checkout_fields->get_all_fields_from_object( $order, 'billing', true ); // array( 'my-plugin-namespace/my-field' => 'my-value', 'old-namespace/old-key' => 'old-value' );
```
### Accessing values directly
While not recommended, you can use the direct meta key to access certain values, this is useful for external engines or page/email builders who only provide access to meta values.
Values are saved under a predefined prefix, this is needed to able to query fields without knowing which ID the field was registered under, for a field with key `'my-plugin-namespace/my-field'`, it's meta key will be the following if it's an address field:
- `_wc_billing/my-plugin-namespace/my-field`
- `_wc_shipping/my-plugin-namespace/my-field`
Or the following if it's a contact/order field:
- `_wc_other/my-plugin-namespace/my-field`.
Those prefixes are part of `CheckoutFields` class, and can be accessed using the following constants:
```php
echo ( CheckoutFields::BILLING_FIELDS_PREFIX ); // _wc_billing/
echo ( CheckoutFields::SHIPPING_FIELDS_PREFIX ); // _wc_shipping/
echo ( CheckoutFields::OTHER_FIELDS_PREFIX ); // _wc_other/
```
`CheckoutFields` provides a couple of helpers to get the group name or key based on one or the other:
```php
CheckoutFields::get_group_name( "_wc_billing" ); // "billing"
CheckoutFields::get_group_name( "_wc_billing/" ); // "billing"
CheckoutFields::get_group_key( "shipping" ); // "_wc_shipping/"
```
Use cases here would be to build the key name to access the meta directly:
```php
$key = CheckoutFields::get_group_key( "other" ) . 'my-plugin/is-opt-in';
$opted_in = get_user_meta( 123, $key, true ) === "1" ? true : false;
```
#### Checkboxes values
When accessing a checkbox values directly, it will either return `"1"` for true, `"0"` for false, or `""` if the value doesn't exist, only the provided functions will sanitize that to a boolean.
## Supported field types
The following field types are supported:
- `select`
- `text`
- `checkbox`
There are plans to expand this list, but for now these are the types available.
## Using the API
To register additional checkout fields you must use the `woocommerce_register_additional_checkout_field` function.
It is recommended to run this function after the `woocommerce_init` action.
The registration function takes an array of options describing your field. Some field types take additional options.
### Options
#### General options
These options apply to all field types (except in a few circumstances which are noted inline).
| Option name | Description | Required? | Example | Default value |
|---------------------|-------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------------------------------------------------------------------------------------------------|----------------------------------------------|------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `id` | The field's ID. This should be a unique identifier for your field. It is composed of a namespace and field name separated by a `/`. | Yes | `plugin-namespace/how-did-you-hear` | No default - this must be provided. |
| `label` | The label shown on your field. This will be the placeholder too. | Yes | `How did you hear about us?` | No default - this must be provided. |
| `optionalLabel` | The label shown on your field if it is optional. This will be the placeholder too. | No | `How did you hear about us? (Optional)` | The default value will be the value of `label` with `(optional)` appended. |
| `location` | The location to render your field. | Yes | `contact`, `address`, or `order` | No default - this must be provided. |
| `type` | The type of field you're rendering. It defaults to `text` and must match one of the supported field types. | No | `text`, `select`, or `checkbox` | `text` |
| `attributes` | An array of additional attributes to render on the field's input element. This is _not_ supported for `select` fields. | No | `[ 'data-custom-data' => 'my-custom-data' ]` | `[]` |
| `sanitize_callback` | A function called to sanitize the customer provided value when posted. | No | See example below | By default the field's value is returned unchanged. |
| `validate_callback` | A function called to validate the customer provided value when posted. This runs _after_ sanitization. | No | See example below | The default validation function will add an error to the response if the field is required and does not have a value. [See the default validation function.](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Blocks/Domain/Services/CheckoutFields.php#L270-L281) |
##### Example of `sanitize_callback`. This function will remove spaces from the value <!-- omit from toc -->
```php
'sanitize_callback' => function( $field_value ) {
return str_replace( ' ', '', $field_value );
},
```
##### Example of `validate_callback`. This function will check if the value is an email <!-- omit from toc -->
```php
'validate_callback' => function( $field_value ) {
if ( ! is_email( $field_value ) ) {
return new WP_Error( 'invalid_alt_email', 'Please ensure your alternative email matches the correct format.' );
}
},
```
#### Options for `text` fields
As well as the options above, text fields also support a `required` option. If this is `true` then the shopper _must_ provide a value for this field during the checkout process.
| Option name | Description | Required? | Example | Default value |
|-----------------|-------------------------------------------------------------------------------------------------------------------------------------|-----------|----------------------------------------------|---|
| `required` | If this is `true` then the shopper _must_ provide a value for this field during the checkout process. | No | `true` | `false` |
#### Options for `select` fields
As well as the options above, select fields must also be registered with an `options` option. This is used to specify what options the shopper can select.
Select fields will mount with no value selected by default, if the field is required, the user will be required to select a value.
You can set a placeholder to be shown on the select by passing a `placeholder` value when registering the field. This will be the first option in the select and will not be selectable if the field is required.
| Option name | Description | Required? | Example | Default value |
|-----|-----|-----|----------------|--------------|
| `options` | An array of options to show in the select input. Each options must be an array containing a `label` and `value` property. Each entry must have a unique `value`. Any duplicate options will be removed. The `value` is what gets submitted to the server during checkout and the `label` is simply a user-friendly representation of this value. It is not transmitted to the server in any way. | Yes | see below | No default - this must be provided. |
| `required` | If this is `true` then the shopper _must_ provide a value for this field during the checkout process. | No | `true` | `false` |
| `placeholder` | If this value is set, the shopper will see this option in the select. If the select is required, the shopper cannot select this option. | No | `Select a role | Select a $label |
##### Example of `options` value
```php
[
[
'value' => 'store_1',
'label' => 'Our London Store'
],
[
'value' => 'store_2',
'label' => 'Our Paris Store'
],
[
'value' => 'store_3',
'label' => 'Our New York Store'
]
]
```
#### Options for `checkbox` fields
The checkbox field type does not have any specific options, however `required` will always be `false` for a checkbox field. Making a checkbox field required is not supported.
### Attributes
Adding additional attributes to checkbox and text fields is supported. Adding them to select fields is **not possible for now**.
These attributes have a 1:1 mapping to the HTML attributes on `input` elements (except `pattern` on checkbox).
The supported attributes are:
- `data-*` attributes
- `aria-*` attributes
- `autocomplete`
- `autocapitalize`
- `pattern` (not supported on checkbox fields)
- `title`
- `maxLength` (equivalent to `maxlength` HTML attribute)
- `readOnly` (equivalent to `readonly` HTML attribute)
`maxLength` and `readOnly` are in camelCase because the attributes are rendered on a React element which must receive them in this format.
Certain attributes are not passed through to the field intentionally, these are `autofocus` and `disabled`. We are welcome to hear feedback and adjust this behaviour if valid use cases are provided.
## Usage examples
### Rendering a text field
This example demonstrates rendering a text field in the address section:
```php
add_action(
'woocommerce_init',
function() {
woocommerce_register_additional_checkout_field(
array(
'id' => 'namespace/gov-id',
'label' => 'Government ID',
'optionalLabel' => 'Government ID (optional)',
'location' => 'address',
'required' => true,
'attributes' => array(
'autocomplete' => 'government-id',
'aria-describedby' => 'some-element',
'aria-label' => 'custom aria label',
'pattern' => '[A-Z0-9]{5}', // A 5-character string of capital letters and numbers.
'title' => 'Title to show on hover',
'data-custom' => 'custom data',
),
),
);
}
);
```
This results in the following address form (the billing form will be the same):
![The shipping address form with the Government ID field rendered at the bottom](https://github.com/woocommerce/woocommerce/assets/5656702/f6eb3c6f-9178-4978-8e74-e6b2ea353192)
The rendered markup looks like this:
```html
&lt;input type="text" id="shipping-namespace-gov-id" autocapitalize="off"
autocomplete="government-id" aria-label="custom aria label"
aria-describedby="some-element" required="" aria-invalid="true"
title="Title to show on hover" pattern="[A-Z0-9]{5}"
data-custom="custom data" value="" &gt;
```
### Rendering a checkbox field
This example demonstrates rendering a checkbox field in the contact information section:
```php
add_action(
'woocommerce_init',
function() {
woocommerce_register_additional_checkout_field(
array(
'id' => 'namespace/marketing-opt-in',
'label' => 'Do you want to subscribe to our newsletter?',
'location' => 'contact',
'type' => 'checkbox',
)
);
}
);
```
This results in the following contact information section:
![The contact information section with a newsletter subscription checkbox rendered inside it](https://github.com/woocommerce/woocommerce/assets/5656702/7444e41a-97cc-451d-b2c9-4eedfbe05724)
Note that because an `optionalLabel` was not supplied, the string `(optional)` is appended to the label. To remove that an `optionalLabel` property should be supplied to override this.
### Rendering a select field
This example demonstrates rendering a select field in the order information section:
```php
add_action(
'woocommerce_init',
function() {
woocommerce_register_additional_checkout_field(
array(
'id' => 'namespace/how-did-you-hear-about-us',
'label' => 'How did you hear about us?',
'placeholder' => 'Select a source',
'location' => 'order',
'type' => 'select',
'options' => [
[
'value' => 'google',
'label' => 'Google'
],
[
'value' => 'facebook',
'label' => 'Facebook'
],
[
'value' => 'friend',
'label' => 'From a friend'
],
[
'value' => 'other',
'label' => 'Other'
],
]
)
);
}
);
```
This results in the order information section being rendered like so:
### The select input before being focused
![The select input before being focused](https://github.com/woocommerce/woocommerce/assets/5656702/bbe17ad0-7c7d-419a-951d-315f56f8898a)
### The select input when focused
![The select input when focused](https://github.com/woocommerce/woocommerce/assets/5656702/bd943906-621b-404f-aa84-b951323e25d3)
If it is undesirable to force the shopper to select a value, mark the select as optional by setting the `required` option to `false`.
## Validation and sanitization
It is possible to add custom validation and sanitization for additional checkout fields using WordPress action hooks.
These actions happen in two places:
1. Updating and submitting the form during the checkout process and,
2. Updating address/contact information in the "My account" area.
### Sanitization
Sanitization is used to ensure the value of a field is in a specific format. An example is when taking a government ID, you may want to format it so that all letters are capitalized and there are no spaces. At this point, the value should **not** be checked for _validity_. That will come later. This step is only intended to set the field up for validation.
#### Using the `woocommerce_sanitize_additional_field` filter
To run a custom sanitization function for a field you can use the `sanitize_callback` function on registration, or the `woocommerce_sanitize_additional_field` filter.
| Argument | Type | Description |
|--------------|-------------------|-------------------------------------------------------------------------|
| `$field_value` | `boolean\|string` | The value of the field. |
| `$field_key` | `string` | The ID of the field. This is the same ID the field was registered with. |
##### Example of sanitization
This example shows how to remove whitespace and capitalize all letters in the example Government ID field we added above.
```php
add_action(
'woocommerce_sanitize_additional_field',
function ( $field_value, $field_key ) {
if ( 'namespace/gov-id' === $field_key ) {
$field_value = str_replace( ' ', '', $field_key );
$field_value = strtoupper( $field_value );
}
return $field_value;
},
10,
2
);
```
### Validation
There are two phases of validation in the additional checkout fields system. The first is validating a single field based on its key and value.
#### Single field validation
##### Using the `woocommerce_validate_additional_field` action
When the `woocommerce_validate_additional_field` action is fired the callback receives the field's key, the field's value, and a `WP_Error` object.
To add validation errors to the response, use the [`WP_Error::add`](https://developer.wordpress.org/reference/classes/wp_error/add/) method.
| Argument | Type | Description |
|--------------|-------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `$errors` | `WP_Error` | An error object containing errors that were already encountered while processing the request. If no errors were added yet, it will still be a `WP_Error` object but it will be empty. |
| `$field_key` | `string` | The id of the field. This is the ID the field was registered with. |
| `$field_value` | `boolean\|string` | The value of the field |
###### The `WP_Error` object
When adding your error to the `WP_Error` object, it should have a unique error code. You may want to prefix the error code with the plugin namespace to reduce the chance of collision. Using codes that are already in use across other plugins may result in the error message being overwritten or showing in a different location.
###### Example of single-field validation
The below example shows how to apply custom validation to the `namespace/gov-id` text field from above. The code here ensures the field is made up of 5 characters, either upper-case letters or numbers. The sanitization function from the example above ensures that all whitespace is removed and all letters are capitalized, so this check is an extra safety net to ensure the input matches the pattern.
```php
add_action(
'woocommerce_validate_additional_field',
function ( WP_Error $errors, $field_key, $field_value ) {
if ( 'namespace/gov-id' === $field_key ) {
$match = preg_match( '/[A-Z0-9]{5}/', $field_value );
if ( 0 === $match || false === $match ) {
$errors->add( 'invalid_gov_id', 'Please ensure your government ID matches the correct format.' );
}
}
},
10,
3
);
```
It is important to note that this action must _add_ errors to the `WP_Error` object it receives. Returning a new `WP_Error` object or any other value will result in the errors not showing.
If no validation errors are encountered the function can just return void.
#### Multiple field validation
There are cases where the validity of a field depends on the value of another field, for example validating the format of a government ID based on what country the shopper is in. In this case, validating only single fields (as above) is not sufficient as the country may be unknown during the `woocommerce_validate_additional_field` action.
To solve this, it is possible to validate a field in the context of the location it renders in. The other fields in that location will be passed to this action.
##### Using the `woocommerce_blocks_validate_location_{location}_fields` action
This action will be fired for each location that additional fields can render in (`address`, `contact`, and `order`). For `address` it fires twice, once for the billing address and once for the shipping address.
The callback receives the keys and values of the other additional fields in the same location.
It is important to note that any fields rendered in other locations will not be passed to this action, however it might be possible to get those values by accessing the customer or order object, however this is not supported and there are no guarantees regarding backward compatibility in future versions.
| Argument | Type | Description |
|----------|-----------------------------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `$errors` | `WP_Error` | An error object containing errors that were already encountered while processing the request. If no errors were added yet, it will still be a `WP_Error` object but it will be empty. |
| `$fields` | `array` | The fields rendered in this locations. |
| `$group` | `'billing'\|'shipping'\|'other'` | If the action is for the address location, the type of address will be set here. If it is for contact or order, this will be 'other'. |
There are several places where these hooks are fired.
- When checking out using the Checkout block or Store API.
- `woocommerce_blocks_validate_location_address_fields` (x2)
- `woocommerce_blocks_validate_location_contact_fields`
- `woocommerce_blocks_validate_location_other_fields`
- When updating addresses in the "My account" area
- `woocommerce_blocks_validate_location_address_fields` (**x1** - only the address being edited)
- When updating the "Account details" section in the "My account" area
- `woocommerce_blocks_validate_location_contact_fields`
##### Example of location validation
In this example, assume there is another field registered alongside the `namespace/gov-id` called `namespace/confirm-gov-id`. This field will be a confirmation for the Government ID field.
The example below illustrates how to verify that the value of the confirmation field matches the value of the main field.
```php
add_action(
'woocommerce_blocks_validate_location_address_fields',
function ( \WP_Error $errors, $fields, $group ) {
if ( $fields['namespace/gov-id'] !== $fields['namespace/confirm-gov-id'] ) {
$errors->add( 'gov_id_mismatch', 'Please ensure your government ID matches the confirmation.' );
}
},
10,
3
);
```
If these fields were rendered in the "contact" location instead, the code would be the same except the hook used would be: `woocommerce_blocks_validate_location_contact_fields`.
## Backward compatibility
Due to technical reasons, it's not yet possible to specify the meta key for fields, as we want them to be prefixed and managed. Plugins with existing fields in shortcode Checkout can be compatible and react to reading and saving fields using hooks.
Assuming 2 fields, named `my-plugin-namespace/address-field` in the address step and `my-plugin-namespace/my-other-field` in the order step, you can:
### React to to saving fields
You can react to those fields being saved by hooking into `woocommerce_set_additional_field_value` action.
```php
add_action(
'woocommerce_set_additional_field_value',
function ( $key, $value, $group, $wc_object ) {
if ( 'my-plugin-namespace/address-field' !== $key ) {
return;
}
if ( 'billing' === $group ) {
$my_plugin_address_key = 'existing_billing_address_field_key';
} else {
$my_plugin_address_key = 'existing_shipping_address_field_key';
}
$wc_object->update_meta_data( $my_plugin_address_key, $value, true );
},
10,
4
);
add_action(
'woocommerce_set_additional_field_value',
function ( $key, $value, $group, $wc_object ) {
if ( 'my-plugin-namespace/my-other-field' !== $key ) {
return;
}
$my_plugin_key = 'existing_order_field_key';
$wc_object->update_meta_data( $my_plugin_key, $value, true );
},
10,
4
);
```
This way, you can ensure existing systems will continue working and your integration will continue to work. However, ideally, you should migrate your existing data and systems to use the new meta fields.
### React to reading fields
You can use the `woocommerce_get_default_value_for_{$key}` filters to provide a different default value (a value coming from another meta field for example):
```php
add_filter(
"woocommerce_get_default_value_for_my-plugin-namespace/address-field",
function ( $value, $group, $wc_object ) {
if ( 'billing' === $group ) {
$my_plugin_key = 'existing_billing_address_field_key';
} else {
$my_plugin_key = 'existing_shipping_address_field_key';
}
return $wc_object->get_meta( $my_plugin_key );
},
10,
3
);
add_filter(
"woocommerce_get_default_value_for_my-plugin-namespace/my-other-field",
function ( $value, $group, $wc_object ) {
$my_plugin_key = 'existing_order_field_key';
return $wc_object->get_meta( $my_plugin_key );
},
10,
3
);
```
## A full example
In this full example we will register the Government ID text field and verify that it conforms to a specific pattern.
This example is just a combined version of the examples shared above.
```php
add_action(
'woocommerce_init',
function() {
woocommerce_register_additional_checkout_field(
array(
'id' => 'namespace/gov-id',
'label' => 'Government ID',
'location' => 'address',
'required' => true,
'attributes' => array(
'autocomplete' => 'government-id',
'pattern' => '[A-Z0-9]{5}', // A 5-character string of capital letters and numbers.
'title' => 'Your 5-digit Government ID',
),
),
);
woocommerce_register_additional_checkout_field(
array(
'id' => 'namespace/confirm-gov-id',
'label' => 'Confirm government ID',
'location' => 'address',
'required' => true,
'attributes' => array(
'autocomplete' => 'government-id',
'pattern' => '[A-Z0-9]{5}', // A 5-character string of capital letters and numbers.
'title' => 'Confirm your 5-digit Government ID',
),
),
);
add_action(
'woocommerce_sanitize_additional_field',
function ( $field_value, $field_key ) {
if ( 'namespace/gov-id' === $field_key || 'namespace/confirm-gov-id' === $field_key ) {
$field_value = str_replace( ' ', '', $field_key );
$field_value = strtoupper( $field_value );
}
return $field_value;
},
10,
2
);
add_action(
'woocommerce_validate_additional_field',
function ( WP_Error $errors, $field_key, $field_value ) {
if ( 'namespace/gov-id' === $field_key ) {
$match = preg_match( '/[A-Z0-9]{5}/', $field_value );
if ( 0 === $match || false === $match ) {
$errors->add( 'invalid_gov_id', 'Please ensure your government ID matches the correct format.' );
}
}
return $error;
},
10,
3
);
}
);
add_action(
'woocommerce_blocks_validate_location_address_fields',
function ( \WP_Error $errors, $fields, $group ) {
if ( $fields['namespace/gov-id'] !== $fields['namespace/confirm-gov-id'] ) {
$errors->add( 'gov_id_mismatch', 'Please ensure your government ID matches the confirmation.' );
}
},
10,
3
);
```

View File

@ -0,0 +1,118 @@
---
category_title: Available Filters
category_slug: cart-and-checkout-available-filters
post_title: Cart and Checkout - Available Filters
---
This document lists the filters that are currently available to extensions and offers usage information for each one of them. Information on registering filters can be found on the [Checkout - Filter Registry](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/packages/checkout/filter-registry/README.md) page.
## Cart Line Items filters
The following [Cart Line Items filters](./cart-line-items.md) are available:
- `cartItemClass`
- `cartItemPrice`
- `itemName`
- `saleBadgePriceFormat`
- `showRemoveItemLink`
- `subtotalPriceFormat`
The following screenshot shows which parts the individual filters affect:
![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)
## Order Summary Items filters
The following [Order Summary Items filters](./order-summary-items.md) are available:
- `cartItemClass`
- `cartItemPrice`
- `itemName`
- `subtotalPriceFormat`
The following screenshot shows which parts the individual filters affect:
![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)
## Totals Footer Item filter
The following [Totals Footer Item filter](./totals-footer-item.md) is available:
- `totalLabel`
- `totalValue`
## Checkout and place order button filters
The following [Checkout and place order button filters](./checkout-and-place-order-button.md) are available:
- `proceedToCheckoutButtonLabel`
- `proceedToCheckoutButtonLink`
- `placeOrderButtonLabel`
## Coupon filters
The following [Coupon filters](./coupons.md) are available:
- `coupons`
- `showApplyCouponNotice`
- `showRemoveCouponNotice`
## Additional Cart and Checkout inner block types filter
The following [Additional Cart and Checkout inner block types filter](./additional-cart-checkout-inner-block-types.md) is available:
- `additionalCartCheckoutInnerBlockTypes`
## Combined filters
Filters can also be combined. The following example shows how to combine some of the available filters.
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const isOrderSummaryContext = ( args ) => args?.context === 'summary';
const modifyCartItemClass = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return 'my-custom-class';
}
return defaultValue;
};
const modifyCartItemPrice = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return '&lt;price/&gt; for all items';
}
return defaultValue;
};
const modifyItemName = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return `${ defaultValue }`;
}
return defaultValue;
};
const modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return '&lt;price/&gt; per item';
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
cartItemClass: modifyCartItemClass,
cartItemPrice: modifyCartItemPrice,
itemName: modifyItemName,
subtotalPriceFormat: modifySubtotalPriceFormat,
} );
```
## Troubleshooting
If you are logged in to the store as an administrator, you should be shown an error like this if your filter is not
working correctly. The error will also be shown in your console.
![Troubleshooting](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-30-at-10.52.53.png)

View File

@ -0,0 +1,75 @@
---
post_title: Cart and Checkout Filters - Inner block types
menu_title: Inner Block Types
tags: reference
---
The following Additional Cart and Checkout inner block types filter is available:
- `additionalCartCheckoutInnerBlockTypes`
## `additionalCartCheckoutInnerBlockTypes`
### Description <!-- omit in toc -->
The Cart and Checkout blocks are made up of inner blocks. These inner blocks areas allow certain block types to be added as children. By default, only `core/paragraph`, `core/image`, and `core/separator` are available to add.
By using the `additionalCartCheckoutInnerBlockTypes` filter it is possible to add items to this array to control what the editor can into an inner block.
This filter is called once for each inner block area, so it is possible to be very granular when determining what blocks can be added where.
### Parameters <!-- omit in toc -->
- _defaultValue_ `array` (default: `[]`) - The default value of the filter.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following key:
- _block_ `string` - The block name of the inner block area, e.g. `woocommerce/checkout-shipping-address-block`.
- _validation_ `boolean` or `Error` - Checks if the returned value is an array of strings. If an error occurs, it will be thrown.
### Returns <!-- omit in toc -->
- `array` - The modified array with allowed block types for the corresponding inner block area.
### Code example <!-- omit in toc -->
Let's suppose we want to allow the editor to add some blocks in specific places in the Cart and Checkout blocks.
1. Allow `core/quote` to be inserted in every block area in the Cart and Checkout blocks.
2. Allow `core/table` to be inserted in the Shipping Address block in the Checkout.
In our extension we could register a filter satisfy both of these conditions like so:
```tsx
document.addEventListener( 'DOMContentLoaded', function () {
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyAdditionalInnerBlockTypes = (
defaultValue,
extensions,
args,
validation
) => {
defaultValue.push( 'core/quote' );
if ( args?.block === 'woocommerce/checkout-shipping-address-block' ) {
defaultValue.push( 'core/table' );
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
additionalCartCheckoutInnerBlockTypes: modifyAdditionalInnerBlockTypes,
} );
} );
```
To call this filter within the editor, wrap the filter registration in a `DOMContentLoaded` event listener and ensure the code runs in the admin panel.
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Additional Cart and Checkout inner block types filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/0d4560c8-c2b1-4ed8-8aee-469b248ccb08) |![After applying the Additional Cart and Checkout inner block types filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/d38cd568-6c8c-4158-9269-d8dffdf66988) |

View File

@ -0,0 +1,626 @@
---
post_title: Cart and Checkout Filters - Cart line items
menu_title: Cart Line Items
tags: reference
---
<!-- markdownlint-disable MD024 -->
The following Cart Line Items filters are available:
- `cartItemClass`
- `cartItemPrice`
- `itemName`
- `saleBadgePriceFormat`
- `showRemoveItemLink`
- `subtotalPriceFormat`
The following objects are shared between the filters:
- Cart object
- Cart Item object
The following screenshot shows which parts the individual filters affect:
![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)
## `cartItemClass`
### Description <!-- omit in toc -->
The `cartItemClass` filter allows to change the cart item class.
### Parameters <!-- omit in toc -->
- _defaultValue_ `object` (default: `''`) - The default cart item class.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `string` - The modified cart item class, or an empty string.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return 'my-custom-class';
};
registerCheckoutFilters( 'example-extension', {
cartItemClass: modifyCartItemClass,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return 'cool-class';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return 'hot-class';
}
return 'my-custom-class';
};
registerCheckoutFilters( 'example-extension', {
cartItemClass: modifyCartItemClass,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Cart Item Class filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/a587a6ce-d051-4ed0-bba5-815b5d72179d) |![After applying the Cart Item Class filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/9b25eeae-6d81-4e28-b177-32f942e1d0c2) |
## `cartItemPrice`
### Description <!-- omit in toc -->
The `cartItemPrice` filter allows to format the cart item price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `&lt;price/&gt;`) - The default cart item price.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the cart item price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
cartItemPrice: modifyCartItemPrice,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '&lt;price/&gt; to keep you warm';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '&lt;price/&gt; to keep you cool';
}
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
cartItemPrice: modifyCartItemPrice,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Cart Item Price filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/bbaeb68a-492e-41e7-87b7-4b8b05ca3709) |![After applying the Cart Item Price filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/bbaeb68a-492e-41e7-87b7-4b8b05ca3709) |
## `itemName`
### Description <!-- omit in toc -->
The `itemName` filter allows to change the cart item name.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` - The default cart item name.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `string` - The original or modified cart item name.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyItemName = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return `🪴 ${ defaultValue } 🪴`;
};
registerCheckoutFilters( 'example-extension', {
itemName: modifyItemName,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyItemName = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return `⛷️ ${ defaultValue } ⛷️`;
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return `🏄‍♂️ ${ defaultValue } 🏄‍♂️`;
}
return `🪴 ${ defaultValue } 🪴`;
};
registerCheckoutFilters( 'example-extension', {
itemName: modifyItemName,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Item Name filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/97d0f501-138e-4448-93df-a4d865b524e6) |![After applying the Item Name filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/69381932-d064-4e8f-b378-c2477fef56ae) |
## `saleBadgePriceFormat`
### Description <!-- omit in toc -->
The `saleBadgePriceFormat` filter allows to format the cart item sale badge price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `&lt;price/&gt;`) - The default cart item sale badge price.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the cart item sale badge price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code examples <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySaleBadgePriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
saleBadgePriceFormat: modifySaleBadgePriceFormat,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySaleBadgePriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '&lt;price/&gt; per item while keeping warm';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '&lt;price/&gt; per item while looking cool';
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
saleBadgePriceFormat: modifySaleBadgePriceFormat,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Sale Badge Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/d2aeb206-e620-44e0-93c1-31484cfcdca6) |![After applying the Sale Badge Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/6b929695-5d89-433b-8694-b9201a7c0519) |
## `showRemoveItemLink`
### Description <!-- omit in toc -->
The `showRemoveItemLink` is used to show or hide the cart item remove link.
### Parameters <!-- omit in toc -->
- _defaultValue_ (type: `boolean`, default: `true`) - The default value of the remove link.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `boolean` - `true` if the cart item remove link should be shown, `false` otherwise.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowRemoveItemLink = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return false;
};
registerCheckoutFilters( 'example-extension', {
showRemoveItemLink: modifyShowRemoveItemLink,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowRemoveItemLink = ( defaultValue, extensions, args ) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return false;
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return false;
}
return true;
};
registerCheckoutFilters( 'example-extension', {
showRemoveItemLink: modifyShowRemoveItemLink,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Show Remove Item Link filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/a4254f3b-f056-47ad-b34a-d5f6d5500e56) |![After applying the Show Remove Item Link filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/32c55dc7-ef65-4f35-ab90-9533bc79d362) |
## `subtotalPriceFormat`
### Description <!-- omit in toc -->
The `subtotalPriceFormat` filter allows to format the cart item subtotal price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `&lt;price/&gt;`) - The default cart item subtotal price.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see Cart object.
- _cartItem_ `object` - The cart item object from `wc/store/cart`, see Cart Item object.
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the cart item subtotal price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySubtotalPriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
subtotalPriceFormat: modifySubtotalPriceFormat,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySubtotalPriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isCartContext = args?.context === 'cart';
if ( ! isCartContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '&lt;price/&gt; per warm beanie';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '&lt;price/&gt; per cool sunglasses';
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
subtotalPriceFormat: modifySubtotalPriceFormat,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Subtotal Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/a392cb24-4c40-4e25-8396-bf4971830e22) |![After applying the Subtotal Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/af69b26f-662a-4ef9-a288-3713b6e46373) |
## Cart object
The Cart object of the filters above has the following keys:
- _billingAddress_ `object` - The billing address object with the following keys:
- _address_1_ `string` - The first line of the address.
- _address_2_ `string` - The second line of the address.
- _city_ `string` - The city of the address.
- _company_ `string` - The company of the address.
- _country_ `string` - The country of the address.
- _email_ `string` - The email of the address.
- _first_name_ `string` - The first name of the address.
- _last_name_ `string` - The last name of the address.
- _phone_ `string` - The phone of the address.
- _postcode_ `string` - The postcode of the address.
- _state_ `string` - The state of the address.
- ~~_billingData_~~ `object` - The billing data object with the same keys as the `billingAddress` object.
- _cartCoupons_ `array` - The cart coupons array.
- _cartErrors_ `array` - The cart errors array.
- _cartFees_ `array` - The cart fees array.
- _cartHasCalculatedShipping_ `boolean` - Whether the cart has calculated shipping.
- _cartIsLoading_ `boolean` - Whether the cart is loading.
- _cartItemErrors_ `array` - The cart item errors array.
- _cartItems_ `array` - The cart items array with cart item objects, see Cart Item object.
- _cartItemsCount_ `number` - The cart items count.
- _cartItemsWeight_ `number` - The cart items weight.
- _cartNeedsPayment_ `boolean` - Whether the cart needs payment.
- _cartNeedsShipping_ `boolean` - Whether the cart needs shipping.
- _cartTotals_ `object` - The cart totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _tax_lines_ `array` - The tax lines array with tax line objects with the following keys:
- _name_ `string` - The name of the tax line.
- _price_ `number` - The price of the tax line.
- _rate_ `string` - The rate ID of the tax line.
- _total_discount_ `string` - The total discount.
- _total_discount_tax_ `string` - The total discount tax.
- _total_fees_ `string` - The total fees.
- _total_fees_tax_ `string` - The total fees tax.
- _total_items_ `string` - The total items.
- _total_items_tax_ `string` - The total items tax.
- _total_price_ `string` - The total price.
- _total_shipping_ `string` - The total shipping.
- _total_shipping_tax_ `string` - The total shipping tax.
- _total_tax_ `string` - The total tax.
- _crossSellsProducts_ `array` - The cross sells products array with cross sells product objects.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _isLoadingRates_ `boolean` - Whether the cart is loading rates.
- _paymentRequirements_ `array` - The payment requirements array.
- _shippingAddress_ `object` - The shipping address object with the same keys as the `billingAddress` object.
- _shippingRates_ `array` - The shipping rates array.
## Cart Item object
The Cart Item object of the filters above has the following keys:
- _backorders_allowed_ `boolean` - Whether backorders are allowed.
- _catalog_visibility_ `string` - The catalog visibility.
- _decsription_ `string` - The cart item description.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _id_ `number` - The item ID.
- _images_ `array` - The item images array.
- _item_data_ `array` - The item data array.
- _key_ `string` - The item key.
- _low_stock_remaining_ `number` - The low stock remaining.
- _name_ `string` - The item name.
- _permalink_ `string` - The item permalink.
- _prices_ `object` - The item prices object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _price_ `string` - The price.
- _price_range_ `string` - The price range.
- _raw_prices_ `object` - The raw prices object with the following keys:
- _precision_ `number` - The precision.
- _price_ `number` - The price.
- _regular_price_ `number` - The regular price.
- _sale_price_ `number` - The sale price.
- _regular_price_ `string` - The regular price.
- _sale_price_ `string` - The sale price.
- _quantity_ `number` - The item quantity.
- _quantity_limits_ `object` - The item quantity limits object with the following keys:
- _editable_ `boolean` - Whether the quantity is editable.
- _maximum_ `number` - The maximum quantity.
- _minimum_ `number` - The minimum quantity.
- _multiple_of_ `number` - The multiple of quantity.
- _short_description_ `string` - The item short description.
- _show_backorder_badge_ `boolean` - Whether to show the backorder badge.
- _sku_ `string` - The item SKU.
- _sold_individually_ `boolean` - Whether the item is sold individually.
- _totals_ `object` - The item totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _line_subtotal_ `string` - The line subtotal.
- _line_subtotal_tax_ `string` - The line subtotal tax.
- _line_total_ `string` - The line total.
- _line_total_tax_ `string` - The line total tax.
- _type_ `string` - The item type.
- _variation_ `array` - The item variation array.

View File

@ -0,0 +1,325 @@
---
post_title: Cart and Checkout Filters - Checkout and place order button
menu_title: Checkout and Place Order Button
tags: reference
---
<!-- markdownlint-disable MD024 -->
The following Checkout and place order button filters are available:
- `proceedToCheckoutButtonLabel`
- `proceedToCheckoutButtonLink`
- `placeOrderButtonLabel`
The following objects are shared between the filters:
- Cart object
- Cart Item object
## `proceedToCheckoutButtonLabel`
### Description <!-- omit in toc -->
The `proceedToCheckoutButtonLabel` filter allows change the label of the "Proceed to checkout" button.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `Proceed to Checkout`) - The label of the "Proceed to checkout" button.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
### Returns <!-- omit in toc -->
- `string` - The label of the "Proceed to checkout" button.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyProceedToCheckoutButtonLabel = (
defaultValue,
extensions,
args
) => {
if ( ! args?.cart.items ) {
return defaultValue;
}
return 'Go to checkout';
};
registerCheckoutFilters( 'example-extension', {
proceedToCheckoutButtonLabel: modifyProceedToCheckoutButtonLabel,
} );
```
#### Advanced example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyProceedToCheckoutButtonLabel = (
defaultValue,
extensions,
args
) => {
if ( ! args?.cart.items ) {
return defaultValue;
}
const isSunglassesInCart = args?.cart.items.some(
( item ) => item.name === 'Sunglasses'
);
if ( isSunglassesInCart ) {
return '😎 Proceed to checkout 😎';
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
proceedToCheckoutButtonLabel: modifyProceedToCheckoutButtonLabel,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Proceed To Checkout Button Label filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/fb0216c1-a091-4d58-b443-f49ccff98ed8) |![After applying the Item Name filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/ef15b6df-fbd7-43e7-a359-b4adfbba961a) |
## `proceedToCheckoutButtonLink`
### Description <!-- omit in toc -->
The `proceedToCheckoutButtonLink` filter allows change the link of the "Proceed to checkout" button.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `/checkout`) - The link of the "Proceed to checkout" button.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](./category/cart-and-checkout-blocks/available-filters/).
### Returns <!-- omit in toc -->
- `string` - The link of the "Proceed to checkout" button.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyProceedToCheckoutButtonLink = (
defaultValue,
extensions,
args
) => {
if ( ! args?.cart.items ) {
return defaultValue;
}
return '/custom-checkout';
};
registerCheckoutFilters( 'example-extension', {
proceedToCheckoutButtonLink: modifyProceedToCheckoutButtonLink,
} );
```
#### Advanced example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyProceedToCheckoutButtonLink = (
defaultValue,
extensions,
args
) => {
if ( ! args?.cart.items ) {
return defaultValue;
}
const isSunglassesInCart = args?.cart.items.some(
( item ) => item.name === 'Sunglasses'
);
if ( isSunglassesInCart ) {
return '/custom-checkout';
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
proceedToCheckoutButtonLink: modifyProceedToCheckoutButtonLink,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Proceed To Checkout Button Link filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/3f657e0f-4fcc-4746-a554-64221e071b2e) |![After applying the Proceed To Checkout Button Link filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/064df213-439e-4d8f-b29c-55962604cb97) |
## `placeOrderButtonLabel`
### Description <!-- omit in toc -->
The `placeOrderButtonLabel` filter allows change the label of the "Place order" button.
### Parameters <!-- omit in toc -->
- _defaultValue_ (type: `string`, default: `Place order`) - The label of the "Place order" button.
- _extensions_ `object` (default: `{}`) - The extensions object.
### Returns <!-- omit in toc -->
- `string` - The label of the "Place order" button.
### Code example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyPlaceOrderButtonLabel = ( defaultValue, extensions ) => {
return '😎 Pay now 😎';
};
registerCheckoutFilters( 'example-extension', {
placeOrderButtonLabel: modifyPlaceOrderButtonLabel,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Place Order Button Label filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/aa6d9b65-4d56-45f7-8162-a6bbfe171250) |![After applying the Place Order Button Label filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/a5cc2572-16e7-4781-a5ab-5d6cdced2ff6) |
<!-- FEEDBACK -->
## Cart object
The Cart object of the filters above has the following keys:
- _billingAddress_ `object` - The billing address object with the following keys:
- _address_1_ `string` - The first line of the address.
- _address_2_ `string` - The second line of the address.
- _city_ `string` - The city of the address.
- _company_ `string` - The company of the address.
- _country_ `string` - The country of the address.
- _email_ `string` - The email of the address.
- _first_name_ `string` - The first name of the address.
- _last_name_ `string` - The last name of the address.
- _phone_ `string` - The phone of the address.
- _postcode_ `string` - The postcode of the address.
- _state_ `string` - The state of the address.
- _coupons_ `array` - The coupons array.
- _crossSells_ `array` - The cross sell items array.
- _errors_ `array` - The errors array.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _fees_ `array` - The fees array.
- _hasCalculatedShipping_ `boolean` - Whether the cart has calculated shipping.
- _items_ `array` - The cart items array with cart item objects, see [Cart Item object](#cart-item-object).
- _itemsCount_ `number` - The number of items in the cart.
- _itemsWeight_ `number` - The total weight of the cart items.
- _needsPayment_ `boolean` - Whether the cart needs payment.
- _needsShipping_ `boolean` - Whether the cart needs shipping.
- _paymentMethods_ `array` - The payment methods array.
- _paymentRequirements_ `array` - The payment requirements array.
- _shippingAddress_ `object` - The shipping address object with the same keys as the billing address object.
- _shippingRates_ `array` - The shipping rates array.
- _totals_ `object` - The totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _tax_lines_ `array` - The tax lines array of objects with the following keys:
- _name_ `string` - The tax name.
- _price_ `string` - The tax price.
- _rate_ `string` - The tax rate.
- _total_discount_ `string` - The total discount.
- _total_discount_tax_ `string` - The total discount tax.
- _total_fee_ `string` - The total fee.
- _total_fee_tax_ `string` - The total fee tax.
- _total_items_ `string` - The total items.
- _total_items_tax_ `string` - The total items tax.
- _total_price_ `string` - The total price.
- _total_shipping_ `string` - The total shipping.
- _total_shipping_tax_ `string` - The total shipping tax.
- _total_tax_ `string` - The total tax.
## Cart Item object
The Cart Item object of the filters above has the following keys:
- _backorders_allowed_ `boolean` - Whether backorders are allowed.
- _catalog_visibility_ `string` - The catalog visibility.
- _decsription_ `string` - The cart item description.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _id_ `number` - The item ID.
- _images_ `array` - The item images array.
- _item_data_ `array` - The item data array.
- _key_ `string` - The item key.
- _low_stock_remaining_ `number` - The low stock remaining.
- _name_ `string` - The item name.
- _permalink_ `string` - The item permalink.
- _prices_ `object` - The item prices object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _price_ `string` - The price.
- _price_range_ `string` - The price range.
- _raw_prices_ `object` - The raw prices object with the following keys:
- _precision_ `number` - The precision.
- _price_ `number` - The price.
- _regular_price_ `number` - The regular price.
- _sale_price_ `number` - The sale price.
- _regular_price_ `string` - The regular price.
- _sale_price_ `string` - The sale price.
- _quantity_ `number` - The item quantity.
- _quantity_limits_ `object` - The item quantity limits object with the following keys:
- _editable_ `boolean` - Whether the quantity is editable.
- _maximum_ `number` - The maximum quantity.
- _minimum_ `number` - The minimum quantity.
- _multiple_of_ `number` - The multiple of quantity.
- _short_description_ `string` - The item short description.
- _show_backorder_badge_ `boolean` - Whether to show the backorder badge.
- _sku_ `string` - The item SKU.
- _sold_individually_ `boolean` - Whether the item is sold individually.
- _totals_ `object` - The item totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _line_subtotal_ `string` - The line subtotal.
- _line_subtotal_tax_ `string` - The line subtotal tax.
- _line_total_ `string` - The line total.
- _line_total_tax_ `string` - The line total tax.
- _type_ `string` - The item type.
- _variation_ `array` - The item variation array.

View File

@ -0,0 +1,189 @@
---
post_title: Cart and Checkout Filters - Coupons
menu_title: Coupons
tags: reference
---
<!-- markdownlint-disable MD024 -->
The following Coupon filters are available:
- `coupons`
- `showApplyCouponNotice`
- `showRemoveCouponNotice`
## `coupons`
### Description <!-- omit in toc -->
The current functionality is to display the coupon codes in the Cart and Checkout sidebars. This could be undesirable if you dynamically generate a coupon code that is not user-friendly. It may, therefore, be desirable to change the way this code is displayed. To achieve this, the filter `coupons` exists. This filter could also be used to show or hide coupons. This filter must _not_ be used to alter the value/totals of a coupon. This will not carry through to the Cart totals.
### Parameters <!-- omit in toc -->
- _coupons_ `object` - The coupons object with the following keys:
- _code_ `string` - The coupon code.
- _discount_type_ `string` - The type of discount. Can be `percent` or `fixed_cart`.
- _totals_ `object` - The totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _total_discount_ `string` - The total discount.
- _total_discount_tax_ `string` - The total discount tax.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following key:
- _context_ `string` (default: `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `array` - The coupons array of objects with the same keys as above.
### Code example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCoupons = ( coupons, extensions, args ) => {
return coupons.map( ( coupon ) => {
if ( ! coupon.label.match( /autocoupon(?:_\d+)+/ ) ) {
return coupon;
}
return {
...coupon,
label: 'Automatic coupon',
};
} );
};
registerCheckoutFilters( 'example-extension', {
coupons: modifyCoupons,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Coupons filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/6cab1aff-e4b9-4909-b81c-5726c6a20c40) |![After applying the Coupons filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/a5cc2572-16e7-4781-a5ab-5d6cdced2ff6) |
## `showApplyCouponNotice`
### Description <!-- omit in toc -->
### Parameters <!-- omit in toc -->
- _value_ `boolean` (default: `true`) - Weather to show the apply coupon notice.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _context_ `string` (allowed values: `wc/cart` and `wc/checkout`) - The context of the coupon notice.
- _code_ `string` - The coupon code.
### Returns <!-- omit in toc -->
- `boolean` - Weather to show the apply coupon notice.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowApplyCouponNotice = ( defaultValue, extensions, args ) => {
return false;
};
registerCheckoutFilters( 'example-extension', {
showApplyCouponNotice: modifyShowApplyCouponNotice,
} );
```
#### Advanced example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowApplyCouponNotice = ( defaultValue, extensions, args ) => {
if ( args?.couponCode === '10off' ) {
return false;
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
showApplyCouponNotice: modifyShowApplyCouponNotice,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Show Apply Coupon Notice filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/374d4899-61f3-49b2-ae04-5541d4c130c2) |![After applying the Show Apply Coupon Notice filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/c35dbd9b-eee4-4afe-9a29-9c554d467729) |
## `showRemoveCouponNotice`
### Description <!-- omit in toc -->
### Parameters <!-- omit in toc -->
- _value_ `boolean` (default: `true`) - Weather to show the remove coupon notice.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _context_ `string` (allowed values: `wc/cart` and `wc/checkout`) - The context of the coupon notice.
- _code_ `string` - The coupon code.
### Returns <!-- omit in toc -->
- `boolean` - Weather to show the apply coupon notice.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowRemoveCouponNotice = ( defaultValue, extensions, args ) => {
return false;
};
registerCheckoutFilters( 'example-extension', {
showRemoveCouponNotice: modifyShowRemoveCouponNotice,
} );
```
#### Advanced example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyShowRemoveCouponNotice = ( defaultValue, extensions, args ) => {
if ( args?.couponCode === '10off' ) {
return false;
}
return defaultValue;
};
registerCheckoutFilters( 'example-extension', {
showRemoveCouponNotice: modifyShowRemoveCouponNotice,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Show Remove Coupon Notice filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/9d8607fa-ab20-4181-b70b-7954e7aa49cb) |![After applying the Show Remove Coupon Notice filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/83d5f65f-c4f3-4707-a250-077952514931) |

View File

@ -0,0 +1,456 @@
---
post_title: Cart and Checkout Filters - Order summary items
menu_title: Order Summary Items
tags: reference
---
<!-- markdownlint-disable MD024 -->
The following Order Summary Items filters are available:
- `cartItemClass`
- `cartItemPrice`
- `itemName`
- `subtotalPriceFormat`
The following objects are shared between the filters:
- Cart object
- Cart Item object
The following screenshot shows which parts the individual filters affect:
![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)
## `cartItemClass`
### Description <!-- omit in toc -->
The `cartItemClass` filter allows to change the order summary item class.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `''`) - The default order summary item class.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `string` - The modified order summary item class, or an empty string.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
return 'my-custom-class';
};
registerCheckoutFilters( 'example-extension', {
cartItemClass: modifyCartItemClass,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return 'cool-class';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return 'hot-class';
}
return 'my-custom-class';
};
registerCheckoutFilters( 'example-extension', {
cartItemClass: modifyCartItemClass,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Cart Item Class filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/ff555a84-8d07-4889-97e1-8f7d50d47350) |![After applying the Cart Item Class filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/183809d8-03dc-466d-a415-d8d2062d880f) |
## `cartItemPrice`
### Description <!-- omit in toc -->
The `cartItemPrice` filter allows to format the order summary item price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `&lt;price/&gt;`) - The default order summary item price.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the order summary item price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
cartItemPrice: modifyCartItemPrice,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '&lt;price/&gt; to keep you ☀️';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '&lt;price/&gt; to keep you ❄️';
}
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
cartItemPrice: modifyCartItemPrice,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Cart Item Price filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/58137fc4-884d-4783-9275-5f78abec1473) |![After applying the Cart Item Price filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/fb502b74-6447-49a8-8d35-241e738f089d) |
## `itemName`
### Description <!-- omit in toc -->
The `itemName` filter allows to change the order summary item name.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` - The default order summary item name.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
### Returns <!-- omit in toc -->
- `string` - The original or modified order summary item name.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyItemName = ( defaultValue, extensions, args ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
return `🪴 ${ defaultValue } 🪴`;
};
registerCheckoutFilters( 'example-extension', {
itemName: modifyItemName,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyItemName = ( defaultValue, extensions, args ) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return `⛷️ ${ defaultValue } ⛷️`;
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return `🏄‍♂️ ${ defaultValue } 🏄‍♂️`;
}
return `🪴 ${ defaultValue } 🪴`;
};
registerCheckoutFilters( 'example-extension', {
itemName: modifyItemName,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Item Name filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/3dc0bda7-fccf-4f35-a2e2-aa04e616563a) |![After applying the Item Name filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/c96b8394-03a7-45f6-813b-5335f4bf83b5) |
## `subtotalPriceFormat`
### Description <!-- omit in toc -->
The `subtotalPriceFormat` filter allows to format the order summary item subtotal price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `&lt;price/&gt;`) - The default order summary item subtotal price.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
- _cartItem_ `object` - The order summary item object from `wc/store/cart`, see [order summary item object](#cart-item-object).
- _context_ `string` (allowed values: `cart` or `summary`) - The context of the item.
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the order summary item subtotal price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code examples <!-- omit in toc -->
#### Basic example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySubtotalPriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
subtotalPriceFormat: modifySubtotalPriceFormat,
} );
```
#### Advanced example <!-- omit in toc -->
```tsx
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifySubtotalPriceFormat = (
defaultValue,
extensions,
args,
validation
) => {
const isOrderSummaryContext = args?.context === 'summary';
if ( ! isOrderSummaryContext ) {
return defaultValue;
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '&lt;price/&gt; per warm beanie';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '&lt;price/&gt; per cool sunglasses';
}
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
subtotalPriceFormat: modifySubtotalPriceFormat,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Subtotal Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/3574e7ae-9857-4651-ac9e-e6b597e3a589) |![After applying the Subtotal Price Format filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/94e18439-6d6b-44a4-ade1-8302c5984641) |
## Cart object
The Cart object of the filters above has the following keys:
- _billingAddress_ `object` - The billing address object with the following keys:
- _address_1_ `string` - The first line of the address.
- _address_2_ `string` - The second line of the address.
- _city_ `string` - The city of the address.
- _company_ `string` - The company of the address.
- _country_ `string` - The country of the address.
- _email_ `string` - The email of the address.
- _first_name_ `string` - The first name of the address.
- _last_name_ `string` - The last name of the address.
- _phone_ `string` - The phone of the address.
- _postcode_ `string` - The postcode of the address.
- _state_ `string` - The state of the address.
- ~~_billingData_~~ `object` - The billing data object with the same keys as the `billingAddress` object.
- _cartCoupons_ `array` - The cart coupons array.
- _cartErrors_ `array` - The cart errors array.
- _cartFees_ `array` - The cart fees array.
- _cartHasCalculatedShipping_ `boolean` - Whether the cart has calculated shipping.
- _cartIsLoading_ `boolean` - Whether the cart is loading.
- _cartItemErrors_ `array` - The cart item errors array.
- _cartItems_ `array` - The cart items array with cart item objects, see [Cart Item object](#cart-item-object).
- _cartItemsCount_ `number` - The cart items count.
- _cartItemsWeight_ `number` - The cart items weight.
- _cartNeedsPayment_ `boolean` - Whether the cart needs payment.
- _cartNeedsShipping_ `boolean` - Whether the cart needs shipping.
- _cartTotals_ `object` - The cart totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _tax_lines_ `array` - The tax lines array with tax line objects with the following keys:
- _name_ `string` - The name of the tax line.
- _price_ `number` - The price of the tax line.
- _rate_ `string` - The rate ID of the tax line.
- _total_discount_ `string` - The total discount.
- _total_discount_tax_ `string` - The total discount tax.
- _total_fees_ `string` - The total fees.
- _total_fees_tax_ `string` - The total fees tax.
- _total_items_ `string` - The total items.
- _total_items_tax_ `string` - The total items tax.
- _total_price_ `string` - The total price.
- _total_shipping_ `string` - The total shipping.
- _total_shipping_tax_ `string` - The total shipping tax.
- _total_tax_ `string` - The total tax.
- _crossSellsProducts_ `array` - The cross sells products array with cross sells product objects.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _isLoadingRates_ `boolean` - Whether the cart is loading rates.
- _paymentRequirements_ `array` - The payment requirements array.
- _shippingAddress_ `object` - The shipping address object with the same keys as the `billingAddress` object.
- _shippingRates_ `array` - The shipping rates array.
## Cart Item object
The Cart Item object of the filters above has the following keys:
- _backorders_allowed_ `boolean` - Whether backorders are allowed.
- _catalog_visibility_ `string` - The catalog visibility.
- _decsription_ `string` - The cart item description.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _id_ `number` - The item ID.
- _images_ `array` - The item images array.
- _item_data_ `array` - The item data array.
- _key_ `string` - The item key.
- _low_stock_remaining_ `number` - The low stock remaining.
- _name_ `string` - The item name.
- _permalink_ `string` - The item permalink.
- _prices_ `object` - The item prices object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _price_ `string` - The price.
- _price_range_ `string` - The price range.
- _raw_prices_ `object` - The raw prices object with the following keys:
- _precision_ `number` - The precision.
- _price_ `number` - The price.
- _regular_price_ `number` - The regular price.
- _sale_price_ `number` - The sale price.
- _regular_price_ `string` - The regular price.
- _sale_price_ `string` - The sale price.
- _quantity_ `number` - The item quantity.
- _quantity_limits_ `object` - The item quantity limits object with the following keys:
- _editable_ `boolean` - Whether the quantity is editable.
- _maximum_ `number` - The maximum quantity.
- _minimum_ `number` - The minimum quantity.
- _multiple_of_ `number` - The multiple of quantity.
- _short_description_ `string` - The item short description.
- _show_backorder_badge_ `boolean` - Whether to show the backorder badge.
- _sku_ `string` - The item SKU.
- _sold_individually_ `boolean` - Whether the item is sold individually.
- _totals_ `object` - The item totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _line_subtotal_ `string` - The line subtotal.
- _line_subtotal_tax_ `string` - The line subtotal tax.
- _line_total_ `string` - The line total.
- _line_total_tax_ `string` - The line total tax.
- _type_ `string` - The item type.
- _variation_ `array` - The item variation array.

View File

@ -0,0 +1,215 @@
---
post_title: Cart and Checkout Filters - Totals footer item
menu_title: Totals Footer Item
tags: reference
---
<!-- markdownlint-disable MD024 -->
The following Totals Footer Item filter are available:
- `totalLabel`
- `totalValue`
## `totalLabel`
The following object is used in the filter:
- [Cart object](#cart-object)
### Description <!-- omit in toc -->
The `totalLabel` filter allows to change the label of the total item in the footer of the Cart and Checkout blocks.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `Total`) - The total label.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
### Returns <!-- omit in toc -->
- `string` - The updated total label.
### Code example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyTotalLabel = ( defaultValue, extensions, args ) => {
return 'Deposit due today';
};
registerCheckoutFilters( 'example-extension', {
totalLabel: modifyTotalLabel,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Total Label filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/5b2fb8ab-db84-4ed0-a676-d5203edc84d2) |![After applying the Total Label filter](https://github.com/woocommerce/woocommerce-blocks/assets/3323310/07955eea-cb17-48e9-9cb5-6548dd6a3b24) |
## `totalValue`
The following object is used in the filter:
- [Cart object](#cart-object)
### Description <!-- omit in toc -->
The `totalValue` filter allows to format the total price in the footer of the Cart and Checkout blocks.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `Total`) - The total label.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _args_ `object` - The arguments object with the following keys:
- _cart_ `object` - The cart object from `wc/store/cart`, see [Cart object](#cart-object).
- _validation_ `boolean` - Checks if the return value contains the substring `&lt;price/&gt;`.
### Returns <!-- omit in toc -->
- `string` - The modified format of the total price, which must contain the substring `&lt;price/&gt;`, or the original price format.
### Code example <!-- omit in toc -->
```ts
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyTotalsPrice = ( defaultValue, extensions, args, validation ) => {
return 'Pay &lt;price/&gt; now';
};
registerCheckoutFilters( 'my-extension', {
totalValue: modifyTotalsPrice,
} );
```
> Filters can be also combined. See [Combined filters](./category/cart-and-checkout-blocks/available-filters/) for an example.
### Screenshots <!-- omit in toc -->
| Before | After |
|:---------------------------------------------------------------------:|:---------------------------------------------------------------------:|
|![Before applying the Total Value filter](https://github.com/woocommerce/woocommerce/assets/3323310/4b788bdd-6fbd-406c-a9ad-4fb13f901c23) |![After applying the Total Value filter](https://github.com/woocommerce/woocommerce/assets/3323310/1b1b5f72-7f2f-4ee5-b2a4-1d8eb2208deb) |
## Cart object
The Cart object of the filters above has the following keys:
- _billingAddress_ `object` - The billing address object with the following keys:
- _address_1_ `string` - The first line of the address.
- _address_2_ `string` - The second line of the address.
- _city_ `string` - The city of the address.
- _company_ `string` - The company of the address.
- _country_ `string` - The country of the address.
- _email_ `string` - The email of the address.
- _first_name_ `string` - The first name of the address.
- _last_name_ `string` - The last name of the address.
- _phone_ `string` - The phone of the address.
- _postcode_ `string` - The postcode of the address.
- _state_ `string` - The state of the address.
- ~~_billingData_~~ `object` - The billing data object with the same keys as the `billingAddress` object.
- _cartCoupons_ `array` - The cart coupons array.
- _cartErrors_ `array` - The cart errors array.
- _cartFees_ `array` - The cart fees array.
- _cartHasCalculatedShipping_ `boolean` - Whether the cart has calculated shipping.
- _cartIsLoading_ `boolean` - Whether the cart is loading.
- _cartItemErrors_ `array` - The cart item errors array.
- _cartItems_ `array` - The cart items array with cart item objects, see [Cart Item object](#cart-item-object).
- _cartItemsCount_ `number` - The cart items count.
- _cartItemsWeight_ `number` - The cart items weight.
- _cartNeedsPayment_ `boolean` - Whether the cart needs payment.
- _cartNeedsShipping_ `boolean` - Whether the cart needs shipping.
- _cartTotals_ `object` - The cart totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _tax_lines_ `array` - The tax lines array with tax line objects with the following keys:
- _name_ `string` - The name of the tax line.
- _price_ `number` - The price of the tax line.
- _rate_ `string` - The rate ID of the tax line.
- _total_discount_ `string` - The total discount.
- _total_discount_tax_ `string` - The total discount tax.
- _total_fees_ `string` - The total fees.
- _total_fees_tax_ `string` - The total fees tax.
- _total_items_ `string` - The total items.
- _total_items_tax_ `string` - The total items tax.
- _total_price_ `string` - The total price.
- _total_shipping_ `string` - The total shipping.
- _total_shipping_tax_ `string` - The total shipping tax.
- _total_tax_ `string` - The total tax.
- _crossSellsProducts_ `array` - The cross sells products array with cross sells product objects.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _isLoadingRates_ `boolean` - Whether the cart is loading rates.
- _paymentRequirements_ `array` - The payment requirements array.
- _shippingAddress_ `object` - The shipping address object with the same keys as the `billingAddress` object.
- _shippingRates_ `array` - The shipping rates array.
## Cart Item object
The Cart Item object of the filters above has the following keys:
- _backorders_allowed_ `boolean` - Whether backorders are allowed.
- _catalog_visibility_ `string` - The catalog visibility.
- _decsription_ `string` - The cart item description.
- _extensions_ `object` (default: `{}`) - The extensions object.
- _id_ `number` - The item ID.
- _images_ `array` - The item images array.
- _item_data_ `array` - The item data array.
- _key_ `string` - The item key.
- _low_stock_remaining_ `number` - The low stock remaining.
- _name_ `string` - The item name.
- _permalink_ `string` - The item permalink.
- _prices_ `object` - The item prices object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _price_ `string` - The price.
- _price_range_ `string` - The price range.
- _raw_prices_ `object` - The raw prices object with the following keys:
- _precision_ `number` - The precision.
- _price_ `number` - The price.
- _regular_price_ `number` - The regular price.
- _sale_price_ `number` - The sale price.
- _regular_price_ `string` - The regular price.
- _sale_price_ `string` - The sale price.
- _quantity_ `number` - The item quantity.
- _quantity_limits_ `object` - The item quantity limits object with the following keys:
- _editable_ `boolean` - Whether the quantity is editable.
- _maximum_ `number` - The maximum quantity.
- _minimum_ `number` - The minimum quantity.
- _multiple_of_ `number` - The multiple of quantity.
- _short_description_ `string` - The item short description.
- _show_backorder_badge_ `boolean` - Whether to show the backorder badge.
- _sku_ `string` - The item SKU.
- _sold_individually_ `boolean` - Whether the item is sold individually.
- _totals_ `object` - The item totals object with the following keys:
- _currency_code_ `string` - The currency code.
- _currency_decimal_separator_ `string` - The currency decimal separator.
- _currency_minor_unit_ `number` - The currency minor unit.
- _currency_prefix_ `string` - The currency prefix.
- _currency_suffix_ `string` - The currency suffix.
- _currency_symbol_ `string` - The currency symbol.
- _currency_thousand_separator_ `string` - The currency thousand separator.
- _line_subtotal_ `string` - The line subtotal.
- _line_subtotal_tax_ `string` - The line subtotal tax.
- _line_total_ `string` - The line total.
- _line_total_tax_ `string` - The line total tax.
- _type_ `string` - The item type.
- _variation_ `array` - The item variation array.

View File

@ -0,0 +1,172 @@
---
post_title: Cart and Checkout - Available slots
menu_title: Available Slots
tags: reference
---
<!-- markdownlint-disable MD024 -->
This document presents the list of available Slots that you can use for adding your custom content (Fill).
If you want to add a new SlotFill component, check the [Checkout - Slot Fill document](https://github.com/woocommerce/woocommerce/blob/1675c63bba94c59703f57c7ef06e7deff8fd6bba/plugins/woocommerce-blocks/packages/checkout/slot/README.md). To read more about Slot and Fill, check the [Slot and Fill document](./cart-and-checkout-slot-and-fill/).
**Note About Naming:** Slots that are prefixed with `Experimental` are experimental and subject to change or remove. Once they graduate from the experimental stage, the naming would change and the `Experimental` prefix would be dropped. Check the [Feature Gating document](https://github.com/woocommerce/woocommerce/blob/1675c63bba94c59703f57c7ef06e7deff8fd6bba/plugins/woocommerce-blocks/docs/internal-developers/blocks/feature-flags-and-experimental-interfaces.md) from more information.
## ExperimentalOrderMeta
This Slot renders below the Checkout summary section and above the "Proceed to Checkout" button in the Cart.
```ts
const { __ } = window.wp.i18n;
const { registerPlugin } = window.wp.plugins;
const { ExperimentalOrderMeta } = window.wc.blocksCheckout;
const render = () => {
return (
&lt;ExperimentalOrderMeta&gt;
&lt;div class="wc-block-components-totals-wrapper"&gt;
{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
&lt;/div&gt;
&lt;/ExperimentalOrderMeta&gt;
);
};
registerPlugin( 'slot-and-fill-examples', {
render,
scope: 'woocommerce-checkout',
} );
```
Cart:
![Example of ExperimentalOrderMeta in the Cart block](https://user-images.githubusercontent.com/1628454/154517779-117bb4e4-568e-413c-904c-855fc3450dfa.png)
Checkout:
![Example of ExperimentalOrderMeta in the Checkout block](https://user-images.githubusercontent.com/1628454/154697224-de245182-6783-4914-81ba-1dbcf77292eb.png)
### Passed parameters
- `cart`: `wc/store/cart` data but in `camelCase` instead of `snake_case`. [Object breakdown.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L172-L188)
- `extensions`: external data registered by third-party developers using `ExtendSchema`. If you used `ExtendSchema` on `wc/store/cart` you would find your data under your namespace here.
- `context`, equal to the name of the Block in which the fill is rendered: `woocommerce/cart` or `woocommerce/checkout`
## ExperimentalOrderShippingPackages
This slot renders inside the shipping step of Checkout and inside the shipping options in Cart.
```ts
const { __ } = window.wp.i18n;
const { registerPlugin } = window.wp.plugins;
const { ExperimentalOrderShippingPackages } = window.wc.blocksCheckout;
const render = () => {
return (
&lt;ExperimentalOrderShippingPackages&gt;
&lt;div&gt;{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }&lt;/div&gt;
&lt;/ExperimentalOrderShippingPackages&gt;
);
};
registerPlugin( 'slot-and-fill-examples', {
render,
scope: 'woocommerce-checkout',
} );
```
Cart:
![Example of ExperimentalOrderShippingPackages in the Cart block](https://user-images.githubusercontent.com/6165348/118399054-2b4dec80-b653-11eb-94a0-989e2e6e362a.png)
Checkout:
![Example of ExperimentalOrderShippingPackages in the Checkout block](https://user-images.githubusercontent.com/6165348/118399133-90094700-b653-11eb-8ff0-c917947c199f.png)
### Passed parameters
- `collapsible`: `Boolean|undefined` If a shipping package panel should be collapsible or not, this is false in Checkout and undefined in Cart.
- `collapse`: `Boolean` If a panel should be collapsed by default, this is true if if panels are collapsible.
- `showItems`: `Boolean|undefined` If we should show the content of each package, this is undefined in Cart and Checkout and is left to the actual package logic to decide.
- `noResultsMessage`: A React element that you can render if there are no shipping options.
- `renderOption`: a render function that takes a rate object and returns a render option.
- `cart`: `wc/store/cart` data but in `camelCase` instead of `snake_case`. [Object breakdown.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L172-L188)
- `extensions`: external data registered by third-party developers using `ExtendSchema`, if you used `ExtendSchema` on `wc/store/cart` you would find your data under your namespace here.
- `components`: an object containing components you can use to render your own shipping rates, it contains `ShippingRatesControlPackage`.
- `context`, equal to the name of the Block in which the fill is rendered: `woocommerce/cart` or `woocommerce/checkout`
## ExperimentalOrderLocalPickupPackages
This slot renders inside the Checkout Pickup Options block in the Checkout block. It does not render in the Cart block.
```ts
const { __ } = window.wp.i18n;
const { registerPlugin } = window.wp.plugins;
const { ExperimentalOrderLocalPickupPackages } = window.wc.blocksCheckout;
const render = () => {
return (
&lt;ExperimentalOrderLocalPickupPackages&gt;
&lt;div&gt;
{ __(
'By using our convenient local pickup option, you can come to our store and pick up your order. We will send you and email when your order is ready for pickup.',
'YOUR-TEXTDOMAIN'
) }
&lt;/div&gt;
&lt;/ExperimentalOrderLocalPickupPackages&gt;
);
};
registerPlugin( 'slot-and-fill-examples', {
render,
scope: 'woocommerce-checkout',
} );
```
Checkout:
![Example of ExperimentalOrderLocalPickupPackages in the Checkout block](https://user-images.githubusercontent.com/5656702/222814945-a449d016-0621-4a70-b0f4-2ae1ce6487f1.png)
### Passed parameters
- `renderPickupLocation`: a render function that renders the address details of a local pickup option.
- `cart`: `wc/store/cart` data but in `camelCase` instead of `snake_case`. [Object breakdown.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L172-L188)
- `extensions`: external data registered by third-party developers using `ExtendSchema`, if you used `ExtendSchema` on `wc/store/cart` you would find your data under your namespace here.
- `components`: an object containing components you can use to render your own pickup rates, it contains `ShippingRatesControlPackage` and `RadioControl`.
## ExperimentalDiscountsMeta
This slot renders below the `CouponCode` input.
```ts
const { __ } = window.wp.i18n;
const { registerPlugin } = window.wp.plugins;
const { ExperimentalDiscountsMeta } = window.wc.blocksCheckout;
const render = () => {
return (
&lt;ExperimentalDiscountsMeta&gt;
&lt;div class="wc-block-components-totals-wrapper"&gt;
{ __( 'You have 98683 coins to spend ...', 'YOUR-TEXTDOMAIN' ) }
&lt;/div&gt;
&lt;/ExperimentalDiscountsMeta&gt;
);
};
registerPlugin( 'slot-and-fill-examples', {
render,
scope: 'woocommerce-checkout',
} );
```
Cart:
![Cart showing ExperimentalDiscountsMeta location](https://user-images.githubusercontent.com/5656702/122774218-ea27a880-d2a0-11eb-9450-11f119567f26.png)
Checkout:
![Checkout showing ExperimentalDiscountsMeta location](https://user-images.githubusercontent.com/5656702/122779606-efd3bd00-d2a5-11eb-8c84-6525eca5d704.png)
### Passed parameters
- `cart`: `wc/store/cart` data but in `camelCase` instead of `snake_case`. [Object breakdown.](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c00da597efe4c16fcf5481c213d8052ec5df3766/assets/js/type-defs/cart.ts#L172-L188)
- `extensions`: external data registered by third-party developers using `ExtendSchema`, if you used `ExtendSchema` on `wc/store/cart` you would find your data under your namespace here.
- `context`, equal to the name of the Block in which the fill is rendered: `woocommerce/cart` or `woocommerce/checkout`

View File

@ -0,0 +1,8 @@
---
category_title: Payment Methods
category_slug: checkout-payment-methods
post_title: Checkout payment methods
---

View File

@ -0,0 +1,469 @@
---
post_title: Cart and Checkout - Checkout flow and events
menu_title: Checkout Flow and Events
tags: reference
---
This document gives an overview of the flow for the checkout in the WooCommerce checkout block, and some general architectural overviews.
The architecture of the Checkout Block is derived from the following principles:
- A single source of truth for data within the checkout flow.
- Provide a consistent interface for extension integrations (eg Payment methods). This interface protects the integrity of the checkout process and isolates extension logic from checkout logic. The checkout block handles _all_ communication with the server for processing the order. Extensions are able to react to and communicate with the checkout block via the provided interface.
- Checkout flow state is tracked by checkout status.
- Extensions are able to interact with the checkout flow via subscribing to emitted events.
Here's a high level overview of the flow:
![checkout flow diagram](https://user-images.githubusercontent.com/1628454/113739726-f8c9df00-96f7-11eb-80f1-78e25ccc88cb.png)
## General Concepts
### Tracking flow through status
At any point in the checkout lifecycle, components should be able to accurately detect the state of the checkout flow. This includes things like:
- Is something loading? What is loading?
- Is there an error? What is the error?
- is the checkout calculating totals?
Using simple booleans can be fine in some cases, but in others it can lead to complicated conditionals and bug prone code (especially for logic behaviour that reacts to various flow state).
To surface the flow state, the block uses statuses that are tracked in the various contexts. _As much as possible_ these statuses are set internally in reaction to various actions so there's no implementation needed in children components (components just have to _consume_ the status not set status).
The following statuses exist in the Checkout.
#### Checkout Data Store Status
There are various statuses that are exposed on the Checkout data store via selectors. All the selectors are detailed below and in the [Checkout API docs](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/docs/internal-developers/block-client-apis/checkout/checkout-api.md).
You can use them in your component like so
```jsx
const { useSelect } = window.wp.data;
const { CHECKOUT_STORE_KEY } = window.wc.wcBlocksData;
const MyComponent = ( props ) => {
const isComplete = useSelect( ( select ) =>
select( CHECKOUT_STORE_KEY ).isComplete()
);
// do something with isComplete
};
```
The following boolean flags available related to status are:
**isIdle**: When the checkout status is `IDLE` this flag is true. Checkout will be this status after any change to checkout state after the block is loaded. It will also be this status when retrying a purchase is possible after processing happens with an error.
**isBeforeProcessing**: When the checkout status is `BEFORE_PROCESSING` this flag is true. Checkout will be this status when the user submits checkout for processing.
**isProcessing**: When the checkout status is `PROCESSING` this flag is true. Checkout will be this status when all the observers on the event emitted with the `BEFORE_PROCESSING` status are completed without error. It is during this status that the block will be sending a request to the server on the checkout endpoint for processing the order. **Note:** there are some checkout payment status changes that happen during this state as well (outlined in the `PaymentProvider` exposed statuses section).
**isAfterProcessing**: When the checkout status is `AFTER_PROCESSING` this flag is true. Checkout will have this status after the block receives the response from the server side processing request.
**isComplete**: When the checkout status is `COMPLETE` this flag is true. Checkout will have this status after all observers on the events emitted during the `AFTER_PROCESSING` status are completed successfully. When checkout is at this status, the shopper's browser will be redirected to the value of `redirectUrl` at that point (usually the `order-received` route).
#### Special States
The following are booleans exposed via the checkout provider that are independent from each other and checkout statuses but can be used in combination to react to various state in the checkout.
**isCalculating:** This is true when the total is being re-calculated for the order. There are numerous things that might trigger a recalculation of the total: coupons being added or removed, shipping rates updated, shipping rate selected etc. This flag consolidates all activity that might be occurring (including requests to the server that potentially affect calculation of totals). So instead of having to check each of those individual states you can reliably just check if this boolean is true (calculating) or false (not calculating).
**hasError:** This is true when anything in the checkout has created an error condition state. This might be validation errors, request errors, coupon application errors, payment processing errors etc.
### `ShippingProvider` Exposed Statuses
The shipping context provider exposes everything related to shipping in the checkout. Included in this are a set of error statuses that inform what error state the shipping context is in and the error state is affected by requests to the server on address changes, rate retrieval and selection.
Currently the error status may be one of `NONE`, `INVALID_ADDRESS` or `UNKNOWN` (note, this may change in the future).
The status is exposed on the `currentErrorStatus` object provided by the `useShippingDataContext` hook. This object has the following properties on it:
- `isPristine` and `isValid`: Both of these booleans are connected to the same error status. When the status is `NONE` the values for these booleans will be `true`. It basically means there is no shipping error.
- `hasInvalidAddress`: When the address provided for shipping is invalid, this will be true.
- `hasError`: This is `true` when the error status for shipping is either `UNKNOWN` or `hasInvalidAddress`.
### Payment Method Data Store Status
The status of the payment lives in the payment data store. You can query the status with the following selectors:
```jsx
const { select } = window.wp.data;
const { PAYMENT_STORE_KEY } = window.wc.wcBlocksData;
const MyComponent = ( props ) => {
const isPaymentIdle = select( PAYMENT_STORE_KEY ).isPaymentIdle();
const isExpressPaymentStarted =
select( PAYMENT_STORE_KEY ).isExpressPaymentStarted();
const isPaymentProcessing =
select( PAYMENT_STORE_KEY ).isPaymentProcessing();
const isPaymentReady = select( PAYMENT_STORE_KEY ).isPaymentReady();
const hasPaymentError = select( PAYMENT_STORE_KEY ).hasPaymentError();
// do something with the boolean values
};
```
The status here will help inform the current state of _client side_ processing for the payment and are updated via the store actions at different points throughout the checkout processing cycle. _Client side_ means the state of processing any payments by registered and active payment methods when the checkout form is submitted via those payment methods registered client side components. It's still possible that payment methods might have additional server side processing when the order is being processed but that is not reflected by these statuses (more in the [payment method integration doc](./payment-method-integration.md)).
The possible _internal_ statuses that may be set are:
- `IDLE`: This is the status when checkout is initialized and there are payment methods that are not doing anything. This status is also set whenever the checkout status is changed to `IDLE`.
- `EXPRESS_STARTED`: **Express Payment Methods Only** - This status is used when an express payment method has been triggered by the user clicking it's button. This flow happens before processing, usually in a modal window.
- `PROCESSING`: This status is set when the checkout status is `PROCESSING`, checkout `hasError` is false, checkout is not calculating, and the current payment status is not `FINISHED`. When this status is set, it will trigger the payment processing event emitter.
- `READY`: This status is set after all the observers hooked into the payment processing event have completed successfully. The `CheckoutProcessor` component uses this along with the checkout `PROCESSING` status to signal things are ready to send the order to the server with data for processing and to take payment
- `ERROR`: This status is set after an observer hooked into the payment processing event returns an error response. This in turn will end up causing the checkout `hasError` flag to be set to true.
### Emitting Events
Another tricky thing for extensibility, is providing opinionated, yet flexible interfaces for extensions to act and react to specific events in the flow. For stability, it's important that the core checkout flow _controls_ all communication to and from the server specific to checkout/order processing and leave extension specific requirements for the extension to handle. This allows for extensions to predictably interact with the checkout data and flow as needed without impacting other extensions hooking into it.
One of the most reliable ways to implement this type of extensibility is via the usage of an events system. Thus the various context providers:
- expose subscriber APIs for extensions to subscribe _observers_ to the events they want to react to.
- emit events at specific points of the checkout flow that in turn will feed data to the registered observers and, in some cases, react accordingly to the responses from observers.
One _**very important rule**_ when it comes to observers registered to any event emitter in this system is that they _cannot_ update context state. Updating state local to a specific component is okay but not any context or global state. The reason for this is that the observer callbacks are run sequentially at a specific point and thus subsequent observers registered to the same event will not react to any change in global/context state in earlier executed observers.
```jsx
const unsubscribe = emitter( myCallback );
```
You could substitute in whatever emitter you are registering for the `emitter` function. So for example if you are registering for the `onCheckoutValidation` event emitter, you'd have something like:
```jsx
const unsubscribe = onCheckoutValidation( myCallback );
```
You can also indicate what priority you want your observer to execute at. Lower priority is run before higher priority, so you can affect when your observer will run in the stack of observers registered to an emitter. You indicate priority via an number on the second argument:
```jsx
const unsubscribe = onCheckoutValidation( myCallback, 10 );
```
In the examples, `myCallback`, is your subscriber function. The subscriber function could receive data from the event emitter (described in the emitter details below) and may be expected to return a response in a specific shape (also described in the specific emitter details). The subscriber function can be a `Promise` and when the event emitter cycles through the registered observers it will await for any registered Promise to resolve.
Finally, the return value of the call to the emitter function is an unsubscribe function that can be used to unregister your observer. This is especially useful in a React component context where you need to make sure you unsubscribe the observer on component unmount. An example is usage in a `useEffect` hook:
```jsx
const MyComponent = ( { onCheckoutValidation } ) => {
useEffect( () => {
const unsubscribe = onCheckoutValidation( () => true );
return unsubscribe;
}, [ onCheckoutValidation ] );
return null;
};
```
**`Event Emitter Utilities`**
There are a bunch of utility methods that can be used related to events. These are available in `assets/js/base/context/event-emit/utils.ts` and can be imported as follows:
```jsx
import {
isSuccessResponse,
isErrorResponse,
isFailResponse,
noticeContexts,
responseTypes,
shouldRetry,
} from '@woocommerce/base-context';
};
```
The helper functions are described below:
- `isSuccessResponse`, `isErrorResponse` and `isFailResponse`: These are helper functions that receive a value and report via boolean whether the object is a type of response expected. For event emitters that receive responses from registered observers, a `type` property on the returned object from the observer indicates what type of response it is and event emitters will react according to that type. So for instance if an observer returned `{ type: 'success' }` the emitter could feed that to `isSuccessResponse` and it would return `true`. You can see an example of this being implemented for the payment processing emitted event [here](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/assets/js/base/context/cart-checkout/payment-methods/payment-method-data-context.js#L281-L307).
- `noticeContexts`: This is an object containing properties referencing areas where notices can be targeted in the checkout. The object has the following properties:
- `PAYMENTS`: This is a reference to the notice area in the payment methods step.
- `EXPRESS_PAYMENTS`: This is a reference to the notice area in the express payment methods step.
- `responseTypes`: This is an object containing properties referencing the various response types that can be returned by observers for some event emitters. It makes it easier for autocompleting the types and avoiding typos due to human error. The types are `SUCCESS`, `FAIL`, `ERROR`. The values for these types also correspond to the [payment status types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/Payments/PaymentResult.php#L21) from the [checkout endpoint response from the server](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L113).
- `shouldRetry`: This is a function containing the logic whether the checkout flow should allow the user to retry the payment after a previous payment failed. It receives the `response` object and by default checks whether the `retry` property is true/undefined or false. Refer to the [`onCheckoutSuccess`](#oncheckoutsuccess) documentation for more details.
Note: `noticeContexts` and `responseTypes` are exposed to payment methods via the `emitResponse` prop given to their component:
```jsx
const MyPaymentMethodComponent = ( { emitResponse } ) => {
const { noticeContexts, responseTypes } = emitResponse;
// other logic for payment method...
};
```
The following event emitters are available to extensions to register observers to:
### `onCheckoutValidation`
Observers registered to this event emitter will receive nothing as an argument. Also, all observers will be executed before the checkout handles the responses from the emitters. Observers registered to this emitter can return `true` if they have nothing to communicate back to checkout, `false` if they want checkout to go back to `IDLE` status state, or an object with any of the following properties:
- `errorMessage`: This will be added as an error notice on the checkout context.
- `validationErrors`: This will be set as inline validation errors on checkout fields. If your observer wants to trigger validation errors it can use the following shape for the errors:
- This is an object where keys are the property names the validation error is for (that correspond to a checkout field, eg `country` or `coupon`) and values are the error message describing the validation problem.
This event is emitted when the checkout status is `BEFORE_PROCESSING` (which happens at validation time, after the checkout form submission is triggered by the user - or Express Payment methods).
If all observers return `true` for this event, then the checkout status will be changed to `PROCESSING`.
This event emitter subscriber can be obtained via the checkout context using the `useCheckoutContext` hook or to payment method extensions as a prop on their registered component:
_For internal development:_
```jsx
import { useCheckoutContext } from '@woocommerce/base-contexts';
import { useEffect } from '@wordpress/element';
const Component = () => {
const { onCheckoutValidation } = useCheckoutContext();
useEffect( () => {
const unsubscribe = onCheckoutValidation( () => true );
return unsubscribe;
}, [ onCheckoutValidation ] );
return null;
};
```
_For registered payment method components:_
```jsx
const { useEffect } = window.wp.element;
const PaymentMethodComponent = ( { eventRegistration } ) => {
const { onCheckoutValidation } = eventRegistration;
useEffect( () => {
const unsubscribe = onCheckoutValidation( () => true );
return unsubscribe;
}, [ onCheckoutValidation ] );
};
```
### ~~`onPaymentProcessing`~~
This is now deprecated and replaced by the `onPaymentSetup` event emitter.
### `onPaymentSetup`
This event emitter was fired when the payment method context status is `PROCESSING` and that status is set when the checkout status is `PROCESSING`, checkout `hasError` is false, checkout is not calculating, and the current payment status is not `FINISHED`.
This event emitter will execute through each registered observer (passing in nothing as an argument) _until_ an observer returns a non-truthy value at which point it will _abort_ further execution of registered observers.
When a payment method returns a non-truthy value, if it returns a valid response type the event emitter will update various internal statuses according to the response. Here's the possible response types that will get handled by the emitter:
#### Success
A successful response should be given when the user's entered data is correct and the payment checks are successful. A response is considered successful if, at a minimum, it is an object with this shape:
```js
const successResponse = { type: 'success' };
```
When a success response is returned, the payment method context status will be changed to `SUCCESS`. In addition, including any of the additional properties will result in extra actions:
- `paymentMethodData`: The contents of this object will be included as the value for `payment_data` when checkout sends a request to the checkout endpoint for processing the order. This is useful if a payment method does additional server side processing.
- `billingAddress`: This allows payment methods to update any billing data information in the checkout (typically used by Express payment methods) so it's included in the checkout processing request to the server. This data should be in the [shape outlined here](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/settings/shared/default-fields.ts).
- `shippingAddress`: This allows payment methods to update any shipping data information for the order (typically used by Express payment methods) so it's included in the checkout processing request to the server. This data should be in the [shape outlined here](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/settings/shared/default-fields.ts).
If `billingAddress` or `shippingAddress` properties aren't in the response object, then the state for the data is left alone.
#### Fail
A fail response should be given when there is an error with the payment processing. A response is considered a fail response when it is an object with this shape:
```js
const failResponse = { type: 'failure' };
```
When a fail response is returned by an observer, the payment method context status will be changed to `FAIL`. In addition, including any of the following properties will result in extra actions:
- `message`: The string provided here will be set as an error notice in the checkout.
- `messageContext`: If provided, this will target the given area for the error notice (this is where `noticeContexts` mentioned earlier come in to play). Otherwise the notice will be added to the `noticeContexts.PAYMENTS` area.
- `paymentMethodData`: (same as for success responses).
- `billingAddress`: (same as for success responses).
#### Error
An error response should be given when there is an error with the user input on the checkout form. A response is considered an error response when it is an object with this shape:
```js
const errorResponse = { type: 'error' };
```
When an error response is returned by an observer, the payment method context status will be changed to `ERROR`. In addition, including any of the following properties will result in extra actions:
- `message`: The string provided here will be set as an error notice.
- `messageContext`: If provided, this will target the given area for the error notice (this is where `noticeContexts` mentioned earlier come in to play). Otherwise, the notice will be added to the `noticeContexts.PAYMENTS` area.
- `validationErrors`: This will be set as inline validation errors on checkout fields. If your observer wants to trigger validation errors it can use the following shape for the errors:
- This is an object where keys are the property names the validation error is for (that correspond to a checkout field, eg `country` or `coupon`) and values are the error message describing the validation problem.
If the response object doesn't match any of the above conditions, then the fallback is to set the payment status as `SUCCESS`.
When the payment status is set to `SUCCESS` and the checkout status is `PROCESSING`, the `CheckoutProcessor` component will trigger the request to the server for processing the order.
This event emitter subscriber can be obtained via the checkout context using the `usePaymentEventsContext` hook or to payment method extensions as a prop on their registered component:
_For internal development:_
```jsx
import { usePaymentEventsContext } from '@woocommerce/base-contexts';
import { useEffect } from '@wordpress/element';
const Component = () => {
const { onPaymentSetup } = usePaymentEventsContext();
useEffect( () => {
const unsubscribe = onPaymentSetup( () => true );
return unsubscribe;
}, [ onPaymentSetup ] );
return null;
};
```
_For registered payment method components:_
```jsx
const { useEffect } = window.wp.element;
const PaymentMethodComponent = ( { eventRegistration } ) => {
const { onPaymentSetup } = eventRegistration;
useEffect( () => {
const unsubscribe = onPaymentSetup( () => true );
return unsubscribe;
}, [ onPaymentSetup ] );
};
```
### `onCheckoutSuccess`
This event emitter is fired when the checkout status is `AFTER_PROCESSING` and the checkout `hasError` state is false. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request.
Observers registered to this event emitter will receive the following object as an argument:
```js
const onCheckoutProcessingData = {
redirectUrl,
orderId,
customerId,
orderNotes,
paymentResult,
};
```
The properties are:
- `redirectUrl`: This is a string that is the url the checkout will redirect to as returned by the processing on the server.
- `orderId`: Is the id of the current order being processed.
- `customerId`: Is the id for the customer making the purchase (that is attached to the order).
- `orderNotes`: This will be any custom note the customer left on the order.
- `paymentResult`: This is the value of [`payment_result` from the /checkout StoreApi response](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L138). The data exposed on this object is (via the object properties):
- `paymentStatus`: Whatever the status is for the payment after it was processed server side. Will be one of `success`, `failure`, `pending`, `error`.
- `paymentDetails`: This will be an arbitrary object that contains any data the payment method processing server side sends back to the client in the checkout processing response. Payment methods are able to hook in on the processing server side and set this data for returning.
This event emitter will invoke each registered observer until a response from any of the registered observers does not equal `true`. At that point any remaining non-invoked observers will be skipped and the response from the observer triggering the abort will be processed.
This emitter will handle a `success` response type (`{ type: success }`) by setting the checkout status to `COMPLETE`. Along with that, if the response includes `redirectUrl` then the checkout will redirect to the given address.
This emitter will also handle a `failure` response type or an `error` response type and if no valid type is detected it will treat it as an `error` response type.
In all cases, if there are the following properties in the response, additional actions will happen:
- `message`: This string will be added as an error notice.
- `messageContext`: If present, the notice will be configured to show in the designated notice area (otherwise it will just be a general notice for the checkout block).
- `retry`: If this is `true` or not defined, then the checkout status will be set to `IDLE`. This basically means that the error is recoverable (for example try a different payment method) and so checkout will be reset to `IDLE` for another attempt by the shopper. If this is `false`, then the checkout status is set to `COMPLETE` and the checkout will redirect to whatever is currently set as the `redirectUrl`.
- `redirectUrl`: If this is present, then the checkout will redirect to this url when the status is `COMPLETE`.
If all observers return `true`, then the checkout status will just be set to `COMPLETE`.
This event emitter subscriber can be obtained via the checkout context using the `useCheckoutContext` hook or to payment method extensions as a prop on their registered component:
_For internal development:_
```jsx
import { useCheckoutContext } from '@woocommerce/base-contexts';
import { useEffect } from '@wordpress/element';
const Component = () => {
const { onCheckoutSuccess } = useCheckoutContext();
useEffect( () => {
const unsubscribe = onCheckoutSuccess( () => true );
return unsubscribe;
}, [ onCheckoutSuccess ] );
return null;
};
```
_For registered payment method components:_
```jsx
const { useEffect } = window.wp.element;
const PaymentMethodComponent = ( { eventRegistration } ) => {
const { onCheckoutSuccess } = eventRegistration;
useEffect( () => {
const unsubscribe = onCheckoutSuccess( () => true );
return unsubscribe;
}, [ onCheckoutSuccess ] );
};
```
### `onCheckoutFail`
This event emitter is fired when the checkout status is `AFTER_PROCESSING` and the checkout `hasError` state is `true`. The `AFTER_PROCESSING` status is set by the `CheckoutProcessor` component after receiving a response from the server for the checkout processing request.
Observers registered to this emitter will receive the same data package as those registered to `onCheckoutSuccess`.
The response from the first observer returning a value that does not `===` true will be handled similarly as the `onCheckoutSuccess` except it only handles when the type is `error` or `failure`.
If all observers return `true`, then the checkout status will just be set to `IDLE` and a default error notice will be shown in the checkout context.
This event emitter subscriber can be obtained via the checkout context using the `useCheckoutContext` hook or to payment method extensions as a prop on their registered component:
_For internal development:_
```jsx
import { useCheckoutContext } from '@woocommerce/base-contexts';
import { useEffect } from '@wordpress/element';
const Component = () => {
const { onCheckoutFail } = useCheckoutContext();
useEffect( () => {
const unsubscribe = onCheckoutFail( () => true );
return unsubscribe;
}, [ onCheckoutFail ] );
return null;
};
```
_For registered payment method components:_
```jsx
const { useEffect } = window.wp.element;
const PaymentMethodComponent = ( { eventRegistration } ) => {
const { onCheckoutFail } = eventRegistration;
useEffect( () => {
const unsubscribe = onCheckoutFail( () => true );
return unsubscribe;
}, [ onCheckoutFail ] );
};
```
### `onShippingRateSuccess`
This event emitter is fired when shipping rates are not loading and the shipping data context error state is `NONE` and there are shipping rates available.
This event emitter doesn't care about any registered observer response and will simply execute all registered observers passing them the current shipping rates retrieved from the server.
### `onShippingRateFail`
This event emitter is fired when shipping rates are not loading and the shipping data context error state is `UNKNOWN` or `INVALID_ADDRESS`.
This event emitter doesn't care about any registered observer response and will simply execute all registered observers passing them the current error status in the context.
### `onShippingRateSelectSuccess`
This event emitter is fired when a shipping rate selection is not being persisted to the server and there are selected rates available and the current error status in the context is `NONE`.
This event emitter doesn't care about any registered observer response and will simply execute all registered observers passing them the current selected rates.
### `onShippingRateSelectFail`
This event emitter is fired when a shipping rate selection is not being persisted to the server and the shipping data context error state is `UNKNOWN` or `INVALID_ADDRESS`.
This event emitter doesn't care about any registered observer response and will simply execute all registered observers passing them the current error status in the context.

View File

@ -0,0 +1,156 @@
---
post_title: Cart and Checkout - Filtering payment methods in the Checkout block
menu_title: Filtering Payment Methods
tags: how-to
---
<!-- markdownlint-disable MD024 -->
## The problem
You're an extension developer, and your extension is conditionally hiding payment gateways on the checkout step. You need to be able to hide payment gateways on the Checkout block using a front-end extensibility point.
### The solution
WooCommerce Blocks provides a function called `registerPaymentMethodExtensionCallbacks` which allows extensions to register callbacks for specific payment methods to determine if they can make payments.
### Importing
#### Aliased import
```js
import { registerPaymentMethodExtensionCallbacks } from '@woocommerce/blocks-registry';
```
#### `wc global`
```js
const { registerPaymentMethodExtensionCallbacks } = window.wc.wcBlocksRegistry;
```
### Signature
| Parameter | Description | Type |
| ----------- | ------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------- |
| `namespace` | Unique string to identify your extension. Choose something that eliminates a name collision with another extension. | `string` |
| `callbacks` | An object containing callbacks registered for different payment methods | Record< string, CanMakePaymentExtensionCallback > |
Read more below about [callbacks](#callbacks-registered-for-payment-methods).
#### Extension namespace collision
When trying to register callbacks under an extension namespace already used with `registerPaymentMethodExtensionCallbacks`, the registration will be aborted and you will be notified that you are not using a unique namespace. This will be shown in the JavaScript console.
### Usage example
```js
registerPaymentMethodExtensionCallbacks( 'my-hypothetical-extension', {
cod: ( arg ) => {
return arg.shippingAddress.city === 'Berlin';
},
cheque: ( arg ) => {
return false;
},
} );
```
### Callbacks registered for payment methods
Extensions can register only one callback per payment method:
```text
payment_method_name: ( arg ) => {...}
```
`payment_method_name` is the value of the [name](payment-method-integration.md#name-required) property used when the payment method was registered with WooCommerce Blocks.
The registered callbacks are used to determine whether the corresponding payment method should be available as an option for the shopper. The function will be passed an object containing data about the current order.
```ts
type CanMakePaymentExtensionCallback = (
cartData: CanMakePaymentArgument
) => boolean;
```
Each callback will have access to the information bellow
```ts
interface CanMakePaymentArgument {
cart: Cart;
cartTotals: CartTotals;
cartNeedsShipping: boolean;
billingAddress: CartResponseBillingAddress;
shippingAddress: CartResponseShippingAddress;
selectedShippingMethods: Record< string, unknown >;
paymentRequirements: Array< string >;
}
```
If you need data that is not available in the parameter received by the callback you can consider [exposing your data in the Store API](https://github.com/woocommerce/woocommerce/blob/1675c63bba94c59703f57c7ef06e7deff8fd6bba/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md).
## Filtering payment methods using requirements
### The problem
Your extension has added functionality to your store in such a way that only specific payment gateways can process orders that contain certain products.
Using the example of `Bookings` if the shopper adds a `Bookable` product to their cart, for example a stay in a hotel, and you, the merchant, want to confirm all bookings before taking payment. You would still need to capture the customer's checkout details but not their payment method at that point.
### The solution
To allow the shopper to check out without entering payment details, but still require them to fill in the other checkout details it is possible to create a new payment method which will handle carts containing a `Bookable` item.
Using the `supports` configuration of payment methods it is possible to prevent other payment methods (such as credit card, PayPal etc.) from being used to check out, and only allow the one your extension has added to appear in the Checkout block.
For more information on how to register a payment method with WooCommerce Blocks, please refer to the [Payment method integration](./payment-method-integration.md) documentation.
### Basic usage
Following the documentation for registering payment methods linked above, you should register your payment method with a unique `supports` feature, for example `booking_availability`. This will be used to isolate it and prevent other methods from displaying.
First you will need to create a function that will perform the checks on the cart to determine what the specific payment requirements of the cart are. Below is an example of doing this for our `Bookable` products.
Then you will need to use the `register_payment_requirements` on the `ExtendSchema` class to tell the Checkout block to execute a callback to check for requirements.
### Putting it all together
This code example assumes there is some class called `Pseudo_Booking_Class` that has the `cart_contains_bookable_product` method available. The implementation of this method is not relevant here.
```php
/**
* Check the content of the cart and add required payment methods.
*
*
* @return array list of features required by cart items.
*/
function inject_payment_feature_requirements_for_cart_api() {
// Cart contains a bookable product, so return an array containing our requirement of booking_availability.
if ( Pseudo_Booking_Class::cart_contains_bookable_product() ) {
return array( 'booking_availability' );
}
// No bookable products in the cart, no need to add anything.
return array();
}
```
To summarise the above: if there's a bookable product in the cart then this function will return an array containing `booking_availability`, otherwise it will return an empty array.
The next step will tell the `ExtendSchema` class to execute this callback when checking which payment methods to display.
To do this you could use the following code:
```php
add_action('woocommerce_blocks_loaded', function() {
woocommerce_store_api_register_payment_requirements(
array(
'data_callback' => 'inject_payment_feature_requirements_for_cart_api',
)
);
});
```
It is important to note the comment in this code block, you must not instantiate your own version of `ExtendSchema`.
If you've added your payment method correctly with the correct `supports` values then when you reach the checkout page with a `Bookable` item in your cart, any method that does not `supports` the `booking_availability` requirement should not display, while yours, the one that _does_ support this requirement _will_ display.

View File

@ -0,0 +1,237 @@
---
post_title: Cart and Checkout - Payment method integration for the Checkout block
menu_title: Payment Method Integration
tags: reference
---
## Client Side integration
The client side integration consists of an API for registering both _express_ payment methods (those that consist of a one-button payment process initiated by the shopper such as Stripe, ApplePay, or GooglePay), and payment methods such as _cheque_, PayPal Standard, or Stripe Credit Card.
In both cases, the client side integration is done using registration methods exposed on the `blocks-registry` API. You can access this via the `wc` global in a WooCommerce environment (`wc.wcBlocksRegistry`).
> Note: In your build process, you could do something similar to what is done in the blocks repository which [aliases this API as an external on `@woocommerce/blocks-registry`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/bin/webpack-helpers.js#L16-L35).
### Express payment methods - `registerExpressPaymentMethod( options )`
![Express Payment Area](https://user-images.githubusercontent.com/1429108/79565636-17fed500-807f-11ea-8e5d-9af32e43b71d.png)
To register an express payment method, you use the `registerExpressPaymentMethod` function from the blocks registry. An example of importing this for use in your JavaScript file is:
#### `registerExpressPaymentMethod` Aliased import
```js
import { registerExpressPaymentMethod } from '@woocommerce/blocks-registry';
```
#### `registerExpressPaymentMethod` on the `wc` global
```js
const { registerExpressPaymentMethod } = window.wc.wcBlocksRegistry;
```
#### The `registerExpressPaymentMethod` registration options
The registry function expects a JavaScript object with options specific to the payment method:
```js
registerExpressPaymentMethod( options );
```
The options you feed the configuration instance should be an object in this shape (see `ExpressPaymentMethodConfiguration` typedef):
```js
const options = {
name: 'my_payment_method',
content: &lt;div&gt;A React node&lt;/div&gt;,
edit: &lt;div&gt;A React node&lt;/div&gt;,
canMakePayment: () => true,
paymentMethodId: 'new_payment_method',
supports: {
features: [],
},
};
```
Here's some more details on the configuration options:
#### `name` (required)
This should be a unique string (wise to try to pick something unique for your gateway that wouldn't be used by another implementation) that is used as the identifier for the gateway client side. If `paymentMethodId` is not provided, `name` is used for `paymentMethodId` as well.
#### `content` (required)
This should be a React node that will output in the express payment method area when the block is rendered in the frontend. It will be cloned in the rendering process. When cloned, this React node will receive props passed in from the checkout payment method interface that will allow your component to interact with checkout data (more on [these props later](#props-fed-to-payment-method-nodes)).
#### `edit` (required)
This should be a React node that will be output in the express payment method area when the block is rendered in the editor. It will be cloned in the rendering process. When cloned, this React node will receive props from the payment method interface to checkout (but they will contain preview data).
#### `canMakePayment` (required)
A callback to determine whether the payment method should be available as an option for the shopper. The function will be passed an object containing data about the current order.
```ts
canMakePayment( {
cart: Cart,
cartTotals: CartTotals,
cartNeedsShipping: boolean,
shippingAddress: CartShippingAddress,
billingAddress: CartBillingAddress,
selectedShippingMethods: Record<string,unknown>,
paymentRequirements: string[],
} )
```
Returns a boolean value - true if payment method is available for use. If your gateway needs to perform async initialization to determine availability, you can return a promise (resolving to boolean). This allows a payment method to be hidden based on the cart, e.g. if the cart has physical/shippable products (example: [`Cash on delivery`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/assets/js/payment-method-extensions/payment-methods/cod/index.js#L48-L70)); or for payment methods to control whether they are available depending on other conditions.
`canMakePayment` only runs on the frontend of the Store. In editor context, rather than use `canMakePayment`, the editor will assume the payment method is available (true) so that the defined `edit` component is shown to the merchant.
**Keep in mind this function could be invoked multiple times in the lifecycle of the checkout and thus any expensive logic in the callback provided on this property should be memoized.**
#### `paymentMethodId`
This is the only optional configuration object. The value of this property is what will accompany the checkout processing request to the server and is used to identify what payment method gateway class to load for processing the payment (if the shopper selected the gateway). So for instance if this is `stripe`, then `WC_Gateway_Stripe::process_payment` will be invoked for processing the payment.
#### `supports:features`
This is an array of payment features supported by the gateway. It is used to crosscheck if the payment method can be used for the content of the cart. By default payment methods should support at least `products` feature. If no value is provided then this assumes that `['products']` are supported.
---
### Payment Methods - `registerPaymentMethod( options )`
![Image 2021-02-24 at 4 24 05 PM](https://user-images.githubusercontent.com/1429108/109067640-c7073680-76bc-11eb-98e5-f04d35ddef99.jpg)
To register a payment method, you use the `registerPaymentMethod` function from the blocks registry. An example of importing this for use in your JavaScript file is:
#### `registerPaymentMethod` Aliased import
```js
import { registerPaymentMethod } from '@woocommerce/blocks-registry';
```
#### `registerPaymentMethod` on the `wc` global
```js
const { registerPaymentMethod } = window.wc.wcBlocksRegistry;
```
#### The `registerPaymentMethod` registration options
The registry function expects a JavaScript object with options specific to the payment method (see `PaymentMethodRegistrationOptions` typedef):
```js
registerPaymentMethod( options );
```
The options you feed the configuration instance are the same as those for express payment methods with the following additions:
- `savedTokenComponent`: This should be a React node that contains logic handling any processing your payment method has to do with saved payment methods if your payment method supports them. This component will be rendered whenever a customer's saved token using your payment method for processing is selected for making the purchase.
- `label`: This should be a React node that will be used to output the label for the option where the payment methods are. For example it might be `<strong>Credit/Debit Cart</strong>` or you might output images.
- `ariaLabel`: This is the label that will be read out via screen-readers when the payment method is selected.
- `placeOrderButtonLabel`: This is an optional label which will change the default "Place Order" button text to something else when the payment method is selected. As an example, the PayPal Standard payment method [changes the text of the button to "Proceed to PayPal"](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/assets/js/payment-method-extensions/payment-methods/paypal/index.js#L37-L40) when it is selected as the payment method for checkout because the payment method takes the shopper offsite to PayPal for completing the payment.
- `supports`: This is an object containing information about what features your payment method supports. The following keys are valid here:
- `showSavedCards`: This value will determine whether saved cards associated with your payment method are shown to the customer.
- `showSaveOption`: This value will control whether to show the checkbox which allows customers to save their payment method for future payments.
### Props Fed to Payment Method Nodes
A big part of the payment method integration is the interface that is exposed for payment methods to use via props when the node provided is cloned and rendered on block mount. While all the props are listed below, you can find more details about what the props reference, their types etc via the [typedefs described in this file](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/assets/js/types/type-defs/payment-method-interface.ts).
| Property | Type | Description | Values |
| ------------------------ | -------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
| `activePaymentMethod` | String | The slug of the current active payment method in the checkout. | - |
| `billing` | Object | Contains everything related to billing. | `billingAddress`, `cartTotal`, `currency`, `cartTotalItems`, `displayPricesIncludingTax`, `appliedCoupons`, `customerId` |
| `cartData` | Object | Data exposed from the cart including items, fees, and any registered extension data. Note that this data should be treated as immutable (should not be modified/mutated) or it will result in errors in your application. | `cartItems`, `cartFees`, `extensions` |
| `checkoutStatus` | Object | The current checkout status exposed as various boolean state. | `isCalculating`, `isComplete`, `isIdle`, `isProcessing` |
| `components` | Object | It exposes React components that can be implemented by your payment method for various common interface elements used by payment methods. | <!-- markdownlint-disable-line no-inline-html --><ul><li>`ValidationInputError`: a container for holding validation errors which typically you'll include after any inputs.</li><li>[`PaymentMethodLabel`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e089ae17043fa525e8397d605f0f470959f2ae95/assets/js/payment-method-extensions/payment-methods/paypal/index.js#L37-L40): use this component for the payment method label, including an optional icon.</li><li>`PaymentMethodIcons`: a React component used for displaying payment method icons.</li><li>- `LoadingMask`: a wrapper component that handles displaying a loading state when the isLoading prop is true. Exposes the [LoadingMask component](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/c9074a4941919987dbad16a80f358b960336a09d/assets/js/base/components/loading-mask/index.js)</li></ul> |
| `emitResponse` | Object | Contains some constants that can be helpful when using the event emitter. Read the _[Emitting Events](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/e267cd96a4329a4eeef816b2ef627e113ebb72a5/docs/extensibility/checkout-flow-and-events.md#emitting-events)_ section for more details. | <!-- markdownlint-disable-line no-inline-html --><ul><li>`noticeContexts`: This is an object containing properties referencing areas where notices can be targeted in the checkout. The object has the following properties: <ul><li>`PAYMENTS`: This is a reference to the notice area in the payment methods step.</li><li>`EXPRESS_PAYMENTS`: This is a reference to the notice area in the express payment methods step.</li></ul></li><li>`responseTypes`: This is an object containing properties referencing the various response types that can be returned by observers for some event emitters. It makes it easier for autocompleting the types and avoiding typos due to human error. The types are `SUCCESS`, `FAIL`, `ERROR`. The values for these types also correspond to the [payment status types](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/Payments/PaymentResult.php#L21) from the [checkout endpoint response from the server](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/34e17c3622637dbe8b02fac47b5c9b9ebf9e3596/src/RestApi/StoreApi/Schemas/CheckoutSchema.php#L103-L113).</li></ul> |
| `eventRegistration` | object | Contains all the checkout event emitter registration functions. These are functions the payment method can register observers on to interact with various points in the checkout flow (see [this doc](./checkout-flow-and-events.md) for more info). | `onCheckoutValidation`, `onCheckoutSuccess`, `onCheckoutFail`, `onPaymentSetup`, `onShippingRateSuccess`, `onShippingRateFail`, `onShippingRateSelectSuccess`, `onShippingRateSelectFail` |
| `onClick` | Function | **Provided to express payment methods** that should be triggered when the payment method button is clicked (which will signal to checkout the payment method has taken over payment processing) | - |
| `onClose` | Function | **Provided to express payment methods** that should be triggered when the express payment method modal closes and control is returned to checkout. | - |
| `onSubmit` | Function | Submits the checkout and begins processing | - |
| `paymentStatus` | Object | Various payment status helpers. Note, your payment method does not have to handle setting this status client side. Checkout will handle this via the responses your payment method gives from observers registered to [checkout event emitters](./checkout-flow-and-events.md). | `isPristine`, `isStarted`, `isProcessing`, `isFinished`, `hasError`, `hasFailed`, `isSuccessful` (see below for explanation) |
| `setExpressPaymentError` | Function | Receives a string and allows express payment methods to set an error notice for the express payment area on demand. This can be necessary because some express payment method processing might happen outside of checkout events. | - |
| `shippingData` | Object | Contains all shipping related data (outside of the shipping status). | `shippingRates`, `shippingRatesLoading`, `selectedRates`, `setSelectedRates`, `isSelectingRate`, `shippingAddress`, `setShippingAddress`, and `needsShipping` |
| `shippingStatus` | Object | Various shipping status helpers. | <!-- markdownlint-disable-line no-inline-html --><ul><li>`shippingErrorStatus`: an object with various error statuses that might exist for shipping</li><li>`shippingErrorTypes`: an object containing all the possible types for shipping error status</li></ul> |
| `shouldSavePayment` | Boolean | Indicates whether or not the shopper has selected to save their payment method details (for payment methods that support saved payments). True if selected, false otherwise. Defaults to false. | - |
- `isPristine`: This is true when the current payment status is `PRISTINE`.
- `isStarted`: This is true when the current payment status is `EXPRESS_STARTED`.
- `isProcessing`: This is true when the current payment status is `PROCESSING`.
- `isFinished`: This is true when the current payment status is one of `ERROR`, `FAILED`, or`SUCCESS`.
- `hasError`: This is true when the current payment status is `ERROR`.
- `hasFailed`: This is true when the current payment status is `FAILED`.
- `isSuccessful`: This is true when the current payment status is `SUCCESS`
Any registered `savedTokenComponent` node will also receive a `token` prop which includes the id for the selected saved token in case your payment method needs to use it for some internal logic. However, keep in mind, this is just the id representing this token in the database (and the value of the radio input the shopper checked), not the actual customer payment token (since processing using that usually happens on the server for security).
## Server Side Integration
### Processing Payment
The checkout block currently has legacy handling for payment processing. It converts incoming `payment_data` provided by the client-side payment method to `$_POST` and calls the payment gateway's `process_payment` function. If you already have a WooCommerce Payment method extension integrated with the existing shortcode checkout flow, the checkout block's legacy handling will take care of processing your payment for you on the server side. However, If your payment method hooks into the core checkout `process_checkout` function in any way, you will need to account for this behavior and make appropriate adjustments. (See the section below about hooking into the checkout process via the Store API.)
See an example of [Passing a value from the client through to server side payment processing](https://github.com/woocommerce/woocommerce-blocks/blob/62243e1731a0773f51b81fb8406ebc2e8b180b40/docs/internal-developers/block-client-apis/checkout/checkout-api.md#passing-a-value-from-the-client-through-to-server-side-payment-processing)
### Registering Assets
Implementing the correct loading of your client side asset registration is tricky for the blocks integration. This is because there are some dependencies on the _loading order_ of dependent assets in the request. To remove the complexity of this for extension consumers here, the server side API interface helps with ensuring you can register any assets and data to pass along to your client side payment method from the server and handles the correct loading order of those assets.
First, you create a class that extends `Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType` (or you can implement the `Automattic\WooCommerce\Blocks\Payments\PaymentMethodTypeInterface`, but you get some functionality for free via the abstract class).
In your class:
- Define a `name` property (This property is a string used to reference your payment method. It is important to use the same name as in your client-side JavaScript payment method registration, see `name: 'my_payment_method'` in the options object above).
- Define an `initialize` function. This function will get called during the server side initialization process and is a good place to put any settings population etc. Basically anything you need to do to initialize your gateway. **Note, this will be called on every request so don't put anything expensive here.**
- Define an `is_active` function. This should return whether the payment method is active or not.
- Define a `get_payment_method_script_handles` function. In this function you should register your payment method scripts (using `wp_register_script`) and then return the script handles you registered with. This will be used to add your payment method as a dependency of the checkout script and thus take sure of loading it correctly. **Note:** You should still make sure any other asset dependencies your script has are registered properly here, if you're using Webpack to build your assets, you may want to use the [WooCommerce Webpack Dependency Extraction Plugin](https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin) to make this easier for you.
- Define a `get_payment_method_script_handles_for_admin` function. Include this if your payment method has a script you _only_ want to load in the editor context for the checkout block. Include here any script from `get_payment_method_script_handles` that is also needed in the admin.
- Define a `get_payment_method_data` function. You can return from this function an associative array of data you want to be exposed for your payment method client side. This data will be available client side via `wc.wcSettings.getSetting`. So for instance if you assigned `stripe` as the value of the `name` property for this class, client side you can access any data via: `wc.wcSettings.getSetting( 'stripe_data' )`. That would return an object matching the shape of the associative array you returned from this function.
### Hooking into the Checkout processing by the Store API
There may be some cases where the fallback legacy processing of Checkout requests from the StoreAPI mentioned earlier doesn't work for your existing payment method integration. For these cases, there is also an [action hook you can implement to hook into the server side processing of the order](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/308e968c700028180cab391f2223eb0a43dd2d4d/src/RestApi/StoreApi/Routes/Checkout.php#L350-L361). **Note:** a good place to register your callback on this hook is in the `initialize` method of the payment method class you created from the above instructions.
This hook is the _preferred_ place to hook in your payment processing and if you set a status on the provided `PaymentResult` object, then the legacy processing will be ignored for your payment method. Hook callbacks will receive:
[`Automattic\WooCommerce\StoreApi\Payments\PaymentContext`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/src/StoreApi/Payments/PaymentContext.php)
This contains various details about the payment extracted from the checkout processing request. Notably is the `payment_data` property that will contain an associative array of data your payment method client side provided to checkout. It also contains a string value for `payment_method` which contains the `paymentMethodId` value for the active payment method used during checkout processing. So you can use this to determine whether your payment method processes this data or not.
[`Automattic\WooCommerce\StoreApi\Payments\PaymentResult`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/src/StoreApi/Payments/PaymentResult.php)
This contains various details about the payment result returned to the client and exposed on the `onAfterCheckoutProcessingWithSucces/WithError` event. Server side, your payment method can use this to:
- set the status to return for the payment method (one of `success`, `failure`, `pending`, `error`).
- set a redirect url.
- set any additional payment details (in case you need to return something for your client to further process with).
### Putting it all together
So you've created a class extending `Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType`, but you still need to _register_ this with the server side handling of payment methods. In order to do this you need to register a callback on the `woocommerce_blocks_payment_method_type_registration` action. Your callback will receive an instance of `Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry` which has a `register` method for registering an instance of the class you created. It's also recommended that you register your callback on this action within the context of a callback on the `woocommerce_blocks_loaded` action.
> Note: With Cart and Checkout Blocks currently only available in the WooCommerce Blocks Feature plugin, you will want to make sure you check for the availability of the `Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType` class before registering your payment method integration server side.
So for example, assuming your class that extends `Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType` is named `MyPaymentMethod`. You would have this somewhere in your extension's bootstrap:
```php
use MyPlugin\MyPaymentMethod;
use Automattic\WooCommerce\Blocks\Payments\PaymentMethodRegistry;
add_action( 'woocommerce_blocks_loaded', 'my_extension_woocommerce_blocks_support' );
function my_extension_woocommerce_blocks_support() {
if ( class_exists( 'Automattic\WooCommerce\Blocks\Payments\Integrations\AbstractPaymentMethodType' ) ) {
add_action(
'woocommerce_blocks_payment_method_type_registration',
function( PaymentMethodRegistry $payment_method_registry ) {
$payment_method_registry->register( new MyPaymentMethod );
}
);
}
}
```
As an example, you can see how the Stripe extension adds it's integration in this [pull request](https://github.com/woocommerce/woocommerce-gateway-stripe/pull/1467/files).

View File

@ -0,0 +1,37 @@
---
post_title: Cart and Checkout - DOM events
menu_title: DOM Events
tags: reference
---
Some blocks need to react to certain events in order to display the most up to date data or behave in a certain way. That's the case of the Cart block, for example, that must listen to 'add to cart' events in order to update the cart contents; or the Mini-Cart block, that gets opened every time a product is added to the cart.
## WooCommerce core events in WooCommerce Blocks
WooCommerce core uses jQuery events to trigger and listen to certain events, like when a product is added or removed from the cart. In WooCommerce Blocks, we moved away from using jQuery, but we still need to listen to those events. To achieve that, we have a utility named [`translatejQueryEventToNative()`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/3f7c3e517d7bf13008a22d0c2eb89434a9c35ae7/assets/js/base/utils/legacy-events.ts#L79-L106) that listens to those jQuery events, and every time one is triggered, it triggers an associated DOM native event (with the `wc-blocks_` prefix).
## WooCommerce Blocks events
### `wc-blocks_adding_to_cart`
This event is the equivalent to the jQuery event `adding_to_cart` triggered by WooCommerce core. It indicates that the process of adding a product to the cart was sent to the server, but there is still no indication on whether the product was successfully added or not.
_Example usage in WC Blocks:_ Mini-Cart block listens to this event to append its dependencies.
### `wc-blocks_added_to_cart`
This event is the equivalent to the jQuery event `added_to_cart` triggered by WooCommerce core. It indicates that the process of adding a product to the cart has finished with success.
_Example usage in WC Blocks:_ Cart and Mini-Cart blocks (via the `useStoreCart()` hook) listen to this event to know if they need to update their contents.
#### `detail` parameters
| Parameter | Type | Default value | Description |
| ------------------ | ------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `preserveCartData` | boolean | `false` | Whether Cart data in the store should be preserved. By default, it's `false` so any `wc-blocks_added_to_cart` event will invalidate cart data and blocks listening to it will refetch cart data again. However, if the code triggering the event already updates the store (ie: All Products block), it can set `preserveCartData: true` to avoid the other blocks refetching the data again. |
### `wc-blocks_removed_from_cart`
This event is the equivalent to the jQuery event `removed_from_cart` triggered by WooCommerce core. It indicates that a product has been removed from the cart.
_Example usage in WC Blocks:_ Cart and Mini-Cart blocks (via the `useStoreCart()` hook) listen to this event to know if they need to update their contents.

View File

@ -0,0 +1,8 @@
---
category_title: Hooks
category_slug: cart-and-checkout-hooks
post_title: Cart and Checkout - Hooks
---

View File

@ -0,0 +1,50 @@
---
post_title: Cart and Checkout - Legacy hooks
menu_title: Legacy Hooks
tags: reference
---
Below are the hooks that exist in WooCommerce core and that were brough over to WooCommerce Blocks.
Please note that the actions and filters here run on the server side. The client-side blocks won't necessarily change based on a callback added to a server side hook. [Please see our documentation relating to APIs for manipulating the blocks on the client-side](./an-introduction-to-extensiblity-in-woocommerce-blocks/).
## Legacy Filters
- [loop_shop_per_page](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#loop_shop_per_page)
- [wc_session_expiration](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#wc_session_expiration)
- [woocommerce_add_cart_item](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_cart_item)
- [woocommerce_add_cart_item_data](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_cart_item_data)
- [woocommerce_add_to_cart_quantity](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_quantity)
- [woocommerce_add_to_cart_sold_individually_quantity](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_sold_individually_quantity)
- [woocommerce_add_to_cart_validation](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_add_to_cart_validation)
- [woocommerce_adjust_non_base_location_prices](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_adjust_non_base_location_prices)
- [woocommerce_apply_base_tax_for_local_pickup](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_apply_base_tax_for_local_pickup)
- [woocommerce_apply_individual_use_coupon](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_apply_individual_use_coupon)
- [woocommerce_apply_with_individual_use_coupon](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_apply_with_individual_use_coupon)
- [woocommerce_cart_contents_changed](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_cart_contents_changed)
- [woocommerce_cart_item_permalink](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_cart_item_permalink)
- [woocommerce_get_item_data](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_get_item_data)
- [woocommerce_loop_add_to_cart_args](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_loop_add_to_cart_args)
- [woocommerce_loop_add_to_cart_link](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_loop_add_to_cart_link)
- [woocommerce_new_customer_data](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_new_customer_data)
- [woocommerce_pay_order_product_has_enough_stock](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_pay_order_product_has_enough_stock)
- [woocommerce_pay_order_product_in_stock](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_pay_order_product_in_stock)
- [woocommerce_registration_errors](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_registration_errors)
- [woocommerce_shipping_package_name](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_shipping_package_name)
- [woocommerce_show_page_title](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_show_page_title)
- [woocommerce_single_product_image_thumbnail_html](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md#woocommerce_single_product_image_thumbnail_html)
## Legacy Actions
- [woocommerce_add_to_cart](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_add_to_cart)
- [woocommerce_after_main_content](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_after_main_content)
- [woocommerce_after_shop_loop](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_after_shop_loop)
- [woocommerce_applied_coupon](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_applied_coupon)
- [woocommerce_archive_description](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_archive_description)
- [woocommerce_before_main_content](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_before_main_content)
- [woocommerce_before_shop_loop](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_before_shop_loop)
- [woocommerce_check_cart_items](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_check_cart_items)
- [woocommerce_created_customer](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_created_customer)
- [woocommerce_no_products_found](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_no_products_found)
- [woocommerce_register_post](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_register_post)
- [woocommerce_shop_loop](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md#woocommerce_shop_loop)

View File

@ -0,0 +1,142 @@
---
post_title: Cart and Checkout - How the checkout block processes an order
menu_title: Processing an Order
tags: reference
---
This document will shed some light on the inner workings of the Checkout flow. More specifically, what happens after a user hits the "Place Order" button.
## Structure
The following areas are associated with processing the checkout for a user.
### The Payment Registry [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/blocks-registry/payment-methods/registry.ts#L1)
The payment registry stores all the configuration information for each payment method. We can register a new payment method here with the `registerPaymentMethod` and `registerExpressPaymentMethod `functions, also available to other plugins.
### Data Stores
Data stores are used to keep track of data that is likely to change during a user's session, such as the active payment method, whether the checkout has an error, etc. We split these data stores by areas of concern, so we have 2 data stores related to the checkout: `wc/store/checkout` [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/index.ts#L1) and `wc/store/payment` [(file)](https://href.li/?https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/index.ts#L1) . Data stores live in the `assets/js/data` folder.
### Contexts
Contexts are used to make data available to the Checkout block. Each of these provide data and functions related to a specific area of concern, via the use of a hook. For example, if we wanted to use the `onPaymentSetup` handler from the `PaymentEventsContext` context, we can do it like this:
```js
const { onPaymentSetup } = usePaymentEventsContext();
```
The other job of contexts is to run side effects for our Checkout block. What typically happens is that the `CheckoutEvents` and `PaymentEvents` will listen for changes in the checkout and payment data stores, and dispatch actions on those stores based on some logic.
For example, in the `CheckoutEvents` context, we dispatch the `emitValidateEvent` action when the checkout status is `before_processing`. There is a lot of similar logic that reacts to changes in status and other state data from these two stores.
The Checkout contexts are:
| Context | Description |
| ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ---------------------------------------------------- |
| [CheckoutEvents](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx#L4) | Provides some checkout related event handlers |
| [ PaymentEvents ](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/payment-methods/payment-method-events-context.tsx#L3) | Provides event handlers related to payments |
| [ CustomerData ](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/customer/index.tsx#L1) | Provides data related to the current customer |
| [ ShippingData ](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/shipping/index.js#L1) | Provides data and actions related to shipping errors |
### The Checkout Processor (checkout-processor.js)
The checkout processor component subscribes to changes in the checkout or payment data stores, packages up some of this data and calls the StoreApi `/checkout` endpoint when the conditions are right.
## The Checkout Provider
The [checkout provider](https://github.com/woocommerce/woocommerce-blocks/blob/trunk/assets/js/base/context/providers/cart-checkout/checkout-provider.js), wraps all the contexts mentioned above around the `CheckoutProcessor` component.
---
## Checkout User Flow
Below is the complete checkout flow
### 1\. Click the "Place Order" button
The checkout process starts when a user clicks the button
### 2\. Checkout status is set to `before_processing` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx#L167)
As soon as the user clicks the "Place Order" button, we change the checkout status to _"before_processing"_. This is where we handle the validation of the checkout information.
### 3\. Emit the `checkout_validation_before_processing` event [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/checkout-events/index.tsx#L113)
This is where the WooCommerce Blocks plugin and other plugins can register event listeners for dealing with validation. The event listeners for this event will run and if there are errors, we set checkout status to `idle` and display the errors to the user.
If there are no errors, we move to step 4 below.
### 4\. Checkout status is set to `processing` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/thunks.ts#L76)
The processing status is used by step 5 below to change the payment status
### 5\. Payment status is set to `processing` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/payment-methods/payment-method-events-context.tsx#L94)
Once all the checkout processing is done and if there are no errors, the payment processing begins
### 6\. Emit the `payment_processing` event [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/thunks.ts#L42)
The `payment_processing` event is emitted. Otherplugins can register event listeners for this event and run their own code.
For example, the Stripe plugin checks the address and payment details here, and uses the stripe APIs to create a customer and payment reference within Stripe.
**Important note: The actual payment is not taken here**. **It acts like a pre-payment hook to run any payment plugin code before the actual payment is attempted.**
### 7\. Execute the `payment_processing` event listeners and set the payment and checkout states accordingly [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/thunks.ts#L54-L132)
If the registered event listeners return errors, we will display this to the user.
If the event listeners are considered successful, we sync up the address of the checkout with the payment address, store the `paymentMethodData` in the payment store, and set the payment status property `{ isProcessing: true }`.
### 8\. POST to `/wc/store/v1/checkout` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/checkout-processor.js#L234)
The `/checkout` StoreApi endpoint is called if there are no payment errors. This will take the final customer addresses and chosen payment method, and any additional payment data, then attempts payment and returns the result.
**Important: payment is attempted through the StoreApi, NOT through the `payment_processing` event that is sent from the client**
### 9\. The `processCheckoutResponse` action is triggered on the checkout store [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/thunks.ts#L33)
Once the fetch to the StoreApi `/checkout` endpoint returns a response, we pass this to the `processCheckoutResponse` action on the `checkout` data store.
It will perform the following actions:
- It sets the redirect url to redirect to once the order is complete
- It stores the payment result in the `checkout` data store.
- It changes the checkout status to `after_processing` (step 10)
### 10\. Checkout status is set to `after_processing` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/thunks.ts#L42)
The `after_processing` status indicates that we've finished the main checkout processing step. In this step, we run cleanup actions and display any errors that have been triggered during the last step.
### 11\. Emit the `checkout_after_processing_with_success` event [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/thunks.ts#L118-L128)
If there are no errors, the `checkout_after_processing_with_success` event is triggered. This is where other plugins can run some code after the checkout process has been successful.
Any event listeners registered on the `checkout_after_processing_with_success` event will be executed. If there are no errors from the event listeners, `setComplete` action is called on the `checkout` data store to set the status to `complete` (step 13). An event listener can also return an error here, which will be displayed to the user.
### 12\. Emit the `checkout_after_processing_with_error` event [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/thunks.ts#L104-L116)
If there has been an error from step 5, the `checkout_after_processing_with_error` event will be emitted. Other plugins can register event listeners to run here to display an error to the user. The event listeners are processed and display any errors to the user.
### 13\. Set checkout status to `complete` [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/utils.ts#L146)
If there are no errors, the `status` property changes to `complete` in the checkout data store. This indicates that the checkout process is complete.
### 14\. Redirect [(file)](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/base/context/providers/cart-checkout/checkout-processor.js#L193-L197)
Once the checkout status is set to `complete`, if there is a `redirectUrl` in the checkout data store, then we redirect the user to the URL.
## Other notable things
### Checking payment methods
A payment method is registered with a [configuration object](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/types/type-defs/payments.ts#L60-L83). It must include a function named `canMakePayment`. This function should return true if the payment method can be used to pay for the current cart. The current cart (items, addresses, shipping methods etc.) is passed to this function, and each payment method is responsible for reporting whether it can be used.
The `checkPaymentMethodsCanPay()` [function](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/check-payment-methods.ts#L26) goes through all the registered payment methods, checks if they can pay, and if so, adds them to the `availablePaymentMethods` property on the payment data store.
The `checkPaymentMethodsCanPay()` [function](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/payment-methods/check-payment-methods.ts#L26) must be called in a few places in order to validate the payment methods before they can be displayed to the user as viable options.
- [Here](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/cart/index.ts#L46-L57), once the cart loads, we want to be able to display express payment methods, so we need to validate them first.
- [Here](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/cart/index.ts#L42-L43), once the cart changes, we may want to enable/disable certain payment methods
- [Here](https://github.com/woocommerce/woocommerce-blocks/blob/4af2c0916a936369be8a4f0044683b90b3af4f0d/assets/js/data/checkout/index.ts#L44-L49), once the checkout loads, we want to verify all registered payment methods

View File

@ -0,0 +1,196 @@
---
post_title: Cart and Checkout - Handling scripts, styles, and data
menu_title: Script, Styles, and Data Handling
tags: how-to
---
## The problem
You are an extension developer, and to allow users to interact with your extension on the client-side, you have written some CSS and JavaScript that you would like to be included on the page. Your JavaScript also relies on some server-side data, and you'd like this to be available to your scripts.
## The solution
You may use the `IntegrationRegistry` to register an `IntegrationInterface` this will be a class that will handle the enqueuing of scripts, styles, and data. You may have a different `IntegrationInterface` for each block (Mini-Cart, Cart and Checkout), or you may use the same one, it is entirely dependent on your use case.
You should use the hooks: `woocommerce_blocks_mini-cart_block_registration`. `woocommerce_blocks_cart_block_registration` and `woocommerce_blocks_checkout_block_registration`. These hooks pass an instance of [`IntegrationRegistry`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/src/Integrations/IntegrationRegistry.php) to the callback.
You may then use the `register` method on this object to register your `IntegrationInterface`.
## `IntegrationInterface` methods
To begin, we'll need to create our integration class, our `IntegrationInterface`. This will be a class that implements WooCommerce Blocks' interface named [`IntegrationInterface`](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/trunk/src/Integrations/IntegrationInterface.php).
In this section, we will step through the interface's members and discuss what they are used for.
### `get_name()`
This is the `IntegrationInterface`'s way of namespacing your integration. The name chosen here should be unique to your extension. This method should return a string.
### `initialize()`
This is where any setup, or initialization for your integration should be placed. For example, you could register the scripts and styles your extension needs here. This method should not return anything.
### `get_script_handles()`
This is where the handles of any scripts you want to be enqueued on the client-side in the frontend context should be placed. This method should return an array of strings.
### `get_editor_script_handles()`
This is where the handles of any scripts you want to be enqueued on the client-side in the editor context should be placed. This method should return an array of strings.
### `get_script_data()`
This is where you can set values you want to be available to your scripts on the frontend. This method should return an associative array, the keys of which will be used to get the data using the JavaScript function `getSetting`.
The keys and values of this array should all be serializable.
## Usage example
Let's suppose we're the author of an extension: `WooCommerce Example Plugin`. We want to enqueue scripts, styles, and data on the frontend when either the Mini-Cart, Cart or Checkout blocks are being used.
We also want some data from a server-side function to be available to our front-end scripts.
You will notice that in the example below, we reference the `/build/index.asset.php` file. This is created by the [`DependencyExtractionWebpackPlugin`](https://www.npmjs.com/package/@wordpress/dependency-extraction-webpack-plugin) which creates a PHP file mapping the dependencies of your client-side scripts, so that they can be added in the `dependencies` array of `wp_register_script`.
Let's create our `IntegrationInterface`.
```php
<?php
use Automattic\WooCommerce\Blocks\Integrations\IntegrationInterface;
/**
* Class for integrating with WooCommerce Blocks
*/
class WooCommerce_Example_Plugin_Integration implements IntegrationInterface {
/**
* The name of the integration.
*
* @return string
*/
public function get_name() {
return 'woocommerce-example-plugin';
}
/**
* When called invokes any initialization/setup for the integration.
*/
public function initialize() {
$script_path = '/build/index.js';
$style_path = '/build/style-index.css';
/**
* The assets linked below should be a path to a file, for the sake of brevity
* we will assume \WooCommerce_Example_Plugin_Assets::$plugin_file is a valid file path
*/
$script_url = plugins_url( $script_path, \WooCommerce_Example_Plugin_Assets::$plugin_file );
$style_url = plugins_url( $style_path, \WooCommerce_Example_Plugin_Assets::$plugin_file );
$script_asset_path = dirname( \WooCommerce_Example_Plugin_Assets::$plugin_file ) . '/build/index.asset.php';
$script_asset = file_exists( $script_asset_path )
? require $script_asset_path
: array(
'dependencies' => array(),
'version' => $this->get_file_version( $script_path ),
);
wp_enqueue_style(
'wc-blocks-integration',
$style_url,
[],
$this->get_file_version( $style_path )
);
wp_register_script(
'wc-blocks-integration',
$script_url,
$script_asset['dependencies'],
$script_asset['version'],
true
);
wp_set_script_translations(
'wc-blocks-integration',
'woocommerce-example-plugin',
dirname( \WooCommerce_Example_Plugin_Assets::$plugin_file ) . '/languages'
);
}
/**
* Returns an array of script handles to enqueue in the frontend context.
*
* @return string[]
*/
public function get_script_handles() {
return array( 'wc-blocks-integration' );
}
/**
* Returns an array of script handles to enqueue in the editor context.
*
* @return string[]
*/
public function get_editor_script_handles() {
return array( 'wc-blocks-integration' );
}
/**
* An array of key, value pairs of data made available to the block on the client side.
*
* @return array
*/
public function get_script_data() {
$woocommerce_example_plugin_data = some_expensive_serverside_function();
return [
'expensive_data_calculation' => $woocommerce_example_plugin_data
];
}
/**
* Get the file modified time as a cache buster if we're in dev mode.
*
* @param string $file Local path to the file.
* @return string The cache buster value to use for the given file.
*/
protected function get_file_version( $file ) {
if ( defined( 'SCRIPT_DEBUG' ) && SCRIPT_DEBUG && file_exists( $file ) ) {
return filemtime( $file );
}
// As above, let's assume that WooCommerce_Example_Plugin_Assets::VERSION resolves to some versioning number our
// extension uses.
return \WooCommerce_Example_Plugin_Assets::VERSION;
}
}
```
As mentioned, we will need register our `IntegrationInterface` with WooCommerce Blocks, as we want our scripts to be included when either the Mini-Cart, Cart or Checkout is used, we need to register callbacks for three actions.
```php
add_action(
'woocommerce_blocks_mini-cart_block_registration',
function( $integration_registry ) {
$integration_registry->register( new WooCommerce_Example_Plugin_Integration() );
}
);
add_action(
'woocommerce_blocks_cart_block_registration',
function( $integration_registry ) {
$integration_registry->register( new WooCommerce_Example_Plugin_Integration() );
}
);
add_action(
'woocommerce_blocks_checkout_block_registration',
function( $integration_registry ) {
$integration_registry->register( new WooCommerce_Example_Plugin_Integration() );
}
);
```
Now, when we load a page containing either block, we should see the scripts we registered in `initialize` being loaded!
### Getting data added in `get_script_data`
We associated some data with the extension in the `get_script_data` method of our interface, we need to know how to get this!
In the `@woocommerce/settings` package there is a method you can import called `getSetting`. This method accepts a string. The name of the setting containing the data added in `get_script_data` is the name of your integration (i.e. the value returned by `get_name`) suffixed with `_data`. In our example it would be: `woocommerce-example-plugin_data`.
The value returned here is a plain old JavaScript object, keyed by the keys of the array returned by `get_script_data`, the values will serialized.

View File

@ -0,0 +1,60 @@
---
post_title: Cart and Checkout - Slot and fill
menu_title: Slot and Fill
tags: reference
---
## The problem
You added custom data to the [Store API](https://github.com/woocommerce/woocommerce/blob/1675c63bba94c59703f57c7ef06e7deff8fd6bba/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md). You changed several strings using [Checkout filters](./category/cart-and-checkout-blocks/available-filters/). Now you want to render your own components in specific places in the Cart and Checkout.
## Solution
Slot and Fill are a pair of components that add the possibility to render your own HTML in pre-defined places in the Cart and Checkout. Your component will get access to contextual data and will get re-rendered when needed.
A _Slot_ is a place in the Cart and Checkout that can render an indefinite number of external components.
A _Fill_ is the component provided by third-party developers to render inside a _Slot_.
Slot and Fill use WordPress' API, and you can learn more about how they work in [the Slot and Fill documentation.](https://github.com/WordPress/gutenberg/tree/trunk/packages/components/src/slot-fill).
## Basic Usage
`ExperimentalOrderMeta` is a fill that will render in a slot below the Order summary section in the Cart and Checkout blocks.
The `ExperimentalOrderMeta` will automatically pass props to its top level child:
- `cart` which contains cart data
- `extensions` which contains data registered with `ExtendSchema::class` in `wc/store/cart` endpoint
- `context`, equal to the name of the Block in which the fill is rendered: `woocommerce/cart` or `woocommerce/checkout`
```jsx
const { registerPlugin } = wp.plugins;
const { ExperimentalOrderMeta } = wc.blocksCheckout;
const MyCustomComponent = ( { cart, extensions } ) => {
return &lt;div className="my-component"&gt;Hello WooCommerce&lt;/div&gt;;
};
const render = () => {
return (
&lt;ExperimentalOrderMeta&gt;
&lt;MyCustomComponent /&gt;
&lt;/ExperimentalOrderMeta&gt;
);
};
registerPlugin( 'my-plugin-namespace', {
render,
scope: 'woocommerce-checkout',
} );
```
## registerPlugin
In the above example, we're using `registerPlugin`. This plugin will take our component and render it, but it won't make it visible. The SlotFill part is the one responsible for actually having it show up in the correct place.
You use `registerPlugin` to feed in your plugin namespace, your component `render`, and the scope of your `registerPlugin`. The value of scope should always be `woocommerce-checkout`.
## Requirements
For this to work, your script must be enqueued after Cart and Checkout. You can follow the [IntegrationInterface](https://github.com/woocommerce/woocommerce-gutenberg-products-block/blob/50f9b3e8d012f425d318908cc13d9c601d97bd68/docs/extensibility/integration-interface.md) documentation for enqueueing your script.

View File

@ -14,17 +14,17 @@ if ( ! function_exists( 'YOUR_PREFIX_login_message' ) ) {
*/
function YOUR_PREFIX_login_message() {
if ( get_option( 'woocommerce_enable_myaccount_registration' ) == 'yes' ) {
?>
<div class="woocommerce-info">
<p><?php _e( 'Returning customers login. New users register for next time so you can:', 'YOUR-TEXTDOMAIN' ); ?></p>
<ul>
<li><?php _e( 'View your order history', 'YOUR-TEXTDOMAIN' ); ?></li>
<li><?php _e( 'Check on your orders', 'YOUR-TEXTDOMAIN' ); ?></li>
<li><?php _e( 'Edit your addresses', 'YOUR-TEXTDOMAIN' ); ?></li>
<li><?php _e( 'Change your password', 'YOUR-TEXTDOMAIN' ); ?></li>
</ul>
</div>
<?php
?&gt;
&lt;div class="woocommerce-info"&gt;
&lt;p&gt;&lt;?php _e( 'Returning customers login. New users register for next time so you can:', 'YOUR-TEXTDOMAIN' ); ?&gt;&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;?php _e( 'View your order history', 'YOUR-TEXTDOMAIN' ); ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php _e( 'Check on your orders', 'YOUR-TEXTDOMAIN' ); ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php _e( 'Edit your addresses', 'YOUR-TEXTDOMAIN' ); ?&gt;&lt;/li&gt;
&lt;li&gt;&lt;?php _e( 'Change your password', 'YOUR-TEXTDOMAIN' ); ?&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;/div&gt;
&lt;?php
}
}
add_action( 'woocommerce_before_customer_login_form', 'YOUR_PREFIX_login_message' );

View File

@ -5,8 +5,6 @@ tags: payment-methods
current wccom url: https://woocommerce.com/document/check-if-payment-gateway-supports-refunds-subscriptions-preorders/
---
# Check if a Payment Method Support Refunds, Subscriptions or Pre-orders
If a payment method's documentation doesnt clearly outline the supported features, you can often find what features are supported by looking at payment methods code.
Payment methods can add support for certain features from WooCommerce and its extensions. For example, a payment method can support refunds, subscriptions or pre-orders functionality.
@ -41,4 +39,4 @@ class WC_Gateway_Simplify_Commerce extends WC_Payment_Gateway {
);
```
If you dont find `$this->supports` in the plugin files, that may mean that the payment method isnt correctly declaring support for refunds, subscripts or pre-orders.
If you don't find `$this->supports` in the plugin files, that may mean that the payment method isn't correctly declaring support for refunds, subscripts or pre-orders.

View File

@ -5,15 +5,11 @@ tags: code-snippet, tax
current wccom url: https://woocommerce.com/document/setting-up-taxes-in-woocommerce/configuring-specific-tax-setups-in-woocommerce/#configuring-special-tax-setups
---
# Code snippets for configuring special tax scenarios
## Scenario A: Charge the same price regardless of location and taxes
Scenario A: Charge the same price regardless of location and taxes
If a store enters product prices including taxes, but levies various location-based tax rates, the prices will appear to change depending on which tax rate is applied. In reality, the base price remains the same, but the taxes influence the total. [Follow this link for a detailed explanation](https://woocommerce.com/document/how-taxes-work-in-woocommerce/#cross-border-taxes).
Some merchants prefer to dynamically change product base prices to account for the changes in taxes and so keep the total price consistent regardless of tax rate. Enable that functionality by adding the following snippet to your child themes functions.php file or via a code snippet plugin.
Some merchants prefer to dynamically change product base prices to account for the changes in taxes and so keep the total price consistent regardless of tax rate. Enable that functionality by adding the following snippet to your child theme's functions.php file or via a code snippet plugin.
```php
<?php
@ -23,7 +19,7 @@ add_filter( 'woocommerce_adjust_non_base_location_prices', '__return_false' );
## Scenario B: Charge tax based on the subtotal amount
The following snippet is useful in case where a store only ads taxes when the subtotal reaches a specified minimum. In the code snippet below that minimum is 110 of the stores currency. Adjust the snippet according to your requirements.
The following snippet is useful in case where a store only ads taxes when the subtotal reaches a specified minimum. In the code snippet below that minimum is 110 of the store's currency. Adjust the snippet according to your requirements.
```php
<?php
@ -42,7 +38,7 @@ function big_apple_get_tax_class( $tax_class, $product ) {
Some merchants may require different tax rates to be applied based on a customer role to accommodate for wholesale status or tax exemption.
To enable this functionality, add the following snippet to your child themes functions.php file or via a code snippet plugin. In this snippet, users with “administrator” capabilities will be assigned the **Zero rate tax class**. Adjust it according to your requirements.
To enable this functionality, add the following snippet to your child theme's functions.php file or via a code snippet plugin. In this snippet, users with "administrator" capabilities will be assigned the **Zero rate tax class**. Adjust it according to your requirements.
```php
<?php
@ -62,7 +58,7 @@ add_filter( 'woocommerce_product_variation_get_tax_class', 'wc_diff_rate_for_use
## Scenario D: Show 0 value taxes
Taxes that have 0-value are hidden by default. To show them regardless, add the following snippet to your themes functions.php file or via a code snippet plugins:
Taxes that have 0-value are hidden by default. To show them regardless, add the following snippet to your theme's functions.php file or via a code snippet plugins:
```php
add_filter( 'woocommerce_order_hide_zero_taxes', '__return_false' );
@ -70,7 +66,7 @@ add_filter( 'woocommerce_order_hide_zero_taxes', '__return_false' );
## Scenario E: Suffixes on the main variable product
One of the tax settings for WooCommerce enables the use of suffixes to add additional information to product prices. Its available for use with the variations of a variable product, but is disabled at the main variation level as it can impact website performance when there are many variations.
One of the tax settings for WooCommerce enables the use of suffixes to add additional information to product prices. It's available for use with the variations of a variable product, but is disabled at the main variation level as it can impact website performance when there are many variations.
The method responsible for the related price output can be customized via filter hooks if needed for variable products. This will require customization that can be implemented via this filter:

Binary file not shown.

After

Width:  |  Height:  |  Size: 189 KiB

View File

@ -295,7 +295,7 @@ function custom_override_checkout_fields( $fields ) {
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'. esc_html__( 'Phone From Checkout Form' ) . ':</strong> ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '</p>';
echo '&lt;p&gt;&lt;strong&gt;'. esc_html__( 'Phone From Checkout Form' ) . ':&lt;/strong&gt; ' . esc_html( $order->get_meta( '_shipping_phone', true ) ) . '&lt;/p&gt;';
}
```
@ -317,7 +317,7 @@ add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
echo '<div id="my_custom_checkout_field"><h2>' . esc_html__( 'My Field' ) . '</h2>';
echo '&lt;div id="my_custom_checkout_field"&gt;&lt;h2&gt;' . esc_html__( 'My Field' ) . '&lt;/h2&gt;';
woocommerce_form_field(
'my_field_name',
@ -330,7 +330,7 @@ function my_custom_checkout_field( $checkout ) {
$checkout->get_value( 'my_field_name' )
);
echo '</div>';
echo '&lt;/div&gt;';
}
```
@ -387,7 +387,7 @@ If you wish to display the custom field value on the admin order edition page, y
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta( $order ){
echo '<p><strong>' . esc_html__( 'My Field' ) . ':</strong> ' . esc_html( $order->get_meta( 'My Field', true ) ) . '</p>';
echo '&lt;p&gt;&lt;strong&gt;' . esc_html__( 'My Field' ) . ':&lt;/strong&gt; ' . esc_html( $order->get_meta( 'My Field', true ) ) . '&lt;/p&gt;';
}
```

View File

@ -4,10 +4,13 @@ menu_title: Disabling marketplace suggestions
current wccom url: https://woocommerce.com/document/woocommerce-marketplace-suggestions-settings/#section-6
---
## Disabling Marketplace Suggestions Programmatically
For those who prefer to programmatically disable marketplace suggestions that are fetched from woocommerce.com, add the `woocommerce_allow_marketplace_suggestions` filter to your themes `functions.php` or a custom plugin.
For example:
```php
add_filter( 'woocommerce_allow_marketplace_suggestions', '__return_false' );
```
This filter will completely remove Marketplace Suggestions from your WooCommerce admin.

View File

@ -33,7 +33,7 @@ function woocommerce_custom_field_example() {
$custom_field_value = get_post_meta( $product->get_id(), 'woo_custom_field', true );
if ( ! empty( $custom_field_value ) ) {
echo '<div class="custom-field">' . esc_html( $custom_field_value ) . '</div>';
echo '&lt;div class="custom-field"&gt;' . esc_html( $custom_field_value ) . '&lt;/div&gt;';
}
}

View File

@ -18,7 +18,7 @@ The functionality to hide all other methods, and only show Free Shipping, requir
Before adding snippets, clear your WooCommerce cache. Go to WooCommerce > System Status > Tools > WooCommerce Transients > Clear transients.
Add this code to your child themes `functions.php`, or via a plugin that allows custom functions to be added. Please dont add custom code directly to a parent themes `functions.php` as changes are entirely erased when a parent theme updates.
Add this code to your child theme's `functions.php`, or via a plugin that allows custom functions to be added. Please don't add custom code directly to a parent theme's `functions.php` as changes are entirely erased when a parent theme updates.
## Code Snippets
@ -34,7 +34,7 @@ This means you can use `add_filter()` on `woocommerce_shipping_free_shipping_is_
### How do I only show Free Shipping?
The following snippet hides everything but `free_shipping`, if its available and the customer's cart qualifies.
The following snippet hides everything but `free_shipping`, if it's available and the customer's cart qualifies.
```php
/**
@ -59,7 +59,7 @@ add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_availabl
### How do I only show Local Pickup and Free Shipping?
The snippet below hides everything but `free_shipping` and `local_pickup`, if its available and the customer's cart qualifies.
The snippet below hides everything but `free_shipping` and `local_pickup`, if it's available and the customer's cart qualifies.
```php

View File

@ -1,15 +1,13 @@
---
post_title: Legacy Local Pickup Advanced Settings and Customization
post_title: Advanced settings and customization for legacy Local Pickup
tags: code-snippet
current wccom url: https://woocommerce.com/document/local-pickup/#advanced-settings-customization
note: Docs links out to Skyverge's site for howto add a custom email - do we have our own alternative?
---
# Advanced settings and customization for legacy Local Pickup
## Disable local taxes when using local pickup
Local Pickup calculates taxes based on your stores location (address) by default, and not the customers address. Add this snippet at the end of your theme's `functions.php` to use your standard tax configuration instead:
Local Pickup calculates taxes based on your store's location (address) by default, and not the customer's address. Add this snippet at the end of your theme's `functions.php` to use your standard tax configuration instead:
```php
add_filter( 'woocommerce_apply_base_tax_for_local_pickup', '__return_false' );
@ -19,7 +17,7 @@ Regular taxes is then used when local pickup is selected, instead of store-locat
## Changing the location for local taxes
To charge local taxes based on the postcode and city of the local pickup location, you need to define the shops base city and post code using this example code:
To charge local taxes based on the postcode and city of the local pickup location, you need to define the shop's base city and post code using this example code:
```php
add_filter( 'woocommerce_countries_base_postcode', create_function( '', 'return "80903";' ) );
@ -33,5 +31,5 @@ Update `80903` to reflect your preferred postcode/zip, and `COLORADO SPRINGS` wi
_Shipping Address_ is not displayed on the admin order emails when Local Pickup is used as the shipping method.
Since all core shipping options use the standard order flow, customers receive the same order confirmation email whether they select local pickup or any other shipping option.
Use this guide to create custom emails for local pickup if youd like to send a separate email for local pickup orders: [How to Add a Custom WooCommerce Email](https://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/).
Use this guide to create custom emails for local pickup if you'd like to send a separate email for local pickup orders: [How to Add a Custom WooCommerce Email](https://www.skyverge.com/blog/how-to-add-a-custom-woocommerce-email/).

View File

@ -19,7 +19,7 @@ if ( defined( 'WC_LOG_DIR' ) ) {
$log_url = add_query_arg( 'log_file', $log_key, $log_url );
// Add a link to the logs to the label
$label .= ' | ' . sprintf( \_\_( '%1$sView Log%2$s', 'your-textdomain-here' ), '<a href\="' . esc_url( $log_url ) . '">', '</a\>' );
$label .= ' | ' . sprintf( \_\_( '%1$sView Log%2$s', 'your-textdomain-here' ), '&lt;a href\="' . esc_url( $log_url ) . '"&gt;', '&lt;/a\&gt;' );
}
// Add the logging option to the form fields

View File

@ -5,8 +5,6 @@ tags: code-snippet
current wccom url: https://woocommerce.com/document/woocommerce-localization/#making-your-translation-upgrade-safe
---
# Making your translation upgrade safe
Like all other plugins, WooCommerce keeps translations in `wp-content/languages/plugins`.
However, if you want to include a custom translation, you can add them to `wp-content/languages/woocommerce`, or you can use a snippet to load a custom translation stored elsewhere:

View File

@ -9,7 +9,7 @@ current wccom url: https://woocommerce.com/document/ssl-and-https/#websites-behi
WooCommerce uses the `is_ssl()` WordPress function to verify if your website using SSL or not.
`is_ssl()` checks if the connection is via HTTPS or on Port 443. However, this wont work for websites behind load balancers, especially websites hosted at Network Solutions. For details, read [WordPress is_ssl() function reference notes](https://codex.wordpress.org/Function_Reference/is_ssl#Notes).
`is_ssl()` checks if the connection is via HTTPS or on Port 443. However, this won't work for websites behind load balancers, especially websites hosted at Network Solutions. For details, read [WordPress is_ssl() function reference notes](https://codex.wordpress.org/Function_Reference/is_ssl#Notes).
Websites behind load balancers or reverse proxies that support `HTTP_X_FORWARDED_PROTO` can be fixed by adding the following code to the `wp-config.php` file, above the require_once call:

View File

@ -5,20 +5,18 @@ tags: code-snippet
current wccom url: https://woocommerce.com/document/installing-uninstalling-woocommerce/#uninstalling-woocommerce
---
# Uninstall and remove all WooCommerce Data
The WooCommerce plugin can be uninstalled like any other WordPress plugin. By default, the WooCommerce data is left in place though.
If you need to remove *all* WooCommerce data as well, including products, order data, coupons, etc., you need to to modify the sites `wp-config.php` *before* deactivating and deleting the WooCommerce plugin.
If you need to remove *all* WooCommerce data as well, including products, order data, coupons, etc., you need to to modify the site's `wp-config.php` *before* deactivating and deleting the WooCommerce plugin.
As this action is destructive and permanent, the information is provided as is. WooCommerce Support cannot help with this process or anything that happens as a result.
To fully remove all WooCommerce data from your WordPress site, open `wp-config.php`, scroll down to the bottom of the file, and add the following constant on its own line above `/* Thats all, stop editing. */`.
To fully remove all WooCommerce data from your WordPress site, open `wp-config.php`, scroll down to the bottom of the file, and add the following constant on its own line above `/* That's all, stop editing. */`.
```php
define( 'WC_REMOVE_ALL_DATA', true );
/* Thats all, stop editing! Happy publishing. */
/* That's all, stop editing! Happy publishing. */
```
Then, once the changes are saved to the file, when you deactivate and delete WooCommerce, all of its data is removed from your WordPress site database.

View File

@ -5,8 +5,6 @@ tags: code-snippet
current wccom url: https://woocommerce.com/document/digital-downloadable-product-handling/#protecting-your-uploads-directory
---
## Using NGINX server to protect your upload directory
If you using NGINX server for your site along with **X-Accel-Redirect/X-Sendfile** or **Force Downloads** download method, it is necessary that you add this configuration for better security:
```php

View File

@ -15,7 +15,7 @@ Inside each subfolder you'll find various markdown files. When imported into the
## Getting Setup
> This guide presumes that you're familar with basic Git and GitHub functionality, that you're signed into a GitHub account, and that you have Git setup locally. If you're new to GitHub, we recommend reading their [quickstart](https://docs.github.com/en/get-started/quickstart/hello-world) and [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) guides before getting started.
> This guide presumes that you're familiar with basic Git and GitHub functionality, that you're signed into a GitHub account, and that you have Git setup locally. If you're new to GitHub, we recommend reading their [quickstart](https://docs.github.com/en/get-started/quickstart/hello-world) and [working with forks](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/working-with-forks/fork-a-repo) guides before getting started.
### Initial Setup
@ -33,7 +33,7 @@ Inside each subfolder you'll find various markdown files. When imported into the
6. [Open a pull request](https://docs.github.com/en/pull-requests/collaborating-with-pull-requests/proposing-changes-to-your-work-with-pull-requests/creating-a-pull-request) that merges your branch with the WooCommerce monorepo's trunk branch.
* To do this, when creating the pull request, set the `base repository` to `woocommerce/woocommerce`, the `base` to `trunk`, the `head repository` to `yourgithubusername/woocommerce` and the `compare` to the branch you created (eg: `docs/improve-extension-performance`).
* When creating the pull request, set a descriptive title. Additionally, ensure you fill out the template provided in the description. For purely docs changes, your testing instructions should reference any major changes you think should be checked.
7. The WooCommerce Developer Advocacy team will review your pull request and provide feedback via the comments as neccesary. Once the content is ready, we'll merge it into `trunk` and it'll appear on the Woo Developer Docs site!
7. The WooCommerce Developer Advocacy team will review your pull request and provide feedback via the comments as necessary. Once the content is ready, we'll merge it into `trunk` and it'll appear on the Woo Developer Docs site!
## Creating New Pages
@ -127,3 +127,9 @@ These instructions presume you're currently have your `docs/` branch open and yo
If you are a non-technical contributor who isn't experienced with command line tools, we're still happy to receive your contributions. If you're unable to include an updated manifest, please ensure that you mention this in your pull request's description.
If you're a technical contributor who is able to regenerate the manifest, we request that you do so where possible.
## Caveats
* Emojis are not supported.
* Avoid copy pasting content from editors such as Google docs. For example, quotation-mark characters in these editors may not translate properly when ingested by our plugin.
* You may want to references HTML like content, however, our plugin is set up to strip non-allowlisted HTML elements. You may use an [HTML named references](https://developer.mozilla.org/en-US/docs/Glossary/Character_reference) to create an HTML like tag, by using the less-than (<) and greater-than (>) symbol named references.

View File

@ -16,7 +16,7 @@ The WooCommerce core plugin code can be found in our [monorepo](https://github.c
### Code of Conduct
Contributing to an open source project requires cooperation amongst individuals and organziations all working to make our project a stable and safe place to build and ask questions. Please thoroughly read our [Code of Conduct](https://github.com/woocommerce/woocommerce/blob/trunk/SECURITY.md) to get familiar with our standards and processes.
Contributing to an open source project requires cooperation amongst individuals and organizations all working to make our project a stable and safe place to build and ask questions. Please thoroughly read our [Code of Conduct](https://github.com/woocommerce/woocommerce/blob/trunk/SECURITY.md) to get familiar with our standards and processes.
### Contributor Guidelines

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,64 @@
---
category_title: Extensibility in Blocks
category_slug: extensibility-in-blocks
post_title: Extensibility in blocks
---
These documents are all dealing with extensibility in the various WooCommerce Blocks.
## Imports and dependency extraction
The documentation in this section will use window globals in code examples, for example:
```js
const { registerCheckoutFilters } = window.wc.blocksCheckout;
```
However, if you're using `@woocommerce/dependency-extraction-webpack-plugin` for enhanced dependency management you can instead use ES module syntax:
```js
import { registerCheckoutFilters } from '@woocommerce/blocks-checkout';
```
See <https://www.npmjs.com/package/@woocommerce/dependency-extraction-webpack-plugin> for more information.
## Hooks (actions and filters)
| Document | Description |
| ----------------------------- | ------------------------------------------------------- |
| [Actions](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/actions.md) | Documentation covering action hooks on the server side. |
| [Filters](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/hooks/filters.md) | Documentation covering filter hooks on the server side. |
| [Migrated Hooks](/docs/cart-and-checkout-legacy-hooks/) | Documentation covering the migrated WooCommerce core hooks. |
## REST API
| Document | Description |
| ---------------------------------------------------------------------------------------------- | ------------------------------------------------------------------- |
| [Exposing your data in the Store API.](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-add-data.md) | Explains how you can add additional data to Store API endpoints. |
| [Available endpoints to extend with ExtendSchema](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/available-endpoints-to-extend.md) | A list of all available endpoints to extend. |
| [Available Formatters](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-formatters.md) | Available `Formatters` to format data for use in the Store API. |
| [Updating the cart with the Store API](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/docs/third-party-developers/extensibility/rest-api/extend-rest-api-update-cart.md) | Update the server-side cart following an action from the front-end. |
## Checkout Payment Methods
| Document | Description |
| -------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------- |
| [Checkout Flow and Events](/docs/cart-and-checkout-checkout-flow-and-events/) | All about the checkout flow in the checkout block and the various emitted events that can be subscribed to. |
| [Payment Method Integration](/docs/cart-and-checkout-payment-method-integration-for-the-checkout-block/) | Information about implementing payment methods. |
| [Filtering Payment Methods](/docs/cart-and-checkout-filtering-payment-methods-in-the-checkout-block/) | Information about filtering the payment methods available in the Checkout Block. |
## Checkout Block
In addition to the reference material below, [please see the `block-checkout` package documentation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/packages/checkout/README.md) which is used to extend checkout with Filters, Slot Fills, and Inner Blocks.
| Document | Description |
|--------------------------------------------------------------------------------------------------| ----------------------------------------------------------------------------------------------------------------- |
| [How the Checkout Block processes an order](/docs/cart-and-checkout-how-the-checkout-block-processes-an-order/) | The detailed inner workings of the Checkout Flow. |
| [IntegrationInterface](/docs/cart-and-checkout-handling-scripts-styles-and-data/) | The `IntegrationInterface` class and how to use it to register scripts, styles, and data with WooCommerce Blocks. |
| [Available Filters](/docs/category/cart-and-checkout-blocks/available-filters/) | All about the filters that you may use to change values of certain elements of WooCommerce Blocks. |
| [Slots and Fills](/docs/cart-and-checkout-slot-and-fill/) | Explains Slot Fills and how to use them to render your own components in Cart and Checkout. |
| [Available Slot Fills](/docs/cart-and-checkout-available-slots/) | Available Slots that you can use and their positions in Cart and Checkout. |
| [DOM Events](/docs/cart-and-checkout-dom-events/) | A list of DOM Events used by some blocks to communicate between them and with other parts of WooCommerce. |
| [Filter Registry](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce-blocks/packages/checkout/filter-registry/README.md) | The filter registry allows callbacks to be registered to manipulate certain values. |
| [Additional Checkout Fields](/docs/cart-and-checkout-additional-checkout-fields/) | The filter registry allows callbacks to be registered to manipulate certain values. |

View File

@ -45,8 +45,8 @@ addFilter(
key: 'custom-product',
title: __('Custom product', 'custom-product'),
content: __('Create an awesome custom product.', 'custom-product'),
before: <FolderMultipleIcon />,
after: <Icon icon={chevronRight} />,
before: &lt;FolderMultipleIcon /&gt;,
after: &lt;Icon icon={chevronRight} /&gt;,
onClick: () => {
}
},

View File

@ -7,21 +7,27 @@ tags: reference
When developing for WordPress and WooCommerce, it's important to consider the nature and permanence of your data. This will help you decide the best way to store it. Here's a quick primer:
## Transients
If the data may not always be present (i.e., it expires), use a [transient](https://developer.wordpress.org/apis/handbook/transients/). Transients are a simple and standardized way of storing cached data in the database temporarily by giving it a custom name and a timeframe after which it will expire and be deleted.
## WP Cache
If the data is persistent but not always present, consider using the [WP Cache](https://developer.wordpress.org/reference/classes/wp_object_cache/). The WP Cache functions allow you to cache data that is computationally expensive to regenerate, such as complex query results.
## wp_options Table
If the data is persistent and always present, consider the [wp_options table](https://developer.wordpress.org/apis/handbook/options/). The Options API is a simple and standardized way of storing data in the wp_options table in the WordPress database.
## Post Types
If the data type is an entity with n units, consider a [post type](https://developer.wordpress.org/post_type/). Post types are "types" of content that are stored in the same way, but are easy to distinguish in the code and UI.
## Taxonomies
If the data is a means of sorting/categorizing an entity, consider a [taxonomy](https://developer.wordpress.org/taxonomy/). Taxonomies are a way of grouping things together.
## Logging
Logs should be written to a file using the [WC_Logger](https://woocommerce.com/wc-apidocs/class-WC_Logger.html) class. This is a simple and standardized way of recording events and errors for debugging purposes.
Remember, the best method of data storage depends on the nature of the data and how it will be used in your application.

View File

@ -26,7 +26,7 @@ Setup tasks appear on the WooCommerce Admin home screen and prompt a merchant to
To register your task as an extended task list item, you'll need to start by creating a new PHP class that extends the Task class. This class will define the properties and behavior of your custom task.
```php
<?php
&lt;?php
/**
* Custom task example.
*
@ -113,37 +113,37 @@ import {
} from '@woocommerce/onboarding';
import { registerPlugin } from '@wordpress/plugins';
const Task = ( { onComplete, task, query } ) => {
const Task = ( { onComplete, task, query } ) =&gt; {
// Implement your task UI/feature here.
return <div></div>;
return &lt;div&gt;&lt;/div&gt;;
};
registerPlugin( 'add-task-content', {
render: () => (
<WooOnboardingTask id="my-task">
{ ( { onComplete, query, task } ) => (
<Task onComplete={ onComplete } task={ task } query={ query } />
render: () =&gt; (
&lt;WooOnboardingTask id="my-task"&gt;
{ ( { onComplete, query, task } ) =&gt; (
&lt;Task onComplete={ onComplete } task={ task } query={ query } /&gt;
) }
</WooOnboardingTask>
&lt;/WooOnboardingTask&gt;
),
} );
registerPlugin( 'add-task-list-item', {
scope: 'woocommerce-tasks',
render: () => (
<WooOnboardingTaskListItem id="my-task">
{ ( { defaultTaskItem: DefaultTaskItem } ) => (
render: () =&gt; (
&lt;WooOnboardingTaskListItem id="my-task"&gt;
{ ( { defaultTaskItem: DefaultTaskItem } ) =&gt; (
// Add a custom wrapper around the default task item.
<div
&lt;div
className="woocommerce-custom-tasklist-item"
style={ {
border: '1px solid red',
} }
>
<DefaultTaskItem />
</div>
&gt;
&lt;DefaultTaskItem /&gt;
&lt;/div&gt;
) }
</WooOnboardingTaskListItem>
&lt;/WooOnboardingTaskListItem&gt;
),
} );
```
@ -168,37 +168,37 @@ import { registerPlugin } from '@wordpress/plugins';
Next, we create a [functional component](https://reactjs.org/docs/components-and-props.html) that returns our task card. The intermixed JavaScript/HTML syntax we're using here is called JSX. If you're unfamiliar with it, you can [read more about it in the React docs](https://reactjs.org/docs/introducing-jsx.html).
```js
const Task = ( { onComplete, task } ) => {
const Task = ( { onComplete, task } ) =&gt; {
const { actionTask } = useDispatch( ONBOARDING_STORE_NAME );
const { isActioned } = task;
return (
<Card className="woocommerce-task-card">
<CardBody>
&lt;Card className="woocommerce-task-card"&gt;
&lt;CardBody&gt;
{ __(
"This task's completion status is dependent on being actioned. The action button below will action this task, while the complete button will optimistically complete the task in the task list and redirect back to the task list. Note that in this example, the task must be actioned for completion to persist.",
'plugin-domain'
) }{ ' ' }
<br />
<br />
&lt;br /&gt;
&lt;br /&gt;
{ __( 'Task actioned status: ', 'plugin-domain' ) }{ ' ' }
{ isActioned ? 'actioned' : 'not actioned' }
<br />
<br />
<div>
<button
onClick={ () => {
&lt;br /&gt;
&lt;br /&gt;
&lt;div&gt;
&lt;button
onClick={ () =&gt; {
actionTask( 'my-task' );
} }
>
&gt;
{ __( 'Action task', 'plugin-domain' ) }
</button>
<button onClick={ onComplete }>
&lt;/button&gt;
&lt;button onClick={ onComplete }&gt;
{ __( 'Complete', 'plugin-domain' ) }
</button>
</div>
</CardBody>
</Card>
&lt;/button&gt;
&lt;/div&gt;
&lt;/CardBody&gt;
&lt;/Card&gt;
);
};
```
@ -211,14 +211,14 @@ Next, we register the Task component as a plugin named "add-task-content" using
```js
registerPlugin( 'add-task-content', {
render: () => (
render: () =&gt; (
{ ( {
onComplete,
// eslint-disable-next-line @typescript-eslint/no-unused-vars
query,
task,
} ) => }
} ) =&gt; }
),
scope: 'woocommerce-tasks',
@ -232,20 +232,20 @@ Finally, we register another plugin named "my-task-list-item-plugin." This plugi
```js
registerPlugin( 'my-task-list-item-plugin', {
scope: 'woocommerce-tasks',
render: () => (
<WooOnboardingTaskListItem id="my-task">
{ ( { defaultTaskItem: DefaultTaskItem } ) => (
render: () =&gt; (
&lt;WooOnboardingTaskListItem id="my-task"&gt;
{ ( { defaultTaskItem: DefaultTaskItem } ) =&gt; (
// Add a custom wrapper around the default task item.
<div
&lt;div
className="woocommerce-custom-tasklist-item"
style={ {
border: '1px solid red',
} }
>
<DefaultTaskItem />
</div>
&gt;
&lt;DefaultTaskItem /&gt;
&lt;/div&gt;
) }
</WooOnboardingTaskListItem>
&lt;/WooOnboardingTaskListItem&gt;
),
} );
```
@ -344,7 +344,7 @@ import { addFilter } from '@wordpress/hooks';
addFilter(
'woocommerce_admin_homescreen_quicklinks',
'my-extension',
( quickLinks ) => {
( quickLinks ) =&gt; {
return [
...quickLinks,
{
@ -374,7 +374,7 @@ Despite being a part of the new React-powered admin experience in WooCommerce, A
The recommended approach for using Admin Notes is to encapsulate your note within its own class that uses the [NoteTraits](https://github.com/woocommerce/woocommerce-admin/blob/831c9ff13a862f22cf53d3ae676daeabbefe90ad/src/Notes/NoteTraits.php) trait included with WooCommerce Admin. Below is a simple example of what this might look like:
```php
<?php
&lt;?php
/**
* Simple note provider
*
@ -423,10 +423,10 @@ class ExampleNote {
$note = new Automattic\WooCommerce\Admin\Notes\Note();
// Set our note's title.
$note->set_title( 'Getting Started' );
$note-&gt;set_title( 'Getting Started' );
// Set our note's content.
$note->set_content(
$note-&gt;set_content(
sprintf(
'Extension activated on %s.', $activated_time_formatted
)
@ -436,41 +436,41 @@ class ExampleNote {
// You can use this property to re-localize notes on the fly, but
// that is just one use. You can store other data here too. This
// is backed by a longtext column in the database.
$note->set_content_data( (object) array(
'getting_started' => true,
'activated' => $activated_time,
'activated_formatted' => $activated_time_formatted
$note-&gt;set_content_data( (object) array(
'getting_started' =&gt; true,
'activated' =&gt; $activated_time,
'activated_formatted' =&gt; $activated_time_formatted
) );
// Set the type of the note. Note types are defined as enum-style
// constants in the Note class. Available note types are:
// error, warning, update, info, marketing.
$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
$note-&gt;set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );
// Set the type of layout the note uses. Supported layout types are:
// 'banner', 'plain', 'thumbnail'
$note->set_layout( 'plain' );
// 'plain', 'thumbnail'
$note-&gt;set_layout( 'plain' );
// Set the image for the note. This property renders as the src
// attribute for an img tag, so use a string here.
$note->set_image( '' );
$note-&gt;set_image( '' );
// Set the note name and source. You should store your extension's
// name (slug) in the source property of the note. You can use
// the name property of the note to support multiple sub-types of
// notes. This also gives you a handy way of namespacing your notes.
$note->set_source( 'inbox-note-example');
$note->set_name( self::NOTE_NAME );
$note-&gt;set_source( 'inbox-note-example');
$note-&gt;set_name( self::NOTE_NAME );
// Add action buttons to the note. A note can support 0, 1, or 2 actions.
// The first parameter is the action name, which can be used for event handling.
// The second parameter renders as the label for the button.
// The third parameter is an optional URL for actions that require navigation.
$note->add_action(
$note-&gt;add_action(
'settings', 'Open Settings', '?page=wc-settings&tab=general'
);
$note->add_action(
$note-&gt;add_action(
'learn_more', 'Learn More', 'https://example.com'
);
@ -559,12 +559,12 @@ Next, we'll instantiate a new `Note` object.
Once we have an instance of the Note class, we can work with its API to set its properties, starting with its title.
`$note->set_title( 'Getting Started' );`
`$note-&gt;set_title( 'Getting Started' );`
Then we'll use some of the timestamp data we collected above to set the note's content.
```php
$note->set_content(
$note-&gt;set_content(
sprintf(
'Extension activated on %s.', $activated_time_formatted
)
@ -574,41 +574,41 @@ $note->set_content(
In addition to regular content, notes also support structured content using the `content_data` property. You can use this property to re-localize notes on the fly, but that is just one use case. You can store other data here too. This is backed by a `longtext` column in the database.
```php
$note->set_content_data( (object) array(
'getting_started' => true,
'activated' => $activated_time,
'activated_formatted' => $activated_time_formatted
$note-&gt;set_content_data( (object) array(
'getting_started' =&gt; true,
'activated' =&gt; $activated_time,
'activated_formatted' =&gt; $activated_time_formatted
) );
```
Next, we'll set the note's `type` property. Note types are defined as enum-style class constants in the `Note` class. Available note types are _error_, _warning_, _update_, _info_, and _marketing_. When selecting a note type, be aware that the _error_ and _update_ result in the note being shown as a Store Alert, not in the Inbox. It's best to avoid using these types of notes unless you absolutely need to.
`$note->set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );`
`$note-&gt;set_type( Note::E_WC_ADMIN_NOTE_INFORMATIONAL );`
Admin Notes also support a few different layouts. You can specify `banner`, `plain`, or `thumbnail` as the layout. If you're interested in seeing the different layouts in action, take a look at [this simple plugin](https://gist.github.com/octaedro/864315edaf9c6a2a6de71d297be1ed88) that you can install to experiment with them.
We'll choose `plain` as our layout, but it's also the default, so we could leave this property alone and the effect would be the same.
`$note->set_layout( 'plain' );`
`$note-&gt;set_layout( 'plain' );`
If you have an image that you want to add to your Admin Note, you can specify it using the `set_image` function. This property ultimately renders as the `src` attribute on an `img` tag, so use a string here.
`$note->set_image( '' );`
`$note-&gt;set_image( '' );`
Next, we'll set the values for our Admin Note's `name` and `source` properties. As a best practice, you should store your extension's name (i.e. its slug) in the `source` property of the note. You can use the `name` property to support multiple sub-types of notes. This gives you a handy way of namespacing your notes and managing them at both a high and low level.
```php
$note->set_source( 'inbox-note-example');
$note->set_name( self::NOTE_NAME );
$note-&gt;set_source( 'inbox-note-example');
$note-&gt;set_name( self::NOTE_NAME );
```
Admin Notes can support 0, 1, or 2 actions (buttons). You can use these actions to capture events that trigger asynchronous processes or help the merchant navigate to a particular view to complete a step, or even simply to provide an external link for further information. The `add_action()` function takes up to three arguments. The first is the action name, which can be used for event handling, the second renders as a label for the action's button, and the third is an optional URL for actions that require navigation.
```php
$note->add_action(
$note-&gt;add_action(
'settings', 'Open Settings', '?page=wc-settings&tab=general'
);
$note->add_action(
$note-&gt;add_action(
'learn_more', 'Learn More', 'https://example.com'
);
```

View File

@ -227,19 +227,19 @@ public function generate_button_html( $key, $data ) {
ob_start();
?>
<tr valign="top">
<th scope="row" class="titledesc">
<label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?></label>
&lt;tr valign="top"&gt;
&lt;th scope="row" class="titledesc"&gt;
&lt;label for="<?php echo esc_attr( $field ); ?>"><?php echo wp_kses_post( $data['title'] ); ?>&lt;/label&gt;
<?php echo $this->get_tooltip_html( $data ); ?>
</th>
<td class="forminp">
<fieldset>
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
<button class="<?php echo esc_attr( $data['class'] ); ?>" type="button" name="<?php echo esc_attr( $field ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php echo $this->get_custom_attribute_html( $data ); ?>><?php echo wp_kses_post( $data['title'] ); ?></button>
&lt;/th&gt;
&lt;td class="forminp"&gt;
&lt;fieldset&lt;
&lt;legend class="screen-reader-text"&gt;&lt;span&gt;<?php echo wp_kses_post( $data['title'] ); ?&gt;&lt;/span&gt;&lt;/legend&gt;
&lt;button class="<?php echo esc_attr( $data['class'] ); ?>" type="button" name="<?php echo esc_attr( $field ); ?>" id="<?php echo esc_attr( $field ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php echo $this->get_custom_attribute_html( $data ); ?>&gt;<?php echo wp_kses_post( $data['title'] ); ?>&lt;/button&gt;
<?php echo $this->get_description_html( $data ); ?>
</fieldset>
</td>
</tr>
&lt;/fieldset&gt;
&lt;/td&gt;
&lt;/tr&gt;
<?php
return ob_get_clean();
}

View File

@ -3,7 +3,7 @@ post_title: Integrating with coming soon mode
tags: how-to, coming-soon
---
This guide provides examples for third-party developers and hosting providers on how to integrate their systems with WooCommerce's coming soon mode. For more details, please read the [developer blog post](https://developer.woocommerce.com/2024/06/18/introducing-coming-soon-mode/).
This guide provides examples for third-party developers and hosting providers on how to integrate their systems with WooCommerce's coming soon mode. For more details, please read the [developer blog post](https://developer.woocommerce.com/2024/06/18/introducing-coming-soon-mode/). For site visibility settings, please refer to the [admin documentation](https://woocommerce.com/document/configuring-woocommerce-settings/coming-soon-mode/).
## Introduction
@ -49,15 +49,15 @@ function sync_coming_soon_to_other_plugins( $old_value, $new_value, $option ) {
$is_enabled = $new_value === 'yes';
// Implement your logic to sync coming soon status.
if ( function_exists( 'set_your_plugin_status' ) ) {
set_your_plugin_status( $is_enabled );
if ( function_exists( 'your_plugin_set_coming_soon' ) ) {
your_plugin_set_coming_soon( $is_enabled );
}
}
```
#### Trigger from other plugins
You can use the following example to enable or disable WooCommerce coming soon mode from another plugin by directy updating `woocommerce_coming_soon` option:
You can use the following example to enable or disable WooCommerce coming soon mode from another plugin by directly updating `woocommerce_coming_soon` option:
```php
function sync_coming_soon_from_other_plugins( $is_enabled ) {
@ -84,8 +84,8 @@ function sync_coming_soon_to_other_plugins( $old_value, $new_value, $option ) {
$is_enabled = $new_value === 'yes';
// Implement your logic to sync coming soon status.
if ( function_exists( 'set_your_plugin_status' ) ) {
set_your_plugin_status( $is_enabled );
if ( function_exists( 'your_plugin_set_coming_soon' ) ) {
your_plugin_set_coming_soon( $is_enabled );
}
}
@ -108,6 +108,38 @@ function sync_coming_soon_from_other_plugins( $is_enabled ) {
}
```
#### One-way binding with option override
We could also programmatically bind the coming soon option from another plugin by overriding the `woocommerce_coming_soon` option. This is advantageous since it simplifies state management and prevents possible out-of-sync issues.
In the following example, we're binding the coming soon option from another plugin by overriding the `woocommerce_coming_soon` option.
```php
add_filter( 'pre_option_woocommerce_coming_soon', 'override_option_woocommerce_coming_soon' );
function override_option_woocommerce_coming_soon( $current_value ) {
// Implement your logic to sync coming soon status.
if ( function_exists( 'your_plugin_is_coming_soon' ) ) {
return your_plugin_is_coming_soon() ? 'yes' : 'no';
}
return $current_value;
}
add_filter( 'pre_update_option_woocommerce_coming_soon', 'override_update_woocommerce_coming_soon', 10, 2 );
function override_update_woocommerce_coming_soon( $new_value, $old_value ) {
// Check user capability.
if ( ! current_user_can( 'manage_options' ) ) {
wp_die( 'You do not have sufficient permissions to access this page.' );
}
// Implement your logic to sync coming soon status.
if ( function_exists( 'your_plugin_set_coming_soon' ) ) {
your_plugin_set_coming_soon( $new_value === 'yes' );
}
}
```
### Custom exclusions filter
It is possible for developers to add custom exclusions that bypass the coming soon protection. This is useful for exclusions like always bypassing the screen on a specific IP address, or making a specific landing page available.
@ -128,9 +160,41 @@ Use the following example to exclude a certain page based on the page's ID. Repl
```php
add_filter( 'woocommerce_coming_soon_exclude', function( $is_excluded ) {
if ( get_the_ID() === <page-id> ) {
if ( get_the_ID() === &lt;page-id&gt; ) {
return true;
}
return $is_excluded;
}, 10 );
```
#### Custom share links
The following example shows how to integrate with a custom share code. We recommend using cookies or other storage to persist the access when users navigate across the site:
```php
add_filter( 'woocommerce_coming_soon_exclude', function( $exclude ) {
// Implement your logic to get and validate share code.
if ( function_exists( 'your_plugin_get_share_code' ) && function_exists( 'your_plugin_is_valid_share_code' ) ) {
$share_code = your_plugin_get_share_code();
if ( your_plugin_is_valid_share_code( $share_code ) ) {
return true;
}
}
return $exclude;
} );
```
### Extend "Apply to store pages only" setting
When using the `Apply to store pages only` setting, you may want to add a custom page to the list of store pages which will be restricted by coming soon mode. You can use the following example to add a custom page:
```php
add_filter( 'woocommerce_store_pages', function( $pages ) {
$page = get_page_by_path( 'your-page-slug' );
if ( $page ) {
$pages[] = $page->ID;
}
return $pages;
} );
```

View File

@ -70,10 +70,10 @@ Create a method called `admin_options` containing the following:
```php
function admin_options() {
?>
<h2><?php esc_html_e( 'Your plugin name', 'your-text-domain' ); ?></h2>
<table class="form-table">
&lt;h2&gt;<?php esc_html_e( 'Your plugin name', 'your-text-domain' ); ?>&lt;/h2&gt;
&lt;table class="form-table"&gt;
<?php $this->generate_settings_html(); ?>
</table>
&lt;/table&gt;
<?php
}
```

View File

@ -48,24 +48,24 @@ Gateways need to use these methods for full 2.1+ compatibility.
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read, Execute, Script" />
<rewrite>
<rules>
<rule name="wordpress" patternSyntax="Wildcard">
<match url="*" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
<&lt;>?xml version="1.0" encoding="UTF-8"?&gt;
&lt;configuration&gt;
&lt;system.webServer&gt;
&lt;handlers accessPolicy="Read, Execute, Script" /&gt;
&lt;rewrite&gt;
&lt;rules&gt;
&lt;rule name="wordpress" patternSyntax="Wildcard"&gt;
&lt;match url="*" /&gt;
&lt;conditions&gt;
&lt;add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /&gt;
&lt;add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /&gt;
&lt;/conditions&gt;
&lt;action type="Rewrite" url="index.php" /&gt;
&lt;/rule&gt;
&lt;/rules&gt;
&lt;/rewrite&gt;
&lt;/system.webServer&gt;
&lt;/configuration&gt;
```
### Pages direct to wrong place
@ -74,6 +74,6 @@ Landing on the wrong page when clicking an endpoint URL is typically caused by i
### How to Remove "Downloads" from My Account
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce → Settings → Advanced → Account endpoints** and clearing the Downloads endpoint field.
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce > Settings > Advanced > Account endpoints** and clearing the Downloads endpoint field.
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)

View File

@ -14,7 +14,7 @@ If you would like to contribute to the WooCommerce core platform; please read ou
## Prerequisites
WooCommerce does adhere to WordPress code standards and guidelines, so its best to familiarize yourself with [WordPress Development](https://learn.wordpress.org/tutorial/introduction-to-wordpress/) as well as [PHP](https://www.php.net/).
WooCommerce does adhere to WordPress code standards and guidelines, so it's best to familiarize yourself with [WordPress Development](https://learn.wordpress.org/tutorial/introduction-to-wordpress/) as well as [PHP](https://www.php.net/).
Knowledge and understanding of [WooCommerce Hooks and Filters](https://woocommerce.com/document/introduction-to-hooks-actions-and-filters/) will allow you to add and change code without editing core files. You can learn more about WordPress hooks and filters in the [WordPress Plugin Development Handbook](https://developer.wordpress.org/plugins/hooks/).
@ -80,22 +80,16 @@ git clone https://github.com/woocommerce/woocommerce.git
cd woocommerce
```
### Activate the required Node version
### Install and Activate the required Node version
```sh
nvm use
Found '/path/to/woocommerce/.nvmrc' with version <v12>
Now using node v12.21.0 (npm v6.14.11)
nvm install
Found '/path/to/woocommerce/.nvmrc' with version <v20>
v20.17.0 is already installed.
Now using node v20.17.0 (npm v10.8.2)
```
Note: if you don't have the required version of Node installed, NVM will alert you so you can install it:
```sh
Found '/path/to/woocommerce/.nvmrc' with version <v12>
N/A: version "v12 -> N/A" is not yet installed.
You need to run "nvm install v12" to install it before using it.
```
Note: if you don't have the required version of Node installed, NVM will install it.
### Install dependencies

View File

@ -18,24 +18,24 @@ For more information, learn how to [Customize Endpoints](./customizing-endpoint-
On Windows servers, the **web.config** file may not be set correctly to allow for the endpoints to work correctly. In this case, clicking on endpoint links (e.g. /edit-account/ or /customer-logout/) may appear to do nothing except refresh the page. In order to resolve this, try simplifying the **web.config** file on your Windows server. Here's a sample file configuration:
```xml
<?xml version="1.0" encoding="UTF-8"?>
<configuration>
<system.webServer>
<handlers accessPolicy="Read, Execute, Script" />
<rewrite>
<rules>
<rule name="wordpress" patternSyntax="Wildcard">
<match url="*" />
<conditions>
<add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" />
<add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" />
</conditions>
<action type="Rewrite" url="index.php" />
</rule>
</rules>
</rewrite>
</system.webServer>
</configuration>
&lt;?xml version="1.0" encoding="UTF-8"?&gt;
&lt;configuration&gt;
&lt;system.webServer&gt;
&lt;handlers accessPolicy="Read, Execute, Script" /&gt;
&lt;rewrite&gt;
&lt;rules&gt;
&lt;rule name="wordpress" patternSyntax="Wildcard"&gt;
&lt;match url="*" /&gt;
&lt;conditions&gt;
&lt;add input="{REQUEST_FILENAME}" matchType="IsFile" negate="true" /&gt;
&lt;add input="{REQUEST_FILENAME}" matchType="IsDirectory" negate="true" /&gt;
&lt;/conditions&gt;
&lt;action type="Rewrite" url="index.php" /&gt;
&lt;/rule&gt;
&lt;/rules&gt;
&lt;/rewrite&gt;
&lt;/system.webServer&gt;
&lt;/configuration&gt;
```
## Pages direct to wrong place
@ -44,6 +44,6 @@ Landing on the wrong page when clicking an endpoint URL is typically caused by i
## How to Remove "Downloads" from My Account
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce → Settings → Advanced → Account endpoints** and clearing the Downloads endpoint field.
Sometimes the "Downloads" endpoint on the "My account" page does not need to be displayed. This can be removed by going to **WooCommerce > Settings > Advanced > Account endpoints** and clearing the Downloads endpoint field.
![Account endpoints](https://developer.woocommerce.com/wp-content/uploads/2023/12/Screenshot-2023-04-09-at-11.45.58-PM.png)

View File

@ -229,7 +229,7 @@ The backfill command can be used to selectively migrate order data (or whole ord
The exact syntax for this command is as follows:
```plaintext
wp wc hpos backfill <order_id> --from=<datastore> --to=<datastore> [--meta_keys=<meta_keys>] [--props=<props>]
wp wc hpos backfill &lt;order_id&gt; --from=&lt;datastore&gt; --to=&lt;datastore&gt; [--meta_keys=&lt;meta_keys&gt;] [--props=&lt;props&gt;]
```
You have to specify which datastore to use as source (either `posts` or `hpos`) and which one to use as destination. The `--meta_keys` and `--props` arguments receive a comma separated list of meta keys and order properties, which can be used to move only certain data from one datastore to the other, instead of the whole order.

View File

@ -87,7 +87,7 @@ Also, we didn't see a noticeable negative performance impact when keeping synchr
### Switch to HPOS as authoritative
It's time to switch to HPOS. Go to **WooCommerce > Settings > Advanced > Features** and set HPOS to be authoritative (select **Use the WooCommerce orders tables**").
It's time to switch to HPOS. Go to **WooCommerce > Settings > Advanced > Features** and set HPOS to be authoritative (select "**Use the WooCommerce orders tables**").
As mentioned above, don't turn off synchronization yet. If there are any issues, the system can be instantaneously reverted to the posts table, resulting in no downtime.
@ -107,7 +107,7 @@ We disable sync on read first because it demands more resources. If your site is
### Switch off sync on write
If everything is working as expected, you can disable sync on write as well. Given sync on read was already disabled, you can disable sync altogether from the settings. As usual, go to **WooCommerce > Settings > Advanced > Features**, and uncheck **Enable compatibility mode"**.
If everything is working as expected, you can disable sync on write as well. Given sync on read was already disabled, you can disable sync altogether from the settings. As usual, go to **WooCommerce > Settings > Advanced > Features**, and uncheck **"Enable compatibility mode"**.
On our high-volume site, we fully disabled sync after 1 week. We still run some manual synchronization (via `wp wc cot sync`) periodically so that we have the opportunity to fall back to posts immediately should anything happen.
@ -118,11 +118,11 @@ Now with synchronization fully disabled, test out various critical flows, check
### Review: Phase 3 Checklist
1. [ ] Plan to be online and monitoring your live site for a period of time.
2. [ ] Enable synchronization with posts set as authoritative: in **WooCommerce > Settings > Advanced > Features** > select **Use the WordPress posts tables**".
2. [ ] Enable synchronization with posts set as authoritative: in **WooCommerce > Settings > Advanced > Features** > select "**Use the WordPress posts tables**".
3. [ ] Start migration via CLI using the `wp wc cot sync` command.
4. [ ] Monitor for errors during migration; halt or resume as necessary.
5. [ ] Verify migrated data integrity using the verify command `wp wc cot verify_cot_data`.
6. [ ] Enable synchronization with HPOS set as authoritative: in **WooCommerce > Settings > Advanced > Features** > select Use the **WooCommerce orders tables**".
6. [ ] Enable synchronization with HPOS set as authoritative: in **WooCommerce > Settings > Advanced > Features** > select "Use the **WooCommerce orders tables**".
7. [ ] Test all critical flows, perform checkouts with multiple payment methods, and verify order data accuracy.
8. [ ] Monitor support tickets for any issues.
9. [ ] Disable synchronization on read using the provided snippet: `add_filter( 'woocommerce_hpos_enable_sync_on_read', '__return_false' );`
@ -137,4 +137,4 @@ Now with synchronization fully disabled, test out various critical flows, check
3. [ ] Regularly communicate with stakeholders regarding testing progress and outcomes.
4. [ ] Plan for potential fallback scenarios, ensuring the ability to revert to posts if issues arise.
Did you follow this guide? Drop us a comment below to let us know how it went. Still have more questions? Reach to us on our dedicated HPOS upgrade channel in the Community Slack: [#hpos-upgrade-party](https://woocommercecommunity.slack.com/archives/C043X91E72M). If you are not yet a member of the Woo Slack Communtiy, you can join [here](https://woocommerce.com/community-slack/).
Did you follow this guide? Drop us a comment below to let us know how it went. Still have more questions? Reach to us on our dedicated HPOS upgrade channel in the Community Slack: [#hpos-upgrade-party](https://woocommercecommunity.slack.com/archives/C043X91E72M). If you are not yet a member of the Woo Slack Community, you can join [here](https://woocommerce.com/community-slack/).

View File

@ -20,7 +20,7 @@ For WooCommerce extensions, performance optimization means ensuring that your co
## Benchmarking Performance
Setting clear performance benchmarks is essential for development and continuous improvement of WooCommerce extensions. A recommended performance standard is achieving a Chrome Core Web Vitals "Performance" score of 90 or above on Woo Express, using tools like the [Chrome Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).
Setting clear performance benchmarks is essential for development and continuous improvement of WooCommerce extensions. A recommended performance standard is achieving a Chrome Core Web Vitals "Performance" score of 90 or above on a simple Woo site, using tools like the [Chrome Lighthouse](https://developer.chrome.com/docs/lighthouse/overview/).
### Using Accessible Tools for Benchmarking

View File

@ -0,0 +1,5 @@
---
category_title: Product Collection Block
category_slug: product-collection
post_title: Product collection block
---

View File

@ -0,0 +1,53 @@
---
post_title: DOM Events sent from product collection block
menu_title: DOM Events
tags: how-to
---
# Product Collection - DOM Events
## `wc-blocks_product_list_rendered`
This event is triggered when Product Collection block was rendered or re-rendered (e.g. due to page change).
### `detail` parameters
| Parameter | Type | Default value | Description |
| ------------------ | ------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collection` | string | `undefined` | Collection type. It's `undefined` for "create your own" collections as the type is not specified. For other Core collections it can be one of type: `woocommerce/product-collection/best-sellers`, `woocommerce/product-collection/featured`, `woocommerce/product-collection/new-arrivals`, `woocommerce/product-collection/on-sale`, `woocommerce/product-collection/top-rated`. For custom collections it will hold their name. |
### Example usage
```javascript
window.document.addEventListener(
'wc-blocks_product_list_rendered',
( e ) => {
const { collection } = e.detail;
console.log( collection ) // -> collection name, e.g. woocommerce/product-collection/on-sale
}
);
```
## Event: `wc-blocks_viewed_product`
This event is triggered when some blocks are clicked in order to view product (redirect to product page).
### `detail` parameters
| Parameter | Type | Default value | Description |
| ------------------ | ------- | ------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `collection` | string | `undefined` | Collection type. It's `undefined` for "create your own" collections as the type is not specified. For other Core collections it can be one of type: `woocommerce/product-collection/best-sellers`, `woocommerce/product-collection/featured`, `woocommerce/product-collection/new-arrivals`, `woocommerce/product-collection/on-sale`, `woocommerce/product-collection/top-rated`. For custom collections it will hold their name. |
| `productId` | number | | Product ID |
### Example usage
```javascript
window.document.addEventListener(
'wc-blocks_viewed_product',
( e ) => {
const { collection, productId } = e.detail;
console.log( collection ) // -> collection name, e.g. "woocommerce/product-collection/featured" or undefined for default one
console.log( productId ) // -> product ID, e.g. 34
}
);
```

View File

@ -0,0 +1,282 @@
---
post_title: Registering custom collections in product collection block
menu_title: Registering custom collections
tags: how-to
---
# Register Product Collection
The `__experimentalRegisterProductCollection` function is part of the `@woocommerce/blocks-registry` package. This function allows third party developers to register a new collection. This function accepts most of the arguments that are accepted by [Block Variation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#defining-a-block-variation).
> [!WARNING]
> It's experimental and may change in the future. Please use it with caution.
**There are two ways to use this function:**
1. Using `@woocommerce/dependency-extraction-webpack-plugin` in a Webpack configuration: This will allow you to import the function from the package & use it in your code. For example:
```tsx
import { __experimentalRegisterProductCollection } from "@woocommerce/blocks-registry";
```
2. Using the global `wc` object: This will allow you to use the function using the global JS object without importing it. For example:
```tsx
wc.wcBlocksRegistry.__experimentalRegisterProductCollection({
...
});
```
> [!TIP]
> The first method is recommended if you are using Webpack.
## Defining a Collection
We will explain important arguments that can be passed to `__experimentalRegisterProductCollection`. For other arguments, you can refer to the [Block Variation](https://developer.wordpress.org/block-editor/reference-guides/block-api/block-variations/#defining-a-block-variation) documentation.
A Collection is defined by an object that can contain the following fields:
- `name` (type `string`): A unique and machine-readable collection name. We recommend using the format `&lt;plugin-name&gt;/product-collection/&lt;collection-name&gt;`. Both `&lt;plugin-name&gt;` and `&lt;collection-name&gt;` should consist only of alphanumeric characters and hyphens (e.g., `my-plugin/product-collection/my-collection`).
- `title` (type `string`): The title of the collection, which will be displayed in various places including the block inserter and collection chooser.
- `description` (optional, type `string`): A human-readable description of the collection.
- `innerBlocks` (optional, type `Array[]`): An array of inner blocks that will be added to the collection. If not provided, the default inner blocks will be used.
- `isDefault`: It's set to `false` for all collections. Third party developers don't need to pass this argument.
- `isActive`: It will be managed by us. Third party developers don't need to pass this argument.
- `usesReference` (optional, type `Array[]`): An array of strings specifying the required reference for the collection. Acceptable values are `product`, `archive`, `cart`, and `order`. When the required reference isn't available on Editor side but will be available in Frontend, we will show a preview label.
### Attributes
Attributes are the properties that define the behavior of the collection. All the attributes are *optional*. Here are some of the important attributes that can be passed to `__experimentalRegisterProductCollection`:
- `query` (type `object`): The query object that defines the query for the collection. It can contain the following fields:
- `offset` (type `number`): The number of items to offset the query by.
- `order` (type `string`): The order of the query. Accepted values are `asc` and `desc`.
- `orderBy` (type `string`): The field to order the query by.
- `pages` (type `number`): The number of pages to query.
- `perPage` (type `number`): The number of products per page.
- `search` (type `string`): The search term to query by.
- `taxQuery` (type `object`): The tax query to filter the query by. For example, if you wanna fetch products with category `Clothing` & `Accessories` and tag `Summer` then you can pass `taxQuery` as `{"product_cat":[20,17],"product_tag":[36]}`. Where array values are the term IDs.
- `featured` (type `boolean`): Whether to query for featured items.
- `timeFrame` (type `object`): The time frame to query by.
- `operator` (type `string`): The operator to use for the time frame query. Accepted values are `in` and `not-in`.
- `value` (type `string`): The value to query by. It should be a valid date string that PHP's `strtotime` function can parse.
- `woocommerceOnSale` (type `boolean`): Whether to query for items on sale.
- `woocommerceStockStatus` (type `array`): The stock status to query by. Some of the accepted values are `instock`, `outofstock`, `onbackorder`.
- `woocommerceAttributes` (type `array`): The attributes to query by.
- For example, if you wanna fetch products with color `blue` & `gray` and size `Large` then you can pass `woocommerceAttributes` as `[{"termId":23,"taxonomy":"pa_color"},{"termId":26,"taxonomy":"pa_size"},{"termId":29,"taxonomy":"pa_color"}]`.
- `woocommerceHandPickedProducts` (type `array`): The hand-picked products to query by. It should contain the product IDs.
- `priceRange` (type `object`): The price range to query by.
- `min` (type `number`): The minimum price.
- `max` (type `number`): The maximum price.
- `displayLayout` (type `object`): The display layout object that defines the layout of the collection. It can contain the following fields:
- `type` (type `string`): The type of layout. Accepted values are `grid` and `stack`.
- `columns` (type `number`): The number of columns to display.
- `shrinkColumns` (type `boolean`): Whether the layout should be responsive.
- `hideControls` (type `array`): The controls to hide. Possible values:
- `order` - "Order by" setting
- `attributes` - "Product Attributes" filter
- `created` - "Created" filter
- `featured` - "Featured" filter
- `hand-picked` - "Hand-picked Products" filter
- `keyword` - "Keyword" filter
- `on-sale` - "On Sale" filter
- `stock-status` - "Stock Status" filter
- `taxonomy` - "Product Categories", "Product Tags" and custom taxonomies filters
- `price-range` - "Price Range" filter
#### Preview Attribute
The `preview` attribute is optional, and it is used to set the preview state of the collection. It can contain the following fields:
- `initialPreviewState` (type `object`): The initial preview state of the collection. It can contain the following fields:
- `isPreview` (type `boolean`): Whether the collection is in preview mode.
- `previewMessage` (type `string`): The message to be displayed in the Tooltip when the user hovers over the preview label.
- `setPreviewState` (optional, type `function`): The function to set the preview state of the collection. It receives the following arguments:
- `setState` (type `function`): The function to set the preview state. You can pass a new preview state to this function containing `isPreview` and `previewMessage`.
- `attributes` (type `object`): The current attributes of the collection.
- `location` (type `object`): The location of the collection. Accepted values are `product`, `archive`, `cart`, `order`, `site`.
For more info, you may check [PR #46369](https://github.com/woocommerce/woocommerce/pull/46369), in which the Preview feature was added
## Examples
### Example 1: Registering a new collection
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection",
title: "My Custom Collection",
icon: "games",
description: "This is a custom collection.",
keywords: ["custom collection", "product collection"],
});
```
As you can see in the example above, we are registering a new collection with the name `woocommerce/product-collection/my-custom-collection` & title `My Custom Collection`. Here is screenshot of how it will look like:
![image](https://github.com/woocommerce/woocommerce/assets/16707866/7fddbc02-a6cd-494e-b2f4-13dd5ef9cf96)
### Example 2: Register a new collection with a preview
As you can see below, setting the initial preview state is possible. In the example below, we are setting `isPreview` and `previewMessage`.
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection-with-preview",
title: "My Custom Collection with Preview",
icon: "games",
description: "This is a custom collection with preview.",
keywords: ["My Custom Collection with Preview", "product collection"],
preview: {
initialPreviewState: {
isPreview: true,
previewMessage:
"This is a preview message for my custom collection with preview.",
},
},
attributes: {
query: {
perPage: 5,
featured: true,
},
displayLayout: {
type: "grid",
columns: 3,
shrinkColumns: true,
},
hideControls: [ "created", "stock-status" ]
},
});
```
Here is how it will look like:
![image](https://github.com/woocommerce/woocommerce/assets/16707866/5fc1aa20-552a-4e09-b811-08babab46665)
### Example 3: Advanced usage of preview
As you can see below, it's also possible to use `setPreviewState` to set the preview state. In the example below, we are setting `initialPreviewState` and using `setPreviewState` to change the preview state after 5 seconds.
**This example shows:**
- How to access current attributes and location in the preview state
- How to use async operations
- We are using `setTimeout` to change the preview state after 5 seconds. You can use any async operation, like fetching data from an API, to decide the preview state.
- How to use the cleanup function as a return value
- We are returning a cleanup function that will clear the timeout after the component is unmounted. You can use this to clean up any resources you have used in `setPreviewState`.
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection-with-advanced-preview",
title: "My Custom Collection with Advanced Preview",
icon: "games",
description: "This is a custom collection with advanced preview.",
keywords: [
"My Custom Collection with Advanced Preview",
"product collection",
],
preview: {
setPreviewState: ({
setState,
attributes: currentAttributes,
location,
}) => {
// setPreviewState has access to the current attributes and location.
// console.log( currentAttributes, location );
const timeoutID = setTimeout(() => {
setState({
isPreview: false,
previewMessage: "",
});
}, 5000);
return () => clearTimeout(timeoutID);
},
initialPreviewState: {
isPreview: true,
previewMessage:
"This is a preview message for my custom collection with advanced preview.",
},
},
});
```
### Example 4: Collection with inner blocks
As you can see below, it's also possible to define inner blocks for the collection. In the example below, we are defining inner blocks for the collection.
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection-with-inner-blocks",
title: "My Custom Collection with Inner Blocks",
icon: "games",
description: "This is a custom collection with inner blocks.",
keywords: ["My Custom Collection with Inner Blocks", "product collection"],
innerBlocks: [
[
"core/heading",
{
textAlign: "center",
level: 2,
content: "Title of the collection",
},
],
[
"woocommerce/product-template",
{},
[
["woocommerce/product-image"],
[
"woocommerce/product-price",
{
textAlign: "center",
fontSize: "small",
},
],
],
],
],
});
```
This will create a collection with a heading, product image, and product price. Here is how it will look like:
![image](https://github.com/woocommerce/woocommerce/assets/16707866/3d92c084-91e9-4872-a898-080b4b93afca)
> [!TIP]
> You can learn more about inner blocks template in the [Inner Blocks](https://developer.wordpress.org/block-editor/how-to-guides/block-tutorial/nested-blocks-inner-blocks/#template) documentation.
### Example 5: Collection with `usesReference` argument
When a collection requires a reference to work properly, you can specify it using the `usesReference` argument. In the example below, we are defining a collection that requires a `product` reference.
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection",
title: "My Custom Collection",
icon: "games",
description: "This is a custom collection.",
keywords: ["custom collection", "product collection"],
usesReference: ["product"],
});
```
This will create a collection that requires a `product` reference. If the required reference isn't available on the Editor side but will be available in the Frontend, we will show a preview label.
When a collection need one of the multiple references, you can specify it using the `usesReference` argument. In the example below, we are defining a collection that requires either a `product` or `order` reference.
```tsx
__experimentalRegisterProductCollection({
name: "your-plugin-name/product-collection/my-custom-collection",
title: "My Custom Collection",
icon: "games",
description: "This is a custom collection.",
keywords: ["custom collection", "product collection"],
usesReference: ["product", "order"],
});
```
---
> [!TIP]
> You can also take a look at how we are defining our core collections at `plugins/woocommerce-blocks/assets/js/blocks/product-collection/collections` directory. Our core collections will also evolve over time.

View File

@ -6,4 +6,4 @@ post_title: Product Editor
Discover how to customize the WooCommerce product editor, from extending product data to adding unique functionalities.
This handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem.
This handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem.

View File

@ -0,0 +1,14 @@
# How-to Guides for the Product form
There are several ways to extend and modify the new product form. Below are links to different tutorials.
## Generic fields
One way to extend the new product form is by making use of generic fields. This allows you to easily modify the form using PHP only. We have a wide variety of generic fields that you can use, like a text, checkbox, pricing or a select field. You can find the full list [here](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/product-editor/src/blocks/generic/README.md).
To see how you can make use of these fields you can follow the [generic fields tutorial](https://github.com/woocommerce/woocommerce/blob/trunk/docs/product-editor-development/how-to-guides/generic-fields-tutorial.md).
## Writing a custom field
It is also possible to write your own custom field and render those within the product form. This is helpful if the generic fields don't quite fit your use case.
To see an example of how to create a basic dropdown field in the product form you can follow [this tutorial](https://github.com/woocommerce/woocommerce/blob/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md).

View File

@ -0,0 +1,263 @@
# Extending the product form with custom fields
Aside from extending the product form using generic fields it is also possible to use custom fields. This does require knowledge of JavaScript and React.
If you are already familiar with writing blocks for the WordPress site editor this will feel very similar.
## Getting started
To get started we would recommend reading through the [fundamentals of block development docs](https://developer.wordpress.org/block-editor/getting-started/fundamentals/) in WordPress. This gives a good overview of working with blocks, the block structure, and the [JavaScript build process](https://developer.wordpress.org/block-editor/getting-started/fundamentals/javascript-in-the-block-editor/).
This tutorial will use vanilla JavaScript to render a new field in the product form for those that already have a plugin and may not have a JavaScript build process set up yet.
If you want to create a plugin from scratch with the necessary build tools, we recommend using the `@wordpress/create-block` script. We also have a specific template for the product form: [README](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/create-product-editor-block/README.md).
## Creating a custom field
### Adding and registering our custom field
Adding and registering our custom field is very similar as creating a brand new block.
Inside a new folder within your plugin, let's create a `block.json` file with the contents below. The only main difference between this `block.json` and a `block.json` for the site editor is that we will set `supports.inserter` to false, so it doesn't show up there. We will also be registering this slightly different.
```json
{
"$schema": "https://schemas.wp.org/trunk/block.json",
"apiVersion": 3,
"name": "tutorial/new-product-form-field",
"title": "Product form field",
"category": "woocommerce",
"description": "A sample field for the product form",
"keywords": [ "products" ],
"attributes": {},
"supports": {
"html": false,
"multiple": true,
// Setting inserter to false is important so that it doesn't show in the site editor.
"inserter": false
},
"textdomain": "woocommerce",
"editorScript": "file:./index.js"
}
```
In the same directory, create a `index.js` file, which we can keep simple by just outputting a hello world.
In this case the `edit` function is the part that will get rendered in the form. We are wrapping it with the `createElement` function to keep support for React.
```javascript
( function ( wp ) {
var el = wp.element.createElement;
wp.blocks.registerBlockType( 'tutorial/new-product-form-field', {
title: 'Product form field',
attributes: {},
edit: function () {
return el( 'p', {}, 'Hello World (from the editor).' );
},
} );
} )( window.wp );
```
In React:
```jsx
import { registerBlockType } from '@wordpress/blocks';
function Edit() {
return &lt;p&gt;Hello World (from the editor).&lt;/p&gt;;
}
registerBlockType( 'tutorial/new-product-form-field', {
title: 'Product form field',
attributes: {},
edit: Edit,
} );
```
Lastly, in order to make this work the block registration needs to know about the JavaScript dependencies, we can do so by adding a `index.asset.php` file with the below contents:
```php
<?php return array('dependencies' => array('react', 'wc-product-editor', 'wp-blocks' ) );
```
Now that we have all the for the field we need to register it and add it to the template.
Registering can be done on `init` by calling `BlockRegistry::get_instance()->register_block_type_from_metadata` like so:
```php
use Automattic\WooCommerce\Admin\Features\ProductBlockEditor\BlockRegistry;
function example_custom_product_form_init() {
if ( isset( $_GET['page'] ) && $_GET['page'] === 'wc-admin' ) {
// This points to the directory that contains your block.json.
BlockRegistry::get_instance()->register_block_type_from_metadata( __DIR__ . '/js/sample-block' );
}
}
add_action( 'init', 'example_custom_product_form_init' );
```
We can add it to the product form by hooking into the `woocommerce_layout_template_after_instantiation` action ( see [block addition and removal](https://github.com/woocommerce/woocommerce/blob/trunk/docs/product-editor-development/block-template-lifecycle.md#block-addition-and-removal) ).
What we did was the following ( see [here](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/README.md#usage) for more related functions ):
- Get a group by the `general` id, this is the General tab.
- Create a new section on the general tab called `Tutorial Section`
- Add our custom field to the `Tutorial Section`
```php
add_action(
'woocommerce_layout_template_after_instantiation',
function( $layout_template_id, $layout_template_area, $layout_template ) {
$general = $layout_template->get_group_by_id( 'general' );
if ( $general ) {
// Creating a new section, this is optional.
$tutorial_section = $general->add_section(
array(
'id' => 'tutorial-section',
'order' => 15,
'attributes' => array(
'title' => __( 'Tutorial Section', 'woocommerce' ),
'description' => __( 'Fields related to the tutorial', 'woocommerce' ),
),
)
);
$tutorial_section->add_block(
[
'id' => 'example-new-product-form-field',
'blockName' => 'tutorial/new-product-form-field',
'attributes' => [],
]
);
}
},
10,
3
);
```
### Turn field into a dropdown
We recommend using components from `@wordpress/components` as this will also keep the styling consistent. We will use the [ComboboxControl](https://wordpress.github.io/gutenberg/?path=/docs/components-comboboxcontrol--docs) core component in this field.
We can add it to our `edit` function pretty easily by making use of `wp.components`. We will also add a constant for the filter options.
**Note:** I also added the `blockProps` to the top element, we still recommend using this as some of these props are being used in the product form. When we add the block props we need to also let the form know it is an interactive element. We do this by adding at-least one attribute with the `__experimentalRole` set to `content`.
So lets add this to our `index.js` attributes:
```javascript
attributes: {
"message": {
"type": "string",
"__experimentalRole": "content",
"source": "text",
"selector": "div"
}
},
```
Dropdown options, these can live outside of the `edit` function:
```javascript
const DROPDOWN_OPTIONS = [
{
value: 'small',
label: 'Small',
},
{
value: 'normal',
label: 'Normal',
},
{
value: 'large',
label: 'Large',
},
];
```
The updated `edit` function:
```javascript
// edit function.
function ( { attributes } ) {
// useState is a React specific function.
const [ value, setValue ] = wp.element.useState();
const [ filteredOptions, setFilteredOptions ] = wp.element.useState( DROPDOWN_OPTIONS );
const blockProps = window.wc.blockTemplates.useWooBlockProps( attributes );
return el( 'div', { ...blockProps }, [
el( wp.components.ComboboxControl, {
label: "Example dropdown",
value: value,
onChange: setValue,
options: filteredOptions,
onFilterValueChange: function( inputValue ) {
setFilteredOptions(
DROPDOWN_OPTIONS.filter( ( option ) =>
option.label
.toLowerCase()
.startsWith( inputValue.toLowerCase() )
)
)
}
} )
] );
},
```
In React:
```jsx
import { createElement, useState } from '@wordpress/element';
import { ComboboxControl } from '@wordpress/components';
import { useWooBlockProps } from '@woocommerce/block-templates';
function Edit( { attributes } ) {
const [ value, setValue ] = useState();
const [ filteredOptions, setFilteredOptions ] =
useState( DROPDOWN_OPTIONS );
const blockProps = useWooBlockProps( attributes );
return (
&lt;div { ...blockProps }&gt;
&lt;ComboboxControl
label="Example dropdown"
value={ value }
onChange={ setValue }
options={ filteredOptions }
onFilterValueChange={ ( inputValue ) =>
setFilteredOptions(
DROPDOWN_OPTIONS.filter( ( option ) =>
option.label
.toLowerCase()
.startsWith( inputValue.toLowerCase() )
)
)
}
/&gt;
&lt;/div&gt;
);
}
```
### Save field data to the product data
We can make use of the `__experimentalUseProductEntityProp` for saving the field input to the product.
The function does rely on `postType`, we can hardcode this to `product`, but the `postType` is also exposed through a context. We can do so by adding `"usesContext": [ "postType" ],` to the `block.json` and getting it from the `context` passed into the `edit` function props.
So the top part of the edit function will look like this, where we also replace the `value, setValue` `useState` line:
```javascript
// edit function.
function ( { attributes, context } ) {
const [ value, setValue ] = window.wc.productEditor.__experimentalUseProductEntityProp(
'meta_data.animal_type',
{
postType: context.postType,
fallbackValue: '',
}
);
// .... Rest of edit function
```
Now if you select small, medium, or large from the dropdown and save your product, the value should persist correctly.
Note, the above function supports the use of `meta_data` by dot notation, but you can also target other fields like `regular_price` or `summary`.

View File

@ -0,0 +1,58 @@
# Extending the product form with generic fields
We have large list of generic fields that a plugin can use to extend the new product form. You can find the full list [here](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/product-editor/src/blocks/generic/README.md). Each field contains documentation for what attributes the field supports.
## Using a generic block
Using a generic block is pretty easy. We have created an template API that allows you to add new fields, the API refers to them as `blocks`. There are a couple actions that allow us to interact with these templates. There is the `woocommerce_layout_template_after_instantiation` that is triggered when a new template is registered. There are also other actions triggered when a specific field/block is added ( see [block addition and removal](https://github.com/woocommerce/woocommerce/blob/trunk/docs/product-editor-development/block-template-lifecycle.md#block-addition-and-removal) ).
Let's say we want to add something to the basic details section, we can do so by making use of the above mentioned hook:
This will add a number field called **Animal age** to each template that has a `basic-details` section.
```php
add_action(
'woocommerce_layout_template_after_instantiation',
function( $layout_template_id, $layout_template_area, $layout_template ) {
$basic_details = $layout_template->get_section_by_id( 'basic-details' );
if ( $basic_details ) {
$basic_details->add_block(
[
'id' => 'example-tutorial-animal-age',
// This orders the field, core fields are separated by sums of 10.
'order' => 40,
'blockName' => 'woocommerce/product-number-field',
'attributes' => [
// Attributes specific for the product-number-field.
'label' => 'Animal age',
'property' => 'meta_data.animal_age',
'suffix' => 'Yrs',
'placeholder' => 'Age of animal',
'required' => true,
'min' => 1,
'max' => 20
],
]
);
}
},
10,
3
);
```
### Dynamically hiding or showing the generic field
It is also possible to dynamically hide or show your field if data on the product form changes.
We can do this by adding a `hideCondition` ( plural ). For example if we wanted to hide our field if the product price is higher than 20, we can do so by adding this expression:
```php
'hideConditions' => array(
array(
'expression' => 'editedProduct.regular_price >= 20',
),
),
```
The `hideConditions` also support targeting meta data by using dot notation. You can do so by writing an expression like this: `! editedProduct.meta_data.animal_type` that will hide a field if the `animal_type` meta data value doesn't exist.

View File

@ -37,6 +37,7 @@ Please note that this check is currently not being enforced: the product editor
## Related documentation
- [Examples on Template API usage](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/README.md/)
- [How to guides](https://github.com/woocommerce/woocommerce/blob/trunk/docs/product-editor-development/how-to-guides/README.md)
- [Related hooks and Template API documentation](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/src/Admin/BlockTemplates/README.md)
- [Generic blocks documentation](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/product-editor/src/blocks/generic/README.md)
- [Validations and error handling](https://github.com/woocommerce/woocommerce/blob/trunk/packages/js/product-editor/src/contexts/validation-context/README.md)

View File

@ -4,4 +4,4 @@ category_slug: quality-and-best-practices
post_title: Quality and best practices
---
Ensuring the quality of your WooCommerce projects is essential. This section will delve into quality exoectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more.
Ensuring the quality of your WooCommerce projects is essential. This section will delve into quality expectations, best practices, coding standards, and other methodologies to ensure your projects stand out in terms of reliability, efficiency, user experience, and more.

View File

@ -56,7 +56,7 @@ These flows will continually evolve as the platform evolves with flows updated,
| Shopper | Product | Variable Product info updates depending on variation | shopper/product-variable.spec.js |
| Shopper | Product | Add Variable Product to Cart | shopper/product-variable.spec.js |
| Shopper | Product | Display up-sell product | products/product-linked-products.spec.js |
| Shopper | Product | Display releated products | products/product-linked-products.spec.js |
| Shopper | Product | Display related products | products/product-linked-products.spec.js |
| Shopper | Product | Display reviews | merchant/product-reviews.spec.js |
| Shopper | Product | Add review | merchant/product-reviews.spec.js |
| Shopper | Product | View product images | shopper/product-simple.spec.js |
@ -74,7 +74,7 @@ These flows will continually evolve as the platform evolves with flows updated,
| Shopper | Cart | Display shipping options by address | shopper/calculate-shipping.spec.js |
| Shopper | Cart | View empty cart | shopper/cart.spec.js |
| Shopper | Cart | Display correct tax | shopper/cart-checkout-calculate-tax.spec.js |
| Shopper | Cart | Respect coupon usage contraints | shopper/cart-checkout-coupons.spec.js |
| Shopper | Cart | Respect coupon usage constraints | shopper/cart-checkout-coupons.spec.js |
| Shopper | Cart | Display cross-sell products | products/product-linked-products.spec.js |
| Shopper | Cart | Proceed to checkout | shopper/checkout.spec.js |
@ -92,7 +92,7 @@ These flows will continually evolve as the platform evolves with flows updated,
| Shopper | Checkout | View checkout | shopper/checkout.spec.js |
| Shopper | Checkout | Receive warnings when form is incomplete | shopper/checkout.spec.js |
| Shopper | Checkout | Add billing address | shopper/checkout.spec.js |
| Shopper | Checkout | Respect coupon usage contraints | shopper/cart-checkout-coupons.spec.js |
| Shopper | Checkout | Respect coupon usage constraints | shopper/cart-checkout-coupons.spec.js |
| Shopper | Checkout | Display correct tax in checkout | shopper/cart-checkout-calculate-tax.spec.js |
| Shopper | Checkout | View order confirmation page | shopper/checkout.spec.js |
@ -147,13 +147,14 @@ These flows will continually evolve as the platform evolves with flows updated,
### Merchant - Settings
| User Type | Flow Area | Flow Name | Test File |
| --------- | --------- | -------------------------------------- | ---------------------------------------- |
| --------- | --------- |----------------------------------------|------------------------------------------|
| Merchant | Settings | Update General Settings | merchant/settings-general.spec.js |
| Merchant | Settings | Add Tax Rates | merchant/settings-tax.spec.js |
| Merchant | Settings | Add Shipping Zones | merchant/create-shipping-zones.spec.js |
| Merchant | Settings | Add Shipping Classes | merchant/create-shipping-classes.spec.js |
| Merchant | Settings | Enable local pickup for checkout block | merchant/settings-shipping.spec.js |
| Merchant | Settings | Update payment settings | admin-tasks/payment.spec.js |
| Merchant | Settings | Handle Product Brands | merchant/create-product-brand.spec.js |
### Merchant - Coupons

View File

@ -0,0 +1,19 @@
---
category_title: Review Guidelines
category_slug: review-guidelines
post_title: Review Guidelines
---
Reviews are an integral part of the online shopping experience, and people installing software pay attention to them. Prospective users of your extensions will likely consider average ratings when making software choices.
Many of today's most popular online review platforms - from Yelp business reviews, to Amazon product reviews - have a range of opinion that can be polarized, with many extremely positive and/or negative reviews, and fewer moderate opinions. This creates a "J-shaped" distribution of reviews that isn't as accurate or as helpful as could be.
WooCommerce.com and WordPress.org both feature reviews heavily, and competing extensions having a higher rating likely have the edge in user choice.
## Primary considerations around reviews
Requesting more reviews for a extension with major issues will not generate good reviews, and analyzing existing reviews will help surface areas to address before soliciting reviews.
It is extremely rare for users of WordPress plugins to leave reviews organically (.2% of users for WordPress.org leave reviews), which means that there's an untapped market of 99.8% of users of the average plugin.
These plugins are competing with other plugins on the same search terms in the WordPress.org plugin directory, and ratings are a large factor in the ranking algorithm. This is not usually a factor to the same extent on the WooCommerce Marketplace. For instance, WooCommerce's PayPal extension directly competes on all possible keywords with other PayPal extensions on the WordPress.org repository, while it does not compete with other PayPal payments extensions on the Marketplace.

View File

@ -0,0 +1,39 @@
---
post_title: How to request WooCommerce extension reviews
menu_title: Requesting reviews
---
## Methods of requesting reviews
### Admin notices
Admin notices are an industry standard method of requesting reviews, but bombarding the admin dashboard with admin notices is not effective. We recommend using restraint in the design of a notice, as well as limiting to a single notice at a time. It's very easy to overwhelm merchants with too many notices, or too intrusive notices.
#### Recommendations
* A good place for an admin notice to review an extension would be to show on the `Plugins` page and extension's settings pages.
* Include a snooze option (or multiple) on your notices with a clear expectation of when the notice will reappear.
* Admin notices should always be always be completely dismissable. They cannot only have a snooze option.
* The options presented in the notice must be phrased carefully to avoid manipulative language.
* Use consistently designed notices so the request for reviews feels like a part of your extension, and looks consistent with WooCommerce's design.
### Direct contact
#### Recommendations
* The most direct route to requesting reviews with the highest chance of being positive is to contact the customer when they are the happiest with the product.
* This can be milestone or time based, following the timing guidelines below.
* The best method for this is either an email or other direct exchange (support chat, call, etc.). This has the highest conversion rate, especially when timed properly so that the customer is happiest.
* This is also extremely effective when you are able to request feedback from specifically qualified merchants, such as merchants that have processed a certain amount with your platform, or who have shipped their first 100 orders using your fulfillment extension, or similar.
* Direct outreach is most likely to be successful if you have ways of targeting users for review requests (merchant account / usage info, etc.), as well as ways to gather the reviews, like sales or marketing teams able to email/call/chat with merchants.
## Messaging for requesting reviews
One method of requesting feedback that we recommend is using the NPS style of review solicitation. This can allow for an increase positive reviews as well as providing the opportunity to assist merchants that are struggling.
NPS-style reviews first ask the user how they rate the product (out of 5 stars), then route them based on their response:
* If they click 4 or 5 stars, ask them to leave a review.
* If they click 1, 2 or 3, tell them we're here to help & ask them to submit a support ticket.
Merchants are significantly more likely to leave a review after a positive support interaction with a support rep who explicitly asked for a review. The language "the best way to thank me is to leave a 5 star review that mentions me in it" or similar tends to work very well - people are more willing to help a person than a produc or company.

View File

@ -0,0 +1,14 @@
---
post_title: Miscellaneous guidelines and advice
menu_title: Miscellaneous guidelines
---
Contributors' names matching search terms directly will rank extremely highly on the WordPress.org plugin repo, which means that having a WordPress.org user named after your business (if that's a search term for your plugin) could tilt the scales over a competing plugin.
Constant nags and overwhelming the admin dashboard with unnecessary alerts detract from your user experience.
You can request to have reviews that are not actually feedback removed. Where this might be applicable is if the request is a simple support request, where it's obviously in the wrong spot. 1 star reviews, even if aggressive or angry, are not usually removed.
Reply to reviews! Thank the giver for offering feedback, acknowledge the issue if needed, ask for more specific feedback, or provide an update when that feedback is addressed! Your reviews are a great window into what your extension's users are actually thinking.
Having folks close to the extension's development (think developers and project managers) looking at reviews on a regular basis is a good way to ensure the customers voice is heard. 1 star reviews are among the most useful, as long as the issue is understood and addressed (if needed).

View File

@ -0,0 +1,18 @@
---
post_title: Notifying users about bug fixes and feature requests
menu_title: Notifying users about bug fixes and feature requests
---
A bug or a missing feature can be a showstopper for merchants. Bugs that pile up or popular features that are not implemented can lead to negative reviews and/or merchants churning and looking at a competitive solution.
Bugs are usually reported via support or GitHub, or you can discover them yourselves in testing.
When a critical bug is found, resolve it within a couple of days (most critical bugs should be resolved within 24 hours) and release a new plugin version promptly. Part of your release process should be to notify all stakeholders (the support team and the merchant affected) about the upcoming release.
Even though a critical bug is a great source of stress for merchants, a quick resolution makes merchants feel heard and supported - having a reliable business partner, who is keen to help in the most difficult situation, helps build a stronger relationship. Therefore, we usually ask merchants for a 5* review when we deliver a fast solution.
When you implement a new feature request and ship a new plugin version, you can follow a similar approach to bugs:
* Notify all stakeholders.
* Update the relevant request in the Feature Requests board, by sharing a public update and marking it as 'Completed'.
* For breaking releases: communicating with your marketing/relations teams to publish updates/newsletters before the release.

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