Merge branch 'trunk' into update/breadcrumb-for-accessibility

This commit is contained in:
Joni Erkkilä 2023-10-14 09:28:42 +03:00
commit 4d133b4ca8
686 changed files with 16463 additions and 5681 deletions

View File

@ -1,6 +1,5 @@
name: Run API tests
description: Runs the WooCommerce Core API tests and generates Allure report.
permissions: {}
inputs:
report-name:
@ -8,6 +7,9 @@ inputs:
required: true
tests:
description: Specific tests to run, separated by single whitespace. See https://playwright.dev/docs/test-cli
playwright-config:
description: Playwright config file to be used
default: playwright.config.js
outputs:
result:
@ -23,7 +25,7 @@ runs:
shell: bash
run: |
pnpm exec playwright test \
--config=tests/api-core-tests/playwright.config.js \
--config=tests/api-core-tests/${{ inputs.playwright-config }} \
${{ inputs.tests }}
- name: Generate Test report.

View File

@ -67,11 +67,11 @@
'plugin: woo-ai':
- plugins/woo-ai/**/*
'focus: performance tests [team:Solaris]':
'focus: performance tests':
- plugins/woocommerce/tests/performance/**/*
'focus: api tests [team:Solaris]':
'focus: api tests':
- plugins/woocommerce/tests/api-core-tests/**/*
'focus: e2e tests [team:Solaris]':
'focus: e2e tests':
- plugins/woocommerce/tests/e2e-pw/**/*

View File

@ -294,6 +294,15 @@ jobs:
core.setOutput( 'cherry-pick-pr', pr.data.html_url )
// label PR
const label = await github.rest.issues.addLabels({
owner: context.repo.owner,
repo: context.repo.repo,
issue_number: pr.data.number,
labels: ["metric: code freeze exception"],
});
- name: Checkout trunk branch
if: steps.changelog.outputs.changelogsToBeDeleted != '' && steps.changelog.outputs.changelogsToBeDeleted != null
run: git checkout trunk

View File

@ -1,4 +1,4 @@
name: Run tests against PR in an environment with COT enabled
name: Run tests against PR in an environment with HPOS disabled
on:
pull_request:
workflow_dispatch:
@ -10,8 +10,8 @@ concurrency:
permissions: {}
jobs:
cot-e2e-tests-run:
name: Runs E2E tests with COT enabled.
non-hpos-e2e-tests-run:
name: Runs E2E tests with HPOS disabled.
runs-on: ubuntu-20.04
permissions:
contents: read
@ -24,11 +24,9 @@ jobs:
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
- name: Load docker images and start containers with COT enabled.
- name: Load docker images and start containers
working-directory: plugins/woocommerce
env:
ENABLE_HPOS: 1
run: pnpm env:test:cot --filter=woocommerce
run: pnpm env:test --filter=woocommerce
- name: Download and install Chromium browser.
working-directory: plugins/woocommerce
@ -39,6 +37,7 @@ jobs:
id: run_playwright_e2e_tests
env:
USE_WP_ENV: 1
ENABLE_HPOS: 0
working-directory: plugins/woocommerce
run: pnpm exec playwright test --config=tests/e2e-pw/playwright.config.js
@ -66,8 +65,8 @@ jobs:
if-no-files-found: ignore
retention-days: 5
cot-api-tests-run:
name: Runs API tests with COT enabled.
non-hpos-api-tests-run:
name: Runs API tests with HPOS disabled.
runs-on: ubuntu-20.04
permissions:
contents: read
@ -80,11 +79,9 @@ jobs:
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
- name: Load docker images and start containers with COT enabled.
- name: Load docker images and start containers
working-directory: plugins/woocommerce
env:
ENABLE_HPOS: 1
run: pnpm env:test:cot --filter=woocommerce
run: pnpm env:test --filter=woocommerce
- name: Run Playwright API tests.
id: run_playwright_api_tests
@ -93,6 +90,7 @@ jobs:
BASE_URL: http://localhost:8086
USER_KEY: admin
USER_SECRET: password
ENABLE_HPOS: 0
run: pnpm exec playwright test --config=tests/api-core-tests/playwright.config.js
- name: Generate Playwright API Test report.
@ -117,4 +115,4 @@ jobs:
${{ env.ALLURE_RESULTS_DIR }}
${{ env.ALLURE_REPORT_DIR }}
if-no-files-found: ignore
retention-days: 5
retention-days: 5

View File

@ -31,7 +31,6 @@ jobs:
- name: Load docker images and start containers.
working-directory: plugins/woocommerce
env:
ENABLE_HPOS: 0
WP_ENV_PHP_VERSION: 7.4
run: pnpm run env:test
@ -265,4 +264,4 @@ jobs:
-f pr_number=$PR_NUMBER \
-f commit_sha=$COMMIT_SHA \
-f s3_root=public \
--repo woocommerce/woocommerce-test-reports
--repo woocommerce/woocommerce-test-reports

View File

@ -155,16 +155,22 @@ jobs:
install-filters: woocommerce
build: false
- name: Download and install Chromium browser.
working-directory: plugins/woocommerce
run: pnpm exec playwright install chromium
- name: Run API tests
id: run-api-composite-action
uses: ./.github/actions/tests/run-api-tests
with:
report-name: ${{ env.API_WP_LATEST_ARTIFACT }}
tests: hello
playwright-config: ci-release.playwright.config.js
env:
API_BASE_URL: ${{ secrets.RELEASE_TEST_URL }}
USER_KEY: ${{ secrets.RELEASE_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.RELEASE_TEST_ADMIN_PASSWORD }}
UPDATE_WC: ${{ needs.get-tag.outputs.tag }}
- name: Upload Allure artifacts to bucket
if: success() || ( failure() && steps.run-api-composite-action.conclusion == 'failure' )
@ -331,7 +337,7 @@ jobs:
script: |
const { getVersionWPLatestMinusOne } = require( './plugins/woocommerce/tests/e2e-pw/utils/wordpress' );
await getVersionWPLatestMinusOne( { core, github } );
- name: Setup WooCommerce Monorepo
uses: ./.github/actions/setup-woocommerce-monorepo
with:
@ -341,7 +347,7 @@ jobs:
working-directory: plugins/woocommerce
run: pnpm run env:test
env:
WP_ENV_CORE: WordPress/WordPress#${{ steps.get-wp-latest-1.outputs.version }}
WP_ENV_CORE: WordPress/WordPress#${{ steps.get-wp-latest-1.outputs.version }}
- name: Download release zip
env:

View File

@ -0,0 +1,88 @@
name: Send a Slack notification when a PR contains rest api changes
on:
pull_request_target:
types: [labeled]
permissions: {}
jobs:
send-slack-notification-when-pr-contains-rest-api-changes:
if: "${{ github.event.label.name == 'contains: rest api change' && (github.event.pull_request.state == 'open' || github.event.pull_request.merged) }}"
runs-on: ubuntu-20.04
steps:
- name: Wait 2 minutes for other labelling jobs to finish
run: sleep 2m
shell: bash
- name: Calculate test date
id: calculate_date
run: |
#!/bin/bash
# Get the day of the week of the merged PR (0 for Sunday, 1 for Monday, etc.)
MERGE_DAY_OF_WEEK=$(date -u -d "${{ github.event.pull_request.merged_at }}" +"%u")
# Calculate days until the next Thursday after the merge
# If the merge is on Thursday, this will give 7 (i.e., next week's Thursday)
DAYS_UNTIL_NEXT_THURSDAY=$(( (4 + 7 - MERGE_DAY_OF_WEEK) % 7 ))
# If DAYS_UNTIL_NEXT_THURSDAY is 0, the merge was on a Thursday, so we set it to 7 to get the next Thursday
if [ $DAYS_UNTIL_NEXT_THURSDAY -eq 0 ]; then
DAYS_UNTIL_NEXT_THURSDAY=7
fi
# Calculate the date for the next Thursday after the merge
THURSDAY_AFTER_MERGE=$(date -u -d "${{ github.event.pull_request.merged_at }} + $DAYS_UNTIL_NEXT_THURSDAY days" +"%Y-%m-%d")
WOOAF_RELEASE_DATE=$(date -u -d "${THURSDAY_AFTER_MERGE} + 6 days" +"%Y-%m-%d")
TEST_DATE_MESSAGE="Thursday, $THURSDAY_AFTER_MERGE. (Targeting release on $WOOAF_RELEASE_DATE)"
echo "TEST_DATE_MESSAGE=${TEST_DATE_MESSAGE}" >> $GITHUB_ENV
- name: Determine Milestone Date
id: get_milestone_date
run: |
#!/bin/bash
MILESTONE_TITLE="${{ github.event.pull_request.milestone.title }}"
MILESTONE_DATE="Undefined"
# Mapping of milestone titles to release dates
declare -A MILESTONE_DATES
MILESTONE_DATES=(
["8.0.0"]="2023-08-08"
["8.1.0"]="2023-09-12"
["8.2.0"]="2023-10-10"
["8.3.0"]="2023-11-14"
["8.4.0"]="2023-12-12"
["8.5.0"]="2024-01-09"
["8.6.0"]="2024-02-13"
["8.7.0"]="2024-03-12"
["8.8.0"]="2024-04-09"
["8.9.0"]="2024-05-14"
["9.0.0"]="2024-06-11"
)
# Check if the milestone title exists in our predefined list and get the date
if [[ -v "MILESTONE_DATES[${MILESTONE_TITLE}]" ]]; then
MILESTONE_DATE=${MILESTONE_DATES[${MILESTONE_TITLE}]}
fi
# Export for later steps
echo "MILESTONE_DATE=${MILESTONE_DATE}" >> $GITHUB_ENV
# Notify Slack Step
- name: Notify Slack
uses: archive/github-actions-slack@d9dae40827adf93bddf939db6552d1e392259d7d
id: notify
with:
slack-bot-user-oauth-access-token: ${{ secrets.TEST_ASSISTANCE_BOT_TOKEN }}
slack-channel: ${{ secrets.WOO_CORE_REST_API_CHANGES_SLACK_CHANNEL }}
slack-text: |
<${{ github.event.pull_request.html_url }}|${{ github.event.pull_request.title }}>
*Labels:* ${{ join(github.event.pull_request.labels.*.name, ', ') }}
*Monthly Release Milestone:* <${{ github.event.pull_request.milestone.html_url }}|${{ github.event.pull_request.milestone.title }}> (Release Date: ${{ env.MILESTONE_DATE }})
*WooAF (weekly) Timeline: this PR can be tested from:* ${{ env.TEST_DATE_MESSAGE }}
Please visit the <#${{ secrets.WOO_CORE_RELEASES_SLACK_CHANNEL }}> to obtain the latest WooAF build for testing.
slack-optional-unfurl_links: false
slack-optional-unfurl_media: false

View File

@ -4,6 +4,7 @@
"MD007": { "indent": 4 },
"MD013": { "line_length": 9999 },
"MD024": { "allow_different_nesting": true },
"MD033": { "allowed_elements": ["video"] },
"no-hard-tabs": false,
"whitespace": false
}

View File

@ -1,5 +1,134 @@
== Changelog ==
= 8.2.0 2023-10-13 =
**WooCommerce**
* Fix - Correctly set 'created_via' for HPOS orders created on the admin. [#40469](https://github.com/woocommerce/woocommerce/pull/40469)
* Fix - Fix backwards compatibility issue with `wc_get_orders()` when HPOS is active and the pagination bit is set. [#40551](https://github.com/woocommerce/woocommerce/pull/40551)
* Fix - Save hpos order data before clearing the order from cache [#40282](https://github.com/woocommerce/woocommerce/pull/40282)
* Fix - Disable WP's post lock on HPOS order edit screen. [#40355](https://github.com/woocommerce/woocommerce/pull/40355)
* Fix - Enqueue media scripts for Images block within the product editor, as is required for Images block. [#40356](https://github.com/woocommerce/woocommerce/pull/40356)
* Fix - Addressed visual tweaks for CYS in response to feedback from 12th Sept [#40155](https://github.com/woocommerce/woocommerce/pull/40155)
* Fix - Address missing order type handling in HPOS compatibility mode sync. [#40279](https://github.com/woocommerce/woocommerce/pull/40279)
* Fix - Add Variation options section back to the product blocks template [#39914](https://github.com/woocommerce/woocommerce/pull/39914)
* Fix - Avoid a fatal error on the order received page if the order ID is not for a valid order. [#39876](https://github.com/woocommerce/woocommerce/pull/39876)
* Fix - Avoid string<>int comparison in products bought query to avoid results with customer_id = 0. [#40030](https://github.com/woocommerce/woocommerce/pull/40030)
* Fix - Changed Tax task completion criteria so that it considers both boolean and stringly typed values as expected [#39983](https://github.com/woocommerce/woocommerce/pull/39983)
* Fix - Display search results subtitle in HPOS list table view. [#40270](https://github.com/woocommerce/woocommerce/pull/40270)
* Fix - Eliminate an unnecessary redirect when the geo hash isalready set to the correct value. [#39634](https://github.com/woocommerce/woocommerce/pull/39634)
* Fix - Fix a bug where updating store location doesn't update store currency. [#40142](https://github.com/woocommerce/woocommerce/pull/40142)
* Fix - Fix cached refund not deleted when the refund is deleted with HPOS active [#40197](https://github.com/woocommerce/woocommerce/pull/40197)
* Fix - Fix changes in order custom fields made from admin not being applied when using the order Update button with HPOS active. [#40278](https://github.com/woocommerce/woocommerce/pull/40278)
* Fix - Fix customize store white screen bug in WP 6.3 [#40031](https://github.com/woocommerce/woocommerce/pull/40031)
* Fix - Fix customize your store task header button [#40031](https://github.com/woocommerce/woocommerce/pull/40031)
* Fix - Fix CYS UI issues [#40269](https://github.com/woocommerce/woocommerce/pull/40269)
* Fix - Fix CYS `__experimentalReapplyBlockTypeFilters` is not a function [#40104](https://github.com/woocommerce/woocommerce/pull/40104)
* Fix - Fixed missed lint error in Assembler Hub [#39964](https://github.com/woocommerce/woocommerce/pull/39964)
* Fix - Fix minor layout shift in the core profiler. [#39898](https://github.com/woocommerce/woocommerce/pull/39898)
* Fix - Fix product e2e tests [#39823](https://github.com/woocommerce/woocommerce/pull/39823)
* Fix - Fix undismissable notice when using localization for certain messages like "Coupon management has moved" [#39913](https://github.com/woocommerce/woocommerce/pull/39913)
* Fix - FIx WC Admin pages are empty for WP 6.2 and below. [#39995](https://github.com/woocommerce/woocommerce/pull/39995)
* Fix - Properly convert local time date queries to UTC in the HPOS datastore. [#40146](https://github.com/woocommerce/woocommerce/pull/40146)
* Fix - Redirect to Jetpack connect when jetpack-boost is selected. [#40261](https://github.com/woocommerce/woocommerce/pull/40261)
* Fix - Remove COT enable requirement from sync and verify command. [#39998](https://github.com/woocommerce/woocommerce/pull/39998)
* Fix - Removed references to the un-used Purchase task item in the onboarding task list. [#40121](https://github.com/woocommerce/woocommerce/pull/40121)
* Fix - Remove use of woocommerce-page class within WooCommerce Admin pages, replaced with woocommerce-admin-page. [#40218](https://github.com/woocommerce/woocommerce/pull/40218)
* Fix - Restore moving to trash functionality within HPOS order edit screen. [#39693](https://github.com/woocommerce/woocommerce/pull/39693)
* Fix - update the SqlQuery filter prefix in data.md [#39319](https://github.com/woocommerce/woocommerce/pull/39319)
* Fix - Use correct object reference when cloning a cart [#39282](https://github.com/woocommerce/woocommerce/pull/39282)
* Fix - [HPOS]Fix duplicate meta handling by passing meta_value|unique in post calls [#40088](https://github.com/woocommerce/woocommerce/pull/40088)
* Fix - [HPOS] Modify query to have less characters before the `FROM` keyword. [#40109](https://github.com/woocommerce/woocommerce/pull/40109)
* Fix - [HPOS] Support deleting metadata just by meta id. [#40064](https://github.com/woocommerce/woocommerce/pull/40064)
* Fix - [HPOS] Use objects method instead of calling datastore directly. [#40158](https://github.com/woocommerce/woocommerce/pull/40158)
* Add - Add ability to remove blocks from templates. [#39900](https://github.com/woocommerce/woocommerce/pull/39900)
* Add - Add a filter to OrdersTableQuery to allow overriding of HPOS queries. [#39945](https://github.com/woocommerce/woocommerce/pull/39945)
* Add - Add after_add_block and after_remove block hooks to the block template API. [#40139](https://github.com/woocommerce/woocommerce/pull/40139)
* Add - Add AI wizard business info step for Customize Your Store task [#39979](https://github.com/woocommerce/woocommerce/pull/39979)
* Add - Add component to Customize Your Store task. [#40140](https://github.com/woocommerce/woocommerce/pull/40140)
* Add - Add customize store - fonts [#40082](https://github.com/woocommerce/woocommerce/pull/40082)
* Add - Add customize store AI wizard call for best colour palette suggestions. [#40295](https://github.com/woocommerce/woocommerce/pull/40295)
* Add - Add customize store AI wizard call for color palette suggestion [#40237](https://github.com/woocommerce/woocommerce/pull/40237)
* Add - Add customize store AI wizard call for font pairing suggestion [#40240](https://github.com/woocommerce/woocommerce/pull/40240)
* Add - Add customize store assembler hub onboarding tour [#39981](https://github.com/woocommerce/woocommerce/pull/39981)
* Add - Add customize store assembler hub [#39843](https://github.com/woocommerce/woocommerce/pull/39843)
* Add - Add customize store color palettes [#40051](https://github.com/woocommerce/woocommerce/pull/40051)
* Add - Add customize store transitional screen [#40122](https://github.com/woocommerce/woocommerce/pull/40122)
* Add - Added URL navigation support to customize-store feature [#40068](https://github.com/woocommerce/woocommerce/pull/40068)
* Add - Add filter woocommerce_hpos_enable_sync_on_read to disable sync on read with HPOS sync enabled. [#40039](https://github.com/woocommerce/woocommerce/pull/40039)
* Add - Add has_price param to the variations REST API query. [#40281](https://github.com/woocommerce/woocommerce/pull/40281)
* Add - Add header customization to the Assembler Hub [#40107](https://github.com/woocommerce/woocommerce/pull/40107)
* Add - Add help text to Name field in Create new category modal [#40059](https://github.com/woocommerce/woocommerce/pull/40059)
* Add - Add new e2e test for Shopper My Account Downloads section [#40100](https://github.com/woocommerce/woocommerce/pull/40100)
* Add - Add new e2e test to cover My Account Addresses section [#40114](https://github.com/woocommerce/woocommerce/pull/40114)
* Add - Add sidebar to customize your store task. [#40136](https://github.com/woocommerce/woocommerce/pull/40136)
* Add - Adds new action hook `woocommerce_pay_order_before_payment` to the `checkout/form-pay.php` template. [#37588](https://github.com/woocommerce/woocommerce/pull/37588)
* Add - Add support for slug auto generation to the create attribute endpoint [#39827](https://github.com/woocommerce/woocommerce/pull/39827)
* Add - Add tags (or general taxonomy ) block [#39966](https://github.com/woocommerce/woocommerce/pull/39966)
* Add - Add track events to customize store AI wizard [#40144](https://github.com/woocommerce/woocommerce/pull/40144)
* Add - Add track events to customize store transitional page [#40143](https://github.com/woocommerce/woocommerce/pull/40143)
* Add - Add Tracks events to Appearance > Themes screen [#40193](https://github.com/woocommerce/woocommerce/pull/40193)
* Add - Add tracks to CYS assembler-hub and hide pages sidebar screen [#40156](https://github.com/woocommerce/woocommerce/pull/40156)
* Add - Add variable product experiment [#40177](https://github.com/woocommerce/woocommerce/pull/40177)
* Add - Add woocommerce_block_template_register action. [#39915](https://github.com/woocommerce/woocommerce/pull/39915)
* Add - Create a plugin to enable Variations feature #40027 [#40027](https://github.com/woocommerce/woocommerce/pull/40027)
* Add - Implement customize store assembler hub - logo feature [#39932](https://github.com/woocommerce/woocommerce/pull/39932)
* Add - Implemented loader design for Customize your store - Design with AI [#40083](https://github.com/woocommerce/woocommerce/pull/40083)
* Add - Made ai completion for look and tone more robust and added tracks [#40052](https://github.com/woocommerce/woocommerce/pull/40052)
* Add - Records plugin API requests and installation errors to coreprofiler_install_plugin_error separately for the core profiler. [#39899](https://github.com/woocommerce/woocommerce/pull/39899)
* Update - Added Marketplace class as basis for Reactified marketplace. [#39121](https://github.com/woocommerce/woocommerce/pull/39121)
* Update - Added xstate scaffolding for AI Wizard in customize your store feature [#39863](https://github.com/woocommerce/woocommerce/pull/39863)
* Update - Display a custom WooPayments onboarding task header content, when an incentive with server based header is available. [#40034](https://github.com/woocommerce/woocommerce/pull/40034)
* Update - Implement customize your store task completion logic [#40267](https://github.com/woocommerce/woocommerce/pull/40267)
* Update - Optimize customize store preview frame resize performance [#39930](https://github.com/woocommerce/woocommerce/pull/39930)
* Update - Remove core-profiler checks from the tests -- core profiler is enabled by default now. [#40260](https://github.com/woocommerce/woocommerce/pull/40260)
* Update - Replace Personalize Your Store task with Choose Your Theme [#40239](https://github.com/woocommerce/woocommerce/pull/40239)
* Update - Track coreprofiler_store_extensions_installed_and_activated when async installation is complete [#39921](https://github.com/woocommerce/woocommerce/pull/39921)
* Update - Turn off the experimental flag for HPOS. [#39846](https://github.com/woocommerce/woocommerce/pull/39846)
* Update - Update Action Scheduler to 3.6.3 [#40147](https://github.com/woocommerce/woocommerce/pull/40147)
* Update - Update intro screen for the new Customize Your Store task [#40293](https://github.com/woocommerce/woocommerce/pull/40293)
* Update - Update Remote Inbox Notifications to add in and !in comparison operators for comparing values against arrays [#40084](https://github.com/woocommerce/woocommerce/pull/40084)
* Update - Update the simple product template implementation to use the product form template API. [#39814](https://github.com/woocommerce/woocommerce/pull/39814)
* Update - Update use of preventLeavingProductForm with new function changes. [#40225](https://github.com/woocommerce/woocommerce/pull/40225)
* Update - Update WooCommerce Blocks to 10.9.3 [#39895](https://github.com/woocommerce/woocommerce/pull/39895)
* Update - Update WooCommerce Blocks to 11.0.0 [#39971](https://github.com/woocommerce/woocommerce/pull/39971)
* Update - Update WooCommerce Blocks to 11.1.0 [#40141](https://github.com/woocommerce/woocommerce/pull/40141)
* Update - Update WooCommerce Blocks to 11.1.1 [#40300](https://github.com/woocommerce/woocommerce/pull/40300)
* Update - Update WooCommerce Blocks to 11.1.2 [#40475](https://github.com/woocommerce/woocommerce/pull/40475)
* Update - We have completely redesigned the In-app Marketplace. [#39121](https://github.com/woocommerce/woocommerce/pull/39121)
* Dev - Added documentation for the Core Profiler [#39963](https://github.com/woocommerce/woocommerce/pull/39963)
* Dev - Add job to post Slack summary of plugin test results in "Smoke test daily" workflow. [#39838](https://github.com/woocommerce/woocommerce/pull/39838)
* Dev - Add new E2E test covering shopper product page and make Product-related tests granular (separated test files) [#40132](https://github.com/woocommerce/woocommerce/pull/40132)
* Dev - Add notice to "track inventory" toggle #40011 [#40011](https://github.com/woocommerce/woocommerce/pull/40011)
* Dev - Add some basic E2E tests for Assembler Hub [#40235](https://github.com/woocommerce/woocommerce/pull/40235)
* Dev - Adds test to check required fields on checkout [#40099](https://github.com/woocommerce/woocommerce/pull/40099)
* Dev - Bump required PHP version to 7.4 [#39820](https://github.com/woocommerce/woocommerce/pull/39820)
* Dev - Cleanup: remove the unused is_feature_visible and show_feature methods. [#39931](https://github.com/woocommerce/woocommerce/pull/39931)
* Dev - Fixes and enables API test suite to run on daily CI run against alternate host [#39858](https://github.com/woocommerce/woocommerce/pull/39858)
* Dev - Fix flakiness around the `Turn off the new product form` menu item. [#39957](https://github.com/woocommerce/woocommerce/pull/39957)
* Dev - Fix for a couple of flaky API tests on daily runs [#39918](https://github.com/woocommerce/woocommerce/pull/39918)
* Dev - Improve documentation for the `is_checkout()` function. [#40258](https://github.com/woocommerce/woocommerce/pull/40258)
* Dev - Refactored core profiler loader to be more generalizable and moved to @woocommerce/onboarding [#39735](https://github.com/woocommerce/woocommerce/pull/39735)
* Dev - Remove "WP Latest-2" from release tests. [#40012](https://github.com/woocommerce/woocommerce/pull/40012)
* Dev - Remove legacy PHP version update checks [#39845](https://github.com/woocommerce/woocommerce/pull/39845)
* Dev - Run a full reset on API daily test site [#40061](https://github.com/woocommerce/woocommerce/pull/40061)
* Dev - Updates Playwright from 1.33 to 1.37.1 [#39815](https://github.com/woocommerce/woocommerce/pull/39815)
* Tweak - Add order property to every block in SimpleProductTemplate [#39946](https://github.com/woocommerce/woocommerce/pull/39946)
* Tweak - Adds an informative tooltip to the Account Details section of the Direct Bank Transfer settings. [#39860](https://github.com/woocommerce/woocommerce/pull/39860)
* Tweak - Fix a minor code typo, no change in functionality [#36402](https://github.com/woocommerce/woocommerce/pull/36402)
* Tweak - Make it easier to disable email verification checks for the order confirmation and order pay pages. [#40050](https://github.com/woocommerce/woocommerce/pull/40050)
* Tweak - Migrate category field to woocommerce/product-taxonomy-field block [#40021](https://github.com/woocommerce/woocommerce/pull/40021)
* Tweak - tweak some of the HPOS Settings UI. [#39912](https://github.com/woocommerce/woocommerce/pull/39912)
* Tweak - Tweak tasklist description color to darker [#39903](https://github.com/woocommerce/woocommerce/pull/39903)
* Enhancement - Add CLI commands to enable or disable HPOS. [#39865](https://github.com/woocommerce/woocommerce/pull/39865)
* Enhancement - Design enhancements for the Attributes tab. [#39987](https://github.com/woocommerce/woocommerce/pull/39987)
* Enhancement - Design enhancements for the Inventory tab. [#39962](https://github.com/woocommerce/woocommerce/pull/39962)
* Enhancement - Enable HPOS by default for new installs. [#40296](https://github.com/woocommerce/woocommerce/pull/40296)
* Enhancement - Improve the existing E2E test to verify one more element on each page load. [#40008](https://github.com/woocommerce/woocommerce/pull/40008)
* Enhancement - Update the default setting for the task list progress bar from 0 to 0.25, which gives the progress better visual context when no tasks have been completed. [#39369](https://github.com/woocommerce/woocommerce/pull/39369)
* Enhancement - Update Venezuelan currency: Bolívar (Bs.). [#29380](https://github.com/woocommerce/woocommerce/pull/29380)
= 8.1.1 2023-09-18 =
**WooCommerce**

449
docs/docs-manifest.json Normal file
View File

@ -0,0 +1,449 @@
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/style-guide.md",
"hash": "e81f1f926568e1792b6814c735c0321dee1356b4f8c053b7a5ee1770440e8052",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/style-guide.md",
"id": "211490a474b1b2ce6a6fc670b159f3497d6a9054"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/README.md",
"hash": "b1a13c53d16ba2a1b089a0cf19c5c37a8181f33bdbe0c6ee106cd1c80aef9fa0",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/README.md",
"id": "2c20e49a2bfd5bfcbb318dedbec96ada77784f14",
"links": {
"extension-development/building-your-first-extension.md": "bfb30a2379ec5e7c7960192b0a9175191e39aef7",
"extension-development/how-to-design-a-simple-extension.md": "c2f4612f31cc3892bfb19c6e9859f2daccdb6fa0",
"style-guide.md": "211490a474b1b2ce6a6fc670b159f3497d6a9054",
"../plugins/woocommerce/README.md": "827066d08695e5002bf059cd2e9d4d2a0fa58df8",
"../plugins/woocommerce/i18n/languages/README.md": "826a4400174812dfabb978c87ff2742bfdf28d62",
"../plugins/woocommerce/includes/README.md": "3d07aabeb0926e4c675e5770e78a0cfa537d2f56",
"../plugins/woocommerce/lib/README.md": "7c7e05959e4e9dcde4ac0e3e2a13258d7521e731",
"../plugins/woocommerce/packages/README.md": "740c206346a48e9dcb2e70efd5a3221992c389dc",
"../plugins/woocommerce/src/README.md": "c7444c322c5bb1ff755b2bf3e961babf3a879f4e",
"../plugins/woocommerce/src/Admin/RemoteInboxNotifications/README.md": "a46d35b9e8a8c15b89082e0c2c04d83c852d545f",
"../plugins/woocommerce/src/Admin/RemoteInboxNotifications/Transformers/README.md": "bbccc83ae18c86679a3b632e7203f6c395987967",
"../plugins/woocommerce/src/Blocks/README.md": "532a6602e970797759269b4c588c724551379214",
"../plugins/woocommerce/src/Internal/README.md": "67d669be90b641e2273194796e3d9bdfdbd69a7e",
"../plugins/woocommerce/src/Internal/Admin/ProductForm/README.md": "1d691e34fd20dd268e8e9f8283f46a595758c33b",
"../plugins/woocommerce/tests/README.md": "722532b12b14b2f5c0b8efdd96cca1854bba38c4",
"../plugins/woocommerce/tests/api-core-tests/README.md": "b000db6a9a2807a49a3bb47c57bb78326a865c78",
"../plugins/woocommerce/tests/e2e/README.md": "c15296a46be7331ed23d791073cdebeb0f4c48c4",
"../plugins/woocommerce/tests/e2e-pw/README.md": "103a9a613a34a031b34ca48f0895640dc9fc2b10",
"../plugins/woocommerce/tests/performance/README.md": "8c14e3b9fac89bced565b78e96d3a3a89e0a568e",
"../plugins/woocommerce/tests/Tools/CodeHacking/README.md": "231d9fc132423f1ecc391aaf1bcb57a3cd749d24",
"../plugins/woocommerce-admin/README.md": "9ba7a7e2c4411e01c70d866f8b8b5604484368d8",
"../plugins/woocommerce-admin/client/activity-panel/README.md": "2de9812a153a9c9ed90588feacd9ece41ecff93c",
"../plugins/woocommerce-admin/client/activity-panel/activity-card/README.md": "c34672cf87665e3ff157c6df3ddf1993fd33e7a4",
"../plugins/woocommerce-admin/client/activity-panel/activity-header/README.md": "13e379fd37082d3cba36e76046acfc63ff70ab8a",
"../plugins/woocommerce-admin/client/analytics/report/README.md": "84430b89912cb95d31240cd2d00a400b2d904ec4",
"../plugins/woocommerce-admin/client/analytics/settings/README.md": "421781cef9f3d0160c1e3892488b21b3f4a2a7f5",
"../plugins/woocommerce-admin/client/dashboard/README.md": "f7d6ff3c0f18554161afaa94698fb127f098986f",
"../plugins/woocommerce-admin/client/header/README.md": "39d3152fc1be21beee488dddd3f5a90e6af2502a",
"../plugins/woocommerce-admin/client/marketing/README.md": "54f1eb4cf5ec67713ce2fdf2b2f1dc28b03e35ef",
"../plugins/woocommerce-admin/client/marketing/components/product-icon/README.md": "3fa5081872b79078ad320dd0d9e218ed4148dc4e",
"../plugins/woocommerce-admin/client/utils/README.md": "0486d6a8f01b89bf171e21678df5dae9b5791a99",
"../plugins/woocommerce-admin/client/wp-admin-scripts/README.md": "641ab0c131d812f0969631b44ed9e8fe3fdb0cba",
"../plugins/woocommerce-admin/docs/README.md": "25155a38fc7599a01bfb30eb31a1edb098b59219",
"../plugins/woocommerce-admin/docs/examples/README.md": "b5ca126b81199d9da6ae62d5d26c093f88405a06",
"../plugins/woocommerce-admin/docs/examples/extensions/README.md": "42a90d07061074d0de1b15aeaf80531f83b2a258",
"../plugins/woocommerce-admin/docs/features/README.md": "1ee849cb8dc013ffbfe8ebcb54b8cc83f39d72e4",
"../plugins/woocommerce-admin/docs/woocommerce.com/README.md": "ee127fc0f256c3ae546869c602e94b4a6e258be8",
"../plugins/woocommerce-beta-tester/README.md": "081da0cc3caba15e926b606082120c2692b71ad4",
"../plugins/woocommerce-beta-tester/src/tools/README.md": "aedc38bbe8b29e676a15d252bcb1be38acc86f3c",
"../plugins/woocommerce-beta-tester/userscripts/README.md": "d3d94172608c29c4968ee73858ee3575a2cc11ce"
}
}
],
"categories": [
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/unhook--remove-woocommerce-emails.md",
"hash": "a22ec5c7c7c670e97e34a438d5e13dc3709716484efbecbf49e5917b6da9079d",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/unhook--remove-woocommerce-emails.md",
"id": "517b5bdeb798c1832c3ba76670e728b7b922d5d1"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/rename-a-country.md",
"hash": "3929e2145dcaad30a83fda6d82d973028e4463eeb2f6a6ba6ff9cb70c6b52fd5",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/rename-a-country.md",
"id": "2197550f7fdfbce39155865ba36f1f396a35e4a6"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/number-of-products-per-row.md",
"hash": "507e7be407716b56fe577109b296b55cdcb48cb2b2e339a761446b4df2d730e9",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/number-of-products-per-row.md",
"id": "7da8ddcdbc3f427d14b040015fb1de9efde79d19"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/change-a-currency-symbol.md",
"hash": "4485b212ff7bdf7fd8c23dc589dbbb6263a530623b939b384297f2377b11056f",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/change-a-currency-symbol.md",
"id": "de0e6701b0e15a209ac6ed3c100b34f67237ea96"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/before-login--register-form.md",
"hash": "3435f3859ec047566696ae5474df697c99a6e1ab04168ae8f1ca831abc519d67",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/before-login--register-form.md",
"id": "5acf55bdb90174bc00a10816ca71a8846bd7040f"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/adjust-quantity-input-values.md",
"hash": "056fb597c07e0e82b92ca8a2c484166f807d3d513fa950cb5c46a8db087fe986",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/adjust-quantity-input-values.md",
"id": "06d0ddda56838dc22ad94716aca95a1f2a9ad67c"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/add-or-modify-states.md",
"hash": "d61d5051439b0cbf949be64958c8101a7c6487672a7b79dd3f528e9c1a5b408e",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/add-or-modify-states.md",
"id": "10568c46b0baa2f8ea01a8cd9dd6b2d65d35aafc"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/add-a-currency-symbol.md",
"hash": "0053a87328ee04a168c5657df26cf18f219d30669b000300ace4284ea2333186",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/add-a-currency-symbol.md",
"id": "6d63d431fa1d66af7b3b47861ccc940775eba397"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/code-snippets/add-a-country.md",
"hash": "9305a5ed51cc0174e19e68ebc94801c5e7d6e62e820d106f35175540b0531d10",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/code-snippets/add-a-country.md",
"id": "7c591c3bd31cb2942fdcb4f77da167bc9ec36207"
}
],
"categories": []
},
{
"category_title": "Contributing",
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/contributing/deciding-pr-high-impact.md",
"hash": "6d9ddea0e44e1ab9f7b12183069c7fde51df26c9bcad15d8b6f9d3ab17ee1fe0",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/contributing/deciding-pr-high-impact.md",
"id": "cee3a746887c88f92966bb72ec1847aa5d97cebd"
}
],
"categories": []
},
{
"category_title": "Data-management",
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/data-management/data-stores.md",
"hash": "7af9424c5b3fdfa5b30b658f0c3a452ac12d67390b58e9c23ef3bc71412b2a92",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/data-management/data-stores.md",
"id": "72609f6c4fecccf2881c76bb8f21fc6a2d3cfef5"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/data-management/crud-objects.md",
"hash": "9b687cd323893ed0fc012ad82e67a329ea0f41c312017bfdf3015ab7ef51a23a",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/data-management/crud-objects.md",
"id": "0214be4dc9e0ddcc6d6a175fcd2f2b9fd4c8b042"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/tools-for-low-code-development.md",
"hash": "5989c60346c29c019332b7e2faee0dfcddf063db2d12f22f7755525e99c8ba4a",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/tools-for-low-code-development.md",
"id": "9db13086ff88d75fc5d5cd7bd36820b2d372b288"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/readme.md",
"hash": "e22a09b0d39adf37cd19fa57263e1195646f766396a36571411c54c64c6ba5a1",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/readme.md",
"id": "4946a26f3f2ba63d5db65033a90b6dda3a43a4ee"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/how-to-design-a-simple-extension.md",
"hash": "893c9361b6a1f6cd8a83dc9a4500c9b3050d66ef6d567fddf56d68de01d182a1",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/how-to-design-a-simple-extension.md",
"id": "c2f4612f31cc3892bfb19c6e9859f2daccdb6fa0"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/how-to-add-your-own-store-management-links.md",
"hash": "59dfa1f941a2fafaccedf2dd9be5bc1ee8c34b7320c6589c860ad98403bcd273",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/how-to-add-your-own-store-management-links.md",
"id": "461423141956d0653582aa15956a7b0401301cf6"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/handling-merchant-onboarding.md",
"hash": "e4a8358de815e378beb07426fd5687a0e91792f70a697574edd5031bf073c08d",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/handling-merchant-onboarding.md",
"id": "878874b744cea792a439935c67ac833a5f7d8796"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/handling-deactivation-and-uninstallation.md",
"hash": "cfc8cdf9e9a41e69cf40dcc1548cf7b0231c51c33c504ee800dd7525afe6d483",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/handling-deactivation-and-uninstallation.md",
"id": "93a623f5b7ff808c92541941787bdc2101518f5a"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/extension-developer-handbook.md",
"hash": "ff87298651dff8672b0c0da8693b53cb19d1fe7e65f04a947029aeec9cc9896f",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/extension-developer-handbook.md",
"id": "9f22e410b1ff4f6e5c22f6b4567c1a676d037295"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/development-environment.md",
"hash": "811f43ef03b40b48ad72a9d787031cb10d5a17b5f4ef4a2d5c0fa4977b2d43df",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/development-environment.md",
"id": "188b18434a7e844978d4d25a4b1fbc74004294d5"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/extension-development/building-your-first-extension.md",
"hash": "2aad1fe83142ff55197f3bc560fafbe2c1279ccf9bb727fea5257eed447ba694",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/extension-development/building-your-first-extension.md",
"id": "bfb30a2379ec5e7c7960192b0a9175191e39aef7"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/readme.md",
"hash": "8aa7cd66683478dff1f37c767f154d35e6b78a738b604d0bc2ae31a10f920ba6",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/readme.md",
"id": "2145ad4acea5e37b1ff4354bf44a8af9d10c750a"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/developer-tools.md",
"hash": "860d227350f472b610351bf416953bf9401bf0df296ee8ebe2af9c7a9d20fc57",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/developer-tools.md",
"id": "3d8c7c1a9187dd7c96d2561bccfcfa88a8d0102a"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/developer-resources.md",
"hash": "e5417528667f6afb2de5ed1b4f7073a63268e72e163bd67a8a1daeda1e623eb0",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/developer-resources.md",
"id": "0923cb0175b15041bcecf8f9dbc60828052e1fec"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/getting-started/debugging.md",
"hash": "e8407732d22ffa183db83e5875e6709bdc8dd7ac47a05280590c4b5f1021fea9",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/getting-started/debugging.md",
"id": "b28ccc6fa293efebd716b510df0331fb222b8a1b",
"links": {
"../utilities/logging.md": "f673f50bdd83d5d0d7fd8d9976828f8736809510"
}
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/readme.md",
"hash": "aada6bfad51c9f68ddb61e6475aae137e6b2d91839afa001aa3862ecd651093b",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/readme.md",
"id": "214c00235e4efed0a786fd704c4bfde25952a669"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/high-performance-order-storage/hpos-overview.md",
"hash": "a7504d828aed93aa68fbaff338406682fa6169f9401b2c4de6e750d7f51c7416",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/high-performance-order-storage/hpos-overview.md",
"id": "380a11e440eb17bc76fb606fecce4ce82fc9b0cb"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/product-editor-development/common-tasks.md",
"hash": "a7725479ff8b34f8069f3a8262502dc82354ea50d6ccd3760c5c7f7a9ae58fe2",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/product-editor-development/common-tasks.md",
"id": "c09542004d78254458250704f3a68cfeb9fa7a7c"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/readme.md",
"hash": "7afc464833ea0eb33127e98cb92f951bcb4a5d9006898e56db9d1f36006970cf",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/readme.md",
"id": "f12729345d42760bd61a4a4cfdcebf6dbf2daac4"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/performance-optimization.md",
"hash": "cc54a9af29f80e413536f46e70bc17512c92de536375bded23e4893a3e95e262",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/performance-optimization.md",
"id": "280d9d16382ef5374226629751cff7fceefbfa62"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/grammar-punctuation-capitalization.md",
"hash": "cea26a41342f5e67bb3313c935726da68647827a60c2fb034f3e64dd783496bd",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/grammar-punctuation-capitalization.md",
"id": "85d910730d1daa03c86c42f2d4cbd2e146cec83c"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/quality-and-best-practices/coding-standards.md",
"hash": "332efc3cccdde767237087abba302fcc371d510e5f287d439de49fe99a5445cc",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/quality-and-best-practices/coding-standards.md",
"id": "3a47d9e0da6c415606b7ee87bb65ed24f4630be1"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reference-code/readme.md",
"hash": "49a289229235989dcb8fa990af7e5017ae37569d6103dfd044ee2d95f250f596",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reference-code/readme.md",
"id": "1934f96989f9b62e2caf7fd0ac7deb2292f161ce"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/readme.md",
"hash": "117ccaf1bf931f7a98486ac0b506c48dd4834a2f2acd76f8936a9bf6ba93171b",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/readme.md",
"id": "fc4ef6d8e26fc46ef6c9da5e0d860cf051928e12"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
"hash": "860c37ab2d1de9744d838e6d3b11eeadb6e6cb11afffa8dfc11021240661d843",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/extending-woocommerce-admin-reports.md",
"id": "9960520d4548fd3647c5bbc7ed4d4fcc6a76cfce"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/reporting/adding-columns-to-analytics-reports-and-csv-downloads.md",
"hash": "e8265405615834b04a02f5406c38e3be8acdd01116b66f08f25f99a86a580948",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/reporting/adding-columns-to-analytics-reports-and-csv-downloads.md",
"id": "10cabd954ae223ac83f84223611f6d82361f9d9d",
"links": {
"extending-woocommerce-admin-reports.md": "9960520d4548fd3647c5bbc7ed4d4fcc6a76cfce"
}
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/rest-api/readme.md",
"hash": "895a1986fd30f437c1bc2aaa618d6a06a98c65511cd257077302c2d1225787d9",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/rest-api/readme.md",
"id": "128b41ed5e9a0ed13a51de3196bd06c0297b2f33"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/rest-api/getting-started.md",
"hash": "b0bb28f6eed57c7d57dde75e8093771450db4666cbfab16d35387c39cd8d1e20",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/rest-api/getting-started.md",
"id": "10f52db2464ea2f373eff9a45ce9e8ff40214122",
"links": {
"_media/permalinks.webp": "5ac10f14cd0ca3ae45a9c089d659fee3ea4d9f22",
"_media/keys.png": "7a29fcb3f0b565f4f6983f1e12200d2c4d62907b",
"_media/postman.png": "b100bbf70f8889c26fcde6a6daca29be796071de",
"_media/insomnia.png": "a50683984998ab518b4b05433ffb1803f2ac135f",
"_media/sslerror.png": "5b6825fb0aba7ed55e1641880701c2afd1744ce1",
"_media/postman-ssl.png": "7e3523b0340acf908e98ac320f822d00a0710ac5",
"_media/insomnia-ssl.png": "84e6406407498b9936d6ef1df5e4c4cc78f75b00"
}
}
],
"categories": [
{
"category_title": "_media",
"categories": []
}
]
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/security/security-best-practices.md",
"hash": "ded14bf9c1b5402c9896c795c4c4cbe6165d465de56009c32559f854446bafda",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/security/security-best-practices.md",
"id": "ee399e729785fec50b90d73b231d321b34ab5ff9"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/security/reporting-security-issues.md",
"hash": "4a748990a0e3207c9f0828c585c1d2edce14bafee9afc331d43bda0b8ee09aa6",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/security/reporting-security-issues.md",
"id": "48caba58b4e5b44fc418bb80cf03aa48f87e4cc8"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/security/readme.md",
"hash": "b484a4886068a33cd8114066262e95a2c8036f1e11d09f0dc63141cd36d85e95",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/security/readme.md",
"id": "8b4aa089616cbeeedfec301eee17b5a00f669154"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/theme-design-ux-guidelines.md",
"hash": "bcab4deb86172df46ff775a23b921f8fb4aadd5b5c96085451609a3863642efc",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/theme-design-ux-guidelines.md",
"id": "1abe0b1ff5e3990387c7da7fa5a147430b3282f7"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/theme-development/marketplace-guidelines.md",
"hash": "5ca562b2f4cabefe47b0d08334f39d56e8d3e6dc31ea347000d3bb221e51d0a1",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/theme-development/marketplace-guidelines.md",
"id": "f39a348d787fd0cf4a390e70e6f0cbd36b27a283"
}
],
"categories": []
},
{
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/tutorials/readme.md",
"hash": "2ca52b9289180adad5d59865ca45c50098119b420662d727d739243e6a98131a",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/tutorials/readme.md",
"id": "0741650e7ad7567b84f776db7ddad2b8f5a598ea"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/tutorials/adding-actions-and-filters.md",
"hash": "fa6bc021c918aa168023a90e683832455dfa35abbb2561470b08002f1281356f",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/tutorials/adding-actions-and-filters.md",
"id": "3f4d6dcdbc181b11c97c438132ec13a0a8484524"
},
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/tutorials/adding-a-custom-field-to-variable-products.md",
"hash": "a6b654234e7c7f1fc3f9be49b7d00187d6f271e2d699971bade3cf9a728a780a",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/tutorials/adding-a-custom-field-to-variable-products.md",
"id": "f0a7a4a194a6e0aee6f939791f3eaebf36aebb27"
}
],
"categories": []
},
{
"category_title": "Utilities",
"posts": [
{
"edit_url": "https://github.com/woocommerce/woocommerce/edit/trunk/docs/utilities/logging.md",
"hash": "8912094df57a66c047fe2177be815a40024b461a10ddd61ed297c4b2c2919d64",
"url": "https://raw.githubusercontent.com/woocommerce/woocommerce/trunk/docs/utilities/logging.md",
"id": "f673f50bdd83d5d0d7fd8d9976828f8736809510",
"links": {
"_media/log-critical.jpg": "cc802f94ac4cf125a66bc6bb77bf95b80bf4fbed"
}
}
],
"categories": [
{
"category_title": "_media",
"categories": []
}
]
}
],
"hash": "fc6ee378adfa92b706b9d0813f541bf6e8029634c0dd6623000f76047316f0af"
}

View File

@ -0,0 +1,110 @@
# Settings API
The WooCommerce Settings API is used by extensions to display, save, and load settings. The best way to make use of the API in your extension is to create a class that extends the `WC_Settings_API` class:
```php
class My_Extension_Settings extends WC_Settings_API {
//
}
```
## Defining form fields
You can define your fields using a method called `init_form_fields` in your class constructor:
```php
$this->init_form_fields();
```
You must have your settings defined before you can load them. Setting definitions go in the `form_fields` array:
```php
/**
* Initialise gateway settings form fields.
*/
function init_form_fields() {
$this->form_fields = array(
'title' => array(
'title' => __( 'Title', 'your-text-domain' ),
'type' => 'text',
'description' => __( 'This controls the title which the user sees during checkout.', 'your-text-domain' ),
'default' => __( 'PayPal', 'your-text-domain' )
),
'description' => array(
'title' => __( 'Description', 'your-text-domain' ),
'type' => 'textarea',
'description' => __( 'This controls the description which the user sees during checkout.', 'your-text-domain' ),
'default' => __( "Pay via PayPal; you can pay with your credit card if you don't have a PayPal account", 'your-text-domain' )
)
);
} // End init_form_fields()
```
(Make sure your class initializes the `form_fields` property so that the "Creation of dynamic property" error is not thrown in PHP 8.2+)
In the above example we define two settings, Title and Description. Title is a text box, whereas Description is a textarea. Notice how you can define a default value and a description for the setting itself.
Setting definitions use the following format:
```php
'setting_name' => array(
'title' => 'Title for your setting shown on the settings page',
'description' => 'Description for your setting shown on the settings page',
'type' => 'text|password|textarea|checkbox|select|multiselect',
'default' => 'Default value for the setting',
'class' => 'Class for the input element',
'css' => 'CSS rules added inline on the input element',
'label' => 'Label', // For checkbox inputs only.
'options' => array( // Array of options for select/multiselect inputs only.
'key' => 'value'
),
)
```
## Displaying your settings
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">
<?php $this->generate_settings_html(); ?>
</table>
<?php
}
```
This will output your settings in the correct format.
## Saving your settings
To have your settings save, add your class's `process_admin_options` method to the appropriate `_update_options_` hook. For example, payment gateways should use the payment gateway hook:
```php
add_action( 'woocommerce_update_options_payment_gateways', array( $this, 'process_admin_options' ) );
```
Other types of plugins have similar hooks:
```php
add_action( 'woocommerce_update_options_shipping_methods', array( $this, 'process_admin_options' ) );
```
## Loading your settings
In the constructor you can load the settings you previously defined:
```php
// Load the settings.
$this->init_settings();
```
After that you can load your settings from the settings API. The `init_settings` method above populates the settings variable for you:
```php
// Define user set variables
$this->title = $this->settings['title'];
$this->description = $this->settings['description'];
```

View File

@ -0,0 +1,38 @@
# Product Editor Development Handbook
> ⚠️ **Notice:** This documentation is currently a **work in progress**. Please be aware that some sections might be incomplete or subject to change. We appreciate your patience and welcome any contributions!
This handbook is a guide for extension developers looking to add support for the new product editor in their extensions. The product editor uses [Gutenberg's Block Editor](https://github.com/WordPress/gutenberg/tree/trunk/packages/block-editor), which is going to help WooCommerce evolve alongside the WordPress ecosystem.
The product editor's UI consists of Groups (currently rendered as tabs), Sections, and Fields, which are all blocks.
![Product editor structure](https://woocommerce.files.wordpress.com/2023/09/groups-sections-fields.jpg)
The form's structure is defined in PHP using a Template, which is a tree structure of blocks. The template can be modified by using the Template API to add new Groups, Sections, and Fields as well as remove existing ones.
Many extensibility implementations can be done using only the PHP-based Block Template API alongside our library of [generic blocks](../../packages/js/product-editor/src/blocks/generic/README.md). More complex interactivity can be implemented using JavaScript and React (the same library used to implement the core blocks used in the product editor). [@woocommerce/create-product-editor-block](../../packages/js/create-product-editor-block/README.md) can help scaffold a development environment with JavaScript and React.
## Declaring compatibility with the product editor
To declare compatibility with the product editor, add the following to your plugin's root PHP file:
```php
use Automattic\WooCommerce\Utilities\FeaturesUtil;
add_action(
'before_woocommerce_init',
function() {
if ( class_exists( FeaturesUtil::class ) ) {
FeaturesUtil::declare_compatibility( 'product_block_editor', plugin_basename( __FILE__ ), true );
}
}
);
```
Please note that this check is currently not being enforced: the product editor can still be enabled even without this declaration. However, we might enforce this in the future, so it is recommended to declare compatibility as soon as possible.
## Related documentation
- [Examples on Template API usage](../../plugins/woocommerce/src/Admin/Features/ProductBlockEditor/ProductTemplates/README.md)
- [Related hooks and Template API documentation](../../plugins/woocommerce/src/Admin/BlockTemplates/README.md)
- [Generic blocks documentation](../../packages/js/product-editor/src/blocks/generic/README.md)

View File

@ -0,0 +1,62 @@
# CSS/Sass Naming Conventions
Table of Contents:
- [Introduction](#introduction)
- [Prefixing](#prefixing)
- [Class names](#class-names)
- [Example](#example)
- [TL;DR](#tldr)
## Introduction
Our guidelines are based on those used in [Calypso](https://github.com/Automattic/wp-calypso), which itself follows the [BEM methodology](https://getbem.com/).
Refer to the [Calypso CSS/Sass Coding Guidelines](https://wpcalypso.wordpress.com/devdocs/docs/coding-guidelines/css.md) for full details.
Read more about [BEM key concepts](https://en.bem.info/methodology/key-concepts/).
There are a few differences in WooCommerce which are outlined below.
## Prefixing
As a WordPress plugin WooCommerce has to play nicely with WordPress core and other plugins/themes. To minimize conflict potential, all classes should be prefixed with `.woocommerce-`.
## Class names
When naming classes, remember:
- **Block** - Standalone entity that is meaningful on its own. Such as the name of a component.
- **Element** - Parts of a block and have no standalone meaning. They are semantically tied to its block.
- **Modifier** - Flags on blocks or elements. Use them to change appearance or behavior.
### Example
```css
/* Block */
.woocommerce-loop {}
/* Nested block */
.woocommerce-loop-product {}
/* Modifier */
.woocommerce-loop-product--sale {}
/* Element */
.woocommerce-loop-product__link {}
/* Element */
.woocommerce-loop-product__button-add-to-cart {}
/* Modifier */
.woocommerce-loop-product__button-add-to-cart--added {}
```
**Note:** `.woocommerce-loop-product` is not named as such because the block is nested within `.woocommerce-loop`. It's to be specific so that we can have separate classes for single products, cart products, etc. **Nested blocks do not need to inherit their parents full name.**
## TL;DR
- Follow the [WordPress Coding standards for CSS](https://make.wordpress.org/core/handbook/best-practices/coding-standards/css/) unless it contradicts anything here.
- Follow [Calypso guidelines for CSS](https://wpcalypso.wordpress.com/devdocs/docs/coding-guidelines/css.md).
- Use BEM for [class names](https://en.bem.info/methodology/naming-convention/).
- Prefix all class names.

View File

@ -0,0 +1,88 @@
# Naming Conventions
Table of Contents:
- [PHP](#php)
- [`/src`](#src)
- [`/includes`](#includes)
- [JS](#js)
- [CSS and SASS](#css-and-sass)
## PHP
WooCommerce core generally follows [WordPress PHP naming conventions](https://make.wordpress.org/core/handbook/best-practices/coding-standards/php/#naming-conventions).
There are some additional conventions that apply, depending on the location of the code.
### `/src`
Classes defined inside `/src` follow the [PSR-4](https://www.php-fig.org/psr/psr-4/) standard. See the [README for `/src`](../../plugins/woocommerce/src/README.md) for more information.
The following conventions apply to this directory:
- No class name prefix is needed, as all classes in this location live within the `Automattic\WooCommerce` namespace.
- Classes are named using `CamelCase` convention.
- Functions are named using `snake_case` convention.
- Class file names should match the class name. They do not need a `class-` prefix.
- The namespace should match the directory structure.
- Hooks are prefixed with `woocommerce_`.
- Hooks are named using `snake_case` convention.
For example, the class defined in `src/Util/StringUtil.php` should be named `StringUtil` and should be in the `Automattic\WooCommerce\Util` namespace.
### `/includes`
The `/includes` directory contains legacy code that does not follow the PSR-4 standard. See the [README for `/includes`](../../plugins/woocommerce/includes/README.md) for more information.
The following conventions apply to this directory:
- Class names are prefixed with `WC_`.
- Classes are named using `Upper_Snake_Case` convention.
- Functions are prefixed with `wc_`.
- Functions are named using `snake_case` convention.
- Hooks are prefixed with `woocommerce_`.
- Hooks are named using `snake_case` convention.
Class name examples:
- `WC_Cache_Helper`
- `WC_Cart`
Function name examples:
- `wc_get_product()`
- `wc_is_active_theme()`
Hook name examples (actions or filters):
- `woocommerce_after_checkout_validation`
- `woocommerce_get_formatted_order_total`
## JS
WooCommerce core follows [WordPress JS naming conventions](https://developer.wordpress.org/coding-standards/wordpress-coding-standards/javascript/#naming-conventions).
As with PHP, function, class, and hook names should be prefixed, but the convention for JS is slightly different.
- Global class names are prefixed with `WC`. Class names exported from modules are not prefixed.
- Classes are named using `UpperCamelCase` convention.
- Global function names are prefixed with `wc`. Function names exported from modules are not prefixed.
- Functions are named using `camelCase` convention.
- Hooks names are prefixed with `woocommerce`.
- Hooks are named using `camelCase` convention.
Global class name example:
- `WCOrdersTable`
Global function name example:
- `wcSettings()`
Hook name example (actions or filters):
- `woocommerceTracksEventProperties`
## CSS and SASS
See [CSS/Sass Naming Conventions](./css-sass-naming-conventions.md).

View File

@ -0,0 +1,138 @@
# Writing high quality testing instructions
## Introduction
Having clear testing Instructions on pull requests is the first level of quality engineering in WooCommerce, which is key for testing early and minimizing the impact of unexpected effects in the upcoming versions of WooCommerce.
This page contains the following sections:
- [What is a test?](#what-is-a-test)
- [What to cover with the testing instructions](#what-to-cover-with-the-testing-instructions)
- [Flow to write good testing instructions](#flow-to-write-good-testing-instructions)
- [Examples](#examples)
## What is a test?
A test is a method that we can use to check that something meets certain criteria. It is typically defined as a procedure which contains the steps required to put the system under test in a certain state before executing the action to be checked. Therefore, a test consists of the following stages:
- **Preconditions:** All the steps that need to be performed to put the system in the desired state before executing the action we want to check. A test could have many preconditions.
- **Action:** This is the exact step that causes the change we want to check in the system. It should be only one because each test should ideally cover one thing at a time.
- **Validation:** Relates to the steps to be performed in order to validate the result of performing the action in the system. A test could validate more than one thing.
For example, in the process of adding an item to the cart:
- The **preconditions** would be all the steps involved in:
- The product creation process.
- Logging as a shopper.
- Heading to the shop page where the products are listed.
- The **action** would be clicking the _"Add to cart"_ button in the desired product.
- The **validation** stage would include checking that the cart icon (if any) shows 1 more item and the product we selected is now included in the cart.
Specifying the preconditions, actions and validations can be quite beneficial when understanding the scope of a test, because:
- The **preconditions** describe what we have to do so that we can execute the test successfully.
- The **action** lets us know the purpose of the test, in other words, it is the key to understanding what we need to test.
- The **validation** stage lets us know what to expect when executing the test.
In this context, we will refer to testing instructions as the tests we need to execute in order to validate that the changes delivered in a pull request or release work as expected. This means the testing instructions could refer to a test or more, involving the happy path and potential edge cases.
## What to cover with the testing instructions
As stated in the previous section, a test (in our context, a testing instruction) is a method to check that a new change or set of changes meets certain criteria.
Therefore, a PR could have testing instructions for multiple scenarios, in fact, it is recommended to include testing instructions for as many scenarios as needed to cover the changes introduced in the PR. In other words, please **add as many testing instructions as needed to cover the acceptance criteria**, understanding acceptance criteria as _the conditions that a software product must satisfy to be accepted by a user, customer or other stakeholders_ or, in the context of a PR, the conditions that this PR must satisfy to be accepted by users, developers and the WooCommerce community as per requirements.
## Flow to write good testing instructions
1. **Outline the user flows** you want to cover.
2. **Define the environment** where the testing instructions should be executed (server, PHP version, WP version, required plugins, etc), and start writing the testing instructions as if you were starting from a fresh install.
3. Identify the **preconditions**, **action** and **validation** steps.
4. Write **as many preconditions as you need** to explain how to set up the state of WooCommerce so that you can execute the desired action to test every flow.
1. Try to be detailed when explaining the interactions the user needs to perform in WooCommerce.
2. If there are several preconditions for a user flow that is explained in a public guide, feel free to simply link the guide in the testing instructions instead of writing several steps. For example, _"Enable dev mode in WooCommerce Payments by following the steps mentioned [here](https://woocommerce.com/document/woocommerce-payments/testing-and-troubleshooting/dev-mode/)"_.
5. Write **the action step**, which should cover the specific action that we want to test as part of this user flow.
6. Write **as many validation steps** as needed in order to assess that the actual result meets expectations.
1. Bear in mind to check only the steps needed to validate that this change works.
### Considerations for writing high-quality testing instructions
- Define the testing instructions in a way that they can be **understood and followed by everybody**, even for people new to WooCommerce.
- Make sure to describe every detail and **avoid assuming knowledge**, the spectrum of readers might be wide and some people would not know the concepts behind what is being assumed. For example, instead of saying _“Enable the [x] experiment”_, say something like:
```text
- Install the WooCommerce Beta Tester plugin.
- Go to `Tools > WCA Test Helper > Experiments`.
- Toggle the [x] experiment.
```
- Always try to explain in detail **where the user should head to**, for example instead of saying “Go to the Orders page as admin”, say “Go to [url]” or even “Go to WooCommerce > Orders”.
- Try to use real test data. For example, instead of saying _"Enter a name for the product"_, say something like _"Enter 'Blue T-Shirt' as the product name"_. This will make it more self-explanatory and remove potential doubts related to assuming knowledge.
- Make sure you **keep your testing instructions updated** if they become obsolete as part of a new commit.
- If the testing instructions require to add custom code, please **provide the code snippet**.
- If the testing instructions require to install a plugin, please **provide a link to this plugin, or the zip file** to install it.
- If the testing instructions require to hit an API endpoint, please provide the **link to the endpoint documentation**.
- Ideally **provide screenshots and/or videos** that supported what the testing instructions are explaining. If you are using links to collaborative tools then also provide an equivalent screenshot/video for those who do not have access.
## Examples
### Good quality testing instructions
#### Example 1
![Sample of good quality instructions](https://woocommerce.files.wordpress.com/2023/10/213682695-3dc51613-b836-4e7e-93ef-f75078ab48ac.png)
#### Example 2
![Another sample of good quality instructions](https://woocommerce.files.wordpress.com/2023/10/213682778-b552ab07-a518-48a7-9358-16adc5762aca.png)
### Improving real testing instructions
In this section, you will see some real examples of testing instructions that have room for improvement (before) and how we can tweak them (after).
Before:
![Instructions needing improvement](https://woocommerce.files.wordpress.com/2023/10/213682262-25bec5c3-154c-45ec-aa3d-d3e07f52669e.png)
After:
![Improved instructions](https://woocommerce.files.wordpress.com/2023/10/213682303-1b12ab97-f27a-41cb-a8db-da8a78d18840.png)
Improvements:
![Changes made](https://woocommerce.files.wordpress.com/2023/10/213682323-0ecc998d-69ab-4201-8daa-820b948315e8.png)
Before:
![Instructions needing improvement](https://woocommerce.files.wordpress.com/2023/10/213682396-8c52d20e-1fca-4ac1-8345-f381c15a102a.png)
After:
![Improved instructions](https://woocommerce.files.wordpress.com/2023/10/213682480-c01e0e84-5969-4456-8f43-70cbb8509e8d.png)
Improvements:
![Changes made](https://woocommerce.files.wordpress.com/2023/10/213682597-8d06e638-35dd-4ff8-9236-63c6ec5d05b8.jpg)
Before:
![Screenshot 2023-02-02 at 16 07 29](https://woocommerce.files.wordpress.com/2023/10/216365611-b540a814-3b8f-40f3-ae64-81018b9f97fb.png)
After:
![Screenshot 2023-02-02 at 16 22 31](https://woocommerce.files.wordpress.com/2023/10/216366043-967e5daa-6a23-4ab8-adda-5f3082d1ebf7.png)
Improvements:
![Screenshot 2023-02-02 at 16 09 24](https://woocommerce.files.wordpress.com/2023/10/216366152-b331648d-bcef-443b-b126-de2621a20862.png)
Before:
![Screenshot 2023-02-02 at 17 25 07](https://woocommerce.files.wordpress.com/2023/10/216388785-8806ea74-62e6-42da-8887-c8e291e7dfe2-1.png)
After:
![Screenshot 2023-02-02 at 17 49 22](https://woocommerce.files.wordpress.com/2023/10/216388842-e5ab433e-d288-4306-862f-72f6f81ab2cd.png)
Improvements:
![Screenshot 2023-02-02 at 17 39 23](https://woocommerce.files.wordpress.com/2023/10/216388874-c5b21fc3-f693-4a7e-a58a-c5d1b6606682.png)

View File

@ -52,6 +52,56 @@ How-to guides are focused and specific, providing instructions on how to accompl
>
> [Divio Framework on How-to-Guide Writing](https://documentation.divio.com/how-to-guides/)
## Custom Linting Rules
At WooCommerce, we're dedicated to maintaining a consistent and high-quality standard for our technical documentation. Our documents primarily adhere to the linting rules provided by `markdownlint`. To assist our contributors, we've detailed our custom configurations and exceptions below.
Note: While we've outlined specific rules above, all other default linting rules from `markdownlint` apply unless otherwise stated. We've only highlighted custom configurations or exceptions here. For a complete list of `markdownlint` rules, you can refer to [this link](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md).
1. **Headings Style**:
- Use the ATX-style (`#`) for headers.
```markdown
# This is an H1
## This is an H2
```
[Reference: MD003](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md#md003---heading-style)
2. **List Indentation**:
- Indent list items with 4 spaces.
```markdown
- Item 1
- Subitem 1.1
```
[Reference: MD007]([https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md)#md007---unordered-list-indentation)
3. **Line Length**:
- No specific restriction on the line length, but keep paragraphs and sentences readable.
[Reference: MD013](https://github.com/DavidAnson/markdownlint/blob/main/doc/Rules.md#md013---line-length)
4. **Multiple Headings with the Same Content**:
- Multiple headings with the same content are permissible as long as they are not siblings.
[Reference: MD024](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md#md024---no-multiple-headings-with-the-same-content)
5. **Inline HTML**:
- Only the `video` element is allowed when using inline HTML.
```markdown
<video src="path_to_video.mp4" controls></video>
```
[Reference: MD033](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md#md033---inline-html)
6. **Tabs and Whitespace**:
- We're flexible with the use of hard tabs and trailing whitespace. However, for consistency, we recommend using spaces over tabs and avoiding trailing whitespaces.
[Reference: no-hard-tabs & whitespace](https://github.com/DavidAnson/markdownlint/blob/3561fc3f38b05b3c55f44e371c2cd9bda194598a/doc/Rules.md)
## Formatting
### Visual style

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -78,7 +78,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name --",
"lint": "eslint --output-file eslint_report.json --format json src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -32,7 +32,8 @@
"scripts": {
"turbo:build": "pnpm run clean && npm run compile",
"turbo:test": "jest",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"prepare": "composer install",
"changelog": "composer exec -- changelogger",
"clean": "rm -rf ./dist ./tsconfig.tsbuildinfo",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -65,7 +65,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Set button optional in MediaUploader component

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Image gallery and media uploader now support initial selected images.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: tweak
Small condition change in the date time picker to avoid edge case where inputControl is null.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Fix invalid focus state of the experimental select control

View File

@ -0,0 +1,4 @@
Significance: patch
Type: tweak
Add z-index=1 to tour-kit close btn to ensure it's clickable

View File

@ -0,0 +1,4 @@
Significance: patch
Type: fix
Add class back in for increase specificity of css for dropdown button.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -153,7 +153,8 @@
"prepare": "composer install",
"changelog": "composer exec -- changelogger",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json --ext=js,ts,tsx src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",

View File

@ -265,7 +265,11 @@ export const DateTimePickerControl = forwardRef(
}, [ onBlur ] );
const callOnBlurIfDropdownIsNotOpening = useCallback( ( willOpen ) => {
if ( ! willOpen && typeof onBlurRef.current === 'function' ) {
if (
! willOpen &&
typeof onBlurRef.current === 'function' &&
inputControl.current
) {
// in case the component is blurred before a debounced
// change has been processed, immediately set the input string
// to the current value of the input field, so that

View File

@ -1,4 +1,4 @@
.woocommerce-dropdown-button {
.components-button.woocommerce-dropdown-button {
background-color: $studio-white;
position: relative;
border: 1px solid $gray-700;

View File

@ -17,13 +17,14 @@
}
.woocommerce-experimental-select-control__popover-menu {
.components-popover__content {
max-height: 300px;
overflow-y: scroll;
overflow: hidden;
}
}
.woocommerce-experimental-select-control__popover-menu-container {
margin: 0;
width: 100%;
max-height: 300px;
overflow-y: scroll;
> .category-field-dropdown__item:not(:first-child) {
.category-field-dropdown__item-content {

View File

@ -15,6 +15,7 @@ import {
useEffect,
createElement,
Fragment,
useRef,
} from '@wordpress/element';
import { chevronDown } from '@wordpress/icons';
@ -138,11 +139,13 @@ function SelectControl< ItemType = DefaultItemType >( {
const instanceId = useInstanceId(
SelectControl,
'woocommerce-experimental-select-control'
);
) as string;
const innerInputClassName =
'woocommerce-experimental-select-control__input';
const selectControlWrapperRef = useRef< HTMLDivElement >( null );
let selectedItems = selected === null ? [] : selected;
selectedItems = Array.isArray( selectedItems )
? selectedItems
@ -186,6 +189,7 @@ function SelectControl< ItemType = DefaultItemType >( {
openMenu,
closeMenu,
} = useCombobox< ItemType | null >( {
id: instanceId,
initialSelectedItem: singleSelectedItem,
inputValue,
items: filteredItems,
@ -246,12 +250,15 @@ function SelectControl< ItemType = DefaultItemType >( {
} );
const isEventOutside = ( event: React.FocusEvent ) => {
const inputClasses = event?.target?.className;
const selectControlWrapperElement = selectControlWrapperRef.current;
const menuElement = document.getElementById( `${ instanceId }-menu` );
const parentPopoverMenuElement = menuElement?.closest(
'.woocommerce-experimental-select-control__popover-menu'
);
return (
! document
.querySelector( '.' + instanceId )
?.contains( event.relatedTarget ) &&
! inputClasses.includes( innerInputClassName )
! selectControlWrapperElement?.contains( event.relatedTarget ) &&
! parentPopoverMenuElement?.contains( event.relatedTarget )
);
};
@ -276,10 +283,11 @@ function SelectControl< ItemType = DefaultItemType >( {
return (
<div
id={ instanceId }
ref={ selectControlWrapperRef }
className={ classnames(
'woocommerce-experimental-select-control',
className,
instanceId,
{
'is-read-only': isReadOnly,
'is-focused': isFocused,

View File

@ -15,6 +15,7 @@ export type ImageGalleryItemProps = {
id?: string;
alt: string;
isCover?: boolean;
isDraggable?: boolean;
src: string;
displayToolbar?: boolean;
className?: string;
@ -26,6 +27,7 @@ export const ImageGalleryItem: React.FC< ImageGalleryItemProps > = ( {
id,
alt,
isCover = false,
isDraggable = true,
src,
className = '',
onClick = () => null,
@ -33,7 +35,7 @@ export const ImageGalleryItem: React.FC< ImageGalleryItemProps > = ( {
children,
}: ImageGalleryItemProps ) => (
<ConditionalWrapper
condition={ isCover }
condition={ ! isDraggable }
wrapper={ ( wrappedChildren ) => (
<NonSortableItem>{ wrappedChildren }</NonSortableItem>
) }
@ -48,15 +50,15 @@ export const ImageGalleryItem: React.FC< ImageGalleryItemProps > = ( {
>
{ children }
{ isCover ? (
<>
<Pill>{ __( 'Cover', 'woocommerce' ) }</Pill>
<img alt={ alt } src={ src } id={ id } />
</>
) : (
{ isDraggable ? (
<SortableHandle>
<img alt={ alt } src={ src } id={ id } />
</SortableHandle>
) : (
<>
{ isCover && <Pill>{ __( 'Cover', 'woocommerce' ) }</Pill> }
<img alt={ alt } src={ src } id={ id } />
</>
) }
</div>
</ConditionalWrapper>

View File

@ -25,6 +25,7 @@ import { ImageGalleryToolbarDropdown } from './image-gallery-toolbar-dropdown';
export type ImageGalleryToolbarProps = {
childIndex: number;
allowDragging?: boolean;
value?: number;
moveItem: ( fromIndex: number, toIndex: number ) => void;
removeItem: ( removeIndex: number ) => void;
replaceItem: (
@ -44,6 +45,7 @@ export const ImageGalleryToolbar: React.FC< ImageGalleryToolbarProps > = ( {
replaceItem,
setToolBarItem,
lastChild,
value,
MediaUploadComponent = MediaUpload,
}: ImageGalleryToolbarProps ) => {
const moveNext = () => {
@ -105,6 +107,7 @@ export const ImageGalleryToolbar: React.FC< ImageGalleryToolbarProps > = ( {
{ isCoverItem && (
<ToolbarGroup className="woocommerce-image-gallery__toolbar-media">
<MediaUploadComponent
value={ value }
onSelect={ ( media ) =>
replaceItem( childIndex, media as MediaItem )
}

View File

@ -100,12 +100,11 @@ export const ImageGallery: React.FC< ImageGalleryProps > = ( {
>
{ orderedChildren.map( ( child, childIndex ) => {
const isToolbarVisible = child.key === activeToolbarKey;
const isCoverItem = ( childIndex === 0 ) as boolean;
return cloneElement(
child,
{
isCover: isCoverItem,
isDraggable: allowDragging && ! child.props.isCover,
className: classnames( {
'is-toolbar-visible': isToolbarVisible,
} ),
@ -152,6 +151,7 @@ export const ImageGallery: React.FC< ImageGalleryProps > = ( {
},
isToolbarVisible ? (
<ImageGalleryToolbar
value={ child.props.id }
allowDragging={ allowDragging }
childIndex={ childIndex }
lastChild={

View File

@ -3,7 +3,7 @@
*/
import { __ } from '@wordpress/i18n';
import { Button, DropZone, FormFileUpload } from '@wordpress/components';
import { createElement } from 'react';
import { Fragment, createElement } from 'react';
import {
MediaItem,
MediaUpload,
@ -25,6 +25,7 @@ type MediaUploaderProps = {
props: MediaUpload.Props< T >
) => JSX.Element;
multipleSelect?: boolean | string;
value?: number | number[];
onSelect?: (
// eslint-disable-next-line @typescript-eslint/no-explicit-any
value: ( { id: number } & { [ k: string ]: any } ) | MediaItem[]
@ -35,8 +36,8 @@ type MediaUploaderProps = {
file: File;
} ) => void;
onMediaGalleryOpen?: () => void;
onUpload?: ( files: MediaItem[] ) => void;
onFileUploadChange?: ( files: MediaItem[] ) => void;
onUpload?: ( files: MediaItem | MediaItem[] ) => void;
onFileUploadChange?: ( files: MediaItem | MediaItem[] ) => void;
uploadMedia?: ( options: UploadMediaOptions ) => Promise< void >;
};
@ -48,6 +49,7 @@ export const MediaUploader = ( {
maxUploadFileSize = 10000000,
MediaUploadComponent = MediaUpload,
multipleSelect = false,
value,
onError = () => null,
onFileUploadChange = () => null,
onMediaGalleryOpen = () => null,
@ -55,19 +57,21 @@ export const MediaUploader = ( {
onSelect = () => null,
uploadMedia = wpUploadMedia,
}: MediaUploaderProps ) => {
const getFormFileUploadAcceptedFiles = () =>
allowedMediaTypes.map( ( type ) => `${ type }/*` );
const multiple = Boolean( multipleSelect );
return (
<FormFileUpload
accept={ getFormFileUploadAcceptedFiles().toString() }
multiple={ true }
accept={ allowedMediaTypes.toString() }
multiple={ multiple }
onChange={ ( { currentTarget } ) => {
uploadMedia( {
allowedTypes: allowedMediaTypes,
filesList: currentTarget.files as FileList,
onError,
onFileChange: onFileUploadChange,
maxUploadFileSize,
onError,
onFileChange( files ) {
onFileUploadChange( multiple ? files : files[ 0 ] );
},
} );
} }
render={ ( { openFileDialog } ) => (
@ -94,31 +98,41 @@ export const MediaUploader = ( {
</div>
<MediaUploadComponent
value={ value }
onSelect={ onSelect }
allowedTypes={ allowedMediaTypes }
// @ts-expect-error - TODO multiple also accepts string.
multiple={ multipleSelect }
render={ ( { open } ) => (
<Button
variant="secondary"
onClick={ () => {
onMediaGalleryOpen();
open();
} }
>
{ buttonText }
</Button>
) }
render={ ( { open } ) =>
buttonText ? (
<Button
variant="secondary"
onClick={ () => {
onMediaGalleryOpen();
open();
} }
>
{ buttonText }
</Button>
) : (
<Fragment />
)
}
/>
{ hasDropZone && (
<DropZone
onFilesDrop={ ( files ) =>
onFilesDrop={ ( droppedFiles ) =>
uploadMedia( {
filesList: files,
onError,
onFileChange: onUpload,
allowedTypes: allowedMediaTypes,
filesList: droppedFiles,
maxUploadFileSize,
onError,
onFileChange( files ) {
onUpload(
multiple ? files : files[ 0 ]
);
},
} )
}
/>

View File

@ -40,6 +40,8 @@
height: 16px;
min-width: 16px;
padding: 0;
z-index: 1;
svg {
fill: #1e1e1e;
}

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -40,7 +40,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -43,7 +43,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -79,7 +79,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add name and parent_id to the ProductVariation type definition

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -86,7 +86,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -55,7 +55,7 @@ export interface ProductVariationImage {
export type ProductVariation = Omit<
Product,
'name' | 'slug' | 'attributes' | 'images' | 'manage_stock'
'slug' | 'attributes' | 'images' | 'manage_stock'
> & {
attributes: ProductVariationAttribute[];
/**
@ -70,6 +70,10 @@ export type ProductVariation = Omit<
* @default false
*/
manage_stock: boolean | 'parent';
/**
* The product id this variation belongs to
*/
parent_id: number;
};
type Query = Omit< ProductQuery, 'name' >;

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -63,7 +63,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -89,7 +89,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -61,7 +61,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
};

View File

@ -0,0 +1 @@
package-lock=false

View File

@ -0,0 +1,3 @@
# Changelog
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

View File

@ -0,0 +1,314 @@
# @woocommerce/expression-evaluation
Evaluation of JavaScript-like expressions in an optional context.
Examples of simple expressions:
```js
1 + 2
```
```js
foo === 'bar'
```
```js
foo ? 'bar' : 'baz'
```
Examples of complex expressions:
```js
foo.bar.baz === 'qux'
```
```js
foo.bar
&& ( foo.bar.baz === 'qux' || foo.baz === 'quux' )
```
```js
foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
```
```js
foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
? "boo"
: "baa"
```
```js
foo
+ 5
/* This is a comment */
* ( bar ? baz : qux )
```
## API
### evaluate
Evaluates an expression in an optional context.
#### Usage
```js
import { evaluate } from '@woocommerce/expression-evaluation';
const result = evaluate( '1 + foo', { foo: 2 } );
console.log( result ); // 3
```
#### Parameters
- _expression_ `string`: The expression to evaluate.
- _context_ `Object`: Optional. The context to evaluate the expression in. Variables in the expression will be looked up in this object.
#### Returns
- `any`: The result of the expression evaluation.
## Expression syntax
### Grammar and types
The expression syntax is based on JavaScript. The formal grammar is defined in [parser.ts](./src/parser.ts).
An expression consists of a single statement.
Features like `if` statements, `for` loops, function calls, and variable assignments, are not supported.
The following types are supported:
- `null`
- Boolean: `true` and `false`
- Number: An integer or floating point number.
- String: A sequence of characters that represent text.
### Literals
Values in an expression can be written as literals.
#### null
```js
null
```
#### Boolean
```js
true
false
```
#### Number
```js
1
5.23
-9
```
#### String
String literals can be written with single or double quotes. This can be helpful if the string contains a single or double quote.
```js
'foo'
"foo"
'foo "bar"'
"foo 'bar'"
```
Quotes can be escaped with a backslash.
```js
'foo \'bar\''
"foo \"bar\""
```
### Context variables
Variables can be used in an expression. The value of a variable is looked up in the context.
```js
const result = evaluate( 'foo', { foo: 1 } );
console.log( result ); // 1
```
Nested properties can be accessed with the dot operator.
```js
const result = evaluate( 'foo.bar', { foo: { bar: 1 } } );
console.log( result ); // 1
```
### Operators
The following operators are supported.
#### Comparison operators
##### Equal (`==`)
Returns `true` if the operands are equal.
```js
1 == 1
```
##### Not equal (`!=`)
Returns `true` if the operands are not equal.
```js
1 != 2
```
##### Strict equal (`===`)
Returns `true` if the operands are equal and of the same type.
```js
1 === 1
```
##### Strict not equal (`!==`)
Returns `true` if the operands are not equal and/or not of the same type.
```js
1 !== "1"
```
##### Greater than (`>`)
Returns `true` if the left operand is greater than the right operand.
```js
2 > 1
```
##### Greater than or equal (`>=`)
Returns `true` if the left operand is greater than or equal to the right operand.
```js
2 >= 2
```
##### Less than (`<`)
Returns `true` if the left operand is less than the right operand.
```js
1 < 2
```
##### Less than or equal (`<=`)
Returns `true` if the left operand is less than or equal to the right operand.
```js
2 <= 2
```
#### Arithmetic operators
##### Addition (`+`)
Returns the sum of two operands.
```js
1 + 2
```
##### Subtraction (`-`)
Returns the difference of two operands.
```js
2 - 1
```
##### Multiplication (`*`)
Returns the product of two operands.
```js
2 * 3
```
##### Division (`/`)
Returns the quotient of two operands.
```js
6 / 2
```
##### Modulus (`%`)
Returns the remainder of two operands.
```js
5 % 2
```
##### Negation (`-`)
Returns the negation of an operand.
```js
-1
```
#### Logical operators
##### Logical AND (`&&`)
Returns `true` if both operands are `true`.
```js
true && true
```
##### Logical OR (`||`)
Returns `true` if either operand is `true`.
```js
true || false
```
##### Logical NOT (`!`)
Returns `true` if the operand is `false`.
```js
!false
```
#### Conditional (ternary) operator
Returns the first value if the condition is `true`, otherwise it returns the second value.
```js
true ? 1 : 2
```
### Comments
Comments can be used to document an expression. Comments are treated as whitespace and are ignored by the parser.
```js
/* This is a comment */
```

View File

@ -0,0 +1,3 @@
module.exports = {
extends: '../internal-js-tests/babel.config.js',
};

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Initial @woocommerce/expression-evaluation package.

View File

@ -0,0 +1,32 @@
{
"name": "woocommerce/expression-evaluation",
"description": "WooCommerce expression evaluation library",
"type": "library",
"license": "GPL-3.0-or-later",
"minimum-stability": "dev",
"require-dev": {
"automattic/jetpack-changelogger": "3.3.0"
},
"config": {
"platform": {
"php": "7.2"
}
},
"extra": {
"changelogger": {
"formatter": {
"filename": "../../../tools/changelogger/class-package-formatter.php"
},
"types": {
"fix": "Fixes an existing bug",
"add": "Adds functionality",
"update": "Update existing functionality",
"dev": "Development related task",
"tweak": "A minor adjustment to the codebase",
"performance": "Address performance issues",
"enhancement": "Improve existing functionality"
},
"changelog": "CHANGELOG.md"
}
}
}

View File

@ -0,0 +1,483 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "76226c5737d8666789d8a162710469da",
"packages": [],
"packages-dev": [
{
"name": "automattic/jetpack-changelogger",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/jetpack-changelogger.git",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Automattic/jetpack-changelogger/zipball/8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"shasum": ""
},
"require": {
"php": ">=5.6",
"symfony/console": "^3.4 || ^5.2 || ^6.0",
"symfony/process": "^3.4 || ^5.2 || ^6.0",
"wikimedia/at-ease": "^1.2 || ^2.0"
},
"require-dev": {
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0",
"yoast/phpunit-polyfills": "1.0.4"
},
"bin": [
"bin/changelogger"
],
"type": "project",
"extra": {
"autotagger": true,
"branch-alias": {
"dev-trunk": "3.3.x-dev"
},
"mirror-repo": "Automattic/jetpack-changelogger",
"version-constants": {
"::VERSION": "src/Application.php"
},
"changelogger": {
"link-template": "https://github.com/Automattic/jetpack-changelogger/compare/${old}...${new}"
}
},
"autoload": {
"psr-4": {
"Automattic\\Jetpack\\Changelog\\": "lib",
"Automattic\\Jetpack\\Changelogger\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.",
"support": {
"source": "https://github.com/Automattic/jetpack-changelogger/tree/v3.3.0"
},
"time": "2022-12-26T13:49:01+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "symfony/console",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/debug": "~2.8|~3.0|~4.0",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "symfony/debug",
"version": "4.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v4.4.44"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"abandoned": "symfony/error-handler",
"time": "2022-07-28T16:29:46+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/process",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "wikimedia/at-ease",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/wikimedia/at-ease.git",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wikimedia/at-ease/zipball/013ac61929797839c80a111a3f1a4710d8248e7a",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a",
"shasum": ""
},
"require": {
"php": ">=5.6.99"
},
"require-dev": {
"jakub-onderka/php-console-highlighter": "0.3.2",
"jakub-onderka/php-parallel-lint": "1.0.0",
"mediawiki/mediawiki-codesniffer": "22.0.0",
"mediawiki/minus-x": "0.3.1",
"ockcyp/covers-validator": "0.5.1 || 0.6.1",
"phpunit/phpunit": "4.8.36 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/Wikimedia/Functions.php"
],
"psr-4": {
"Wikimedia\\AtEase\\": "src/Wikimedia/AtEase/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Tim Starling",
"email": "tstarling@wikimedia.org"
},
{
"name": "MediaWiki developers",
"email": "wikitech-l@lists.wikimedia.org"
}
],
"description": "Safe replacement to @ for suppressing warnings.",
"homepage": "https://www.mediawiki.org/wiki/at-ease",
"support": {
"source": "https://github.com/wikimedia/at-ease/tree/master"
},
"time": "2018-10-10T15:39:06+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"platform-overrides": {
"php": "7.2"
},
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,4 @@
{
"rootDir": "./src",
"preset": "../node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}

View File

@ -0,0 +1,69 @@
{
"name": "@woocommerce/expression-evaluation",
"version": "0.0.1",
"description": "Library for evaluating expressions.",
"author": "Automattic",
"license": "GPL-3.0-or-later",
"keywords": [
"wordpress",
"woocommerce",
"expression",
"evalution"
],
"engines": {
"node": "^16.14.1",
"pnpm": "^8.6.7"
},
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/expression-evaluation/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"module": "build-module/index.js",
"types": "build-types",
"react-native": "src/index",
"dependencies": {
"@wordpress/i18n": "wp-6.0",
"peggy": "^3.0.2"
},
"publishConfig": {
"access": "public"
},
"scripts": {
"turbo:build": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"turbo:test": "jest --config ./jest.config.json",
"prepare": "composer install",
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",
"lint:fix": "eslint src --fix",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"
},
"devDependencies": {
"@babel/core": "^7.17.5",
"@types/jest": "^27.4.1",
"@woocommerce/eslint-plugin": "workspace:*",
"@woocommerce/internal-js-tests": "workspace:*",
"concurrently": "^7.0.0",
"eslint": "^8.32.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^5.1.6"
},
"lint-staged": {
"*.(t|j)s?(x)": [
"pnpm lint:fix",
"pnpm test-staged"
]
}
}

View File

@ -0,0 +1,9 @@
/**
* Internal dependencies
*/
import { parser } from './parser';
export function evaluate( expression: string, context = {} ) {
return parser.parse( expression, { context } );
}

View File

@ -0,0 +1,404 @@
/**
* External dependencies
*/
import * as peggy from 'peggy';
const grammar = `
{{
function evaluateUnaryExpression( operator, operand ) {
switch ( operator ) {
case '!':
return !operand;
break;
case '-':
return -operand;
break;
case '+':
return +operand;
break;
default:
return undefined;
break;
}
}
function evaluateBinaryExpression( head, tail ) {
return tail.reduce( ( leftOperand, tailElement ) => {
const operator = tailElement[ 1 ];
const rightOperand = tailElement[ 3 ];
switch ( operator ) {
case '&&':
return leftOperand && rightOperand;
break;
case '||':
return leftOperand || rightOperand;
break;
case '===':
return leftOperand === rightOperand;
break;
case '!==':
return leftOperand !== rightOperand;
break;
case '==':
return leftOperand == rightOperand;
break;
case '!=':
return leftOperand != rightOperand;
break;
case '<=':
return leftOperand <= rightOperand;
break;
case '<':
return leftOperand < rightOperand;
break;
case '>=':
return leftOperand >= rightOperand;
break;
case '>':
return leftOperand > rightOperand;
break;
case '+':
return leftOperand + rightOperand;
break;
case '-':
return leftOperand - rightOperand;
break;
case '*':
return leftOperand * rightOperand;
break;
case '/':
return leftOperand / rightOperand;
break;
case '%':
return leftOperand % rightOperand;
break;
default:
return undefined;
break;
}
}, head );
}
}}
Start
= Expression
SourceCharacter
= .
WhiteSpace
= " "
/ "\\t"
LineTerminator
= "\\n"
/ "\\r"
/ "\\u2028"
/ "\\u2029"
LineTerminatorSequence
= "\\n"
/ "\\r\\n"
/ "\\r"
/ "\\u2028"
/ "\\u2029"
Comment "comment"
= MultiLineComment
MultiLineComment
= "/*" (!"*/" SourceCharacter)* "*/"
__ "skipped"
= (WhiteSpace / LineTerminatorSequence / Comment)*
IdentifierPath
= variable:Identifier accessor:(__ "." __ Identifier)* {
const path = variable.split( '.' );
let result = path.reduce( ( nextObject, propertyName ) => nextObject[ propertyName ], options.context );
for ( let i = 0; i < accessor.length; i++ ) {
result = result[ accessor[ i ][ 3 ] ];
}
return result;
}
Identifier
= !ReservedWord name:IdentifierName {
return name;
}
IdentifierName
= first:IdentifierStart rest:IdentifierPart* {
return text();
}
IdentifierStart
= [a-zA-Z]
/ "_"
/ "$"
IdentifierPart
= IdentifierStart
ReservedWord
= NullLiteral
/ BooleanLiteral
// Literals
Literal
= NullLiteral
/ BooleanLiteral
/ NumericLiteral
/ StringLiteral
NullLiteral
= NullToken { return null; }
BooleanLiteral
= "true" { return true; }
/ "false" { return false; }
NumericLiteral
= literal:HexIntegerLiteral !(IdentifierStart / DecimalDigit) {
return literal;
}
/ literal:DecimalLiteral !(IdentifierStart / DecimalDigit) {
return literal;
}
HexIntegerLiteral
= "0x"i digits:$HexDigit+ {
return parseInt( digits, 16 );
}
HexDigit
= [0-9a-f]i
DecimalLiteral
= DecimalIntegerLiteral "." DecimalDigit* ExponentPart? {
return parseFloat( text() );
}
/ "." DecimalDigit+ ExponentPart? {
return parseFloat( text() );
}
/ DecimalIntegerLiteral ExponentPart? {
return parseFloat( text() );
}
DecimalIntegerLiteral
= "0"
/ NonZeroDigit DecimalDigit*
DecimalDigit
= [0-9]
NonZeroDigit
= [1-9]
ExponentPart
= ExponentIndicator SignedInteger
ExponentIndicator
= "e"i
SignedInteger
= [+-]? DecimalDigit+
StringLiteral
= '"' chars:DoubleQuotedStringCharacter* '"' {
return chars.join( '' );
}
/ "'" chars:SingleQuotedStringCharacter* "'" {
return chars.join( '' );
}
DoubleQuotedStringCharacter
= !('"' / "\\\\" / LineTerminator) SourceCharacter {
return text();
}
/ "\\\\" escapeSequence:EscapeSequence {
return escapeSequence;
}
/ LineContinuation
SingleQuotedStringCharacter
= !("'" / "\\\\" / LineTerminator) SourceCharacter {
return text();
}
/ "\\\\" escapeSequence:EscapeSequence {
return escapeSequence;
}
/ LineContinuation
LineContinuation
= "\\\\" LineTerminatorSequence {
return '';
}
EscapeSequence
= CharacterEscapeSequence
/ "0" !DecimalDigit {
return "\\0";
}
/ HexEscapeSequence
/ UnicodeEscapeSequence
CharacterEscapeSequence
= SingleEscapeCharacter
/ NonEscapeCharacter
SingleEscapeCharacter
= "'"
/ '"'
/ "\\\\"
/ "b" {
return "\\b";
}
/ "f" {
return "\\f";
}
/ "n" {
return "\\n";
}
/ "r" {
return "\\r";
}
/ "t" {
return "\\t";
}
/ "v" {
return "\\v";
}
NonEscapeCharacter
= (!EscapeCharacter / LineTerminator) SourceCharacter {
return text();
}
EscapeCharacter
= SingleEscapeCharacter
/ DecimalDigit
/ "x"
/ "u"
HexEscapeSequence
= "x" digits:$(HexDigit HexDigit) {
return String.fromCharCode( parseInt( digits, 16 ) );
}
UnicodeEscapeSequence
= "u" digits:$(HexDigit HexDigit HexDigit HexDigit) {
return String.fromCharCode( parseInt( digits, 16 ) );
}
// Tokens
NullToken
= "null" !IdentifierPart
TrueToken
= "true" !IdentifierPart
FalseToken
= "false" !IdentifierPart
// Expressions
PrimaryExpression
= IdentifierPath
/ Literal
/ "(" __ expression:Expression __ ")" {
return expression;
}
UnaryExpression
= PrimaryExpression
/ operator:UnaryOperator __ operand:UnaryExpression {
return evaluateUnaryExpression( operator, operand );
}
UnaryOperator
= "!"
/ "-"
/ "+"
MultiplicativeExpression
= head:UnaryExpression tail:(__ MultiplicativeOperator __ UnaryExpression)* {
return evaluateBinaryExpression( head, tail );
}
MultiplicativeOperator
= "*"
/ "/"
/ "%"
AdditiveExpression
= head:MultiplicativeExpression tail:(__ AdditiveOperator __ MultiplicativeExpression)* {
return evaluateBinaryExpression( head, tail );
}
AdditiveOperator
= "+"
/ "-"
RelationalExpression
= head:AdditiveExpression tail:(__ RelationalOperator __ AdditiveExpression)* {
return evaluateBinaryExpression( head, tail );
}
RelationalOperator
= "<="
/ "<"
/ ">="
/ ">"
EqualityExpression
= head:RelationalExpression tail:(__ EqualityOperator __ RelationalExpression)* {
return evaluateBinaryExpression( head, tail );
}
EqualityOperator
= "==="
/ "!=="
/ "=="
/ "!="
LogicalAndExpression
= head:EqualityExpression tail:(__ LogicalAndOperator __ EqualityExpression)* {
return evaluateBinaryExpression( head, tail );
}
LogicalAndOperator
= "&&"
LogicalOrExpression
= head:LogicalAndExpression tail:(__ LogicalOrOperator __ LogicalAndExpression)* {
return evaluateBinaryExpression( head, tail );
}
LogicalOrOperator
= "||"
ConditionalExpression
= condition:LogicalOrExpression __ ConditionalTrueOperator __ expressionIfTrue:ConditionalExpression __ ConditionalFalseOperator __ expressionIfFalse:ConditionalExpression {
return condition ? expressionIfTrue : expressionIfFalse;
}
/ LogicalOrExpression
ConditionalTrueOperator
= "?"
ConditionalFalseOperator
= ":"
Expression
= __ expression:ConditionalExpression __ {
return expression;
}
`;
export const parser = peggy.generate( grammar );

View File

@ -0,0 +1,482 @@
/**
* Internal dependencies
*/
import { evaluate } from '../';
describe( 'evaluate', () => {
it( 'should evaluate a null literal', () => {
const result = evaluate( 'null' );
expect( result ).toEqual( null );
} );
it( 'should evaluate a boolean true literal', () => {
const result = evaluate( 'true' );
expect( result ).toEqual( true );
} );
it( 'should evaluate a boolean false literal', () => {
const result = evaluate( 'false' );
expect( result ).toEqual( false );
} );
it( 'should evaluate a numeric integer literal', () => {
const result = evaluate( '23' );
expect( result ).toEqual( 23 );
} );
it( 'should evaluate a signed negative integer literal', () => {
const result = evaluate( '-1' );
expect( result ).toEqual( -1 );
} );
it( 'should evaluate a signed positive integer literal', () => {
const result = evaluate( '+1' );
expect( result ).toEqual( 1 );
} );
it( 'should evaluate a numeric floating point literal', () => {
const result = evaluate( '5.23' );
expect( result ).toEqual( 5.23 );
} );
it( 'should evaluate a signed negative floating point literal', () => {
const result = evaluate( '-9.95' );
expect( result ).toEqual( -9.95 );
} );
it( 'should evaluate a signed positive floating point literal', () => {
const result = evaluate( '+9.95' );
expect( result ).toEqual( 9.95 );
} );
it( 'should evaluate a numeric hexadecimal literal', () => {
const result = evaluate( '0x23' );
expect( result ).toEqual( 35 );
} );
it( 'should evaluate a string literal with double quotes', () => {
const result = evaluate( '"foo"' );
expect( result ).toEqual( 'foo' );
} );
it( 'should evaluate a string literal with double quotes and single quotes', () => {
const result = evaluate( '"foo \'bar\'"' );
expect( result ).toEqual( "foo 'bar'" );
} );
it( 'should evaluate a string literal with double quotes and escaped double quotes', () => {
const result = evaluate( '"foo \\"bar\\""' );
expect( result ).toEqual( 'foo "bar"' );
} );
it( 'should evaluate a string literal with double quotes and escaped backslashes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( '"foo \\\\\\"bar\\\\\\""' );
expect( result ).toEqual( 'foo \\"bar\\"' );
} );
it( 'should evaluate a string literal with single quotes', () => {
const result = evaluate( "'foo'" );
expect( result ).toEqual( 'foo' );
} );
it( 'should evaluate a string literal with single quotes and double quotes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( "'foo \"bar\"'" );
expect( result ).toEqual( 'foo "bar"' );
} );
it( 'should evaluate a string literal with single quotes and escaped single quotes', () => {
const result = evaluate( "'foo \\'bar\\''" );
expect( result ).toEqual( "foo 'bar'" );
} );
it( 'should evaluate a string literal with single quotes and escaped backslashes', () => {
// eslint-disable-next-line prettier/prettier
const result = evaluate( "'foo \\\\\\'bar\\\\\\''" );
expect( result ).toEqual( "foo \\'bar\\'" );
} );
it( 'should evaluate a literal with whitespace around it', () => {
const result = evaluate( ' 23 ' );
expect( result ).toEqual( 23 );
} );
it( 'should evaluate a top-level context property', () => {
const result = evaluate( 'foo', {
foo: 'bar',
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a top-level context property with whitespace', () => {
const result = evaluate( ' foo ', {
foo: 'bar',
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a nested context property', () => {
const result = evaluate( 'foo.bar', {
foo: {
bar: 'baz',
},
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with whitespace', () => {
const result = evaluate( 'foo. bar', {
foo: {
bar: 'baz',
},
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a nested context property with multiple lines', () => {
const result = evaluate(
`foo.
bar`,
{
foo: {
bar: 'baz',
},
}
);
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a NOT expression', () => {
const result = evaluate( '!foo', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a double NOT expression', () => {
const result = evaluate( '!!foo', {
foo: true,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a NOT expression with parentheses', () => {
const result = evaluate( '!( foo )', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a NOT expression with parentheses and spaces', () => {
const result = evaluate( '! ( foo ) ', {
foo: true,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a multiplication expression', () => {
const result = evaluate( 'foo * 2', {
foo: 2,
} );
expect( result ).toEqual( 4 );
} );
it( 'should evaluate a division expression', () => {
const result = evaluate( 'foo / 2', {
foo: 4,
} );
expect( result ).toEqual( 2 );
} );
it( 'should evaluate a modulo expression', () => {
const result = evaluate( 'foo % 2', {
foo: 5,
} );
expect( result ).toEqual( 1 );
} );
it( 'should evaluate an addition expression', () => {
const result = evaluate( 'foo + 2', {
foo: 3,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate a subtraction expression', () => {
const result = evaluate( 'foo - 2', {
foo: 5,
} );
expect( result ).toEqual( 3 );
} );
it( 'should evaluate a complex arithmetic expression', () => {
const result = evaluate( 'foo * 2 + 1', {
foo: 3,
} );
expect( result ).toEqual( 7 );
} );
it( 'should evaluate a complex arithmetic expression with parenthesis', () => {
const result = evaluate( 'foo * (2 + 1)', {
foo: 3,
} );
expect( result ).toEqual( 9 );
} );
it( 'should evaluate a less than or equal expression', () => {
const result = evaluate( 'foo <= 1', {
foo: 1,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a less than expression', () => {
const result = evaluate( 'foo < 1', {
foo: 1,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a greater than or equal expression', () => {
const result = evaluate( 'foo >= 1', {
foo: 1,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a greater than expression', () => {
const result = evaluate( 'foo > 1', {
foo: 1,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate an strict equality expression', () => {
const result = evaluate( 'foo === "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an strict inequality expression', () => {
const result = evaluate( 'foo !== "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate an equality expression', () => {
const result = evaluate( 'foo == "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an inequality expression', () => {
const result = evaluate( 'foo != "bar"', {
foo: 'bar',
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a conditional expression that is true', () => {
const result = evaluate( 'foo ? "bar" : "baz"', {
foo: true,
} );
expect( result ).toEqual( 'bar' );
} );
it( 'should evaluate a conditional expression that is false', () => {
const result = evaluate( 'foo ? "bar" : "baz"', {
foo: false,
} );
expect( result ).toEqual( 'baz' );
} );
it( 'should evaluate a logical OR expression', () => {
const result = evaluate( 'foo || bar', {
foo: true,
bar: false,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate a logical AND expression', () => {
const result = evaluate( 'foo && bar', {
foo: true,
bar: false,
} );
expect( result ).toEqual( false );
} );
it( 'should evaluate a multiline expression', () => {
const result = evaluate(
`foo
|| bar
|| baz`,
{
foo: false,
bar: false,
baz: true,
}
);
expect( result ).toEqual( true );
} );
it( 'should evaluate a complex expression', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )`,
{
foo: {
bar: true,
baz: 'quux',
},
}
);
expect( result ).toEqual( true );
} );
it( 'should evaluate a complex expression with arithmetic, relational, and logical operators', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )`,
{
foo: {
bar: true,
baz: 'quux',
quux: 10,
},
}
);
expect( result ).toEqual( false );
} );
it( 'should evaluate a complex expression with conditional, arithmetic, relational, and logical operators', () => {
const result = evaluate(
`foo.bar
&& ( foo.baz === "qux" || foo.baz === "quux" )
&& ( foo.quux > 1 && foo.quux <= 5 )
? "boo"
: "baa"`,
{
foo: {
bar: true,
baz: 'quux',
quux: 10,
},
}
);
expect( result ).toEqual( 'baa' );
} );
it( 'should evaluate an expression with needless parentheses', () => {
const result = evaluate( '(((foo)))', {
foo: true,
} );
expect( result ).toEqual( true );
} );
it( 'should evaluate an expression with a multiline comment at the end', () => {
const result = evaluate( 'foo /* + 23 */', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment at the beginning', () => {
const result = evaluate( '/* 23 + */ foo', {
foo: 5,
} );
expect( result ).toEqual( 5 );
} );
it( 'should evaluate an expression with a multiline comment in the middle', () => {
const result = evaluate( 'foo + /* 23 */ bar', {
foo: 5,
bar: 3,
} );
expect( result ).toEqual( 8 );
} );
it( 'should evaluate a multiline expression with a multiline comment', () => {
const result = evaluate(
`foo
/*
+ bar
+ boo
*/
+ baz`,
{
foo: 5,
bar: 23,
boo: 6,
baz: 3,
}
);
expect( result ).toEqual( 8 );
} );
it( 'should throw an error if the expression is invalid', () => {
expect( () => evaluate( '= 1' ) ).toThrow();
} );
} );

View File

@ -0,0 +1,11 @@
{
"extends": "../tsconfig-cjs",
"compilerOptions": {
"declaration": true,
"outDir": "build",
"typeRoots": [
"./typings",
"./node_modules/@types"
]
}
}

View File

@ -0,0 +1,14 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"rootDir": "src",
"outDir": "build-module",
"declaration": true,
"declarationMap": true,
"declarationDir": "./build-types",
"typeRoots": [
"./typings",
"./node_modules/@types"
]
}
}

View File

@ -0,0 +1,12 @@
module.exports = {
extends: [ 'plugin:@woocommerce/eslint-plugin/recommended' ],
root: true,
overrides: [
{
files: [ '**/*.js', '**/*.jsx', '**/*.tsx' ],
rules: {
'react/react-in-jsx-scope': 'off',
},
},
],
};

View File

@ -0,0 +1 @@
package-lock=false

View File

@ -0,0 +1,4 @@
# @woocommerce/integrate-plugin
Integrate plugin is a tool to help existing WordPress plugins get set up with JavaScript & React in order to extend and create Blocks.
The tool can also be used for scaffolding block examples.

View File

@ -0,0 +1,3 @@
module.exports = {
extends: '../internal-js-tests/babel.config.js',
};

View File

@ -0,0 +1,3 @@
#!/usr/bin/env node
require( '../build' );

View File

@ -0,0 +1,3 @@
# Changelog
This project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add initial scripts for integrate plugin to get plugin details.

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Initial version of @woocommerce/block-templates package. Adds registerWooBlockType and useWooBlockProps.

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -0,0 +1,32 @@
{
"name": "woocommerce/block-templates",
"description": "WooCommerce Admin block templates component library",
"type": "library",
"license": "GPL-3.0-or-later",
"minimum-stability": "dev",
"require-dev": {
"automattic/jetpack-changelogger": "3.3.0"
},
"config": {
"platform": {
"php": "7.2"
}
},
"extra": {
"changelogger": {
"formatter": {
"filename": "../../../tools/changelogger/class-package-formatter.php"
},
"types": {
"fix": "Fixes an existing bug",
"add": "Adds functionality",
"update": "Update existing functionality",
"dev": "Development related task",
"tweak": "A minor adjustment to the codebase",
"performance": "Address performance issues",
"enhancement": "Improve existing functionality"
},
"changelog": "CHANGELOG.md"
}
}
}

483
packages/js/integrate-plugin/composer.lock generated Normal file
View File

@ -0,0 +1,483 @@
{
"_readme": [
"This file locks the dependencies of your project to a known state",
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "2d316cec186ab12385e8dda54f6df0f6",
"packages": [],
"packages-dev": [
{
"name": "automattic/jetpack-changelogger",
"version": "v3.3.0",
"source": {
"type": "git",
"url": "https://github.com/Automattic/jetpack-changelogger.git",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/Automattic/jetpack-changelogger/zipball/8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"reference": "8f63c829b8d1b0d7b1d5de93510d78523ed18959",
"shasum": ""
},
"require": {
"php": ">=5.6",
"symfony/console": "^3.4 || ^5.2 || ^6.0",
"symfony/process": "^3.4 || ^5.2 || ^6.0",
"wikimedia/at-ease": "^1.2 || ^2.0"
},
"require-dev": {
"wikimedia/testing-access-wrapper": "^1.0 || ^2.0",
"yoast/phpunit-polyfills": "1.0.4"
},
"bin": [
"bin/changelogger"
],
"type": "project",
"extra": {
"autotagger": true,
"branch-alias": {
"dev-trunk": "3.3.x-dev"
},
"mirror-repo": "Automattic/jetpack-changelogger",
"version-constants": {
"::VERSION": "src/Application.php"
},
"changelogger": {
"link-template": "https://github.com/Automattic/jetpack-changelogger/compare/${old}...${new}"
}
},
"autoload": {
"psr-4": {
"Automattic\\Jetpack\\Changelog\\": "lib",
"Automattic\\Jetpack\\Changelogger\\": "src"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.",
"support": {
"source": "https://github.com/Automattic/jetpack-changelogger/tree/v3.3.0"
},
"time": "2022-12-26T13:49:01+00:00"
},
{
"name": "psr/log",
"version": "1.1.4",
"source": {
"type": "git",
"url": "https://github.com/php-fig/log.git",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/php-fig/log/zipball/d49695b909c3b7628b6289db5479a1c204601f11",
"reference": "d49695b909c3b7628b6289db5479a1c204601f11",
"shasum": ""
},
"require": {
"php": ">=5.3.0"
},
"type": "library",
"extra": {
"branch-alias": {
"dev-master": "1.1.x-dev"
}
},
"autoload": {
"psr-4": {
"Psr\\Log\\": "Psr/Log/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "PHP-FIG",
"homepage": "https://www.php-fig.org/"
}
],
"description": "Common interface for logging libraries",
"homepage": "https://github.com/php-fig/log",
"keywords": [
"log",
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
"name": "symfony/console",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/console.git",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"reference": "a10b1da6fc93080c180bba7219b5ff5b7518fe81",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8",
"symfony/debug": "~2.8|~3.0|~4.0",
"symfony/polyfill-mbstring": "~1.0"
},
"conflict": {
"symfony/dependency-injection": "<3.4",
"symfony/process": "<3.3"
},
"provide": {
"psr/log-implementation": "1.0"
},
"require-dev": {
"psr/log": "~1.0",
"symfony/config": "~3.3|~4.0",
"symfony/dependency-injection": "~3.4|~4.0",
"symfony/event-dispatcher": "~2.8|~3.0|~4.0",
"symfony/lock": "~3.4|~4.0",
"symfony/process": "~3.3|~4.0"
},
"suggest": {
"psr/log": "For using the console logger",
"symfony/event-dispatcher": "",
"symfony/lock": "",
"symfony/process": ""
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Console\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "symfony/debug",
"version": "4.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/debug.git",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/debug/zipball/1a692492190773c5310bc7877cb590c04c2f05be",
"reference": "1a692492190773c5310bc7877cb590c04c2f05be",
"shasum": ""
},
"require": {
"php": ">=7.1.3",
"psr/log": "^1|^2|^3"
},
"conflict": {
"symfony/http-kernel": "<3.4"
},
"require-dev": {
"symfony/http-kernel": "^3.4|^4.0|^5.0"
},
"default-branch": true,
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Debug\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Provides tools to ease debugging PHP code",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v4.4.44"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"abandoned": "symfony/error-handler",
"time": "2022-07-28T16:29:46+00:00"
},
{
"name": "symfony/polyfill-mbstring",
"version": "1.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/polyfill-mbstring.git",
"reference": "42292d99c55abe617799667f454222c54c60e229"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/polyfill-mbstring/zipball/42292d99c55abe617799667f454222c54c60e229",
"reference": "42292d99c55abe617799667f454222c54c60e229",
"shasum": ""
},
"require": {
"php": ">=7.1"
},
"provide": {
"ext-mbstring": "*"
},
"suggest": {
"ext-mbstring": "For best performance"
},
"default-branch": true,
"type": "library",
"extra": {
"branch-alias": {
"dev-main": "1.28-dev"
},
"thanks": {
"name": "symfony/polyfill",
"url": "https://github.com/symfony/polyfill"
}
},
"autoload": {
"files": [
"bootstrap.php"
],
"psr-4": {
"Symfony\\Polyfill\\Mbstring\\": ""
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Nicolas Grekas",
"email": "p@tchwork.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony polyfill for the Mbstring extension",
"homepage": "https://symfony.com",
"keywords": [
"compatibility",
"mbstring",
"polyfill",
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.28.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2023-07-28T09:04:16+00:00"
},
{
"name": "symfony/process",
"version": "3.4.x-dev",
"source": {
"type": "git",
"url": "https://github.com/symfony/process.git",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/symfony/process/zipball/b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"reference": "b8648cf1d5af12a44a51d07ef9bf980921f15fca",
"shasum": ""
},
"require": {
"php": "^5.5.9|>=7.0.8"
},
"type": "library",
"autoload": {
"psr-4": {
"Symfony\\Component\\Process\\": ""
},
"exclude-from-classmap": [
"/Tests/"
]
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"authors": [
{
"name": "Fabien Potencier",
"email": "fabien@symfony.com"
},
{
"name": "Symfony Community",
"homepage": "https://symfony.com/contributors"
}
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/3.4"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
"type": "custom"
},
{
"url": "https://github.com/fabpot",
"type": "github"
},
{
"url": "https://tidelift.com/funding/github/packagist/symfony/symfony",
"type": "tidelift"
}
],
"time": "2020-10-24T10:57:07+00:00"
},
{
"name": "wikimedia/at-ease",
"version": "v2.0.0",
"source": {
"type": "git",
"url": "https://github.com/wikimedia/at-ease.git",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/wikimedia/at-ease/zipball/013ac61929797839c80a111a3f1a4710d8248e7a",
"reference": "013ac61929797839c80a111a3f1a4710d8248e7a",
"shasum": ""
},
"require": {
"php": ">=5.6.99"
},
"require-dev": {
"jakub-onderka/php-console-highlighter": "0.3.2",
"jakub-onderka/php-parallel-lint": "1.0.0",
"mediawiki/mediawiki-codesniffer": "22.0.0",
"mediawiki/minus-x": "0.3.1",
"ockcyp/covers-validator": "0.5.1 || 0.6.1",
"phpunit/phpunit": "4.8.36 || ^6.5"
},
"type": "library",
"autoload": {
"files": [
"src/Wikimedia/Functions.php"
],
"psr-4": {
"Wikimedia\\AtEase\\": "src/Wikimedia/AtEase/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"GPL-2.0-or-later"
],
"authors": [
{
"name": "Tim Starling",
"email": "tstarling@wikimedia.org"
},
{
"name": "MediaWiki developers",
"email": "wikitech-l@lists.wikimedia.org"
}
],
"description": "Safe replacement to @ for suppressing warnings.",
"homepage": "https://www.mediawiki.org/wiki/at-ease",
"support": {
"source": "https://github.com/wikimedia/at-ease/tree/master"
},
"time": "2018-10-10T15:39:06+00:00"
}
],
"aliases": [],
"minimum-stability": "dev",
"stability-flags": [],
"prefer-stable": false,
"prefer-lowest": false,
"platform": [],
"platform-dev": [],
"platform-overrides": {
"php": "7.2"
},
"plugin-api-version": "2.6.0"
}

View File

@ -0,0 +1,4 @@
{
"rootDir": "./src",
"preset": "../node_modules/@woocommerce/internal-js-tests/jest-preset.js"
}

View File

@ -0,0 +1,79 @@
{
"name": "@woocommerce/integrate-plugin",
"version": "0.1.0",
"description": "WooCommerce plugin integration scripts.",
"author": "Automattic",
"license": "GPL-3.0-or-later",
"keywords": [
"wordpress",
"woocommerce",
"plugin"
],
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/packages/js/integrate-plugin/README.md",
"repository": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce.git"
},
"bugs": {
"url": "https://github.com/woocommerce/woocommerce/issues"
},
"main": "build/index.js",
"bin": {
"woo-integrate-plugin": "./build/index.js"
},
"types": "build-types",
"react-native": "src/index",
"sideEffects": [],
"publishConfig": {
"access": "public"
},
"dependencies": {
"@wordpress/create-block": "wp-6.0",
"chalk": "^4.1.2",
"change-case": "^4.1.2",
"commander": "^9.2.0",
"execa": "^4.0.2",
"fast-glob": "^3.2.7",
"inquirer": "^7.1.0",
"npm-package-arg": "^8.1.5",
"rimraf": "^3.0.2",
"write-pkg": "^4.0.0"
},
"devDependencies": {
"@babel/core": "^7.21.3",
"@babel/runtime": "^7.17.2",
"@testing-library/jest-dom": "^5.16.2",
"@testing-library/react-hooks": "^8.0.1",
"@types/jest": "^27.4.1",
"@types/node": "^16.18.18",
"@types/testing-library__jest-dom": "^5.14.3",
"@woocommerce/eslint-plugin": "workspace:*",
"@woocommerce/internal-js-tests": "workspace:*",
"@wordpress/browserslist-config": "wp-6.0",
"copy-webpack-plugin": "^9.1.0",
"css-loader": "^3.6.0",
"eslint": "^8.32.0",
"jest": "^27.5.1",
"jest-cli": "^27.5.1",
"rimraf": "^3.0.2",
"ts-jest": "^27.1.3",
"typescript": "^5.1.6",
"webpack": "^5.70.0",
"webpack-cli": "^3.3.12"
},
"scripts": {
"turbo:build": "pnpm run build:js",
"turbo:test": "jest --config ./jest.config.json",
"prepare": "composer install",
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\" \"webpack --watch\"",
"prepack": "pnpm run clean && pnpm run build",
"lint:fix": "eslint src --fix"
}
}

View File

@ -0,0 +1,54 @@
/**
* External dependencies
*/
import { existsSync, readFileSync, promises } from 'fs';
import { join } from 'path';
/**
* Internal dependencies
*/
import { info } from './log';
const { writeFile } = promises;
function getUniqueItems( arr: string[] ) {
const uniqueObject = arr.reduce( ( unique, item ) => {
unique[ item ] = true;
return unique;
}, {} as Record< string, boolean > );
return Object.keys( uniqueObject );
}
const getPluginConfig = () => {
const cwd = join( process.cwd() );
if ( ! existsSync( join( cwd, '.woo-plugin.json' ) ) ) {
return {};
}
return JSON.parse(
readFileSync( join( cwd, '.woo-plugin.json' ), 'utf8' )
);
};
const updateConfig = async ( { modules }: { modules: string[] } ) => {
const cwd = join( process.cwd() );
const config = getPluginConfig();
const uniqueModules = modules.reduce( ( unique, module ) => {
unique[ module ] = true;
return unique;
}, {} as Record< string, boolean > );
config.modules = Object.keys( uniqueModules );
info( '' );
info( 'Updating plugin config file.' );
await writeFile(
join( cwd, '.woo-plugin.json' ),
JSON.stringify( config, null, 4 )
);
};
export { getPluginConfig, getUniqueItems, updateConfig };

View File

@ -0,0 +1,40 @@
/**
* External dependencies
*/
import { readdirSync, readFileSync } from 'fs';
import CLIError from '@wordpress/create-block/lib/cli-error';
import path from 'path';
/**
* Get the plugin data.
*
* @return {Object} - Plugin data as key value pairs.
*/
export function getPluginData() {
const files = readdirSync( process.cwd() );
for ( let i = 0; i < files.length; i++ ) {
const file = path.join( process.cwd(), files[ i ] );
if ( path.extname( file ) !== '.php' ) {
continue;
}
const content = readFileSync( file, 'utf8' );
const name = content.match( /^\s+\*\s*Plugin Name:\s*(.*)/m );
if ( name && name.length > 1 ) {
const description = content.match(
/^\s+\*\s+Description:\s*(.*)/m
);
const textdomain = content.match( /^\s+\*\s*Text Domain:\s*(.*)/m );
const version = content.match( /^\s+\*\s*Version:\s*(.*)/m );
return {
description: description && description[ 1 ].trim(),
name: name[ 1 ].trim(),
textdomain: textdomain && textdomain[ 1 ].trim(),
version: version && version[ 1 ].trim(),
namespace: textdomain && textdomain[ 1 ].trim(),
};
}
}
throw new CLIError( 'Plugin file not found.' );
}

View File

@ -0,0 +1,76 @@
#!/usr/bin/env node
/**
* External dependencies
*/
import { Command } from 'commander';
import CLIError from '@wordpress/create-block/lib/cli-error';
/**
* Internal dependencies
*/
import * as log from './log';
import { getPluginData } from './get-plugin-data';
import { getPluginConfig } from './get-plugin-config';
//add the following line
const program = new Command();
const commandName = `woo-integrate-plugin`;
program
.name( commandName )
.description(
'Integrates a plugin with WooCommerce build scripts and dependencies.\n\n' +
'The provided build scripts provide an easy way to build in a modern ' +
'JS environment and automatically assist in building block assets. '
)
.version( '0.1.0' )
.option(
'--wp-scripts',
'enable integration with `@wordpress/scripts` package'
)
.option(
'--no-wp-scripts',
'disable integration with `@wordpress/scripts` package'
)
.option(
'-t, --template <name>',
'project template type name; allowed values: "standard", "es5", the name of an external npm package, or the path to a local directory',
'standard'
)
.option( '--variant <variant>', 'the variant of the template to use' )
.option( '--wp-env', 'enable integration with `@wordpress/env` package' )
.option(
'--includes-dir <dir>',
'the path to the includes directory with backend logic'
)
.option(
'--src-dir <dir>',
'the path to the src directory with client-side logic'
)
.option( '--namespace <value>', 'internal namespace for the plugin' )
.action( async () => {
try {
const pluginData = getPluginData();
const pluginConfig = getPluginConfig();
log.info( JSON.stringify( pluginData ) );
log.info( JSON.stringify( pluginConfig ) );
} catch ( error ) {
if ( error instanceof CLIError ) {
log.error( error.message );
process.exit( 1 );
} else {
throw error;
}
}
} )
.on( '--help', () => {
log.info( '' );
log.info( 'Examples:' );
log.info( ` $ ${ commandName }` );
log.info( ` $ ${ commandName } todo-list` );
log.info(
` $ ${ commandName } todo-list --template es5 --title "TODO List"`
);
} )
.parse( process.argv );

View File

@ -0,0 +1,23 @@
/* eslint-disable no-console */
/**
* External dependencies
*/
import chalk from 'chalk';
const code = ( input: string ) => {
console.log( chalk.cyan( input ) );
};
const error = ( input: string ) => {
console.log( chalk.bold.red( input ) );
};
const info = ( input: string ) => {
console.log( input );
};
const success = ( input: string ) => {
console.log( chalk.bold.green( input ) );
};
export { code, error, info, success };
/* eslint-enable no-console */

View File

@ -0,0 +1,16 @@
{
"extends": "../tsconfig-cjs",
"include": [
"**/*.d.ts",
"src/**/*",
"src/**/*.json"
],
"compilerOptions": {
"outDir": "build",
"resolveJsonModule": true,
"typeRoots": [
"./typings",
"./node_modules/@types"
]
}
}

View File

@ -0,0 +1,13 @@
{
"extends": "../tsconfig",
"compilerOptions": {
"rootDir": "src",
"outDir": "build-module",
"declaration": true,
"declarationMap": true,
"declarationDir": "./build-types",
"resolveJsonModule": true,
"typeRoots": [ "./typings", "./node_modules/@types" ]
},
"include": [ "**/*.d.ts", "src/**/*", "src/**/*.json" ]
}

View File

@ -0,0 +1,3 @@
declare module '@wordpress/create-block/lib/cli-error' {
export default Error;
}

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -51,7 +51,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -37,7 +37,8 @@
"changelog": "composer exec -- changelogger",
"clean": "pnpm exec rimraf tsconfig.tsbuildinfo build build-*",
"build": "pnpm -w exec turbo run turbo:build --filter=$npm_package_name",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"lint": "eslint --output-file eslint_report.json --format json src",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\"",
"prepack": "pnpm run clean && pnpm run build",

View File

@ -0,0 +1,4 @@
Significance: patch
Type: dev
Comment: This is just a change to developer commands.

View File

@ -79,7 +79,8 @@
"build:js": "tsc --project tsconfig.json && tsc --project tsconfig-cjs.json",
"build:css": "webpack",
"start": "concurrently \"tsc --project tsconfig.json --watch\" \"tsc --project tsconfig-cjs.json --watch\" \"webpack --watch\"",
"test": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"test": "pnpm test:js",
"test:js": "pnpm -w exec turbo run turbo:test --filter=$npm_package_name",
"prepack": "pnpm run clean && pnpm run build",
"lint:fix": "eslint src --fix",
"test-staged": "jest --bail --config ./jest.config.json --findRelatedTests"

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add download file list product block

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Set shipping disabled when the product is virtual

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Show a summary when adding or removing variation option values

View File

@ -0,0 +1,4 @@
Significance: minor
Type: add
Add virtual and downloads related controls to variation management quick actions

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