Merge branch 'woocommerce-trunk' into add/bulk-action-shortcircuit

This commit is contained in:
Luigi Pulcini 2021-12-07 11:10:04 +01:00
commit 2b3aef0711
243 changed files with 2797 additions and 1602 deletions

View File

@ -17,7 +17,7 @@ jobs:
ref: ${{ github.event.inputs.ref || github.ref }} ref: ${{ github.event.inputs.ref || github.ref }}
- name: Build the zip file - name: Build the zip file
id: build id: build
uses: woocommerce/action-build@v2 uses: woocommerce/action-build@trunk
- name: Unzip the file (prevents double zip problem) - name: Unzip the file (prevents double zip problem)
run: unzip ${{ steps.build.outputs.zip_path }} -d zipfile run: unzip ${{ steps.build.outputs.zip_path }} -d zipfile
- name: Upload the zip file as an artifact - name: Upload the zip file as an artifact

View File

@ -11,7 +11,7 @@ jobs:
uses: actions/checkout@v2 uses: actions/checkout@v2
- name: Build - name: Build
id: build id: build
uses: woocommerce/action-build@v2 uses: woocommerce/action-build@trunk
- name: Upload release asset - name: Upload release asset
uses: actions/upload-release-asset@v1 uses: actions/upload-release-asset@v1
env: env:

View File

@ -59,8 +59,13 @@ jobs:
./vendor ./vendor
key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }} key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }}
- name: Install PNPM and install dependencies
run: |
npm install -g pnpm
pnpm install
- name: Setup and install composer - name: Setup and install composer
run: composer install run: pnpm nx composer-install woocommerce
- name: Add PHP8 Compatibility. - name: Add PHP8 Compatibility.
run: | run: |
@ -71,11 +76,11 @@ jobs:
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}' composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
rm -rf ./vendor/phpunit/ rm -rf ./vendor/phpunit/
composer dump-autoload pnpm nx composer-dump-autoload woocommerce
fi fi
- name: Init DB and WP - name: Init DB and WP
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }} run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }}
- name: Run tests - name: Run tests
run: ./vendor/bin/phpunit -c ./phpunit.xml run: pnpm nx test-unit woocommerce

View File

@ -77,9 +77,60 @@ jobs:
WC_E2E_SCREENSHOTS: 1 WC_E2E_SCREENSHOTS: 1
E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }} E2E_SLACK_TOKEN: ${{ secrets.E2E_SLACK_TOKEN }}
E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }} E2E_SLACK_CHANNEL: ${{ secrets.E2E_SLACK_CHANNEL }}
run: pnpx wc-e2e test:e2e
api-tests-run:
name: Runs API tests.
runs-on: ubuntu-18.04
needs: [build]
steps:
- name: Create dirs.
run: |
mkdir -p code/woocommerce
mkdir -p package/woocommerce
mkdir -p tmp/woocommerce
mkdir -p node_modules
- name: Checkout code.
uses: actions/checkout@v2
with:
path: package/woocommerce
- name: Install PNPM and install dependencies
working-directory: package/woocommerce
run: |
npm install -g pnpm
pnpm install
- name: Load docker images and start containers.
working-directory: package/woocommerce/plugins/woocommerce
run: pnpx wc-e2e docker:up
- name: Move current directory to code. We will install zip file in this dir later.
run: mv ./package/woocommerce/plugins/woocommerce/* ./code/woocommerce
- name: Download WooCommerce ZIP.
uses: actions/download-artifact@v2
with:
name: woocommerce
path: tmp
- name: Extract and replace WooCommerce zip.
working-directory: tmp
run: |
unzip woocommerce.zip -d woocommerce
mv woocommerce/woocommerce/* ../package/woocommerce/plugins/woocommerce/
- name: Install dependencies again
working-directory: package/woocommerce
run: |
npm install -g pnpm
pnpm install
- name: Run tests command.
working-directory: package/woocommerce/plugins/woocommerce
env:
BASE_URL: ${{ secrets.PR_E2E_TEST_URL }} BASE_URL: ${{ secrets.PR_E2E_TEST_URL }}
USER_KEY: ${{ secrets.PR_E2E_TEST_ADMIN_USER }} USER_KEY: ${{ secrets.PR_E2E_TEST_ADMIN_USER }}
USER_SECRET: ${{ secrets.PR_E2E_TEST_ADMIN_PASSWORD }} USER_SECRET: ${{ secrets.PR_E2E_TEST_ADMIN_PASSWORD }}
run: | run: pnpx wc-api-tests test api
pnpx wc-e2e test:e2e
pnpx wc-api-tests test api

View File

@ -45,15 +45,20 @@ jobs:
./vendor ./vendor
key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }} key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }}
- name: Install PNPM and install dependencies
run: |
npm install -g pnpm
pnpm install
- name: Setup and install composer - name: Setup and install composer
run: composer install run: pnpm nx composer-install woocommerce
- name: Init DB and WP - name: Init DB and WP
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 latest run: pnpm nx install-unit-test-db woocommerce
- name: Run unit tests with code coverage. Allow to fail. - name: Run unit tests with code coverage. Allow to fail.
run: | run: |
RUN_CODE_COVERAGE=1 bash ./tests/bin/phpunit.sh pnpm nx test-code-coverage woocommerce
exit 0 exit 0
- name: Send code coverage to Codecov. - name: Send code coverage to Codecov.

View File

@ -35,8 +35,13 @@ jobs:
./vendor ./vendor
key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }} key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }}
- name: Install PNPM and install dependencies
run: |
npm install -g pnpm
pnpm install
- name: Setup and install composer - name: Setup and install composer
run: composer install run: pnpm nx composer-install woocommerce
- name: Run code sniff - name: Run code sniff
continue-on-error: true continue-on-error: true

View File

@ -28,8 +28,8 @@ jobs:
run: | run: |
npm install -g pnpm npm install -g pnpm
pnpm install pnpm install
composer install --no-dev pnpm nx composer-install-no-dev woocommerce
pnpm run build:assets pnpm nx build-assets woocommerce
pnpm install jest pnpm install jest
- name: Run smoke test. - name: Run smoke test.

View File

@ -56,8 +56,11 @@ jobs:
./vendor ./vendor
key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }} key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }}
- name: Setup and install composer - name: Install PNPM and install dependencies
run: composer install run: |
npm install -g pnpm
pnpm install
pnpm nx composer-install woocommerce
- name: Add PHP8 Compatibility. - name: Add PHP8 Compatibility.
run: | run: |
@ -75,4 +78,4 @@ jobs:
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }} run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }}
- name: Run tests - name: Run tests
run: ./vendor/bin/phpunit -c ./phpunit.xml run: pnpm nx test-unit woocommerce

View File

@ -26,8 +26,8 @@ jobs:
run: | run: |
npm install -g pnpm npm install -g pnpm
pnpm install pnpm install
composer install --no-dev pnpm nx composer-install-no-dev woocommerce
pnpm run build:assets pnpm nx build-assets woocommerce
pnpm install jest pnpm install jest
- name: Run smoke test. - name: Run smoke test.

View File

@ -26,8 +26,8 @@ jobs:
run: | run: |
npm install -g pnpm npm install -g pnpm
pnpm install pnpm install
composer install --no-dev pnpm nx composer-install-no-dev woocommerce
pnpm run build:assets pnpm nx build-assets woocommerce
pnpm install jest pnpm install jest
- name: Run smoke test. - name: Run smoke test.
@ -73,8 +73,9 @@ jobs:
with: with:
path: package/woocommerce path: package/woocommerce
- name: Run npm install. - name: Install PNPM and install dependencies
working-directory: package/woocommerce/plugins/woocommerce working-directory: package/woocommerce
run: |
npm install -g pnpm npm install -g pnpm
pnpm install pnpm install
@ -82,7 +83,7 @@ jobs:
working-directory: package/woocommerce/plugins/woocommerce working-directory: package/woocommerce/plugins/woocommerce
env: env:
LATEST_WP_VERSION_MINUS: ${{ matrix.wp }} LATEST_WP_VERSION_MINUS: ${{ matrix.wp }}
run: pnpx wc-e2e docker:up run: pnpm nx docker-up woocommerce
- name: Move current directory to code. We will install zip file in this dir later. - name: Move current directory to code. We will install zip file in this dir later.
run: mv ./package/woocommerce/plugins/woocommerce/* ./code/woocommerce run: mv ./package/woocommerce/plugins/woocommerce/* ./code/woocommerce
@ -103,4 +104,4 @@ jobs:
WC_E2E_SCREENSHOTS: 1 WC_E2E_SCREENSHOTS: 1
E2E_SLACK_TOKEN: ${{ secrets.SMOKE_TEST_SLACK_TOKEN }} E2E_SLACK_TOKEN: ${{ secrets.SMOKE_TEST_SLACK_TOKEN }}
E2E_SLACK_CHANNEL: ${{ secrets.RELEASE_TEST_SLACK_CHANNEL }} E2E_SLACK_CHANNEL: ${{ secrets.RELEASE_TEST_SLACK_CHANNEL }}
run: pnpx wc-e2e test:e2e run: pnpm nx test-e2e woocommerce

View File

@ -34,9 +34,8 @@ The port # might be different depending on your `.wp-env.override.json` configur
Once you have WP-ENV container up, we need to run a few commands to start developing. Once you have WP-ENV container up, we need to run a few commands to start developing.
1. Run `pnpm install` to install npm modules. 1. Run `pnpm install` to install npm modules.
2. Navigate to Core WooCommerce `cd plugins/woocommerce`. 2. Run `pnpm nx build woocommerce` to build core.
3. Run `pnpm run build:core` 3. Run `pnpm nx composer-install woocommerce` to install PHP dependencies.
4. Run `composer install` to install PHP dependencies.
If you don't have Composer available locally, run the following command. It runs the command in WP-ENV container. If you don't have Composer available locally, run the following command. It runs the command in WP-ENV container.

View File

@ -6,3 +6,5 @@
- Coupons API Tests - Coupons API Tests
- Refunds API Tests - Refunds API Tests
- Products API Tests - Products API Tests
- CRUD tests for the Orders API
- Order Search API Tests

View File

@ -12,15 +12,15 @@
"formatter": { "formatter": {
"filename": "../../../tools/changelogger/PackageFormatter.php" "filename": "../../../tools/changelogger/PackageFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }
} }

View File

@ -14,5 +14,5 @@ const refund = {
}; };
module.exports = { module.exports = {
refund: refund, refund,
}; };

View File

@ -0,0 +1,86 @@
const { ordersApi } = require( '../../endpoints' );
const { getOrderExample, shared } = require( '../../data' );
/**
* Order to be searched
*/
const order = {
...getOrderExample(),
shipping: {
...shared.customerShipping,
company: 'Murphy LLC',
phone: '6146524353',
},
shipping_lines: [],
fee_lines: [],
coupon_lines: [],
};
/**
* Search parameters to be used.
* The following scenarios are not covered in this test suite because they're already covered in the `List all orders > search` test in `orders.test.js`
* ```
* can search by billing address 1
* can search by shipping address 1
* can search by billing last name
* can search by billing email
* can search by item name
* ```
*/
const searchParams = [
[ 'orderId', 'orderId' ],
[ 'billing first name', order.billing.first_name ],
[ 'billing company name', order.billing.company ],
[ 'billing address 2', order.billing.address_2 ],
[ 'billing city name', order.billing.city ],
[ 'billing post code', order.billing.postcode ],
[ 'billing phone', order.billing.phone ],
[ 'billing state', order.billing.state ],
[ 'shipping first name', order.shipping.first_name ],
[ 'shipping last name', order.shipping.last_name ],
[ 'shipping address 2', order.shipping.address_2 ],
[ 'shipping city', order.shipping.city ],
[ 'shipping post code', order.shipping.postcode ],
[ 'shipping state', order.shipping.state ],
];
/**
* Tests for the WooCommerce Order Search API.
*
* @group api
* @group orders
*
*/
describe( 'Order Search API tests', () => {
beforeAll( async () => {
// Create an order and save its ID
const { body } = await ordersApi.create.order( order );
order.id = body.id;
} );
afterAll( async () => {
// Cleanup: Delete the order
await ordersApi.delete.order( order.id, true );
} );
it.each( searchParams )( 'can search by %s', async ( title, param ) => {
const searchValue = param === 'orderId' ? order.id : param;
const { status, body } = await ordersApi.listAll.orders( {
search: searchValue,
} );
expect( status ).toEqual( ordersApi.listAll.responseCode );
expect( body ).toHaveLength( 1 );
expect( body[ 0 ].id ).toEqual( order.id );
} );
it( 'can return an empty result set when no matches were found', async () => {
const { status, body } = await ordersApi.listAll.orders( {
search: 'Chauncey Smith Kunde',
} );
expect( status ).toEqual( ordersApi.listAll.responseCode );
expect( body ).toEqual( [] );
} );
} );

View File

@ -0,0 +1,215 @@
const { ordersApi, productsApi } = require( '../../endpoints' );
const { order } = require( '../../data' );
/**
* Billing properties to update.
*/
const updatedCustomerBilling = {
first_name: 'Jane',
last_name: 'Doe',
company: 'Automattic',
country: 'US',
address_1: '123 Market Street',
address_2: 'Suite 500',
city: 'Austin',
state: 'TX',
postcode: '73301',
phone: '123456789',
email: 'jane.doe@example.com',
};
/**
* Shipping properties to update.
*/
const updatedCustomerShipping = {
first_name: 'Mike',
last_name: 'Anderson',
company: 'Automattic',
country: 'US',
address_1: '123 Ocean Ave',
address_2: '',
city: 'New York',
state: 'NY',
postcode: '10013',
phone: '123456789',
};
/**
* Data tables to be used for testing the 'Create an order' API.
*/
const statusesDataTable = [
'pending',
'processing',
'on-hold',
'completed',
'cancelled',
'refunded',
'failed',
];
/**
* A simple product that will be added to an order.
*/
const simpleProduct = {
name: 'Incredible Plastic Table',
regular_price: '48',
};
/**
* Tests for the WooCommerce Orders API.
*
* @group api
* @group orders
*
*/
describe( 'Orders API tests: CRUD', () => {
let orderId;
describe( 'Create an order', () => {
it( 'can create a pending order by default', async () => {
// Create an order that has a null status
const requestPayload = {
...order,
status: null,
};
const { body, status } = await ordersApi.create.order(
requestPayload
);
// Save the order ID. It will be used by the retrieve, update, and delete tests.
orderId = body.id;
// Verify that the order status is 'pending'
expect( status ).toEqual( ordersApi.create.responseCode );
expect( typeof body.id ).toEqual( 'number' );
expect( body.status ).toEqual( 'pending' );
} );
it.each( statusesDataTable )(
"can create an order with status '%s'",
async ( expectedStatus ) => {
const requestPayload = {
...order,
status: expectedStatus,
};
const { status, body } = await ordersApi.create.order(
requestPayload
);
expect( status ).toEqual( ordersApi.create.responseCode );
expect( typeof body.id ).toEqual( 'number' );
expect( body.status ).toEqual( expectedStatus );
// Cleanup: Delete this order
await ordersApi.delete.order( body.id, true );
}
);
} );
describe( 'Retrieve an order', () => {
it( 'can retrieve an order', async () => {
const response = await ordersApi.retrieve.order( orderId );
expect( response.status ).toEqual(
ordersApi.retrieve.responseCode
);
expect( response.body.id ).toEqual( orderId );
} );
} );
describe( 'Update an order', () => {
beforeAll( async () => {
// Create the product and save its id
const { body } = await productsApi.create.product( simpleProduct );
simpleProduct.id = body.id;
} );
afterAll( async () => {
// Delete the created product
await productsApi.delete.product( simpleProduct.id, true );
} );
it.each( statusesDataTable )(
"can update status of an order to '%s'",
async ( expectedOrderStatus ) => {
const requestPayload = {
status: expectedOrderStatus,
};
const { status, body } = await ordersApi.update.order(
orderId,
requestPayload
);
expect( status ).toEqual( ordersApi.update.responseCode );
expect( body.id ).toEqual( orderId );
expect( body.status ).toEqual( expectedOrderStatus );
}
);
it( 'can add shipping and billing contacts to an order', async () => {
// Update the billing and shipping fields on the order
order.billing = updatedCustomerBilling;
order.shipping = updatedCustomerShipping;
const response = await ordersApi.update.order( orderId, order );
expect( response.status ).toEqual( ordersApi.update.responseCode );
expect( response.body.billing ).toEqual( updatedCustomerBilling );
expect( response.body.shipping ).toEqual( updatedCustomerShipping );
} );
it( 'can add a product to an order', async () => {
// Add the product to the order
const requestPayload = {
line_items: [ { product_id: simpleProduct.id } ],
};
const { body, status } = await ordersApi.update.order(
orderId,
requestPayload
);
// Verify that the added product has the correct values
expect( status ).toEqual( ordersApi.update.responseCode );
expect( body.line_items ).toHaveLength( 1 );
expect( body.line_items[ 0 ].product_id ).toEqual(
simpleProduct.id
);
expect( body.line_items[ 0 ].name ).toEqual( simpleProduct.name );
} );
it( 'can pay for an order', async () => {
// Setup: Set order status to 'pending'
await ordersApi.update.order( orderId, {
status: 'pending',
} );
// Pay for the order by setting `set_paid` to true
const updateRequestPayload = {
set_paid: true,
};
const { status, body } = await ordersApi.update.order(
orderId,
updateRequestPayload
);
expect( status ).toEqual( ordersApi.update.responseCode );
expect( body.id ).toEqual( orderId );
// Validate that the status of the order was automatically set to 'processing'
expect( body.status ).toEqual( 'processing' );
// Validate that the date_paid and date_paid_gmt properties are no longer null
expect( body.date_paid ).not.toBeNull();
expect( body.date_paid_gmt ).not.toBeNull();
} );
} );
describe( 'Delete an order', () => {
it( 'can permanently delete an order', async () => {
// Delete the order.
const response = await ordersApi.delete.order( orderId, true );
expect( response.status ).toEqual( ordersApi.delete.responseCode );
// Verify that the order can no longer be retrieved.
const getOrderResponse = await ordersApi.retrieve.order( orderId );
expect( getOrderResponse.status ).toEqual( 404 );
} );
} );
} );

View File

@ -12,15 +12,15 @@
"formatter": { "formatter": {
"filename": "../../../tools/changelogger/PackageFormatter.php" "filename": "../../../tools/changelogger/PackageFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }
} }

1
packages/js/e2e-core-tests/.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/test-data/sample_products.csv

View File

@ -1,8 +1,14 @@
# Unreleased # Unreleased
## Added
- A `specs/data` folder to store page element data.
- Tests to verify that different top-level menu and their associated sub-menus load successfully.
## Changed ## Changed
- New coupon test deletes the coupon instead of trashing it. - New coupon test deletes the coupon instead of trashing it.
- A copy of sample_data.csv is included in the package.
# 0.1.6 # 0.1.6

View File

@ -72,6 +72,7 @@ The functions to access the core tests are:
- `runAnalyticsPageLoadsTest` - Merchant can load and see all pages in Analytics - `runAnalyticsPageLoadsTest` - Merchant can load and see all pages in Analytics
- `runImportProductsTest` - Merchant can import products via CSV file - `runImportProductsTest` - Merchant can import products via CSV file
- `runInitiateWccomConnectionTest` - Merchant can initiate connection to WooCommerce.com - `runInitiateWccomConnectionTest` - Merchant can initiate connection to WooCommerce.com
- `runAdminPageLoadTests` - Merchant can load pages from the WP Admin sidebar
### Shopper ### Shopper

View File

@ -0,0 +1,8 @@
#!/usr/bin/env bash
#
# Copy the WooCommerce sample data file to the package
#
PACKAGEPATH=$(dirname $(dirname "$0"))
cp -v $PACKAGEPATH/../../../plugins/woocommerce/sample-data/sample_products.csv $PACKAGEPATH/test-data

View File

@ -12,15 +12,15 @@
"formatter": { "formatter": {
"filename": "../../../tools/changelogger/PackageFormatter.php" "filename": "../../../tools/changelogger/PackageFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }
} }

View File

@ -11,6 +11,7 @@
"main": "index.js", "main": "index.js",
"dependencies": { "dependencies": {
"@jest/globals": "^26.4.2", "@jest/globals": "^26.4.2",
"@wordpress/deprecated": "^3.2.3",
"config": "3.3.3", "config": "3.3.3",
"faker": "^5.1.0" "faker": "^5.1.0"
}, },
@ -20,5 +21,9 @@
}, },
"publishConfig": { "publishConfig": {
"access": "public" "access": "public"
},
"scripts": {
"build": "./bin/build.sh",
"prepare": "pnpm run build"
} }
} }

View File

@ -11,6 +11,7 @@ const {
describe, describe,
beforeAll, beforeAll,
} = require( '@jest/globals' ); } = require( '@jest/globals' );
import deprecated from '@wordpress/deprecated';
const runActivationTest = () => { const runActivationTest = () => {
describe('Store owner can login and make sure WooCommerce is activated', () => { describe('Store owner can login and make sure WooCommerce is activated', () => {
@ -19,6 +20,10 @@ const runActivationTest = () => {
}); });
it('can make sure WooCommerce is activated. If not, activate it', async () => { it('can make sure WooCommerce is activated. If not, activate it', async () => {
deprecated( 'runActivationTest', {
alternative: '@woocommerce/admin-e2e-tests `testAdminBasicSetup()`',
});
const slug = 'woocommerce'; const slug = 'woocommerce';
await merchant.openPlugins(); await merchant.openPlugins();
const disableLink = await page.$(`tr[data-slug="${slug}"] .deactivate a`); const disableLink = await page.$(`tr[data-slug="${slug}"] .deactivate a`);

View File

@ -13,6 +13,7 @@ const {
* External dependencies * External dependencies
*/ */
const config = require( 'config' ); const config = require( 'config' );
import deprecated from '@wordpress/deprecated';
const { const {
it, it,
describe, describe,
@ -47,6 +48,9 @@ const runOnboardingFlowTest = () => {
} }
it('can start and complete onboarding when visiting the site for the first time.', async () => { it('can start and complete onboarding when visiting the site for the first time.', async () => {
deprecated( 'runOnboardingFlowTest', {
alternative: '@woocommerce/admin-e2e-tests `testAdminOnboardingWizard()`',
});
await completeOnboardingWizard(); await completeOnboardingWizard();
}); });
}); });
@ -59,6 +63,9 @@ const runTaskListTest = () => {
}); });
it('can setup shipping', async () => { it('can setup shipping', async () => {
deprecated( 'runTaskListTest', {
alternative: '@woocommerce/admin-e2e-tests `testAdminHomescreenTasklist()`',
});
await page.evaluate(() => { await page.evaluate(() => {
document.querySelector('.woocommerce-list__item-title').scrollIntoView(); document.querySelector('.woocommerce-list__item-title').scrollIntoView();
}); });

View File

@ -6,6 +6,7 @@ const {
it, it,
describe, describe,
} = require( '@jest/globals' ); } = require( '@jest/globals' );
import deprecated from '@wordpress/deprecated';
/** /**
* Internal dependencies * Internal dependencies
@ -31,6 +32,9 @@ const runInitialStoreSettingsTest = () => {
}); });
it('can enable tax rates and calculations', async () => { it('can enable tax rates and calculations', async () => {
deprecated( 'runInitialStoreSettingsTest', {
alternative: '@woocommerce/admin-e2e-tests `testAdminBasicSetup()`',
});
// Go to general settings page // Go to general settings page
await merchant.openSettings('general'); await merchant.openSettings('general');

View File

@ -0,0 +1,85 @@
/**
* WP top-level menu items and their associated sub-menus
*/
export const MENUS = [
[
'WooCommerce',
'#adminmenu > li:nth-child(8) > a',
[
[
'Home',
'#toplevel_page_woocommerce > ul > li:nth-child(2) > a',
'Home',
],
[
'Orders',
'#toplevel_page_woocommerce > ul > li:nth-child(3) > a',
'Orders',
],
[
'Reports',
'#toplevel_page_woocommerce > ul > li:nth-child(6) > a',
'Orders',
],
[
'Settings',
'#toplevel_page_woocommerce > ul > li:nth-child(7) > a',
'General',
],
[
'Status',
'#toplevel_page_woocommerce > ul > li:nth-child(8) > a',
'System status',
],
// [ 'Extensions', '#toplevel_page_woocommerce > ul > li:nth-child(9)', 'Extensions' ],
],
],
[
'Products',
'#adminmenu > li:nth-child(9) > a',
[
[
'All Products',
'#menu-posts-product > ul > li:nth-child(2) > a',
'Products',
],
[
'Add New',
'#menu-posts-product > ul > li:nth-child(3) > a',
'Add New',
],
[
'Categories',
'#menu-posts-product > ul > li:nth-child(4) > a',
'Product categories',
],
[
'Product tags',
'#menu-posts-product > ul > li:nth-child(5) > a',
'Product tags',
],
[
'Attributes',
'#menu-posts-product > ul > li:nth-child(6) > a',
'Attributes',
],
],
],
[
'Marketing',
'#adminmenu > li:nth-child(11) > a',
[
[
'Overview',
'#toplevel_page_woocommerce-marketing > ul > li:nth-child(2) > a',
'Overview',
],
[
'Coupons',
'#toplevel_page_woocommerce-marketing > ul > li:nth-child(3) > a',
'Coupons',
],
],
],
];

View File

@ -37,6 +37,7 @@ const runProductSettingsTest = require( './merchant/wp-admin-settings-product.te
const runTaxSettingsTest = require( './merchant/wp-admin-settings-tax.test' ); const runTaxSettingsTest = require( './merchant/wp-admin-settings-tax.test' );
const runOrderStatusFiltersTest = require( './merchant/wp-admin-order-status-filters.test' ); const runOrderStatusFiltersTest = require( './merchant/wp-admin-order-status-filters.test' );
const runOrderRefundTest = require( './merchant/wp-admin-order-refund.test' ); const runOrderRefundTest = require( './merchant/wp-admin-order-refund.test' );
const runOrderRefundRestockTest = require( './merchant/wp-admin-order-refund-restock.test' );
const runOrderApplyCouponTest = require( './merchant/wp-admin-order-apply-coupon.test' ); const runOrderApplyCouponTest = require( './merchant/wp-admin-order-apply-coupon.test' );
const runProductEditDetailsTest = require( './merchant/wp-admin-product-edit-details.test' ); const runProductEditDetailsTest = require( './merchant/wp-admin-product-edit-details.test' );
const runProductSearchTest = require( './merchant/wp-admin-product-search.test' ); const runProductSearchTest = require( './merchant/wp-admin-product-search.test' );
@ -46,6 +47,7 @@ const runOrderSearchingTest = require( './merchant/wp-admin-order-searching.test
const runAnalyticsPageLoadsTest = require( './merchant/wp-admin-analytics-page-loads.test' ); const runAnalyticsPageLoadsTest = require( './merchant/wp-admin-analytics-page-loads.test' );
const runImportProductsTest = require( './merchant/wp-admin-product-import-csv.test' ); const runImportProductsTest = require( './merchant/wp-admin-product-import-csv.test' );
const runInitiateWccomConnectionTest = require( './merchant/wp-admin-extensions-connect-wccom.test' ); const runInitiateWccomConnectionTest = require( './merchant/wp-admin-extensions-connect-wccom.test' );
const runAdminPageLoadTests = require( './merchant/wp-admin-page-loads.test.js' );
// REST API tests // REST API tests
const runExternalProductAPITest = require( './api/external-product.test' ); const runExternalProductAPITest = require( './api/external-product.test' );
@ -95,12 +97,14 @@ const runMerchantTests = () => {
runTaxSettingsTest(); runTaxSettingsTest();
runOrderStatusFiltersTest(); runOrderStatusFiltersTest();
runOrderRefundTest(); runOrderRefundTest();
runOrderRefundRestockTest();
runOrderApplyCouponTest(); runOrderApplyCouponTest();
runProductEditDetailsTest(); runProductEditDetailsTest();
runProductSearchTest(); runProductSearchTest();
runMerchantOrdersCustomerPaymentPage(); runMerchantOrdersCustomerPaymentPage();
runAnalyticsPageLoadsTest(); runAnalyticsPageLoadsTest();
runInitiateWccomConnectionTest(); runInitiateWccomConnectionTest();
runAdminPageLoadTests();
} }
const runApiTests = () => { const runApiTests = () => {
@ -142,6 +146,7 @@ module.exports = {
runOrderApiTest, runOrderApiTest,
runOrderStatusFiltersTest, runOrderStatusFiltersTest,
runOrderRefundTest, runOrderRefundTest,
runOrderRefundRestockTest,
runOrderApplyCouponTest, runOrderApplyCouponTest,
runProductEditDetailsTest, runProductEditDetailsTest,
runProductSearchTest, runProductSearchTest,
@ -163,4 +168,5 @@ module.exports = {
runOrderEmailReceivingTest, runOrderEmailReceivingTest,
runInitiateWccomConnectionTest, runInitiateWccomConnectionTest,
runTelemetryAPITest, runTelemetryAPITest,
runAdminPageLoadTests,
}; };

View File

@ -15,6 +15,7 @@ const {
describe, describe,
beforeAll, beforeAll,
} = require( '@jest/globals' ); } = require( '@jest/globals' );
import deprecated from '@wordpress/deprecated';
/** /**
* Quick check for page title and no data message. * Quick check for page title and no data message.
@ -57,6 +58,10 @@ const runAnalyticsPageLoadsTest = () => {
await merchant.login(); await merchant.login();
}); });
deprecated( 'runAnalyticsPageLoadsTest', {
alternative: '@woocommerce/admin-e2e-tests `testAdminAnalyticsPages()`',
});
it.each(pages)( it.each(pages)(
'can see %s page properly', 'can see %s page properly',
async (pageTitle, element, elementText) => { async (pageTitle, element, elementText) => {

View File

@ -0,0 +1,117 @@
/**
* Internal dependencies
*/
const {
merchant,
createOrder,
createSimpleProduct,
verifyCheckboxIsSet,
uiUnblocked,
evalAndClick,
clickUpdateOrder,
} = require( '@woocommerce/e2e-utils' );
const { waitForSelector } = require( '@woocommerce/e2e-environment' );
/**
* Evaluate and click a button selector then wait for a result selector.
* This is a work around for what appears to be intermittent delays in handling confirm dialogs.
*
* @param {string} buttonSelector
* @param {string} resultSelector
* @returns {Promise<void>}
*/
const clickAndWaitForSelector = async ( buttonSelector, resultSelector ) => {
await evalAndClick( buttonSelector );
await waitForSelector( page, resultSelector, {
timeout: 5000,
} );
};
const getRefundQuantityInputSelector = ( productName ) =>
`td.name[data-sort-value="${ productName }"] ~ td.quantity input.refund_order_item_qty`;
const runOrderRefundRestockTest = () => {
describe( 'WooCommerce Orders > Refund and restock an order item', () => {
// See: https://github.com/woocommerce/woocommerce/issues/30618
it( 'Can update order after refunding item without automatic stock adjustment', async () => {
const noInventoryProductId = await createSimpleProduct();
const productToRestockId = await createSimpleProduct(
'Product with Stock',
'10',
{
trackInventory: true,
remainingStock: 10,
}
);
const orderId = await createOrder( {
status: 'completed',
lineItems: [
{
product_id: noInventoryProductId,
},
{
product_id: productToRestockId,
quantity: 2,
},
],
} );
await merchant.login();
await merchant.goToOrder( orderId );
// Get the currency symbol for the store's selected currency
await page.waitForSelector( '.woocommerce-Price-currencySymbol' );
// Verify stock reduction system note was added
await expect( page ).toMatchElement( '.system-note', {
text: `Stock levels reduced: Product with Stock (#${ productToRestockId }) 10→8`,
} );
// Click the Refund button
await expect( page ).toClick( 'button.refund-items' );
// Verify the refund section shows
await page.waitForSelector( 'div.wc-order-refund-items', {
visible: true,
} );
await verifyCheckboxIsSet( '#restock_refunded_items' );
// Initiate a refund
await expect( page ).toFill(
getRefundQuantityInputSelector( 'Product with Stock' ),
'2'
);
await expect( page ).toFill( '#refund_reason', 'No longer wanted' );
await clickAndWaitForSelector(
'.do-manual-refund',
'.quantity .refunded'
);
await uiUnblocked();
// Verify restock system note was added
await expect( page ).toMatchElement( '.system-note', {
text: `Item #${ productToRestockId } stock increased from 8 to 10.`,
} );
// Update the order.
await clickUpdateOrder( 'Order updated.' );
// Verify that inventory wasn't modified.
// For some reason using expect().not.toMatchElement() did not work for this case.
expect(
await page.$$eval( '.note', ( notes ) =>
notes.every(
( note ) =>
! note.textContent.match(
/Adjusted stock: Product with Stock \(10→8\)/
)
)
)
).toEqual( true );
} );
} );
};
module.exports = runOrderRefundRestockTest;

View File

@ -0,0 +1,49 @@
/**
* Internal dependencies
*/
const { merchant } = require( '@woocommerce/e2e-utils' );
const { MENUS } = require( '../data/elements' );
/**
* External dependencies
*/
const { it, describe, beforeAll } = require( '@jest/globals' );
const runPageLoadTest = () => {
describe.each( MENUS )(
' %s > Opening Top Level Pages',
( menuTitle, menuElement, subMenus ) => {
beforeAll( async () => {
await merchant.login();
} );
afterAll( async () => {
await merchant.logout();
} );
it.each( subMenus )(
'can see %s page properly',
async ( subMenuTitle, subMenuElement, subMenuText ) => {
// Go to Top Level Menu
await Promise.all( [
page.click( menuElement ),
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
] );
// Click sub-menu item and wait for the page to finish loading
await Promise.all( [
page.click( subMenuElement ),
page.waitForNavigation( { waitUntil: 'networkidle0' } ),
] );
await expect( page ).toMatchElement( 'h1', {
text: subMenuText,
} );
}
);
}
);
};
// eslint-disable-next-line jest/no-export
module.exports = runPageLoadTest;

View File

@ -17,8 +17,8 @@ const { it, describe, beforeAll, afterAll } = require( '@jest/globals' );
const path = require( 'path' ); const path = require( 'path' );
const coreTestsPath = getCoreTestsRoot(); const coreTestsPath = getCoreTestsRoot();
const filePath = path.resolve( const filePath = path.resolve(
coreTestsPath.appRoot, coreTestsPath.packageRoot,
'plugins/woocommerce/sample-data/sample_products.csv' 'test-data/sample_products.csv'
); );
const filePathOverride = path.resolve( const filePathOverride = path.resolve(
coreTestsPath.packageRoot, coreTestsPath.packageRoot,

View File

@ -8,12 +8,13 @@ const {
uiUnblocked, uiUnblocked,
evalAndClick, evalAndClick,
setCheckbox, setCheckbox,
setBrowserViewport,
verifyAndPublish, verifyAndPublish,
waitForSelector,
waitForSelectorWithoutThrow waitForSelectorWithoutThrow
} = require( '@woocommerce/e2e-utils' ); } = require( '@woocommerce/e2e-utils' );
const { const {
waitAndClick, waitAndClick,
waitForSelector,
} = require( '@woocommerce/e2e-environment' ); } = require( '@woocommerce/e2e-environment' );
/** /**
@ -45,6 +46,13 @@ const runAddSimpleProductTest = () => {
}); });
it('can create simple virtual product and add it to the cart', async () => { it('can create simple virtual product and add it to the cart', async () => {
// @todo: remove this once https://github.com/woocommerce/woocommerce/issues/31337 has been addressed
await setBrowserViewport( {
width: 970,
height: 700,
} );
await openNewProductAndVerify(); await openNewProductAndVerify();
// Set product data and publish the product // Set product data and publish the product
@ -72,6 +80,12 @@ const runAddSimpleProductTest = () => {
}); });
it('can create simple non-virtual product and add it to the cart', async () => { it('can create simple non-virtual product and add it to the cart', async () => {
// @todo: remove this once https://github.com/woocommerce/woocommerce/issues/31337 has been addressed
await setBrowserViewport( {
width: 960,
height: 700,
} );
await merchant.login(); await merchant.login();
await openNewProductAndVerify(); await openNewProductAndVerify();

View File

@ -39,6 +39,10 @@ const runAddNewShippingZoneTest = () => {
await merchant.login(); await merchant.login();
}); });
afterAll( async () => {
await shopper.logout();
} );
it('add shipping zone for San Francisco with free Local pickup', async () => { it('add shipping zone for San Francisco with free Local pickup', async () => {
// Add a new shipping zone for San Francisco 94107, CA, US with Local pickup // Add a new shipping zone for San Francisco 94107, CA, US with Local pickup
await addShippingZoneAndMethod(shippingZoneNameSF, california, sanFranciscoZIP, 'local_pickup'); await addShippingZoneAndMethod(shippingZoneNameSF, california, sanFranciscoZIP, 'local_pickup');

View File

@ -9,6 +9,7 @@ const {
applyCoupon, applyCoupon,
removeCoupon, removeCoupon,
} = require( '@woocommerce/e2e-utils' ); } = require( '@woocommerce/e2e-utils' );
const { getCouponId, getCouponsTable } = require( '../utils/coupons' );
/** /**
* External dependencies * External dependencies
@ -19,36 +20,12 @@ const {
beforeAll, beforeAll,
} = require( '@jest/globals' ); } = require( '@jest/globals' );
const couponsTable = [
['fixed cart', { text: '$5.00' }, { text: '$4.99' }],
['percentage', { text: '$4.99' }, { text: '$5.00' }],
['fixed product', { text: '$5.00' }, { text: '$4.99' }]
];
let couponFixedCart;
let couponPercentage;
let couponFixedProduct;
const getCoupon = (couponType) => {
switch (couponType) {
case 'fixed cart':
return couponFixedCart;
case 'percentage':
return couponPercentage;
case 'fixed product':
return couponFixedProduct;
}
};
const runCartApplyCouponsTest = () => { const runCartApplyCouponsTest = () => {
describe('Cart applying coupons', () => { describe('Cart applying coupons', () => {
let productId; let productId;
beforeAll(async () => { beforeAll(async () => {
productId = await createSimpleProduct(); productId = await createSimpleProduct();
couponFixedCart = await createCoupon();
couponPercentage = await createCoupon('50', 'Percentage discount');
couponFixedProduct = await createCoupon('5', 'Fixed product discount');
await shopper.emptyCart(); await shopper.emptyCart();
await shopper.goToShop(); await shopper.goToShop();
await shopper.addToCartFromShopPage( productId ); await shopper.addToCartFromShopPage( productId );
@ -56,8 +33,8 @@ const runCartApplyCouponsTest = () => {
await shopper.goToCart(); await shopper.goToCart();
}); });
it.each(couponsTable)('allows cart to apply %s coupon', async (couponType, cartDiscount, orderTotal) => { it.each( getCouponsTable() )( 'allows cart to apply %s coupon', async ( couponType, cartDiscount, orderTotal ) => {
const coupon = getCoupon(couponType); const coupon = await getCouponId( couponType );
await applyCoupon(coupon); await applyCoupon(coupon);
await expect(page).toMatchElement('.woocommerce-message', { text: 'Coupon code applied successfully.' }); await expect(page).toMatchElement('.woocommerce-message', { text: 'Coupon code applied successfully.' });
@ -69,9 +46,10 @@ const runCartApplyCouponsTest = () => {
}); });
it('prevents cart applying same coupon twice', async () => { it('prevents cart applying same coupon twice', async () => {
await applyCoupon(couponFixedCart); const couponId = await getCouponId( 'fixed cart' );
await applyCoupon( couponId );
await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'});
await applyCoupon(couponFixedCart); await applyCoupon( couponId );
// Verify only one discount applied // Verify only one discount applied
// This is a work around for Puppeteer inconsistently finding 'Coupon code already applied' // This is a work around for Puppeteer inconsistently finding 'Coupon code already applied'
await expect(page).toMatchElement('.cart-discount .amount', {text: '$5.00'}); await expect(page).toMatchElement('.cart-discount .amount', {text: '$5.00'});
@ -79,7 +57,7 @@ const runCartApplyCouponsTest = () => {
}); });
it('allows cart to apply multiple coupons', async () => { it('allows cart to apply multiple coupons', async () => {
await applyCoupon(couponFixedProduct); await applyCoupon( await getCouponId( 'fixed product' ) );
await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'});
// Verify discount applied and order total // Verify discount applied and order total
@ -88,8 +66,8 @@ const runCartApplyCouponsTest = () => {
}); });
it('restores cart total when coupons are removed', async () => { it('restores cart total when coupons are removed', async () => {
await removeCoupon(couponFixedCart); await removeCoupon( await getCouponId( 'fixed cart' ) );
await removeCoupon(couponFixedProduct); await removeCoupon( await getCouponId( 'fixed product' ) );
await expect(page).toMatchElement('.order-total .amount', {text: '$9.99'}); await expect(page).toMatchElement('.order-total .amount', {text: '$9.99'});
}); });
}); });

View File

@ -10,6 +10,7 @@ const {
removeCoupon, removeCoupon,
waitForSelectorWithoutThrow, waitForSelectorWithoutThrow,
} = require( '@woocommerce/e2e-utils' ); } = require( '@woocommerce/e2e-utils' );
const { getCouponId, getCouponsTable } = require( '../utils/coupons' );
/** /**
* External dependencies * External dependencies
@ -20,26 +21,6 @@ const {
beforeAll, beforeAll,
} = require( '@jest/globals' ); } = require( '@jest/globals' );
const couponsTable = [
['fixed cart', { text: '$5.00' }, { text: '$4.99' }],
['percentage', { text: '$4.99' }, { text: '$5.00' }],
['fixed product', { text: '$5.00' }, { text: '$4.99' }]
];
let couponFixedCart;
let couponPercentage;
let couponFixedProduct;
const getCoupon = (couponType) => {
switch (couponType) {
case 'fixed cart':
return couponFixedCart;
case 'percentage':
return couponPercentage;
case 'fixed product':
return couponFixedProduct;
}
};
const runCheckoutApplyCouponsTest = () => { const runCheckoutApplyCouponsTest = () => {
describe('Checkout coupons', () => { describe('Checkout coupons', () => {
@ -47,9 +28,6 @@ const runCheckoutApplyCouponsTest = () => {
beforeAll(async () => { beforeAll(async () => {
productId = await createSimpleProduct(); productId = await createSimpleProduct();
couponFixedCart = await createCoupon();
couponPercentage = await createCoupon('50', 'Percentage discount');
couponFixedProduct = await createCoupon('5', 'Fixed product discount');
await shopper.emptyCart(); await shopper.emptyCart();
await shopper.goToShop(); await shopper.goToShop();
await waitForSelectorWithoutThrow( '.add_to_cart_button' ); await waitForSelectorWithoutThrow( '.add_to_cart_button' );
@ -58,8 +36,8 @@ const runCheckoutApplyCouponsTest = () => {
await shopper.goToCheckout(); await shopper.goToCheckout();
}); });
it.each(couponsTable)('allows checkout to apply %s coupon', async (couponType, cartDiscount, orderTotal) => { it.each( getCouponsTable() )( 'allows checkout to apply %s coupon', async ( couponType, cartDiscount, orderTotal ) => {
const coupon = getCoupon(couponType); const coupon = await getCouponId( couponType );
await applyCoupon(coupon); await applyCoupon(coupon);
await expect(page).toMatchElement('.woocommerce-message', { text: 'Coupon code applied successfully.' }); await expect(page).toMatchElement('.woocommerce-message', { text: 'Coupon code applied successfully.' });
@ -73,9 +51,10 @@ const runCheckoutApplyCouponsTest = () => {
}); });
it('prevents checkout applying same coupon twice', async () => { it('prevents checkout applying same coupon twice', async () => {
await applyCoupon(couponFixedCart); const couponId = await getCouponId( 'fixed cart' );
await applyCoupon( couponId );
await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'});
await applyCoupon(couponFixedCart); await applyCoupon( couponId );
// Verify only one discount applied // Verify only one discount applied
// This is a work around for Puppeteer inconsistently finding 'Coupon code already applied' // This is a work around for Puppeteer inconsistently finding 'Coupon code already applied'
await expect(page).toMatchElement('.cart-discount .amount', {text: '$5.00'}); await expect(page).toMatchElement('.cart-discount .amount', {text: '$5.00'});
@ -83,7 +62,7 @@ const runCheckoutApplyCouponsTest = () => {
}); });
it('allows checkout to apply multiple coupons', async () => { it('allows checkout to apply multiple coupons', async () => {
await applyCoupon(couponFixedProduct); await applyCoupon( await getCouponId( 'fixed product' ) );
await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'}); await expect(page).toMatchElement('.woocommerce-message', {text: 'Coupon code applied successfully.'});
// Verify discount applied and order total // Verify discount applied and order total
@ -92,8 +71,8 @@ const runCheckoutApplyCouponsTest = () => {
}); });
it('restores checkout total when coupons are removed', async () => { it('restores checkout total when coupons are removed', async () => {
await removeCoupon(couponFixedCart); await removeCoupon( await getCouponId( 'fixed cart' ) );
await removeCoupon(couponFixedProduct); await removeCoupon( await getCouponId( 'fixed product' ) );
await expect(page).toMatchElement('.order-total .amount', {text: '$9.99'}); await expect(page).toMatchElement('.order-total .amount', {text: '$9.99'});
}); });
}); });

View File

@ -42,6 +42,10 @@ const runCheckoutLoginAccountTest = () => {
await shopper.goToCheckout(); await shopper.goToCheckout();
}); });
afterAll( async () => {
await shopper.logout();
} );
it('can login to an existing account during checkout', async () => { it('can login to an existing account during checkout', async () => {
// Click to login during checkout // Click to login during checkout
await page.waitForSelector('.woocommerce-form-login-toggle'); await page.waitForSelector('.woocommerce-form-login-toggle');
@ -65,8 +69,11 @@ const runCheckoutLoginAccountTest = () => {
// Verify the user is logged in on my account page // Verify the user is logged in on my account page
await shopper.gotoMyAccount(); await shopper.gotoMyAccount();
await expect(page.url()).toMatch('my-account/');
await expect(page).toMatchElement('h1', {text: 'My account'}); await Promise.all( [
await expect(page.url()).toMatch('my-account/'),
await expect(page).toMatchElement('h1', {text: 'My account'}),
] );
}); });
}); });
}; };

View File

@ -25,6 +25,10 @@ const runMyAccountCreateAccountTest = () => {
await merchant.logout(); await merchant.logout();
}); });
afterAll( async () => {
await shopper.logout();
} );
it('can create a new account via my account', async () => { it('can create a new account via my account', async () => {
await shopper.gotoMyAccount(); await shopper.gotoMyAccount();
await page.waitForSelector('.woocommerce-form-register'); await page.waitForSelector('.woocommerce-form-register');

View File

@ -34,6 +34,10 @@ const runMyAccountPayOrderTest = () => {
await merchant.logout(); await merchant.logout();
}); });
afterAll( async () => {
await shopper.logout();
} );
it('allows customer to pay for their order in My Account', async () => { it('allows customer to pay for their order in My Account', async () => {
await shopper.login(); await shopper.login();
await shopper.goToOrders(); await shopper.goToOrders();

View File

@ -15,6 +15,10 @@ const pages = [
const runMyAccountPageTest = () => { const runMyAccountPageTest = () => {
describe('My account page', () => { describe('My account page', () => {
afterAll( async () => {
await shopper.logout();
} );
it('allows customer to login', async () => { it('allows customer to login', async () => {
await shopper.login(); await shopper.login();
expect(page).toMatch('Hello'); expect(page).toMatch('Hello');

View File

@ -36,6 +36,10 @@ const runOrderEmailReceivingTest = () => {
await merchant.logout(); await merchant.logout();
}); });
afterAll( async () => {
await shopper.logout();
} );
it('should receive order email after purchasing an item', async () => { it('should receive order email after purchasing an item', async () => {
await shopper.login(); await shopper.login();

View File

@ -0,0 +1,49 @@
/**
* Internal dependencies
*/
const { createCoupon } = require( '@woocommerce/e2e-utils' );
const couponsTable = [
[ 'fixed cart', { text: '$5.00' }, { text: '$4.99' } ],
[ 'percentage', { text: '$4.99' }, { text: '$5.00' } ],
[ 'fixed product', { text: '$5.00' }, { text: '$4.99' } ]
];
let couponFixedCart;
let couponPercentage;
let couponFixedProduct;
/**
* Get a test coupon Id. Create the coupon if it does not exist.
*
* @param {string} couponType Coupon type.
* @return {string} Coupon code.
*/
const getCouponId = async ( couponType ) => {
switch ( couponType ) {
case 'fixed cart':
if ( ! couponFixedCart ) {
couponFixedCart = await createCoupon();
}
return couponFixedCart;
case 'percentage':
if ( ! couponPercentage ) {
couponPercentage = await createCoupon( '50', 'Percentage discount' );
}
return couponPercentage;
case 'fixed product':
if ( ! couponFixedProduct ) {
couponFixedProduct = await createCoupon( '5', 'Fixed product discount' );
}
return couponFixedProduct;
}
};
const getCouponsTable = () => {
return couponsTable;
};
module.exports = {
getCouponsTable,
getCouponId,
};

View File

@ -2,9 +2,18 @@
## Added ## Added
- Added `await` for every call to `shopper.logout`
## Fixed
- Updated the browserViewport in `jest.setup.js` to match the `defaultViewport` dimensions defined in `jest-puppeteer.config.js`
## Added
- Added quotes around `WORDPRESS_TITLE` value in .env file to address issue with docker compose 2 "key cannot contain a space" error. - Added quotes around `WORDPRESS_TITLE` value in .env file to address issue with docker compose 2 "key cannot contain a space" error.
- Added `LATEST_WP_VERSION_MINUS` that allows setting a number to subtract from the current WordPress version for the WordPress Docker image. - Added `LATEST_WP_VERSION_MINUS` that allows setting a number to subtract from the current WordPress version for the WordPress Docker image.
- Support for PHP_VERSION, MARIADB_VERSION environment variables for built in container initialization - Support for PHP_VERSION, MARIADB_VERSION environment variables for built in container initialization
- `resolveLocalE2ePath` to resolve path to local E2E file
- `WC_E2E_FOLDER` for mapping plugin root to path within repo
## Fixed ## Fixed

View File

@ -10,6 +10,7 @@ const {
getAppRoot, getAppRoot,
getAppName, getAppName,
getTestConfig, getTestConfig,
resolveLocalE2ePath,
} = require( '../utils' ); } = require( '../utils' );
const dockerArgs = []; const dockerArgs = [];
@ -56,10 +57,7 @@ if ( appPath ) {
const appInitFile = customInitFile const appInitFile = customInitFile
? customInitFile ? customInitFile
: path.resolve( : resolveLocalE2ePath( 'docker/initialize.sh' );
appPath,
'plugins/woocommerce/tests/e2e/docker/initialize.sh'
);
// If found, copy it into the wp-cli Docker context so // If found, copy it into the wp-cli Docker context so
// it gets picked up by the entrypoint script. // it gets picked up by the entrypoint script.
if ( fs.existsSync( appInitFile ) ) { if ( fs.existsSync( appInitFile ) ) {
@ -84,11 +82,6 @@ if ( ! process.env.WC_E2E_FOLDER_MAPPING ) {
'/var/www/html/wp-content/plugins/' + getAppBase(); '/var/www/html/wp-content/plugins/' + getAppBase();
} }
// Set some environment variables
if ( ! process.env.WC_CORE_PATH ) {
envVars.WC_CORE_PATH = 'plugins/woocommerce';
}
if ( ! process.env.WORDPRESS_PORT ) { if ( ! process.env.WORDPRESS_PORT ) {
process.env.WORDPRESS_PORT = testConfig.port; process.env.WORDPRESS_PORT = testConfig.port;
} }

View File

@ -4,7 +4,7 @@ const { spawnSync } = require( 'child_process' );
const program = require( 'commander' ); const program = require( 'commander' );
const path = require( 'path' ); const path = require( 'path' );
const fs = require( 'fs' ); const fs = require( 'fs' );
const { getAppRoot } = require( '../utils' ); const { getAppRoot, resolveLocalE2ePath } = require( '../utils' );
const { const {
WC_E2E_SCREENSHOTS, WC_E2E_SCREENSHOTS,
JEST_PUPPETEER_CONFIG, JEST_PUPPETEER_CONFIG,
@ -21,10 +21,7 @@ const appPath = getAppRoot();
// clear the screenshots folder before running tests. // clear the screenshots folder before running tests.
if ( WC_E2E_SCREENSHOTS ) { if ( WC_E2E_SCREENSHOTS ) {
const screenshotPath = path.resolve( const screenshotPath = resolveLocalE2ePath( 'screenshots' );
appPath,
'plugins/woocommerce/tests/e2e/screenshots'
);
if ( fs.existsSync( screenshotPath ) ) { if ( fs.existsSync( screenshotPath ) ) {
fs.readdirSync( screenshotPath ).forEach( ( file, index ) => { fs.readdirSync( screenshotPath ).forEach( ( file, index ) => {
const filename = path.join( screenshotPath, file ); const filename = path.join( screenshotPath, file );
@ -36,9 +33,7 @@ if ( WC_E2E_SCREENSHOTS ) {
const nodeConfigDirs = [ path.resolve( __dirname, '../config' ) ]; const nodeConfigDirs = [ path.resolve( __dirname, '../config' ) ];
if ( appPath ) { if ( appPath ) {
nodeConfigDirs.unshift( nodeConfigDirs.unshift( resolveLocalE2ePath( 'config' ) );
path.resolve( appPath, 'plugins/woocommerce/tests/e2e/config' )
);
} }
const testEnvVars = { const testEnvVars = {
@ -55,10 +50,7 @@ if ( DEFAULT_TIMEOUT_OVERRIDE ) {
if ( ! JEST_PUPPETEER_CONFIG ) { if ( ! JEST_PUPPETEER_CONFIG ) {
// Use local Puppeteer config if there is one. // Use local Puppeteer config if there is one.
// Load test configuration file into an object. // Load test configuration file into an object.
const localJestConfigFile = path.resolve( const localJestConfigFile = resolveLocalE2ePath( 'config/jest-puppeteer.config.js' );
appPath,
'tests/e2e/config/jest-puppeteer.config.js'
);
const jestConfigFile = path.resolve( const jestConfigFile = path.resolve(
__dirname, __dirname,
'../config/jest-puppeteer.config.js' '../config/jest-puppeteer.config.js'
@ -100,10 +92,7 @@ let configPath = path.resolve( __dirname, '../config/jest.config.js' );
// Look for a Jest config in the dependent app's path. // Look for a Jest config in the dependent app's path.
if ( appPath ) { if ( appPath ) {
const appConfig = path.resolve( const appConfig = resolveLocalE2ePath( 'config/jest.config.js' );
appPath,
'plugins/woocommerce/tests/e2e/config/jest.config.js'
);
if ( fs.existsSync( appConfig ) ) { if ( fs.existsSync( appConfig ) ) {
configPath = appConfig; configPath = appConfig;

View File

@ -11,7 +11,8 @@ count=0
WP_BASE_URL=$(node utils/get-base-url.js) WP_BASE_URL=$(node utils/get-base-url.js)
printf "Testing URL: $WP_BASE_URL\n\n" printf "Testing URL: $WP_BASE_URL\n\n"
while [[ "$(curl -s -o /dev/null -w ''%{http_code}'' ${WP_BASE_URL}/?pagename=ready)" != "200" ]] RAWDATA=$(curl -s -o /dev/null -w '%{http_code}' ${WP_BASE_URL}/?pagename=ready)
while [[ "${RAWDATA: -3}" != "200" ]]
do do
echo "$(date) - Waiting for testing environment" echo "$(date) - Waiting for testing environment"
@ -23,6 +24,7 @@ do
echo "$(date) - Testing environment couldn't be found" echo "$(date) - Testing environment couldn't be found"
exit 1 exit 1
fi fi
RAWDATA=$(curl -s -o /dev/null -w '%{http_code}' ${WP_BASE_URL}/?pagename=ready)
done done
if [[ $count -gt 0 ]]; then if [[ $count -gt 0 ]]; then

View File

@ -33,6 +33,18 @@ SCRIPTPATH=$(dirname "$0")
REALPATH=$(readlink "$0") REALPATH=$(readlink "$0")
cd "$SCRIPTPATH/$(dirname "$REALPATH")/.." cd "$SCRIPTPATH/$(dirname "$REALPATH")/.."
# Set a flag to distinguish between the development repo and npm package
DEV_PATH=$(echo $0 | rev | cut -f4 -d/ | rev)
if [ "$DEV_PATH" != "node_modules" ]; then
export WC_E2E_WOOCOMMERCE_DEV='true'
export WC_E2E_FOLDER='plugins/woocommerce'
else
export WC_E2E_WOOCOMMERCE_DEV=''
if [ -z $WC_E2E_FOLDER ]; then
export WC_E2E_FOLDER=''
fi
fi
# Run scripts # Run scripts
case $1 in case $1 in
'docker:up') 'docker:up')

View File

@ -119,7 +119,12 @@ You can override these in `/tests/e2e/config/default.json`.
### Folder Mapping ### Folder Mapping
The built in container defaults to mapping the root folder of the repository to a folder in the `plugins` folder. For example `woocommerce` is mapped to `/var/www/html/wp-content/plugins/woocommerce`. Use the `WC_E2E_FOLDER_MAPPING` environment variable to override this mapping. The built in container defaults to mapping the root folder of the repository to a folder in the `plugins` folder. Use the environment variables `WC_E2E_FOLDER` and `WC_E2E_FOLDER_MAPPING` to override this mapping. The `WC_E2E_FOLDER` is a path relative to the root of the project. For example, in the `woocommerce` repository this mapping is:
- `WC_E2E_FOLDER=plugins/woocommerce`
- `WC_E2E_FOLDER_MAPPING=/var/www/html/wp-content/plugins/woocommerce`
Other repository examples:
- Storefront Theme - ```WC_E2E_FOLDER_MAPPING=/var/www/html/wp-content/themes/storefront npx wc-e2e docker:up``` - Storefront Theme - ```WC_E2E_FOLDER_MAPPING=/var/www/html/wp-content/themes/storefront npx wc-e2e docker:up```
- Site Project - ```WC_E2E_FOLDER_MAPPING=/var/www/html/wp-content npx wc-e2e docker:up``` - Site Project - ```WC_E2E_FOLDER_MAPPING=/var/www/html/wp-content npx wc-e2e docker:up```

View File

@ -12,15 +12,15 @@
"formatter": { "formatter": {
"filename": "../../../tools/changelogger/PackageFormatter.php" "filename": "../../../tools/changelogger/PackageFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }
} }

View File

@ -1,32 +1,46 @@
/** @format */ /** @format */
const { jestPuppeteerConfig } = require( '@automattic/puppeteer-utils' ); /**
* For a detailed explanation of configuration properties, visit:
* https://github.com/GoogleChrome/puppeteer/blob/master/docs/api.md#puppeteerlaunchoptions
*/
const { CI, E2E_DEBUG, PUPPETEER_SLOWMO, E2E_EXE_PATH } = process.env;
let executablePath = '';
let dumpio = false;
let puppeteerConfig; let puppeteerConfig;
if ( 'no' == global.process.env.node_config_dev ) {
puppeteerConfig = { if ( ! CI && E2E_EXE_PATH !== '' ) {
launch: { executablePath = E2E_EXE_PATH;
}
if ( E2E_DEBUG ) {
dumpio = true;
}
const jestPuppeteerLaunch = {
// Required for the logged out and logged in tests so they don't share app state/token. // Required for the logged out and logged in tests so they don't share app state/token.
browserContext: 'incognito', browserContext: 'incognito',
defaultViewport: { defaultViewport: {
width: 1280, width: 1280,
height: 800, height: 800,
}, },
}, };
if ( 'no' == global.process.env.node_config_dev ) {
puppeteerConfig = {
launch: jestPuppeteerLaunch,
}; };
} else { } else {
puppeteerConfig = { puppeteerConfig = {
launch: { launch: {
...jestPuppeteerConfig.launch, ...jestPuppeteerLaunch,
slowMo: process.env.PUPPETEER_SLOWMO ? process.env.PUPPETEER_SLOWMO : 50, executablePath,
dumpio,
slowMo: PUPPETEER_SLOWMO ? PUPPETEER_SLOWMO : 50,
headless: false, headless: false,
ignoreHTTPSErrors: true, ignoreHTTPSErrors: true,
args: [ '--window-size=1920,1080', '--user-agent=chrome' ], args: [ '--window-size=1920,1080', '--user-agent=chrome' ],
devtools: true, devtools: true,
defaultViewport: {
width: 1280,
height: 800,
},
}, },
}; };
} }

View File

@ -1,7 +1,6 @@
/** /**
* External Dependencies * External Dependencies
*/ */
const { jestConfig } = require( '@automattic/puppeteer-utils' );
const { WC_E2E_SCREENSHOTS } = process.env; const { WC_E2E_SCREENSHOTS } = process.env;
const path = require( 'path' ); const path = require( 'path' );
const fs = require( 'fs' ); const fs = require( 'fs' );
@ -9,7 +8,7 @@ const fs = require( 'fs' );
/** /**
* Internal Dependencies * Internal Dependencies
*/ */
const { getAppRoot } = require( '../utils' ); const { resolveLocalE2ePath } = require( '../utils' );
const failureSetup = []; const failureSetup = [];
if ( WC_E2E_SCREENSHOTS ) { if ( WC_E2E_SCREENSHOTS ) {
@ -23,19 +22,24 @@ const setupFilesAfterEnv = [
'expect-puppeteer', 'expect-puppeteer',
]; ];
const appPath = getAppRoot(); const localJestSetupFile = resolveLocalE2ePath( 'config/jest.setup.js' );
const localJestSetupFile = path.resolve( const moduleNameMap = resolveLocalE2ePath( '$1' );
appPath, const testSpecs = resolveLocalE2ePath( 'specs' );
'plugins/woocommerce/tests/e2e/config/jest.setup.js'
);
if ( fs.existsSync( localJestSetupFile ) ) { if ( fs.existsSync( localJestSetupFile ) ) {
setupFilesAfterEnv.push( localJestSetupFile ); setupFilesAfterEnv.push( localJestSetupFile );
} }
const combinedConfig = { const combinedConfig = {
...jestConfig, preset: 'jest-puppeteer',
clearMocks: true,
moduleFileExtensions: [ 'js' ],
testMatch: [
'**/*.(test|spec).js',
'*.(test|spec).js'
],
moduleNameMapper: { moduleNameMapper: {
'@woocommerce/e2e/tests/(.*)': appPath + 'tests/e2e/$1', '@woocommerce/e2e/tests/(.*)': moduleNameMap,
}, },
setupFiles: [ '<rootDir>/config/env.setup.js' ], setupFiles: [ '<rootDir>/config/env.setup.js' ],
@ -49,10 +53,9 @@ const combinedConfig = {
testTimeout: parseInt( global.process.env.jest_test_timeout ), testTimeout: parseInt( global.process.env.jest_test_timeout ),
transformIgnorePatterns: [ transformIgnorePatterns: [
...jestConfig.transformIgnorePatterns,
'node_modules/(?!(woocommerce)/)', 'node_modules/(?!(woocommerce)/)',
], ],
roots: [ appPath + 'tests/e2e/specs' ], roots: [ testSpecs ],
}; };
if ( process.env.jest_test_spec ) { if ( process.env.jest_test_spec ) {

View File

@ -35,7 +35,7 @@ services:
WORDPRESS_DEBUG: 1 WORDPRESS_DEBUG: 1
volumes: volumes:
- wordpress:/var/www/html - wordpress:/var/www/html
- "../../../${WC_CORE_PATH}:${WC_E2E_FOLDER_MAPPING}" - "../../../${WC_E2E_FOLDER}:${WC_E2E_FOLDER_MAPPING}"
wordpress-cli: wordpress-cli:
container_name: "${APP_NAME}_wordpress-cli" container_name: "${APP_NAME}_wordpress-cli"
@ -60,7 +60,7 @@ services:
volumes: volumes:
- wordpress:/var/www/html - wordpress:/var/www/html
- "../../../plugins/woocommerce:${WC_E2E_FOLDER_MAPPING}" - "../../../${WC_E2E_FOLDER}:${WC_E2E_FOLDER_MAPPING}"
volumes: volumes:
db: db:

View File

@ -38,7 +38,10 @@ const OBSERVED_CONSOLE_MESSAGE_TYPES = {
async function setupBrowser() { async function setupBrowser() {
await clearLocalStorage(); await clearLocalStorage();
await setBrowserViewport( 'large' ); await setBrowserViewport( {
width: 1280,
height: 800,
});
} }
/** /**

View File

@ -1,6 +1,6 @@
const getAppRoot = require( './app-root' ); const getAppRoot = require( './app-root' );
const { getAppName, getAppBase } = require( './app-name' ); const { getAppName, getAppBase } = require( './app-name' );
const { getTestConfig, getAdminConfig } = require( './test-config' ); const { getTestConfig, getAdminConfig, resolveLocalE2ePath } = require( './test-config' );
const { getRemotePluginZip, getLatestReleaseZipUrl } = require('./get-plugin-zip'); const { getRemotePluginZip, getLatestReleaseZipUrl } = require('./get-plugin-zip');
const takeScreenshotFor = require( './take-screenshot' ); const takeScreenshotFor = require( './take-screenshot' );
const updateReadyPageStatus = require('./update-ready-page'); const updateReadyPageStatus = require('./update-ready-page');
@ -12,6 +12,7 @@ module.exports = {
getAppName, getAppName,
getTestConfig, getTestConfig,
getAdminConfig, getAdminConfig,
resolveLocalE2ePath,
getRemotePluginZip, getRemotePluginZip,
getLatestReleaseZipUrl, getLatestReleaseZipUrl,
takeScreenshotFor, takeScreenshotFor,

View File

@ -1,6 +1,6 @@
const path = require( 'path' ); const path = require( 'path' );
const mkdirp = require( 'mkdirp' ); const mkdirp = require( 'mkdirp' );
const getAppRoot = require( './app-root' ); const { resolveLocalE2ePath } = require( './test-config' );
/** /**
* Take a screenshot if browser context exists. * Take a screenshot if browser context exists.
@ -10,11 +10,7 @@ const getAppRoot = require( './app-root' );
*/ */
const takeScreenshotFor = async ( message ) => { const takeScreenshotFor = async ( message ) => {
const title = message.replace( /\.$/, '' ); const title = message.replace( /\.$/, '' );
const appPath = getAppRoot(); const savePath = resolveLocalE2ePath( 'screenshots' );
const savePath = path.resolve(
appPath,
'plugins/woocommerce/tests/e2e/screenshots'
);
const filePath = path.join( const filePath = path.join(
savePath, savePath,
`${ title }.png`.replace( /[^a-z0-9.-]+/gi, '-' ) `${ title }.png`.replace( /[^a-z0-9.-]+/gi, '-' )

View File

@ -2,12 +2,27 @@ const path = require( 'path' );
const fs = require( 'fs' ); const fs = require( 'fs' );
const getAppRoot = require( './app-root' ); const getAppRoot = require( './app-root' );
// Copy local test configuration file if it exists.
const appPath = getAppRoot(); const appPath = getAppRoot();
const localTestConfigFile = path.resolve(
/**
* Resolve a local E2E file.
*
* @param {string} filename Filename to append to the path.
* @return {string}
*/
const resolveLocalE2ePath = ( filename = '' ) => {
const { WC_E2E_FOLDER } = process.env;
const localPath = `${WC_E2E_FOLDER}/tests/e2e/${filename}`;
const resolvedPath = path.resolve(
appPath, appPath,
'plugins/woocommerce/tests/e2e/config/default.json' localPath.indexOf( '/' ) == 0 ? localPath.slice( 1 ) : localPath
); );
return resolvedPath;
}
// Copy local test configuration file if it exists.
const localTestConfigFile = resolveLocalE2ePath( 'config/default.json' );
const defaultConfigFile = path.resolve( const defaultConfigFile = path.resolve(
__dirname, __dirname,
'../config/default/default.json' '../config/default/default.json'
@ -78,4 +93,5 @@ const getAdminConfig = () => {
module.exports = { module.exports = {
getTestConfig, getTestConfig,
getAdminConfig, getAdminConfig,
resolveLocalE2ePath,
}; };

View File

@ -1,5 +1,9 @@
# Unreleased # Unreleased
## Changes
- Removed `page.waitForNavigation()` from `shopper.logout()`
## Added ## Added
- `utils.waitForTimeout( delay )` pause processing for `delay` milliseconds - `utils.waitForTimeout( delay )` pause processing for `delay` milliseconds
@ -14,6 +18,7 @@
- `withRestApi.addTaxRates()` that adds an array of tax rates if they do not exist - `withRestApi.addTaxRates()` that adds an array of tax rates if they do not exist
- `clickAndWaitForSelector( buttonSelector, resultSelector, timeout )` to click a button and wait for response - `clickAndWaitForSelector( buttonSelector, resultSelector, timeout )` to click a button and wait for response
- Optional parameter `testResponse` to `withRestApi` functions that contain an `expect()` - Optional parameter `testResponse` to `withRestApi` functions that contain an `expect()`
- `shopper.logout()` to log out the shopper account
# 0.1.6 # 0.1.6

View File

@ -129,6 +129,7 @@ This package provides support for enabling retries in tests:
| `goToProduct` | `productId` | Go to a single product in the shop | | `goToProduct` | `productId` | Go to a single product in the shop |
| `goToShop` | | Go to the shop page | | `goToShop` | | Go to the shop page |
| `login` | | Log in as the shopper | | `login` | | Log in as the shopper |
| `logout` | | Log out of the shopper account |
| `placeOrder` | | Place an order from the checkout page | | `placeOrder` | | Place an order from the checkout page |
| `productIsInCheckout` | `productTitle, quantity, total, cartSubtotal` | Verify product is in cart on checkout page | | `productIsInCheckout` | `productTitle, quantity, total, cartSubtotal` | Verify product is in cart on checkout page |
| `removeFromCart` | `productIdOrTitle` | Remove a product from the cart on the cart page | | `removeFromCart` | `productIdOrTitle` | Remove a product from the cart on the cart page |

View File

@ -12,15 +12,15 @@
"formatter": { "formatter": {
"filename": "../../../tools/changelogger/PackageFormatter.php" "filename": "../../../tools/changelogger/PackageFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }
} }

View File

@ -12,7 +12,7 @@
"module": "build-module/index.js", "module": "build-module/index.js",
"dependencies": { "dependencies": {
"@automattic/puppeteer-utils": "github:Automattic/puppeteer-utils#0f3ec50", "@automattic/puppeteer-utils": "github:Automattic/puppeteer-utils#0f3ec50",
"@wordpress/deprecated": "^2.10.0", "@wordpress/deprecated": "^3.2.3",
"@wordpress/e2e-test-utils": "^4.16.1", "@wordpress/e2e-test-utils": "^4.16.1",
"config": "3.3.3", "config": "3.3.3",
"faker": "^5.1.0", "faker": "^5.1.0",

View File

@ -190,16 +190,23 @@ const completeOnboardingWizard = async () => {
/** /**
* Create simple product. * Create simple product.
* *
* @param productTitle Defaults to Simple Product. Customizable title. * @param {string} productTitle Defaults to Simple Product. Customizable title.
* @param productPrice Defaults to $9.99. Customizable pricing. * @param {string} productPrice Defaults to $9.99. Customizable pricing.
* @param {Object} additionalProps Defaults to nothing. Additional product properties.
*/ */
const createSimpleProduct = async ( productTitle = simpleProductName, productPrice = simpleProductPrice ) => { const createSimpleProduct = async (
const product = await factories.products.simple.create( { productTitle = simpleProductName,
productPrice = simpleProductPrice,
additionalProps = {}
) => {
const newProduct = {
name: productTitle, name: productTitle,
regularPrice: productPrice, regularPrice: productPrice,
} ); ...additionalProps,
};
const product = await factories.products.simple.create( newProduct );
return product.id; return product.id;
} ; };
/** /**
* Create simple product with categories * Create simple product with categories
@ -335,21 +342,29 @@ const createGroupedProduct = async (groupedProduct = defaultGroupedProduct) => {
*/ */
const createOrder = async ( orderOptions = {} ) => { const createOrder = async ( orderOptions = {} ) => {
const newOrder = { const newOrder = {
...( orderOptions.status ) && { status: orderOptions.status }, ...( orderOptions.status && { status: orderOptions.status } ),
...( orderOptions.customerId ) && { customer_id: orderOptions.customerId }, ...( orderOptions.customerId && {
...( orderOptions.customerBilling ) && { billing: orderOptions.customerBilling }, customer_id: orderOptions.customerId,
...( orderOptions.customerShipping ) && { shipping: orderOptions.customerShipping }, } ),
...( orderOptions.productId ) && { line_items: [ ...( orderOptions.customerBilling && {
{ product_id: orderOptions.productId }, billing: orderOptions.customerBilling,
] } ),
}, ...( orderOptions.customerShipping && {
shipping: orderOptions.customerShipping,
} ),
...( orderOptions.productId && {
line_items: [ { product_id: orderOptions.productId } ],
} ),
...( orderOptions.lineItems && {
line_items: orderOptions.lineItems,
} ),
}; };
const repository = Order.restRepository( client ); const repository = Order.restRepository( client );
const order = await repository.create( newOrder ); const order = await repository.create( newOrder );
return order.id; return order.id;
} };
/** /**
* Create a basic order with the provided order status. * Create a basic order with the provided order status.

View File

@ -24,7 +24,7 @@ const {
SHOP_PRODUCT_PAGE SHOP_PRODUCT_PAGE
} = require( './constants' ); } = require( './constants' );
const { uiUnblocked } = require( '../page-utils' ); const { uiUnblocked, clickAndWaitForSelector } = require( '../page-utils' );
const gotoMyAccount = async () => { const gotoMyAccount = async () => {
await page.goto( SHOP_MY_ACCOUNT_PAGE, { await page.goto( SHOP_MY_ACCOUNT_PAGE, {
@ -235,6 +235,12 @@ const shopper = {
page.click( 'button[name="login"]' ), page.click( 'button[name="login"]' ),
] ); ] );
}, },
logout: async () => {
await gotoMyAccount();
await expect( page.title() ).resolves.toMatch( 'My account' );
await page.click( '.woocommerce-MyAccount-navigation-link--customer-logout a' );
},
}; };
module.exports = shopper; module.exports = shopper;

View File

@ -2,7 +2,6 @@
* External dependencies * External dependencies
*/ */
import { pressKeyWithModifier } from '@wordpress/e2e-test-utils'; import { pressKeyWithModifier } from '@wordpress/e2e-test-utils';
import { waitForSelector } from '@automattic/puppeteer-utils';
/** /**
* Internal dependencies * Internal dependencies
@ -318,3 +317,21 @@ export const clickAndWaitForSelector = async ( buttonSelector, resultSelector, t
} }
); );
}; };
/**
* Waits for selector to be present in DOM.
* Throws a `TimeoutError` if element was not found after 30 sec.
* Behavior can be modified with @param options. Possible keys: `visible`, `hidden`, `timeout`.
* More details at: https://pptr.dev/#?product=Puppeteer&show=api-pagewaitforselectorselector-options
*
* @param {Puppeteer.Page} page Puppeteer representation of the page.
* @param {string} selector CSS selector of the element
* @param {Object} options Custom options to modify function behavior.
*/
export async function waitForSelector( page, selector, options = {} ) {
// set up default options
const defaultOptions = { timeout: 30000, logHTML: false };
options = Object.assign( defaultOptions, options );
const element = await page.waitForSelector( selector, options );
return element;
}

View File

@ -5,24 +5,25 @@
*.zip *.zip
/bin/ /bin/
/build/ /build/
/changelog/
/node_modules/ /node_modules/
/tests/ /tests/
babel.config.js babel.config.js
changelog.txt changelog.txt
composer.* composer.*
tsconfig.*
contributors.html contributors.html
docker-compose.yaml docker-compose.yaml
Dockerfile Dockerfile
Gruntfile.js Gruntfile.js
none none
project.json
package-lock.json package-lock.json
package.json package.json
packages/woocommerce-admin/docs packages/woocommerce-admin/docs
phpcs.xml phpcs.xml
phpunit.xml phpunit.xml
phpunit.xml.dist phpunit.xml.dist
project.json
README.md README.md
renovate.json renovate.json
tsconfig.*
webpack.config.js webpack.config.js

View File

@ -7,12 +7,13 @@ none
# Sass # Sass
.sass-cache/ .sass-cache/
# Compiled CSS # All CSS
/assets/css/**
/assets/css/*.css /assets/css/*.css
/assets/css/photoswipe/**/*.min.css
# Minified JS # All JS
/assets/js/**/*.min.js /assets/js/**
/assets/js/*.js
# Behat/CLI Tests # Behat/CLI Tests
tests/cli/installer tests/cli/installer
@ -34,6 +35,9 @@ tests/cli/vendor
# Logs # Logs
/logs /logs
# TypeScript files
tsconfig.tsbuildinfo
# Composer # Composer
/vendor/ /vendor/
/bin/composer/**/vendor/ /bin/composer/**/vendor/

View File

@ -1,231 +0,0 @@
module.exports = function( grunt ) {
'use strict';
var sass = require( 'node-sass' );
grunt.initConfig({
// Setting folder templates.
dirs: {
css: 'assets/css',
fonts: 'assets/fonts',
images: 'assets/images',
js: 'assets/js',
php: 'includes'
},
// JavaScript linting with ESLint.
eslint: {
src: [
'<%= dirs.js %>/admin/*.js',
'!<%= dirs.js %>/admin/*.min.js',
'<%= dirs.js %>/frontend/*.js',
'!<%= dirs.js %>/frontend/*.min.js'
]
},
// Sass linting with Stylelint.
stylelint: {
options: {
configFile: '.stylelintrc'
},
all: [
'<%= dirs.css %>/*.scss',
'!<%= dirs.css %>/select2.scss'
]
},
// Minify .js files.
uglify: {
options: {
ie8: true,
parse: {
strict: false
},
output: {
comments : /@license|@preserve|^!/
}
},
js_assets: {
files: [{
expand: true,
cwd: '<%= dirs.js %>/',
src: [
'**/*.js',
'!**/*.min.js'
],
extDot: 'last',
dest: '<%= dirs.js %>',
ext: '.min.js'
}]
}
},
// Compile all .scss files.
sass: {
compile: {
options: {
implementation: sass,
sourceMap: 'none'
},
files: [{
expand: true,
cwd: '<%= dirs.css %>/',
src: ['*.scss'],
dest: '<%= dirs.css %>/',
ext: '.css'
}]
}
},
// Generate RTL .css files.
rtlcss: {
woocommerce: {
expand: true,
cwd: '<%= dirs.css %>',
src: [
'*.css',
'!select2.css',
'!*-rtl.css'
],
dest: '<%= dirs.css %>/',
ext: '-rtl.css'
}
},
// Minify all .css files.
cssmin: {
minify: {
files: [
{
expand: true,
cwd: '<%= dirs.css %>/',
src: ['*.css'],
dest: '<%= dirs.css %>/',
ext: '.css'
},
{
expand: true,
cwd: '<%= dirs.css %>/photoswipe/',
src: ['*.css', '!*.min.css'],
dest: '<%= dirs.css %>/photoswipe/',
ext: '.min.css'
},
{
expand: true,
cwd: '<%= dirs.css %>/photoswipe/default-skin/',
src: ['*.css', '!*.min.css'],
dest: '<%= dirs.css %>/photoswipe/default-skin/',
ext: '.min.css'
}
]
}
},
// Concatenate select2.css onto the admin.css files.
concat: {
admin: {
files: {
'<%= dirs.css %>/admin.css' : ['<%= dirs.css %>/select2.css', '<%= dirs.css %>/admin.css'],
'<%= dirs.css %>/admin-rtl.css' : ['<%= dirs.css %>/select2.css', '<%= dirs.css %>/admin-rtl.css']
}
}
},
// Watch changes for assets.
watch: {
css: {
files: ['<%= dirs.css %>/*.scss'],
tasks: ['sass', 'rtlcss', 'postcss', 'cssmin', 'concat']
},
js: {
files: [
'GruntFile.js',
'<%= dirs.js %>/**/*.js',
'!<%= dirs.js %>/**/*.min.js'
],
tasks: ['eslint','newer:uglify']
}
},
// PHP Code Sniffer.
phpcs: {
options: {
bin: 'vendor/bin/phpcs'
},
dist: {
src: [
'**/*.php', // Include all php files.
'!includes/api/legacy/**',
'!includes/libraries/**',
'!node_modules/**',
'!tests/cli/**',
'!tmp/**',
'!vendor/**'
]
}
},
// Autoprefixer.
postcss: {
options: {
processors: [
require( 'autoprefixer' )
]
},
dist: {
src: [
'<%= dirs.css %>/*.css'
]
}
}
});
// Load NPM tasks to be used here.
grunt.loadNpmTasks( 'grunt-sass' );
grunt.loadNpmTasks( 'grunt-phpcs' );
grunt.loadNpmTasks( 'grunt-rtlcss' );
grunt.loadNpmTasks( 'grunt-postcss' );
grunt.loadNpmTasks( 'grunt-stylelint' );
grunt.loadNpmTasks( 'gruntify-eslint' );
grunt.loadNpmTasks( 'grunt-contrib-uglify' );
grunt.loadNpmTasks( 'grunt-contrib-cssmin' );
grunt.loadNpmTasks( 'grunt-contrib-concat' );
grunt.loadNpmTasks( 'grunt-contrib-copy' );
grunt.loadNpmTasks( 'grunt-contrib-watch' );
grunt.loadNpmTasks( 'grunt-contrib-clean' );
grunt.loadNpmTasks( 'grunt-newer' );
// Register tasks.
grunt.registerTask( 'default', [
'js',
'css'
]);
grunt.registerTask( 'js', [
'eslint',
'uglify:js_assets'
]);
grunt.registerTask( 'css', [
'sass',
'rtlcss',
'postcss',
'cssmin',
'concat'
]);
grunt.registerTask( 'assets', [
'js',
'css'
]);
grunt.registerTask( 'e2e-build', [
'uglify:js_assets',
'css'
]);
// Only an alias to 'default' task.
grunt.registerTask( 'dev', [
'default'
]);
};

View File

View File

View File

@ -33,7 +33,6 @@
"squizlabs/php_codesniffer": "^3.5", "squizlabs/php_codesniffer": "^3.5",
"vimeo/psalm": "^4.4" "vimeo/psalm": "^4.4"
}, },
"default-branch": true,
"bin": [ "bin": [
"bin/mozart" "bin/mozart"
], ],
@ -54,10 +53,6 @@
} }
], ],
"description": "Composes all dependencies as a package inside a WordPress plugin", "description": "Composes all dependencies as a package inside a WordPress plugin",
"support": {
"issues": "https://github.com/coenjacobs/mozart/issues",
"source": "https://github.com/coenjacobs/mozart/tree/master"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/coenjacobs", "url": "https://github.com/coenjacobs",
@ -68,16 +63,16 @@
}, },
{ {
"name": "league/flysystem", "name": "league/flysystem",
"version": "1.1.5", "version": "1.1.8",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/flysystem.git", "url": "https://github.com/thephpleague/flysystem.git",
"reference": "18634df356bfd4119fe3d6156bdb990c414c14ea" "reference": "c995bb0c23c58c9813d081f9523c9b7bb496698e"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/flysystem/zipball/18634df356bfd4119fe3d6156bdb990c414c14ea", "url": "https://api.github.com/repos/thephpleague/flysystem/zipball/c995bb0c23c58c9813d081f9523c9b7bb496698e",
"reference": "18634df356bfd4119fe3d6156bdb990c414c14ea", "reference": "c995bb0c23c58c9813d081f9523c9b7bb496698e",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -148,30 +143,26 @@
"sftp", "sftp",
"storage" "storage"
], ],
"support": {
"issues": "https://github.com/thephpleague/flysystem/issues",
"source": "https://github.com/thephpleague/flysystem/tree/1.1.5"
},
"funding": [ "funding": [
{ {
"url": "https://offset.earth/frankdejonge", "url": "https://offset.earth/frankdejonge",
"type": "other" "type": "other"
} }
], ],
"time": "2021-08-17T13:49:42+00:00" "time": "2021-11-28T21:50:23+00:00"
}, },
{ {
"name": "league/mime-type-detection", "name": "league/mime-type-detection",
"version": "1.8.0", "version": "1.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/thephpleague/mime-type-detection.git", "url": "https://github.com/thephpleague/mime-type-detection.git",
"reference": "b38b25d7b372e9fddb00335400467b223349fd7e" "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/b38b25d7b372e9fddb00335400467b223349fd7e", "url": "https://api.github.com/repos/thephpleague/mime-type-detection/zipball/aa70e813a6ad3d1558fc927863d47309b4c23e69",
"reference": "b38b25d7b372e9fddb00335400467b223349fd7e", "reference": "aa70e813a6ad3d1558fc927863d47309b4c23e69",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -179,7 +170,7 @@
"php": "^7.2 || ^8.0" "php": "^7.2 || ^8.0"
}, },
"require-dev": { "require-dev": {
"friendsofphp/php-cs-fixer": "^2.18", "friendsofphp/php-cs-fixer": "^3.2",
"phpstan/phpstan": "^0.12.68", "phpstan/phpstan": "^0.12.68",
"phpunit/phpunit": "^8.5.8 || ^9.3" "phpunit/phpunit": "^8.5.8 || ^9.3"
}, },
@ -200,10 +191,6 @@
} }
], ],
"description": "Mime-type detection for Flysystem", "description": "Mime-type detection for Flysystem",
"support": {
"issues": "https://github.com/thephpleague/mime-type-detection/issues",
"source": "https://github.com/thephpleague/mime-type-detection/tree/1.8.0"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/frankdejonge", "url": "https://github.com/frankdejonge",
@ -214,7 +201,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-09-25T08:23:19+00:00" "time": "2021-11-21T11:48:40+00:00"
}, },
{ {
"name": "psr/container", "name": "psr/container",
@ -258,34 +245,30 @@
"container-interop", "container-interop",
"psr" "psr"
], ],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/1.1.1"
},
"time": "2021-03-05T17:36:06+00:00" "time": "2021-03-05T17:36:06+00:00"
}, },
{ {
"name": "symfony/console", "name": "symfony/console",
"version": "v5.3.10", "version": "v5.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/console.git", "url": "https://github.com/symfony/console.git",
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3" "reference": "ec3661faca1d110d6c307e124b44f99ac54179e3"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/console/zipball/d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", "url": "https://api.github.com/repos/symfony/console/zipball/ec3661faca1d110d6c307e124b44f99ac54179e3",
"reference": "d4e409d9fbcfbf71af0e5a940abb7b0b4bad0bd3", "reference": "ec3661faca1d110d6c307e124b44f99ac54179e3",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1", "symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php73": "^1.8", "symfony/polyfill-php73": "^1.8",
"symfony/polyfill-php80": "^1.16", "symfony/polyfill-php80": "^1.16",
"symfony/service-contracts": "^1.1|^2", "symfony/service-contracts": "^1.1|^2|^3",
"symfony/string": "^5.1" "symfony/string": "^5.1|^6.0"
}, },
"conflict": { "conflict": {
"psr/log": ">=3", "psr/log": ">=3",
@ -300,12 +283,12 @@
}, },
"require-dev": { "require-dev": {
"psr/log": "^1|^2", "psr/log": "^1|^2",
"symfony/config": "^4.4|^5.0", "symfony/config": "^4.4|^5.0|^6.0",
"symfony/dependency-injection": "^4.4|^5.0", "symfony/dependency-injection": "^4.4|^5.0|^6.0",
"symfony/event-dispatcher": "^4.4|^5.0", "symfony/event-dispatcher": "^4.4|^5.0|^6.0",
"symfony/lock": "^4.4|^5.0", "symfony/lock": "^4.4|^5.0|^6.0",
"symfony/process": "^4.4|^5.0", "symfony/process": "^4.4|^5.0|^6.0",
"symfony/var-dumper": "^4.4|^5.0" "symfony/var-dumper": "^4.4|^5.0|^6.0"
}, },
"suggest": { "suggest": {
"psr/log": "For using the console logger", "psr/log": "For using the console logger",
@ -344,9 +327,6 @@
"console", "console",
"terminal" "terminal"
], ],
"support": {
"source": "https://github.com/symfony/console/tree/v5.3.10"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -361,20 +341,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-10-26T09:30:15+00:00" "time": "2021-11-29T15:30:56+00:00"
}, },
{ {
"name": "symfony/deprecation-contracts", "name": "symfony/deprecation-contracts",
"version": "v2.4.0", "version": "v2.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/deprecation-contracts.git", "url": "https://github.com/symfony/deprecation-contracts.git",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627" "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/5f38c8804a9e97d23e0c8d63341088cd8a22d627", "url": "https://api.github.com/repos/symfony/deprecation-contracts/zipball/6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"reference": "5f38c8804a9e97d23e0c8d63341088cd8a22d627", "reference": "6f981ee24cf69ee7ce9736146d1c57c2780598a8",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -383,7 +363,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "2.4-dev" "dev-main": "2.5-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -411,9 +391,6 @@
], ],
"description": "A generic function and convention to trigger deprecation notices", "description": "A generic function and convention to trigger deprecation notices",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/deprecation-contracts/tree/v2.4.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -428,24 +405,25 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-03-23T23:28:01+00:00" "time": "2021-07-12T14:48:14+00:00"
}, },
{ {
"name": "symfony/finder", "name": "symfony/finder",
"version": "v5.3.7", "version": "v5.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/finder.git", "url": "https://github.com/symfony/finder.git",
"reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93" "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/finder/zipball/a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "url": "https://api.github.com/repos/symfony/finder/zipball/d2f29dac98e96a98be467627bd49c2efb1bc2590",
"reference": "a10000ada1e600d109a6c7632e9ac42e8bf2fb93", "reference": "d2f29dac98e96a98be467627bd49c2efb1bc2590",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"symfony/deprecation-contracts": "^2.1|^3",
"symfony/polyfill-php80": "^1.16" "symfony/polyfill-php80": "^1.16"
}, },
"type": "library", "type": "library",
@ -473,9 +451,6 @@
], ],
"description": "Finds files and directories via an intuitive fluent interface", "description": "Finds files and directories via an intuitive fluent interface",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/v5.3.7"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -490,7 +465,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-08-04T21:20:46+00:00" "time": "2021-11-28T15:25:38+00:00"
}, },
{ {
"name": "symfony/polyfill-ctype", "name": "symfony/polyfill-ctype",
@ -552,9 +527,6 @@
"polyfill", "polyfill",
"portable" "portable"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.23.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -633,9 +605,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-intl-grapheme/tree/v1.23.1"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -717,9 +686,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-intl-normalizer/tree/v1.23.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -797,9 +763,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.23.1"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -876,9 +839,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-php73/tree/v1.23.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -959,9 +919,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-php80/tree/v1.23.1"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -980,21 +937,25 @@
}, },
{ {
"name": "symfony/service-contracts", "name": "symfony/service-contracts",
"version": "v2.4.0", "version": "v2.5.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/service-contracts.git", "url": "https://github.com/symfony/service-contracts.git",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb" "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/service-contracts/zipball/f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", "url": "https://api.github.com/repos/symfony/service-contracts/zipball/1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc",
"reference": "f040a30e04b57fbcc9c6cbcf4dbaa96bd318b9bb", "reference": "1ab11b933cd6bc5464b08e81e2c5b07dec58b0fc",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
"php": ">=7.2.5", "php": ">=7.2.5",
"psr/container": "^1.1" "psr/container": "^1.1",
"symfony/deprecation-contracts": "^2.1"
},
"conflict": {
"ext-psr": "<1.1|>=2"
}, },
"suggest": { "suggest": {
"symfony/service-implementation": "" "symfony/service-implementation": ""
@ -1002,7 +963,7 @@
"type": "library", "type": "library",
"extra": { "extra": {
"branch-alias": { "branch-alias": {
"dev-main": "2.4-dev" "dev-main": "2.5-dev"
}, },
"thanks": { "thanks": {
"name": "symfony/contracts", "name": "symfony/contracts",
@ -1038,9 +999,6 @@
"interoperability", "interoperability",
"standards" "standards"
], ],
"support": {
"source": "https://github.com/symfony/service-contracts/tree/v2.4.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -1055,20 +1013,20 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-04-01T10:43:52+00:00" "time": "2021-11-04T16:48:04+00:00"
}, },
{ {
"name": "symfony/string", "name": "symfony/string",
"version": "v5.3.10", "version": "v5.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/symfony/string.git", "url": "https://github.com/symfony/string.git",
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c" "reference": "9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/symfony/string/zipball/d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", "url": "https://api.github.com/repos/symfony/string/zipball/9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d",
"reference": "d70c35bb20bbca71fc4ab7921e3c6bda1a82a60c", "reference": "9ffaaba53c61ba75a3c7a3a779051d1e9ec4fd2d",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -1079,11 +1037,14 @@
"symfony/polyfill-mbstring": "~1.0", "symfony/polyfill-mbstring": "~1.0",
"symfony/polyfill-php80": "~1.15" "symfony/polyfill-php80": "~1.15"
}, },
"conflict": {
"symfony/translation-contracts": ">=3.0"
},
"require-dev": { "require-dev": {
"symfony/error-handler": "^4.4|^5.0", "symfony/error-handler": "^4.4|^5.0|^6.0",
"symfony/http-client": "^4.4|^5.0", "symfony/http-client": "^4.4|^5.0|^6.0",
"symfony/translation-contracts": "^1.1|^2", "symfony/translation-contracts": "^1.1|^2",
"symfony/var-exporter": "^4.4|^5.0" "symfony/var-exporter": "^4.4|^5.0|^6.0"
}, },
"type": "library", "type": "library",
"autoload": { "autoload": {
@ -1121,9 +1082,6 @@
"utf-8", "utf-8",
"utf8" "utf8"
], ],
"support": {
"source": "https://github.com/symfony/string/tree/v5.3.10"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -1138,7 +1096,7 @@
"type": "tidelift" "type": "tidelift"
} }
], ],
"time": "2021-10-27T18:21:46+00:00" "time": "2021-11-24T10:02:00+00:00"
} }
], ],
"aliases": [], "aliases": [],
@ -1153,5 +1111,5 @@
"platform-overrides": { "platform-overrides": {
"php": "7.3" "php": "7.3"
}, },
"plugin-api-version": "2.1.0" "plugin-api-version": "1.1.0"
} }

View File

@ -71,10 +71,6 @@
"stylecheck", "stylecheck",
"tests" "tests"
], ],
"support": {
"issues": "https://github.com/dealerdirect/phpcodesniffer-composer-installer/issues",
"source": "https://github.com/dealerdirect/phpcodesniffer-composer-installer"
},
"time": "2020-12-07T18:04:37+00:00" "time": "2020-12-07T18:04:37+00:00"
}, },
{ {
@ -133,10 +129,6 @@
"phpcs", "phpcs",
"standards" "standards"
], ],
"support": {
"issues": "https://github.com/PHPCompatibility/PHPCompatibility/issues",
"source": "https://github.com/PHPCompatibility/PHPCompatibility"
},
"time": "2019-12-27T09:44:58+00:00" "time": "2019-12-27T09:44:58+00:00"
}, },
{ {
@ -189,10 +181,6 @@
"polyfill", "polyfill",
"standards" "standards"
], ],
"support": {
"issues": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie/issues",
"source": "https://github.com/PHPCompatibility/PHPCompatibilityParagonie"
},
"time": "2021-02-15T10:24:51+00:00" "time": "2021-02-15T10:24:51+00:00"
}, },
{ {
@ -243,10 +231,6 @@
"standards", "standards",
"wordpress" "wordpress"
], ],
"support": {
"issues": "https://github.com/PHPCompatibility/PHPCompatibilityWP/issues",
"source": "https://github.com/PHPCompatibility/PHPCompatibilityWP"
},
"time": "2021-07-21T11:09:57+00:00" "time": "2021-07-21T11:09:57+00:00"
}, },
{ {
@ -298,11 +282,6 @@
"phpcs", "phpcs",
"standards" "standards"
], ],
"support": {
"issues": "https://github.com/squizlabs/PHP_CodeSniffer/issues",
"source": "https://github.com/squizlabs/PHP_CodeSniffer",
"wiki": "https://github.com/squizlabs/PHP_CodeSniffer/wiki"
},
"time": "2021-10-11T04:00:11+00:00" "time": "2021-10-11T04:00:11+00:00"
}, },
{ {
@ -343,10 +322,6 @@
"woocommerce", "woocommerce",
"wordpress" "wordpress"
], ],
"support": {
"issues": "https://github.com/woocommerce/woocommerce-sniffs/issues",
"source": "https://github.com/woocommerce/woocommerce-sniffs/tree/0.1.1"
},
"time": "2021-07-29T17:25:16+00:00" "time": "2021-07-29T17:25:16+00:00"
}, },
{ {
@ -393,11 +368,6 @@
"standards", "standards",
"wordpress" "wordpress"
], ],
"support": {
"issues": "https://github.com/WordPress/WordPress-Coding-Standards/issues",
"source": "https://github.com/WordPress/WordPress-Coding-Standards",
"wiki": "https://github.com/WordPress/WordPress-Coding-Standards/wiki"
},
"time": "2020-05-13T23:57:56+00:00" "time": "2020-05-13T23:57:56+00:00"
} }
], ],
@ -411,5 +381,5 @@
"platform-overrides": { "platform-overrides": {
"php": "7.0" "php": "7.0"
}, },
"plugin-api-version": "2.1.0" "plugin-api-version": "1.1.0"
} }

View File

@ -59,10 +59,6 @@
"constructor", "constructor",
"instantiate" "instantiate"
], ],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/master"
},
"time": "2015-06-14T21:17:01+00:00" "time": "2015-06-14T21:17:01+00:00"
}, },
{ {
@ -108,10 +104,6 @@
"object", "object",
"object graph" "object graph"
], ],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
},
"time": "2017-10-19T19:58:43+00:00" "time": "2017-10-19T19:58:43+00:00"
}, },
{ {
@ -167,10 +159,6 @@
} }
], ],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": {
"issues": "https://github.com/phar-io/manifest/issues",
"source": "https://github.com/phar-io/manifest/tree/master"
},
"time": "2017-03-05T18:14:27+00:00" "time": "2017-03-05T18:14:27+00:00"
}, },
{ {
@ -218,10 +206,6 @@
} }
], ],
"description": "Library for handling version information and constraints", "description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/master"
},
"time": "2017-03-05T17:38:23+00:00" "time": "2017-03-05T17:38:23+00:00"
}, },
{ {
@ -276,10 +260,6 @@
"reflection", "reflection",
"static analysis" "static analysis"
], ],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
},
"time": "2017-09-11T18:02:19+00:00" "time": "2017-09-11T18:02:19+00:00"
}, },
{ {
@ -332,10 +312,6 @@
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x"
},
"time": "2019-12-28T18:55:12+00:00" "time": "2019-12-28T18:55:12+00:00"
}, },
{ {
@ -381,10 +357,6 @@
"email": "me@mikevanriel.com" "email": "me@mikevanriel.com"
} }
], ],
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/master"
},
"time": "2017-12-30T13:23:38+00:00" "time": "2017-12-30T13:23:38+00:00"
}, },
{ {
@ -448,10 +420,6 @@
"spy", "spy",
"stub" "stub"
], ],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
},
"time": "2020-03-05T15:02:03+00:00" "time": "2020-03-05T15:02:03+00:00"
}, },
{ {
@ -515,10 +483,6 @@
"testing", "testing",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3"
},
"time": "2018-04-06T15:36:58+00:00" "time": "2018-04-06T15:36:58+00:00"
}, },
{ {
@ -566,11 +530,6 @@
"filesystem", "filesystem",
"iterator" "iterator"
], ],
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
},
"time": "2017-11-27T13:52:08+00:00" "time": "2017-11-27T13:52:08+00:00"
}, },
{ {
@ -612,10 +571,6 @@
"keywords": [ "keywords": [
"template" "template"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
},
"time": "2015-06-21T13:50:34+00:00" "time": "2015-06-21T13:50:34+00:00"
}, },
{ {
@ -665,10 +620,6 @@
"keywords": [ "keywords": [
"timer" "timer"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
},
"time": "2017-02-26T11:10:40+00:00" "time": "2017-02-26T11:10:40+00:00"
}, },
{ {
@ -718,10 +669,6 @@
"keywords": [ "keywords": [
"tokenizer" "tokenizer"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
},
"abandoned": true, "abandoned": true,
"time": "2017-11-27T05:48:46+00:00" "time": "2017-11-27T05:48:46+00:00"
}, },
@ -807,10 +754,6 @@
"testing", "testing",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14"
},
"time": "2019-02-01T05:22:47+00:00" "time": "2019-02-01T05:22:47+00:00"
}, },
{ {
@ -870,10 +813,6 @@
"mock", "mock",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
"source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10"
},
"abandoned": true, "abandoned": true,
"time": "2018-08-09T05:50:03+00:00" "time": "2018-08-09T05:50:03+00:00"
}, },
@ -920,10 +859,6 @@
], ],
"description": "Looks up which function or method a line of code belongs to", "description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -994,10 +929,6 @@
"compare", "compare",
"equality" "equality"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/master"
},
"time": "2018-02-01T13:46:46+00:00" "time": "2018-02-01T13:46:46+00:00"
}, },
{ {
@ -1050,10 +981,6 @@
"keywords": [ "keywords": [
"diff" "diff"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/master"
},
"time": "2017-08-03T08:09:46+00:00" "time": "2017-08-03T08:09:46+00:00"
}, },
{ {
@ -1104,10 +1031,6 @@
"environment", "environment",
"hhvm" "hhvm"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/master"
},
"time": "2017-07-01T08:51:00+00:00" "time": "2017-07-01T08:51:00+00:00"
}, },
{ {
@ -1175,10 +1098,6 @@
"export", "export",
"exporter" "exporter"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -1236,10 +1155,6 @@
"keywords": [ "keywords": [
"global state" "global state"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
},
"time": "2017-04-27T15:39:26+00:00" "time": "2017-04-27T15:39:26+00:00"
}, },
{ {
@ -1287,10 +1202,6 @@
], ],
"description": "Traverses array structures and object graphs to enumerate all referenced objects", "description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/", "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -1342,10 +1253,6 @@
], ],
"description": "Allows reflection of object attributes, including inherited and non-public ones", "description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/", "homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
"source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -1405,10 +1312,6 @@
], ],
"description": "Provides functionality to recursively process PHP variables", "description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context", "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -1457,10 +1360,6 @@
], ],
"description": "Provides a list of PHP built-in functions that operate on resources", "description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations", "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
"source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
},
"time": "2015-07-28T20:34:47+00:00" "time": "2015-07-28T20:34:47+00:00"
}, },
{ {
@ -1504,10 +1403,6 @@
], ],
"description": "Library that helps with managing the version number of Git-hosted PHP projects", "description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
"source": "https://github.com/sebastianbergmann/version/tree/master"
},
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03T07:35:21+00:00"
}, },
{ {
@ -1570,9 +1465,6 @@
"polyfill", "polyfill",
"portable" "portable"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -1627,10 +1519,6 @@
} }
], ],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/master"
},
"time": "2019-06-13T22:48:21+00:00" "time": "2019-06-13T22:48:21+00:00"
}, },
{ {
@ -1680,10 +1568,6 @@
"check", "check",
"validate" "validate"
], ],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
},
"time": "2020-07-08T17:02:28+00:00" "time": "2020-07-08T17:02:28+00:00"
} }
], ],
@ -1697,5 +1581,5 @@
"platform-overrides": { "platform-overrides": {
"php": "7.0" "php": "7.0"
}, },
"plugin-api-version": "2.1.0" "plugin-api-version": "1.1.0"
} }

View File

@ -67,11 +67,6 @@
"po", "po",
"translation" "translation"
], ],
"support": {
"email": "oom@oscarotero.com",
"issues": "https://github.com/oscarotero/Gettext/issues",
"source": "https://github.com/php-gettext/Gettext/tree/v4.8.6"
},
"funding": [ "funding": [
{ {
"url": "https://paypal.me/oscarotero", "url": "https://paypal.me/oscarotero",
@ -146,10 +141,6 @@
"translations", "translations",
"unicode" "unicode"
], ],
"support": {
"issues": "https://github.com/php-gettext/Languages/issues",
"source": "https://github.com/php-gettext/Languages/tree/2.9.0"
},
"funding": [ "funding": [
{ {
"url": "https://paypal.me/mlocati", "url": "https://paypal.me/mlocati",
@ -205,10 +196,6 @@
} }
], ],
"description": "Peast is PHP library that generates AST for JavaScript code", "description": "Peast is PHP library that generates AST for JavaScript code",
"support": {
"issues": "https://github.com/mck89/peast/issues",
"source": "https://github.com/mck89/peast/tree/v1.13.9"
},
"time": "2021-11-12T13:44:49+00:00" "time": "2021-11-12T13:44:49+00:00"
}, },
{ {
@ -255,10 +242,6 @@
"mustache", "mustache",
"templating" "templating"
], ],
"support": {
"issues": "https://github.com/bobthecow/mustache.php/issues",
"source": "https://github.com/bobthecow/mustache.php/tree/master"
},
"time": "2019-11-23T21:40:31+00:00" "time": "2019-11-23T21:40:31+00:00"
}, },
{ {
@ -315,10 +298,6 @@
"iri", "iri",
"sockets" "sockets"
], ],
"support": {
"issues": "https://github.com/WordPress/Requests/issues",
"source": "https://github.com/WordPress/Requests/tree/v1.8.1"
},
"time": "2021-06-04T09:56:25+00:00" "time": "2021-06-04T09:56:25+00:00"
}, },
{ {
@ -368,9 +347,6 @@
], ],
"description": "Symfony Finder Component", "description": "Symfony Finder Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/finder/tree/3.3"
},
"time": "2017-06-01T21:01:25+00:00" "time": "2017-06-01T21:01:25+00:00"
}, },
{ {
@ -431,10 +407,6 @@
], ],
"description": "Provides internationalization tools for WordPress projects.", "description": "Provides internationalization tools for WordPress projects.",
"homepage": "https://github.com/wp-cli/i18n-command", "homepage": "https://github.com/wp-cli/i18n-command",
"support": {
"issues": "https://github.com/wp-cli/i18n-command/issues",
"source": "https://github.com/wp-cli/i18n-command/tree/v2.2.9"
},
"time": "2021-07-20T21:25:54+00:00" "time": "2021-07-20T21:25:54+00:00"
}, },
{ {
@ -483,9 +455,6 @@
], ],
"description": "A simple YAML loader/dumper class for PHP (WP-CLI fork)", "description": "A simple YAML loader/dumper class for PHP (WP-CLI fork)",
"homepage": "https://github.com/mustangostang/spyc/", "homepage": "https://github.com/mustangostang/spyc/",
"support": {
"source": "https://github.com/wp-cli/spyc/tree/autoload"
},
"time": "2017-04-25T11:26:20+00:00" "time": "2017-04-25T11:26:20+00:00"
}, },
{ {
@ -536,10 +505,6 @@
"cli", "cli",
"console" "console"
], ],
"support": {
"issues": "https://github.com/wp-cli/php-cli-tools/issues",
"source": "https://github.com/wp-cli/php-cli-tools/tree/v0.11.13"
},
"time": "2021-07-01T15:08:16+00:00" "time": "2021-07-01T15:08:16+00:00"
}, },
{ {
@ -606,11 +571,6 @@
"cli", "cli",
"wordpress" "wordpress"
], ],
"support": {
"docs": "https://make.wordpress.org/cli/handbook/",
"issues": "https://github.com/wp-cli/wp-cli/issues",
"source": "https://github.com/wp-cli/wp-cli"
},
"time": "2021-05-14T13:44:51+00:00" "time": "2021-05-14T13:44:51+00:00"
} }
], ],
@ -624,5 +584,5 @@
"platform-overrides": { "platform-overrides": {
"php": "7.0" "php": "7.0"
}, },
"plugin-api-version": "2.1.0" "plugin-api-version": "1.1.0"
} }

View File

@ -20,9 +20,9 @@
"maxmind-db/reader": "1.6.0", "maxmind-db/reader": "1.6.0",
"pelago/emogrifier": "3.1.0", "pelago/emogrifier": "3.1.0",
"psr/container": "1.0.0", "psr/container": "1.0.0",
"woocommerce/action-scheduler": "3.3.0", "woocommerce/action-scheduler": "3.4.0",
"woocommerce/woocommerce-admin": "2.8.0", "woocommerce/woocommerce-admin": "2.9.0",
"woocommerce/woocommerce-blocks": "6.1.0" "woocommerce/woocommerce-blocks": "6.3.3"
}, },
"require-dev": { "require-dev": {
"bamarni/composer-bin-plugin": "^1.4", "bamarni/composer-bin-plugin": "^1.4",
@ -122,15 +122,15 @@
"formatter": { "formatter": {
"filename": "../../tools/changelogger/PluginFormatter.php" "filename": "../../tools/changelogger/PluginFormatter.php"
}, },
"types": [ "types": {
"Fix", "fix": "Fixes an existing bug",
"Add", "add": "Adds functionality",
"Update", "update": "Update existing functionality",
"Dev", "dev": "Development related task",
"Tweak", "tweak": "A minor adjustment to the codebase",
"Performance", "performance": "Address performance issues",
"Enhancement" "enhancement": "Improve existing functionality"
], },
"versioning": "wordpress", "versioning": "wordpress",
"changelog": "NEXT_CHANGELOG.md" "changelog": "NEXT_CHANGELOG.md"
} }

View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies", "Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically" "This file is @generated automatically"
], ],
"content-hash": "f6fc527d8719df0b0247ee188eb3eee9", "content-hash": "ec7987721f51ed5c0faf6251128ba110",
"packages": [ "packages": [
{ {
"name": "automattic/jetpack-autoloader", "name": "automattic/jetpack-autoloader",
@ -51,9 +51,6 @@
"GPL-2.0-or-later" "GPL-2.0-or-later"
], ],
"description": "Creates a custom autoloader for a plugin or theme.", "description": "Creates a custom autoloader for a plugin or theme.",
"support": {
"source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1"
},
"time": "2021-03-30T15:15:59+00:00" "time": "2021-03-30T15:15:59+00:00"
}, },
{ {
@ -85,9 +82,6 @@
"GPL-2.0-or-later" "GPL-2.0-or-later"
], ],
"description": "A wrapper for defining constants in a more testable way.", "description": "A wrapper for defining constants in a more testable way.",
"support": {
"source": "https://github.com/Automattic/jetpack-constants/tree/v1.5.1"
},
"time": "2020-10-28T19:00:31+00:00" "time": "2020-10-28T19:00:31+00:00"
}, },
{ {
@ -221,10 +215,6 @@
"zend", "zend",
"zikula" "zikula"
], ],
"support": {
"issues": "https://github.com/composer/installers/issues",
"source": "https://github.com/composer/installers/tree/v1.12.0"
},
"funding": [ "funding": [
{ {
"url": "https://packagist.com", "url": "https://packagist.com",
@ -299,10 +289,6 @@
"geolocation", "geolocation",
"maxmind" "maxmind"
], ],
"support": {
"issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
"source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.6.0"
},
"time": "2019-12-19T22:59:03+00:00" "time": "2019-12-19T22:59:03+00:00"
}, },
{ {
@ -377,10 +363,6 @@
"email", "email",
"pre-processing" "pre-processing"
], ],
"support": {
"issues": "https://github.com/MyIntervals/emogrifier/issues",
"source": "https://github.com/MyIntervals/emogrifier"
},
"time": "2019-12-26T19:37:31+00:00" "time": "2019-12-26T19:37:31+00:00"
}, },
{ {
@ -430,10 +412,6 @@
"container-interop", "container-interop",
"psr" "psr"
], ],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/master"
},
"time": "2017-02-14T16:28:37+00:00" "time": "2017-02-14T16:28:37+00:00"
}, },
{ {
@ -482,9 +460,6 @@
], ],
"description": "Symfony CssSelector Component", "description": "Symfony CssSelector Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v3.4.47"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -503,22 +478,23 @@
}, },
{ {
"name": "woocommerce/action-scheduler", "name": "woocommerce/action-scheduler",
"version": "3.3.0", "version": "3.4.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/woocommerce/action-scheduler.git", "url": "https://github.com/woocommerce/action-scheduler.git",
"reference": "5588a831cd2453ecf7d4803f3a81063e13cde93d" "reference": "3218a33ff14b968f8cb05de9656c2efa1eeb1330"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/5588a831cd2453ecf7d4803f3a81063e13cde93d", "url": "https://api.github.com/repos/woocommerce/action-scheduler/zipball/3218a33ff14b968f8cb05de9656c2efa1eeb1330",
"reference": "5588a831cd2453ecf7d4803f3a81063e13cde93d", "reference": "3218a33ff14b968f8cb05de9656c2efa1eeb1330",
"shasum": "" "shasum": ""
}, },
"require-dev": { "require-dev": {
"phpunit/phpunit": "^7.5", "phpunit/phpunit": "^7.5",
"woocommerce/woocommerce-sniffs": "0.1.0", "woocommerce/woocommerce-sniffs": "0.1.0",
"wp-cli/wp-cli": "~2.5.0" "wp-cli/wp-cli": "~2.5.0",
"yoast/phpunit-polyfills": "^1.0"
}, },
"type": "wordpress-plugin", "type": "wordpress-plugin",
"extra": { "extra": {
@ -534,24 +510,20 @@
], ],
"description": "Action Scheduler for WordPress and WooCommerce", "description": "Action Scheduler for WordPress and WooCommerce",
"homepage": "https://actionscheduler.org/", "homepage": "https://actionscheduler.org/",
"support": { "time": "2021-10-28T17:09:12+00:00"
"issues": "https://github.com/woocommerce/action-scheduler/issues",
"source": "https://github.com/woocommerce/action-scheduler/tree/3.3.0"
},
"time": "2021-09-15T21:08:48+00:00"
}, },
{ {
"name": "woocommerce/woocommerce-admin", "name": "woocommerce/woocommerce-admin",
"version": "2.8.0", "version": "2.9.0",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git", "url": "https://github.com/woocommerce/woocommerce-admin.git",
"reference": "63b93a95db4bf788f42587a41f2378128a2adfdf" "reference": "8040a6ac2af1b217324ae83a4137b0bfe3edbc23"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/63b93a95db4bf788f42587a41f2378128a2adfdf", "url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/8040a6ac2af1b217324ae83a4137b0bfe3edbc23",
"reference": "63b93a95db4bf788f42587a41f2378128a2adfdf", "reference": "8040a6ac2af1b217324ae83a4137b0bfe3edbc23",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -605,24 +577,20 @@
], ],
"description": "A modern, javascript-driven WooCommerce Admin experience.", "description": "A modern, javascript-driven WooCommerce Admin experience.",
"homepage": "https://github.com/woocommerce/woocommerce-admin", "homepage": "https://github.com/woocommerce/woocommerce-admin",
"support": { "time": "2021-11-29T23:28:44+00:00"
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.8.0"
},
"time": "2021-11-02T19:28:38+00:00"
}, },
{ {
"name": "woocommerce/woocommerce-blocks", "name": "woocommerce/woocommerce-blocks",
"version": "v6.1.0", "version": "v6.3.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git", "url": "https://github.com/woocommerce/woocommerce-gutenberg-products-block.git",
"reference": "8556efd69e85c01f5571d39e6581d9b8486b682f" "reference": "38975ad6de9c6a556059c4de6e9ffc586ab82245"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/8556efd69e85c01f5571d39e6581d9b8486b682f", "url": "https://api.github.com/repos/woocommerce/woocommerce-gutenberg-products-block/zipball/38975ad6de9c6a556059c4de6e9ffc586ab82245",
"reference": "8556efd69e85c01f5571d39e6581d9b8486b682f", "reference": "38975ad6de9c6a556059c4de6e9ffc586ab82245",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -630,6 +598,8 @@
"composer/installers": "^1.7.0" "composer/installers": "^1.7.0"
}, },
"require-dev": { "require-dev": {
"johnbillion/wp-hooks-generator": "0.6.1",
"mockery/mockery": "^1.4",
"woocommerce/woocommerce-sniffs": "0.1.0", "woocommerce/woocommerce-sniffs": "0.1.0",
"wp-phpunit/wp-phpunit": "^5.4", "wp-phpunit/wp-phpunit": "^5.4",
"yoast/phpunit-polyfills": "^1.0" "yoast/phpunit-polyfills": "^1.0"
@ -659,9 +629,9 @@
], ],
"support": { "support": {
"issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues", "issues": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/issues",
"source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v6.1.0" "source": "https://github.com/woocommerce/woocommerce-gutenberg-products-block/tree/v6.3.3"
}, },
"time": "2021-10-12T13:07:11+00:00" "time": "2021-11-25T09:47:27+00:00"
} }
], ],
"packages-dev": [ "packages-dev": [
@ -717,9 +687,6 @@
"GPL-2.0-or-later" "GPL-2.0-or-later"
], ],
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.", "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.0.2"
},
"time": "2021-11-02T14:06:49+00:00" "time": "2021-11-02T14:06:49+00:00"
}, },
{ {
@ -766,10 +733,6 @@
"isolation", "isolation",
"tool" "tool"
], ],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
"source": "https://github.com/bamarni/composer-bin-plugin/tree/master"
},
"time": "2020-05-03T08:27:20+00:00" "time": "2020-05-03T08:27:20+00:00"
}, },
{ {
@ -824,10 +787,6 @@
"constructor", "constructor",
"instantiate" "instantiate"
], ],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/master"
},
"time": "2015-06-14T21:17:01+00:00" "time": "2015-06-14T21:17:01+00:00"
}, },
{ {
@ -873,10 +832,6 @@
"object", "object",
"object graph" "object graph"
], ],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
},
"time": "2017-10-19T19:58:43+00:00" "time": "2017-10-19T19:58:43+00:00"
}, },
{ {
@ -932,10 +887,6 @@
} }
], ],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)", "description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": {
"issues": "https://github.com/phar-io/manifest/issues",
"source": "https://github.com/phar-io/manifest/tree/master"
},
"time": "2017-03-05T18:14:27+00:00" "time": "2017-03-05T18:14:27+00:00"
}, },
{ {
@ -983,10 +934,6 @@
} }
], ],
"description": "Library for handling version information and constraints", "description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/master"
},
"time": "2017-03-05T17:38:23+00:00" "time": "2017-03-05T17:38:23+00:00"
}, },
{ {
@ -1041,10 +988,6 @@
"reflection", "reflection",
"static analysis" "static analysis"
], ],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
},
"time": "2017-09-11T18:02:19+00:00" "time": "2017-09-11T18:02:19+00:00"
}, },
{ {
@ -1097,10 +1040,6 @@
} }
], ],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.", "description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x"
},
"time": "2019-12-28T18:55:12+00:00" "time": "2019-12-28T18:55:12+00:00"
}, },
{ {
@ -1146,10 +1085,6 @@
"email": "me@mikevanriel.com" "email": "me@mikevanriel.com"
} }
], ],
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/master"
},
"time": "2017-12-30T13:23:38+00:00" "time": "2017-12-30T13:23:38+00:00"
}, },
{ {
@ -1213,10 +1148,6 @@
"spy", "spy",
"stub" "stub"
], ],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
},
"time": "2020-03-05T15:02:03+00:00" "time": "2020-03-05T15:02:03+00:00"
}, },
{ {
@ -1280,10 +1211,6 @@
"testing", "testing",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3"
},
"time": "2018-04-06T15:36:58+00:00" "time": "2018-04-06T15:36:58+00:00"
}, },
{ {
@ -1331,11 +1258,6 @@
"filesystem", "filesystem",
"iterator" "iterator"
], ],
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
},
"time": "2017-11-27T13:52:08+00:00" "time": "2017-11-27T13:52:08+00:00"
}, },
{ {
@ -1377,10 +1299,6 @@
"keywords": [ "keywords": [
"template" "template"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
},
"time": "2015-06-21T13:50:34+00:00" "time": "2015-06-21T13:50:34+00:00"
}, },
{ {
@ -1430,10 +1348,6 @@
"keywords": [ "keywords": [
"timer" "timer"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
},
"time": "2017-02-26T11:10:40+00:00" "time": "2017-02-26T11:10:40+00:00"
}, },
{ {
@ -1483,10 +1397,6 @@
"keywords": [ "keywords": [
"tokenizer" "tokenizer"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
},
"abandoned": true, "abandoned": true,
"time": "2017-11-27T05:48:46+00:00" "time": "2017-11-27T05:48:46+00:00"
}, },
@ -1572,10 +1482,6 @@
"testing", "testing",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14"
},
"time": "2019-02-01T05:22:47+00:00" "time": "2019-02-01T05:22:47+00:00"
}, },
{ {
@ -1635,10 +1541,6 @@
"mock", "mock",
"xunit" "xunit"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
"source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10"
},
"abandoned": true, "abandoned": true,
"time": "2018-08-09T05:50:03+00:00" "time": "2018-08-09T05:50:03+00:00"
}, },
@ -1687,9 +1589,6 @@
"psr", "psr",
"psr-3" "psr-3"
], ],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00" "time": "2021-05-03T11:20:27+00:00"
}, },
{ {
@ -1735,10 +1634,6 @@
], ],
"description": "Looks up which function or method a line of code belongs to", "description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/", "homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -1809,10 +1704,6 @@
"compare", "compare",
"equality" "equality"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/master"
},
"time": "2018-02-01T13:46:46+00:00" "time": "2018-02-01T13:46:46+00:00"
}, },
{ {
@ -1865,10 +1756,6 @@
"keywords": [ "keywords": [
"diff" "diff"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/master"
},
"time": "2017-08-03T08:09:46+00:00" "time": "2017-08-03T08:09:46+00:00"
}, },
{ {
@ -1919,10 +1806,6 @@
"environment", "environment",
"hhvm" "hhvm"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/master"
},
"time": "2017-07-01T08:51:00+00:00" "time": "2017-07-01T08:51:00+00:00"
}, },
{ {
@ -1990,10 +1873,6 @@
"export", "export",
"exporter" "exporter"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -2051,10 +1930,6 @@
"keywords": [ "keywords": [
"global state" "global state"
], ],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
},
"time": "2017-04-27T15:39:26+00:00" "time": "2017-04-27T15:39:26+00:00"
}, },
{ {
@ -2102,10 +1977,6 @@
], ],
"description": "Traverses array structures and object graphs to enumerate all referenced objects", "description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/", "homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -2157,10 +2028,6 @@
], ],
"description": "Allows reflection of object attributes, including inherited and non-public ones", "description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/", "homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
"source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -2220,10 +2087,6 @@
], ],
"description": "Provides functionality to recursively process PHP variables", "description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context", "homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
},
"funding": [ "funding": [
{ {
"url": "https://github.com/sebastianbergmann", "url": "https://github.com/sebastianbergmann",
@ -2272,10 +2135,6 @@
], ],
"description": "Provides a list of PHP built-in functions that operate on resources", "description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations", "homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
"source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
},
"time": "2015-07-28T20:34:47+00:00" "time": "2015-07-28T20:34:47+00:00"
}, },
{ {
@ -2319,10 +2178,6 @@
], ],
"description": "Library that helps with managing the version number of Git-hosted PHP projects", "description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version", "homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
"source": "https://github.com/sebastianbergmann/version/tree/master"
},
"time": "2016-10-03T07:35:21+00:00" "time": "2016-10-03T07:35:21+00:00"
}, },
{ {
@ -2390,9 +2245,6 @@
], ],
"description": "Symfony Console Component", "description": "Symfony Console Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/v3.4.47"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -2458,9 +2310,6 @@
], ],
"description": "Symfony Debug Component", "description": "Symfony Debug Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v3.4.47"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -2537,9 +2386,6 @@
"polyfill", "polyfill",
"portable" "portable"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -2617,9 +2463,6 @@
"portable", "portable",
"shim" "shim"
], ],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.19.0"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -2678,9 +2521,6 @@
], ],
"description": "Symfony Process Component", "description": "Symfony Process Component",
"homepage": "https://symfony.com", "homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v3.4.47"
},
"funding": [ "funding": [
{ {
"url": "https://symfony.com/sponsor", "url": "https://symfony.com/sponsor",
@ -2735,10 +2575,6 @@
} }
], ],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats", "description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/master"
},
"time": "2019-06-13T22:48:21+00:00" "time": "2019-06-13T22:48:21+00:00"
}, },
{ {
@ -2788,10 +2624,6 @@
"check", "check",
"validate" "validate"
], ],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
},
"time": "2020-07-08T17:02:28+00:00" "time": "2020-07-08T17:02:28+00:00"
}, },
{ {
@ -2844,23 +2676,20 @@
], ],
"description": "Safe replacement to @ for suppressing warnings.", "description": "Safe replacement to @ for suppressing warnings.",
"homepage": "https://www.mediawiki.org/wiki/at-ease", "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" "time": "2018-10-10T15:39:06+00:00"
}, },
{ {
"name": "yoast/phpunit-polyfills", "name": "yoast/phpunit-polyfills",
"version": "1.0.2", "version": "1.0.3",
"source": { "source": {
"type": "git", "type": "git",
"url": "https://github.com/Yoast/PHPUnit-Polyfills.git", "url": "https://github.com/Yoast/PHPUnit-Polyfills.git",
"reference": "1a582ab1d91e86aa450340c4d35631a85314ff9f" "reference": "5ea3536428944955f969bc764bbe09738e151ada"
}, },
"dist": { "dist": {
"type": "zip", "type": "zip",
"url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/1a582ab1d91e86aa450340c4d35631a85314ff9f", "url": "https://api.github.com/repos/Yoast/PHPUnit-Polyfills/zipball/5ea3536428944955f969bc764bbe09738e151ada",
"reference": "1a582ab1d91e86aa450340c4d35631a85314ff9f", "reference": "5ea3536428944955f969bc764bbe09738e151ada",
"shasum": "" "shasum": ""
}, },
"require": { "require": {
@ -2904,11 +2733,7 @@
"polyfill", "polyfill",
"testing" "testing"
], ],
"support": { "time": "2021-11-23T01:37:03+00:00"
"issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues",
"source": "https://github.com/Yoast/PHPUnit-Polyfills"
},
"time": "2021-10-03T08:40:26+00:00"
} }
], ],
"aliases": [], "aliases": [],

View File

@ -15,6 +15,20 @@ defined( 'ABSPATH' ) || exit;
return array( return array(
'AF' => array(), 'AF' => array(),
'AL' => array( // Albania states.
'AL-01' => __( 'Berat', 'woocommerce' ),
'AL-09' => __( 'Dibër', 'woocommerce' ),
'AL-02' => __( 'Durrës', 'woocommerce' ),
'AL-03' => __( 'Elbasan', 'woocommerce' ),
'AL-04' => __( 'Fier', 'woocommerce' ),
'AL-05' => __( 'Gjirokastër', 'woocommerce' ),
'AL-06' => __( 'Korçë', 'woocommerce' ),
'AL-07' => __( 'Kukës', 'woocommerce' ),
'AL-08' => __( 'Lezhë', 'woocommerce' ),
'AL-10' => __( 'Shkodër', 'woocommerce' ),
'AL-11' => __( 'Tirana', 'woocommerce' ),
'AL-12' => __( 'Vlorë', 'woocommerce' ),
),
'AO' => array( // Angola states. 'AO' => array( // Angola states.
'BGO' => __( 'Bengo', 'woocommerce' ), 'BGO' => __( 'Bengo', 'woocommerce' ),
'BLU' => __( 'Benguela', 'woocommerce' ), 'BLU' => __( 'Benguela', 'woocommerce' ),
@ -187,15 +201,15 @@ return array(
'ZO' => __( 'Zou', 'woocommerce' ), 'ZO' => __( 'Zou', 'woocommerce' ),
), ),
'BO' => array( // Bolivian states. 'BO' => array( // Bolivian states.
'B' => __( 'Chuquisaca', 'woocommerce' ), 'BO-B' => __( 'Beni', 'woocommerce' ),
'H' => __( 'Beni', 'woocommerce' ), 'BO-H' => __( 'Chuquisaca', 'woocommerce' ),
'C' => __( 'Cochabamba', 'woocommerce' ), 'BO-C' => __( 'Cochabamba', 'woocommerce' ),
'L' => __( 'La Paz', 'woocommerce' ), 'BO-L' => __( 'La Paz', 'woocommerce' ),
'O' => __( 'Oruro', 'woocommerce' ), 'BO-O' => __( 'Oruro', 'woocommerce' ),
'N' => __( 'Pando', 'woocommerce' ), 'BO-N' => __( 'Pando', 'woocommerce' ),
'P' => __( 'Potosí', 'woocommerce' ), 'BO-P' => __( 'Potosí', 'woocommerce' ),
'S' => __( 'Santa Cruz', 'woocommerce' ), 'BO-S' => __( 'Santa Cruz', 'woocommerce' ),
'T' => __( 'Tarija', 'woocommerce' ), 'BO-T' => __( 'Tarija', 'woocommerce' ),
), ),
'BR' => array( // Brazillian states. 'BR' => array( // Brazillian states.
'AC' => __( 'Acre', 'woocommerce' ), 'AC' => __( 'Acre', 'woocommerce' ),
@ -321,6 +335,50 @@ return array(
'CN31' => __( 'Tibet / 西藏', 'woocommerce' ), 'CN31' => __( 'Tibet / 西藏', 'woocommerce' ),
'CN32' => __( 'Xinjiang / 新疆', 'woocommerce' ), 'CN32' => __( 'Xinjiang / 新疆', 'woocommerce' ),
), ),
'CO' => array( // Colombia States.
'CO-AMA' => __( 'Amazonas', 'woocommerce' ),
'CO-ANT' => __( 'Antioquia', 'woocommerce' ),
'CO-ARA' => __( 'Arauca', 'woocommerce' ),
'CO-ATL' => __( 'Atlántico', 'woocommerce' ),
'CO-BOL' => __( 'Bolívar', 'woocommerce' ),
'CO-BOY' => __( 'Boyacá', 'woocommerce' ),
'CO-CAL' => __( 'Caldas', 'woocommerce' ),
'CO-CAQ' => __( 'Caquetá', 'woocommerce' ),
'CO-CAS' => __( 'Casanare', 'woocommerce' ),
'CO-CAU' => __( 'Cauca', 'woocommerce' ),
'CO-CES' => __( 'Cesar', 'woocommerce' ),
'CO-CHO' => __( 'Chocó', 'woocommerce' ),
'CO-COR' => __( 'Córdoba', 'woocommerce' ),
'CO-CUN' => __( 'Cundinamarca', 'woocommerce' ),
'CO-DC' => __( 'Capital District', 'woocommerce' ),
'CO-GUA' => __( 'Guainía', 'woocommerce' ),
'CO-GUV' => __( 'Guaviare', 'woocommerce' ),
'CO-HUI' => __( 'Huila', 'woocommerce' ),
'CO-LAG' => __( 'La Guajira', 'woocommerce' ),
'CO-MAG' => __( 'Magdalena', 'woocommerce' ),
'CO-MET' => __( 'Meta', 'woocommerce' ),
'CO-NAR' => __( 'Nariño', 'woocommerce' ),
'CO-NSA' => __( 'Norte de Santander', 'woocommerce' ),
'CO-PUT' => __( 'Putumayo', 'woocommerce' ),
'CO-QUI' => __( 'Quindío', 'woocommerce' ),
'CO-RIS' => __( 'Risaralda', 'woocommerce' ),
'CO-SAN' => __( 'Santander', 'woocommerce' ),
'CO-SAP' => __( 'San Andrés & Providencia', 'woocommerce' ),
'CO-SUC' => __( 'Sucre', 'woocommerce' ),
'CO-TOL' => __( 'Tolima', 'woocommerce' ),
'CO-VAC' => __( 'Valle del Cauca', 'woocommerce' ),
'CO-VAU' => __( 'Vaupés', 'woocommerce' ),
'CO-VID' => __( 'Vichada', 'woocommerce' ),
),
'CR' => array( // Costa Rica states.
'CR-A' => __( 'Alajuela', 'woocommerce' ),
'CR-C' => __( 'Cartago', 'woocommerce' ),
'CR-G' => __( 'Guanacaste', 'woocommerce' ),
'CR-H' => __( 'Heredia', 'woocommerce' ),
'CR-L' => __( 'Limón', 'woocommerce' ),
'CR-P' => __( 'Puntarenas', 'woocommerce' ),
'CR-SJ' => __( 'San José', 'woocommerce' ),
),
'CZ' => array(), 'CZ' => array(),
'DE' => array(), 'DE' => array(),
'DK' => array(), 'DK' => array(),
@ -329,34 +387,44 @@ return array(
'DO-02' => __( 'Azua', 'woocommerce' ), 'DO-02' => __( 'Azua', 'woocommerce' ),
'DO-03' => __( 'Baoruco', 'woocommerce' ), 'DO-03' => __( 'Baoruco', 'woocommerce' ),
'DO-04' => __( 'Barahona', 'woocommerce' ), 'DO-04' => __( 'Barahona', 'woocommerce' ),
'DO-33' => __( 'Cibao Nordeste', 'woocommerce' ),
'DO-34' => __( 'Cibao Noroeste', 'woocommerce' ),
'DO-35' => __( 'Cibao Norte', 'woocommerce' ),
'DO-36' => __( 'Cibao Sur', 'woocommerce' ),
'DO-05' => __( 'Dajabón', 'woocommerce' ), 'DO-05' => __( 'Dajabón', 'woocommerce' ),
'DO-06' => __( 'Duarte', 'woocommerce' ), 'DO-06' => __( 'Duarte', 'woocommerce' ),
'DO-07' => __( 'Elías Piña', 'woocommerce' ),
'DO-08' => __( 'El Seibo', 'woocommerce' ), 'DO-08' => __( 'El Seibo', 'woocommerce' ),
'DO-37' => __( 'El Valle', 'woocommerce' ),
'DO-07' => __( 'Elías Piña', 'woocommerce' ),
'DO-38' => __( 'Enriquillo', 'woocommerce' ),
'DO-09' => __( 'Espaillat', 'woocommerce' ), 'DO-09' => __( 'Espaillat', 'woocommerce' ),
'DO-30' => __( 'Hato Mayor', 'woocommerce' ),
'DO-19' => __( 'Hermanas Mirabal', 'woocommerce' ),
'DO-39' => __( 'Higüamo', 'woocommerce' ),
'DO-10' => __( 'Independencia', 'woocommerce' ), 'DO-10' => __( 'Independencia', 'woocommerce' ),
'DO-11' => __( 'La Altagracia', 'woocommerce' ), 'DO-11' => __( 'La Altagracia', 'woocommerce' ),
'DO-12' => __( 'La Romana', 'woocommerce' ), 'DO-12' => __( 'La Romana', 'woocommerce' ),
'DO-13' => __( 'La Vega', 'woocommerce' ), 'DO-13' => __( 'La Vega', 'woocommerce' ),
'DO-14' => __( 'María Trinidad Sánchez', 'woocommerce' ), 'DO-14' => __( 'María Trinidad Sánchez', 'woocommerce' ),
'DO-28' => __( 'Monseñor Nouel', 'woocommerce' ),
'DO-15' => __( 'Monte Cristi', 'woocommerce' ), 'DO-15' => __( 'Monte Cristi', 'woocommerce' ),
'DO-29' => __( 'Monte Plata', 'woocommerce' ),
'DO-40' => __( 'Ozama', 'woocommerce' ),
'DO-16' => __( 'Pedernales', 'woocommerce' ), 'DO-16' => __( 'Pedernales', 'woocommerce' ),
'DO-17' => __( 'Peravia', 'woocommerce' ), 'DO-17' => __( 'Peravia', 'woocommerce' ),
'DO-18' => __( 'Puerto Plata', 'woocommerce' ), 'DO-18' => __( 'Puerto Plata', 'woocommerce' ),
'DO-19' => __( 'Hermanas Mirabal', 'woocommerce' ),
'DO-20' => __( 'Samaná', 'woocommerce' ), 'DO-20' => __( 'Samaná', 'woocommerce' ),
'DO-21' => __( 'San Cristóbal', 'woocommerce' ), 'DO-21' => __( 'San Cristóbal', 'woocommerce' ),
'DO-31' => __( 'San José de Ocoa', 'woocommerce' ),
'DO-22' => __( 'San Juan', 'woocommerce' ), 'DO-22' => __( 'San Juan', 'woocommerce' ),
'DO-23' => __( 'San Pedro de Macorís', 'woocommerce' ), 'DO-23' => __( 'San Pedro de Macorís', 'woocommerce' ),
'DO-24' => __( 'Sánchez Ramírez', 'woocommerce' ), 'DO-24' => __( 'Sánchez Ramírez', 'woocommerce' ),
'DO-25' => __( 'Santiago', 'woocommerce' ), 'DO-25' => __( 'Santiago', 'woocommerce' ),
'DO-26' => __( 'Santiago Rodríguez', 'woocommerce' ), 'DO-26' => __( 'Santiago Rodríguez', 'woocommerce' ),
'DO-27' => __( 'Valverde', 'woocommerce' ),
'DO-28' => __( 'Monseñor Nouel', 'woocommerce' ),
'DO-29' => __( 'Monte Plata', 'woocommerce' ),
'DO-30' => __( 'Hato Mayor', 'woocommerce' ),
'DO-31' => __( 'San José de Ocoa', 'woocommerce' ),
'DO-32' => __( 'Santo Domingo', 'woocommerce' ), 'DO-32' => __( 'Santo Domingo', 'woocommerce' ),
'DO-41' => __( 'Valdesia', 'woocommerce' ),
'DO-27' => __( 'Valverde', 'woocommerce' ),
'DO-42' => __( 'Yuma', 'woocommerce' ),
), ),
'DZ' => array( 'DZ' => array(
'DZ-01' => __( 'Adrar', 'woocommerce' ), 'DZ-01' => __( 'Adrar', 'woocommerce' ),
@ -409,6 +477,32 @@ return array(
'DZ-48' => __( 'Relizane', 'woocommerce' ), 'DZ-48' => __( 'Relizane', 'woocommerce' ),
), ),
'EE' => array(), 'EE' => array(),
'EC' => array( // Ecuador states.
'EC-A' => __( 'Azuay', 'woocommerce' ),
'EC-B' => __( 'Bolívar', 'woocommerce' ),
'EC-F' => __( 'Cañar', 'woocommerce' ),
'EC-C' => __( 'Carchi', 'woocommerce' ),
'EC-H' => __( 'Chimborazo', 'woocommerce' ),
'EC-X' => __( 'Cotopaxi', 'woocommerce' ),
'EC-O' => __( 'El Oro', 'woocommerce' ),
'EC-E' => __( 'Esmeraldas', 'woocommerce' ),
'EC-W' => __( 'Galápagos', 'woocommerce' ),
'EC-G' => __( 'Guayas', 'woocommerce' ),
'EC-I' => __( 'Imbabura', 'woocommerce' ),
'EC-L' => __( 'Loja', 'woocommerce' ),
'EC-R' => __( 'Los Ríos', 'woocommerce' ),
'EC-M' => __( 'Manabí', 'woocommerce' ),
'EC-S' => __( 'Morona-Santiago', 'woocommerce' ),
'EC-N' => __( 'Napo', 'woocommerce' ),
'EC-D' => __( 'Orellana', 'woocommerce' ),
'EC-Y' => __( 'Pastaza', 'woocommerce' ),
'EC-P' => __( 'Pichincha', 'woocommerce' ),
'EC-SE' => __( 'Santa Elena', 'woocommerce' ),
'EC-SD' => __( 'Santo Domingo de los Tsáchilas', 'woocommerce' ),
'EC-U' => __( 'Sucumbíos', 'woocommerce' ),
'EC-T' => __( 'Tungurahua', 'woocommerce' ),
'EC-Z' => __( 'Zamora-Chinchipe', 'woocommerce' ),
),
'EG' => array( // Egypt states. 'EG' => array( // Egypt states.
'EGALX' => __( 'Alexandria', 'woocommerce' ), 'EGALX' => __( 'Alexandria', 'woocommerce' ),
'EGASN' => __( 'Aswan', 'woocommerce' ), 'EGASN' => __( 'Aswan', 'woocommerce' ),
@ -531,34 +625,54 @@ return array(
'M' => __( 'Crete', 'woocommerce' ), 'M' => __( 'Crete', 'woocommerce' ),
), ),
'GT' => array( // Guatemalan states. 'GT' => array( // Guatemalan states.
'AV' => __( 'Alta Verapaz', 'woocommerce' ), 'GT-AV' => __( 'Alta Verapaz', 'woocommerce' ),
'BV' => __( 'Baja Verapaz', 'woocommerce' ), 'GT-BV' => __( 'Baja Verapaz', 'woocommerce' ),
'CM' => __( 'Chimaltenango', 'woocommerce' ), 'GT-CM' => __( 'Chimaltenango', 'woocommerce' ),
'CQ' => __( 'Chiquimula', 'woocommerce' ), 'GT-CQ' => __( 'Chiquimula', 'woocommerce' ),
'PR' => __( 'El Progreso', 'woocommerce' ), 'GT-PR' => __( 'El Progreso', 'woocommerce' ),
'ES' => __( 'Escuintla', 'woocommerce' ), 'GT-ES' => __( 'Escuintla', 'woocommerce' ),
'GU' => __( 'Guatemala', 'woocommerce' ), 'GT-GU' => __( 'Guatemala', 'woocommerce' ),
'HU' => __( 'Huehuetenango', 'woocommerce' ), 'GT-HU' => __( 'Huehuetenango', 'woocommerce' ),
'IZ' => __( 'Izabal', 'woocommerce' ), 'GT-IZ' => __( 'Izabal', 'woocommerce' ),
'JA' => __( 'Jalapa', 'woocommerce' ), 'GT-JA' => __( 'Jalapa', 'woocommerce' ),
'JU' => __( 'Jutiapa', 'woocommerce' ), 'GT-JU' => __( 'Jutiapa', 'woocommerce' ),
'PE' => __( 'Petén', 'woocommerce' ), 'GT-PE' => __( 'Petén', 'woocommerce' ),
'QZ' => __( 'Quetzaltenango', 'woocommerce' ), 'GT-QZ' => __( 'Quetzaltenango', 'woocommerce' ),
'QC' => __( 'Quiché', 'woocommerce' ), 'GT-QC' => __( 'Quiché', 'woocommerce' ),
'RE' => __( 'Retalhuleu', 'woocommerce' ), 'GT-RE' => __( 'Retalhuleu', 'woocommerce' ),
'SA' => __( 'Sacatepéquez', 'woocommerce' ), 'GT-SA' => __( 'Sacatepéquez', 'woocommerce' ),
'SM' => __( 'San Marcos', 'woocommerce' ), 'GT-SM' => __( 'San Marcos', 'woocommerce' ),
'SR' => __( 'Santa Rosa', 'woocommerce' ), 'GT-SR' => __( 'Santa Rosa', 'woocommerce' ),
'SO' => __( 'Sololá', 'woocommerce' ), 'GT-SO' => __( 'Sololá', 'woocommerce' ),
'SU' => __( 'Suchitepéquez', 'woocommerce' ), 'GT-SU' => __( 'Suchitepéquez', 'woocommerce' ),
'TO' => __( 'Totonicapán', 'woocommerce' ), 'GT-TO' => __( 'Totonicapán', 'woocommerce' ),
'ZA' => __( 'Zacapa', 'woocommerce' ), 'GT-ZA' => __( 'Zacapa', 'woocommerce' ),
), ),
'HK' => array( // Hong Kong states. 'HK' => array( // Hong Kong states.
'HONG KONG' => __( 'Hong Kong Island', 'woocommerce' ), 'HONG KONG' => __( 'Hong Kong Island', 'woocommerce' ),
'KOWLOON' => __( 'Kowloon', 'woocommerce' ), 'KOWLOON' => __( 'Kowloon', 'woocommerce' ),
'NEW TERRITORIES' => __( 'New Territories', 'woocommerce' ), 'NEW TERRITORIES' => __( 'New Territories', 'woocommerce' ),
), ),
'HN' => array( // Honduras states.
'HN-AT' => __( 'Atlántida', 'woocommerce' ),
'HN-IB' => __( 'Bay Islands', 'woocommerce' ),
'HN-CH' => __( 'Choluteca', 'woocommerce' ),
'HN-CL' => __( 'Colón', 'woocommerce' ),
'HN-CM' => __( 'Comayagua', 'woocommerce' ),
'HN-CP' => __( 'Copán', 'woocommerce' ),
'HN-CR' => __( 'Cortés', 'woocommerce' ),
'HN-EP' => __( 'El Paraíso', 'woocommerce' ),
'HN-FM' => __( 'Francisco Morazán', 'woocommerce' ),
'HN-GD' => __( 'Gracias a Dios', 'woocommerce' ),
'HN-IN' => __( 'Intibucá', 'woocommerce' ),
'HN-LE' => __( 'Lempira', 'woocommerce' ),
'HN-LP' => __( 'La Paz', 'woocommerce' ),
'HN-OC' => __( 'Ocotepeque', 'woocommerce' ),
'HN-OL' => __( 'Olancho', 'woocommerce' ),
'HN-SB' => __( 'Santa Bárbara', 'woocommerce' ),
'HN-VA' => __( 'Valle', 'woocommerce' ),
'HN-YO' => __( 'Yoro', 'woocommerce' ),
),
'HU' => array( // Hungary states. 'HU' => array( // Hungary states.
'BK' => __( 'Bács-Kiskun', 'woocommerce' ), 'BK' => __( 'Bács-Kiskun', 'woocommerce' ),
'BE' => __( 'Békés', 'woocommerce' ), 'BE' => __( 'Békés', 'woocommerce' ),
@ -1168,6 +1282,25 @@ return array(
'SAG' => __( 'Sagarmatha', 'woocommerce' ), 'SAG' => __( 'Sagarmatha', 'woocommerce' ),
'SET' => __( 'Seti', 'woocommerce' ), 'SET' => __( 'Seti', 'woocommerce' ),
), ),
'NI' => array( // Nicaragua states
'NI-AN' => __( 'Atlántico Norte', 'woocommerce' ),
'NI-AS' => __( 'Atlántico Sur', 'woocommerce' ),
'NI-BO' => __( 'Boaco', 'woocommerce' ),
'NI-CA' => __( 'Carazo', 'woocommerce' ),
'NI-CI' => __( 'Chinandega', 'woocommerce' ),
'NI-CO' => __( 'Chontales', 'woocommerce' ),
'NI-ES' => __( 'Estelí', 'woocommerce' ),
'NI-GR' => __( 'Granada', 'woocommerce' ),
'NI-JI' => __( 'Jinotega', 'woocommerce' ),
'NI-LE' => __( 'León', 'woocommerce' ),
'NI-MD' => __( 'Madriz', 'woocommerce' ),
'NI-MN' => __( 'Managua', 'woocommerce' ),
'NI-MS' => __( 'Masaya', 'woocommerce' ),
'NI-MT' => __( 'Matagalpa', 'woocommerce' ),
'NI-NS' => __( 'Nueva Segovia', 'woocommerce' ),
'NI-RI' => __( 'Rivas', 'woocommerce' ),
'NI-SJ' => __( 'Río San Juan', 'woocommerce' ),
),
'NZ' => array( // New Zealand States. 'NZ' => array( // New Zealand States.
'NL' => __( 'Northland', 'woocommerce' ), 'NL' => __( 'Northland', 'woocommerce' ),
'AK' => __( 'Auckland', 'woocommerce' ), 'AK' => __( 'Auckland', 'woocommerce' ),
@ -1186,6 +1319,21 @@ return array(
'OT' => __( 'Otago', 'woocommerce' ), 'OT' => __( 'Otago', 'woocommerce' ),
'SL' => __( 'Southland', 'woocommerce' ), 'SL' => __( 'Southland', 'woocommerce' ),
), ),
'PA' => array( // Panama states.
'PA-1' => __( 'Bocas del Toro', 'woocommerce' ),
'PA-2' => __( 'Coclé', 'woocommerce' ),
'PA-3' => __( 'Colón', 'woocommerce' ),
'PA-4' => __( 'Chiriquí', 'woocommerce' ),
'PA-5' => __( 'Darién', 'woocommerce' ),
'PA-6' => __( 'Herrera', 'woocommerce' ),
'PA-7' => __( 'Los Santos', 'woocommerce' ),
'PA-8' => __( 'Panamá', 'woocommerce' ),
'PA-9' => __( 'Veraguas', 'woocommerce' ),
'PA-10' => __( 'West Panamá', 'woocommerce' ),
'PA-EM' => __( 'Emberá', 'woocommerce' ),
'PA-KY' => __( 'Guna Yala', 'woocommerce' ),
'PA-NB' => __( 'Ngöbe-Buglé', 'woocommerce' ),
),
'PE' => array( // Peru states. 'PE' => array( // Peru states.
'CAL' => __( 'El Callao', 'woocommerce' ), 'CAL' => __( 'El Callao', 'woocommerce' ),
'LMA' => __( 'Municipalidad Metropolitana de Lima', 'woocommerce' ), 'LMA' => __( 'Municipalidad Metropolitana de Lima', 'woocommerce' ),
@ -1383,6 +1531,22 @@ return array(
'SG' => array(), 'SG' => array(),
'SK' => array(), 'SK' => array(),
'SI' => array(), 'SI' => array(),
'SV' => array( // El Salvador states.
'SV-AH' => __( 'Ahuachapán', 'woocommerce' ),
'SV-CA' => __( 'Cabañas', 'woocommerce' ),
'SV-CH' => __( 'Chalatenango', 'woocommerce' ),
'SV-CU' => __( 'Cuscatlán', 'woocommerce' ),
'SV-LI' => __( 'La Libertad', 'woocommerce' ),
'SV-MO' => __( 'Morazán', 'woocommerce' ),
'SV-PA' => __( 'La Paz', 'woocommerce' ),
'SV-SA' => __( 'Santa Ana', 'woocommerce' ),
'SV-SM' => __( 'San Miguel', 'woocommerce' ),
'SV-SO' => __( 'Sonsonate', 'woocommerce' ),
'SV-SS' => __( 'San Salvador', 'woocommerce' ),
'SV-SV' => __( 'San Vicente', 'woocommerce' ),
'SV-UN' => __( 'La Unión', 'woocommerce' ),
'SV-US' => __( 'Usulután', 'woocommerce' ),
),
'TH' => array( // Thailand states. 'TH' => array( // Thailand states.
'TH-37' => __( 'Amnat Charoen', 'woocommerce' ), 'TH-37' => __( 'Amnat Charoen', 'woocommerce' ),
'TH-15' => __( 'Ang Thong', 'woocommerce' ), 'TH-15' => __( 'Ang Thong', 'woocommerce' ),
@ -1836,32 +2000,53 @@ return array(
'AE' => __( 'Armed Forces (AE)', 'woocommerce' ), 'AE' => __( 'Armed Forces (AE)', 'woocommerce' ),
'AP' => __( 'Armed Forces (AP)', 'woocommerce' ), 'AP' => __( 'Armed Forces (AP)', 'woocommerce' ),
), ),
'UY' => array( // Uruguay States.
'UY-AR' => __( 'Artigas', 'woocommerce' ),
'UY-CA' => __( 'Canelones', 'woocommerce' ),
'UY-CL' => __( 'Cerro Largo', 'woocommerce' ),
'UY-CO' => __( 'Colonia', 'woocommerce' ),
'UY-DU' => __( 'Durazno', 'woocommerce' ),
'UY-FS' => __( 'Flores', 'woocommerce' ),
'UY-FD' => __( 'Florida', 'woocommerce' ),
'UY-LA' => __( 'Lavalleja', 'woocommerce' ),
'UY-MA' => __( 'Maldonado', 'woocommerce' ),
'UY-MO' => __( 'Montevideo', 'woocommerce' ),
'UY-PA' => __( 'Paysandú', 'woocommerce' ),
'UY-RN' => __( 'Río Negro', 'woocommerce' ),
'UY-RV' => __( 'Rivera', 'woocommerce' ),
'UY-RO' => __( 'Rocha', 'woocommerce' ),
'UY-SA' => __( 'Salto', 'woocommerce' ),
'UY-SJ' => __( 'San José', 'woocommerce' ),
'UY-SO' => __( 'Soriano', 'woocommerce' ),
'UY-TA' => __( 'Tacuarembó', 'woocommerce' ),
'UY-TT' => __( 'Treinta y Tres', 'woocommerce' ),
),
'VE' => array( // Venezuela States. 'VE' => array( // Venezuela States.
'A' => __( 'Capital', 'woocommerce' ), 'VE-A' => __( 'Capital', 'woocommerce' ),
'B' => __( 'Anzoátegui', 'woocommerce' ), 'VE-B' => __( 'Anzoátegui', 'woocommerce' ),
'C' => __( 'Apure', 'woocommerce' ), 'VE-C' => __( 'Apure', 'woocommerce' ),
'D' => __( 'Aragua', 'woocommerce' ), 'VE-D' => __( 'Aragua', 'woocommerce' ),
'E' => __( 'Barinas', 'woocommerce' ), 'VE-E' => __( 'Barinas', 'woocommerce' ),
'F' => __( 'Bolívar', 'woocommerce' ), 'VE-F' => __( 'Bolívar', 'woocommerce' ),
'G' => __( 'Carabobo', 'woocommerce' ), 'VE-G' => __( 'Carabobo', 'woocommerce' ),
'H' => __( 'Cojedes', 'woocommerce' ), 'VE-H' => __( 'Cojedes', 'woocommerce' ),
'I' => __( 'Falcón', 'woocommerce' ), 'VE-I' => __( 'Falcón', 'woocommerce' ),
'J' => __( 'Guárico', 'woocommerce' ), 'VE-J' => __( 'Guárico', 'woocommerce' ),
'K' => __( 'Lara', 'woocommerce' ), 'VE-K' => __( 'Lara', 'woocommerce' ),
'L' => __( 'Mérida', 'woocommerce' ), 'VE-L' => __( 'Mérida', 'woocommerce' ),
'M' => __( 'Miranda', 'woocommerce' ), 'VE-M' => __( 'Miranda', 'woocommerce' ),
'N' => __( 'Monagas', 'woocommerce' ), 'VE-N' => __( 'Monagas', 'woocommerce' ),
'O' => __( 'Nueva Esparta', 'woocommerce' ), 'VE-O' => __( 'Nueva Esparta', 'woocommerce' ),
'P' => __( 'Portuguesa', 'woocommerce' ), 'VE-P' => __( 'Portuguesa', 'woocommerce' ),
'R' => __( 'Sucre', 'woocommerce' ), 'VE-R' => __( 'Sucre', 'woocommerce' ),
'S' => __( 'Táchira', 'woocommerce' ), 'VE-S' => __( 'Táchira', 'woocommerce' ),
'T' => __( 'Trujillo', 'woocommerce' ), 'VE-T' => __( 'Trujillo', 'woocommerce' ),
'U' => __( 'Yaracuy', 'woocommerce' ), 'VE-U' => __( 'Yaracuy', 'woocommerce' ),
'V' => __( 'Zulia', 'woocommerce' ), 'VE-V' => __( 'Zulia', 'woocommerce' ),
'W' => __( 'Federal Dependencies', 'woocommerce' ), 'VE-W' => __( 'Federal Dependencies', 'woocommerce' ),
'X' => __( 'Vargas', 'woocommerce' ), 'VE-X' => __( 'La Guaira (Vargas)', 'woocommerce' ),
'Y' => __( 'Delta Amacuro', 'woocommerce' ), 'VE-Y' => __( 'Delta Amacuro', 'woocommerce' ),
'Z' => __( 'Amazonas', 'woocommerce' ), 'VE-Z' => __( 'Amazonas', 'woocommerce' ),
), ),
'VN' => array(), 'VN' => array(),
'YT' => array(), 'YT' => array(),

View File

@ -87,17 +87,57 @@ class WC_Admin_Addons {
) )
); );
if ( ! is_wp_error( $raw_featured ) ) { if ( is_wp_error( $raw_featured ) ) {
do_action( 'woocommerce_page_wc-addons_connection_error', $raw_featured->get_error_message() );
$message = self::is_ssl_error( $raw_featured->get_error_message() )
? __( 'We encountered an SSL error. Please ensure your site supports TLS version 1.2 or above.', 'woocommerce' )
: $raw_featured->get_error_message();
self::output_empty( $message );
return;
}
$response_code = (int) wp_remote_retrieve_response_code( $raw_featured );
if ( 200 !== $response_code ) {
do_action( 'woocommerce_page_wc-addons_connection_error', $response_code );
/* translators: %d: HTTP error code. */
$message = sprintf(
esc_html(
__(
'Our request to the featured API got error code %d.',
'woocommerce'
)
),
$response_code
);
self::output_empty( $message );
return;
}
$featured = json_decode( wp_remote_retrieve_body( $raw_featured ) ); $featured = json_decode( wp_remote_retrieve_body( $raw_featured ) );
if ( empty( $featured ) || ! is_array( $featured ) ) {
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
$message = __( 'Our request to the featured API got a malformed response.', 'woocommerce' );
self::output_empty( $message );
return;
}
if ( $featured ) { if ( $featured ) {
set_transient( 'wc_addons_featured', $featured, DAY_IN_SECONDS ); set_transient( 'wc_addons_featured', $featured, DAY_IN_SECONDS );
} }
} }
}
if ( ! empty( $featured ) ) {
self::output_featured( $featured ); self::output_featured( $featured );
} }
public static function is_ssl_error( $error_message ) {
return false !== stripos( $error_message, 'cURL error 35' );
} }
/** /**
@ -127,7 +167,7 @@ class WC_Admin_Addons {
* @param string $term Search terms. * @param string $term Search terms.
* @param string $country Store country. * @param string $country Store country.
* *
* @return object of extensions and promotions. * @return object|WP_Error Object with products and promotions properties, or WP_Error
*/ */
public static function get_extension_data( $category, $term, $country ) { public static function get_extension_data( $category, $term, $country ) {
$parameters = self::build_parameter_string( $category, $term, $country ); $parameters = self::build_parameter_string( $category, $term, $country );
@ -144,9 +184,24 @@ class WC_Admin_Addons {
array( 'headers' => $headers ) array( 'headers' => $headers )
); );
if ( ! is_wp_error( $raw_extensions ) ) { if ( is_wp_error( $raw_extensions ) ) {
$addons = json_decode( wp_remote_retrieve_body( $raw_extensions ) ); do_action( 'woocommerce_page_wc-addons_connection_error', $raw_extensions->get_error_message() );
return $raw_extensions;
} }
$response_code = (int) wp_remote_retrieve_response_code( $raw_extensions );
if ( 200 !== $response_code ) {
do_action( 'woocommerce_page_wc-addons_connection_error', $response_code );
return new WP_Error( 'error', __( "Our request to the search API got response code $response_code.", 'woocommerce' ) );
}
$addons = json_decode( wp_remote_retrieve_body( $raw_extensions ) );
if ( ! is_object( $addons ) || ! isset( $addons->products ) ) {
do_action( 'woocommerce_page_wc-addons_connection_error', 'Empty or malformed response' );
return new WP_Error( 'error', __( "Our request to the search API got a malformed response.", 'woocommerce' ) );
}
return $addons; return $addons;
} }
@ -908,6 +963,31 @@ class WC_Admin_Addons {
<?php <?php
} }
public static function output_empty( $message = '' ) {
?>
<div class="wc-addons__empty">
<h2><?php echo wp_kses_post( __( 'Oh no! We\'re having trouble connecting to the extensions catalog right now.', 'woocommerce' ) ); ?></h2>
<?php if ( ! empty( $message ) ) : ?>
<p><?php echo esc_html( $message ); ?></p>
<?php endif; ?>
<p>
<?php
/* translators: a url */
printf(
wp_kses_post(
__(
'To start growing your business, head over to <a href="%s">WooCommerce.com</a>, where you\'ll find the most popular WooCommerce extensions.',
'woocommerce'
)
),
'https://woocommerce.com/products/?utm_source=extensionsscreen&utm_medium=product&utm_campaign=connectionerror'
);
?>
</p>
</div>
<?php
}
/** /**
* Handles output of the addons page in admin. * Handles output of the addons page in admin.
@ -946,7 +1026,7 @@ class WC_Admin_Addons {
$term = $search ? $search : null; $term = $search ? $search : null;
$country = WC()->countries->get_base_country(); $country = WC()->countries->get_base_country();
$extension_data = self::get_extension_data( $category, $term, $country ); $extension_data = self::get_extension_data( $category, $term, $country );
$addons = $extension_data->products; $addons = is_wp_error( $extension_data ) ? $extension_data : $extension_data->products;
$promotions = ! empty( $extension_data->promotions ) ? $extension_data->promotions : array(); $promotions = ! empty( $extension_data->promotions ) ? $extension_data->promotions : array();
} }

View File

@ -70,12 +70,12 @@ $current_section_name = __( 'Browse Categories', 'woocommerce' );
<div class="wrap"> <div class="wrap">
<div class="marketplace-content-wrapper"> <div class="marketplace-content-wrapper">
<?php require __DIR__ . '/html-admin-page-addons-category-nav.php'; ?> <?php require __DIR__ . '/html-admin-page-addons-category-nav.php'; ?>
<?php if ( ! empty( $search ) && 0 === count( $addons ) ) : ?> <?php if ( ! empty( $search ) && ! is_wp_error( $addons ) && 0 === count( $addons ) ) : ?>
<h1 class="search-form-title"> <h1 class="search-form-title">
<?php esc_html_e( 'Sorry, could not find anything. Try searching again using a different term.', 'woocommerce' ); ?></p> <?php esc_html_e( 'Sorry, could not find anything. Try searching again using a different term.', 'woocommerce' ); ?></p>
</h1> </h1>
<?php endif; ?> <?php endif; ?>
<?php if ( ! empty( $search ) && count( $addons ) > 0 ) : ?> <?php if ( ! empty( $search ) && ! is_wp_error( $addons ) && count( $addons ) > 0 ) : ?>
<h1 class="search-form-title"> <h1 class="search-form-title">
<?php // translators: search keyword. ?> <?php // translators: search keyword. ?>
<?php printf( esc_html__( 'Search results for "%s"', 'woocommerce' ), esc_html( sanitize_text_field( wp_unslash( $search ) ) ) ); ?> <?php printf( esc_html__( 'Search results for "%s"', 'woocommerce' ), esc_html( sanitize_text_field( wp_unslash( $search ) ) ) ); ?>
@ -87,7 +87,10 @@ $current_section_name = __( 'Browse Categories', 'woocommerce' );
<?php WC_Admin_Addons::render_featured(); ?> <?php WC_Admin_Addons::render_featured(); ?>
</div> </div>
<?php endif; ?> <?php endif; ?>
<?php if ( '_featured' !== $current_section && $addons ) : ?> <?php if ( '_featured' !== $current_section ) : ?>
<?php if ( is_wp_error( $addons ) ) : ?>
<?php WC_Admin_Addons::output_empty( $addons->get_error_message() ); ?>
<?php else: ?>
<?php <?php
if ( ! empty( $promotions ) && WC()->is_wc_admin_active() ) { if ( ! empty( $promotions ) && WC()->is_wc_admin_active() ) {
foreach ( $promotions as $promotion ) { foreach ( $promotions as $promotion ) {
@ -124,6 +127,7 @@ $current_section_name = __( 'Browse Categories', 'woocommerce' );
<?php endforeach; ?> <?php endforeach; ?>
</ul> </ul>
<?php endif; ?> <?php endif; ?>
<?php endif; ?>
</div> </div>
<?php else : ?> <?php else : ?>
<?php /* translators: a url */ ?> <?php /* translators: a url */ ?>

View File

@ -812,6 +812,11 @@ class WC_Countries {
'hidden' => true, 'hidden' => true,
), ),
), ),
'AL' => array(
'state' => array(
'label' => __( 'County', 'woocommerce' ),
),
),
'AO' => array( 'AO' => array(
'postcode' => array( 'postcode' => array(
'required' => false, 'required' => false,
@ -897,6 +902,9 @@ class WC_Countries {
'required' => false, 'required' => false,
'hidden' => true, 'hidden' => true,
), ),
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
), ),
'BS' => array( 'BS' => array(
'postcode' => array( 'postcode' => array(
@ -941,6 +949,14 @@ class WC_Countries {
'postcode' => array( 'postcode' => array(
'required' => false, 'required' => false,
), ),
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'CR' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
), ),
'CW' => array( 'CW' => array(
'postcode' => array( 'postcode' => array(
@ -975,6 +991,16 @@ class WC_Countries {
'hidden' => true, 'hidden' => true,
), ),
), ),
'DO' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'EC' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'EE' => array( 'EE' => array(
'postcode' => array( 'postcode' => array(
'priority' => 65, 'priority' => 65,
@ -1047,6 +1073,11 @@ class WC_Countries {
'label' => __( 'Region', 'woocommerce' ), 'label' => __( 'Region', 'woocommerce' ),
), ),
), ),
'HN' => array(
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'HU' => array( 'HU' => array(
'last_name' => array( 'last_name' => array(
'class' => array( 'form-row-first' ), 'class' => array( 'form-row-first' ),
@ -1214,6 +1245,11 @@ class WC_Countries {
'label' => __( 'Province', 'woocommerce' ), 'label' => __( 'Province', 'woocommerce' ),
), ),
), ),
'NI' => array(
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'NL' => array( 'NL' => array(
'postcode' => array( 'postcode' => array(
'priority' => 65, 'priority' => 65,
@ -1259,6 +1295,11 @@ class WC_Countries {
'required' => false, 'required' => false,
), ),
), ),
'PA' => array(
'state' => array(
'label' => __( 'Province', 'woocommerce' ),
),
),
'PL' => array( 'PL' => array(
'postcode' => array( 'postcode' => array(
'priority' => 65, 'priority' => 65,
@ -1283,6 +1324,11 @@ class WC_Countries {
'hidden' => true, 'hidden' => true,
), ),
), ),
'PY' => array(
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'RE' => array( 'RE' => array(
'state' => array( 'state' => array(
'required' => false, 'required' => false,
@ -1340,6 +1386,11 @@ class WC_Countries {
'hidden' => true, 'hidden' => true,
), ),
), ),
'SV' => array(
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'ES' => array( 'ES' => array(
'postcode' => array( 'postcode' => array(
'priority' => 65, 'priority' => 65,
@ -1413,6 +1464,11 @@ class WC_Countries {
'label' => __( 'State', 'woocommerce' ), 'label' => __( 'State', 'woocommerce' ),
), ),
), ),
'UY' => array(
'state' => array(
'label' => __( 'Department', 'woocommerce' ),
),
),
'GB' => array( 'GB' => array(
'postcode' => array( 'postcode' => array(
'label' => __( 'Postcode', 'woocommerce' ), 'label' => __( 'Postcode', 'woocommerce' ),

View File

@ -311,14 +311,15 @@ downloads_remaining = IF( downloads_remaining = '', '', GREATEST( 0, downloads_r
WHERE permission_id = %d", WHERE permission_id = %d",
$this->get_id() $this->get_id()
); );
$wpdb->query( $query ); // WPCS: unprepared SQL ok. // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared
$wpdb->query( $query );
// Re-read this download from the data store to pull updated counts. // Re-read this download from the data store to pull updated counts.
$this->data_store->read( $this ); $this->data_store->read( $this );
// Track download in download log. // Track download in download log.
$download_log = new WC_Customer_Download_Log(); $download_log = new WC_Customer_Download_Log();
$download_log->set_timestamp( current_time( 'timestamp', true ) ); $download_log->set_timestamp( time() );
$download_log->set_permission_id( $this->get_id() ); $download_log->set_permission_id( $this->get_id() );
if ( ! is_null( $user_id ) ) { if ( ! is_null( $user_id ) ) {
@ -341,9 +342,10 @@ WHERE permission_id = %d",
/** /**
* OffsetGet. * OffsetGet.
* *
* @param string $offset Offset. * @param mixed $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
if ( is_callable( array( $this, "get_$offset" ) ) ) { if ( is_callable( array( $this, "get_$offset" ) ) ) {
return $this->{"get_$offset"}(); return $this->{"get_$offset"}();
@ -353,9 +355,10 @@ WHERE permission_id = %d",
/** /**
* OffsetSet. * OffsetSet.
* *
* @param string $offset Offset. * @param mixed $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
if ( is_callable( array( $this, "set_$offset" ) ) ) { if ( is_callable( array( $this, "set_$offset" ) ) ) {
$this->{"set_$offset"}( $value ); $this->{"set_$offset"}( $value );
@ -365,8 +368,9 @@ WHERE permission_id = %d",
/** /**
* OffsetUnset * OffsetUnset
* *
* @param string $offset Offset. * @param mixed $offset Offset.
*/ */
#[\ReturnTypeWillChange]
public function offsetUnset( $offset ) { public function offsetUnset( $offset ) {
if ( is_callable( array( $this, "set_$offset" ) ) ) { if ( is_callable( array( $this, "set_$offset" ) ) ) {
$this->{"set_$offset"}( '' ); $this->{"set_$offset"}( '' );
@ -376,9 +380,10 @@ WHERE permission_id = %d",
/** /**
* OffsetExists. * OffsetExists.
* *
* @param string $offset Offset. * @param mixed $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
return in_array( $offset, array_keys( $this->data ), true ); return in_array( $offset, array_keys( $this->data ), true );
} }

View File

@ -270,7 +270,7 @@ class WC_Download_Handler {
); );
$count = 0; $count = 0;
$file_path = str_replace( array_keys( $replacements ), array_values( $replacements ), $file_path ); $file_path = str_replace( array_keys( $replacements ), array_values( $replacements ), $file_path, $count );
$parsed_file_path = wp_parse_url( $file_path ); $parsed_file_path = wp_parse_url( $file_path );
$remote_file = null === $count || 0 === $count; // Remote file only if there were no replacements. $remote_file = null === $count || 0 === $count; // Remote file only if there were no replacements.

View File

@ -1046,7 +1046,7 @@ CREATE TABLE {$wpdb->prefix}wc_reserved_stock (
`expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00', `expires` datetime NOT NULL DEFAULT '0000-00-00 00:00:00',
PRIMARY KEY (`order_id`, `product_id`) PRIMARY KEY (`order_id`, `product_id`)
) $collate; ) $collate;
CREATE TABLE {$wpdb->prefix}woocommerce_rate_limits ( CREATE TABLE {$wpdb->prefix}wc_rate_limits (
rate_limit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT, rate_limit_id BIGINT UNSIGNED NOT NULL AUTO_INCREMENT,
rate_limit_key varchar(200) NOT NULL, rate_limit_key varchar(200) NOT NULL,
rate_limit_expiry BIGINT UNSIGNED NOT NULL, rate_limit_expiry BIGINT UNSIGNED NOT NULL,
@ -1087,7 +1087,7 @@ CREATE TABLE {$wpdb->prefix}woocommerce_rate_limits (
"{$wpdb->prefix}woocommerce_tax_rate_locations", "{$wpdb->prefix}woocommerce_tax_rate_locations",
"{$wpdb->prefix}woocommerce_tax_rates", "{$wpdb->prefix}woocommerce_tax_rates",
"{$wpdb->prefix}wc_reserved_stock", "{$wpdb->prefix}wc_reserved_stock",
"{$wpdb->prefix}woocommerce_rate_limits", "{$wpdb->prefix}wc_rate_limits",
); );
/** /**

View File

@ -140,6 +140,7 @@ class WC_Order_Item_Coupon extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
wc_deprecated_function( 'WC_Order_Item_Coupon::offsetGet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Coupon::offsetGet', '4.4.0', '' );
if ( 'discount_amount' === $offset ) { if ( 'discount_amount' === $offset ) {
@ -157,6 +158,7 @@ class WC_Order_Item_Coupon extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
wc_deprecated_function( 'WC_Order_Item_Coupon::offsetSet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Coupon::offsetSet', '4.4.0', '' );
if ( 'discount_amount' === $offset ) { if ( 'discount_amount' === $offset ) {
@ -173,6 +175,7 @@ class WC_Order_Item_Coupon extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'discount_amount', 'discount_amount_tax' ), true ) ) { if ( in_array( $offset, array( 'discount_amount', 'discount_amount_tax' ), true ) ) {
return true; return true;

View File

@ -293,6 +293,7 @@ class WC_Order_Item_Fee extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
if ( 'line_total' === $offset ) { if ( 'line_total' === $offset ) {
$offset = 'total'; $offset = 'total';
@ -311,6 +312,7 @@ class WC_Order_Item_Fee extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
wc_deprecated_function( 'WC_Order_Item_Fee::offsetSet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Fee::offsetSet', '4.4.0', '' );
if ( 'line_total' === $offset ) { if ( 'line_total' === $offset ) {
@ -329,6 +331,7 @@ class WC_Order_Item_Fee extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'line_total', 'line_tax', 'line_tax_data' ), true ) ) { if ( in_array( $offset, array( 'line_total', 'line_tax', 'line_tax_data' ), true ) ) {
return true; return true;

View File

@ -428,6 +428,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
if ( 'line_subtotal' === $offset ) { if ( 'line_subtotal' === $offset ) {
$offset = 'subtotal'; $offset = 'subtotal';
@ -452,6 +453,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
wc_deprecated_function( 'WC_Order_Item_Product::offsetSet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Product::offsetSet', '4.4.0', '' );
if ( 'line_subtotal' === $offset ) { if ( 'line_subtotal' === $offset ) {
@ -476,6 +478,7 @@ class WC_Order_Item_Product extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'line_tax_data', 'item_meta_array', 'item_meta', 'qty' ), true ) ) { if ( in_array( $offset, array( 'line_subtotal', 'line_subtotal_tax', 'line_total', 'line_tax', 'line_tax_data', 'item_meta_array', 'item_meta', 'qty' ), true ) ) {
return true; return true;

View File

@ -279,6 +279,7 @@ class WC_Order_Item_Shipping extends WC_Order_Item {
* @param string $offset Key. * @param string $offset Key.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
if ( 'cost' === $offset ) { if ( 'cost' === $offset ) {
$offset = 'total'; $offset = 'total';
@ -293,6 +294,7 @@ class WC_Order_Item_Shipping extends WC_Order_Item {
* @param string $offset Key. * @param string $offset Key.
* @param mixed $value Value to set. * @param mixed $value Value to set.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
wc_deprecated_function( 'WC_Order_Item_Shipping::offsetSet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Shipping::offsetSet', '4.4.0', '' );
if ( 'cost' === $offset ) { if ( 'cost' === $offset ) {
@ -307,6 +309,7 @@ class WC_Order_Item_Shipping extends WC_Order_Item {
* @param string $offset Key. * @param string $offset Key.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'cost' ), true ) ) { if ( in_array( $offset, array( 'cost' ), true ) ) {
return true; return true;

View File

@ -247,6 +247,7 @@ class WC_Order_Item_Tax extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
if ( 'tax_amount' === $offset ) { if ( 'tax_amount' === $offset ) {
$offset = 'tax_total'; $offset = 'tax_total';
@ -263,6 +264,7 @@ class WC_Order_Item_Tax extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
wc_deprecated_function( 'WC_Order_Item_Tax::offsetSet', '4.4.0', '' ); wc_deprecated_function( 'WC_Order_Item_Tax::offsetSet', '4.4.0', '' );
if ( 'tax_amount' === $offset ) { if ( 'tax_amount' === $offset ) {
@ -279,6 +281,7 @@ class WC_Order_Item_Tax extends WC_Order_Item {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
if ( in_array( $offset, array( 'tax_amount', 'shipping_tax_amount' ), true ) ) { if ( in_array( $offset, array( 'tax_amount', 'shipping_tax_amount' ), true ) ) {
return true; return true;

View File

@ -310,6 +310,7 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
if ( 'item_meta_array' === $offset ) { if ( 'item_meta_array' === $offset ) {
foreach ( $value as $meta_id => $meta ) { foreach ( $value as $meta_id => $meta ) {
@ -334,6 +335,7 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
* *
* @param string $offset Offset. * @param string $offset Offset.
*/ */
#[\ReturnTypeWillChange]
public function offsetUnset( $offset ) { public function offsetUnset( $offset ) {
$this->maybe_read_meta_data(); $this->maybe_read_meta_data();
@ -359,6 +361,7 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
$this->maybe_read_meta_data(); $this->maybe_read_meta_data();
if ( 'item_meta_array' === $offset || 'item_meta' === $offset || array_key_exists( $offset, $this->data ) ) { if ( 'item_meta_array' === $offset || 'item_meta' === $offset || array_key_exists( $offset, $this->data ) ) {
@ -373,6 +376,7 @@ class WC_Order_Item extends WC_Data implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
$this->maybe_read_meta_data(); $this->maybe_read_meta_data();

View File

@ -266,6 +266,7 @@ class WC_Product_Attribute implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
switch ( $offset ) { switch ( $offset ) {
case 'is_variation': case 'is_variation':
@ -291,6 +292,7 @@ class WC_Product_Attribute implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Value. * @param mixed $value Value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
switch ( $offset ) { switch ( $offset ) {
case 'is_variation': case 'is_variation':
@ -304,7 +306,7 @@ class WC_Product_Attribute implements ArrayAccess {
break; break;
default: default:
if ( is_callable( array( $this, "set_$offset" ) ) ) { if ( is_callable( array( $this, "set_$offset" ) ) ) {
return $this->{"set_$offset"}( $value ); $this->{"set_$offset"}( $value );
} }
break; break;
} }
@ -315,6 +317,7 @@ class WC_Product_Attribute implements ArrayAccess {
* *
* @param string $offset Offset. * @param string $offset Offset.
*/ */
#[\ReturnTypeWillChange]
public function offsetUnset( $offset ) {} public function offsetUnset( $offset ) {}
/** /**
@ -323,6 +326,7 @@ class WC_Product_Attribute implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
return in_array( $offset, array_merge( array( 'is_variation', 'is_visible', 'is_taxonomy', 'value' ), array_keys( $this->data ) ), true ); return in_array( $offset, array_merge( array( 'is_variation', 'is_visible', 'is_taxonomy', 'value' ), array_keys( $this->data ) ), true );
} }

View File

@ -54,13 +54,13 @@ class WC_Product_Download implements ArrayAccess {
*/ */
public function get_type_of_file_path( $file_path = '' ) { public function get_type_of_file_path( $file_path = '' ) {
$file_path = $file_path ? $file_path : $this->get_file(); $file_path = $file_path ? $file_path : $this->get_file();
$parsed_url = parse_url( $file_path ); $parsed_url = wp_parse_url( $file_path );
if ( if (
$parsed_url && $parsed_url &&
isset( $parsed_url['host'] ) && // Absolute url means that it has a host. isset( $parsed_url['host'] ) && // Absolute url means that it has a host.
( // Theoretically we could permit any scheme (like ftp as well), but that has not been the case before. So we allow none or http(s). ( // Theoretically we could permit any scheme (like ftp as well), but that has not been the case before. So we allow none or http(s).
! isset( $parsed_url['scheme'] ) || ! isset( $parsed_url['scheme'] ) ||
in_array( $parsed_url['scheme'], array( 'http', 'https' ) ) in_array( $parsed_url['scheme'], array( 'http', 'https' ), true )
) )
) { ) {
return 'absolute'; return 'absolute';
@ -255,6 +255,7 @@ class WC_Product_Download implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return mixed * @return mixed
*/ */
#[\ReturnTypeWillChange]
public function offsetGet( $offset ) { public function offsetGet( $offset ) {
switch ( $offset ) { switch ( $offset ) {
default: default:
@ -272,11 +273,12 @@ class WC_Product_Download implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @param mixed $value Offset value. * @param mixed $value Offset value.
*/ */
#[\ReturnTypeWillChange]
public function offsetSet( $offset, $value ) { public function offsetSet( $offset, $value ) {
switch ( $offset ) { switch ( $offset ) {
default: default:
if ( is_callable( array( $this, "set_$offset" ) ) ) { if ( is_callable( array( $this, "set_$offset" ) ) ) {
return $this->{"set_$offset"}( $value ); $this->{"set_$offset"}( $value );
} }
break; break;
} }
@ -287,6 +289,7 @@ class WC_Product_Download implements ArrayAccess {
* *
* @param string $offset Offset. * @param string $offset Offset.
*/ */
#[\ReturnTypeWillChange]
public function offsetUnset( $offset ) {} public function offsetUnset( $offset ) {}
/** /**
@ -295,6 +298,7 @@ class WC_Product_Download implements ArrayAccess {
* @param string $offset Offset. * @param string $offset Offset.
* @return bool * @return bool
*/ */
#[\ReturnTypeWillChange]
public function offsetExists( $offset ) { public function offsetExists( $offset ) {
return in_array( $offset, array_keys( $this->data ), true ); return in_array( $offset, array_keys( $this->data ), true );
} }

View File

@ -101,7 +101,7 @@ class WC_Rate_Limiter {
$wpdb->prepare( $wpdb->prepare(
" "
SELECT rate_limit_expiry SELECT rate_limit_expiry
FROM {$wpdb->prefix}woocommerce_rate_limits FROM {$wpdb->prefix}wc_rate_limits
WHERE rate_limit_key = %s WHERE rate_limit_key = %s
", ",
$action_id $action_id
@ -138,7 +138,7 @@ class WC_Rate_Limiter {
$next_try_allowed_at = time() + $delay; $next_try_allowed_at = time() + $delay;
$result = $wpdb->replace( $result = $wpdb->replace(
$wpdb->prefix . 'woocommerce_rate_limits', $wpdb->prefix . 'wc_rate_limits',
array( array(
'rate_limit_key' => $action_id, 'rate_limit_key' => $action_id,
'rate_limit_expiry' => $next_try_allowed_at, 'rate_limit_expiry' => $next_try_allowed_at,
@ -159,7 +159,7 @@ class WC_Rate_Limiter {
$wpdb->query( $wpdb->query(
$wpdb->prepare( $wpdb->prepare(
"DELETE FROM {$wpdb->prefix}woocommerce_rate_limits WHERE rate_limit_expiry < %d", "DELETE FROM {$wpdb->prefix}wc_rate_limits WHERE rate_limit_expiry < %d",
time() time()
) )
); );

View File

@ -27,7 +27,7 @@ final class WooCommerce {
* *
* @var string * @var string
*/ */
public $version = '6.0.0'; public $version = '6.1.0';
/** /**
* WooCommerce Schema version. * WooCommerce Schema version.
@ -932,7 +932,7 @@ final class WooCommerce {
return; return;
} }
$message_one = __( 'You have installed a development version of WooCommerce which requires files to be built and minified. From the plugin directory, run <code>grunt assets</code> to build and minify assets.', 'woocommerce' ); $message_one = __( 'You have installed a development version of WooCommerce which requires files to be built and minified. From the plugin directory, run <code>pnpm install</code> and then <code>pnpm nx build woocommerce-legacy-assets</code> to build and minify assets.', 'woocommerce' );
$message_two = sprintf( $message_two = sprintf(
/* translators: 1: URL of WordPress.org Repository 2: URL of the GitHub Repository release page */ /* translators: 1: URL of WordPress.org Repository 2: URL of the GitHub Repository release page */
__( 'Or you can download a pre-built version of the plugin from the <a href="%1$s">WordPress.org repository</a> or by visiting <a href="%2$s">the releases page in the GitHub repository</a>.', 'woocommerce' ), __( 'Or you can download a pre-built version of the plugin from the <a href="%1$s">WordPress.org repository</a> or by visiting <a href="%2$s">the releases page in the GitHub repository</a>.', 'woocommerce' ),

View File

@ -51,6 +51,13 @@ if ( ! class_exists( 'WC_Email_Customer_New_Account', false ) ) :
*/ */
public $password_generated; public $password_generated;
/**
* Magic link to set initial password.
*
* @var string
*/
public $set_password_url;
/** /**
* Constructor. * Constructor.
*/ */
@ -104,6 +111,7 @@ if ( ! class_exists( 'WC_Email_Customer_New_Account', false ) ) :
$this->user_email = stripslashes( $this->object->user_email ); $this->user_email = stripslashes( $this->object->user_email );
$this->recipient = $this->user_email; $this->recipient = $this->user_email;
$this->password_generated = $password_generated; $this->password_generated = $password_generated;
$this->set_password_url = $this->generate_set_password_url();
} }
if ( $this->is_enabled() && $this->get_recipient() ) { if ( $this->is_enabled() && $this->get_recipient() ) {
@ -131,6 +139,7 @@ if ( ! class_exists( 'WC_Email_Customer_New_Account', false ) ) :
'sent_to_admin' => false, 'sent_to_admin' => false,
'plain_text' => false, 'plain_text' => false,
'email' => $this, 'email' => $this,
'set_password_url' => $this->set_password_url,
) )
); );
} }
@ -153,6 +162,7 @@ if ( ! class_exists( 'WC_Email_Customer_New_Account', false ) ) :
'sent_to_admin' => false, 'sent_to_admin' => false,
'plain_text' => true, 'plain_text' => true,
'email' => $this, 'email' => $this,
'set_password_url' => $this->set_password_url,
) )
); );
} }
@ -166,6 +176,26 @@ if ( ! class_exists( 'WC_Email_Customer_New_Account', false ) ) :
public function get_default_additional_content() { public function get_default_additional_content() {
return __( 'We look forward to seeing you soon.', 'woocommerce' ); return __( 'We look forward to seeing you soon.', 'woocommerce' );
} }
/**
* Generate set password URL link for a new user.
*
* See also Automattic\WooCommerce\Blocks\Domain\Services\Email\CustomerNewAccount and wp_new_user_notification.
*
* @since 6.0.0
* @return string
*/
protected function generate_set_password_url() {
// Generate a magic link so user can set initial password.
$key = get_password_reset_key( $this->object );
if ( ! is_wp_error( $key ) ) {
$action = 'newaccount';
return wc_get_account_endpoint_url( 'lost-password' ) . "?action=$action&key=$key&login=" . rawurlencode( $this->object->user_login );
} else {
// Something went wrong while getting the key for new password URL, send customer to the generic password reset.
return wc_get_account_endpoint_url( 'lost-password' );
}
}
} }
endif; endif;

View File

@ -275,24 +275,31 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
$response = rest_ensure_response( $taxes ); $response = rest_ensure_response( $taxes );
// Store pagination values for headers then unset for count query.
$per_page = (int) $prepared_args['number']; $per_page = (int) $prepared_args['number'];
$page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 ); $page = ceil( ( ( (int) $prepared_args['offset'] ) / $per_page ) + 1 );
// Query only for ids. // Unset LIMIT args.
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared array_splice( $wpdb_prepare_args, -2 );
$query = str_replace( 'SELECT *', 'SELECT tax_rate_id', $query );
$wpdb->get_results( // Count query.
$wpdb->prepare( $query = str_replace(
$query, array(
$wpdb_prepare_args 'SELECT *',
) 'LIMIT %d, %d',
),
array(
'SELECT COUNT(*)',
'',
),
$query
); );
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
$total_taxes = (int) $wpdb->get_var( empty( $wpdb_prepare_args ) ? $query : $wpdb->prepare( $query, $wpdb_prepare_args ) );
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared // phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
// Calculate totals. // Calculate totals.
$total_taxes = (int) $wpdb->num_rows; $response->header( 'X-WP-Total', $total_taxes );
$response->header( 'X-WP-Total', (int) $total_taxes );
$max_pages = ceil( $total_taxes / $per_page ); $max_pages = ceil( $total_taxes / $per_page );
$response->header( 'X-WP-TotalPages', (int) $max_pages ); $response->header( 'X-WP-TotalPages', (int) $max_pages );

View File

@ -68,6 +68,7 @@ class WC_Tracks {
/** /**
* Record an event in Tracks - this is the preferred way to record events from PHP. * Record an event in Tracks - this is the preferred way to record events from PHP.
* Note: the event request won't be made if $properties has a member called `error`.
* *
* @param string $event_name The name of the event. * @param string $event_name The name of the event.
* @param array $properties Custom properties to send with the event. * @param array $properties Custom properties to send with the event.

View File

@ -22,6 +22,7 @@ class WC_Extensions_Tracking {
add_action( 'woocommerce_helper_disconnected', array( $this, 'track_helper_disconnected' ) ); add_action( 'woocommerce_helper_disconnected', array( $this, 'track_helper_disconnected' ) );
add_action( 'woocommerce_helper_subscriptions_refresh', array( $this, 'track_helper_subscriptions_refresh' ) ); add_action( 'woocommerce_helper_subscriptions_refresh', array( $this, 'track_helper_subscriptions_refresh' ) );
add_action( 'woocommerce_addon_installed', array( $this, 'track_addon_install' ), 10, 2 ); add_action( 'woocommerce_addon_installed', array( $this, 'track_addon_install' ), 10, 2 );
add_action( 'woocommerce_page_wc-addons_connection_error', array( $this, 'track_extensions_page_connection_error' ), 10, 1 );
} }
/** /**
@ -47,6 +48,29 @@ class WC_Extensions_Tracking {
WC_Tracks::record_event( $event, $properties ); WC_Tracks::record_event( $event, $properties );
} }
/**
* Send a Tracks event when the Extensions page gets a bad response or no response
* from the WCCOM extensions API.
*
* @param string $error
*/
public function track_extensions_page_connection_error( string $error = '' ) {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
$properties = array(
'section' => empty( $_REQUEST['section'] ) ? '_featured' : wc_clean( wp_unslash( $_REQUEST['section'] ) ),
);
if ( ! empty( $_REQUEST['search'] ) ) {
$properties['search_term'] = wc_clean( wp_unslash( $_REQUEST['search'] ) );
}
// phpcs:enable
if ( ! empty( $error ) ) {
$properties['error_data'] = $error;
}
WC_Tracks::record_event( 'extensions_view_connection_error', $properties );
}
/** /**
* Send a Tracks even when a Helper connection process is initiated. * Send a Tracks even when a Helper connection process is initiated.
*/ */

View File

@ -715,16 +715,11 @@ function wc_restock_refunded_items( $order, $refunded_line_items ) {
// Update _reduced_stock meta to track changes. // Update _reduced_stock meta to track changes.
$item_stock_reduced = $item_stock_reduced - $qty_to_refund; $item_stock_reduced = $item_stock_reduced - $qty_to_refund;
if ( 0 < $item_stock_reduced ) {
// Keeps track of total running tally of reduced stock. // Keeps track of total running tally of reduced stock.
$item->update_meta_data( '_reduced_stock', $item_stock_reduced ); $item->update_meta_data( '_reduced_stock', $item_stock_reduced );
// Keeps track of only refunded items that needs restock. // Keeps track of only refunded items that needs restock.
$item->update_meta_data( '_restock_refunded_items', $qty_to_refund + $restock_refunded_items ); $item->update_meta_data( '_restock_refunded_items', $qty_to_refund + $restock_refunded_items );
} else {
$item->delete_meta_data( '_reduced_stock' );
$item->delete_meta_data( '_restock_refunded_items' );
}
/* translators: 1: product ID 2: old stock level 3: new stock level */ /* translators: 1: product ID 2: old stock level 3: new stock level */
$order->add_order_note( sprintf( __( 'Item #%1$s stock increased from %2$s to %3$s.', 'woocommerce' ), $product->get_id(), $old_stock, $new_stock ) ); $order->add_order_note( sprintf( __( 'Item #%1$s stock increased from %2$s to %3$s.', 'woocommerce' ), $product->get_id(), $old_stock, $new_stock ) );

View File

@ -0,0 +1,3 @@
> 0.1%
ie 8
ie 9

View File

@ -0,0 +1,21 @@
*.min.js
/js/accounting/**
/js/flexslider/**
/js/jquery-blockui/**
/js/jquery-cookie/**
/js/jquery-flot/**
/js/jquery-payment/**
/js/jquery-qrcode/**
/js/jquery-serializejson/**
/js/jquery-tiptip/**
/js/jquery-ui-touch-punch/**
/js/js-cookie/**
/js/photoswipe/**
/js/prettyPhoto/**
/js/round/**
/js/select2/**
/js/selectWoo/**
/js/stupidtable/**
/js/zeroclipboard/**
/js/zoom/**

View File

@ -0,0 +1,31 @@
/** @format */
module.exports = {
root: true,
env: {
browser: true,
es6: true,
node: true
},
globals: {
wp: true,
wpApiSettings: true,
wcSettings: true,
es6: true
},
rules: {
camelcase: 0,
indent: 0,
'max-len': [ 2, { 'code': 140 } ],
'no-console': 1
},
parser: 'babel-eslint',
parserOptions: {
ecmaVersion: 8,
ecmaFeatures: {
modules: true,
experimentalObjectRestSpread: true,
jsx: true
}
},
};

3
plugins/woocommerce/legacy/.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
js/**/*.min.js
css/*.css
css/photoswipe/**/*.min.css

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