Merge branch 'trunk' into dev/update-iapi-to-latest

This commit is contained in:
Tung Du 2024-09-18 20:55:50 +07:00
commit b923944450
1397 changed files with 43617 additions and 101830 deletions

View File

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

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

@ -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

@ -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

@ -186,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:
@ -216,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:
@ -231,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:
@ -279,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:
@ -300,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:
@ -348,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:
@ -369,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:
@ -380,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:
@ -395,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:
@ -406,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:

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

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,6 +1,8 @@
#!/usr/bin/env bash
. "$(dirname "$0")/_/husky.sh"
# 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"

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

@ -201,7 +201,9 @@
"@wordpress/interface",
"@wordpress/router",
"@wordpress/edit-site",
"@wordpress/private-apis"
"@wordpress/private-apis",
"@wordpress/dataviews",
"@wordpress/icons"
],
"packages": [
"@woocommerce/block-templates",

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

@ -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,245 @@
== 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**

View File

@ -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`.

View File

@ -1109,16 +1109,16 @@ The contents of this block will display when there are no products found.
- **Supports:** align, color (background, gradients, link, text), typography (fontSize, lineHeight), ~~html~~, ~~reusable~~
- **Attributes:**
## Product Filter (Experimental) - woocommerce/product-filter
## Product Filters (Experimental) - woocommerce/product-filters
A block that adds product filters to the product collection.
Let shoppers filter products displayed on the page.
- **Name:** woocommerce/product-filter
- **Name:** woocommerce/product-filters
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filters
- **Ancestor:**
- **Parent:**
- **Supports:** ~~html~~, ~~inserter~~, ~~reusable~~
- **Attributes:** attributeId, filterType, heading, isPreview
- **Supports:** align, color (background, text), interactivity, layout (allowJustification, allowOrientation, allowVerticalAlignment, default, ~~allowInheriting~~), spacing (blockGap), typography (fontSize, textAlign), ~~inserter~~, ~~multiple~~
- **Attributes:** overlay, overlayButtonStyle, overlayIcon, overlayIconSize
## Filter Options - woocommerce/product-filter-active
@ -1153,50 +1153,6 @@ Allows shoppers to reset this filter.
- **Supports:** interactivity, ~~inserter~~
- **Attributes:**
## Filter Options - woocommerce/product-filter-price
Enable customers to filter the product collection by choosing a price range.
- **Name:** woocommerce/product-filter-price
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** interactivity, ~~inserter~~
- **Attributes:** inlineInput, showInputFields
## Filter Options - woocommerce/product-filter-rating
Enable customers to filter the product collection by rating.
- **Name:** woocommerce/product-filter-rating
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** color (text, ~~background~~), interactivity, ~~inserter~~
- **Attributes:** className, displayStyle, isPreview, selectType, showCounts
## Filter Options - woocommerce/product-filter-stock-status
Enable customers to filter the product collection by stock status.
- **Name:** woocommerce/product-filter-stock-status
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** color (text, ~~background~~), interactivity, ~~html~~, ~~inserter~~, ~~multiple~~
- **Attributes:** className, displayStyle, isPreview, selectType, showCounts
## Product Filters (Experimental) - woocommerce/product-filters
Let shoppers filter products displayed on the page.
- **Name:** woocommerce/product-filters
- **Category:** woocommerce
- **Ancestor:**
- **Parent:**
- **Supports:** align, color (background, text), interactivity, layout (allowJustification, allowOrientation, allowVerticalAlignment, default, ~~allowInheriting~~), spacing (blockGap), typography (fontSize, textAlign), ~~inserter~~, ~~multiple~~
- **Attributes:** overlay, overlayButtonStyle, overlayIcon, overlayIconSize
## Product Filters Overlay (Experimental) - woocommerce/product-filters-overlay
Display product filters in an overlay on top of a page.
@ -1219,6 +1175,50 @@ Display overlay navigation controls.
- **Supports:** align (center, left, right), color (background, text), layout (default, ~~allowEditing~~), position (sticky), spacing (blockGap, margin, padding), typography (fontSize, lineHeight), ~~inserter~~
- **Attributes:** align, buttonStyle, iconSize, navigationStyle, overlayMode, style, triggerType
## Filter Options - woocommerce/product-filter-price
Enable customers to filter the product collection by choosing a price range.
- **Name:** woocommerce/product-filter-price
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** interactivity, ~~inserter~~
- **Attributes:** inlineInput, showInputFields
## Product Filter (Experimental) - woocommerce/product-filter
A block that adds product filters to the product collection.
- **Name:** woocommerce/product-filter
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filters
- **Parent:**
- **Supports:** inserter, ~~html~~, ~~reusable~~
- **Attributes:** attributeId, filterType, heading, isPreview
## Filter Options - woocommerce/product-filter-rating
Enable customers to filter the product collection by rating.
- **Name:** woocommerce/product-filter-rating
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** color (text, ~~background~~), interactivity, ~~inserter~~
- **Attributes:** className, displayStyle, isPreview, selectType, showCounts
## Filter Options - woocommerce/product-filter-stock-status
Enable customers to filter the product collection by stock status.
- **Name:** woocommerce/product-filter-stock-status
- **Category:** woocommerce
- **Ancestor:** woocommerce/product-filter
- **Parent:**
- **Supports:** color (text, ~~background~~), interactivity, ~~html~~, ~~inserter~~
- **Attributes:** className, displayStyle, isPreview, selectType, showCounts
## Product Gallery (Beta) - woocommerce/product-gallery
Showcase your products relevant images and media.

View File

@ -339,11 +339,11 @@ This results in the following address form (the billing form will be the same):
The rendered markup looks like this:
```html
<input type="text" id="shipping-namespace-gov-id" autocapitalize="off"
&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="" >
data-custom="custom data" value="" &gt;
```
### Rendering a checkbox field

View File

@ -81,7 +81,7 @@ const modifyCartItemClass = ( defaultValue, extensions, args ) => {
const modifyCartItemPrice = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return '<price/> for all items';
return '&lt;price/&gt; for all items';
}
return defaultValue;
};
@ -95,7 +95,7 @@ const modifyItemName = ( defaultValue, extensions, args ) => {
const modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {
if ( isOrderSummaryContext( args ) ) {
return '<price/> per item';
return '&lt;price/&gt; per item';
}
return defaultValue;
};

View File

@ -106,17 +106,17 @@ The `cartItemPrice` filter allows to format the order summary item price.
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item price.
- _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 `<price/>`.
- _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 `<price/>`, or the original price format.
- `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 -->
@ -132,7 +132,7 @@ const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
return defaultValue;
}
return '<price/> for all items';
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
@ -153,14 +153,14 @@ const modifyCartItemPrice = ( defaultValue, extensions, args, validation ) => {
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '<price/> to keep you ☀️';
return '&lt;price/&gt; to keep you ☀️';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '<price/> to keep you ❄️';
return '&lt;price/&gt; to keep you ❄️';
}
return '<price/> for all items';
return '&lt;price/&gt; for all items';
};
registerCheckoutFilters( 'example-extension', {
@ -261,17 +261,17 @@ The `subtotalPriceFormat` filter allows to format the order summary item subtota
### Parameters <!-- omit in toc -->
- _defaultValue_ `string` (default: `<price/>`) - The default order summary item subtotal price.
- _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 `<price/>`.
- _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 `<price/>`, or the original price format.
- `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 -->
@ -292,7 +292,7 @@ const modifySubtotalPriceFormat = (
return defaultValue;
}
return '<price/> per item';
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {
@ -318,14 +318,14 @@ const modifySubtotalPriceFormat = (
}
if ( args?.cartItem?.name === 'Beanie with Logo' ) {
return '<price/> per warm beanie';
return '&lt;price/&gt; per warm beanie';
}
if ( args?.cartItem?.name === 'Sunglasses' ) {
return '<price/> per cool sunglasses';
return '&lt;price/&gt; per cool sunglasses';
}
return '<price/> per item';
return '&lt;price/&gt; per item';
};
registerCheckoutFilters( 'example-extension', {

View File

@ -71,11 +71,11 @@ The `totalValue` filter allows to format the total price in the footer of the Ca
- _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 `<price/>`.
- _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 `<price/>`, or the original price format.
- `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 -->
@ -83,7 +83,7 @@ The `totalValue` filter allows to format the total price in the footer of the Ca
const { registerCheckoutFilters } = window.wc.blocksCheckout;
const modifyTotalsPrice = ( defaultValue, extensions, args, validation ) => {
return 'Pay <price/> now';
return 'Pay &lt;price/&gt; now';
};
registerCheckoutFilters( 'my-extension', {

View File

@ -22,11 +22,11 @@ const { ExperimentalOrderMeta } = window.wc.blocksCheckout;
const render = () => {
return (
<ExperimentalOrderMeta>
<div class="wc-block-components-totals-wrapper">
&lt;ExperimentalOrderMeta&gt;
&lt;div class="wc-block-components-totals-wrapper"&gt;
{ __( 'Yearly recurring total ...', 'YOUR-TEXTDOMAIN' ) }
</div>
</ExperimentalOrderMeta>
&lt;/div&gt;
&lt;/ExperimentalOrderMeta&gt;
);
};
@ -61,9 +61,9 @@ const { ExperimentalOrderShippingPackages } = window.wc.blocksCheckout;
const render = () => {
return (
<ExperimentalOrderShippingPackages>
<div>{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }</div>
</ExperimentalOrderShippingPackages>
&lt;ExperimentalOrderShippingPackages&gt;
&lt;div&gt;{ __( 'Express Shipping', 'YOUR-TEXTDOMAIN' ) }&lt;/div&gt;
&lt;/ExperimentalOrderShippingPackages&gt;
);
};
@ -104,14 +104,14 @@ const { ExperimentalOrderLocalPickupPackages } = window.wc.blocksCheckout;
const render = () => {
return (
<ExperimentalOrderLocalPickupPackages>
<div>
&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'
) }
</div>
</ExperimentalOrderLocalPickupPackages>
&lt;/div&gt;
&lt;/ExperimentalOrderLocalPickupPackages&gt;
);
};
@ -143,11 +143,11 @@ const { ExperimentalDiscountsMeta } = window.wc.blocksCheckout;
const render = () => {
return (
<ExperimentalDiscountsMeta>
<div class="wc-block-components-totals-wrapper">
&lt;ExperimentalDiscountsMeta&gt;
&lt;div class="wc-block-components-totals-wrapper"&gt;
{ __( 'You have 98683 coins to spend ...', 'YOUR-TEXTDOMAIN' ) }
</div>
</ExperimentalDiscountsMeta>
&lt;/div&gt;
&lt;/ExperimentalDiscountsMeta&gt;
);
};

View File

@ -43,8 +43,8 @@ The options you feed the configuration instance should be an object in this shap
```js
const options = {
name: 'my_payment_method',
content: <div>A React node</div>,
edit: <div>A React node</div>,
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: {

View File

@ -32,14 +32,14 @@ const { registerPlugin } = wp.plugins;
const { ExperimentalOrderMeta } = wc.blocksCheckout;
const MyCustomComponent = ( { cart, extensions } ) => {
return <div className="my-component">Hello WooCommerce</div>;
return &lt;div className="my-component"&gt;Hello WooCommerce&lt;/div&gt;;
};
const render = () => {
return (
<ExperimentalOrderMeta>
<MyCustomComponent />
</ExperimentalOrderMeta>
&lt;ExperimentalOrderMeta&gt;
&lt;MyCustomComponent /&gt;
&lt;/ExperimentalOrderMeta&gt;
);
};

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

@ -38,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 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.
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

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

@ -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

@ -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

@ -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

@ -74,7 +74,7 @@
"post_title": "Blocks reference",
"menu_title": "Blocks Reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/building-a-woo-store/block-references.md",
"hash": "329f17097ce67074a915d7814b2363e8b9e908910c1f7b196c8f4fd8594cc55c",
"hash": "9bbd3555641a70a0d7c24c818323a9270e437a6446998de9a6506e0c2ed6ddf5",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/block-references.md",
"id": "1fbe91d7fa4fafaf35f0297e4cee1e7958756aed"
},
@ -83,7 +83,7 @@
"menu_title": "Add Custom Fields to Products",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/building-a-woo-store/adding-a-custom-field-to-variable-products.md",
"hash": "59ef97ed2053dedfa5e7c658d5c7fa470d8110afc9b84584cb32b58389bf5687",
"hash": "fe8cf43940f5166bf69f102aa4643cbe32415b1167d6b6d8968d434a4d113879",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/building-a-woo-store/adding-a-custom-field-to-variable-products.md",
"id": "64b686dcd5fdd4842be2fc570108231d5a8bfc1b"
}
@ -100,7 +100,7 @@
"menu_title": "Slot and Fill",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
"hash": "f83a5fbef86e5ef6b0ec1d63fdbcbf4742f54de1125e535fa0f32f5f80ec794a",
"hash": "a232ca3d53f10857170113f6dc5b37ac7ae629e852629bac015a8d3c2cd1bbc4",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/slot-fills.md",
"id": "e388101586765dd9aca752d66d667d74951a1504"
},
@ -136,7 +136,7 @@
"menu_title": "Available Slots",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
"hash": "770da9156eea1fdc24db0736ce4ccd44ebde4f3b0373cd875b1ae88d4d9c8a49",
"hash": "444d9892cb6552c8394ecdf81816952987b59bc79fa53f3083c3d14a89d1e961",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-slot-fills.md",
"id": "c7ac16eee5540b06b6db928f5d03282ff177e84e"
},
@ -145,14 +145,14 @@
"menu_title": "Additional Checkout Fields",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
"hash": "1b034ede098b933b6b00a9a27ba33e418b1c88c4883e2b9b191092e32866f7b9",
"hash": "641615864f627be4bb42574df378cea91f4a7fda9edab099558bad06b92ce62d",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/additional-checkout-fields.md",
"id": "cb5dd8d59043a4e53929121b45da7b33b1661ab8"
}
],
"categories": [
{
"content": "\nThis 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.\n\n## Cart Line Items filters\n\nThe following [Cart Line Items filters](./cart-line-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `saleBadgePriceFormat`\n- `showRemoveItemLink`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)\n\n## Order Summary Items filters\n\nThe following [Order Summary Items filters](./order-summary-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)\n\n## Totals Footer Item filter\n\nThe following [Totals Footer Item filter](./totals-footer-item.md) is available:\n\n- `totalLabel`\n- `totalValue`\n\n## Checkout and place order button filters\n\nThe following [Checkout and place order button filters](./checkout-and-place-order-button.md) are available:\n\n- `proceedToCheckoutButtonLabel`\n- `proceedToCheckoutButtonLink`\n- `placeOrderButtonLabel`\n\n## Coupon filters\n\nThe following [Coupon filters](./coupons.md) are available:\n\n- `coupons`\n- `showApplyCouponNotice`\n- `showRemoveCouponNotice`\n\n## Additional Cart and Checkout inner block types filter\n\nThe following [Additional Cart and Checkout inner block types filter](./additional-cart-checkout-inner-block-types.md) is available:\n\n- `additionalCartCheckoutInnerBlockTypes`\n\n## Combined filters\n\nFilters can also be combined. The following example shows how to combine some of the available filters.\n\n```tsx\nconst { registerCheckoutFilters } = window.wc.blocksCheckout;\n\nconst isOrderSummaryContext = ( args ) => args?.context === 'summary';\n\nconst modifyCartItemClass = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn 'my-custom-class';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyCartItemPrice = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> for all items';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyItemName = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn `${ defaultValue }`;\n\t}\n\treturn defaultValue;\n};\n\nconst modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '<price/> per item';\n\t}\n\treturn defaultValue;\n};\n\nregisterCheckoutFilters( 'example-extension', {\n\tcartItemClass: modifyCartItemClass,\n\tcartItemPrice: modifyCartItemPrice,\n\titemName: modifyItemName,\n\tsubtotalPriceFormat: modifySubtotalPriceFormat,\n} );\n```\n\n## Troubleshooting\n\nIf you are logged in to the store as an administrator, you should be shown an error like this if your filter is not\nworking correctly. The error will also be shown in your console.\n\n![Troubleshooting](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-30-at-10.52.53.png)\n\n\n",
"content": "\nThis 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.\n\n## Cart Line Items filters\n\nThe following [Cart Line Items filters](./cart-line-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `saleBadgePriceFormat`\n- `showRemoveItemLink`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Cart Line Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-13.12.33.png)\n\n## Order Summary Items filters\n\nThe following [Order Summary Items filters](./order-summary-items.md) are available:\n\n- `cartItemClass`\n- `cartItemPrice`\n- `itemName`\n- `subtotalPriceFormat`\n\nThe following screenshot shows which parts the individual filters affect:\n\n![Order Summary Items](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-26-at-16.29.45.png)\n\n## Totals Footer Item filter\n\nThe following [Totals Footer Item filter](./totals-footer-item.md) is available:\n\n- `totalLabel`\n- `totalValue`\n\n## Checkout and place order button filters\n\nThe following [Checkout and place order button filters](./checkout-and-place-order-button.md) are available:\n\n- `proceedToCheckoutButtonLabel`\n- `proceedToCheckoutButtonLink`\n- `placeOrderButtonLabel`\n\n## Coupon filters\n\nThe following [Coupon filters](./coupons.md) are available:\n\n- `coupons`\n- `showApplyCouponNotice`\n- `showRemoveCouponNotice`\n\n## Additional Cart and Checkout inner block types filter\n\nThe following [Additional Cart and Checkout inner block types filter](./additional-cart-checkout-inner-block-types.md) is available:\n\n- `additionalCartCheckoutInnerBlockTypes`\n\n## Combined filters\n\nFilters can also be combined. The following example shows how to combine some of the available filters.\n\n```tsx\nconst { registerCheckoutFilters } = window.wc.blocksCheckout;\n\nconst isOrderSummaryContext = ( args ) => args?.context === 'summary';\n\nconst modifyCartItemClass = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn 'my-custom-class';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyCartItemPrice = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '&lt;price/&gt; for all items';\n\t}\n\treturn defaultValue;\n};\n\nconst modifyItemName = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn `${ defaultValue }`;\n\t}\n\treturn defaultValue;\n};\n\nconst modifySubtotalPriceFormat = ( defaultValue, extensions, args ) => {\n\tif ( isOrderSummaryContext( args ) ) {\n\t\treturn '&lt;price/&gt; per item';\n\t}\n\treturn defaultValue;\n};\n\nregisterCheckoutFilters( 'example-extension', {\n\tcartItemClass: modifyCartItemClass,\n\tcartItemPrice: modifyCartItemPrice,\n\titemName: modifyItemName,\n\tsubtotalPriceFormat: modifySubtotalPriceFormat,\n} );\n```\n\n## Troubleshooting\n\nIf you are logged in to the store as an administrator, you should be shown an error like this if your filter is not\nworking correctly. The error will also be shown in your console.\n\n![Troubleshooting](https://woocommerce.com/wp-content/uploads/2023/10/Screenshot-2023-10-30-at-10.52.53.png)\n\n\n",
"category_slug": "cart-and-checkout-available-filters",
"category_title": "Available Filters",
"posts": [
@ -161,7 +161,7 @@
"menu_title": "Totals Footer Item",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
"hash": "3a9869d7d7beadb8117c100c3b58675e416e16386ee753f78e1a9087e768053f",
"hash": "6cf668422809b036dca7c1996ae907497a38631dd5bfb7e67d6bf3620425e411",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/totals-footer-item.md",
"id": "90a9b8df374082f1713866a58b810303adb4d3da"
},
@ -170,7 +170,7 @@
"menu_title": "Order Summary Items",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
"hash": "36f1bfa8d192b106d28d71334b42413d4c289a0a8d1f5b76b2f905d6fa453883",
"hash": "1796f53f3d67dd6b47fe8d7f67cbd69bddcaa6416bb5a0cc1a0fc99f42ea9d10",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/available-filters/order-summary-items.md",
"id": "78eb3b135f82a3624a49979e3e93334295abd060"
},
@ -223,7 +223,7 @@
"menu_title": "Payment Method Integration",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
"hash": "f60acaaea4a6ac4adf637bc7069c966e01db089f9dfaa937def91165a71a4255",
"hash": "138ffbf27e79ec8b35d2c46e87e3663c203d91fc9ba3f76c43f3cbe76258e5bf",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/cart-and-checkout-blocks/checkout-payment-methods/payment-method-integration.md",
"id": "c9a763b6976ecf03aeb961577c17c31f1ac7c420",
"links": {
@ -363,7 +363,7 @@
"menu_title": "Add link to logged data",
"tags": "code-snippets",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/link-to-logged-data.md",
"hash": "fd1c3a58da8b7eed11da841d901b4d3cc117c6753c3b3834f3de41ea266490b9",
"hash": "4e51c120a6ea7b14c0e43f11e8eb1b785e4447fbe2b997f5789f10b57c485137",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/link-to-logged-data.md",
"id": "34da337f79be5ce857024f541a99d302174ca37d"
},
@ -389,7 +389,7 @@
"menu_title": "Displaying custom fields in theme",
"tags": "code-snippet",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
"hash": "8048c2e9e5d25268d17d4f4ca7929e265eddbd4653318dd8f544856ddecd39dd",
"hash": "013acf9daaef92daf49e49315b2c0eba730b96adb8078eaab1146db4afc5270b",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/displaying_custom_fields_in_your_theme_or_site.md",
"id": "3e3fd004afda355cf9dbb05f0967523d6d0da1ce"
},
@ -405,7 +405,7 @@
"post_title": "Customizing checkout fields using actions and filters",
"tags": "code-snippet",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/customising-checkout-fields.md",
"hash": "8bbfe162402e484ae89427e1aedaed4faa57555b64b5a77ca800f701524314cb",
"hash": "ce63f640d5b91d85c3bbb80128d8a19e9c00d1c0e252abd4f958e29dcc1e60ce",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/customising-checkout-fields.md",
"id": "83097d3b7414557fc80dcf9f8f1a708bbdcdd884"
},
@ -414,7 +414,7 @@
"menu_title": "Configuring special tax scenarios",
"tags": "code-snippet, tax",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/configuring_special_tax_scenarios.md",
"hash": "acce5111eb917b7381d9bdcb260c72870e89d723195b86522050032741c5107c",
"hash": "c2459568db70b97d9a901c83eecb7737746499fe03cc84133aab3cf981b5c96a",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/configuring_special_tax_scenarios.md",
"id": "a8ab8b6734ba2ac5af7c6653635d15548abdab2a"
},
@ -439,7 +439,7 @@
"post_title": "Add a message above the login / register form",
"tags": "code-snippet",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/before-login--register-form.md",
"hash": "49f0d942364ea6815e799972894406cb0963164adfb6c373222dcf7fb0ee6fb9",
"hash": "dd3d61cd1f99d459956167041718e6a25693901a810d4bde47613d5ea2595ca3",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/before-login--register-form.md",
"id": "26ea2036f16952c8c965f2ab38ab214e421aa615"
},
@ -594,7 +594,7 @@
"post_title": "Contributing Technical Documentation",
"menu_title": "Contributing Docs",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/contributing-docs/contributing-docs.md",
"hash": "ee2eed4bc33ccbc4a84a2c73ee503f2df5a92183013e3f703bb439edab0a3fe3",
"hash": "6733ba23f82a6e784ef10e2862aa3afd8a61e32181e157f67ccabfc8354aa989",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/contributing-docs/contributing-docs.md",
"id": "71c1a72bfd4d5ae6aa656d4264b1bf3beb6eca1c"
}
@ -676,7 +676,7 @@
{
"post_title": "Settings API",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/settings-api.md",
"hash": "ca80728c56d60bb7416bb2865678b9e04807d0e208a4df56b8efaf32e9ac465d",
"hash": "9015453d8be72871bb26a450b86e542aa698c67b93284a04cd2b18008113bf43",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/settings-api.md",
"id": "ed56b97b9de350074a302373ebaaa5dcce727e8b"
},
@ -691,7 +691,7 @@
"post_title": "Integrating with coming soon mode",
"tags": "how-to, coming-soon",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/integrating-coming-soon-mode.md",
"hash": "910dbbab77c6fb4735e7704796242c38d86f3bf3b897de1075338eb47194f8f5",
"hash": "791cd6d3928b3aafc72a24d0283a404a90a0f021c7c36edaa445eb44978114a3",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/integrating-coming-soon-mode.md",
"id": "787743efb6ef0ad509b17735eaf58b2a9a08afbc"
},
@ -700,7 +700,7 @@
"menu_title": "Creating custom settings",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/implementing-settings.md",
"hash": "604d455f9e413c23a208c174ba25611c333e02eef0bafb0d38253f8dd8e3a04c",
"hash": "5cab83a84bb7eb11090bac244754fdae1f8aef1030850d12c29c09054c50bc61",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/implementing-settings.md",
"id": "58bcbd3a0cd3b3e5fe738c3bb625cf9b7747c99a"
},
@ -727,7 +727,7 @@
"menu_title": "Implement merchant onboarding",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/handling-merchant-onboarding.md",
"hash": "a34e2c637ac47adb1dd2e7b2510fb3eb7ff517b8f31e9cfa6fe4d3920f2567e7",
"hash": "85fc7d70f47fdb195ad2c690d3b95565169221f9e4d7afa98e88f3824ad0e267",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/handling-merchant-onboarding.md",
"id": "89fe15dc232379f546852822230c334d3d940b93"
},
@ -814,7 +814,7 @@
"menu_title": "Add custom product types to Add Products onboarding list",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
"hash": "60e50ef5d7e2ac6d0745c31031140df1dbb3c1b8724230cab1eaedebe3814688",
"hash": "92a8e17f2cd8dc32a78f03970ded1beec2fd60cadbf14c8cefcabbf7abae59c5",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/adding-custom-products-to-add-products-onboarding-list.md",
"id": "747321d7fd2eb5c9c3351ea38374dfc80d3ec968"
},
@ -861,7 +861,7 @@
"menu_title": "Troubleshooting Endpoints",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/troubleshooting-endpoints.md",
"hash": "1a015d82f4d82cc2d9f13f188f03c4e6e03b98ea9d22c5a7710547e7d3c8c78f",
"hash": "448bcd827ff44e9eb10d039bfd933cd63a37df05bd694bf80f9d9f978a3afdf5",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/troubleshooting-endpoints.md",
"id": "dff57bd736ae83850bfc7e4ac994bd22141d96ee",
"links": {
@ -874,7 +874,7 @@
"menu_title": "Development environment setup",
"tags": "tutorial, setup",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/development-environment.md",
"hash": "b9f56987247aee67eaa2c74d1059e1cadfd335fa81c77b76c0717648d5631c0f",
"hash": "bf5d77349ea64d1b8e19fe6b7472be35ed92406c5aafe677ce92363fb13f94d4",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/development-environment.md",
"id": "9080572a3904349c44c565ca7e1bef1212c58757"
},
@ -903,7 +903,7 @@
"menu_title": "Customizing Endpoint URLs",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/customizing-endpoint-urls.md",
"hash": "7feda75b07a1c11d533afabc7781abb80438ce2fa2c3fb37c173e1275098e720",
"hash": "364ed14d70c49498ba5017104b9c83743322d5095c215262d4311866a76181e5",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/customizing-endpoint-urls.md",
"id": "c19e1b1da6543f8a95ee04ba120f4f171f8e6e40",
"links": {
@ -939,7 +939,7 @@
"menu_title": "Enable HPOS for large stores",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/guide-large-store.md",
"hash": "8bcae74d27e3a4ee9a902719c7e8d5aec4a4d82d7c14acd8665a72b9d4758181",
"hash": "1e144ac0d0a7c869093533bf94a1f218a42930a3f3edcbcfdd1210448243a992",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/guide-large-store.md",
"id": "b6156ac7b77d75022867e9ebb968bc9c1c35f0da"
},
@ -956,7 +956,7 @@
"post_title": "HPOS CLI Tools",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/cli-tools.md",
"hash": "8cd823759ce20551d582c39f57ae79f9e0227a8cb0131146e6b7dac5e7312708",
"hash": "63e5edd55720c963de6700854515ea51946ff734b716ab61793955308b72af91",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/cli-tools.md",
"id": "cdd9d9ad5777d978ba953e3478fbb61cab8fdf59"
}
@ -1033,7 +1033,7 @@
"menu_title": "Performance best practices",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/performance/performance-best-practices.md",
"hash": "5af1f4e4085e85a1693390f40e238cbd6a4a0b7d5d304afdda935c34fed97c64",
"hash": "3c49b5553e99b64ecdbdad565866479f7af5e474dbbcc9aa36d711c02d8b0906",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/performance/performance-best-practices.md",
"id": "35bda1cd7068d6179a9e46cca8d7dc2694d0df96"
}
@ -1050,7 +1050,7 @@
"menu_title": "Registering custom collections",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/register-product-collection.md",
"hash": "e3df65c5eec52e4bb797e34c040dbb8f820ea6571e9ce50b1d518e95ca6cb169",
"hash": "6d32bc27924226b032e03624dbeedde3c899c2e8eb777a1fece93bed99544f03",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/register-product-collection.md",
"id": "3bf26fc7c56ae6e6a56e1171f750f5204fcfcece"
},
@ -1059,7 +1059,7 @@
"menu_title": "DOM Events",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-collection-block/dom-events.md",
"hash": "fbad20bc55cc569161e80478c0789db3c34cf35513e669554af36db1de967a26",
"hash": "85cffe1cc273621f16f7362b5efe28ede9689cee0a6e87d0d426014bacc24b05",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-collection-block/dom-events.md",
"id": "c8d247b91472740075871e6b57a9583d893ac650"
}
@ -1117,7 +1117,7 @@
{
"post_title": "Extending the product form with custom fields",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
"hash": "f0d0273c0d65739d605448492bfbe684f0ed33f9e6e274df06f26e83cb6ba341",
"hash": "dfa00ed71af6eda1f539684657d5c880850ececea4c07bd11e89a605fab77ec7",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-editor-development/how-to-guides/custom-field-tutorial.md",
"id": "fed80efbb225df9054fadd6e1fc45c2cd03e7f99"
}
@ -1229,7 +1229,7 @@
"menu_title": "Core critical flows",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/core-critical-flows.md",
"hash": "472f5a240abe907fec83a8a9f88af6699f2d994aa7ae87faa1716a087baa66db",
"hash": "34109195216ebcb5b23e741391b9f355ba861777a5533d4ef1e341472cb5209e",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/core-critical-flows.md",
"id": "e561b46694dba223c38b87613ce4907e4e14333a"
},
@ -1329,7 +1329,7 @@
"menu_title": "Extend analytics reports",
"tags": "how-to",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
"hash": "b694b0e857d3ca60acdef2ffaae329a93f0a0243eacc4b192562c7f507f169b3",
"hash": "56712b3583d0b0a4d96eb19153e5abcb8a386fcd083fa56481acf1be530afa25",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
"id": "3ef20148084c97d7f62b565b92df844392ac27f7"
},
@ -1411,7 +1411,7 @@
"categories": []
},
{
"content": "\nProperly setting up your test environment and writing tests when contributing to WooCommrece core are essential parts of our development pipeline. The links below are also included in our [Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) on GitHub.\n\nIf you have any questions about testing please reach out to the developer community in our public channels([Developer Blog](https://developer.woocommerce.com/blog/), [GitHub Discussions](https://github.com/woocommerce/woocommerce/discussions), or [Community Slack](https://woocommerce.com/community-slack/)).\n\n## Unit Testing\n\n[End-to-end tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e-pw) are powered by `Playwright`. The test site is spun up using `wp-env` ([recommended](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/)), but we will continue to support `e2e-environment` in the meantime, and slowly [deprecate](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md) `Puppeteer` testing. \n\n## API Testing\n\n`api-core-tests` is a [package](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/api-core-tests#guide-for-writing-api-tests) that contains automated API tests for WooCommerce, based on `Playwright` and `wp-env`. It supersedes the SuperTest based `api-core-tests` package and `e2e-environment` setup, which we will gradually deprecate.\n\n## Calls for Testing\n\nKeep tabs on calls for testing on our developer blog, and make sure to read our beta testing instructions to help us build new features and enhancements.\n",
"content": "\nProperly setting up your test environment and writing tests when contributing to WooCommerce core are essential parts of our development pipeline. The links below are also included in our [Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) on GitHub.\n\nIf you have any questions about testing please reach out to the developer community in our public channels([Developer Blog](https://developer.woocommerce.com/blog/), [GitHub Discussions](https://github.com/woocommerce/woocommerce/discussions), or [Community Slack](https://woocommerce.com/community-slack/)).\n\n## Unit Testing\n\n[End-to-end tests](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/e2e-pw) are powered by `Playwright`. The test site is spun up using `wp-env` ([recommended](https://developer.wordpress.org/block-editor/reference-guides/packages/packages-env/)), but we will continue to support `e2e-environment` in the meantime, and slowly [deprecate](https://github.com/woocommerce/woocommerce/blob/trunk/plugins/woocommerce/tests/e2e/README.md) `Puppeteer` testing. \n\n## API Testing\n\n`api-core-tests` is a [package](https://github.com/woocommerce/woocommerce/tree/trunk/plugins/woocommerce/tests/api-core-tests#guide-for-writing-api-tests) that contains automated API tests for WooCommerce, based on `Playwright` and `wp-env`. It supersedes the SuperTest based `api-core-tests` package and `e2e-environment` setup, which we will gradually deprecate.\n\n## Calls for Testing\n\nKeep tabs on calls for testing on our developer blog, and make sure to read our beta testing instructions to help us build new features and enhancements.\n",
"category_slug": "testing",
"category_title": "Testing",
"posts": [
@ -1451,7 +1451,7 @@
{
"post_title": "Template structure & Overriding templates via a theme",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/template-structure.md",
"hash": "ff781eff7998ea93723f644bddd4f6da6f73c635bcfc3cd46950f03a8b83b26c",
"hash": "a82d885c8395385dc51c976b2b51eec88cdcce72bf905fda78f97d77533ce079",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/template-structure.md",
"id": "34bfebec9fc45e680976814928a7b8a1778af14e"
},
@ -1498,7 +1498,7 @@
"post_title": "Classic theme development handbook",
"menu_title": "Classic theme development",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/classic-theme-developer-handbook.md",
"hash": "1194437fbc2ec82d60c8b73a9742ec650bd90fe734758c3a2b27ed852d4d14f7",
"hash": "95ce7250479a5133bba6c68939d86e4e79708c65044d70727c73f6a88f716da7",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/classic-theme-developer-handbook.md",
"id": "c2fde53e1dc3efbded3cfe1fb4df27136a3799a4"
}
@ -1554,7 +1554,7 @@
"post_title": "WooCommerce Extension Guidelines - Navigation",
"menu_title": "Navigation",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/ux-guidelines-extensions/navigation.md",
"hash": "f14cbd3750451934d173ec43aa996067699bdd8fc05f5c34097d1967a79145db",
"hash": "9c5313a31ebe26909a2cfaaa0bcfcdc9d5a0855ac0ddb9808832524be313ebb6",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/ux-guidelines-extensions/navigation.md",
"id": "9922abbcea787a91b3360f49fa53d5402a604e6b"
},
@ -1775,7 +1775,7 @@
"menu_title": "Commands",
"tags": "reference",
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/wc-cli/wc-cli-commands.md",
"hash": "a926ff45642539e0edc6b4e3dfeba4b31c2d01082700af132a2e8d56cfa25ec5",
"hash": "17bbb18fd0ad0523a5b864f74acbec64c853ae7b42ecd7e6d9dbce1fbe2669aa",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/wc-cli/wc-cli-commands.md",
"id": "73d6bc6468d23a9e93d16d574399105b143e43af"
},
@ -1804,5 +1804,5 @@
"categories": []
}
],
"hash": "2ecf48b6181dae0526b3858df889bce4e6ee425e10f2c43d151771d845c5a948"
"hash": "47dc2a7e213e1e9d83e93a85dafdf8c7b539cc5474b4166eb6398b734d150ff3"
}

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

@ -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,8 +49,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 );
}
}
```
@ -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' );`

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

@ -27,3 +27,27 @@ window.document.addEventListener(
}
);
```
## 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

@ -6,20 +6,20 @@ 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).
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:
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:
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({
@ -36,7 +36,7 @@ We will explain important arguments that can be passed to `__experimentalRegiste
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 `<plugin-name>/product-collection/<collection-name>`. Both `<plugin-name>` and `<collection-name>` should consist only of alphanumeric characters and hyphens (e.g., `my-plugin/product-collection/my-collection`).
- `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.
@ -113,7 +113,7 @@ __experimentalRegisterProductCollection({
});
```
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:
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

View File

@ -62,7 +62,7 @@ In React:
import { registerBlockType } from '@wordpress/blocks';
function Edit() {
return <p>Hello World (from the editor).</p>;
return &lt;p&gt;Hello World (from the editor).&lt;/p&gt;;
}
registerBlockType( 'tutorial/new-product-form-field', {
@ -217,8 +217,8 @@ function Edit( { attributes } ) {
const blockProps = useWooBlockProps( attributes );
return (
<div { ...blockProps }>
<ComboboxControl
&lt;div { ...blockProps }&gt;
&lt;ComboboxControl
label="Example dropdown"
value={ value }
onChange={ setValue }
@ -232,8 +232,8 @@ function Edit( { attributes } ) {
)
)
}
/>
</div>
/&gt;
&lt;/div&gt;
);
}
```

View File

@ -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

@ -32,7 +32,7 @@ npm run create-wc-extension
After choosing a name, move into that folder and start webpack to watch and build files.
```sh
cd ../<my-plugin-name>
cd ../&lt;my-plugin-name&gt;
npm install
npm start
```

View File

@ -4,7 +4,7 @@ category_slug: testing
post_title: Testing
---
Properly setting up your test environment and writing tests when contributing to WooCommrece core are essential parts of our development pipeline. The links below are also included in our [Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) on GitHub.
Properly setting up your test environment and writing tests when contributing to WooCommerce core are essential parts of our development pipeline. The links below are also included in our [Contributing Guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) on GitHub.
If you have any questions about testing please reach out to the developer community in our public channels([Developer Blog](https://developer.woocommerce.com/blog/), [GitHub Discussions](https://github.com/woocommerce/woocommerce/discussions), or [Community Slack](https://woocommerce.com/community-slack/)).

View File

@ -73,11 +73,11 @@ add_action('woocommerce_before_main_content', 'my_theme_wrapper_start', 10);
add_action('woocommerce_after_main_content', 'my_theme_wrapper_end', 10);
function my_theme_wrapper_start() {
echo '<section id="main">';
echo '&lt;section id="main"&gt;';
}
function my_theme_wrapper_end() {
echo '</section>';
echo '&lt;/section&gt;';
}
```

View File

@ -22,7 +22,7 @@ Below is video walkthrough showing how one may go about updating the template fi
## Template list
The various template files on your WooCommerce site can be found via an FTP client or your hosts file manager, in `/wp-content/plugins/woocommerce/templates/`. Below are links to the current and earlier versions of the WooCommerce template files on Github, where you can view the code exactly as it appears in those files:
The various template files on your WooCommerce site can be found via an FTP client or your hosts file manager, in `/wp-content/plugins/woocommerce/templates/`. Below are links to the current and earlier versions of the WooCommerce template files on Github, where you can view the code exactly as it appears in those files:
| Latest Version | Files |
| -------------- | ----- |
@ -96,7 +96,7 @@ Below are the links to the files of all major previous WooCommerce versions:
## Changing Templates via Hooks
When you open a template file, you will notice they all contain _hooks_ that allow you to add/move content without needing to edit template files themselves. Hooks are a way for one piece of code to interact/modify another piece of code at specific, pre-defined spots. This method allows implementing a code snippet that “hooks” into a particular a theme location. It avoids upgrade issues, as the template files can be left completely untouched and doesn't require a child theme to be configured.
When you open a template file, you will notice they all contain _hooks_ that allow you to add/move content without needing to edit template files themselves. Hooks are a way for one piece of code to interact/modify another piece of code at specific, pre-defined spots. This method allows implementing a code snippet that "hooks" into a particular a theme location. It avoids upgrade issues, as the template files can be left completely untouched and doesn't require a child theme to be configured.
Let's take a look at [/wp-content/plugins/woocommerce/templates/emails/admin-new-order.php](https://github.com/woocommerce/woocommerce/blob/8.9.0/plugins/woocommerce/templates/emails/admin-new-order.php) and see what a hook looks like. Starting on line 30, we see the following code, which is responsible for producing the order details section of the New Order email.
@ -137,7 +137,7 @@ The copied file will now override the WooCommerce default template file, so you
---
**Note** A (desirable) side-effect of your templates being upgrade-safe is that WooCommerce core templates will update, but your custom overrides will not. You may occassionally see notices in your System Status report that says, e.g. “version 3.5.0 is out of date. The core version is 3.7.0″. Should that happen, follow the Fixing Outdated WooCommerce Templates guide to bring them in line.
**Note** A (desirable) side-effect of your templates being upgrade-safe is that WooCommerce core templates will update, but your custom overrides will not. You may occassionally see notices in your System Status report that says, e.g. "version 3.5.0 is out of date. The core version is 3.7.0". Should that happen, follow the Fixing Outdated WooCommerce Templates guide to bring them in line.
---

View File

@ -7,10 +7,7 @@ menu_title: Navigation
Examples:
- If your extension is extending a component within WooCommerce, it should live within either the Extensions navigation drawer (in Woo Express stores), or directly within that category's section.
Extensions drawer (Woo Express)
![Navigation extensions drawer](https://developer.woocommerce.com/docs/wp-content/uploads/sites/3/2024/01/Image-1224x572-1.png)
- If your extension is extending a component within WooCommerce, it should live directly within that category's section.
![Navigation category](https://developer.woocommerce.com/docs/wp-content/uploads/sites/3/2024/01/Image-1242x764-1.png)

View File

@ -117,7 +117,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc customer_download
#### wc customer_download list <customer_id>
#### wc customer_download list &lt;customer_id&gt;
- `--customer_id` - Unique identifier for the resource.
- `--context` - Scope under which the request is made; determines fields present in response.
@ -198,7 +198,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc order_note
#### wc order_note list <order_id>
#### wc order_note list &lt;order_id&gt;
- `--order_id` - The order ID.
- `--context` - Scope under which the request is made; determines fields present in response.
@ -211,14 +211,14 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc order_note create <order_id>
#### wc order_note create &lt;order_id&gt;
- `--order_id` - The order ID.
- `--note` - Order note content. (*Required*)
- `--customer_note` - If true, the note will be shown to customers and they will be notified. If false, the note will be for admin reference only.
- `--porcelain` - Output just the id when the operation is successful.
#### wc order_note get <order_id> [id]
#### wc order_note get &lt;order_id&gt; [id]
- `--id` - Unique identifier for the resource.
- `--order_id` - The order ID.
@ -231,7 +231,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc order_note delete <order_id> [id]
#### wc order_note delete &lt;order_id&gt; [id]
- `--id` - Unique identifier for the resource.
- `--order_id` - The order ID.
@ -240,7 +240,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc shop_order_refund
#### wc shop_order_refund list <order_id>
#### wc shop_order_refund list &lt;order_id&gt;
- `--order_id` - The order ID.
- `--context` - Scope under which the request is made; determines fields present in response.
@ -265,7 +265,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc shop_order_refund create <order_id>
#### wc shop_order_refund create &lt;order_id&gt;
- `--order_id` - The order ID.
- `--amount` - Refund amount.
@ -276,7 +276,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--api_refund` - When true, the payment gateway API is used to generate the refund.
- `--porcelain` - Output just the id when the operation is successful.
#### wc shop_order_refund get <order_id> [id]
#### wc shop_order_refund get &lt;order_id&gt; [id]
- `--order_id` - The order ID.
- `--id` - Unique identifier for the resource.
@ -289,7 +289,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc shop_order_refund delete <order_id> [id]
#### wc shop_order_refund delete &lt;order_id&gt; [id]
- `--order_id` - The order ID.
- `--id` - Unique identifier for the resource.
@ -386,7 +386,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc product_attribute_term
#### wc product_attribute_term list <attribute_id>
#### wc product_attribute_term list &lt;attribute_id&gt;
- `--attribute_id` - Unique identifier for the attribute of the terms.
- `--context` - Scope under which the request is made; determines fields present in response.
@ -409,7 +409,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_attribute_term create <attribute_id>
#### wc product_attribute_term create &lt;attribute_id&gt;
- `--attribute_id` - Unique identifier for the attribute of the terms.
- `--name` - Name for the resource. (*Required*)
@ -418,7 +418,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--menu_order` - Menu order, used to custom sort the resource.
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_attribute_term get <attribute_id> [id]
#### wc product_attribute_term get &lt;attribute_id&gt; [id]
- `--id` - Unique identifier for the resource.
- `--attribute_id` - Unique identifier for the attribute of the terms.
@ -431,7 +431,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_attribute_term update <attribute_id> [id]
#### wc product_attribute_term update &lt;attribute_id&gt; [id]
- `--id` - Unique identifier for the resource.
- `--attribute_id` - Unique identifier for the attribute of the terms.
@ -441,7 +441,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--menu_order` - Menu order, used to custom sort the resource.
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_attribute_term delete <attribute_id> [id]
#### wc product_attribute_term delete &lt;attribute_id&gt; [id]
- `--id` - Unique identifier for the resource.
- `--attribute_id` - Unique identifier for the attribute of the terms.
@ -565,7 +565,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc product_review
#### wc product_review list <product_id>
#### wc product_review list &lt;product_id&gt;
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the variation.
@ -578,7 +578,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_review create <product_id>
#### wc product_review create &lt;product_id&gt;
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the variation.
@ -590,7 +590,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--email` - Email of the reviewer. (*Required*)
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_review get <product_id> [id]
#### wc product_review get &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the resource.
@ -603,7 +603,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_review update <product_id> [id]
#### wc product_review update &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the resource.
@ -615,7 +615,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--email` - Reviewer email.
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_review delete <product_id> [id]
#### wc product_review delete &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the resource.
@ -893,7 +893,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
### wc product_variation
#### wc product_variation list <product_id>
#### wc product_variation list &lt;product_id&gt;
- `--product_id` - Unique identifier for the variable product.
- `--context` - Scope under which the request is made; determines fields present in response.
@ -932,7 +932,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_variation create <product_id>
#### wc product_variation create &lt;product_id&gt;
- `--product_id` - Unique identifier for the variable product.
- `--description` - Variation description.
@ -964,7 +964,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--meta_data` - Meta data.
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_variation get <product_id> [id]
#### wc product_variation get &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the variation.
@ -977,7 +977,7 @@ Default: table
Options: table, json, csv, ids, yaml, count, headers, body, envelope
#### wc product_variation update <product_id> [id]
#### wc product_variation update &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the variation.
@ -1010,7 +1010,7 @@ Options: table, json, csv, ids, yaml, count, headers, body, envelope
- `--meta_data` - Meta data.
- `--porcelain` - Output just the id when the operation is successful.
#### wc product_variation delete <product_id> [id]
#### wc product_variation delete &lt;product_id&gt; [id]
- `--product_id` - Unique identifier for the variable product.
- `--id` - Unique identifier for the variation.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: update
Update storybook file format in support with Storybook 7 story indexer.

View File

@ -132,18 +132,10 @@
"devDependencies": {
"@babel/core": "^7.23.5",
"@babel/runtime": "^7.23.5",
"@storybook/addon-actions": "6.5.17-alpha.0",
"@storybook/addon-console": "^1.2.3",
"@storybook/addon-controls": "6.5.17-alpha.0",
"@storybook/addon-docs": "6.5.17-alpha.0",
"@storybook/addon-knobs": "^6.4.0",
"@storybook/addon-links": "6.5.17-alpha.0",
"@storybook/addons": "6.5.17-alpha.0",
"@storybook/api": "6.5.17-alpha.0",
"@storybook/components": "6.5.17-alpha.0",
"@storybook/core-events": "6.5.17-alpha.0",
"@storybook/addon-docs": "7.6.19",
"@storybook/addon-links": "7.6.19",
"@storybook/react": "6.5.17-alpha.0",
"@storybook/theming": "6.5.17-alpha.0",
"@testing-library/dom": "8.11.3",
"@testing-library/jest-dom": "5.16.2",
"@testing-library/react": "12.1.3",

View File

@ -7,7 +7,7 @@ import { createElement } from '@wordpress/element';
/**
* Internal dependencies
*/
import { Basic } from '../stories/index';
import { Basic } from '../stories/compare-filter.story';
import { CompareFilter } from '../index';
import Search from '../../search';
import productAutocompleter from '../../search/autocompleters/product';

View File

@ -8,7 +8,7 @@ import { createElement } from '@wordpress/element';
/**
* Internal dependencies
*/
import { Basic } from '../stories/index';
import { Basic } from '../stories/filter-picker.story';
import FilterPicker from '../index';
import Search from '../../search';
import productAutocompleter from '../../search/autocompleters/product';

View File

@ -0,0 +1,116 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import React from 'react';
/**
* Internal dependencies
*/
import { ImageGallery, ImageGalleryItem } from '../';
import { MockMediaUpload } from '../../media-uploader/stories/mock-media-uploader';
export const Basic: React.FC = () => {
return (
<ImageGallery
MediaUploadComponent={ MockMediaUpload }
onReplace={ ( { replaceIndex } ) =>
// eslint-disable-next-line no-console
console.info( `Item ${ replaceIndex } replaced` )
}
onRemove={ ( { removeIndex } ) => {
// eslint-disable-next-line no-console
console.info( `Item ${ removeIndex } removed` );
} }
onOrderChange={ () => {
// eslint-disable-next-line no-console
console.info( `Order changed` );
} }
>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
<ImageGalleryItem
alt="Random image 3"
src="https://picsum.photos/id/24/200/200"
/>
<ImageGalleryItem
alt="Random image 4"
src="https://picsum.photos/id/58/200/200"
/>
<ImageGalleryItem
alt="Random image 5"
src="https://picsum.photos/id/309/200/200"
/>
<ImageGalleryItem
alt="Random image 6"
src="https://picsum.photos/id/46/200/200"
/>
<ImageGalleryItem
alt="Random image 7"
src="https://picsum.photos/id/8/200/200"
/>
<ImageGalleryItem
alt="Random image 8"
src="https://picsum.photos/id/101/200/200"
/>
</ImageGallery>
);
};
export const Cover: React.FC = () => {
return (
<ImageGallery MediaUploadComponent={ MockMediaUpload }>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
isCover
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
</ImageGallery>
);
};
export const Columns: React.FC = () => {
return (
<ImageGallery columns={ 3 } MediaUploadComponent={ MockMediaUpload }>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
<ImageGalleryItem
alt="Random image 3"
src="https://picsum.photos/id/24/200/200"
/>
<ImageGalleryItem
alt="Random image 4"
src="https://picsum.photos/id/58/200/200"
/>
<ImageGalleryItem
alt="Random image 5"
src="https://picsum.photos/id/309/200/200"
/>
<ImageGalleryItem
alt="Random image 6"
src="https://picsum.photos/id/46/200/200"
/>
</ImageGallery>
);
};
export default {
title: 'WooCommerce Admin/components/ImageGallery',
component: ImageGallery,
};

View File

@ -1,116 +0,0 @@
/**
* External dependencies
*/
import { createElement } from '@wordpress/element';
import React from 'react';
/**
* Internal dependencies
*/
import { ImageGallery, ImageGalleryItem } from '../';
import { MockMediaUpload } from '../../media-uploader/stories/index.tsx';
export const Basic: React.FC = () => {
return (
<ImageGallery
MediaUploadComponent={ MockMediaUpload }
onReplace={ ( { replaceIndex } ) =>
// eslint-disable-next-line no-console
console.info( `Item ${ replaceIndex } replaced` )
}
onRemove={ ( { removeIndex } ) => {
// eslint-disable-next-line no-console
console.info( `Item ${ removeIndex } removed` );
} }
onOrderChange={ () => {
// eslint-disable-next-line no-console
console.info( `Order changed` );
} }
>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
<ImageGalleryItem
alt="Random image 3"
src="https://picsum.photos/id/24/200/200"
/>
<ImageGalleryItem
alt="Random image 4"
src="https://picsum.photos/id/58/200/200"
/>
<ImageGalleryItem
alt="Random image 5"
src="https://picsum.photos/id/309/200/200"
/>
<ImageGalleryItem
alt="Random image 6"
src="https://picsum.photos/id/46/200/200"
/>
<ImageGalleryItem
alt="Random image 7"
src="https://picsum.photos/id/8/200/200"
/>
<ImageGalleryItem
alt="Random image 8"
src="https://picsum.photos/id/101/200/200"
/>
</ImageGallery>
);
};
export const Cover: React.FC = () => {
return (
<ImageGallery MediaUploadComponent={ MockMediaUpload }>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
isCover
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
</ImageGallery>
);
};
export const Columns: React.FC = () => {
return (
<ImageGallery columns={ 3 } MediaUploadComponent={ MockMediaUpload }>
<ImageGalleryItem
alt="Random image 1"
src="https://picsum.photos/id/137/200/200"
/>
<ImageGalleryItem
alt="Random image 2"
src="https://picsum.photos/id/208/200/200"
/>
<ImageGalleryItem
alt="Random image 3"
src="https://picsum.photos/id/24/200/200"
/>
<ImageGalleryItem
alt="Random image 4"
src="https://picsum.photos/id/58/200/200"
/>
<ImageGalleryItem
alt="Random image 5"
src="https://picsum.photos/id/309/200/200"
/>
<ImageGalleryItem
alt="Random image 6"
src="https://picsum.photos/id/46/200/200"
/>
</ImageGallery>
);
};
export default {
title: 'WooCommerce Admin/components/ImageGallery',
component: ImageGallery,
};

View File

@ -1,216 +0,0 @@
/**
* External dependencies
*/
import React, { createElement } from 'react';
import { Modal, Notice } from '@wordpress/components';
import { MediaItem } from '@wordpress/media-utils';
import { useState } from '@wordpress/element';
import { cloudUpload } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { MediaUploader } from '../';
import { File } from '../types';
const MockMediaUpload = ( { onSelect, render } ) => {
const [ isOpen, setOpen ] = useState( false );
return (
<>
{ render( {
open: () => setOpen( true ),
} ) }
{ isOpen && (
<Modal
title="Media Modal"
onRequestClose={ ( event ) => {
setOpen( false );
event.stopPropagation();
} }
>
<p>
Use the default built-in{ ' ' }
<code>MediaUploadComponent</code> prop to render the WP
Media Modal.
</p>
{ Array( ...Array( 3 ) ).map( ( n, i ) => {
return (
<button
key={ i }
onClick={ ( event ) => {
onSelect( {
alt: 'Random',
url: `https://picsum.photos/200?i=${ i }`,
} );
setOpen( false );
event.stopPropagation();
} }
style={ {
marginRight: '16px',
} }
>
<img
src={ `https://picsum.photos/200?i=${ i }` }
alt="Random"
style={ {
maxWidth: '100px',
} }
/>
</button>
);
} ) }
</Modal>
) }
</>
);
};
const ImageGallery = ( { images }: { images: File[] } ) => {
return (
<div style={ { marginBottom: '16px' } }>
{ images.map( ( image, index ) => {
return (
<img
key={ index }
alt={ image.alt }
src={ image.url }
style={ {
maxWidth: '100px',
marginRight: '16px',
} }
/>
);
} ) }
</div>
);
};
const readImage = ( file: Blob ) => {
return new Promise< MediaItem >( ( resolve ) => {
const fileReader = new FileReader();
fileReader.onload = function ( event ) {
const image = {
alt: 'Temporary image',
url: event?.target?.result,
} as MediaItem;
resolve( image );
};
fileReader.readAsDataURL( file );
} );
};
const mockUploadMedia = async ( { filesList, onFileChange } ) => {
// The values sent by the FormFileUpload and the DropZone components are different.
// This is why we need to transform everything into an array.
const list = await Object.keys( filesList ).map(
( key ) => filesList[ key ]
);
const images = await Promise.all(
list.map( ( file ) => {
if ( typeof file === 'object' ) {
return readImage( file );
}
return {};
} )
);
onFileChange( images );
};
export const Basic: React.FC = () => {
const [ images, setImages ] = useState< File[] >( [] );
return (
<>
<ImageGallery images={ images } />
<MediaUploader
MediaUploadComponent={ MockMediaUpload }
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
onError={ () => null }
onFileUploadChange={ ( files ) =>
setImages( [ ...images, ...files ] )
}
onUpload={ ( files ) => setImages( [ ...images, ...files ] ) }
uploadMedia={ mockUploadMedia }
/>
</>
);
};
export const DisabledDropZone: React.FC = () => {
const [ images, setImages ] = useState< File[] >( [] );
return (
<>
<ImageGallery images={ images } />
<MediaUploader
hasDropZone={ false }
label={ 'Click the button below to upload' }
MediaUploadComponent={ MockMediaUpload }
onFileUploadChange={ ( files ) =>
setImages( [ ...images, ...files ] )
}
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
onError={ () => null }
uploadMedia={ mockUploadMedia }
/>
</>
);
};
export const MaxUploadFileSize: React.FC = () => {
const [ error, setError ] = useState< string | null >( null );
return (
<>
{ error && (
<Notice isDismissible={ false } status={ 'error' }>
{ error }
</Notice>
) }
<MediaUploader
maxUploadFileSize={ 1000 }
MediaUploadComponent={ MockMediaUpload }
onSelect={ () => null }
onError={ ( e ) => setError( e.message ) }
onUpload={ () => null }
/>
</>
);
};
export const ButtonWithOnlyIcon: React.FC = () => {
const [ error, setError ] = useState< string | null >( null );
return (
<>
{ error && (
<Notice isDismissible={ false } status={ 'error' }>
{ error }
</Notice>
) }
<MediaUploader
maxUploadFileSize={ 1000 }
buttonProps={ {
icon: cloudUpload,
iconSize: 32,
variant: 'tertiary',
'aria-label': 'Upload media',
} }
buttonText=""
MediaUploadComponent={ MockMediaUpload }
onSelect={ () => null }
onError={ ( e ) => setError( e.message ) }
onUpload={ () => null }
/>
</>
);
};
export default {
title: 'WooCommerce Admin/components/MediaUploader',
component: Basic,
};

View File

@ -0,0 +1,164 @@
/**
* External dependencies
*/
import React, { createElement } from 'react';
import { Notice } from '@wordpress/components';
import { MediaItem } from '@wordpress/media-utils';
import { useState } from '@wordpress/element';
import { cloudUpload } from '@wordpress/icons';
/**
* Internal dependencies
*/
import { MediaUploader } from '../';
import { File } from '../types';
import { MockMediaUpload } from './mock-media-uploader';
const ImageGallery = ( { images }: { images: File[] } ) => {
return (
<div style={ { marginBottom: '16px' } }>
{ images.map( ( image, index ) => {
return (
<img
key={ index }
alt={ image.alt }
src={ image.url }
style={ {
maxWidth: '100px',
marginRight: '16px',
} }
/>
);
} ) }
</div>
);
};
const readImage = ( file: Blob ) => {
return new Promise< MediaItem >( ( resolve ) => {
const fileReader = new FileReader();
fileReader.onload = function ( event ) {
const image = {
alt: 'Temporary image',
url: event?.target?.result,
} as MediaItem;
resolve( image );
};
fileReader.readAsDataURL( file );
} );
};
const mockUploadMedia = async ( { filesList, onFileChange } ) => {
// The values sent by the FormFileUpload and the DropZone components are different.
// This is why we need to transform everything into an array.
const list = await Object.keys( filesList ).map(
( key ) => filesList[ key ]
);
const images = await Promise.all(
list.map( ( file ) => {
if ( typeof file === 'object' ) {
return readImage( file );
}
return {};
} )
);
onFileChange( images );
};
export const Basic: React.FC = () => {
const [ images, setImages ] = useState< File[] >( [] );
return (
<>
<ImageGallery images={ images } />
<MediaUploader
MediaUploadComponent={ MockMediaUpload }
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
onError={ () => null }
onFileUploadChange={ ( files ) =>
setImages( [ ...images, ...files ] )
}
onUpload={ ( files ) => setImages( [ ...images, ...files ] ) }
uploadMedia={ mockUploadMedia }
/>
</>
);
};
export const DisabledDropZone: React.FC = () => {
const [ images, setImages ] = useState< File[] >( [] );
return (
<>
<ImageGallery images={ images } />
<MediaUploader
hasDropZone={ false }
label={ 'Click the button below to upload' }
MediaUploadComponent={ MockMediaUpload }
onFileUploadChange={ ( files ) =>
setImages( [ ...images, ...files ] )
}
onSelect={ ( file ) => setImages( [ ...images, file ] ) }
onError={ () => null }
uploadMedia={ mockUploadMedia }
/>
</>
);
};
export const MaxUploadFileSize: React.FC = () => {
const [ error, setError ] = useState< string | null >( null );
return (
<>
{ error && (
<Notice isDismissible={ false } status={ 'error' }>
{ error }
</Notice>
) }
<MediaUploader
maxUploadFileSize={ 1000 }
MediaUploadComponent={ MockMediaUpload }
onSelect={ () => null }
onError={ ( e ) => setError( e.message ) }
onUpload={ () => null }
/>
</>
);
};
export const ButtonWithOnlyIcon: React.FC = () => {
const [ error, setError ] = useState< string | null >( null );
return (
<>
{ error && (
<Notice isDismissible={ false } status={ 'error' }>
{ error }
</Notice>
) }
<MediaUploader
maxUploadFileSize={ 1000 }
buttonProps={ {
icon: cloudUpload,
iconSize: 32,
variant: 'tertiary',
'aria-label': 'Upload media',
} }
buttonText=""
MediaUploadComponent={ MockMediaUpload }
onSelect={ () => null }
onError={ ( e ) => setError( e.message ) }
onUpload={ () => null }
/>
</>
);
};
export default {
title: 'WooCommerce Admin/components/MediaUploader',
component: Basic,
};

View File

@ -0,0 +1,59 @@
/**
* External dependencies
*/
import React, { createElement } from 'react';
import { Modal } from '@wordpress/components';
import { useState } from '@wordpress/element';
export const MockMediaUpload = ( { onSelect, render } ) => {
const [ isOpen, setOpen ] = useState( false );
return (
<>
{ render( {
open: () => setOpen( true ),
} ) }
{ isOpen && (
<Modal
title="Media Modal"
onRequestClose={ ( event ) => {
setOpen( false );
event.stopPropagation();
} }
>
<p>
Use the default built-in{ ' ' }
<code>MediaUploadComponent</code> prop to render the WP
Media Modal.
</p>
{ Array( ...Array( 3 ) ).map( ( n, i ) => {
return (
<button
key={ i }
onClick={ ( event ) => {
onSelect( {
alt: 'Random',
url: `https://picsum.photos/200?i=${ i }`,
} );
setOpen( false );
event.stopPropagation();
} }
style={ {
marginRight: '16px',
} }
>
<img
src={ `https://picsum.photos/200?i=${ i }` }
alt="Random"
style={ {
maxWidth: '100px',
} }
/>
</button>
);
} ) }
</Modal>
) }
</>
);
};

View File

@ -11,7 +11,12 @@ import {
} from '@wordpress/element';
import { SyntheticEvent, useCallback } from 'react';
import { useDispatch, useSelect } from '@wordpress/data';
import { PLUGINS_STORE_NAME, InstallPluginsResponse } from '@woocommerce/data';
import { PLUGINS_STORE_NAME } from '@woocommerce/data';
import type {
InstallPluginsResponse,
PluginSelectors,
PluginActions,
} from '@woocommerce/data';
type PluginsProps = {
onComplete: (
@ -52,10 +57,14 @@ export const Plugins = ( {
const [ hasErrors, setHasErrors ] = useState( false );
// Tracks action so that multiple instances of this button don't all light up when one is clicked
const [ hasBeenClicked, setHasBeenClicked ] = useState( false );
const { installAndActivatePlugins } = useDispatch( PLUGINS_STORE_NAME );
const { installAndActivatePlugins }: PluginActions =
useDispatch( PLUGINS_STORE_NAME );
const { isRequesting } = useSelect( ( select ) => {
const { getActivePlugins, getInstalledPlugins, isPluginsRequesting } =
select( PLUGINS_STORE_NAME );
const {
getActivePlugins,
getInstalledPlugins,
isPluginsRequesting,
}: PluginSelectors = select( PLUGINS_STORE_NAME );
return {
isRequesting:
@ -64,7 +73,7 @@ export const Plugins = ( {
activePlugins: getActivePlugins(),
installedPlugins: getInstalledPlugins(),
};
} );
}, [] );
const handleErrors = useCallback(
( errors: unknown, response: InstallPluginsResponse ) => {

View File

@ -13,7 +13,7 @@ import { useDispatch } from '@wordpress/data';
import { Plugins } from '../index';
jest.mock( '@wordpress/data', () => ( {
...jest.requireActual( '@wordpress/data' ),
__esModule: true,
useDispatch: jest
.fn()
.mockReturnValue( { installAndActivatePlugins: jest.fn() } ),

View File

@ -12,7 +12,6 @@ import * as actions from './actions';
import { STORE_NAME } from './constants';
export const store = createReduxStore( STORE_NAME, {
// @ts-expect-error reducer has correct format.
reducer,
selectors,
actions,

View File

@ -8,6 +8,7 @@ export type ProductFieldDefinition = {
type?: HTMLInputTypeAttribute;
// eslint-disable-next-line @typescript-eslint/no-explicit-any
render?: ComponentType;
attributes?: Record< string, string >;
};
export type ProductFieldState = {

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