Merge branch 'trunk' into e2e/e2e-merchant-settings-add-shipping-classes
This commit is contained in:
commit
cb53050892
|
@ -21,3 +21,17 @@ jobs:
|
||||||
asset_path: ${{ steps.build.outputs.zip_path }}
|
asset_path: ${{ steps.build.outputs.zip_path }}
|
||||||
asset_name: woocommerce.zip
|
asset_name: woocommerce.zip
|
||||||
asset_content_type: application/zip
|
asset_content_type: application/zip
|
||||||
|
update-code-reference:
|
||||||
|
if: github.event.release.prerelease == false && github.event.release.draft == false && github.repository_owner == 'woocommerce'
|
||||||
|
name: Update Code Reference
|
||||||
|
needs: build
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- name: Invoke Code Reference build and deploy workflow
|
||||||
|
uses: aurelien-baudet/workflow-dispatch@v2
|
||||||
|
with:
|
||||||
|
workflow: GitHub Pages deploy
|
||||||
|
repo: woocommerce/code-reference
|
||||||
|
token: ${{ secrets.CUSTOM_GH_TOKEN }}
|
||||||
|
ref: refs/heads/trunk
|
||||||
|
inputs: '{ "version": "${{ github.event.release.tag_name }}" }'
|
||||||
|
|
|
@ -0,0 +1,74 @@
|
||||||
|
name: Run CI
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
branches:
|
||||||
|
- trunk
|
||||||
|
- 'release/**'
|
||||||
|
jobs:
|
||||||
|
test:
|
||||||
|
name: PHP ${{ matrix.php }} WP ${{ matrix.wp }}
|
||||||
|
timeout-minutes: 15
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
strategy:
|
||||||
|
fail-fast: false
|
||||||
|
matrix:
|
||||||
|
php: [ '7.0', '7.1', '7.2', '7.3', '7.4', '8.0' ]
|
||||||
|
wp: [ 'latest' ]
|
||||||
|
include:
|
||||||
|
- wp: nightly
|
||||||
|
php: '7.4'
|
||||||
|
- wp: '5.5'
|
||||||
|
php: 7.2
|
||||||
|
- wp: '5.4'
|
||||||
|
php: 7.2
|
||||||
|
services:
|
||||||
|
database:
|
||||||
|
image: mysql:5.6
|
||||||
|
env:
|
||||||
|
MYSQL_ROOT_PASSWORD: root
|
||||||
|
ports:
|
||||||
|
- 3306:3306
|
||||||
|
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
||||||
|
steps:
|
||||||
|
- name: Checkout code
|
||||||
|
uses: actions/checkout@v2
|
||||||
|
|
||||||
|
- name: Setup PHP
|
||||||
|
uses: shivammathur/setup-php@v2
|
||||||
|
with:
|
||||||
|
php-version: ${{ matrix.php }}
|
||||||
|
tools: composer
|
||||||
|
extensions: mysql
|
||||||
|
coverage: none
|
||||||
|
|
||||||
|
- name: Tool versions
|
||||||
|
run: |
|
||||||
|
php --version
|
||||||
|
composer --version
|
||||||
|
|
||||||
|
- name: Get cached composer directories
|
||||||
|
uses: actions/cache@v2
|
||||||
|
with:
|
||||||
|
path: |
|
||||||
|
./packages
|
||||||
|
./vendor
|
||||||
|
key: ${{ runner.os }}-${{ hashFiles('./composer.lock') }}
|
||||||
|
|
||||||
|
- name: Setup and install composer
|
||||||
|
run: composer install
|
||||||
|
|
||||||
|
- name: Add PHP8 Compatibility.
|
||||||
|
run: |
|
||||||
|
if [ "$(php -r "echo version_compare(PHP_VERSION,'8.0','>=');")" ]; then
|
||||||
|
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
|
||||||
|
unzip -d /tmp/phpunit-7.5-fork /tmp/phpunit-7.5-fork.zip
|
||||||
|
composer bin phpunit config --unset platform
|
||||||
|
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
|
||||||
|
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
|
||||||
|
fi
|
||||||
|
|
||||||
|
- name: Init DB and WP
|
||||||
|
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 ${{ matrix.wp }}
|
||||||
|
|
||||||
|
- name: Run tests
|
||||||
|
run: ./vendor/bin/phpunit -c ./phpunit.xml
|
|
@ -17,6 +17,8 @@ jobs:
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 100
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
|
@ -49,3 +51,7 @@ jobs:
|
||||||
run: |
|
run: |
|
||||||
RUN_CODE_COVERAGE=1 bash ./tests/bin/phpunit.sh
|
RUN_CODE_COVERAGE=1 bash ./tests/bin/phpunit.sh
|
||||||
exit 0
|
exit 0
|
||||||
|
|
||||||
|
- name: Send code coverage to Codecov.
|
||||||
|
run: |
|
||||||
|
bash <(curl -s https://codecov.io/bash)
|
||||||
|
|
|
@ -6,25 +6,17 @@ jobs:
|
||||||
name: Code sniff (PHP 7.4, WP Latest)
|
name: Code sniff (PHP 7.4, WP Latest)
|
||||||
timeout-minutes: 15
|
timeout-minutes: 15
|
||||||
runs-on: ubuntu-latest
|
runs-on: ubuntu-latest
|
||||||
services:
|
|
||||||
database:
|
|
||||||
image: mysql:5.6
|
|
||||||
env:
|
|
||||||
MYSQL_ROOT_PASSWORD: root
|
|
||||||
ports:
|
|
||||||
- 3306:3306
|
|
||||||
options: --health-cmd="mysqladmin ping" --health-interval=10s --health-timeout=5s --health-retries=5
|
|
||||||
steps:
|
steps:
|
||||||
- name: Checkout code
|
- name: Checkout code
|
||||||
uses: actions/checkout@v2
|
uses: actions/checkout@v2
|
||||||
|
with:
|
||||||
|
fetch-depth: 100
|
||||||
|
|
||||||
- name: Setup PHP
|
- name: Setup PHP
|
||||||
uses: shivammathur/setup-php@v2
|
uses: shivammathur/setup-php@v2
|
||||||
with:
|
with:
|
||||||
php-version: 7.4
|
php-version: 7.4
|
||||||
tools: composer
|
tools: composer, cs2pr
|
||||||
extensions: mysql
|
|
||||||
coverage: none
|
|
||||||
|
|
||||||
- name: Tool versions
|
- name: Tool versions
|
||||||
run: |
|
run: |
|
||||||
|
@ -42,8 +34,9 @@ jobs:
|
||||||
- name: Setup and install composer
|
- name: Setup and install composer
|
||||||
run: composer install
|
run: composer install
|
||||||
|
|
||||||
- name: Init DB and WP
|
|
||||||
run: ./tests/bin/install.sh woo_test root root 127.0.0.1 latest
|
|
||||||
|
|
||||||
- name: Run code sniff
|
- name: Run code sniff
|
||||||
run: RUN_PHPCS=1 bash ./tests/bin/phpcs.sh
|
continue-on-error: true
|
||||||
|
run: ./tests/bin/phpcs.sh "${{ github.event.pull_request.base.sha }}" "${{ github.event.after }}"
|
||||||
|
|
||||||
|
- name: Show PHPCS results in PR
|
||||||
|
run: cs2pr ./phpcs-report.xml
|
||||||
|
|
|
@ -0,0 +1,20 @@
|
||||||
|
name: 'Close stale needs-feedback issues'
|
||||||
|
on:
|
||||||
|
schedule:
|
||||||
|
- cron: '0 21 * * *'
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
stale:
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/stale@v3
|
||||||
|
with:
|
||||||
|
repo-token: ${{ secrets.GITHUB_TOKEN }}
|
||||||
|
stale-issue-message: "As a part of this repository’s maintenance, this issue is being marked as stale due to inactivity. Please feel free to comment on it in case we missed something.\n\n###### After 7 days with no activity this issue will be automatically be closed."
|
||||||
|
close-issue-message: 'This issue was closed because it has been 14 days with no activity.'
|
||||||
|
days-before-issue-stale: 7
|
||||||
|
days-before-issue-close: 7
|
||||||
|
days-before-pr-close: -1
|
||||||
|
only-issue-labels: 'needs feedback'
|
||||||
|
close-issue-label: "category: can't reproduce"
|
||||||
|
debug-only: true
|
110
.travis.yml
110
.travis.yml
|
@ -1,110 +0,0 @@
|
||||||
version: ~> 1.0
|
|
||||||
|
|
||||||
# Specifies that Travis should create builds for trunk and release branches and also tags.
|
|
||||||
branches:
|
|
||||||
only:
|
|
||||||
- trunk
|
|
||||||
- /^\d+\.\d+(\.\d+)?(-\S*)?$/
|
|
||||||
- /^release\//
|
|
||||||
|
|
||||||
language: php
|
|
||||||
os:
|
|
||||||
- linux
|
|
||||||
dist: xenial
|
|
||||||
|
|
||||||
# Test main supported versions of PHP against latest WP.
|
|
||||||
php:
|
|
||||||
- "7.0"
|
|
||||||
- "7.1"
|
|
||||||
- "7.2"
|
|
||||||
- "7.3"
|
|
||||||
- "7.4"
|
|
||||||
- "8.0"
|
|
||||||
|
|
||||||
env:
|
|
||||||
- WP_VERSION=latest WP_MULTISITE=0
|
|
||||||
|
|
||||||
# Additional tests against stable PHP (min version is 7.0)
|
|
||||||
# and code coverage report.
|
|
||||||
jobs:
|
|
||||||
fast_finish: true
|
|
||||||
include:
|
|
||||||
- name: "Core E2E Tests"
|
|
||||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_E2E=1
|
|
||||||
install:
|
|
||||||
- nvm install
|
|
||||||
- npm install
|
|
||||||
- composer install --no-dev
|
|
||||||
script:
|
|
||||||
- npm run build:assets
|
|
||||||
- npm run docker:up
|
|
||||||
- npm run test:e2e
|
|
||||||
after_script:
|
|
||||||
- npm run docker:down
|
|
||||||
- name: "WP Nightly"
|
|
||||||
php: "7.4"
|
|
||||||
env: WP_VERSION=nightly WP_MULTISITE=0
|
|
||||||
- name: "WP Latest - 1"
|
|
||||||
php: "7.2"
|
|
||||||
env: WP_VERSION=5.5 WP_MULTISITE=0
|
|
||||||
- name: "WP Latest - 2"
|
|
||||||
php: "7.2"
|
|
||||||
env: WP_VERSION=5.4 WP_MULTISITE=0
|
|
||||||
- name: "Code Standards"
|
|
||||||
php: "7.4"
|
|
||||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_PHPCS=1
|
|
||||||
- name: "Code Coverage"
|
|
||||||
php: "7.4"
|
|
||||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
|
|
||||||
allow_failures:
|
|
||||||
- php: "7.4"
|
|
||||||
env: WP_VERSION=latest WP_MULTISITE=0 RUN_CODE_COVERAGE=1
|
|
||||||
|
|
||||||
# Git clone depth
|
|
||||||
# By default Travis CI clones repositories to a depth of 50 commits. Using a depth of 1 makes this step a bit faster.
|
|
||||||
git:
|
|
||||||
depth: 1
|
|
||||||
|
|
||||||
# Since Xenial services are not started by default, we need to instruct it below to start.
|
|
||||||
services:
|
|
||||||
- mysql
|
|
||||||
- docker
|
|
||||||
|
|
||||||
cache:
|
|
||||||
directories:
|
|
||||||
- $HOME/.composer/cache
|
|
||||||
|
|
||||||
# Composer 2.0.7 introduced a change that broke the jetpack autoloader in PHP 7.0 - 7.3.
|
|
||||||
before_install:
|
|
||||||
- composer self-update 2.0.6
|
|
||||||
|
|
||||||
install:
|
|
||||||
- export PATH="$HOME/.composer/vendor/bin:$PATH"
|
|
||||||
- |
|
|
||||||
# Remove Xdebug for a huge performance increase:
|
|
||||||
if [ -f ~/.phpenv/versions/$(phpenv version-name)/etc/conf.d/xdebug.ini ]; then
|
|
||||||
phpenv config-rm xdebug.ini
|
|
||||||
else
|
|
||||||
echo "xdebug.ini does not exist"
|
|
||||||
fi
|
|
||||||
- composer install
|
|
||||||
- |
|
|
||||||
if [ "$(php -r "echo version_compare(PHP_VERSION,'8.0','>=');")" ]; then
|
|
||||||
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
|
|
||||||
unzip -d /tmp/phpunit-7.5-fork /tmp/phpunit-7.5-fork.zip
|
|
||||||
composer bin phpunit config --unset platform
|
|
||||||
composer bin phpunit config repositories.0 '{"type": "path", "url": "/tmp/phpunit-7.5-fork/phpunit-add-compatibility-with-php8-to-phpunit-7", "options": {"symlink": false}}'
|
|
||||||
composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-reqs
|
|
||||||
fi
|
|
||||||
- |
|
|
||||||
# Install WP Test suite:
|
|
||||||
if [[ ! -z "$WP_VERSION" ]]; then
|
|
||||||
bash tests/bin/install.sh woocommerce_test root '' localhost $WP_VERSION
|
|
||||||
fi
|
|
||||||
|
|
||||||
script:
|
|
||||||
- bash tests/bin/phpunit.sh
|
|
||||||
- bash tests/bin/phpcs.sh
|
|
||||||
|
|
||||||
after_script:
|
|
||||||
- bash tests/bin/travis.sh after
|
|
|
@ -5,7 +5,7 @@
|
||||||
<a href="https://packagist.org/packages/woocommerce/woocommerce"><img src="https://poser.pugx.org/woocommerce/woocommerce/v/stable" alt="Latest Stable Version"></a>
|
<a href="https://packagist.org/packages/woocommerce/woocommerce"><img src="https://poser.pugx.org/woocommerce/woocommerce/v/stable" alt="Latest Stable Version"></a>
|
||||||
<img src="https://img.shields.io/wordpress/plugin/dt/woocommerce.svg" alt="WordPress.org downloads">
|
<img src="https://img.shields.io/wordpress/plugin/dt/woocommerce.svg" alt="WordPress.org downloads">
|
||||||
<img src="https://img.shields.io/wordpress/plugin/r/woocommerce.svg" alt="WordPress.org rating">
|
<img src="https://img.shields.io/wordpress/plugin/r/woocommerce.svg" alt="WordPress.org rating">
|
||||||
<a href="https://travis-ci.com/woocommerce/woocommerce"><img src="https://travis-ci.com/woocommerce/woocommerce.svg?branch=trunk" alt="Build Status"></a>
|
<a href="https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml"><img src="https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml/badge.svg?branch=trunk" alt="Build Status"></a>
|
||||||
<a href="https://codecov.io/gh/woocommerce/woocommerce"><img src="https://codecov.io/gh/woocommerce/woocommerce/branch/trunk/graph/badge.svg" alt="codecov"></a>
|
<a href="https://codecov.io/gh/woocommerce/woocommerce"><img src="https://codecov.io/gh/woocommerce/woocommerce/branch/trunk/graph/badge.svg" alt="codecov"></a>
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
@ -35,3 +35,9 @@ Support requests in issues on this repository will be closed on sight.
|
||||||
|
|
||||||
## Contributing to WooCommerce
|
## Contributing to WooCommerce
|
||||||
If you have a patch or have stumbled upon an issue with WooCommerce core, you can contribute this back to the code. Please read our [contributor guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) for more information how you can do this.
|
If you have a patch or have stumbled upon an issue with WooCommerce core, you can contribute this back to the code. Please read our [contributor guidelines](https://github.com/woocommerce/woocommerce/blob/trunk/.github/CONTRIBUTING.md) for more information how you can do this.
|
||||||
|
|
||||||
|
<p align="center">
|
||||||
|
<br/><br/>
|
||||||
|
Made with 💜 by <a href="https://woocommerce.com/">WooCommerce</a>.<br/>
|
||||||
|
<a href="https://woocommerce.com/careers/">We're hiring</a>! Come work with us!
|
||||||
|
</p>
|
||||||
|
|
|
@ -348,6 +348,12 @@ a.button {
|
||||||
.woocommerce,
|
.woocommerce,
|
||||||
.woocommerce-page {
|
.woocommerce-page {
|
||||||
|
|
||||||
|
&.is-dark-theme {
|
||||||
|
.select2-dropdown {
|
||||||
|
color: var(--global--color-dark-gray);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table.shop_table {
|
table.shop_table {
|
||||||
|
|
||||||
td,
|
td,
|
||||||
|
@ -1312,6 +1318,30 @@ a.reset_variations {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
&.woocommerce-lost-password {
|
||||||
|
.woocommerce {
|
||||||
|
|
||||||
|
max-width: var(--responsive--alignwide-width) !important;
|
||||||
|
padding: 0 !important;
|
||||||
|
flex-wrap: wrap;
|
||||||
|
|
||||||
|
.woocommerce-notices-wrapper {
|
||||||
|
flex: 1 0 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.woocommerce-ResetPassword {
|
||||||
|
|
||||||
|
.woocommerce-form-row--first {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
#user_login {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table.account-orders-table {
|
table.account-orders-table {
|
||||||
margin-top: 0;
|
margin-top: 0;
|
||||||
border: 0;
|
border: 0;
|
||||||
|
@ -1433,6 +1463,11 @@ a.reset_variations {
|
||||||
}
|
}
|
||||||
|
|
||||||
.woocommerce-cart {
|
.woocommerce-cart {
|
||||||
|
table.woocommerce-cart-form__contents {
|
||||||
|
thead, tfoot {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.post-inner {
|
.post-inner {
|
||||||
padding-top: 0;
|
padding-top: 0;
|
||||||
|
@ -2123,6 +2158,10 @@ a.reset_variations {
|
||||||
|
|
||||||
.woocommerce-table--order-details {
|
.woocommerce-table--order-details {
|
||||||
margin-bottom: 2rem;
|
margin-bottom: 2rem;
|
||||||
|
|
||||||
|
thead, tfoot {
|
||||||
|
text-align: left;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2474,6 +2474,12 @@ a.reset_variations {
|
||||||
margin: 1.5rem 0;
|
margin: 1.5rem 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.woocommerce-ResetPassword {
|
||||||
|
.woocommerce-form-row--first {
|
||||||
|
float: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -72,6 +72,49 @@ jQuery( function( $ ) {
|
||||||
$( this ).selectWoo( select2_args ).addClass( 'enhanced' );
|
$( this ).selectWoo( select2_args ).addClass( 'enhanced' );
|
||||||
});
|
});
|
||||||
|
|
||||||
|
function display_result( self, select2_args ) {
|
||||||
|
select2_args = $.extend( select2_args, getEnhancedSelectFormatString() );
|
||||||
|
|
||||||
|
$( self ).selectWoo( select2_args ).addClass( 'enhanced' );
|
||||||
|
|
||||||
|
if ( $( self ).data( 'sortable' ) ) {
|
||||||
|
var $select = $(self);
|
||||||
|
var $list = $( self ).next( '.select2-container' ).find( 'ul.select2-selection__rendered' );
|
||||||
|
|
||||||
|
$list.sortable({
|
||||||
|
placeholder : 'ui-state-highlight select2-selection__choice',
|
||||||
|
forcePlaceholderSize: true,
|
||||||
|
items : 'li:not(.select2-search__field)',
|
||||||
|
tolerance : 'pointer',
|
||||||
|
stop: function() {
|
||||||
|
$( $list.find( '.select2-selection__choice' ).get().reverse() ).each( function() {
|
||||||
|
var id = $( self ).data( 'data' ).id;
|
||||||
|
var option = $select.find( 'option[value="' + id + '"]' )[0];
|
||||||
|
$select.prepend( option );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
});
|
||||||
|
// Keep multiselects ordered alphabetically if they are not sortable.
|
||||||
|
} else if ( $( self ).prop( 'multiple' ) ) {
|
||||||
|
$( self ).on( 'change', function(){
|
||||||
|
var $children = $( self ).children();
|
||||||
|
$children.sort(function(a, b){
|
||||||
|
var atext = a.text.toLowerCase();
|
||||||
|
var btext = b.text.toLowerCase();
|
||||||
|
|
||||||
|
if ( atext > btext ) {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
if ( atext < btext ) {
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
});
|
||||||
|
$( self ).html( $children );
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Ajax product search box
|
// Ajax product search box
|
||||||
$( ':input.wc-product-search' ).filter( ':not(.enhanced)' ).each( function() {
|
$( ':input.wc-product-search' ).filter( ':not(.enhanced)' ).each( function() {
|
||||||
var select2_args = {
|
var select2_args = {
|
||||||
|
@ -112,46 +155,48 @@ jQuery( function( $ ) {
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
select2_args = $.extend( select2_args, getEnhancedSelectFormatString() );
|
display_result( this, select2_args );
|
||||||
|
});
|
||||||
|
|
||||||
|
// Ajax Page Search.
|
||||||
|
$( ':input.wc-page-search' ).filter( ':not(.enhanced)' ).each( function() {
|
||||||
|
var select2_args = {
|
||||||
|
allowClear: $( this ).data( 'allow_clear' ) ? true : false,
|
||||||
|
placeholder: $( this ).data( 'placeholder' ),
|
||||||
|
minimumInputLength: $( this ).data( 'minimum_input_length' ) ? $( this ).data( 'minimum_input_length' ) : '3',
|
||||||
|
escapeMarkup: function( m ) {
|
||||||
|
return m;
|
||||||
|
},
|
||||||
|
ajax: {
|
||||||
|
url: wc_enhanced_select_params.ajax_url,
|
||||||
|
dataType: 'json',
|
||||||
|
delay: 250,
|
||||||
|
data: function( params ) {
|
||||||
|
return {
|
||||||
|
term : params.term,
|
||||||
|
action : $( this ).data( 'action' ) || 'woocommerce_json_search_pages',
|
||||||
|
security : wc_enhanced_select_params.search_pages_nonce,
|
||||||
|
exclude : $( this ).data( 'exclude' ),
|
||||||
|
post_status : $( this ).data( 'post_status' ),
|
||||||
|
limit : $( this ).data( 'limit' ),
|
||||||
|
};
|
||||||
|
},
|
||||||
|
processResults: function( data ) {
|
||||||
|
var terms = [];
|
||||||
|
if ( data ) {
|
||||||
|
$.each( data, function( id, text ) {
|
||||||
|
terms.push( { id: id, text: text } );
|
||||||
|
} );
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
results: terms
|
||||||
|
};
|
||||||
|
},
|
||||||
|
cache: true
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
$( this ).selectWoo( select2_args ).addClass( 'enhanced' );
|
$( this ).selectWoo( select2_args ).addClass( 'enhanced' );
|
||||||
|
|
||||||
if ( $( this ).data( 'sortable' ) ) {
|
|
||||||
var $select = $(this);
|
|
||||||
var $list = $( this ).next( '.select2-container' ).find( 'ul.select2-selection__rendered' );
|
|
||||||
|
|
||||||
$list.sortable({
|
|
||||||
placeholder : 'ui-state-highlight select2-selection__choice',
|
|
||||||
forcePlaceholderSize: true,
|
|
||||||
items : 'li:not(.select2-search__field)',
|
|
||||||
tolerance : 'pointer',
|
|
||||||
stop: function() {
|
|
||||||
$( $list.find( '.select2-selection__choice' ).get().reverse() ).each( function() {
|
|
||||||
var id = $( this ).data( 'data' ).id;
|
|
||||||
var option = $select.find( 'option[value="' + id + '"]' )[0];
|
|
||||||
$select.prepend( option );
|
|
||||||
} );
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Keep multiselects ordered alphabetically if they are not sortable.
|
|
||||||
} else if ( $( this ).prop( 'multiple' ) ) {
|
|
||||||
$( this ).on( 'change', function(){
|
|
||||||
var $children = $( this ).children();
|
|
||||||
$children.sort(function(a, b){
|
|
||||||
var atext = a.text.toLowerCase();
|
|
||||||
var btext = b.text.toLowerCase();
|
|
||||||
|
|
||||||
if ( atext > btext ) {
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
if ( atext < btext ) {
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
return 0;
|
|
||||||
});
|
|
||||||
$( this ).html( $children );
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
});
|
||||||
|
|
||||||
// Ajax customer search boxes
|
// Ajax customer search boxes
|
||||||
|
|
|
@ -62,6 +62,9 @@
|
||||||
shippingMethod.trigger( 'change:methods' );
|
shippingMethod.trigger( 'change:methods' );
|
||||||
shippingMethod.changes = {};
|
shippingMethod.changes = {};
|
||||||
shippingMethod.trigger( 'saved:methods' );
|
shippingMethod.trigger( 'saved:methods' );
|
||||||
|
|
||||||
|
// Overrides the onbeforeunload callback added by settings.js.
|
||||||
|
window.onbeforeunload = null;
|
||||||
} else {
|
} else {
|
||||||
window.alert( data.strings.save_failed );
|
window.alert( data.strings.save_failed );
|
||||||
}
|
}
|
||||||
|
|
|
@ -57,6 +57,28 @@ jQuery( function( $ ) {
|
||||||
$node.removeClass( 'processing' ).unblock();
|
$node.removeClass( 'processing' ).unblock();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Removes duplicate notices.
|
||||||
|
*
|
||||||
|
* @param {JQuery Object} notices
|
||||||
|
*/
|
||||||
|
var remove_duplicate_notices = function( notices ) {
|
||||||
|
var seen = [];
|
||||||
|
var new_notices = notices;
|
||||||
|
|
||||||
|
notices.each( function( index ) {
|
||||||
|
var text = $( this ).text();
|
||||||
|
|
||||||
|
if ( 'undefined' === typeof seen[ text ] ) {
|
||||||
|
seen[ text ] = true;
|
||||||
|
} else {
|
||||||
|
new_notices.splice( index, 1 );
|
||||||
|
}
|
||||||
|
} );
|
||||||
|
|
||||||
|
return new_notices;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update the .woocommerce div with a string of html.
|
* Update the .woocommerce div with a string of html.
|
||||||
*
|
*
|
||||||
|
@ -67,7 +89,7 @@ jQuery( function( $ ) {
|
||||||
var $html = $.parseHTML( html_str );
|
var $html = $.parseHTML( html_str );
|
||||||
var $new_form = $( '.woocommerce-cart-form', $html );
|
var $new_form = $( '.woocommerce-cart-form', $html );
|
||||||
var $new_totals = $( '.cart_totals', $html );
|
var $new_totals = $( '.cart_totals', $html );
|
||||||
var $notices = $( '.woocommerce-error, .woocommerce-message, .woocommerce-info', $html );
|
var $notices = remove_duplicate_notices( $( '.woocommerce-error, .woocommerce-message, .woocommerce-info', $html ) );
|
||||||
|
|
||||||
// No form, cannot do this.
|
// No form, cannot do this.
|
||||||
if ( $( '.woocommerce-cart-form' ).length === 0 ) {
|
if ( $( '.woocommerce-cart-form' ).length === 0 ) {
|
||||||
|
|
|
@ -1,5 +1,15 @@
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 5.2.0 RC 2021-03-30 =
|
||||||
|
|
||||||
|
* Update - WooCommerce Admin package 2.1.4. #29520
|
||||||
|
* Fix - Don't remove existing coupons from order when an invalid REST API request for updating coupons is submitted. #29474
|
||||||
|
* Fix - Wrong logic for including or excluding the payments step in the list of completed tasks in the onboarding wizard. #29518
|
||||||
|
|
||||||
|
**WooCommerce Admin - 2.1.4**
|
||||||
|
|
||||||
|
* Fix - Adding New Zealand and Ireland to selective bundle option, previously missed. #6649
|
||||||
|
|
||||||
= 5.2.0 beta 2021-03-23 =
|
= 5.2.0 beta 2021-03-23 =
|
||||||
|
|
||||||
**WooCommerce**
|
**WooCommerce**
|
||||||
|
@ -42,6 +52,8 @@
|
||||||
* Fix - add validation of the posted country codes on checkout. #28849
|
* Fix - add validation of the posted country codes on checkout. #28849
|
||||||
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
||||||
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
||||||
|
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||||
|
* Fix - Revert a replacement of wp_redirect to wp_safe_redirect in WC_Checkout::process_order_payment that caused issues in the default PayPal interface. #29459
|
||||||
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
||||||
* Tweak - Update the contributor guidelines. #29150
|
* Tweak - Update the contributor guidelines. #29150
|
||||||
* Tweak - Introduced phone number input validation. #27242
|
* Tweak - Introduced phone number input validation. #27242
|
||||||
|
@ -1342,6 +1354,7 @@
|
||||||
* Fix - Don't show duplicated update notifications on Woo Screens. #25828
|
* Fix - Don't show duplicated update notifications on Woo Screens. #25828
|
||||||
* Fix - Escape MaxMind database URL. #25682
|
* Fix - Escape MaxMind database URL. #25682
|
||||||
* Fix - System status report should correctly identify inactive package. #25830
|
* Fix - System status report should correctly identify inactive package. #25830
|
||||||
|
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||||
* Dev - Added support for placeholder attribute in quantity inputs. #25418
|
* Dev - Added support for placeholder attribute in quantity inputs. #25418
|
||||||
* Dev - Added `tax_status` and `tax_class` columns to the product meta data lookup table. #25428
|
* Dev - Added `tax_status` and `tax_class` columns to the product meta data lookup table. #25428
|
||||||
* Dev - Introduced `woocommerce_top_rated_widget_args` filter. #25320
|
* Dev - Introduced `woocommerce_top_rated_widget_args` filter. #25320
|
||||||
|
|
|
@ -14,14 +14,14 @@
|
||||||
],
|
],
|
||||||
"require": {
|
"require": {
|
||||||
"php": ">=7.0",
|
"php": ">=7.0",
|
||||||
"automattic/jetpack-autoloader": "2.9.1",
|
"automattic/jetpack-autoloader": "2.10.1",
|
||||||
"automattic/jetpack-constants": "1.5.1",
|
"automattic/jetpack-constants": "1.5.1",
|
||||||
"composer/installers": "~1.7",
|
"composer/installers": "~1.7",
|
||||||
"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.1.6",
|
"woocommerce/action-scheduler": "3.1.6",
|
||||||
"woocommerce/woocommerce-admin": "2.1.3",
|
"woocommerce/woocommerce-admin": "2.1.4",
|
||||||
"woocommerce/woocommerce-blocks": "4.7.0"
|
"woocommerce/woocommerce-blocks": "4.7.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
|
|
@ -4,32 +4,39 @@
|
||||||
"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": "dc5e21e29d4fb70bba776d20112c74f0",
|
"content-hash": "b1d6d94c8cfae572ab27c288c6865787",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "automattic/jetpack-autoloader",
|
"name": "automattic/jetpack-autoloader",
|
||||||
"version": "v2.9.1",
|
"version": "2.10.1",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/Automattic/jetpack-autoloader.git",
|
"url": "https://github.com/Automattic/jetpack-autoloader.git",
|
||||||
"reference": "d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88"
|
"reference": "20393c4677765c3e737dcb5aee7a3f7b90dce4b3"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88",
|
"url": "https://api.github.com/repos/Automattic/jetpack-autoloader/zipball/20393c4677765c3e737dcb5aee7a3f7b90dce4b3",
|
||||||
"reference": "d6ca2cc26ad6963e1be19b3338a9e98f40d9bd88",
|
"reference": "20393c4677765c3e737dcb5aee7a3f7b90dce4b3",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"composer-plugin-api": "^1.1 || ^2.0"
|
"composer-plugin-api": "^1.1 || ^2.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
|
"automattic/jetpack-changelogger": "^1.1",
|
||||||
"yoast/phpunit-polyfills": "0.2.0"
|
"yoast/phpunit-polyfills": "0.2.0"
|
||||||
},
|
},
|
||||||
"type": "composer-plugin",
|
"type": "composer-plugin",
|
||||||
"extra": {
|
"extra": {
|
||||||
"class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin",
|
"class": "Automattic\\Jetpack\\Autoloader\\CustomAutoloaderPlugin",
|
||||||
"mirror-repo": "Automattic/jetpack-autoloader"
|
"mirror-repo": "Automattic/jetpack-autoloader",
|
||||||
|
"changelogger": {
|
||||||
|
"link-template": "https://github.com/Automattic/jetpack-autoloader/compare/v${old}...v${new}"
|
||||||
|
},
|
||||||
|
"branch-alias": {
|
||||||
|
"dev-master": "2.10.x-dev"
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"autoload": {
|
"autoload": {
|
||||||
"classmap": [
|
"classmap": [
|
||||||
|
@ -45,9 +52,9 @@
|
||||||
],
|
],
|
||||||
"description": "Creates a custom autoloader for a plugin or theme.",
|
"description": "Creates a custom autoloader for a plugin or theme.",
|
||||||
"support": {
|
"support": {
|
||||||
"source": "https://github.com/Automattic/jetpack-autoloader/tree/v2.9.1"
|
"source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1"
|
||||||
},
|
},
|
||||||
"time": "2021-02-05T19:07:06+00:00"
|
"time": "2021-03-30T15:15:59+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "automattic/jetpack-constants",
|
"name": "automattic/jetpack-constants",
|
||||||
|
@ -523,16 +530,16 @@
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "woocommerce/woocommerce-admin",
|
"name": "woocommerce/woocommerce-admin",
|
||||||
"version": "2.1.3",
|
"version": "2.1.4",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/woocommerce/woocommerce-admin.git",
|
"url": "https://github.com/woocommerce/woocommerce-admin.git",
|
||||||
"reference": "60f4297838569341ae88738a4a8a8090889faaac"
|
"reference": "f992b8c8664e72b00ee7283ba1d34e74e4b67ab0"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/60f4297838569341ae88738a4a8a8090889faaac",
|
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/f992b8c8664e72b00ee7283ba1d34e74e4b67ab0",
|
||||||
"reference": "60f4297838569341ae88738a4a8a8090889faaac",
|
"reference": "f992b8c8664e72b00ee7283ba1d34e74e4b67ab0",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
|
@ -566,9 +573,9 @@
|
||||||
"homepage": "https://github.com/woocommerce/woocommerce-admin",
|
"homepage": "https://github.com/woocommerce/woocommerce-admin",
|
||||||
"support": {
|
"support": {
|
||||||
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
|
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
|
||||||
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.1.3"
|
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.1.4"
|
||||||
},
|
},
|
||||||
"time": "2021-03-15T04:42:40+00:00"
|
"time": "2021-03-29T11:59:33+00:00"
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
"name": "woocommerce/woocommerce-blocks",
|
"name": "woocommerce/woocommerce-blocks",
|
||||||
|
|
|
@ -1633,6 +1633,7 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
$saved_rate_ids[] = $tax->get_rate_id();
|
$saved_rate_ids[] = $tax->get_rate_id();
|
||||||
|
$tax->set_rate( $tax->get_rate_id() );
|
||||||
$tax->set_tax_total( isset( $cart_taxes[ $tax->get_rate_id() ] ) ? $cart_taxes[ $tax->get_rate_id() ] : 0 );
|
$tax->set_tax_total( isset( $cart_taxes[ $tax->get_rate_id() ] ) ? $cart_taxes[ $tax->get_rate_id() ] : 0 );
|
||||||
$tax->set_label( WC_Tax::get_rate_label( $tax->get_rate_id() ) );
|
$tax->set_label( WC_Tax::get_rate_label( $tax->get_rate_id() ) );
|
||||||
$tax->set_shipping_tax_total( ! empty( $shipping_taxes[ $tax->get_rate_id() ] ) ? $shipping_taxes[ $tax->get_rate_id() ] : 0 );
|
$tax->set_shipping_tax_total( ! empty( $shipping_taxes[ $tax->get_rate_id() ] ) ? $shipping_taxes[ $tax->get_rate_id() ] : 0 );
|
||||||
|
|
|
@ -696,6 +696,7 @@ abstract class WC_Settings_API {
|
||||||
);
|
);
|
||||||
|
|
||||||
$data = wp_parse_args( $data, $defaults );
|
$data = wp_parse_args( $data, $defaults );
|
||||||
|
$value = $this->get_option( $key );
|
||||||
|
|
||||||
ob_start();
|
ob_start();
|
||||||
?>
|
?>
|
||||||
|
@ -708,7 +709,15 @@ abstract class WC_Settings_API {
|
||||||
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
|
<legend class="screen-reader-text"><span><?php echo wp_kses_post( $data['title'] ); ?></span></legend>
|
||||||
<select class="select <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
|
<select class="select <?php echo esc_attr( $data['class'] ); ?>" name="<?php echo esc_attr( $field_key ); ?>" id="<?php echo esc_attr( $field_key ); ?>" style="<?php echo esc_attr( $data['css'] ); ?>" <?php disabled( $data['disabled'], true ); ?> <?php echo $this->get_custom_attribute_html( $data ); // WPCS: XSS ok. ?>>
|
||||||
<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
|
<?php foreach ( (array) $data['options'] as $option_key => $option_value ) : ?>
|
||||||
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( (string) $option_key, esc_attr( $this->get_option( $key ) ) ); ?>><?php echo esc_html( $option_value ); ?></option>
|
<?php if ( is_array( $option_value ) ) : ?>
|
||||||
|
<optgroup label="<?php echo esc_attr( $option_key ); ?>">
|
||||||
|
<?php foreach ( $option_value as $option_key_inner => $option_value_inner ) : ?>
|
||||||
|
<option value="<?php echo esc_attr( $option_key_inner ); ?>" <?php selected( (string) $option_key_inner, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value_inner ); ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</optgroup>
|
||||||
|
<?php else : ?>
|
||||||
|
<option value="<?php echo esc_attr( $option_key ); ?>" <?php selected( (string) $option_key, esc_attr( $value ) ); ?>><?php echo esc_html( $option_value ); ?></option>
|
||||||
|
<?php endif; ?>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
</select>
|
</select>
|
||||||
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
|
<?php echo $this->get_description_html( $data ); // WPCS: XSS ok. ?>
|
||||||
|
|
|
@ -145,6 +145,7 @@ if ( ! class_exists( 'WC_Admin_Assets', false ) ) :
|
||||||
'search_products_nonce' => wp_create_nonce( 'search-products' ),
|
'search_products_nonce' => wp_create_nonce( 'search-products' ),
|
||||||
'search_customers_nonce' => wp_create_nonce( 'search-customers' ),
|
'search_customers_nonce' => wp_create_nonce( 'search-customers' ),
|
||||||
'search_categories_nonce' => wp_create_nonce( 'search-categories' ),
|
'search_categories_nonce' => wp_create_nonce( 'search-categories' ),
|
||||||
|
'search_pages_nonce' => wp_create_nonce( 'search-pages' ),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -178,7 +178,7 @@ if ( ! class_exists( 'WC_Admin_Dashboard_Setup', false ) ) :
|
||||||
}
|
}
|
||||||
|
|
||||||
// payments can't be used when woocommerce-payments exists and country is US.
|
// payments can't be used when woocommerce-payments exists and country is US.
|
||||||
if ( $is_woo_payment_installed || 'US' === $country ) {
|
if ( $is_woo_payment_installed && 'US' === $country ) {
|
||||||
unset( $this->tasks['payments'] );
|
unset( $this->tasks['payments'] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -579,6 +579,47 @@ if ( ! class_exists( 'WC_Admin_Settings', false ) ) :
|
||||||
<?php
|
<?php
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'single_select_page_with_search':
|
||||||
|
$option_value = $value['value'];
|
||||||
|
$page = get_post( $option_value );
|
||||||
|
|
||||||
|
if ( ! is_null( $page ) ) {
|
||||||
|
$page = get_post( $option_value );
|
||||||
|
$option_display_name = sprintf(
|
||||||
|
/* translators: 1: page name 2: page ID */
|
||||||
|
__( '%1$s (ID: %2$s)', 'woocommerce' ),
|
||||||
|
$page->post_title,
|
||||||
|
$option_value
|
||||||
|
);
|
||||||
|
}
|
||||||
|
?>
|
||||||
|
<tr valign="top" class="single_select_page">
|
||||||
|
<th scope="row" class="titledesc">
|
||||||
|
<label for="<?php echo esc_attr( $value['id'] ); ?>"><?php echo esc_html( $value['title'] ); ?> <?php echo $tooltip_html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></label>
|
||||||
|
</th>
|
||||||
|
<td class="forminp forminp-<?php echo esc_attr( sanitize_title( $value['type'] ) ); ?>">
|
||||||
|
<select
|
||||||
|
name="<?php echo esc_attr( $value['id'] ); ?>"
|
||||||
|
id="<?php echo esc_attr( $value['id'] ); ?>"
|
||||||
|
style="<?php echo esc_attr( $value['css'] ); ?>"
|
||||||
|
class="<?php echo esc_attr( $value['class'] ); ?>"
|
||||||
|
<?php echo implode( ' ', $custom_attributes ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
|
data-placeholder="<?php esc_attr_e( 'Search for a page…', 'woocommerce' ); ?>"
|
||||||
|
data-allow_clear="true"
|
||||||
|
data-exclude="<?php echo wc_esc_json( wp_json_encode( $value['args']['exclude'] ) ); ?>"
|
||||||
|
>
|
||||||
|
<option value=""></option>
|
||||||
|
<?php if ( ! is_null( $page ) ) { ?>
|
||||||
|
<option value="<?php echo esc_attr( $option_value ); ?>" selected="selected">
|
||||||
|
<?php echo wp_strip_all_tags( $option_display_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
|
</option>
|
||||||
|
<?php } ?>
|
||||||
|
</select> <?php echo $description; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
break;
|
||||||
|
|
||||||
// Single country selects.
|
// Single country selects.
|
||||||
case 'single_select_country':
|
case 'single_select_country':
|
||||||
$country_setting = (string) $value['value'];
|
$country_setting = (string) $value['value'];
|
||||||
|
|
|
@ -15,7 +15,7 @@ if ( class_exists( 'WC_Admin_List_Table_Orders', false ) ) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
|
if ( ! class_exists( 'WC_Admin_List_Table', false ) ) {
|
||||||
include_once __DIR__ . '/abstract-class-wc-admin-list-table.php';
|
include_once __DIR__ . '/abstract-class-wc-admin-list-table.php';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -765,7 +765,7 @@ class WC_Admin_List_Table_Orders extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
?>
|
?>
|
||||||
<select class="wc-customer-search" name="_customer_user" data-placeholder="<?php esc_attr_e( 'Filter by registered customer', 'woocommerce' ); ?>" data-allow_clear="true">
|
<select class="wc-customer-search" name="_customer_user" data-placeholder="<?php esc_attr_e( 'Filter by registered customer', 'woocommerce' ); ?>" data-allow_clear="true">
|
||||||
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo htmlspecialchars( wp_kses_post( $user_string ) ); // htmlspecialchars to prevent XSS when rendered by selectWoo. ?><option>
|
<option value="<?php echo esc_attr( $user_id ); ?>" selected="selected"><?php echo htmlspecialchars( wp_kses_post( $user_string ) ); // htmlspecialchars to prevent XSS when rendered by selectWoo. ?></option>
|
||||||
</select>
|
</select>
|
||||||
<?php
|
<?php
|
||||||
}
|
}
|
||||||
|
|
|
@ -148,7 +148,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: thumb.
|
* Render column: thumb.
|
||||||
*/
|
*/
|
||||||
protected function render_thumb_column() {
|
protected function render_thumb_column() {
|
||||||
echo '<a href="' . esc_url( get_edit_post_link( $this->object->get_id() ) ) . '">' . $this->object->get_image( 'thumbnail' ) . '</a>'; // WPCS: XSS ok.
|
echo '<a href="' . esc_url( get_edit_post_link( $this->object->get_id() ) ) . '">' . $this->object->get_image( 'thumbnail' ) . '</a>'; // WPCS: XSS ok.
|
||||||
|
@ -203,21 +203,21 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: sku.
|
* Render column: sku.
|
||||||
*/
|
*/
|
||||||
protected function render_sku_column() {
|
protected function render_sku_column() {
|
||||||
echo $this->object->get_sku() ? esc_html( $this->object->get_sku() ) : '<span class="na">–</span>';
|
echo $this->object->get_sku() ? esc_html( $this->object->get_sku() ) : '<span class="na">–</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: price.
|
* Render column: price.
|
||||||
*/
|
*/
|
||||||
protected function render_price_column() {
|
protected function render_price_column() {
|
||||||
echo $this->object->get_price_html() ? wp_kses_post( $this->object->get_price_html() ) : '<span class="na">–</span>';
|
echo $this->object->get_price_html() ? wp_kses_post( $this->object->get_price_html() ) : '<span class="na">–</span>';
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: product_cat.
|
* Render column: product_cat.
|
||||||
*/
|
*/
|
||||||
protected function render_product_cat_column() {
|
protected function render_product_cat_column() {
|
||||||
$terms = get_the_terms( $this->object->get_id(), 'product_cat' );
|
$terms = get_the_terms( $this->object->get_id(), 'product_cat' );
|
||||||
|
@ -234,7 +234,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: product_tag.
|
* Render column: product_tag.
|
||||||
*/
|
*/
|
||||||
protected function render_product_tag_column() {
|
protected function render_product_tag_column() {
|
||||||
$terms = get_the_terms( $this->object->get_id(), 'product_tag' );
|
$terms = get_the_terms( $this->object->get_id(), 'product_tag' );
|
||||||
|
@ -251,7 +251,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: featured.
|
* Render column: featured.
|
||||||
*/
|
*/
|
||||||
protected function render_featured_column() {
|
protected function render_featured_column() {
|
||||||
$url = wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_feature_product&product_id=' . $this->object->get_id() ), 'woocommerce-feature-product' );
|
$url = wp_nonce_url( admin_url( 'admin-ajax.php?action=woocommerce_feature_product&product_id=' . $this->object->get_id() ), 'woocommerce-feature-product' );
|
||||||
|
@ -265,7 +265,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Render columm: is_in_stock.
|
* Render column: is_in_stock.
|
||||||
*/
|
*/
|
||||||
protected function render_is_in_stock_column() {
|
protected function render_is_in_stock_column() {
|
||||||
if ( $this->object->is_on_backorder() ) {
|
if ( $this->object->is_on_backorder() ) {
|
||||||
|
@ -337,7 +337,7 @@ class WC_Admin_List_Table_Products extends WC_Admin_List_Table {
|
||||||
?>
|
?>
|
||||||
<select class="wc-category-search" name="product_cat" data-placeholder="<?php esc_attr_e( 'Filter by category', 'woocommerce' ); ?>" data-allow_clear="true">
|
<select class="wc-category-search" name="product_cat" data-placeholder="<?php esc_attr_e( 'Filter by category', 'woocommerce' ); ?>" data-allow_clear="true">
|
||||||
<?php if ( $current_category_slug && $current_category ) : ?>
|
<?php if ( $current_category_slug && $current_category ) : ?>
|
||||||
<option value="<?php echo esc_attr( $current_category_slug ); ?>" selected="selected"><?php echo esc_html( htmlspecialchars( wp_kses_post( $current_category->name ) ) ); ?><option>
|
<option value="<?php echo esc_attr( $current_category_slug ); ?>" selected="selected"><?php echo esc_html( htmlspecialchars( wp_kses_post( $current_category->name ) ) ); ?></option>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</select>
|
</select>
|
||||||
<?php
|
<?php
|
||||||
|
|
|
@ -74,9 +74,9 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||||
/* Translators: %s Page contents. */
|
/* Translators: %s Page contents. */
|
||||||
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) ),
|
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_cart_shortcode_tag', 'woocommerce_cart' ) ),
|
||||||
'id' => 'woocommerce_cart_page_id',
|
'id' => 'woocommerce_cart_page_id',
|
||||||
'type' => 'single_select_page',
|
'type' => 'single_select_page_with_search',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'class' => 'wc-enhanced-select-nostd',
|
'class' => 'wc-page-search',
|
||||||
'css' => 'min-width:300px;',
|
'css' => 'min-width:300px;',
|
||||||
'args' => array(
|
'args' => array(
|
||||||
'exclude' =>
|
'exclude' =>
|
||||||
|
@ -94,9 +94,9 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||||
/* Translators: %s Page contents. */
|
/* Translators: %s Page contents. */
|
||||||
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) ),
|
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_checkout_shortcode_tag', 'woocommerce_checkout' ) ),
|
||||||
'id' => 'woocommerce_checkout_page_id',
|
'id' => 'woocommerce_checkout_page_id',
|
||||||
'type' => 'single_select_page',
|
'type' => 'single_select_page_with_search',
|
||||||
'default' => '',
|
'default' => wc_get_page_id( 'checkout' ),
|
||||||
'class' => 'wc-enhanced-select-nostd',
|
'class' => 'wc-page-search',
|
||||||
'css' => 'min-width:300px;',
|
'css' => 'min-width:300px;',
|
||||||
'args' => array(
|
'args' => array(
|
||||||
'exclude' =>
|
'exclude' =>
|
||||||
|
@ -114,9 +114,9 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||||
/* Translators: %s Page contents. */
|
/* Translators: %s Page contents. */
|
||||||
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) ),
|
'desc' => sprintf( __( 'Page contents: [%s]', 'woocommerce' ), apply_filters( 'woocommerce_my_account_shortcode_tag', 'woocommerce_my_account' ) ),
|
||||||
'id' => 'woocommerce_myaccount_page_id',
|
'id' => 'woocommerce_myaccount_page_id',
|
||||||
'type' => 'single_select_page',
|
'type' => 'single_select_page_with_search',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'class' => 'wc-enhanced-select-nostd',
|
'class' => 'wc-page-search',
|
||||||
'css' => 'min-width:300px;',
|
'css' => 'min-width:300px;',
|
||||||
'args' => array(
|
'args' => array(
|
||||||
'exclude' =>
|
'exclude' =>
|
||||||
|
@ -134,9 +134,9 @@ class WC_Settings_Advanced extends WC_Settings_Page {
|
||||||
'desc' => __( 'If you define a "Terms" page the customer will be asked if they accept them when checking out.', 'woocommerce' ),
|
'desc' => __( 'If you define a "Terms" page the customer will be asked if they accept them when checking out.', 'woocommerce' ),
|
||||||
'id' => 'woocommerce_terms_page_id',
|
'id' => 'woocommerce_terms_page_id',
|
||||||
'default' => '',
|
'default' => '',
|
||||||
'class' => 'wc-enhanced-select-nostd',
|
'class' => 'wc-page-search',
|
||||||
'css' => 'min-width:300px;',
|
'css' => 'min-width:300px;',
|
||||||
'type' => 'single_select_page',
|
'type' => 'single_select_page_with_search',
|
||||||
'args' => array( 'exclude' => wc_get_page_id( 'checkout' ) ),
|
'args' => array( 'exclude' => wc_get_page_id( 'checkout' ) ),
|
||||||
'desc_tip' => true,
|
'desc_tip' => true,
|
||||||
'autoload' => false,
|
'autoload' => false,
|
||||||
|
|
|
@ -207,6 +207,10 @@ class WC_Settings_Emails extends WC_Settings_Page {
|
||||||
'autoload' => false,
|
'autoload' => false,
|
||||||
),
|
),
|
||||||
|
|
||||||
|
array(
|
||||||
|
'type' => 'sectionend',
|
||||||
|
'id' => 'email_merchant_notes',
|
||||||
|
),
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
|
@ -2,17 +2,13 @@
|
||||||
/**
|
/**
|
||||||
* WooCommerce Integration Settings
|
* WooCommerce Integration Settings
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
* @package WooCommerce\Admin
|
||||||
* @category Admin
|
* @version 2.1.0
|
||||||
* @package WooCommerce\Admin
|
|
||||||
* @version 2.1.0
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
use Automattic\Jetpack\Constants;
|
use Automattic\Jetpack\Constants;
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
defined( 'ABSPATH' ) || exit;
|
||||||
exit; // Exit if accessed directly
|
|
||||||
}
|
|
||||||
|
|
||||||
if ( ! class_exists( 'WC_Settings_Integrations', false ) ) :
|
if ( ! class_exists( 'WC_Settings_Integrations', false ) ) :
|
||||||
|
|
||||||
|
@ -50,7 +46,7 @@ if ( ! class_exists( 'WC_Settings_Integrations', false ) ) :
|
||||||
$current_section = current( $integrations )->id;
|
$current_section = current( $integrations )->id;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( sizeof( $integrations ) > 1 ) {
|
if ( count( $integrations ) > 1 ) {
|
||||||
foreach ( $integrations as $integration ) {
|
foreach ( $integrations as $integration ) {
|
||||||
$title = empty( $integration->method_title ) ? ucfirst( $integration->id ) : $integration->method_title;
|
$title = empty( $integration->method_title ) ? ucfirst( $integration->id ) : $integration->method_title;
|
||||||
$sections[ strtolower( $integration->id ) ] = esc_html( $title );
|
$sections[ strtolower( $integration->id ) ] = esc_html( $title );
|
||||||
|
|
|
@ -2,14 +2,12 @@
|
||||||
/**
|
/**
|
||||||
* WooCommerce Settings Page/Tab
|
* WooCommerce Settings Page/Tab
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
|
||||||
* @category Admin
|
|
||||||
* @package WooCommerce\Admin
|
* @package WooCommerce\Admin
|
||||||
* @version 2.1.0
|
* @version 2.1.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit; // Exit if accessed directly
|
exit; // Exit if accessed directly.
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
||||||
|
@ -66,7 +64,7 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
||||||
/**
|
/**
|
||||||
* Add this page to settings.
|
* Add this page to settings.
|
||||||
*
|
*
|
||||||
* @param array $pages
|
* @param array $pages The pages array to add this page to.
|
||||||
*
|
*
|
||||||
* @return mixed
|
* @return mixed
|
||||||
*/
|
*/
|
||||||
|
@ -102,7 +100,7 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
||||||
|
|
||||||
$sections = $this->get_sections();
|
$sections = $this->get_sections();
|
||||||
|
|
||||||
if ( empty( $sections ) || 1 === sizeof( $sections ) ) {
|
if ( empty( $sections ) || 1 === count( $sections ) ) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -111,7 +109,8 @@ if ( ! class_exists( 'WC_Settings_Page', false ) ) :
|
||||||
$array_keys = array_keys( $sections );
|
$array_keys = array_keys( $sections );
|
||||||
|
|
||||||
foreach ( $sections as $id => $label ) {
|
foreach ( $sections as $id => $label ) {
|
||||||
echo '<li><a href="' . admin_url( 'admin.php?page=wc-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) . '" class="' . ( $current_section == $id ? 'current' : '' ) . '">' . $label . '</a> ' . ( end( $array_keys ) == $id ? '' : '|' ) . ' </li>';
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
echo '<li><a href="' . admin_url( 'admin.php?page=wc-settings&tab=' . $this->id . '§ion=' . sanitize_title( $id ) ) . '" class="' . ( $current_section === $id ? 'current' : '' ) . '">' . esc_html( $label ) . '</a> ' . ( end( $array_keys ) === $id ? '' : '|' ) . ' </li>';
|
||||||
}
|
}
|
||||||
|
|
||||||
echo '</ul><br class="clear" />';
|
echo '</ul><br class="clear" />';
|
||||||
|
|
|
@ -2,8 +2,6 @@
|
||||||
/**
|
/**
|
||||||
* WooCommerce Tax Settings
|
* WooCommerce Tax Settings
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
|
||||||
* @category Admin
|
|
||||||
* @package WooCommerce\Admin
|
* @package WooCommerce\Admin
|
||||||
* @version 2.1.0
|
* @version 2.1.0
|
||||||
*/
|
*/
|
||||||
|
@ -66,6 +64,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
$tax_classes = WC_Tax::get_tax_classes();
|
$tax_classes = WC_Tax::get_tax_classes();
|
||||||
|
|
||||||
foreach ( $tax_classes as $class ) {
|
foreach ( $tax_classes as $class ) {
|
||||||
|
/* translators: $s tax rate section name */
|
||||||
$sections[ sanitize_title( $class ) ] = sprintf( __( '%s rates', 'woocommerce' ), $class );
|
$sections[ sanitize_title( $class ) ] = sprintf( __( '%s rates', 'woocommerce' ), $class );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -95,7 +94,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
|
|
||||||
$tax_classes = WC_Tax::get_tax_class_slugs();
|
$tax_classes = WC_Tax::get_tax_class_slugs();
|
||||||
|
|
||||||
if ( 'standard' === $current_section || in_array( $current_section, $tax_classes, true ) ) {
|
if ( 'standard' === $current_section || in_array( $current_section, array_filter( $tax_classes ), true ) ) {
|
||||||
$this->output_tax_rates();
|
$this->output_tax_rates();
|
||||||
} else {
|
} else {
|
||||||
$settings = $this->get_settings();
|
$settings = $this->get_settings();
|
||||||
|
@ -149,7 +148,19 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( $added as $name ) {
|
foreach ( $added as $name ) {
|
||||||
WC_Tax::create_tax_class( $name );
|
$tax_class = WC_Tax::create_tax_class( $name );
|
||||||
|
|
||||||
|
// Display any error that could be triggered while creating tax classes.
|
||||||
|
if ( is_wp_error( $tax_class ) ) {
|
||||||
|
WC_Admin_Settings::add_error(
|
||||||
|
sprintf(
|
||||||
|
/* translators: 1: tax class name 2: error message */
|
||||||
|
esc_html__( 'Additional tax class "%1$s" couldn\'t be saved. %2$s.', 'woocommerce' ),
|
||||||
|
esc_html( $name ),
|
||||||
|
$tax_class->get_error_message()
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return null;
|
return null;
|
||||||
|
@ -201,6 +212,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
|
'wc_tax_nonce' => wp_create_nonce( 'wc_tax_nonce-class:' . $current_class ),
|
||||||
'base_url' => $base_url,
|
'base_url' => $base_url,
|
||||||
'rates' => array_values( WC_Tax::get_rates_for_tax_class( $current_class ) ),
|
'rates' => array_values( WC_Tax::get_rates_for_tax_class( $current_class ) ),
|
||||||
|
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
|
||||||
'page' => ! empty( $_GET['p'] ) ? absint( $_GET['p'] ) : 1,
|
'page' => ! empty( $_GET['p'] ) ? absint( $_GET['p'] ) : 1,
|
||||||
'limit' => 100,
|
'limit' => 100,
|
||||||
'countries' => $countries,
|
'countries' => $countries,
|
||||||
|
@ -278,6 +290,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
'tax_rate_priority',
|
'tax_rate_priority',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||||
foreach ( $tax_rate_keys as $tax_rate_key ) {
|
foreach ( $tax_rate_keys as $tax_rate_key ) {
|
||||||
if ( isset( $_POST[ $tax_rate_key ], $_POST[ $tax_rate_key ][ $key ] ) ) {
|
if ( isset( $_POST[ $tax_rate_key ], $_POST[ $tax_rate_key ][ $key ] ) ) {
|
||||||
$tax_rate[ $tax_rate_key ] = wc_clean( wp_unslash( $_POST[ $tax_rate_key ][ $key ] ) );
|
$tax_rate[ $tax_rate_key ] = wc_clean( wp_unslash( $_POST[ $tax_rate_key ][ $key ] ) );
|
||||||
|
@ -288,6 +301,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
$tax_rate['tax_rate_shipping'] = isset( $_POST['tax_rate_shipping'][ $key ] ) ? 1 : 0;
|
$tax_rate['tax_rate_shipping'] = isset( $_POST['tax_rate_shipping'][ $key ] ) ? 1 : 0;
|
||||||
$tax_rate['tax_rate_order'] = $order;
|
$tax_rate['tax_rate_order'] = $order;
|
||||||
$tax_rate['tax_rate_class'] = $class;
|
$tax_rate['tax_rate_class'] = $class;
|
||||||
|
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||||
|
|
||||||
return $tax_rate;
|
return $tax_rate;
|
||||||
}
|
}
|
||||||
|
@ -298,7 +312,8 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
public function save_tax_rates() {
|
public function save_tax_rates() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
$current_class = sanitize_title( $this->get_current_tax_class() );
|
$current_class = sanitize_title( $this->get_current_tax_class() );
|
||||||
|
// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotValidated, WordPress.Security.NonceVerification.Missing
|
||||||
$posted_countries = wc_clean( wp_unslash( $_POST['tax_rate_country'] ) );
|
$posted_countries = wc_clean( wp_unslash( $_POST['tax_rate_country'] ) );
|
||||||
|
|
||||||
// get the tax rate id of the first submited row.
|
// get the tax rate id of the first submited row.
|
||||||
|
@ -310,13 +325,14 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
$index = isset( $tax_rate_order ) ? $tax_rate_order : 0;
|
$index = isset( $tax_rate_order ) ? $tax_rate_order : 0;
|
||||||
|
|
||||||
// Loop posted fields.
|
// Loop posted fields.
|
||||||
|
// phpcs:disable WordPress.Security.NonceVerification.Missing
|
||||||
foreach ( $posted_countries as $key => $value ) {
|
foreach ( $posted_countries as $key => $value ) {
|
||||||
$mode = ( 0 === strpos( $key, 'new-' ) ) ? 'insert' : 'update';
|
$mode = ( 0 === strpos( $key, 'new-' ) ) ? 'insert' : 'update';
|
||||||
$tax_rate = $this->get_posted_tax_rate( $key, $index ++, $current_class );
|
$tax_rate = $this->get_posted_tax_rate( $key, $index ++, $current_class );
|
||||||
|
|
||||||
if ( 'insert' === $mode ) {
|
if ( 'insert' === $mode ) {
|
||||||
$tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
|
$tax_rate_id = WC_Tax::_insert_tax_rate( $tax_rate );
|
||||||
} elseif ( 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
|
} elseif ( isset( $_POST['remove_tax_rate'][ $key ] ) && 1 === absint( $_POST['remove_tax_rate'][ $key ] ) ) {
|
||||||
$tax_rate_id = absint( $key );
|
$tax_rate_id = absint( $key );
|
||||||
WC_Tax::_delete_tax_rate( $tax_rate_id );
|
WC_Tax::_delete_tax_rate( $tax_rate_id );
|
||||||
continue;
|
continue;
|
||||||
|
@ -332,6 +348,7 @@ class WC_Settings_Tax extends WC_Settings_Page {
|
||||||
WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_city'][ $key ] ) ) );
|
WC_Tax::_update_tax_rate_cities( $tax_rate_id, wc_clean( wp_unslash( $_POST['tax_rate_city'][ $key ] ) ) );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// phpcs:enable WordPress.Security.NonceVerification.Missing
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -514,7 +514,7 @@ $untested_plugins = $plugin_updates->get_untested_plugins( WC()->version, Cons
|
||||||
<tbody>
|
<tbody>
|
||||||
<tr>
|
<tr>
|
||||||
<td data-export-label="WC Database Version"><?php esc_html_e( 'WooCommerce database version', 'woocommerce' ); ?>:</td>
|
<td data-export-label="WC Database Version"><?php esc_html_e( 'WooCommerce database version', 'woocommerce' ); ?>:</td>
|
||||||
<td class="help"><?php echo wc_help_tip( esc_html__( 'The version of WooCommerce that the database is formatted for. This should be the same as your WooCommerce version.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
|
<td class="help"><?php echo wc_help_tip( esc_html__( 'The database version for WooCommerce. Note that it may not match WooCommerce core version and that is normal.', 'woocommerce' ) ); /* phpcs:ignore WordPress.XSS.EscapeOutput.OutputNotEscaped */ ?></td>
|
||||||
<td><?php echo esc_html( $database['wc_database_version'] ); ?></td>
|
<td><?php echo esc_html( $database['wc_database_version'] ); ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<tr>
|
<tr>
|
||||||
|
|
|
@ -155,6 +155,7 @@ class WC_AJAX {
|
||||||
'json_search_downloadable_products_and_variations',
|
'json_search_downloadable_products_and_variations',
|
||||||
'json_search_customers',
|
'json_search_customers',
|
||||||
'json_search_categories',
|
'json_search_categories',
|
||||||
|
'json_search_pages',
|
||||||
'term_ordering',
|
'term_ordering',
|
||||||
'product_ordering',
|
'product_ordering',
|
||||||
'refund_line_items',
|
'refund_line_items',
|
||||||
|
@ -794,10 +795,14 @@ class WC_AJAX {
|
||||||
$loop = intval( $_POST['loop'] );
|
$loop = intval( $_POST['loop'] );
|
||||||
$file_counter = 0;
|
$file_counter = 0;
|
||||||
$order = wc_get_order( $order_id );
|
$order = wc_get_order( $order_id );
|
||||||
|
$items = $order->get_items();
|
||||||
|
|
||||||
foreach ( $product_ids as $product_id ) {
|
foreach ( $items as $item ) {
|
||||||
$product = wc_get_product( $product_id );
|
$product = $item->get_product();
|
||||||
$files = $product->get_downloads();
|
if ( ! in_array( $product->get_id(), $product_ids, true ) ) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$files = $product->get_downloads();
|
||||||
|
|
||||||
if ( ! $order->get_billing_email() ) {
|
if ( ! $order->get_billing_email() ) {
|
||||||
wp_die();
|
wp_die();
|
||||||
|
@ -805,7 +810,7 @@ class WC_AJAX {
|
||||||
|
|
||||||
if ( ! empty( $files ) ) {
|
if ( ! empty( $files ) ) {
|
||||||
foreach ( $files as $download_id => $file ) {
|
foreach ( $files as $download_id => $file ) {
|
||||||
$inserted_id = wc_downloadable_file_permission( $download_id, $product_id, $order );
|
$inserted_id = wc_downloadable_file_permission( $download_id, $product_id, $order, $item->get_quantity(), $item );
|
||||||
if ( $inserted_id ) {
|
if ( $inserted_id ) {
|
||||||
$download = new WC_Customer_Download( $inserted_id );
|
$download = new WC_Customer_Download( $inserted_id );
|
||||||
$loop ++;
|
$loop ++;
|
||||||
|
@ -1766,6 +1771,47 @@ class WC_AJAX {
|
||||||
wp_send_json( apply_filters( 'woocommerce_json_search_found_categories', $found_categories ) );
|
wp_send_json( apply_filters( 'woocommerce_json_search_found_categories', $found_categories ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Ajax request handling for page searching.
|
||||||
|
*/
|
||||||
|
public static function json_search_pages() {
|
||||||
|
ob_start();
|
||||||
|
|
||||||
|
check_ajax_referer( 'search-pages', 'security' );
|
||||||
|
|
||||||
|
if ( ! current_user_can( 'manage_woocommerce' ) ) {
|
||||||
|
wp_die( -1 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$search_text = isset( $_GET['term'] ) ? wc_clean( wp_unslash( $_GET['term'] ) ) : '';
|
||||||
|
$limit = isset( $_GET['limit'] ) ? absint( wp_unslash( $_GET['limit'] ) ) : -1;
|
||||||
|
$exclude_ids = ! empty( $_GET['exclude'] ) ? array_map( 'absint', (array) wp_unslash( $_GET['exclude'] ) ) : array();
|
||||||
|
|
||||||
|
$args = array(
|
||||||
|
'no_found_rows' => true,
|
||||||
|
'update_post_meta_cache' => false,
|
||||||
|
'update_post_term_cache' => false,
|
||||||
|
'posts_per_page' => $limit,
|
||||||
|
'post_type' => 'page',
|
||||||
|
'post_status' => array( 'publish', 'private', 'draft' ),
|
||||||
|
's' => $search_text,
|
||||||
|
'post__not_in' => $exclude_ids,
|
||||||
|
);
|
||||||
|
$search_results_query = new WP_Query( $args );
|
||||||
|
|
||||||
|
$pages_results = array();
|
||||||
|
foreach ( $search_results_query->get_posts() as $post ) {
|
||||||
|
$pages_results[ $post->ID ] = sprintf(
|
||||||
|
/* translators: 1: page name 2: page ID */
|
||||||
|
__( '%1$s (ID: %2$s)', 'woocommerce' ),
|
||||||
|
get_the_title( $post ),
|
||||||
|
$post->ID
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_send_json( apply_filters( 'woocommerce_json_search_found_pages', $pages_results ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Ajax request handling for categories ordering.
|
* Ajax request handling for categories ordering.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -175,6 +175,10 @@ final class WC_Cart_Session {
|
||||||
if ( $update_cart_session || is_null( WC()->session->get( 'cart_totals', null ) ) ) {
|
if ( $update_cart_session || is_null( WC()->session->get( 'cart_totals', null ) ) ) {
|
||||||
WC()->session->set( 'cart', $this->get_cart_for_session() );
|
WC()->session->set( 'cart', $this->get_cart_for_session() );
|
||||||
$this->cart->calculate_totals();
|
$this->cart->calculate_totals();
|
||||||
|
|
||||||
|
if ( $merge_saved_cart ) {
|
||||||
|
$this->persistent_cart_update();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// If this is a re-order, redirect to the cart page to get rid of the `order_again` query string.
|
// If this is a re-order, redirect to the cart page to get rid of the `order_again` query string.
|
||||||
|
|
|
@ -977,7 +977,8 @@ class WC_Checkout {
|
||||||
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );
|
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );
|
||||||
|
|
||||||
if ( ! is_ajax() ) {
|
if ( ! is_ajax() ) {
|
||||||
wp_safe_redirect( $result['redirect'] );
|
// phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
|
||||||
|
wp_redirect( $result['redirect'] );
|
||||||
exit;
|
exit;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -51,6 +51,9 @@ class WC_Comments {
|
||||||
|
|
||||||
// Set comment type.
|
// Set comment type.
|
||||||
add_action( 'preprocess_comment', array( __CLASS__, 'update_comment_type' ), 1 );
|
add_action( 'preprocess_comment', array( __CLASS__, 'update_comment_type' ), 1 );
|
||||||
|
|
||||||
|
// Validate product reviews if requires verified owners.
|
||||||
|
add_action( 'pre_comment_on_post', array( __CLASS__, 'validate_product_review_verified_owners' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -444,6 +447,36 @@ class WC_Comments {
|
||||||
return $comment_data;
|
return $comment_data;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Validate product reviews if requires a verified owner.
|
||||||
|
*
|
||||||
|
* @param int $comment_post_id Post ID.
|
||||||
|
*/
|
||||||
|
public static function validate_product_review_verified_owners( $comment_post_id ) {
|
||||||
|
// Only validate if option is enabled.
|
||||||
|
if ( 'yes' !== get_option( 'woocommerce_review_rating_verification_required' ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Validate only products.
|
||||||
|
if ( 'product' !== get_post_type( $comment_post_id ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Skip if is a verified owner.
|
||||||
|
if ( wc_customer_bought_product( '', get_current_user_id(), $comment_post_id ) ) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
wp_die(
|
||||||
|
esc_html__( 'Only logged in customers who have purchased this product may leave a review.', 'woocommerce' ),
|
||||||
|
esc_html__( 'Reviews can only be left by "verified owners"', 'woocommerce' ),
|
||||||
|
array(
|
||||||
|
'code' => 403,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Determines if a comment is of the default type.
|
* Determines if a comment is of the default type.
|
||||||
*
|
*
|
||||||
|
|
|
@ -449,7 +449,19 @@ class WC_Customer extends WC_Legacy_Customer {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function get_billing( $context = 'view' ) {
|
public function get_billing( $context = 'view' ) {
|
||||||
return $this->get_prop( 'billing', $context );
|
$value = null;
|
||||||
|
$prop = 'billing';
|
||||||
|
|
||||||
|
if ( array_key_exists( $prop, $this->data ) ) {
|
||||||
|
$changes = array_key_exists( $prop, $this->changes ) ? $this->changes[ $prop ] : array();
|
||||||
|
$value = array_merge( $this->data[ $prop ], $changes );
|
||||||
|
|
||||||
|
if ( 'view' === $context ) {
|
||||||
|
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -580,7 +592,19 @@ class WC_Customer extends WC_Legacy_Customer {
|
||||||
* @return array
|
* @return array
|
||||||
*/
|
*/
|
||||||
public function get_shipping( $context = 'view' ) {
|
public function get_shipping( $context = 'view' ) {
|
||||||
return $this->get_prop( 'shipping', $context );
|
$value = null;
|
||||||
|
$prop = 'shipping';
|
||||||
|
|
||||||
|
if ( array_key_exists( $prop, $this->data ) ) {
|
||||||
|
$changes = array_key_exists( $prop, $this->changes ) ? $this->changes[ $prop ] : array();
|
||||||
|
$value = array_merge( $this->data[ $prop ], $changes );
|
||||||
|
|
||||||
|
if ( 'view' === $context ) {
|
||||||
|
$value = apply_filters( $this->get_hook_prefix() . $prop, $value, $this );
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $value;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -75,7 +75,7 @@ class WC_Session_Handler extends WC_Session {
|
||||||
add_action( 'wp_logout', array( $this, 'destroy_session' ) );
|
add_action( 'wp_logout', array( $this, 'destroy_session' ) );
|
||||||
|
|
||||||
if ( ! is_user_logged_in() ) {
|
if ( ! is_user_logged_in() ) {
|
||||||
add_filter( 'nonce_user_logged_out', array( $this, 'nonce_user_logged_out' ) );
|
add_filter( 'nonce_user_logged_out', array( $this, 'maybe_update_nonce_user_logged_out' ), 10, 2 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -187,6 +187,25 @@ class WC_Session_Handler extends WC_Session {
|
||||||
return $customer_id;
|
return $customer_id;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get session unique ID for requests if session is initialized or user ID if logged in.
|
||||||
|
* Introduced to help with unit tests.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
* @return string
|
||||||
|
*/
|
||||||
|
public function get_customer_unique_id() {
|
||||||
|
$customer_id = '';
|
||||||
|
|
||||||
|
if ( $this->has_session() && $this->_customer_id ) {
|
||||||
|
$customer_id = $this->_customer_id;
|
||||||
|
} elseif ( is_user_logged_in() ) {
|
||||||
|
$customer_id = (string) get_current_user_id();
|
||||||
|
}
|
||||||
|
|
||||||
|
return $customer_id;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the session cookie, if set. Otherwise return false.
|
* Get the session cookie, if set. Otherwise return false.
|
||||||
*
|
*
|
||||||
|
@ -288,13 +307,33 @@ class WC_Session_Handler extends WC_Session {
|
||||||
/**
|
/**
|
||||||
* When a user is logged out, ensure they have a unique nonce by using the customer/session ID.
|
* When a user is logged out, ensure they have a unique nonce by using the customer/session ID.
|
||||||
*
|
*
|
||||||
|
* @deprecated 5.3.0
|
||||||
* @param int $uid User ID.
|
* @param int $uid User ID.
|
||||||
* @return string
|
* @return int|string
|
||||||
*/
|
*/
|
||||||
public function nonce_user_logged_out( $uid ) {
|
public function nonce_user_logged_out( $uid ) {
|
||||||
|
wc_deprecated_function( 'WC_Session_Handler::nonce_user_logged_out', '5.3', 'WC_Session_Handler::maybe_update_nonce_user_logged_out' );
|
||||||
|
|
||||||
return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid;
|
return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* When a user is logged out, ensure they have a unique nonce to manage cart and more using the customer/session ID.
|
||||||
|
* This filter runs everything `wp_verify_nonce()` and `wp_create_nonce()` gets called.
|
||||||
|
*
|
||||||
|
* @since 5.3.0
|
||||||
|
* @param int $uid User ID.
|
||||||
|
* @param string $action The nonce action.
|
||||||
|
* @return int|string
|
||||||
|
*/
|
||||||
|
public function maybe_update_nonce_user_logged_out( $uid, $action ) {
|
||||||
|
if ( Automattic\WooCommerce\Utilities\StringUtil::starts_with( $action, 'woocommerce' ) ) {
|
||||||
|
return $this->has_session() && $this->_customer_id ? $this->_customer_id : $uid;
|
||||||
|
}
|
||||||
|
|
||||||
|
return $uid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Cleanup session data from the database and clear caches.
|
* Cleanup session data from the database and clear caches.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -198,7 +198,7 @@ class WC_Structured_Data {
|
||||||
$markup = array(
|
$markup = array(
|
||||||
'@type' => 'Product',
|
'@type' => 'Product',
|
||||||
'@id' => $permalink . '#product', // Append '#product' to differentiate between this @id and the @id generated for the Breadcrumblist.
|
'@id' => $permalink . '#product', // Append '#product' to differentiate between this @id and the @id generated for the Breadcrumblist.
|
||||||
'name' => $product->get_name(),
|
'name' => wp_kses_post( $product->get_name() ),
|
||||||
'url' => $permalink,
|
'url' => $permalink,
|
||||||
'description' => wp_strip_all_tags( do_shortcode( $product->get_short_description() ? $product->get_short_description() : $product->get_description() ) ),
|
'description' => wp_strip_all_tags( do_shortcode( $product->get_short_description() ? $product->get_short_description() : $product->get_description() ) ),
|
||||||
);
|
);
|
||||||
|
@ -477,7 +477,7 @@ class WC_Structured_Data {
|
||||||
),
|
),
|
||||||
'itemOffered' => array(
|
'itemOffered' => array(
|
||||||
'@type' => 'Product',
|
'@type' => 'Product',
|
||||||
'name' => apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible ),
|
'name' => wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, $is_visible ) ),
|
||||||
'sku' => $product_exists ? $product->get_sku() : '',
|
'sku' => $product_exists ? $product->get_sku() : '',
|
||||||
'image' => $product_exists ? wp_get_attachment_image_url( $product->get_image_id() ) : '',
|
'image' => $product_exists ? wp_get_attachment_image_url( $product->get_image_id() ) : '',
|
||||||
'url' => $is_visible ? get_permalink( $product->get_id() ) : get_home_url(),
|
'url' => $is_visible ? get_permalink( $product->get_id() ) : get_home_url(),
|
||||||
|
|
|
@ -815,6 +815,7 @@ class WC_Tax {
|
||||||
|
|
||||||
$existing = self::get_tax_classes();
|
$existing = self::get_tax_classes();
|
||||||
$existing_slugs = self::get_tax_class_slugs();
|
$existing_slugs = self::get_tax_class_slugs();
|
||||||
|
$name = wc_clean( $name );
|
||||||
|
|
||||||
if ( in_array( $name, $existing, true ) ) {
|
if ( in_array( $name, $existing, true ) ) {
|
||||||
return new WP_Error( 'tax_class_exists', __( 'Tax class already exists', 'woocommerce' ) );
|
return new WP_Error( 'tax_class_exists', __( 'Tax class already exists', 'woocommerce' ) );
|
||||||
|
@ -824,6 +825,11 @@ class WC_Tax {
|
||||||
$slug = sanitize_title( $name );
|
$slug = sanitize_title( $name );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Stop if there's no slug.
|
||||||
|
if ( ! $slug ) {
|
||||||
|
return new WP_Error( 'tax_class_slug_invalid', __( 'Tax class slug is invalid', 'woocommerce' ) );
|
||||||
|
}
|
||||||
|
|
||||||
if ( in_array( $slug, $existing_slugs, true ) ) {
|
if ( in_array( $slug, $existing_slugs, true ) ) {
|
||||||
return new WP_Error( 'tax_class_slug_exists', __( 'Tax class slug already exists', 'woocommerce' ) );
|
return new WP_Error( 'tax_class_slug_exists', __( 'Tax class slug already exists', 'woocommerce' ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,8 +4,6 @@
|
||||||
*
|
*
|
||||||
* Handles requests to the /taxes endpoint.
|
* Handles requests to the /taxes endpoint.
|
||||||
*
|
*
|
||||||
* @author WooThemes
|
|
||||||
* @category API
|
|
||||||
* @package WooCommerce\RestApi
|
* @package WooCommerce\RestApi
|
||||||
* @since 3.0.0
|
* @since 3.0.0
|
||||||
*/
|
*/
|
||||||
|
@ -40,67 +38,79 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
* Register the routes for taxes.
|
* Register the routes for taxes.
|
||||||
*/
|
*/
|
||||||
public function register_routes() {
|
public function register_routes() {
|
||||||
register_rest_route( $this->namespace, '/' . $this->rest_base, array(
|
register_rest_route(
|
||||||
|
$this->namespace,
|
||||||
|
'/' . $this->rest_base,
|
||||||
array(
|
array(
|
||||||
'methods' => WP_REST_Server::READABLE,
|
array(
|
||||||
'callback' => array( $this, 'get_items' ),
|
'methods' => WP_REST_Server::READABLE,
|
||||||
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
'callback' => array( $this, 'get_items' ),
|
||||||
'args' => $this->get_collection_params(),
|
'permission_callback' => array( $this, 'get_items_permissions_check' ),
|
||||||
),
|
'args' => $this->get_collection_params(),
|
||||||
array(
|
),
|
||||||
'methods' => WP_REST_Server::CREATABLE,
|
array(
|
||||||
'callback' => array( $this, 'create_item' ),
|
'methods' => WP_REST_Server::CREATABLE,
|
||||||
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
'callback' => array( $this, 'create_item' ),
|
||||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
'permission_callback' => array( $this, 'create_item_permissions_check' ),
|
||||||
),
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::CREATABLE ),
|
||||||
'schema' => array( $this, 'get_public_item_schema' ),
|
),
|
||||||
) );
|
'schema' => array( $this, 'get_public_item_schema' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>[\d]+)', array(
|
register_rest_route(
|
||||||
'args' => array(
|
$this->namespace,
|
||||||
'id' => array(
|
'/' . $this->rest_base . '/(?P<id>[\d]+)',
|
||||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
|
||||||
'type' => 'integer',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
array(
|
array(
|
||||||
'methods' => WP_REST_Server::READABLE,
|
'args' => array(
|
||||||
'callback' => array( $this, 'get_item' ),
|
'id' => array(
|
||||||
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||||
'args' => array(
|
'type' => 'integer',
|
||||||
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
|
||||||
),
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'methods' => WP_REST_Server::EDITABLE,
|
|
||||||
'callback' => array( $this, 'update_item' ),
|
|
||||||
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
|
||||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
|
||||||
),
|
|
||||||
array(
|
|
||||||
'methods' => WP_REST_Server::DELETABLE,
|
|
||||||
'callback' => array( $this, 'delete_item' ),
|
|
||||||
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
|
||||||
'args' => array(
|
|
||||||
'force' => array(
|
|
||||||
'default' => false,
|
|
||||||
'type' => 'boolean',
|
|
||||||
'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
|
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
),
|
array(
|
||||||
'schema' => array( $this, 'get_public_item_schema' ),
|
'methods' => WP_REST_Server::READABLE,
|
||||||
) );
|
'callback' => array( $this, 'get_item' ),
|
||||||
|
'permission_callback' => array( $this, 'get_item_permissions_check' ),
|
||||||
|
'args' => array(
|
||||||
|
'context' => $this->get_context_param( array( 'default' => 'view' ) ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'methods' => WP_REST_Server::EDITABLE,
|
||||||
|
'callback' => array( $this, 'update_item' ),
|
||||||
|
'permission_callback' => array( $this, 'update_item_permissions_check' ),
|
||||||
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
'methods' => WP_REST_Server::DELETABLE,
|
||||||
|
'callback' => array( $this, 'delete_item' ),
|
||||||
|
'permission_callback' => array( $this, 'delete_item_permissions_check' ),
|
||||||
|
'args' => array(
|
||||||
|
'force' => array(
|
||||||
|
'default' => false,
|
||||||
|
'type' => 'boolean',
|
||||||
|
'description' => __( 'Required to be true, as resource does not support trashing.', 'woocommerce' ),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'schema' => array( $this, 'get_public_item_schema' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
register_rest_route( $this->namespace, '/' . $this->rest_base . '/batch', array(
|
register_rest_route(
|
||||||
|
$this->namespace,
|
||||||
|
'/' . $this->rest_base . '/batch',
|
||||||
array(
|
array(
|
||||||
'methods' => WP_REST_Server::EDITABLE,
|
array(
|
||||||
'callback' => array( $this, 'batch_items' ),
|
'methods' => WP_REST_Server::EDITABLE,
|
||||||
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
|
'callback' => array( $this, 'batch_items' ),
|
||||||
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
'permission_callback' => array( $this, 'batch_items_permissions_check' ),
|
||||||
),
|
'args' => $this->get_endpoint_args_for_item_schema( WP_REST_Server::EDITABLE ),
|
||||||
'schema' => array( $this, 'get_public_batch_schema' ),
|
),
|
||||||
) );
|
'schema' => array( $this, 'get_public_batch_schema' ),
|
||||||
|
)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -200,7 +210,7 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
public function get_items( $request ) {
|
public function get_items( $request ) {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
$prepared_args = array();
|
$prepared_args = array();
|
||||||
$prepared_args['order'] = $request['order'];
|
$prepared_args['order'] = $request['order'];
|
||||||
$prepared_args['number'] = $request['per_page'];
|
$prepared_args['number'] = $request['per_page'];
|
||||||
if ( ! empty( $request['offset'] ) ) {
|
if ( ! empty( $request['offset'] ) ) {
|
||||||
|
@ -208,9 +218,10 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
} else {
|
} else {
|
||||||
$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
|
$prepared_args['offset'] = ( $request['page'] - 1 ) * $prepared_args['number'];
|
||||||
}
|
}
|
||||||
$orderby_possibles = array(
|
$orderby_possibles = array(
|
||||||
'id' => 'tax_rate_id',
|
'id' => 'tax_rate_id',
|
||||||
'order' => 'tax_rate_order',
|
'order' => 'tax_rate_order',
|
||||||
|
'priority' => 'tax_rate_priority',
|
||||||
);
|
);
|
||||||
$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
|
$prepared_args['orderby'] = $orderby_possibles[ $request['orderby'] ];
|
||||||
$prepared_args['class'] = $request['class'];
|
$prepared_args['class'] = $request['class'];
|
||||||
|
@ -223,30 +234,42 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
*/
|
*/
|
||||||
$prepared_args = apply_filters( 'woocommerce_rest_tax_query', $prepared_args, $request );
|
$prepared_args = apply_filters( 'woocommerce_rest_tax_query', $prepared_args, $request );
|
||||||
|
|
||||||
$query = "
|
$orderby = sanitize_key( $prepared_args['orderby'] ) . ' ' . sanitize_key( $prepared_args['order'] );
|
||||||
|
$query = "
|
||||||
SELECT *
|
SELECT *
|
||||||
FROM {$wpdb->prefix}woocommerce_tax_rates
|
FROM {$wpdb->prefix}woocommerce_tax_rates
|
||||||
WHERE 1 = 1
|
%s
|
||||||
|
ORDER BY {$orderby}
|
||||||
|
LIMIT %%d, %%d
|
||||||
";
|
";
|
||||||
|
|
||||||
|
$wpdb_prepare_args = array(
|
||||||
|
$prepared_args['offset'],
|
||||||
|
$prepared_args['number'],
|
||||||
|
);
|
||||||
|
|
||||||
// Filter by tax class.
|
// Filter by tax class.
|
||||||
if ( ! empty( $prepared_args['class'] ) ) {
|
if ( empty( $prepared_args['class'] ) ) {
|
||||||
|
$query = sprintf( $query, '' );
|
||||||
|
} else {
|
||||||
$class = 'standard' !== $prepared_args['class'] ? sanitize_title( $prepared_args['class'] ) : '';
|
$class = 'standard' !== $prepared_args['class'] ? sanitize_title( $prepared_args['class'] ) : '';
|
||||||
$query .= " AND tax_rate_class = '$class'";
|
array_unshift( $wpdb_prepare_args, $class );
|
||||||
|
$query = sprintf( $query, 'WHERE tax_rate_class = %s' );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Order tax rates.
|
|
||||||
$order_by = sprintf( ' ORDER BY %s', sanitize_key( $prepared_args['orderby'] ) );
|
|
||||||
|
|
||||||
// Pagination.
|
|
||||||
$pagination = sprintf( ' LIMIT %d, %d', $prepared_args['offset'], $prepared_args['number'] );
|
|
||||||
|
|
||||||
// Query taxes.
|
// Query taxes.
|
||||||
$results = $wpdb->get_results( $query . $order_by . $pagination );
|
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$results = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
$query,
|
||||||
|
$wpdb_prepare_args
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
|
||||||
$taxes = array();
|
$taxes = array();
|
||||||
foreach ( $results as $tax ) {
|
foreach ( $results as $tax ) {
|
||||||
$data = $this->prepare_item_for_response( $tax, $request );
|
$data = $this->prepare_item_for_response( $tax, $request );
|
||||||
$taxes[] = $this->prepare_response_for_collection( $data );
|
$taxes[] = $this->prepare_response_for_collection( $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -254,10 +277,18 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
|
|
||||||
// Store pagination values for headers then unset for count query.
|
// 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.
|
// Query only for ids.
|
||||||
$wpdb->get_results( str_replace( 'SELECT *', 'SELECT tax_rate_id', $query ) );
|
// phpcs:disable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
$query = str_replace( 'SELECT *', 'SELECT tax_rate_id', $query );
|
||||||
|
$wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
$query,
|
||||||
|
$wpdb_prepare_args
|
||||||
|
)
|
||||||
|
);
|
||||||
|
// phpcs:enable WordPress.DB.PreparedSQL.NotPrepared
|
||||||
|
|
||||||
// Calculate totals.
|
// Calculate totals.
|
||||||
$total_taxes = (int) $wpdb->num_rows;
|
$total_taxes = (int) $wpdb->num_rows;
|
||||||
|
@ -287,13 +318,13 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
* Take tax data from the request and return the updated or newly created rate.
|
* Take tax data from the request and return the updated or newly created rate.
|
||||||
*
|
*
|
||||||
* @param WP_REST_Request $request Full details about the request.
|
* @param WP_REST_Request $request Full details about the request.
|
||||||
* @param stdClass|null $current Existing tax object.
|
* @param stdClass|null $current Existing tax object.
|
||||||
* @return object
|
* @return object
|
||||||
*/
|
*/
|
||||||
protected function create_or_update_tax( $request, $current = null ) {
|
protected function create_or_update_tax( $request, $current = null ) {
|
||||||
$id = absint( isset( $request['id'] ) ? $request['id'] : 0 );
|
$id = absint( isset( $request['id'] ) ? $request['id'] : 0 );
|
||||||
$data = array();
|
$data = array();
|
||||||
$fields = array(
|
$fields = array(
|
||||||
'tax_rate_country',
|
'tax_rate_country',
|
||||||
'tax_rate_state',
|
'tax_rate_state',
|
||||||
'tax_rate',
|
'tax_rate',
|
||||||
|
@ -321,25 +352,25 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
|
|
||||||
// Add to data array.
|
// Add to data array.
|
||||||
switch ( $key ) {
|
switch ( $key ) {
|
||||||
case 'tax_rate_priority' :
|
case 'tax_rate_priority':
|
||||||
case 'tax_rate_compound' :
|
case 'tax_rate_compound':
|
||||||
case 'tax_rate_shipping' :
|
case 'tax_rate_shipping':
|
||||||
case 'tax_rate_order' :
|
case 'tax_rate_order':
|
||||||
$data[ $field ] = absint( $request[ $key ] );
|
$data[ $field ] = absint( $request[ $key ] );
|
||||||
break;
|
break;
|
||||||
case 'tax_rate_class' :
|
case 'tax_rate_class':
|
||||||
$data[ $field ] = 'standard' !== $request['tax_rate_class'] ? $request['tax_rate_class'] : '';
|
$data[ $field ] = 'standard' !== $request['tax_rate_class'] ? $request['tax_rate_class'] : '';
|
||||||
break;
|
break;
|
||||||
default :
|
default:
|
||||||
$data[ $field ] = wc_clean( $request[ $key ] );
|
$data[ $field ] = wc_clean( $request[ $key ] );
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ( $id ) {
|
if ( ! $id ) {
|
||||||
WC_Tax::_update_tax_rate( $id, $data );
|
|
||||||
} else {
|
|
||||||
$id = WC_Tax::_insert_tax_rate( $data );
|
$id = WC_Tax::_insert_tax_rate( $data );
|
||||||
|
} elseif ( $data ) {
|
||||||
|
WC_Tax::_update_tax_rate( $id, $data );
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add locales.
|
// Add locales.
|
||||||
|
@ -487,13 +518,12 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
/**
|
/**
|
||||||
* Prepare a single tax output for response.
|
* Prepare a single tax output for response.
|
||||||
*
|
*
|
||||||
* @param stdClass $tax Tax object.
|
* @param stdClass $tax Tax object.
|
||||||
* @param WP_REST_Request $request Request object.
|
* @param WP_REST_Request $request Request object.
|
||||||
|
*
|
||||||
* @return WP_REST_Response $response Response data.
|
* @return WP_REST_Response $response Response data.
|
||||||
*/
|
*/
|
||||||
public function prepare_item_for_response( $tax, $request ) {
|
public function prepare_item_for_response( $tax, $request ) {
|
||||||
global $wpdb;
|
|
||||||
|
|
||||||
$id = (int) $tax->tax_rate_id;
|
$id = (int) $tax->tax_rate_id;
|
||||||
$data = array(
|
$data = array(
|
||||||
'id' => $id,
|
'id' => $id,
|
||||||
|
@ -510,18 +540,7 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
'class' => $tax->tax_rate_class ? $tax->tax_rate_class : 'standard',
|
'class' => $tax->tax_rate_class ? $tax->tax_rate_class : 'standard',
|
||||||
);
|
);
|
||||||
|
|
||||||
// Get locales from a tax rate.
|
$data = $this->add_tax_rate_locales( $data, $tax );
|
||||||
$locales = $wpdb->get_results( $wpdb->prepare( "
|
|
||||||
SELECT location_code, location_type
|
|
||||||
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
|
|
||||||
WHERE tax_rate_id = %d
|
|
||||||
", $id ) );
|
|
||||||
|
|
||||||
if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) {
|
|
||||||
foreach ( $locales as $locale ) {
|
|
||||||
$data[ $locale->location_type ] = $locale->location_code;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
$context = ! empty( $request['context'] ) ? $request['context'] : 'view';
|
||||||
$data = $this->add_additional_fields_to_object( $data, $request );
|
$data = $this->add_additional_fields_to_object( $data, $request );
|
||||||
|
@ -550,7 +569,7 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
*/
|
*/
|
||||||
protected function prepare_links( $tax ) {
|
protected function prepare_links( $tax ) {
|
||||||
$links = array(
|
$links = array(
|
||||||
'self' => array(
|
'self' => array(
|
||||||
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ),
|
'href' => rest_url( sprintf( '/%s/%s/%d', $this->namespace, $this->rest_base, $tax->tax_rate_id ) ),
|
||||||
),
|
),
|
||||||
'collection' => array(
|
'collection' => array(
|
||||||
|
@ -561,6 +580,38 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
return $links;
|
return $links;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tax rate locales to the response array.
|
||||||
|
*
|
||||||
|
* @param array $data Response data.
|
||||||
|
* @param stdClass $tax Tax object.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function add_tax_rate_locales( $data, $tax ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
// Get locales from a tax rate.
|
||||||
|
$locales = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"
|
||||||
|
SELECT location_code, location_type
|
||||||
|
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
|
||||||
|
WHERE tax_rate_id = %d
|
||||||
|
",
|
||||||
|
$tax->tax_rate_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) {
|
||||||
|
foreach ( $locales as $locale ) {
|
||||||
|
$data[ $locale->location_type ] = $locale->location_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Get the Taxes schema, conforming to JSON Schema.
|
* Get the Taxes schema, conforming to JSON Schema.
|
||||||
*
|
*
|
||||||
|
@ -572,18 +623,18 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
'title' => 'tax',
|
'title' => 'tax',
|
||||||
'type' => 'object',
|
'type' => 'object',
|
||||||
'properties' => array(
|
'properties' => array(
|
||||||
'id' => array(
|
'id' => array(
|
||||||
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
'description' => __( 'Unique identifier for the resource.', 'woocommerce' ),
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
'readonly' => true,
|
'readonly' => true,
|
||||||
),
|
),
|
||||||
'country' => array(
|
'country' => array(
|
||||||
'description' => __( 'Country ISO 3166 code.', 'woocommerce' ),
|
'description' => __( 'Country ISO 3166 code.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'state' => array(
|
'state' => array(
|
||||||
'description' => __( 'State code.', 'woocommerce' ),
|
'description' => __( 'State code.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
|
@ -593,17 +644,17 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'city' => array(
|
'city' => array(
|
||||||
'description' => __( 'City name.', 'woocommerce' ),
|
'description' => __( 'City name.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'rate' => array(
|
'rate' => array(
|
||||||
'description' => __( 'Tax rate.', 'woocommerce' ),
|
'description' => __( 'Tax rate.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'name' => array(
|
'name' => array(
|
||||||
'description' => __( 'Tax rate name.', 'woocommerce' ),
|
'description' => __( 'Tax rate name.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
|
@ -626,12 +677,12 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
'default' => true,
|
'default' => true,
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'order' => array(
|
'order' => array(
|
||||||
'description' => __( 'Indicates the order that will appear in queries.', 'woocommerce' ),
|
'description' => __( 'Indicates the order that will appear in queries.', 'woocommerce' ),
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'context' => array( 'view', 'edit' ),
|
'context' => array( 'view', 'edit' ),
|
||||||
),
|
),
|
||||||
'class' => array(
|
'class' => array(
|
||||||
'description' => __( 'Tax class.', 'woocommerce' ),
|
'description' => __( 'Tax class.', 'woocommerce' ),
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'default' => 'standard',
|
'default' => 'standard',
|
||||||
|
@ -654,54 +705,55 @@ class WC_REST_Taxes_V1_Controller extends WC_REST_Controller {
|
||||||
$params['context'] = $this->get_context_param();
|
$params['context'] = $this->get_context_param();
|
||||||
$params['context']['default'] = 'view';
|
$params['context']['default'] = 'view';
|
||||||
|
|
||||||
$params['page'] = array(
|
$params['page'] = array(
|
||||||
'description' => __( 'Current page of the collection.', 'woocommerce' ),
|
'description' => __( 'Current page of the collection.', 'woocommerce' ),
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'default' => 1,
|
'default' => 1,
|
||||||
'sanitize_callback' => 'absint',
|
'sanitize_callback' => 'absint',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
'minimum' => 1,
|
'minimum' => 1,
|
||||||
);
|
);
|
||||||
$params['per_page'] = array(
|
$params['per_page'] = array(
|
||||||
'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce' ),
|
'description' => __( 'Maximum number of items to be returned in result set.', 'woocommerce' ),
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'default' => 10,
|
'default' => 10,
|
||||||
'minimum' => 1,
|
'minimum' => 1,
|
||||||
'maximum' => 100,
|
'maximum' => 100,
|
||||||
'sanitize_callback' => 'absint',
|
'sanitize_callback' => 'absint',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
);
|
);
|
||||||
$params['offset'] = array(
|
$params['offset'] = array(
|
||||||
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
|
'description' => __( 'Offset the result set by a specific number of items.', 'woocommerce' ),
|
||||||
'type' => 'integer',
|
'type' => 'integer',
|
||||||
'sanitize_callback' => 'absint',
|
'sanitize_callback' => 'absint',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
);
|
);
|
||||||
$params['order'] = array(
|
$params['order'] = array(
|
||||||
'default' => 'asc',
|
'default' => 'asc',
|
||||||
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
|
'description' => __( 'Order sort attribute ascending or descending.', 'woocommerce' ),
|
||||||
'enum' => array( 'asc', 'desc' ),
|
'enum' => array( 'asc', 'desc' ),
|
||||||
'sanitize_callback' => 'sanitize_key',
|
'sanitize_callback' => 'sanitize_key',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
);
|
);
|
||||||
$params['orderby'] = array(
|
$params['orderby'] = array(
|
||||||
'default' => 'order',
|
'default' => 'order',
|
||||||
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
|
'description' => __( 'Sort collection by object attribute.', 'woocommerce' ),
|
||||||
'enum' => array(
|
'enum' => array(
|
||||||
'id',
|
'id',
|
||||||
'order',
|
'order',
|
||||||
|
'priority',
|
||||||
),
|
),
|
||||||
'sanitize_callback' => 'sanitize_key',
|
'sanitize_callback' => 'sanitize_key',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
);
|
);
|
||||||
$params['class'] = array(
|
$params['class'] = array(
|
||||||
'description' => __( 'Sort by tax class.', 'woocommerce' ),
|
'description' => __( 'Sort by tax class.', 'woocommerce' ),
|
||||||
'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ),
|
'enum' => array_merge( array( 'standard' ), WC_Tax::get_tax_class_slugs() ),
|
||||||
'sanitize_callback' => 'sanitize_title',
|
'sanitize_callback' => 'sanitize_title',
|
||||||
'type' => 'string',
|
'type' => 'string',
|
||||||
'validate_callback' => 'rest_validate_request_arg',
|
'validate_callback' => 'rest_validate_request_arg',
|
||||||
);
|
);
|
||||||
|
|
||||||
return $params;
|
return $params;
|
||||||
|
|
|
@ -34,31 +34,58 @@ class WC_REST_Orders_Controller extends WC_REST_Orders_V2_Controller {
|
||||||
* @return bool
|
* @return bool
|
||||||
*/
|
*/
|
||||||
protected function calculate_coupons( $request, $order ) {
|
protected function calculate_coupons( $request, $order ) {
|
||||||
if ( ! isset( $request['coupon_lines'] ) || ! is_array( $request['coupon_lines'] ) ) {
|
if ( ! isset( $request['coupon_lines'] ) ) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove all coupons first to ensure calculation is correct.
|
// Validate input and at the same time store the processed coupon codes to apply.
|
||||||
foreach ( $order->get_items( 'coupon' ) as $coupon ) {
|
|
||||||
$order->remove_coupon( $coupon->get_code() );
|
$coupon_codes = array();
|
||||||
}
|
$discounts = new WC_Discounts( $order );
|
||||||
|
|
||||||
|
$current_order_coupons = array_values( $order->get_coupons() );
|
||||||
|
$current_order_coupon_codes = array_map(
|
||||||
|
function( $coupon ) {
|
||||||
|
return $coupon->get_code();
|
||||||
|
},
|
||||||
|
$current_order_coupons
|
||||||
|
);
|
||||||
|
|
||||||
foreach ( $request['coupon_lines'] as $item ) {
|
foreach ( $request['coupon_lines'] as $item ) {
|
||||||
if ( is_array( $item ) ) {
|
if ( ! empty( $item['id'] ) ) {
|
||||||
if ( ! empty( $item['id'] ) ) {
|
throw new WC_REST_Exception( 'woocommerce_rest_coupon_item_id_readonly', __( 'Coupon item ID is readonly.', 'woocommerce' ), 400 );
|
||||||
throw new WC_REST_Exception( 'woocommerce_rest_coupon_item_id_readonly', __( 'Coupon item ID is readonly.', 'woocommerce' ), 400 );
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if ( empty( $item['code'] ) ) {
|
if ( empty( $item['code'] ) ) {
|
||||||
throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
|
throw new WC_REST_Exception( 'woocommerce_rest_invalid_coupon', __( 'Coupon code is required.', 'woocommerce' ), 400 );
|
||||||
}
|
}
|
||||||
|
|
||||||
$results = $order->apply_coupon( wc_clean( $item['code'] ) );
|
$coupon_code = wc_format_coupon_code( wc_clean( $item['code'] ) );
|
||||||
|
$coupon = new WC_Coupon( $coupon_code );
|
||||||
|
|
||||||
if ( is_wp_error( $results ) ) {
|
// Skip check if the coupon is already applied to the order, as this could wrongly throw an error for single-use coupons.
|
||||||
throw new WC_REST_Exception( 'woocommerce_rest_' . $results->get_error_code(), $results->get_error_message(), 400 );
|
if ( ! in_array( $coupon_code, $current_order_coupon_codes, true ) ) {
|
||||||
|
$check_result = $discounts->is_coupon_valid( $coupon );
|
||||||
|
if ( is_wp_error( $check_result ) ) {
|
||||||
|
throw new WC_REST_Exception( 'woocommerce_rest_' . $check_result->get_error_code(), $check_result->get_error_message(), 400 );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
$coupon_codes[] = $coupon_code;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Remove all coupons first to ensure calculation is correct.
|
||||||
|
foreach ( $order->get_items( 'coupon' ) as $existing_coupon ) {
|
||||||
|
$order->remove_coupon( $existing_coupon->get_code() );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Apply the coupons.
|
||||||
|
foreach ( $coupon_codes as $new_coupon ) {
|
||||||
|
$results = $order->apply_coupon( $new_coupon );
|
||||||
|
|
||||||
|
if ( is_wp_error( $results ) ) {
|
||||||
|
throw new WC_REST_Exception( 'woocommerce_rest_' . $results->get_error_code(), $results->get_error_message(), 400 );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -24,4 +24,118 @@ class WC_REST_Taxes_Controller extends WC_REST_Taxes_V2_Controller {
|
||||||
* @var string
|
* @var string
|
||||||
*/
|
*/
|
||||||
protected $namespace = 'wc/v3';
|
protected $namespace = 'wc/v3';
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Add tax rate locales to the response array.
|
||||||
|
*
|
||||||
|
* @param array $data Response data.
|
||||||
|
* @param stdClass $tax Tax object.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
protected function add_tax_rate_locales( $data, $tax ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
$data = parent::add_tax_rate_locales( $data, $tax );
|
||||||
|
$data['postcodes'] = array();
|
||||||
|
$data['cities'] = array();
|
||||||
|
|
||||||
|
// Get locales from a tax rate.
|
||||||
|
$locales = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"
|
||||||
|
SELECT location_code, location_type
|
||||||
|
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
|
||||||
|
WHERE tax_rate_id = %d
|
||||||
|
",
|
||||||
|
$tax->tax_rate_id
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( ! is_wp_error( $tax ) && ! is_null( $tax ) ) {
|
||||||
|
foreach ( $locales as $locale ) {
|
||||||
|
if ( 'postcode' === $locale->location_type ) {
|
||||||
|
$data['postcodes'][] = $locale->location_code;
|
||||||
|
} elseif ( 'city' === $locale->location_type ) {
|
||||||
|
$data['cities'][] = $locale->location_code;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return $data;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get the taxes schema, conforming to JSON Schema.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function get_item_schema() {
|
||||||
|
$schema = parent::get_item_schema();
|
||||||
|
|
||||||
|
$schema['properties']['postcodes'] = array(
|
||||||
|
'description' => __( 'List of postcodes / ZIPs. Introduced in WooCommerce 5.3.', 'woocommerce' ),
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
),
|
||||||
|
'context' => array( 'view', 'edit' ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$schema['properties']['cities'] = array(
|
||||||
|
'description' => __( 'List of city names. Introduced in WooCommerce 5.3.', 'woocommerce' ),
|
||||||
|
'type' => 'array',
|
||||||
|
'items' => array(
|
||||||
|
'type' => 'string',
|
||||||
|
),
|
||||||
|
'context' => array( 'view', 'edit' ),
|
||||||
|
);
|
||||||
|
|
||||||
|
$schema['properties']['postcode']['description'] =
|
||||||
|
__( "Postcode/ZIP, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, 'postcodes' should be used instead.", 'woocommerce' );
|
||||||
|
|
||||||
|
$schema['properties']['city']['description'] =
|
||||||
|
__( "City name, it doesn't support multiple values. Deprecated as of WooCommerce 5.3, 'cities' should be used instead.", 'woocommerce' );
|
||||||
|
|
||||||
|
return $schema;
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a single tax.
|
||||||
|
*
|
||||||
|
* @param WP_REST_Request $request Full details about the request.
|
||||||
|
* @return WP_Error|WP_REST_Response The response, or an error.
|
||||||
|
*/
|
||||||
|
public function create_item( $request ) {
|
||||||
|
$this->adjust_cities_and_postcodes( $request );
|
||||||
|
|
||||||
|
return parent::create_item( $request );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Update a single tax.
|
||||||
|
*
|
||||||
|
* @param WP_REST_Request $request Full details about the request.
|
||||||
|
* @return WP_Error|WP_REST_Response The response, or an error.
|
||||||
|
*/
|
||||||
|
public function update_item( $request ) {
|
||||||
|
$this->adjust_cities_and_postcodes( $request );
|
||||||
|
|
||||||
|
return parent::update_item( $request );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Convert array "cities" and "postcodes" parameters
|
||||||
|
* into semicolon-separated strings "city" and "postcode".
|
||||||
|
*
|
||||||
|
* @param WP_REST_Request $request The request to adjust.
|
||||||
|
*/
|
||||||
|
private function adjust_cities_and_postcodes( &$request ) {
|
||||||
|
if ( isset( $request['cities'] ) ) {
|
||||||
|
$request['city'] = join( ';', $request['cities'] );
|
||||||
|
}
|
||||||
|
if ( isset( $request['postcodes'] ) ) {
|
||||||
|
$request['postcode'] = join( ';', $request['postcodes'] );
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -84,7 +84,7 @@ class WC_Shortcode_Products {
|
||||||
* Get shortcode type.
|
* Get shortcode type.
|
||||||
*
|
*
|
||||||
* @since 3.2.0
|
* @since 3.2.0
|
||||||
* @return array
|
* @return string
|
||||||
*/
|
*/
|
||||||
public function get_type() {
|
public function get_type() {
|
||||||
return $this->type;
|
return $this->type;
|
||||||
|
|
|
@ -366,9 +366,10 @@ function wc_orders_count( $status ) {
|
||||||
* @param int|WC_Product $product Product instance or ID.
|
* @param int|WC_Product $product Product instance or ID.
|
||||||
* @param WC_Order $order Order data.
|
* @param WC_Order $order Order data.
|
||||||
* @param int $qty Quantity purchased.
|
* @param int $qty Quantity purchased.
|
||||||
|
* @param WC_Order_Item $item Item of the order.
|
||||||
* @return int|bool insert id or false on failure.
|
* @return int|bool insert id or false on failure.
|
||||||
*/
|
*/
|
||||||
function wc_downloadable_file_permission( $download_id, $product, $order, $qty = 1 ) {
|
function wc_downloadable_file_permission( $download_id, $product, $order, $qty = 1, $item = null ) {
|
||||||
if ( is_numeric( $product ) ) {
|
if ( is_numeric( $product ) ) {
|
||||||
$product = wc_get_product( $product );
|
$product = wc_get_product( $product );
|
||||||
}
|
}
|
||||||
|
@ -390,7 +391,7 @@ function wc_downloadable_file_permission( $download_id, $product, $order, $qty =
|
||||||
$download->set_access_expires( strtotime( $from_date . ' + ' . $expiry . ' DAY' ) );
|
$download->set_access_expires( strtotime( $from_date . ' + ' . $expiry . ' DAY' ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
$download = apply_filters( 'woocommerce_downloadable_file_permission', $download, $product, $order, $qty );
|
$download = apply_filters( 'woocommerce_downloadable_file_permission', $download, $product, $order, $qty, $item );
|
||||||
|
|
||||||
return $download->save();
|
return $download->save();
|
||||||
}
|
}
|
||||||
|
@ -420,7 +421,7 @@ function wc_downloadable_product_permissions( $order_id, $force = false ) {
|
||||||
$downloads = $product->get_downloads();
|
$downloads = $product->get_downloads();
|
||||||
|
|
||||||
foreach ( array_keys( $downloads ) as $download_id ) {
|
foreach ( array_keys( $downloads ) as $download_id ) {
|
||||||
wc_downloadable_file_permission( $download_id, $product, $order, $item->get_quantity() );
|
wc_downloadable_file_permission( $download_id, $product, $order, $item->get_quantity(), $item );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@
|
||||||
"psr/container": "^1.0"
|
"psr/container": "^1.0"
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"league/container": "3.3.3"
|
"league/container": "3.3.5"
|
||||||
},
|
},
|
||||||
"config": {
|
"config": {
|
||||||
"platform": {
|
"platform": {
|
||||||
|
|
|
@ -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": "df548645b5c00d585705cd10c6ffd3f7",
|
"content-hash": "9ae561875707d59bc392f6329d4f565a",
|
||||||
"packages": [
|
"packages": [
|
||||||
{
|
{
|
||||||
"name": "psr/container",
|
"name": "psr/container",
|
||||||
|
@ -59,21 +59,21 @@
|
||||||
"packages-dev": [
|
"packages-dev": [
|
||||||
{
|
{
|
||||||
"name": "league/container",
|
"name": "league/container",
|
||||||
"version": "3.3.3",
|
"version": "3.3.5",
|
||||||
"source": {
|
"source": {
|
||||||
"type": "git",
|
"type": "git",
|
||||||
"url": "https://github.com/thephpleague/container.git",
|
"url": "https://github.com/thephpleague/container.git",
|
||||||
"reference": "7dc67bdf89efc338e674863c0ea70a63efe4de05"
|
"reference": "048ab87810f508dbedbcb7ae941b606eb8ee353b"
|
||||||
},
|
},
|
||||||
"dist": {
|
"dist": {
|
||||||
"type": "zip",
|
"type": "zip",
|
||||||
"url": "https://api.github.com/repos/thephpleague/container/zipball/7dc67bdf89efc338e674863c0ea70a63efe4de05",
|
"url": "https://api.github.com/repos/thephpleague/container/zipball/048ab87810f508dbedbcb7ae941b606eb8ee353b",
|
||||||
"reference": "7dc67bdf89efc338e674863c0ea70a63efe4de05",
|
"reference": "048ab87810f508dbedbcb7ae941b606eb8ee353b",
|
||||||
"shasum": ""
|
"shasum": ""
|
||||||
},
|
},
|
||||||
"require": {
|
"require": {
|
||||||
"php": "^7.0 || ^8.0",
|
"php": "^7.0 || ^8.0",
|
||||||
"psr/container": "^1.0"
|
"psr/container": "^1.0.0 || ^2.0.0"
|
||||||
},
|
},
|
||||||
"provide": {
|
"provide": {
|
||||||
"psr/container-implementation": "^1.0"
|
"psr/container-implementation": "^1.0"
|
||||||
|
@ -83,11 +83,14 @@
|
||||||
},
|
},
|
||||||
"require-dev": {
|
"require-dev": {
|
||||||
"phpunit/phpunit": "^6.0",
|
"phpunit/phpunit": "^6.0",
|
||||||
"squizlabs/php_codesniffer": "^3.3"
|
"roave/security-advisories": "dev-master",
|
||||||
|
"scrutinizer/ocular": "^1.8",
|
||||||
|
"squizlabs/php_codesniffer": "^3.5"
|
||||||
},
|
},
|
||||||
"type": "library",
|
"type": "library",
|
||||||
"extra": {
|
"extra": {
|
||||||
"branch-alias": {
|
"branch-alias": {
|
||||||
|
"dev-master": "3.x-dev",
|
||||||
"dev-3.x": "3.x-dev",
|
"dev-3.x": "3.x-dev",
|
||||||
"dev-2.x": "2.x-dev",
|
"dev-2.x": "2.x-dev",
|
||||||
"dev-1.x": "1.x-dev"
|
"dev-1.x": "1.x-dev"
|
||||||
|
@ -127,7 +130,7 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"time": "2020-09-28T13:38:44+00:00"
|
"time": "2021-03-16T09:42:56+00:00"
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"aliases": [],
|
"aliases": [],
|
||||||
|
|
|
@ -9307,7 +9307,7 @@
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"prettier": {
|
"prettier": {
|
||||||
"version": "npm:wp-prettier@1.19.1",
|
"version": "npm:prettier@1.19.1",
|
||||||
"resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-1.19.1.tgz",
|
"resolved": "https://registry.npmjs.org/wp-prettier/-/wp-prettier-1.19.1.tgz",
|
||||||
"integrity": "sha512-mqAC2r1NDmRjG+z3KCJ/i61tycKlmADIjxnDhQab+KBxSAGbF/W7/zwB2guy/ypIeKrrftNsIYkNZZQKf3vJcg==",
|
"integrity": "sha512-mqAC2r1NDmRjG+z3KCJ/i61tycKlmADIjxnDhQab+KBxSAGbF/W7/zwB2guy/ypIeKrrftNsIYkNZZQKf3vJcg==",
|
||||||
"dev": true
|
"dev": true
|
||||||
|
|
14
readme.txt
14
readme.txt
|
@ -1,5 +1,5 @@
|
||||||
=== WooCommerce ===
|
=== WooCommerce ===
|
||||||
Contributors: automattic, mikejolley, jameskoster, claudiosanches, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, wpmuguru, royho
|
Contributors: automattic, mikejolley, jameskoster, claudiosanches, rodrigosprimo, peterfabian1000, vedjain, jamosova, obliviousharmony, konamiman, sadowski, wpmuguru, royho, barryhughes-1
|
||||||
Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, downloads, payments, paypal, storefront, stripe, woo commerce
|
Tags: e-commerce, store, sales, sell, woo, shop, cart, checkout, downloadable, downloads, payments, paypal, storefront, stripe, woo commerce
|
||||||
Requires at least: 5.5
|
Requires at least: 5.5
|
||||||
Tested up to: 5.7
|
Tested up to: 5.7
|
||||||
|
@ -160,6 +160,16 @@ WooCommerce comes with some sample data you can use to see how products look; im
|
||||||
|
|
||||||
== Changelog ==
|
== Changelog ==
|
||||||
|
|
||||||
|
= 5.2.0 RC 2021-03-30 =
|
||||||
|
|
||||||
|
* Update - WooCommerce Admin package 2.1.4. #29520
|
||||||
|
* Fix - Don't remove existing coupons from order when an invalid REST API request for updating coupons is submitted. #29474
|
||||||
|
* Fix - Wrong logic for including or excluding the payments step in the list of completed tasks in the onboarding wizard. #29518
|
||||||
|
|
||||||
|
**WooCommerce Admin - 2.1.4**
|
||||||
|
|
||||||
|
* Fix - Adding New Zealand and Ireland to selective bundle option, previously missed. #6649
|
||||||
|
|
||||||
= 5.2.0 beta 2021-03-23 =
|
= 5.2.0 beta 2021-03-23 =
|
||||||
|
|
||||||
**WooCommerce**
|
**WooCommerce**
|
||||||
|
@ -202,6 +212,8 @@ WooCommerce comes with some sample data you can use to see how products look; im
|
||||||
* Fix - add validation of the posted country codes on checkout. #28849
|
* Fix - add validation of the posted country codes on checkout. #28849
|
||||||
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
* Fix - Correctly display pagination arrows on RTL languages. #28523
|
||||||
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
* Fix - Invalid refund amount error on $0 refund when number of decimals is equal to 0. #27277
|
||||||
|
* Fix - Revert a replacement of wp_redirect to wp_safe_redirect in WC_Checkout::process_order_payment that caused issues in the default PayPal interface. #29459
|
||||||
|
* Fix - "Sale" badge misaligned on products when displaying 1 item per row. #29425
|
||||||
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
* Tweak - Added the Mercado Pago logo into the assets/images folder in order to use it in the payments setup task. #29365
|
||||||
* Tweak - Update the contributor guidelines. #29150
|
* Tweak - Update the contributor guidelines. #29150
|
||||||
* Tweak - Introduced phone number input validation. #27242
|
* Tweak - Introduced phone number input validation. #27242
|
||||||
|
|
|
@ -14,7 +14,7 @@
|
||||||
*
|
*
|
||||||
* @see https://docs.woocommerce.com/document/template-structure/
|
* @see https://docs.woocommerce.com/document/template-structure/
|
||||||
* @package WooCommerce\Templates
|
* @package WooCommerce\Templates
|
||||||
* @version 3.7.0
|
* @version 5.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
@ -53,10 +53,10 @@ do_action( 'woocommerce_before_mini_cart' ); ?>
|
||||||
);
|
);
|
||||||
?>
|
?>
|
||||||
<?php if ( empty( $product_permalink ) ) : ?>
|
<?php if ( empty( $product_permalink ) ) : ?>
|
||||||
<?php echo $thumbnail . $product_name; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo $thumbnail . wp_kses_post( $product_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
<?php else : ?>
|
<?php else : ?>
|
||||||
<a href="<?php echo esc_url( $product_permalink ); ?>">
|
<a href="<?php echo esc_url( $product_permalink ); ?>">
|
||||||
<?php echo $thumbnail . $product_name; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo $thumbnail . wp_kses_post( $product_name ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
</a>
|
</a>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
* @see https://docs.woocommerce.com/document/template-structure/
|
* @see https://docs.woocommerce.com/document/template-structure/
|
||||||
* @package WooCommerce\Templates
|
* @package WooCommerce\Templates
|
||||||
* @version 3.4.0
|
* @version 5.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
@ -40,7 +40,7 @@ $totals = $order->get_order_item_totals(); // phpcs:ignore WordPress.WP.GlobalVa
|
||||||
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
|
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_order_item_class', 'order_item', $item, $order ) ); ?>">
|
||||||
<td class="product-name">
|
<td class="product-name">
|
||||||
<?php
|
<?php
|
||||||
echo apply_filters( 'woocommerce_order_item_name', esc_html( $item->get_name() ), $item, false ); // @codingStandardsIgnoreLine
|
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
|
||||||
|
|
||||||
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, false );
|
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, false );
|
||||||
|
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
* @see https://docs.woocommerce.com/document/template-structure/
|
* @see https://docs.woocommerce.com/document/template-structure/
|
||||||
* @package WooCommerce\Templates
|
* @package WooCommerce\Templates
|
||||||
* @version 3.8.0
|
* @version 5.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
defined( 'ABSPATH' ) || exit;
|
defined( 'ABSPATH' ) || exit;
|
||||||
|
@ -35,7 +35,7 @@ defined( 'ABSPATH' ) || exit;
|
||||||
?>
|
?>
|
||||||
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
|
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
|
||||||
<td class="product-name">
|
<td class="product-name">
|
||||||
<?php echo apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' '; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) ) . ' '; ?>
|
||||||
<?php echo apply_filters( 'woocommerce_checkout_cart_item_quantity', ' <strong class="product-quantity">' . sprintf( '× %s', $cart_item['quantity'] ) . '</strong>', $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo apply_filters( 'woocommerce_checkout_cart_item_quantity', ' <strong class="product-quantity">' . sprintf( '× %s', $cart_item['quantity'] ) . '</strong>', $cart_item, $cart_item_key ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
<?php echo wc_get_formatted_cart_item_data( $cart_item ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?>
|
||||||
</td>
|
</td>
|
||||||
|
|
|
@ -21,14 +21,27 @@ defined( 'ABSPATH' ) || exit;
|
||||||
<li>
|
<li>
|
||||||
<?php do_action( 'woocommerce_widget_product_review_item_start', $args ); ?>
|
<?php do_action( 'woocommerce_widget_product_review_item_start', $args ); ?>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
?>
|
||||||
|
|
||||||
<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
|
<a href="<?php echo esc_url( get_comment_link( $comment->comment_ID ) ); ?>">
|
||||||
<?php echo $product->get_image(); ?>
|
<?php echo $product->get_image(); ?>
|
||||||
<span class="product-title"><?php echo $product->get_name(); ?></span>
|
<span class="product-title"><?php echo wp_kses_post( $product->get_name() ); ?></span>
|
||||||
</a>
|
</a>
|
||||||
|
|
||||||
<?php echo wc_get_rating_html( intval( get_comment_meta( $comment->comment_ID, 'rating', true ) ) ); ?>
|
<?php echo wc_get_rating_html( intval( get_comment_meta( $comment->comment_ID, 'rating', true ) ) ); ?>
|
||||||
|
|
||||||
<span class="reviewer"><?php echo sprintf( esc_html__( 'by %s', 'woocommerce' ), get_comment_author( $comment->comment_ID ) ); ?></span>
|
<span class="reviewer">
|
||||||
|
<?php
|
||||||
|
/* translators: %s: Comment author. */
|
||||||
|
echo sprintf( esc_html__( 'by %s', 'woocommerce' ), get_comment_author( $comment->comment_ID ) );
|
||||||
|
?>
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<?php
|
||||||
|
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
?>
|
||||||
|
|
||||||
<?php do_action( 'woocommerce_widget_product_review_item_end', $args ); ?>
|
<?php do_action( 'woocommerce_widget_product_review_item_end', $args ); ?>
|
||||||
</li>
|
</li>
|
||||||
|
|
|
@ -12,11 +12,11 @@
|
||||||
*
|
*
|
||||||
* @see https://docs.woocommerce.com/document/template-structure/
|
* @see https://docs.woocommerce.com/document/template-structure/
|
||||||
* @package WooCommerce\Templates\Emails\Plain
|
* @package WooCommerce\Templates\Emails\Plain
|
||||||
* @version 3.7.0
|
* @version 5.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
exit; // Exit if accessed directly
|
exit; // Exit if accessed directly.
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach ( $items as $item_id => $item ) :
|
foreach ( $items as $item_id => $item ) :
|
||||||
|
@ -30,15 +30,18 @@ foreach ( $items as $item_id => $item ) :
|
||||||
$purchase_note = $product->get_purchase_note();
|
$purchase_note = $product->get_purchase_note();
|
||||||
}
|
}
|
||||||
|
|
||||||
echo apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false );
|
// phpcs:disable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $item->get_name(), $item, false ) );
|
||||||
if ( $show_sku && $sku ) {
|
if ( $show_sku && $sku ) {
|
||||||
echo ' (#' . $sku . ')';
|
echo ' (#' . $sku . ')';
|
||||||
}
|
}
|
||||||
echo ' X ' . apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item );
|
echo ' X ' . apply_filters( 'woocommerce_email_order_item_quantity', $item->get_quantity(), $item );
|
||||||
echo ' = ' . $order->get_formatted_line_subtotal( $item ) . "\n";
|
echo ' = ' . $order->get_formatted_line_subtotal( $item ) . "\n";
|
||||||
|
// phpcs:enable WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
|
|
||||||
// allow other plugins to add additional product information here
|
// allow other plugins to add additional product information here.
|
||||||
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
|
do_action( 'woocommerce_order_item_meta_start', $item_id, $item, $order, $plain_text );
|
||||||
|
// phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||||||
echo strip_tags(
|
echo strip_tags(
|
||||||
wc_display_item_meta(
|
wc_display_item_meta(
|
||||||
$item,
|
$item,
|
||||||
|
@ -52,10 +55,10 @@ foreach ( $items as $item_id => $item ) :
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
|
|
||||||
// allow other plugins to add additional product information here
|
// allow other plugins to add additional product information here.
|
||||||
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
|
do_action( 'woocommerce_order_item_meta_end', $item_id, $item, $order, $plain_text );
|
||||||
}
|
}
|
||||||
// Note
|
// Note.
|
||||||
if ( $show_purchase_note && $purchase_note ) {
|
if ( $show_purchase_note && $purchase_note ) {
|
||||||
echo "\n" . do_shortcode( wp_kses_post( $purchase_note ) );
|
echo "\n" . do_shortcode( wp_kses_post( $purchase_note ) );
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
*
|
*
|
||||||
* @see https://docs.woocommerce.com/document/template-structure/
|
* @see https://docs.woocommerce.com/document/template-structure/
|
||||||
* @package WooCommerce\Templates
|
* @package WooCommerce\Templates
|
||||||
* @version 3.7.0
|
* @version 5.2.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
if ( ! defined( 'ABSPATH' ) ) {
|
if ( ! defined( 'ABSPATH' ) ) {
|
||||||
|
@ -30,7 +30,7 @@ if ( ! apply_filters( 'woocommerce_order_item_visible', true, $item ) ) {
|
||||||
$is_visible = $product && $product->is_visible();
|
$is_visible = $product && $product->is_visible();
|
||||||
$product_permalink = apply_filters( 'woocommerce_order_item_permalink', $is_visible ? $product->get_permalink( $item ) : '', $item, $order );
|
$product_permalink = apply_filters( 'woocommerce_order_item_permalink', $is_visible ? $product->get_permalink( $item ) : '', $item, $order );
|
||||||
|
|
||||||
echo apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
echo wp_kses_post( apply_filters( 'woocommerce_order_item_name', $product_permalink ? sprintf( '<a href="%s">%s</a>', $product_permalink, $item->get_name() ) : $item->get_name(), $item, $is_visible ) );
|
||||||
|
|
||||||
$qty = $item->get_quantity();
|
$qty = $item->get_quantity();
|
||||||
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
|
$refunded_qty = $order->get_qty_refunded_for_item( $item_id );
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
|
|
||||||
This document discusses unit tests. See [the e2e README](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e) to learn how to setup testing environment for running e2e tests and run them.
|
This document discusses unit tests. See [the e2e README](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e) to learn how to setup testing environment for running e2e tests and run them.
|
||||||
|
|
||||||
|
|
||||||
## Table of contents
|
## Table of contents
|
||||||
|
|
||||||
- [WooCommerce Tests](#woocommerce-tests)
|
- [WooCommerce Tests](#woocommerce-tests)
|
||||||
|
@ -51,7 +50,6 @@ Example:
|
||||||
|
|
||||||
**Important**: The `<db-name>` database will be created if it doesn't exist and all data will be removed during testing.
|
**Important**: The `<db-name>` database will be created if it doesn't exist and all data will be removed during testing.
|
||||||
|
|
||||||
|
|
||||||
## Running Tests
|
## Running Tests
|
||||||
|
|
||||||
Change to the plugin root directory and type:
|
Change to the plugin root directory and type:
|
||||||
|
@ -78,9 +76,9 @@ WooCommerce currently supports PHP versions from 7.0 up to 8.0, and this poses a
|
||||||
To workaround this, the testing strategy used by WooCommerce is as follows:
|
To workaround this, the testing strategy used by WooCommerce is as follows:
|
||||||
|
|
||||||
* We normally use PHPUnit 6.5.14
|
* We normally use PHPUnit 6.5.14
|
||||||
* For PHP 8 we use [a custom fork of PHPUnit 7.5.20 with support for PHP 8](https://github.com/woocommerce/phpunit/pull/1). The Travis build is configured to use this fork instead of the old version 6 when running in PHP 8.
|
* For PHP 8 we use [a custom fork of PHPUnit 7.5.20 with support for PHP 8](https://github.com/woocommerce/phpunit/pull/1). WooCommerce's GitHub Actions CI workflow is configured to use this fork instead of the old version 6 when running in PHP 8.
|
||||||
|
|
||||||
If you want to run the tests locally under PHP 8 you'll need to temporarily modify `composer.json` to use the custom PHPUnit fork in the same way that the Travis setup script does. These are the commands that you'll need (run them after a regular `composer install`):
|
If you want to run the tests locally under PHP 8 you'll need to temporarily modify `composer.json` to use the custom PHPUnit fork in the same way that the GitHub Actions CI workflow file does. These are the commands that you'll need (run them after a regular `composer install`):
|
||||||
|
|
||||||
```shell
|
```shell
|
||||||
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
|
curl -L https://github.com/woocommerce/phpunit/archive/add-compatibility-with-php8-to-phpunit-7.zip -o /tmp/phpunit-7.5-fork.zip
|
||||||
|
@ -92,7 +90,6 @@ composer bin phpunit require --dev -W phpunit/phpunit:@dev --ignore-platform-req
|
||||||
|
|
||||||
Just remember that you can't include the modified `composer.json` in any commit!
|
Just remember that you can't include the modified `composer.json` in any commit!
|
||||||
|
|
||||||
|
|
||||||
## Writing Tests
|
## Writing Tests
|
||||||
|
|
||||||
There are three different unit test directories:
|
There are three different unit test directories:
|
||||||
|
@ -122,12 +119,10 @@ General guidelines for all the unit tests:
|
||||||
* Filters persist between test cases so be sure to remove them in your test method or in the `tearDown()` method.
|
* Filters persist between test cases so be sure to remove them in your test method or in the `tearDown()` method.
|
||||||
* Use data providers where possible. Be sure that their name is like `data_provider_function_to_test` (i.e. the data provider for `test_is_postcode` would be `data_provider_test_is_postcode`). Read more about data providers [here](https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers).
|
* Use data providers where possible. Be sure that their name is like `data_provider_function_to_test` (i.e. the data provider for `test_is_postcode` would be `data_provider_test_is_postcode`). Read more about data providers [here](https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.data-providers).
|
||||||
|
|
||||||
|
|
||||||
## Automated Tests
|
## Automated Tests
|
||||||
|
|
||||||
Tests are automatically run with [Travis-CI](https://travis-ci.org/woocommerce/woocommerce) for each commit and pull request.
|
Tests are automatically run with [GitHub Actions](https://github.com/woocommerce/woocommerce/actions/workflows/ci.yml) for each commit and pull request.
|
||||||
|
|
||||||
|
|
||||||
## Code Coverage
|
## Code Coverage
|
||||||
|
|
||||||
Code coverage is available on [Codecov](https://codecov.io/gh/woocommerce/woocommerce/) which receives updated data after each Travis build.
|
Code coverage is available on [Codecov](https://codecov.io/gh/woocommerce/woocommerce/) which receives updated data after each build.
|
||||||
|
|
|
@ -1,11 +1,14 @@
|
||||||
#!/usr/bin/env bash
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
if [[ ${RUN_PHPCS} == 1 ]]; then
|
COMMIT_RANGE="${1}...${2}"
|
||||||
CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $TRAVIS_COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '`
|
CHANGED_FILES=`git diff --name-only --diff-filter=ACMR $COMMIT_RANGE | grep \\\\.php | awk '{print}' ORS=' '`
|
||||||
IGNORE="tests/cli/,includes/libraries/,includes/api/legacy/"
|
IGNORE="tests/cli/,includes/libraries/,includes/api/legacy/"
|
||||||
|
|
||||||
if [ "$CHANGED_FILES" != "" ]; then
|
if [ "$CHANGED_FILES" != "" ]; then
|
||||||
echo "Running Code Sniffer."
|
echo "Changed files: $CHANGED_FILES"
|
||||||
vendor/bin/phpcs --ignore=$IGNORE --encoding=utf-8 -s -n -p $CHANGED_FILES
|
echo "Running Code Sniffer."
|
||||||
fi
|
|
||||||
|
./vendor/bin/phpcs --ignore=$IGNORE --encoding=utf-8 -s -n -p --report-full --report-checkstyle=./phpcs-report.xml ${CHANGED_FILES}
|
||||||
|
else
|
||||||
|
echo "No changes found. Skipping PHPCS run."
|
||||||
fi
|
fi
|
||||||
|
|
|
@ -1,13 +0,0 @@
|
||||||
#!/usr/bin/env bash
|
|
||||||
# usage: travis.sh before|after
|
|
||||||
|
|
||||||
if [ $1 == 'after' ]; then
|
|
||||||
|
|
||||||
if [[ ${RUN_CODE_COVERAGE} == 1 ]]; then
|
|
||||||
bash <(curl -s https://codecov.io/bash)
|
|
||||||
wget https://scrutinizer-ci.com/ocular.phar
|
|
||||||
chmod +x ocular.phar
|
|
||||||
php ocular.phar code-coverage:upload --format=php-clover coverage.clover
|
|
||||||
fi
|
|
||||||
|
|
||||||
fi
|
|
|
@ -55,7 +55,7 @@ This section explains how e2e tests are working behind the scenes. These are not
|
||||||
|
|
||||||
### Test Environment
|
### Test Environment
|
||||||
|
|
||||||
We recommend using Docker for running tests locally in order for the test environment to match the setup on Travis CI (where Docker is also used for running tests). [An official WordPress Docker image](https://github.com/docker-library/docs/blob/master/wordpress/README.md) is used to build the site. Once the site using the WP Docker image is built, the current WooCommerce dev branch is mapped into the `plugins` folder of that newly built test site.
|
We recommend using Docker for running tests locally in order for the test environment to match the setup on Github CI (where Docker is also used for running tests). [An official WordPress Docker image](https://github.com/docker-library/docs/blob/master/wordpress/README.md) is used to build the site. Once the site using the WP Docker image is built, the current WooCommerce dev branch is mapped into the `plugins` folder of that newly built test site.
|
||||||
|
|
||||||
### Test Variables
|
### Test Variables
|
||||||
|
|
||||||
|
@ -77,13 +77,13 @@ The jest test sequencer uses the following test variables:
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
If you need to modify the port for your local test environment (eg. port is already in use), copy `tests/e2e/env/config/default.json` to `tests/e2e/config/default.json` and edit that copy. Only edit this file while your test container is `down`.
|
If you need to modify the port for your local test environment (eg. port is already in use), edit `tests/e2e/config/default.json`. Only edit this file while your test container is `down`.
|
||||||
|
|
||||||
### Jest test sequencer
|
### Jest test sequencer
|
||||||
|
|
||||||
[Jest](https://jestjs.io/) is being used to run e2e tests. Jest sequencer introduces tools that can be used to specify the order in which the tests are being run. In our case, they are being run in alphabetical order of the directories where tests are located. This way, tests in the new directory `activate-and-setup` will run first. By default, jest runs tests ordered by the time it takes to run the test (the test that takes longer to run will be run first, the test that takes less time to run will run last).
|
[Jest](https://jestjs.io/) is being used to run e2e tests. Jest sequencer introduces tools that can be used to specify the order in which the tests are being run. In our case, they are being run in alphabetical order of the directories where tests are located. This way, tests in the directory `activate-and-setup` will run first. By default, jest runs tests ordered by the time it takes to run the test (the test that takes longer to run will be run first, the test that takes less time to run will run last).
|
||||||
|
|
||||||
The Setup Wizard e2e test (located in `activate-and-setup` directory) will run first. This ensures that WooCommerce is active and the setup wizard has been completed. This is necessary because `docker:up` creates a brand new install of WordPress and WooCommerce.
|
The Setup Wizard e2e test runs first to ensure that WooCommerce is active and that the setup wizard has been completed. This is necessary because `docker:up` creates a brand new install of WordPress and WooCommerce.
|
||||||
|
|
||||||
### Chromium Download
|
### Chromium Download
|
||||||
|
|
||||||
|
@ -99,23 +99,25 @@ Puppeteer will still automatically download Chromium when needed.
|
||||||
|
|
||||||
### Prep work for running tests
|
### Prep work for running tests
|
||||||
|
|
||||||
|
Run the following in a terminal/command line window
|
||||||
|
|
||||||
- `cd` to the WooCommerce plugin folder
|
- `cd` to the WooCommerce plugin folder
|
||||||
|
|
||||||
- `git checkout trunk` or checkout the branch where you need to run tests
|
- `git checkout trunk` (or the branch where you need to run tests)
|
||||||
|
|
||||||
- Run `nvm use`
|
- `nvm use`
|
||||||
|
|
||||||
- Run `npm install`
|
- `npm install`
|
||||||
|
|
||||||
- Run `composer install --no-dev`
|
- `composer install --no-dev`
|
||||||
|
|
||||||
- Run `npm run build:assets`
|
- `npm run build:assets`
|
||||||
|
|
||||||
- Run `npm install jest --global` (this only needs to be done once)
|
- `npm install jest --global` (this only needs to be done once)
|
||||||
|
|
||||||
- Run `npx wc-e2e docker:up` - it will build the test site using Docker.
|
- `npx wc-e2e docker:up` (this will build the test site using Docker)
|
||||||
|
|
||||||
- Run `docker ps` - to confirm that the Docker containers are running. You should see the log that looks similar to below indicating that everything had been built as expected:
|
- Use `docker ps` to confirm that the Docker containers are running. You should see a log similar to one below indicating that everything had been built as expected:
|
||||||
|
|
||||||
```
|
```
|
||||||
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
|
||||||
|
@ -305,7 +307,7 @@ describe( 'Merchant can create virtual product', () => {
|
||||||
} );
|
} );
|
||||||
```
|
```
|
||||||
|
|
||||||
Next, you can start filling up each section with relevant functions (test building blocks). Note, that we have the `@woocommerce/e2e-utils` package where many reusable helper functions can be found for writing tests. For example, `flows.js` of `@woocommerce/e2e-utils` package contains `merchant` object that has `login` method. As a result, in the test it can be used as `await merchant.login();` so the first `it()` section of the test will become:
|
Next, you can start filling up each section with relevant functions (test building blocks). Note, that we have the `@woocommerce/e2e-utils` package where many reusable helper functions can be found for writing tests. For example, `merchant.js` of `@woocommerce/e2e-utils` package contains `merchant` object that has `login` method. As a result, in the test it can be used as `await merchant.login();` so the first `it()` section of the test will become:
|
||||||
|
|
||||||
```
|
```
|
||||||
it( 'merchant can log in', async () => {
|
it( 'merchant can log in', async () => {
|
||||||
|
@ -327,7 +329,7 @@ it( 'merchant can create virtual product', async () => {
|
||||||
|
|
||||||
You would then continue writing the test using utilities where possible.
|
You would then continue writing the test using utilities where possible.
|
||||||
|
|
||||||
Make sure to utilize the functions of the `@automattic/puppeteer-utils` package where possible. For example, if you need to wait for certain element to be ready to be clicked on and then click on it, you can use `waitAndClick()` function:
|
Make sure to utilize the functions of the `@automattic/puppeteer-utils` package where possible. For example, if you need to wait for a certain element to be ready to be clicked on and then click on it, you can use `waitAndClick()` function:
|
||||||
|
|
||||||
```
|
```
|
||||||
await waitAndClick( page, '#selector' );
|
await waitAndClick( page, '#selector' );
|
||||||
|
@ -351,4 +353,6 @@ In the example above, you can see that `allows customer to see downloads` part o
|
||||||
|
|
||||||
## Debugging tests
|
## Debugging tests
|
||||||
|
|
||||||
|
The test sequencer (`npx wc-e2e test:e2e`) includes support for saving [screenshots on test errors](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env#test-screenshots) which can be sent to a Slack channel via a [Slackbot](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env#slackbot-setup).
|
||||||
|
|
||||||
For Puppeteer debugging, follow [Google's documentation](https://developers.google.com/web/tools/puppeteer/debugging).
|
For Puppeteer debugging, follow [Google's documentation](https://developers.google.com/web/tools/puppeteer/debugging).
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
# 0.1.2
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Support for the external product type.
|
- Support for the external product type.
|
||||||
|
|
|
@ -49,11 +49,19 @@ httpClient.get( '/wc/v3/products' ).then( ( response ) => {
|
||||||
|
|
||||||
### Repositories
|
### Repositories
|
||||||
|
|
||||||
As a convenience utility we've created repositories for core data types that can simplify interacting with the API.
|
As a convenience utility we've created repositories for core data types that can simplify interacting with the API:
|
||||||
|
|
||||||
|
- `SimpleProduct`
|
||||||
|
- `ExternalProduct`
|
||||||
|
- `GroupedProduct`
|
||||||
|
- `VariableProduct`
|
||||||
|
- `ProductVariation`
|
||||||
|
- `Coupon`
|
||||||
|
|
||||||
These repositories provide CRUD methods for ease-of-use:
|
These repositories provide CRUD methods for ease-of-use:
|
||||||
|
|
||||||
```javascript
|
```javascript
|
||||||
import { SimpleProduct } from '@woocommerce/api';
|
import { HTTPClientFactory, SimpleProduct } from '@woocommerce/api';
|
||||||
|
|
||||||
// Prepare the HTTP client that will be consumed by the repository.
|
// Prepare the HTTP client that will be consumed by the repository.
|
||||||
// This is necessary so that it can make requests to the REST API.
|
// This is necessary so that it can make requests to the REST API.
|
||||||
|
@ -68,5 +76,86 @@ const product = repository.create( { name: 'Simple Product', regularPrice: '9.99
|
||||||
|
|
||||||
// The response will be one of the models with structured properties and TypeScript support.
|
// The response will be one of the models with structured properties and TypeScript support.
|
||||||
product.id;
|
product.id;
|
||||||
|
```
|
||||||
|
|
||||||
|
#### Repository Methods
|
||||||
|
|
||||||
|
The following methods are available on all repositories:
|
||||||
|
|
||||||
|
- `create( {...properties} )` - Create a single object of the model type
|
||||||
|
- `delete( objectId )` - Delete a single object of the model type
|
||||||
|
- `list` - Retrieve a list of the existing objects of that model type
|
||||||
|
- `read( objectId )` - Read a single object of the model type
|
||||||
|
- `update( objectId, {...properties} )` - Update a single object of the model type
|
||||||
|
|
||||||
|
#### Child Repositories
|
||||||
|
|
||||||
|
`ProductVariation` is a child model repository. In child model repositories, each method requires the `parentId` as the first parameter:
|
||||||
|
|
||||||
|
```javascript
|
||||||
|
import { HTTPClientFactory, VariableProduct, ProductVariation } from '@woocommerce/api';
|
||||||
|
|
||||||
|
const httpClient = HTTPClientFactory.build( 'https://example.com' )
|
||||||
|
.withBasicAuth( 'username', 'password' )
|
||||||
|
.withIndexPermalinks()
|
||||||
|
.create();
|
||||||
|
|
||||||
|
const productRepository = VariableProduct.restRepository( httpClient );
|
||||||
|
const variationRepository = ProductVariation.restRepository( httpClient );
|
||||||
|
|
||||||
|
const product = await productRepository.create({
|
||||||
|
"name": "Variable Product with Three Attributes",
|
||||||
|
"defaultAttributes": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "Size",
|
||||||
|
"option": "Medium"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "Colour",
|
||||||
|
"option": "Blue"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "Colour",
|
||||||
|
"isVisibleOnProductPage": true,
|
||||||
|
"isForVariations": true,
|
||||||
|
"options": [
|
||||||
|
"Red",
|
||||||
|
"Green",
|
||||||
|
"Blue"
|
||||||
|
],
|
||||||
|
"sortOrder": 0
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"id": 0,
|
||||||
|
"name": "Size",
|
||||||
|
"isVisibleOnProductPage": true,
|
||||||
|
"isForVariations": true,
|
||||||
|
"options": [
|
||||||
|
"Small",
|
||||||
|
"Medium",
|
||||||
|
"Large"
|
||||||
|
],
|
||||||
|
"sortOrder": 0
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
const variation = await variationRepository.create( product.id, {
|
||||||
|
"regularPrice": "19.99",
|
||||||
|
"attributes": [
|
||||||
|
{
|
||||||
|
"name": "Size",
|
||||||
|
"option": "Large"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"name": "Colour",
|
||||||
|
"option": "Red"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
});
|
||||||
```
|
```
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@woocommerce/api",
|
"name": "@woocommerce/api",
|
||||||
"version": "0.1.0",
|
"version": "0.1.1",
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@woocommerce/api",
|
"name": "@woocommerce/api",
|
||||||
"version": "0.1.1",
|
"version": "0.1.2",
|
||||||
"author": "Automattic",
|
"author": "Automattic",
|
||||||
"description": "A simple interface for interacting with a WooCommerce installation.",
|
"description": "A simple interface for interacting with a WooCommerce installation.",
|
||||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/api/README.md",
|
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/api/README.md",
|
||||||
|
|
|
@ -27,6 +27,14 @@ export const baseProductURL = () => '/wc/v3/products/';
|
||||||
*/
|
*/
|
||||||
export const buildProductURL = ( id: ModelID ) => baseProductURL() + id;
|
export const buildProductURL = ( id: ModelID ) => baseProductURL() + id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A common delete product URL builder.
|
||||||
|
*
|
||||||
|
* @param {ModelID} id the id of the product.
|
||||||
|
* @return {string} RESTful Url.
|
||||||
|
*/
|
||||||
|
export const deleteProductURL = ( id: ModelID ) => buildProductURL( id ) + '?force=true';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The base for all product types.
|
* The base for all product types.
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -3,6 +3,7 @@ import { ModelRepository } from '../../../framework';
|
||||||
import {
|
import {
|
||||||
baseProductURL,
|
baseProductURL,
|
||||||
buildProductURL,
|
buildProductURL,
|
||||||
|
deleteProductURL,
|
||||||
ExternalProduct,
|
ExternalProduct,
|
||||||
CreatesExternalProducts,
|
CreatesExternalProducts,
|
||||||
DeletesExternalProducts,
|
DeletesExternalProducts,
|
||||||
|
@ -61,6 +62,6 @@ export function externalProductRESTRepository( httpClient: HTTPClient ): ListsEx
|
||||||
restCreate< ExternalProductRepositoryParams >( baseProductURL, ExternalProduct, httpClient, transformer ),
|
restCreate< ExternalProductRepositoryParams >( baseProductURL, ExternalProduct, httpClient, transformer ),
|
||||||
restRead< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
|
restRead< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
|
||||||
restUpdate< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
|
restUpdate< ExternalProductRepositoryParams >( buildProductURL, ExternalProduct, httpClient, transformer ),
|
||||||
restDelete< ExternalProductRepositoryParams >( buildProductURL, httpClient ),
|
restDelete< ExternalProductRepositoryParams >( deleteProductURL, httpClient ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
UpdatesGroupedProducts,
|
UpdatesGroupedProducts,
|
||||||
baseProductURL,
|
baseProductURL,
|
||||||
buildProductURL,
|
buildProductURL,
|
||||||
|
deleteProductURL,
|
||||||
} from '../../../models';
|
} from '../../../models';
|
||||||
import {
|
import {
|
||||||
createProductTransformer,
|
createProductTransformer,
|
||||||
|
@ -55,6 +56,6 @@ export function groupedProductRESTRepository( httpClient: HTTPClient ): ListsGro
|
||||||
restCreate< GroupedProductRepositoryParams >( baseProductURL, GroupedProduct, httpClient, transformer ),
|
restCreate< GroupedProductRepositoryParams >( baseProductURL, GroupedProduct, httpClient, transformer ),
|
||||||
restRead< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
|
restRead< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
|
||||||
restUpdate< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
|
restUpdate< GroupedProductRepositoryParams >( buildProductURL, GroupedProduct, httpClient, transformer ),
|
||||||
restDelete< GroupedProductRepositoryParams >( buildProductURL, httpClient ),
|
restDelete< GroupedProductRepositoryParams >( deleteProductURL, httpClient ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -4,6 +4,7 @@ import {
|
||||||
SimpleProduct,
|
SimpleProduct,
|
||||||
baseProductURL,
|
baseProductURL,
|
||||||
buildProductURL,
|
buildProductURL,
|
||||||
|
deleteProductURL,
|
||||||
CreatesSimpleProducts,
|
CreatesSimpleProducts,
|
||||||
DeletesSimpleProducts,
|
DeletesSimpleProducts,
|
||||||
ListsSimpleProducts,
|
ListsSimpleProducts,
|
||||||
|
@ -70,6 +71,6 @@ export function simpleProductRESTRepository( httpClient: HTTPClient ): ListsSimp
|
||||||
restCreate< SimpleProductRepositoryParams >( baseProductURL, SimpleProduct, httpClient, transformer ),
|
restCreate< SimpleProductRepositoryParams >( baseProductURL, SimpleProduct, httpClient, transformer ),
|
||||||
restRead< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
|
restRead< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
|
||||||
restUpdate< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
|
restUpdate< SimpleProductRepositoryParams >( buildProductURL, SimpleProduct, httpClient, transformer ),
|
||||||
restDelete< SimpleProductRepositoryParams >( buildProductURL, httpClient ),
|
restDelete< SimpleProductRepositoryParams >( deleteProductURL, httpClient ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,6 +10,7 @@ import {
|
||||||
UpdatesVariableProducts,
|
UpdatesVariableProducts,
|
||||||
baseProductURL,
|
baseProductURL,
|
||||||
buildProductURL,
|
buildProductURL,
|
||||||
|
deleteProductURL,
|
||||||
} from '../../../models';
|
} from '../../../models';
|
||||||
import {
|
import {
|
||||||
createProductTransformer,
|
createProductTransformer,
|
||||||
|
@ -67,6 +68,6 @@ export function variableProductRESTRepository( httpClient: HTTPClient ): ListsVa
|
||||||
restCreate< VariableProductRepositoryParams >( baseProductURL, VariableProduct, httpClient, transformer ),
|
restCreate< VariableProductRepositoryParams >( baseProductURL, VariableProduct, httpClient, transformer ),
|
||||||
restRead< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
|
restRead< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
|
||||||
restUpdate< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
|
restUpdate< VariableProductRepositoryParams >( buildProductURL, VariableProduct, httpClient, transformer ),
|
||||||
restDelete< VariableProductRepositoryParams >( buildProductURL, httpClient ),
|
restDelete< VariableProductRepositoryParams >( deleteProductURL, httpClient ),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,26 +1,28 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
# 0.1.3
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Shopper My Account Create Account
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- removed use of ES6 `import`
|
||||||
|
|
||||||
|
# 0.1.2
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- api package test for variable products and product variations
|
- api package test for variable products and product variations
|
||||||
- api package test for grouped products
|
- api package test for grouped products
|
||||||
- api package test for external products
|
- api package test for external products
|
||||||
- api package test for coupons
|
- api package test for coupons
|
||||||
|
|
||||||
# 0.1.1
|
|
||||||
|
|
||||||
## Added
|
|
||||||
|
|
||||||
- Registered Shopper Checkout tests
|
- Registered Shopper Checkout tests
|
||||||
- Merchant Order Status Filter tests
|
|
||||||
- Merchant Order Refund tests
|
|
||||||
- Merchant Apply Coupon tests
|
|
||||||
- Added new config variable for Simple Product price to `tests/e2e/env/config/default.json`. Defaults to 9.99
|
|
||||||
- Merchant Product Edit tests
|
- Merchant Product Edit tests
|
||||||
- Merchant Product Search tests
|
- Merchant Product Search tests
|
||||||
- Shopper Single Product tests
|
- Shopper Single Product tests
|
||||||
- Shopper My Account Pay Order
|
- Shopper My Account Pay Order
|
||||||
- Shopper Checkout Apply Coupon
|
|
||||||
- Shopper Shop Browse Search Sort
|
- Shopper Shop Browse Search Sort
|
||||||
- Merchant Orders Customer Checkout Page
|
- Merchant Orders Customer Checkout Page
|
||||||
- Shopper Cart Apply Coupon
|
- Shopper Cart Apply Coupon
|
||||||
|
@ -28,6 +30,18 @@
|
||||||
- Merchant Settings Shipping Zones
|
- Merchant Settings Shipping Zones
|
||||||
- Shopper Variable product info updates on different variations
|
- Shopper Variable product info updates on different variations
|
||||||
- Merchant order emails flow
|
- Merchant order emails flow
|
||||||
|
- Merchant analytics page load tests
|
||||||
|
- Shopper Checkout Create Account
|
||||||
|
|
||||||
|
# 0.1.1
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- Merchant Order Status Filter tests
|
||||||
|
- Merchant Order Refund tests
|
||||||
|
- Merchant Apply Coupon tests
|
||||||
|
- Added new config variable for Simple Product price to `tests/e2e/env/config/default.json`. Defaults to 9.99
|
||||||
|
- Shopper Checkout Apply Coupon
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
|
||||||
|
|
|
@ -45,22 +45,24 @@ The functions to access the core tests are:
|
||||||
### Merchant
|
### Merchant
|
||||||
|
|
||||||
- `runMerchantTests` - Run all merchant tests
|
- `runMerchantTests` - Run all merchant tests
|
||||||
- `runCreateCouponTest` - Merchant can create coupon
|
- `runAddNewShippingZoneTest` - Merchant can create shipping zones and let shopper test them
|
||||||
- `runCreateOrderTest` - Merchant can create order
|
|
||||||
- `runAddSimpleProductTest` - Merchant can create a simple product
|
- `runAddSimpleProductTest` - Merchant can create a simple product
|
||||||
- `runAddVariableProductTest` - Merchant can create a variable product
|
- `runAddVariableProductTest` - Merchant can create a variable product
|
||||||
- `runUpdateGeneralSettingsTest` - Merchant can update general settings
|
- `runCreateCouponTest` - Merchant can create coupon
|
||||||
- `runProductSettingsTest` - Merchant can update product settings
|
- `runCreateOrderTest` - Merchant can create order
|
||||||
- `runTaxSettingsTest` - Merchant can update tax settings
|
- `runMerchantOrdersCustomerPaymentPage` - Merchant can visit the customer payment page
|
||||||
|
- `runMerchantOrderEmailsTest` - Merchant can receive order emails and resend emails by Order Actions
|
||||||
- `runOrderStatusFilterTest` - Merchant can filter orders by order status
|
- `runOrderStatusFilterTest` - Merchant can filter orders by order status
|
||||||
- `runOrderRefundTest` - Merchant can refund an order
|
- `runOrderRefundTest` - Merchant can refund an order
|
||||||
- `runOrderApplyCouponTest` - Merchant can apply a coupon to an order
|
- `runOrderApplyCouponTest` - Merchant can apply a coupon to an order
|
||||||
|
- `runOrderSearchingTest` - Merchant can search for order via different terms
|
||||||
- `runProductEditDetailsTest` - Merchant can edit an existing product
|
- `runProductEditDetailsTest` - Merchant can edit an existing product
|
||||||
- `runProductSearchTest` - Merchant can search for a product and view it
|
- `runProductSearchTest` - Merchant can search for a product and view it
|
||||||
- `runMerchantOrdersCustomerPaymentPage` - Merchant can visit the customer payment page
|
- `runProductSettingsTest` - Merchant can update product settings
|
||||||
- `runOrderSearchingTest` - Merchant can search for order via different terms
|
- `runTaxSettingsTest` - Merchant can update tax settings
|
||||||
- `runAddNewShippingZoneTest` - Merchant can create shipping zones and let shopper test them
|
- `runUpdateGeneralSettingsTest` - Merchant can update general settings
|
||||||
- `runMerchantOrderEmailsTest` - Merchant can receive order emails and resend emails by Order Actions
|
- `runMerchantOrderEmailsTest` - Merchant can receive order emails and resend emails by Order Actions
|
||||||
|
- `runAnalyticsPageLoadsTest` - Merchant can load and see all pages in Analytics
|
||||||
|
|
||||||
### Shopper
|
### Shopper
|
||||||
|
|
||||||
|
@ -70,12 +72,21 @@ The functions to access the core tests are:
|
||||||
- `runCheckoutApplyCouponsTest` - Shopper can use coupons on checkout
|
- `runCheckoutApplyCouponsTest` - Shopper can use coupons on checkout
|
||||||
- `runCheckoutPageTest` - Shopper can complete checkout
|
- `runCheckoutPageTest` - Shopper can complete checkout
|
||||||
- `runMyAccountPageTest` - Shopper can access my account page
|
- `runMyAccountPageTest` - Shopper can access my account page
|
||||||
- `runSingleProductPageTest` - Shopper can view single product page in many variations (simple, variable, grouped)
|
- `runMyAccountPayOrderTest` - Shopper can pay for their order in My Account
|
||||||
- `runMyAccountPayOrderTest` - Shopper can pay for his order in My Account
|
|
||||||
- `runCartApplyCouponsTest` - Shopper can apply coupons in the cart
|
|
||||||
- `runCheckoutApplyCouponsTest` - Shopper can apply coupons in the checkout
|
|
||||||
- `runProductBrowseSearchSortTest` - Shopper can browse, search & sort products
|
- `runProductBrowseSearchSortTest` - Shopper can browse, search & sort products
|
||||||
|
- `runSingleProductPageTest` - Shopper can view single product page in many variations (simple, variable, grouped)
|
||||||
- `runVariableProductUpdateTest` - Shopper can view and update variations on a variable product
|
- `runVariableProductUpdateTest` - Shopper can view and update variations on a variable product
|
||||||
|
- `runCheckoutCreateAccountTest` - Shopper can create an account during checkout
|
||||||
|
- `runMyAccountCreateAccountTest` - Shopper can create an account via my account page
|
||||||
|
|
||||||
|
### REST API
|
||||||
|
|
||||||
|
- `runApiTests` - Run all API tests
|
||||||
|
- `runExternalProductAPITest` - Can create, read, and delete an external product
|
||||||
|
- `runGroupedProductAPITest` - Can create, read, and delete a grouped product
|
||||||
|
- `runVariableProductAPITest` - Can create, read, and delete a variable product and its variations
|
||||||
|
- `runCouponApiTest` - Can create, read, and delete a coupon
|
||||||
|
|
||||||
|
|
||||||
## Contributing a new test
|
## Contributing a new test
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@woocommerce/e2e-core-tests",
|
"name": "@woocommerce/e2e-core-tests",
|
||||||
"version": "0.1.1",
|
"version": "0.1.3",
|
||||||
"description": "End-To-End (E2E) tests for WooCommerce",
|
"description": "End-To-End (E2E) tests for WooCommerce",
|
||||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests/README.md",
|
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/core-tests/README.md",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -15,8 +15,8 @@
|
||||||
"faker": "^5.5.2"
|
"faker": "^5.5.2"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@woocommerce/api": "^0.1.1",
|
"@woocommerce/api": "^0.1.2",
|
||||||
"@woocommerce/e2e-utils": "^0.1.2"
|
"@woocommerce/e2e-utils": "^0.1.4"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|
|
@ -80,6 +80,10 @@ const runGroupedProductAPITest = () => {
|
||||||
it('can delete a grouped product', async () => {
|
it('can delete a grouped product', async () => {
|
||||||
const status = repository.delete( product.id );
|
const status = repository.delete( product.id );
|
||||||
expect( status ).toBeTruthy();
|
expect( status ).toBeTruthy();
|
||||||
|
// Delete the simple "child" products.
|
||||||
|
groupedProducts.forEach( ( productId ) => {
|
||||||
|
repository.delete( productId );
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
|
@ -16,8 +16,10 @@ const runCheckoutApplyCouponsTest = require( './shopper/front-end-checkout-coupo
|
||||||
const runCheckoutPageTest = require( './shopper/front-end-checkout.test' );
|
const runCheckoutPageTest = require( './shopper/front-end-checkout.test' );
|
||||||
const runMyAccountPageTest = require( './shopper/front-end-my-account.test' );
|
const runMyAccountPageTest = require( './shopper/front-end-my-account.test' );
|
||||||
const runMyAccountPayOrderTest = require( './shopper/front-end-my-account-pay-order.test' );
|
const runMyAccountPayOrderTest = require( './shopper/front-end-my-account-pay-order.test' );
|
||||||
|
const runMyAccountCreateAccountTest = require( './shopper/front-end-my-account-create-account.test' );
|
||||||
const runSingleProductPageTest = require( './shopper/front-end-single-product.test' );
|
const runSingleProductPageTest = require( './shopper/front-end-single-product.test' );
|
||||||
const runVariableProductUpdateTest = require( './shopper/front-end-variable-product-updates.test' );
|
const runVariableProductUpdateTest = require( './shopper/front-end-variable-product-updates.test' );
|
||||||
|
const runCheckoutCreateAccountTest = require( './shopper/front-end-checkout-create-account.test' );
|
||||||
|
|
||||||
// Merchant tests
|
// Merchant tests
|
||||||
const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' );
|
const runAddNewShippingZoneTest = require ( './merchant/wp-admin-settings-shipping-zones.test' );
|
||||||
|
@ -37,6 +39,7 @@ const runProductSearchTest = require( './merchant/wp-admin-product-search.test'
|
||||||
const runMerchantOrdersCustomerPaymentPage = require( './merchant/wp-admin-order-customer-payment-page.test' );
|
const runMerchantOrdersCustomerPaymentPage = require( './merchant/wp-admin-order-customer-payment-page.test' );
|
||||||
const runMerchantOrderEmailsTest = require( './merchant/wp-admin-order-emails.test' );
|
const runMerchantOrderEmailsTest = require( './merchant/wp-admin-order-emails.test' );
|
||||||
const runOrderSearchingTest = require( './merchant/wp-admin-order-searching.test' );
|
const runOrderSearchingTest = require( './merchant/wp-admin-order-searching.test' );
|
||||||
|
const runAnalyticsPageLoadsTest = require( './merchant/wp-admin-analytics-page-loads.test' );
|
||||||
|
|
||||||
// REST API tests
|
// REST API tests
|
||||||
const runExternalProductAPITest = require( './api/external-product.test' );
|
const runExternalProductAPITest = require( './api/external-product.test' );
|
||||||
|
@ -59,8 +62,10 @@ const runShopperTests = () => {
|
||||||
runCheckoutPageTest();
|
runCheckoutPageTest();
|
||||||
runMyAccountPageTest();
|
runMyAccountPageTest();
|
||||||
runMyAccountPayOrderTest();
|
runMyAccountPayOrderTest();
|
||||||
|
runMyAccountCreateAccountTest();
|
||||||
runSingleProductPageTest();
|
runSingleProductPageTest();
|
||||||
runVariableProductUpdateTest();
|
runVariableProductUpdateTest();
|
||||||
|
runCheckoutCreateAccountTest();
|
||||||
};
|
};
|
||||||
|
|
||||||
const runMerchantTests = () => {
|
const runMerchantTests = () => {
|
||||||
|
@ -81,6 +86,7 @@ const runMerchantTests = () => {
|
||||||
runProductEditDetailsTest();
|
runProductEditDetailsTest();
|
||||||
runProductSearchTest();
|
runProductSearchTest();
|
||||||
runMerchantOrdersCustomerPaymentPage();
|
runMerchantOrdersCustomerPaymentPage();
|
||||||
|
runAnalyticsPageLoadsTest();
|
||||||
}
|
}
|
||||||
|
|
||||||
const runApiTests = () => {
|
const runApiTests = () => {
|
||||||
|
@ -129,5 +135,8 @@ module.exports = {
|
||||||
runAddNewShippingZoneTest,
|
runAddNewShippingZoneTest,
|
||||||
runProductBrowseSearchSortTest,
|
runProductBrowseSearchSortTest,
|
||||||
runApiTests,
|
runApiTests,
|
||||||
runAddShippingClassesTest
|
runAddShippingClassesTest,
|
||||||
|
runAnalyticsPageLoadsTest,
|
||||||
|
runCheckoutCreateAccountTest,
|
||||||
|
runMyAccountCreateAccountTest
|
||||||
};
|
};
|
||||||
|
|
|
@ -0,0 +1,105 @@
|
||||||
|
/* eslint-disable jest/no-export, jest/no-disabled-tests */
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
merchant,
|
||||||
|
} = require( '@woocommerce/e2e-utils' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
it,
|
||||||
|
describe,
|
||||||
|
beforeAll,
|
||||||
|
} = require( '@jest/globals' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Quick check for page title and no data message.
|
||||||
|
*
|
||||||
|
* @param pageTitle Page title in H1.
|
||||||
|
* @param element Defaults to '.d3-chart__empty-message'
|
||||||
|
* @param elementText Defaults to 'No data for the selected date range'
|
||||||
|
*/
|
||||||
|
const checkHeadingAndElement = async (
|
||||||
|
pageTitle, element = '.d3-chart__empty-message', elementText = 'No data for the selected date range') => {
|
||||||
|
await expect(page).toMatchElement('h1', {text: pageTitle});
|
||||||
|
await expect(page).toMatchElement(element, elementText);
|
||||||
|
};
|
||||||
|
|
||||||
|
const runAnalyticsPageLoadsTest = () => {
|
||||||
|
describe('Analytics > Opening Top Level Pages', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await merchant.login();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Overview page properly', async () => {
|
||||||
|
// Go to "overview" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('overview');
|
||||||
|
await checkHeadingAndElement('Overview');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Products page properly', async () => {
|
||||||
|
// Go to "products" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('products');
|
||||||
|
await checkHeadingAndElement('Products');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Revenue page properly', async () => {
|
||||||
|
// Go to "revenue" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('revenue');
|
||||||
|
await checkHeadingAndElement('Revenue');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Orders page properly', async () => {
|
||||||
|
// Go to "orders" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('orders');
|
||||||
|
await checkHeadingAndElement('Orders');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Variations page properly', async () => {
|
||||||
|
// Go to "variations" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('variations');
|
||||||
|
await checkHeadingAndElement('Variations');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Categories page properly', async () => {
|
||||||
|
// Go to "categories" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('categories');
|
||||||
|
await checkHeadingAndElement('Categories');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Coupons page properly', async () => {
|
||||||
|
// Go to "coupons" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('coupons');
|
||||||
|
await checkHeadingAndElement('Coupons');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Taxes page properly', async () => {
|
||||||
|
// Go to "taxes" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('taxes');
|
||||||
|
await checkHeadingAndElement('Taxes');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Downloads page properly', async () => {
|
||||||
|
// Go to "downloads" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('downloads');
|
||||||
|
await checkHeadingAndElement('Downloads');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Stock page properly', async () => {
|
||||||
|
// Go to "stock" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('stock');
|
||||||
|
await checkHeadingAndElement('Stock', '.components-button > span', 'Product / Variation');
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can see Settings page properly', async () => {
|
||||||
|
// Go to "settings" page and verify it
|
||||||
|
await merchant.openAnalyticsPage('settings');
|
||||||
|
await checkHeadingAndElement('Settings', 'h2', 'Analytics Settings');
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
module.exports = runAnalyticsPageLoadsTest;
|
|
@ -1,5 +1,5 @@
|
||||||
/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/no-standalone-expect */
|
/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/no-standalone-expect */
|
||||||
import {createSimpleProduct} from "@woocommerce/e2e-utils";
|
const { createSimpleProduct } = require( '@woocommerce/e2e-utils' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
|
|
|
@ -6,7 +6,6 @@
|
||||||
const {
|
const {
|
||||||
merchant,
|
merchant,
|
||||||
clearAndFillInput,
|
clearAndFillInput,
|
||||||
selectOptionInSelect2,
|
|
||||||
searchForOrder,
|
searchForOrder,
|
||||||
createSimpleProduct,
|
createSimpleProduct,
|
||||||
addProductToOrder,
|
addProductToOrder,
|
||||||
|
@ -20,40 +19,36 @@ const runOrderSearchingTest = () => {
|
||||||
await merchant.login();
|
await merchant.login();
|
||||||
await createSimpleProduct('Wanted Product');
|
await createSimpleProduct('Wanted Product');
|
||||||
|
|
||||||
await Promise.all([
|
// Create new order for testing
|
||||||
// Create new order for testing
|
await merchant.openNewOrder();
|
||||||
await merchant.openNewOrder(),
|
await page.waitForSelector('#order_status');
|
||||||
await page.waitForSelector('#order_status'),
|
await page.click('#customer_user');
|
||||||
await page.click('#customer_user'),
|
await page.click('span.select2-search > input.select2-search__field');
|
||||||
await page.click('span.select2-search > input.select2-search__field'),
|
await page.type('span.select2-search > input.select2-search__field', 'Customer');
|
||||||
await page.type('span.select2-search > input.select2-search__field', 'Customer'),
|
await page.waitFor(2000); // to avoid flakyness
|
||||||
await page.waitFor(2000), // to avoid flakyness
|
await page.keyboard.press('Enter');
|
||||||
await page.keyboard.press('Enter'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
await Promise.all([
|
// Change the shipping data
|
||||||
// Change the shipping data
|
await page.waitFor(1000); // to avoid flakiness
|
||||||
await page.waitFor(1000), // to avoid flakiness
|
await page.click('.billing-same-as-shipping');
|
||||||
await page.waitForSelector('#_shipping_first_name'),
|
await page.keyboard.press('Enter');
|
||||||
await clearAndFillInput('#_shipping_first_name', 'Tim'),
|
await page.waitForSelector('#_shipping_first_name');
|
||||||
await clearAndFillInput('#_shipping_last_name', 'Clark'),
|
await clearAndFillInput('#_shipping_first_name', 'Tim');
|
||||||
await clearAndFillInput('#_shipping_address_1', 'Oxford Ave'),
|
await clearAndFillInput('#_shipping_last_name', 'Clark');
|
||||||
await clearAndFillInput('#_shipping_address_2', 'Linwood Ave'),
|
await clearAndFillInput('#_shipping_address_1', 'Oxford Ave');
|
||||||
await clearAndFillInput('#_shipping_city', 'Buffalo'),
|
await clearAndFillInput('#_shipping_address_2', 'Linwood Ave');
|
||||||
await clearAndFillInput('#_shipping_postcode', '14201'),
|
await clearAndFillInput('#_shipping_city', 'Buffalo');
|
||||||
await page.keyboard.press('Tab'),
|
await clearAndFillInput('#_shipping_postcode', '14201');
|
||||||
await page.keyboard.press('Tab'),
|
|
||||||
await page.keyboard.press('Enter'),
|
|
||||||
await page.select('select[name="_shipping_state"]', 'NY'),
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Get the post id
|
// Get the post id
|
||||||
const variablePostId = await page.$('#post_ID');
|
const variablePostId = await page.$('#post_ID');
|
||||||
orderId = (await(await variablePostId.getProperty('value')).jsonValue());
|
orderId = (await(await variablePostId.getProperty('value')).jsonValue());
|
||||||
|
|
||||||
// Save new order
|
// Save new order and add desired product to order
|
||||||
await clickUpdateOrder('Order updated.', true);
|
await clickUpdateOrder('Order updated.', true);
|
||||||
await addProductToOrder(orderId, 'Wanted Product');
|
await addProductToOrder(orderId, 'Wanted Product');
|
||||||
|
|
||||||
|
// Open All Orders view
|
||||||
await merchant.openAllOrdersView();
|
await merchant.openAllOrdersView();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -126,7 +121,7 @@ const runOrderSearchingTest = () => {
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can search for order by shipping state name', async () => {
|
it('can search for order by shipping state name', async () => {
|
||||||
await searchForOrder('NY', orderId, 'John Doe');
|
await searchForOrder('CA', orderId, 'John Doe');
|
||||||
})
|
})
|
||||||
|
|
||||||
it('can search for order by item name', async () => {
|
it('can search for order by item name', async () => {
|
||||||
|
|
|
@ -17,7 +17,7 @@ const {
|
||||||
const config = require( 'config' );
|
const config = require( 'config' );
|
||||||
const simpleProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99';
|
const simpleProductPrice = config.has( 'products.simple.price' ) ? config.get( 'products.simple.price' ) : '9.99';
|
||||||
const simpleProductName = config.get( 'products.simple.name' );
|
const simpleProductName = config.get( 'products.simple.name' );
|
||||||
const california = 'California, United States (US)';
|
const california = 'state:US:CA';
|
||||||
const sanFranciscoZIP = '94107';
|
const sanFranciscoZIP = '94107';
|
||||||
const shippingZoneNameUS = 'US with Flat rate';
|
const shippingZoneNameUS = 'US with Flat rate';
|
||||||
const shippingZoneNameFL = 'CA with Free shipping';
|
const shippingZoneNameFL = 'CA with Free shipping';
|
||||||
|
@ -90,10 +90,6 @@ const runAddNewShippingZoneTest = () => {
|
||||||
await selectOptionInSelect2('New York');
|
await selectOptionInSelect2('New York');
|
||||||
await expect(page).toClick('button[name="calc_shipping"]');
|
await expect(page).toClick('button[name="calc_shipping"]');
|
||||||
|
|
||||||
// Set shipping postcode to 10010
|
|
||||||
await clearAndFillInput('#calc_shipping_postcode', '10010');
|
|
||||||
await expect(page).toClick('button[name="calc_shipping"]');
|
|
||||||
|
|
||||||
// Verify shipping costs
|
// Verify shipping costs
|
||||||
await page.waitForSelector('.order-total');
|
await page.waitForSelector('.order-total');
|
||||||
await expect(page).toMatchElement('.shipping .amount', {text: '$10.00'});
|
await expect(page).toMatchElement('.shipping .amount', {text: '$10.00'});
|
||||||
|
@ -102,6 +98,7 @@ const runAddNewShippingZoneTest = () => {
|
||||||
|
|
||||||
it('allows customer to benefit from a Free shipping if in CA', async () => {
|
it('allows customer to benefit from a Free shipping if in CA', async () => {
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
|
||||||
// Set shipping state to California
|
// Set shipping state to California
|
||||||
await expect(page).toClick('a.shipping-calculator-button');
|
await expect(page).toClick('a.shipping-calculator-button');
|
||||||
await expect(page).toClick('#select2-calc_shipping_state-container');
|
await expect(page).toClick('#select2-calc_shipping_state-container');
|
||||||
|
@ -119,6 +116,7 @@ const runAddNewShippingZoneTest = () => {
|
||||||
|
|
||||||
it('allows customer to benefit from a free Local pickup if in SF', async () => {
|
it('allows customer to benefit from a free Local pickup if in SF', async () => {
|
||||||
await page.reload();
|
await page.reload();
|
||||||
|
|
||||||
// Set shipping postcode to 94107
|
// Set shipping postcode to 94107
|
||||||
await expect(page).toClick('a.shipping-calculator-button');
|
await expect(page).toClick('a.shipping-calculator-button');
|
||||||
await clearAndFillInput('#calc_shipping_postcode', '94107');
|
await clearAndFillInput('#calc_shipping_postcode', '94107');
|
||||||
|
|
|
@ -0,0 +1,62 @@
|
||||||
|
/* eslint-disable jest/no-export, jest/no-disabled-tests, jest/expect-expect */
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
shopper,
|
||||||
|
merchant,
|
||||||
|
createSimpleProduct,
|
||||||
|
uiUnblocked,
|
||||||
|
setCheckbox,
|
||||||
|
settingsPageSaveChanges,
|
||||||
|
} = require( '@woocommerce/e2e-utils' );
|
||||||
|
|
||||||
|
/**
|
||||||
|
* External dependencies
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
it,
|
||||||
|
describe,
|
||||||
|
beforeAll,
|
||||||
|
} = require( '@jest/globals' );
|
||||||
|
|
||||||
|
const config = require( 'config' );
|
||||||
|
const simpleProductName = config.get( 'products.simple.name' );
|
||||||
|
|
||||||
|
const runCheckoutCreateAccountTest = () => {
|
||||||
|
describe('Shopper Checkout Create Account', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await merchant.login();
|
||||||
|
await createSimpleProduct();
|
||||||
|
await merchant.openSettings('account');
|
||||||
|
await setCheckbox('#woocommerce_enable_signup_and_login_from_checkout');
|
||||||
|
await settingsPageSaveChanges();
|
||||||
|
await merchant.logout();
|
||||||
|
await shopper.goToShop();
|
||||||
|
await shopper.addToCartFromShopPage(simpleProductName);
|
||||||
|
await uiUnblocked();
|
||||||
|
await shopper.goToCheckout();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create an account during checkout', async () => {
|
||||||
|
// Fill all the details for a new customer
|
||||||
|
await shopper.fillBillingDetails(config.get('addresses.customer.billing'));
|
||||||
|
await uiUnblocked();
|
||||||
|
|
||||||
|
// Set checkbox for creating account during checkout
|
||||||
|
await setCheckbox('#createaccount');
|
||||||
|
|
||||||
|
// Place an order
|
||||||
|
await shopper.placeOrder();
|
||||||
|
await expect(page).toMatchElement('h1.entry-title', {text: 'Order received'});
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can verify that the customer has been created', async () => {
|
||||||
|
await merchant.login();
|
||||||
|
await merchant.openAllUsersView();
|
||||||
|
await expect(page).toMatchElement('td.email.column-email > a', {text: 'john.doe@example.com'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = runCheckoutCreateAccountTest;
|
|
@ -0,0 +1,41 @@
|
||||||
|
/* eslint-disable jest/no-export, jest/no-disabled-tests */
|
||||||
|
/**
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const {
|
||||||
|
shopper,
|
||||||
|
merchant,
|
||||||
|
setCheckbox,
|
||||||
|
settingsPageSaveChanges,
|
||||||
|
} = require( '@woocommerce/e2e-utils' );
|
||||||
|
|
||||||
|
const runMyAccountCreateAccountTest = () => {
|
||||||
|
describe('Shopper My Account Create Account', () => {
|
||||||
|
beforeAll(async () => {
|
||||||
|
await merchant.login();
|
||||||
|
|
||||||
|
// Set checkbox in the settings to enable registration in my account
|
||||||
|
await merchant.openSettings('account');
|
||||||
|
await setCheckbox('#woocommerce_enable_myaccount_registration');
|
||||||
|
await settingsPageSaveChanges();
|
||||||
|
|
||||||
|
await merchant.logout();
|
||||||
|
});
|
||||||
|
|
||||||
|
it('can create a new account via my account', async () => {
|
||||||
|
await shopper.gotoMyAccount();
|
||||||
|
await page.waitForSelector('.woocommerce-form-register');
|
||||||
|
await expect(page).toFill('input#reg_email', 'john.doe.test@example.com');
|
||||||
|
await expect(page).toClick('button[name="register"]');
|
||||||
|
await page.waitForNavigation({waitUntil: 'networkidle0'});
|
||||||
|
await expect(page).toMatchElement('h1', 'My account');
|
||||||
|
|
||||||
|
// Verify user has been created successfully
|
||||||
|
await merchant.login();
|
||||||
|
await merchant.openAllUsersView();
|
||||||
|
await expect(page).toMatchElement('td.email.column-email > a', {text: 'john.doe.test@example.com'});
|
||||||
|
});
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
module.exports = runMyAccountCreateAccountTest;
|
|
@ -4,9 +4,7 @@
|
||||||
*/
|
*/
|
||||||
const {
|
const {
|
||||||
shopper,
|
shopper,
|
||||||
merchant,
|
|
||||||
createSimpleProductWithCategory,
|
createSimpleProductWithCategory,
|
||||||
uiUnblocked,
|
|
||||||
} = require( '@woocommerce/e2e-utils' );
|
} = require( '@woocommerce/e2e-utils' );
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -2,13 +2,16 @@
|
||||||
|
|
||||||
echo "Initializing WooCommerce E2E"
|
echo "Initializing WooCommerce E2E"
|
||||||
|
|
||||||
wp plugin install woocommerce --activate
|
wp plugin activate woocommerce
|
||||||
wp theme install twentynineteen --activate
|
wp theme install twentynineteen --activate
|
||||||
wp user create customer customer@woocommercecoree2etestsuite.com --user_pass=password --role=customer --path=/var/www/html
|
wp user create customer customer@woocommercecoree2etestsuite.com --user_pass=password --role=customer --path=/var/www/html
|
||||||
|
|
||||||
# we cannot create API keys for the API, so we using basic auth, this plugin allows that.
|
# we cannot create API keys for the API, so we using basic auth, this plugin allows that.
|
||||||
wp plugin install https://github.com/WP-API/Basic-Auth/archive/master.zip --activate
|
wp plugin install https://github.com/WP-API/Basic-Auth/archive/master.zip --activate
|
||||||
|
|
||||||
|
# install the WP Mail Logging plugin to test emails
|
||||||
|
wp plugin install wp-mail-logging --activate
|
||||||
|
|
||||||
echo "Updating to WordPress Nightly Point Release"
|
echo "Updating to WordPress Nightly Point Release"
|
||||||
|
|
||||||
wp plugin install wordpress-beta-tester --activate
|
wp plugin install wordpress-beta-tester --activate
|
||||||
|
|
|
@ -1,5 +1,8 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
|
||||||
|
# 0.2.1
|
||||||
|
|
||||||
## Added
|
## Added
|
||||||
|
|
||||||
- Support for screenshots on test errors
|
- Support for screenshots on test errors
|
||||||
|
|
|
@ -11,7 +11,7 @@ npm install jest --global
|
||||||
|
|
||||||
## Configuration
|
## Configuration
|
||||||
|
|
||||||
The `@woocommerce/e2e-environment` package exports configuration objects that can be consumed in JavaScript config files in your project. Additionally, it includes a hosting container for running tests and includes instructions for creating your Travis CI setup.
|
The `@woocommerce/e2e-environment` package exports configuration objects that can be consumed in JavaScript config files in your project. Additionally, it includes a basic hosting container for running tests and includes instructions for creating your Travis CI setup.
|
||||||
|
|
||||||
### Babel Config
|
### Babel Config
|
||||||
|
|
||||||
|
@ -56,7 +56,7 @@ module.exports = useE2EEsLintConfig( {
|
||||||
|
|
||||||
### Jest Config
|
### Jest Config
|
||||||
|
|
||||||
The E2E environment uses Jest as a test runner. Extending the base config is needed in order for Jest to run your project's test files.
|
The E2E environment uses Jest as a test runner. Extending the base config is necessary in order for Jest to run your project's test files.
|
||||||
|
|
||||||
```js
|
```js
|
||||||
const path = require( 'path' );
|
const path = require( 'path' );
|
||||||
|
@ -69,7 +69,7 @@ const jestConfig = useE2EJestConfig( {
|
||||||
module.exports = jestConfig;
|
module.exports = jestConfig;
|
||||||
```
|
```
|
||||||
|
|
||||||
**NOTE:** Your project's Jest config file is expected to be: `tests/e2e/config/jest.config.js`.
|
**NOTE:** Your project's Jest config file is: `tests/e2e/config/jest.config.js`.
|
||||||
|
|
||||||
#### Test Screenshots
|
#### Test Screenshots
|
||||||
|
|
||||||
|
@ -79,7 +79,7 @@ The test sequencer provides a screenshot function for test failures. To enable s
|
||||||
WC_E2E_SCREENSHOTS=1 npx wc-e2e test:e2e
|
WC_E2E_SCREENSHOTS=1 npx wc-e2e test:e2e
|
||||||
```
|
```
|
||||||
|
|
||||||
Screenshots will be saved to `tests/e2e/screenshots`
|
Screenshots will be saved to `tests/e2e/screenshots`. This folder is cleared at the beginning of each test run.
|
||||||
|
|
||||||
### Jest Puppeteer Config
|
### Jest Puppeteer Config
|
||||||
|
|
||||||
|
@ -125,11 +125,11 @@ module.exports = puppeteerConfig;
|
||||||
|
|
||||||
### Jest Setup
|
### Jest Setup
|
||||||
|
|
||||||
Jest provides setup and teardown functions similar to PHPUnit. The default setup and teardown is in [`tests/e2e/env/src/setup/jest.setup.js`](src/setup/jest.setup.js). Additional setup and teardown functions can be added to [`tests/e2e/config/jest.setup.js`](../config/jest.setup.js)
|
Jest provides [setup and teardown functions](https://jestjs.io/docs/setup-teardown) similar to PHPUnit. The default setup and teardown is in [`tests/e2e/env/src/setup/jest.setup.js`](src/setup/jest.setup.js). Additional setup and teardown functions can be added to [`tests/e2e/config/jest.setup.js`](../config/jest.setup.js)
|
||||||
|
|
||||||
### Container Setup
|
### Container Setup
|
||||||
|
|
||||||
Depending on the project and testing scenario, the built in testing environment container might not be the best solution for testing. This could be local testing where there is already a testing container, a repository that isn't a plugin or theme and there are multiple folders mapped into the container, or similar. The `e2e-environment` container supports using either the built in container or an external container. See the the appropriate readme for details:
|
Depending on the project and testing scenario, the built in testing environment container might not be the best solution for testing. This could be local testing where there is already a testing container, a repository that isn't a plugin or theme and there are multiple folders mapped into the container, or similar. The `e2e-environment` test runner supports using either the built in container or an external container. See the appropriate readme for details:
|
||||||
|
|
||||||
- [Built In Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/builtin.md)
|
- [Built In Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/builtin.md)
|
||||||
- [External Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/external.md)
|
- [External Container](https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e/env/external.md)
|
||||||
|
|
|
@ -34,6 +34,35 @@ echo "Initializing WooCommerce E2E"
|
||||||
wp plugin activate woocommerce
|
wp plugin activate woocommerce
|
||||||
wp theme install twentynineteen --activate
|
wp theme install twentynineteen --activate
|
||||||
```
|
```
|
||||||
|
### Adhoc Initialization
|
||||||
|
|
||||||
|
The container build script supports an initialization script parameter
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
npx wc-e2e docker:up tests/e2e/docker/init-wp-beta.sh
|
||||||
|
```
|
||||||
|
|
||||||
|
This script updates WordPress to the latest nightly point release
|
||||||
|
|
||||||
|
```shell script
|
||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
echo "Initializing WooCommerce E2E"
|
||||||
|
|
||||||
|
wp plugin install woocommerce --activate
|
||||||
|
wp theme install twentynineteen --activate
|
||||||
|
wp user create customer customer@woocommercecoree2etestsuite.com --user_pass=password --role=customer --path=/var/www/html
|
||||||
|
|
||||||
|
# we cannot create API keys for the API, so we using basic auth, this plugin allows that.
|
||||||
|
wp plugin install https://github.com/WP-API/Basic-Auth/archive/master.zip --activate
|
||||||
|
|
||||||
|
echo "Updating to WordPress Nightly Point Release"
|
||||||
|
|
||||||
|
wp plugin install wordpress-beta-tester --activate
|
||||||
|
wp core check-update
|
||||||
|
|
||||||
|
```
|
||||||
|
|
||||||
|
|
||||||
### Container Configuration
|
### Container Configuration
|
||||||
|
|
||||||
|
|
|
@ -66,7 +66,7 @@ version: ~> 1.0
|
||||||
script:
|
script:
|
||||||
- npm install jest --global
|
- npm install jest --global
|
||||||
# add your initialization script here
|
# add your initialization script here
|
||||||
- npm explore @woocommerce/e2e-environment -- npm run test:e2e
|
- npx wc-e2e test:e2e
|
||||||
|
|
||||||
....
|
....
|
||||||
|
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@woocommerce/e2e-environment",
|
"name": "@woocommerce/e2e-environment",
|
||||||
"version": "0.2.0",
|
"version": "0.2.1",
|
||||||
"description": "WooCommerce End to End Testing Environment Configuration.",
|
"description": "WooCommerce End to End Testing Environment Configuration.",
|
||||||
"author": "Automattic",
|
"author": "Automattic",
|
||||||
"license": "GPL-3.0-or-later",
|
"license": "GPL-3.0-or-later",
|
||||||
|
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const { runCheckoutCreateAccountTest } = require( '@woocommerce/e2e-core-tests' );
|
||||||
|
|
||||||
|
runCheckoutCreateAccountTest();
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const { runMyAccountCreateAccountTest } = require( '@woocommerce/e2e-core-tests' );
|
||||||
|
|
||||||
|
runMyAccountCreateAccountTest();
|
|
@ -0,0 +1,6 @@
|
||||||
|
/*
|
||||||
|
* Internal dependencies
|
||||||
|
*/
|
||||||
|
const { runAnalyticsPageLoadsTest } = require( '@woocommerce/e2e-core-tests' );
|
||||||
|
|
||||||
|
runAnalyticsPageLoadsTest();
|
|
@ -1,5 +1,30 @@
|
||||||
# Unreleased
|
# Unreleased
|
||||||
|
|
||||||
|
# 0.1.4
|
||||||
|
|
||||||
|
## Fixed
|
||||||
|
|
||||||
|
- build issue with faker import
|
||||||
|
|
||||||
|
# 0.1.3
|
||||||
|
|
||||||
|
## Added
|
||||||
|
|
||||||
|
- `selectOptionInSelect2( selector, value )` util helper method that search and select in any select2 type field
|
||||||
|
- `searchForOrder( value, orderId, customerName )` util helper method that search order with different terms
|
||||||
|
- `addShippingZoneAndMethod( zoneName, zoneLocation, zipCode, zoneMethod )` util helper method for adding shipping zones with shipping methods
|
||||||
|
- `createSimpleProductWithCategory` component which creates a simple product with categories, containing three parameters for title, price and category name.
|
||||||
|
- `applyCoupon( couponName )` util helper method which applies previously created coupon to cart or checkout
|
||||||
|
- `removeCoupon()` util helper method that removes a single coupon within cart or checkout
|
||||||
|
- `selectOrderAction( action )` util helper method to select and initiate an order action in the Order Action postbox
|
||||||
|
- `merchant.openEmailLog()` go to the WP Mail Log page
|
||||||
|
- `deleteAllEmailLogs` delete all email logs in the WP Mail Log plugin
|
||||||
|
- `clickUpdateOrder( noticeText, waitForSave )` util helper that clicks the `Update` button on an order
|
||||||
|
|
||||||
|
## Changed
|
||||||
|
|
||||||
|
- Added coupon type parameter to `createCoupon( couponAmount, couponType )`. Default coupon type is fixed cart.
|
||||||
|
|
||||||
# 0.1.2
|
# 0.1.2
|
||||||
|
|
||||||
## Fixed
|
## Fixed
|
||||||
|
@ -16,16 +41,6 @@
|
||||||
- `addProductToOrder( orderId, productName )` component which adds the provided productName to the passed in orderId
|
- `addProductToOrder( orderId, productName )` component which adds the provided productName to the passed in orderId
|
||||||
- `createCoupon( couponAmount )` component which accepts a coupon amount string (it defaults to 5) and creates a basic coupon. Returns the generated coupon code.
|
- `createCoupon( couponAmount )` component which accepts a coupon amount string (it defaults to 5) and creates a basic coupon. Returns the generated coupon code.
|
||||||
- `evalAndClick( selector )` use Puppeteer page.$eval to select and click and element.
|
- `evalAndClick( selector )` use Puppeteer page.$eval to select and click and element.
|
||||||
- `selectOptionInSelect2( selector, value )` util helper method that search and select in any select2 type field
|
|
||||||
- `searchForOrder( value, orderId, customerName )` util helper method that search order with different terms
|
|
||||||
- `addShippingZoneAndMethod( zoneName, zoneLocation, zipCode, zoneMethod )` util helper method for adding shipping zones with shipping methods
|
|
||||||
- `createSimpleProductWithCategory` component which creates a simple product with categories, containing three parameters for title, price and category name.
|
|
||||||
- `applyCoupon( couponName )` util helper method which applies previously created coupon to cart or checkout
|
|
||||||
- `removeCoupon()` util helper method that removes a single coupon within cart or checkout
|
|
||||||
- `selectOrderAction( action )` util helper method to select and initiate an order action in the Order Action postbox
|
|
||||||
- `merchant.openEmailLog()` go to the WP Mail Log page
|
|
||||||
- `deleteAllEmailLogs` delete all email logs in the WP Mail Log plugin
|
|
||||||
- `clickUpdateOrder( noticeText, waitForSave )` util helper that clicks the `Update` button on an order
|
|
||||||
|
|
||||||
## Changes
|
## Changes
|
||||||
|
|
||||||
|
|
|
@ -21,9 +21,7 @@ import {
|
||||||
|
|
||||||
describe( 'Cart page', () => {
|
describe( 'Cart page', () => {
|
||||||
beforeAll( async () => {
|
beforeAll( async () => {
|
||||||
await merchant.login();
|
|
||||||
await createSimpleProduct();
|
await createSimpleProduct();
|
||||||
await merchant.logout();
|
|
||||||
} );
|
} );
|
||||||
|
|
||||||
it( 'should display no item in the cart', async () => {
|
it( 'should display no item in the cart', async () => {
|
||||||
|
@ -55,6 +53,8 @@ describe( 'Cart page', () => {
|
||||||
| `runSetupWizard` | | Open the onboarding profiler |
|
| `runSetupWizard` | | Open the onboarding profiler |
|
||||||
| `updateOrderStatus` | `orderId, status` | Update the status of an order |
|
| `updateOrderStatus` | `orderId, status` | Update the status of an order |
|
||||||
| `openEmailLog` | | Open the WP Mail Log page |
|
| `openEmailLog` | | Open the WP Mail Log page |
|
||||||
|
| `openAnalyticsPage` | | Open any Analytics page |
|
||||||
|
| `openAllUsersView` | | Open the All Users page |
|
||||||
|
|
||||||
### Shopper `shopper`
|
### Shopper `shopper`
|
||||||
|
|
||||||
|
@ -85,20 +85,33 @@ describe( 'Cart page', () => {
|
||||||
| Function | Parameters | Description |
|
| Function | Parameters | Description |
|
||||||
|----------|------------|-------------|
|
|----------|------------|-------------|
|
||||||
| `addProductToOrder` | `orderId, productName` | adds a product to an order using the product search |
|
| `addProductToOrder` | `orderId, productName` | adds a product to an order using the product search |
|
||||||
|
| `applyCoupon` | `couponName` | helper method which applies a coupon in cart or checkout |
|
||||||
| `clearAndFillInput` | `selector, value` | Replace the contents of an input with the passed value |
|
| `clearAndFillInput` | `selector, value` | Replace the contents of an input with the passed value |
|
||||||
| `clickFilter` | `selector` | helper method that clicks on a list page filter |
|
| `clickFilter` | `selector` | helper method that clicks on a list page filter |
|
||||||
| `clickTab` | `tabName` | Click on a WooCommerce -> Settings tab |
|
| `clickTab` | `tabName` | Click on a WooCommerce -> Settings tab |
|
||||||
| `createCoupon` | `couponAmount` | creates a basic coupon. Default amount is 5. Returns the generated coupon code. |
|
| `clickUpdateOrder` | `noticeText`, `waitForSave` | Helper method to click the Update button on the order details page |
|
||||||
|
| `completeOnboardingWizard` | | completes the onboarding wizard with some default settings |
|
||||||
|
| `createCoupon` | `couponAmount`, `couponType` | creates a basic coupon. Default amount is 5. Default coupon type is fixed discount. Returns the generated coupon code. |
|
||||||
|
| `createGroupedProduct` | | creates a grouped product for the grouped product tests. Returns the product id. |
|
||||||
| `createSimpleOrder` | `status` | creates a basic order with the provided status string |
|
| `createSimpleOrder` | `status` | creates a basic order with the provided status string |
|
||||||
|
| `createSimpleProduct` | | creates the simple product configured in default.json. Returns the product id. |
|
||||||
|
| `createSimpleProductWithCategory` | `name`, `price`,`categoryName` | creates a simple product used passed values. Returns the product id. |
|
||||||
|
| `createVariableProduct` | | creates a variable product for the variable product tests. Returns the product id. |
|
||||||
|
| `deleteAllEmailLogs` | | deletes the emails generated by WP Mail Logging plugin |
|
||||||
|
| `evalAndClick` | `selector` | helper method that clicks an element inserted in the DOM by a script |
|
||||||
| `moveAllItemsToTrash` | | helper method that checks every item in a list page and moves them to the trash |
|
| `moveAllItemsToTrash` | | helper method that checks every item in a list page and moves them to the trash |
|
||||||
| `settingsPageSaveChanges` | | Save the current WooCommerce settings page |
|
|
||||||
| `permalinkSettingsPageSaveChanges` | | Save the current Permalink settings |
|
| `permalinkSettingsPageSaveChanges` | | Save the current Permalink settings |
|
||||||
|
| `removeCoupon` | | helper method that removes a single coupon within cart or checkout |
|
||||||
|
| `selectOptionInSelect2` | `selector, value` | helper method that searchs for select2 type fields and select plus insert value inside |
|
||||||
|
| `selectOrderAction` | `action` | Helper method to select an order action in the `Order Actions` postbox |
|
||||||
| `setCheckbox` | `selector` | Check a checkbox |
|
| `setCheckbox` | `selector` | Check a checkbox |
|
||||||
| `unsetCheckbox` | `selector` | Uncheck a checkbox |
|
| `settingsPageSaveChanges` | | Save the current WooCommerce settings page |
|
||||||
| `uiUnblocked` | | Wait until the page is unblocked |
|
| `uiUnblocked` | | Wait until the page is unblocked |
|
||||||
| `verifyPublishAndTrash` | `button, publishNotice, publishVerification, trashVerification` | Verify that an item can be published and trashed |
|
| `unsetCheckbox` | `selector` | Uncheck a checkbox |
|
||||||
|
| `verifyAndPublish` | `noticeText` | Verify that an item can be published |
|
||||||
| `verifyCheckboxIsSet` | `selector` | Verify that a checkbox is checked |
|
| `verifyCheckboxIsSet` | `selector` | Verify that a checkbox is checked |
|
||||||
| `verifyCheckboxIsUnset` | `selector` | Verify that a checkbox is unchecked |
|
| `verifyCheckboxIsUnset` | `selector` | Verify that a checkbox is unchecked |
|
||||||
|
| `verifyPublishAndTrash` | `button, publishNotice, publishVerification, trashVerification` | Verify that an item can be published and trashed |
|
||||||
| `verifyValueOfInputField` | `selector, value` | Verify an input contains the passed value |
|
| `verifyValueOfInputField` | `selector, value` | Verify an input contains the passed value |
|
||||||
| `clickFilter` | `selector` | Click on a list page filter |
|
| `clickFilter` | `selector` | Click on a list page filter |
|
||||||
| `moveAllItemsToTrash` | | Moves all items in a list view to the Trash |
|
| `moveAllItemsToTrash` | | Moves all items in a list view to the Trash |
|
||||||
|
@ -113,4 +126,4 @@ describe( 'Cart page', () => {
|
||||||
|
|
||||||
### Test Utilities
|
### Test Utilities
|
||||||
|
|
||||||
As of version 0.1.2, all test utilities from [`@wordpress/e2e-test-utils`](https://www.npmjs.com/package/@wordpress/e2e-test-utils) are available through this package.
|
As of version 0.1.3, all test utilities from [`@wordpress/e2e-test-utils`](https://www.npmjs.com/package/@wordpress/e2e-test-utils) are available through this package.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
{
|
{
|
||||||
"name": "@woocommerce/e2e-utils",
|
"name": "@woocommerce/e2e-utils",
|
||||||
"version": "0.1.2",
|
"version": "0.1.4",
|
||||||
"description": "End-To-End (E2E) test utils for WooCommerce",
|
"description": "End-To-End (E2E) test utils for WooCommerce",
|
||||||
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e-utils/README.md",
|
"homepage": "https://github.com/woocommerce/woocommerce/tree/trunk/tests/e2e-utils/README.md",
|
||||||
"repository": {
|
"repository": {
|
||||||
|
@ -18,7 +18,7 @@
|
||||||
"fishery": "^1.2.0"
|
"fishery": "^1.2.0"
|
||||||
},
|
},
|
||||||
"peerDependencies": {
|
"peerDependencies": {
|
||||||
"@woocommerce/api": "^0.1.0"
|
"@woocommerce/api": "^0.1.2"
|
||||||
},
|
},
|
||||||
"publishConfig": {
|
"publishConfig": {
|
||||||
"access": "public"
|
"access": "public"
|
||||||
|
|
|
@ -6,7 +6,14 @@
|
||||||
* Internal dependencies
|
* Internal dependencies
|
||||||
*/
|
*/
|
||||||
import { merchant } from './flows';
|
import { merchant } from './flows';
|
||||||
import { clickTab, uiUnblocked, verifyCheckboxIsUnset, evalAndClick, selectOptionInSelect2, setCheckbox } from './page-utils';
|
import {
|
||||||
|
clickTab,
|
||||||
|
uiUnblocked,
|
||||||
|
verifyCheckboxIsUnset,
|
||||||
|
selectOptionInSelect2,
|
||||||
|
setCheckbox,
|
||||||
|
unsetCheckbox
|
||||||
|
} from './page-utils';
|
||||||
import factories from './factories';
|
import factories from './factories';
|
||||||
|
|
||||||
const config = require( 'config' );
|
const config = require( 'config' );
|
||||||
|
@ -143,7 +150,8 @@ const completeOnboardingWizard = async () => {
|
||||||
await waitAndClickPrimary( false );
|
await waitAndClickPrimary( false );
|
||||||
|
|
||||||
// Skip installing extensions
|
// Skip installing extensions
|
||||||
await evalAndClick( '.components-checkbox-control__input' );
|
await unsetCheckbox( '.components-checkbox-control__input' );
|
||||||
|
await verifyCheckboxIsUnset( '.components-checkbox-control__input' );
|
||||||
await waitAndClickPrimary();
|
await waitAndClickPrimary();
|
||||||
|
|
||||||
// Theme section
|
// Theme section
|
||||||
|
@ -464,11 +472,11 @@ const createCoupon = async ( couponAmount = '5', discountType = 'Fixed cart disc
|
||||||
* Adds a shipping zone along with a shipping method.
|
* Adds a shipping zone along with a shipping method.
|
||||||
*
|
*
|
||||||
* @param zoneName Shipping zone name.
|
* @param zoneName Shipping zone name.
|
||||||
* @param zoneLocation Shiping zone location. Defaults to United States (US).
|
* @param zoneLocation Shiping zone location. Defaults to country:US. For states use: state:US:CA
|
||||||
* @param zipCode Shipping zone zip code. Defaults to empty one space.
|
* @param zipCode Shipping zone zip code. Defaults to empty one space.
|
||||||
* @param zoneMethod Shipping method type. Defaults to flat_rate (use also: free_shipping or local_pickup)
|
* @param zoneMethod Shipping method type. Defaults to flat_rate (use also: free_shipping or local_pickup)
|
||||||
*/
|
*/
|
||||||
const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States (US)', zipCode = ' ', zoneMethod = 'flat_rate' ) => {
|
const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'country:US', zipCode = ' ', zoneMethod = 'flat_rate' ) => {
|
||||||
await merchant.openNewShipping();
|
await merchant.openNewShipping();
|
||||||
|
|
||||||
// Fill shipping zone name
|
// Fill shipping zone name
|
||||||
|
@ -476,12 +484,7 @@ const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States
|
||||||
await expect(page).toFill('input#zone_name', zoneName);
|
await expect(page).toFill('input#zone_name', zoneName);
|
||||||
|
|
||||||
// Select shipping zone location
|
// Select shipping zone location
|
||||||
// (.toSelect is not best option here because a lot of   are present in country/state names)
|
await expect(page).toSelect('select[name="zone_locations"]', zoneLocation);
|
||||||
await expect(page).toFill('#zone_locations', zoneLocation);
|
|
||||||
await uiUnblocked();
|
|
||||||
await page.keyboard.press('Tab');
|
|
||||||
await uiUnblocked();
|
|
||||||
await page.keyboard.press('Enter');
|
|
||||||
|
|
||||||
// Fill shipping zone postcode if needed otherwise just put empty space
|
// Fill shipping zone postcode if needed otherwise just put empty space
|
||||||
await page.waitForSelector('a.wc-shipping-zone-postcodes-toggle');
|
await page.waitForSelector('a.wc-shipping-zone-postcodes-toggle');
|
||||||
|
@ -491,14 +494,12 @@ const addShippingZoneAndMethod = async ( zoneName, zoneLocation = 'United States
|
||||||
await expect(page).toClick('button#submit');
|
await expect(page).toClick('button#submit');
|
||||||
|
|
||||||
// Add shipping zone method
|
// Add shipping zone method
|
||||||
await uiUnblocked();
|
await page.waitFor(1000);
|
||||||
await expect(page).toClick('button.wc-shipping-zone-add-method', {text:'Add shipping method'});
|
await expect(page).toClick('button.wc-shipping-zone-add-method', {text:'Add shipping method'});
|
||||||
await page.waitForSelector('.wc-shipping-zone-method-selector');
|
await page.waitForSelector('.wc-shipping-zone-method-selector');
|
||||||
await expect(page).toSelect('select[name="add_method_id"]', zoneMethod);
|
await expect(page).toSelect('select[name="add_method_id"]', zoneMethod);
|
||||||
await uiUnblocked();
|
|
||||||
await expect(page).toClick('button#btn-ok');
|
await expect(page).toClick('button#btn-ok');
|
||||||
await page.waitForSelector('#zone_locations');
|
await page.waitForSelector('#zone_locations');
|
||||||
await uiUnblocked();
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { SimpleProduct } from '@woocommerce/api';
|
import { SimpleProduct } from '@woocommerce/api';
|
||||||
import faker from 'faker/locale/en';
|
const faker = require( 'faker/locale/en' );
|
||||||
import { Factory } from 'fishery';
|
import { Factory } from 'fishery';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -17,6 +17,8 @@ export const WP_ADMIN_NEW_PRODUCT = baseUrl + 'wp-admin/post-new.php?post_type=p
|
||||||
export const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
|
export const WP_ADMIN_WC_SETTINGS = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=';
|
||||||
export const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php';
|
export const WP_ADMIN_PERMALINK_SETTINGS = baseUrl + 'wp-admin/options-permalink.php';
|
||||||
export const WP_ADMIN_NEW_SHIPPING_ZONE = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=shipping&zone_id=new';
|
export const WP_ADMIN_NEW_SHIPPING_ZONE = baseUrl + 'wp-admin/admin.php?page=wc-settings&tab=shipping&zone_id=new';
|
||||||
|
export const WP_ADMIN_ANALYTICS_PAGES = baseUrl + 'wp-admin/admin.php?page=wc-admin&path=%2Fanalytics%2F';
|
||||||
|
export const WP_ADMIN_ALL_USERS_VIEW = baseUrl + 'wp-admin/users.php';
|
||||||
|
|
||||||
export const SHOP_PAGE = baseUrl + 'shop';
|
export const SHOP_PAGE = baseUrl + 'shop';
|
||||||
export const SHOP_PRODUCT_PAGE = baseUrl + '?p=';
|
export const SHOP_PRODUCT_PAGE = baseUrl + '?p=';
|
||||||
|
|
|
@ -19,7 +19,9 @@ const {
|
||||||
WP_ADMIN_PLUGINS,
|
WP_ADMIN_PLUGINS,
|
||||||
WP_ADMIN_SETUP_WIZARD,
|
WP_ADMIN_SETUP_WIZARD,
|
||||||
WP_ADMIN_WC_SETTINGS,
|
WP_ADMIN_WC_SETTINGS,
|
||||||
WP_ADMIN_NEW_SHIPPING_ZONE
|
WP_ADMIN_NEW_SHIPPING_ZONE,
|
||||||
|
WP_ADMIN_ANALYTICS_PAGES,
|
||||||
|
WP_ADMIN_ALL_USERS_VIEW,
|
||||||
} = require( './constants' );
|
} = require( './constants' );
|
||||||
|
|
||||||
const baseUrl = config.get( 'url' );
|
const baseUrl = config.get( 'url' );
|
||||||
|
@ -182,6 +184,18 @@ const merchant = {
|
||||||
waitUntil: 'networkidle0',
|
waitUntil: 'networkidle0',
|
||||||
} );
|
} );
|
||||||
},
|
},
|
||||||
|
|
||||||
|
openAnalyticsPage: async ( pageName ) => {
|
||||||
|
await page.goto( WP_ADMIN_ANALYTICS_PAGES + pageName, {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
} );
|
||||||
|
},
|
||||||
|
|
||||||
|
openAllUsersView: async () => {
|
||||||
|
await page.goto( WP_ADMIN_ALL_USERS_VIEW, {
|
||||||
|
waitUntil: 'networkidle0',
|
||||||
|
} );
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
module.exports = merchant;
|
module.exports = merchant;
|
||||||
|
|
|
@ -4,11 +4,18 @@
|
||||||
*
|
*
|
||||||
* Provides REST API specific methods and setup/teardown.
|
* Provides REST API specific methods and setup/teardown.
|
||||||
*
|
*
|
||||||
|
* @package WooCommerce\Tests
|
||||||
* @since 3.0
|
* @since 3.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Base class for REST related unit test classes.
|
||||||
|
*/
|
||||||
class WC_REST_Unit_Test_Case extends WC_Unit_Test_Case {
|
class WC_REST_Unit_Test_Case extends WC_Unit_Test_Case {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @var WP_REST_Server
|
||||||
|
*/
|
||||||
protected $server;
|
protected $server;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -36,4 +43,64 @@ class WC_REST_Unit_Test_Case extends WC_Unit_Test_Case {
|
||||||
unset( $this->server );
|
unset( $this->server );
|
||||||
$wp_rest_server = null;
|
$wp_rest_server = null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a REST request.
|
||||||
|
*
|
||||||
|
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||||
|
* @param string $verb HTTP verb for the request, default is GET.
|
||||||
|
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||||
|
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||||
|
* @return array Result from the request.
|
||||||
|
*/
|
||||||
|
public function do_rest_request( $url, $verb = 'GET', $body_params = null, $query_params = null ) {
|
||||||
|
if ( '/' !== $url[0] ) {
|
||||||
|
$url = '/wc/v3/' . $url;
|
||||||
|
}
|
||||||
|
|
||||||
|
$request = new WP_REST_Request( $verb, $url );
|
||||||
|
if ( ! is_null( $query_params ) ) {
|
||||||
|
$request->set_query_params( $query_params );
|
||||||
|
}
|
||||||
|
if ( ! is_null( $body_params ) ) {
|
||||||
|
$request->set_body_params( $body_params );
|
||||||
|
}
|
||||||
|
|
||||||
|
return $this->server->dispatch( $request );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a GET REST request.
|
||||||
|
*
|
||||||
|
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||||
|
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||||
|
* @return WP_REST_Response The response for the request.
|
||||||
|
*/
|
||||||
|
public function do_rest_get_request( $url, $query_params = null ) {
|
||||||
|
return $this->do_rest_request( $url, 'GET', null, $query_params );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a POST REST request.
|
||||||
|
*
|
||||||
|
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||||
|
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||||
|
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||||
|
* @return array Result from the request.
|
||||||
|
*/
|
||||||
|
public function do_rest_post_request( $url, $body_params = null, $query_params = null ) {
|
||||||
|
return $this->do_rest_request( $url, 'POST', $body_params, $query_params );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Perform a PUT REST request.
|
||||||
|
*
|
||||||
|
* @param string $url The endpopint url, if it doesn't start with '/' it'll be prepended with '/wc/v3/'.
|
||||||
|
* @param array|null $body_params Body parameters for the request, null if none are required.
|
||||||
|
* @param array|null $query_params Query string parameters for the request, null if none are required.
|
||||||
|
* @return array Result from the request.
|
||||||
|
*/
|
||||||
|
public function do_rest_put_request( $url, $body_params = null, $query_params = null ) {
|
||||||
|
return $this->do_rest_request( $url, 'PUT', $body_params, $query_params );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,6 +6,9 @@
|
||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper;
|
||||||
|
use Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Class WC_Tests_API_Orders
|
* Class WC_Tests_API_Orders
|
||||||
*/
|
*/
|
||||||
|
@ -51,7 +54,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
|
|
||||||
// Create 10 orders.
|
// Create 10 orders.
|
||||||
for ( $i = 0; $i < 10; $i++ ) {
|
for ( $i = 0; $i < 10; $i++ ) {
|
||||||
$this->orders[] = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
$this->orders[] = OrderHelper::create_order( $this->user );
|
||||||
}
|
}
|
||||||
|
|
||||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
||||||
|
@ -67,8 +70,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
public function test_get_items_ordered_by_modified() {
|
public function test_get_items_ordered_by_modified() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
$order1 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
$order1 = OrderHelper::create_order( $this->user );
|
||||||
$order2 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( $this->user );
|
$order2 = OrderHelper::create_order( $this->user );
|
||||||
|
|
||||||
$order1->set_status( 'completed' );
|
$order1->set_status( 'completed' );
|
||||||
$order1->save();
|
$order1->save();
|
||||||
|
@ -80,7 +83,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
$request->set_query_params(
|
$request->set_query_params(
|
||||||
array(
|
array(
|
||||||
'orderby' => 'modified',
|
'orderby' => 'modified',
|
||||||
'order' => 'asc',
|
'order' => 'asc',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
|
@ -90,7 +93,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
$request->set_query_params(
|
$request->set_query_params(
|
||||||
array(
|
array(
|
||||||
'orderby' => 'modified',
|
'orderby' => 'modified',
|
||||||
'order' => 'desc',
|
'order' => 'desc',
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
|
@ -105,7 +108,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_get_items_without_permission() {
|
public function test_get_items_without_permission() {
|
||||||
wp_set_current_user( 0 );
|
wp_set_current_user( 0 );
|
||||||
$this->orders[] = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$this->orders[] = OrderHelper::create_order();
|
||||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders' ) );
|
||||||
$this->assertEquals( 401, $response->get_status() );
|
$this->assertEquals( 401, $response->get_status() );
|
||||||
}
|
}
|
||||||
|
@ -116,7 +119,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_get_item() {
|
public function test_get_item() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$order->add_meta_data( 'key', 'value' );
|
$order->add_meta_data( 'key', 'value' );
|
||||||
$order->add_meta_data( 'key2', 'value2' );
|
$order->add_meta_data( 'key2', 'value2' );
|
||||||
$order->save();
|
$order->save();
|
||||||
|
@ -140,7 +143,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_get_item_without_permission() {
|
public function test_get_item_without_permission() {
|
||||||
wp_set_current_user( 0 );
|
wp_set_current_user( 0 );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$this->orders[] = $order;
|
$this->orders[] = $order;
|
||||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||||
$this->assertEquals( 401, $response->get_status() );
|
$this->assertEquals( 401, $response->get_status() );
|
||||||
|
@ -152,18 +155,18 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
public function test_get_item_with_line_items_meta_data() {
|
public function test_get_item_with_line_items_meta_data() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
$attribute_name = 'Site Level Type';
|
$attribute_name = 'Site Level Type';
|
||||||
$site_level_attribute_id = wc_create_attribute( array( 'name' => $attribute_name ) );
|
$site_level_attribute_id = wc_create_attribute( array( 'name' => $attribute_name ) );
|
||||||
$site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id );
|
$site_level_attribute_slug = wc_attribute_taxonomy_name_by_id( $site_level_attribute_id );
|
||||||
|
|
||||||
// Register the attribute so that wp_insert_term will be successful.
|
// Register the attribute so that wp_insert_term will be successful.
|
||||||
register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() );
|
register_taxonomy( $site_level_attribute_slug, array( 'product' ), array() );
|
||||||
|
|
||||||
$term_name = 'Site Level Value - Wood';
|
$term_name = 'Site Level Value - Wood';
|
||||||
$site_level_term_insertion_result = wp_insert_term( $term_name, $site_level_attribute_slug );
|
$site_level_term_insertion_result = wp_insert_term( $term_name, $site_level_attribute_slug );
|
||||||
$site_level_term = get_term( $site_level_term_insertion_result['term_id'] );
|
$site_level_term = get_term( $site_level_term_insertion_result['term_id'] );
|
||||||
|
|
||||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||||
$variation = wc_get_product( $product->get_children()[0] );
|
$variation = wc_get_product( $product->get_children()[0] );
|
||||||
|
|
||||||
$line_item = new WC_Order_Item_Product();
|
$line_item = new WC_Order_Item_Product();
|
||||||
|
@ -172,12 +175,12 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
array( 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) )
|
array( 'variation' => array( "attribute_{$site_level_attribute_slug}" => $site_level_term->slug ) )
|
||||||
);
|
);
|
||||||
|
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$order->add_item( $line_item );
|
$order->add_item( $line_item );
|
||||||
$order->save();
|
$order->save();
|
||||||
|
|
||||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||||
$data = $response->get_data();
|
$data = $response->get_data();
|
||||||
|
|
||||||
$this->assertEquals( 200, $response->get_status() );
|
$this->assertEquals( 200, $response->get_status() );
|
||||||
$this->assertEquals( $order->get_id(), $data['id'] );
|
$this->assertEquals( $order->get_id(), $data['id'] );
|
||||||
|
@ -205,18 +208,18 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
public function test_get_item_with_variation_parent_name() {
|
public function test_get_item_with_variation_parent_name() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_variation_product();
|
||||||
$variation = wc_get_product( $product->get_children()[0] );
|
$variation = wc_get_product( $product->get_children()[0] );
|
||||||
|
|
||||||
$line_item = new WC_Order_Item_Product();
|
$line_item = new WC_Order_Item_Product();
|
||||||
$line_item->set_product( $variation );
|
$line_item->set_product( $variation );
|
||||||
|
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$order->add_item( $line_item );
|
$order->add_item( $line_item );
|
||||||
$order->save();
|
$order->save();
|
||||||
|
|
||||||
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
$response = $this->server->dispatch( new WP_REST_Request( 'GET', '/wc/v3/orders/' . $order->get_id() ) );
|
||||||
$data = $response->get_data();
|
$data = $response->get_data();
|
||||||
|
|
||||||
$this->assertEquals( 200, $response->get_status() );
|
$this->assertEquals( 200, $response->get_status() );
|
||||||
$this->assertEquals( $order->get_id(), $data['id'] );
|
$this->assertEquals( $order->get_id(), $data['id'] );
|
||||||
|
@ -248,7 +251,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_get_item_refund_id() {
|
public function test_get_item_refund_id() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$refund = wc_create_refund(
|
$refund = wc_create_refund(
|
||||||
array(
|
array(
|
||||||
'order_id' => $order->get_id(),
|
'order_id' => $order->get_id(),
|
||||||
|
@ -352,7 +355,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
$this->assertEquals( 1, count( $data['line_items'] ) );
|
$this->assertEquals( 1, count( $data['line_items'] ) );
|
||||||
$this->assertEquals( 1, count( $data['shipping_lines'] ) );
|
$this->assertEquals( 1, count( $data['shipping_lines'] ) );
|
||||||
|
|
||||||
$shipping = current( $order->get_items( 'shipping' ) );
|
$shipping = current( $order->get_items( 'shipping' ) );
|
||||||
$expected_shipping_line = array(
|
$expected_shipping_line = array(
|
||||||
'id' => $shipping->get_id(),
|
'id' => $shipping->get_id(),
|
||||||
'method_title' => $shipping->get_method_title(),
|
'method_title' => $shipping->get_method_title(),
|
||||||
|
@ -542,7 +545,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_update_order() {
|
public function test_update_order() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$request->set_body_params(
|
$request->set_body_params(
|
||||||
array(
|
array(
|
||||||
|
@ -569,7 +572,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_update_order_remove_items() {
|
public function test_update_order_remove_items() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$fee = new WC_Order_Item_Fee();
|
$fee = new WC_Order_Item_Fee();
|
||||||
$fee->set_props(
|
$fee->set_props(
|
||||||
array(
|
array(
|
||||||
|
@ -610,7 +613,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
public function test_update_order_after_delete_product() {
|
public function test_update_order_after_delete_product() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
$product = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\ProductHelper::create_simple_product();
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order( 1, $product );
|
$order = OrderHelper::create_order( 1, $product );
|
||||||
$product->delete( true );
|
$product->delete( true );
|
||||||
|
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
|
@ -621,8 +624,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
array(
|
array(
|
||||||
'line_items' => array(
|
'line_items' => array(
|
||||||
array(
|
array(
|
||||||
'id' => $item->get_id(),
|
'id' => $item->get_id(),
|
||||||
'quantity' => 10,
|
'quantity' => 10,
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
@ -652,56 +655,274 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
$this->assertEquals( $expected, $data['line_items'][0] );
|
$this->assertEquals( $expected, $data['line_items'][0] );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for test_update_order_add_coupons.
|
||||||
|
*
|
||||||
|
* @return array Data for test_update_order_add_coupons.
|
||||||
|
*/
|
||||||
|
public function data_provider_for_test_update_order_add_coupons() {
|
||||||
|
return array(
|
||||||
|
|
||||||
|
// Successful case, no previous coupon, it gets created.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'code' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 200,
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Successful case with previous coupon, it gets replaced.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'code' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 200,
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid coupon name, no previous coupon, it doesn't get added.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'code' => 'not-existing-coupon',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon "not-existing-coupon" does not exist!',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => null,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid coupon name, coupon existed, it's kept.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'code' => 'not-existing-coupon',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon "not-existing-coupon" does not exist!',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: has coupon id, no previous coupon, it doesn't get added.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'id' => '1234',
|
||||||
|
'code' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon item ID is readonly.',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => null,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: has coupon id, previous coupon existed, it's kept.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(
|
||||||
|
'id' => '1234',
|
||||||
|
'code' => 'fake-coupon-2',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon item ID is readonly.',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: no coupon code, no previous coupon, it doesn't get added.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon code is required.',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => null,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: no coupon code, previous coupon existed, it's kept.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array(
|
||||||
|
array(),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Coupon code is required.',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid input ('coupon_lines' is not an array), no previous coupon, it doesn't get added.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => 1234,
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Invalid parameter(s): coupon_lines',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => null,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid input ('coupon_lines' is not an array), previous coupon existed, it's kept.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => 1234,
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Invalid parameter(s): coupon_lines',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid input ('coupon_lines' has non-array elements), no previous coupon, it doesn't get added.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array( 1234 ),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => false,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Invalid parameter(s): coupon_lines',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => null,
|
||||||
|
),
|
||||||
|
|
||||||
|
// Bad request: invalid input ('coupon_lines' has non-array elements), previous coupon existed, it's kept.
|
||||||
|
array(
|
||||||
|
'request_body' => array(
|
||||||
|
'coupon_lines' => array( 1234 ),
|
||||||
|
),
|
||||||
|
'order_has_coupon_before_request' => true,
|
||||||
|
'expected_request_result' => array(
|
||||||
|
'code' => 400,
|
||||||
|
'message' => 'Invalid parameter(s): coupon_lines',
|
||||||
|
),
|
||||||
|
'expected_order_coupon_code_after_request' => 'fake-coupon',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests updating an order and adding a coupon.
|
* Tests updating an order and adding a coupon.
|
||||||
*
|
*
|
||||||
|
* @dataProvider data_provider_for_test_update_order_add_coupons
|
||||||
|
*
|
||||||
|
* @param array $request_body The body for the API request.
|
||||||
|
* @param bool $order_has_coupon_before_request If true, the order will have 'fake-coupon' applied before the API request.
|
||||||
|
* @param array $expected_request_result Expected result from the API request, with 'code' and optionally 'message'.
|
||||||
|
* @param string $expected_order_coupon_code_after_request Code of the expected applied coupon after the API request, null if it shouldn't have a coupon applied.
|
||||||
|
*
|
||||||
* @since 3.5.0
|
* @since 3.5.0
|
||||||
*/
|
*/
|
||||||
public function test_update_order_add_coupons() {
|
public function test_update_order_add_coupons( $request_body, $order_has_coupon_before_request, $expected_request_result, $expected_order_coupon_code_after_request ) {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
// Create order and coupons.
|
||||||
$order_item = current( $order->get_items() );
|
|
||||||
$coupon = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper::create_coupon( 'fake-coupon' );
|
$order = OrderHelper::create_order();
|
||||||
|
$original_order_amount = $order->get_total();
|
||||||
|
|
||||||
|
$coupons = array();
|
||||||
|
|
||||||
|
$coupon = CouponHelper::create_coupon( 'fake-coupon' );
|
||||||
$coupon->set_amount( 5 );
|
$coupon->set_amount( 5 );
|
||||||
$coupon->save();
|
$coupon->save();
|
||||||
|
$coupons['fake-coupon'] = $coupon;
|
||||||
|
|
||||||
|
$coupon = CouponHelper::create_coupon( 'fake-coupon-2' );
|
||||||
|
$coupon->set_amount( 10 );
|
||||||
|
$coupon->save();
|
||||||
|
$coupons['fake-coupon-2'] = $coupon;
|
||||||
|
|
||||||
|
if ( $order_has_coupon_before_request ) {
|
||||||
|
$order->apply_coupon( $coupons['fake-coupon'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
// Perform the request.
|
||||||
|
|
||||||
// Let's try a well-formed request first of all.
|
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$request->set_body_params(
|
$request->set_body_params( $request_body );
|
||||||
array(
|
|
||||||
'coupon_lines' => array(
|
|
||||||
array(
|
|
||||||
'code' => 'fake-coupon',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
$data = $response->get_data();
|
$data = $response->get_data();
|
||||||
|
|
||||||
$this->assertEquals( 200, $response->get_status() );
|
// Check the response and the actual order data after the operation.
|
||||||
$this->assertCount( 1, $data['coupon_lines'] );
|
|
||||||
$this->assertEquals( '45.00', $data['total'] );
|
|
||||||
|
|
||||||
// Let's repeat, but this time we'll specify the item ID for the coupon: this is
|
$this->assertEquals( $expected_request_result['code'], $response->get_status() );
|
||||||
// a readonly property and we expect the request to fail as a result.
|
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
|
||||||
$request->set_body_params(
|
|
||||||
array(
|
|
||||||
'coupon_lines' => array(
|
|
||||||
array(
|
|
||||||
'id' => 123,
|
|
||||||
'code' => 'fake-coupon',
|
|
||||||
),
|
|
||||||
),
|
|
||||||
)
|
|
||||||
);
|
|
||||||
$response = $this->server->dispatch( $request );
|
|
||||||
$data = $response->get_data();
|
|
||||||
|
|
||||||
$this->assertEquals( 400, $response->get_status() );
|
$order = wc_get_order( $order->get_id() );
|
||||||
$this->assertEquals( 'woocommerce_rest_coupon_item_id_readonly', $data['code'] );
|
$order_coupons = array_values( $order->get_coupons() );
|
||||||
|
if ( is_null( $expected_order_coupon_code_after_request ) ) {
|
||||||
|
$expected_coupon = null;
|
||||||
|
$expected_order_amount = $original_order_amount;
|
||||||
|
} else {
|
||||||
|
$expected_coupon = $coupons[ $expected_order_coupon_code_after_request ];
|
||||||
|
$expected_order_amount = number_format( 50 - $expected_coupon->get_amount(), 2 );
|
||||||
|
}
|
||||||
|
|
||||||
|
$is_ok_status = $response->get_status() < 300;
|
||||||
|
if ( $is_ok_status ) {
|
||||||
|
$this->assertEquals( $expected_order_amount, $data['total'] );
|
||||||
|
$this->assertCount( 1, $data['coupon_lines'] );
|
||||||
|
} else {
|
||||||
|
$this->assertEquals( $expected_request_result['message'], $data['message'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
if ( is_null( $expected_order_coupon_code_after_request ) ) {
|
||||||
|
$this->assertEquals( '50.00', $order->get_total() );
|
||||||
|
$this->assertCount( 0, $order_coupons );
|
||||||
|
} else {
|
||||||
|
$this->assertEquals( number_format( $expected_order_amount, 2 ), $order->get_total() );
|
||||||
|
$this->assertCount( 1, $order_coupons );
|
||||||
|
$this->assertEquals( $expected_coupon->get_code(), $order_coupons[0]->get_code() );
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -711,9 +932,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_update_order_remove_coupons() {
|
public function test_update_order_remove_coupons() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$order_item = current( $order->get_items() );
|
$order_item = current( $order->get_items() );
|
||||||
$coupon = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\CouponHelper::create_coupon( 'fake-coupon' );
|
$coupon = CouponHelper::create_coupon( 'fake-coupon' );
|
||||||
$coupon->set_amount( 5 );
|
$coupon->set_amount( 5 );
|
||||||
$coupon->save();
|
$coupon->save();
|
||||||
|
|
||||||
|
@ -723,7 +944,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
// Check that the coupon is applied.
|
// Check that the coupon is applied.
|
||||||
$this->assertEquals( '45.00', $order->get_total() );
|
$this->assertEquals( '45.00', $order->get_total() );
|
||||||
|
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
|
|
||||||
$request->set_body_params(
|
$request->set_body_params(
|
||||||
array(
|
array(
|
||||||
|
@ -752,7 +973,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_invalid_coupon() {
|
public function test_invalid_coupon() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
|
|
||||||
$request->set_body_params(
|
$request->set_body_params(
|
||||||
|
@ -779,7 +1000,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_update_order_without_permission() {
|
public function test_update_order_without_permission() {
|
||||||
wp_set_current_user( 0 );
|
wp_set_current_user( 0 );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'PUT', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$request->set_body_params(
|
$request->set_body_params(
|
||||||
array(
|
array(
|
||||||
|
@ -822,7 +1043,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_delete_order() {
|
public function test_delete_order() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$request->set_param( 'force', true );
|
$request->set_param( 'force', true );
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
|
@ -837,7 +1058,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_delete_order_without_permission() {
|
public function test_delete_order_without_permission() {
|
||||||
wp_set_current_user( 0 );
|
wp_set_current_user( 0 );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'DELETE', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$request->set_param( 'force', true );
|
$request->set_param( 'force', true );
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
|
@ -865,9 +1086,9 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
public function test_orders_batch() {
|
public function test_orders_batch() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
$order1 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order1 = OrderHelper::create_order();
|
||||||
$order2 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order2 = OrderHelper::create_order();
|
||||||
$order3 = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order3 = OrderHelper::create_order();
|
||||||
|
|
||||||
$request = new WP_REST_Request( 'POST', '/wc/v3/orders/batch' );
|
$request = new WP_REST_Request( 'POST', '/wc/v3/orders/batch' );
|
||||||
$request->set_body_params(
|
$request->set_body_params(
|
||||||
|
@ -904,7 +1125,7 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_order_schema() {
|
public function test_order_schema() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
$data = $response->get_data();
|
$data = $response->get_data();
|
||||||
|
@ -919,8 +1140,8 @@ class WC_Tests_API_Orders extends WC_REST_Unit_Test_Case {
|
||||||
*/
|
*/
|
||||||
public function test_order_line_items_schema() {
|
public function test_order_line_items_schema() {
|
||||||
wp_set_current_user( $this->user );
|
wp_set_current_user( $this->user );
|
||||||
$order = \Automattic\WooCommerce\RestApi\UnitTests\Helpers\OrderHelper::create_order();
|
$order = OrderHelper::create_order();
|
||||||
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
$request = new WP_REST_Request( 'OPTIONS', '/wc/v3/orders/' . $order->get_id() );
|
||||||
$response = $this->server->dispatch( $request );
|
$response = $this->server->dispatch( $request );
|
||||||
|
|
||||||
$data = $response->get_data();
|
$data = $response->get_data();
|
||||||
|
|
|
@ -10,6 +10,9 @@
|
||||||
*/
|
*/
|
||||||
class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Setup.
|
||||||
|
*/
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
|
|
||||||
|
@ -17,6 +20,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
$this->create_session();
|
$this->create_session();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that save data should insert new row.
|
||||||
|
*/
|
||||||
public function test_save_data_should_insert_new_row() {
|
public function test_save_data_should_insert_new_row() {
|
||||||
$current_session_data = $this->get_session_from_db( $this->session_key );
|
$current_session_data = $this->get_session_from_db( $this->session_key );
|
||||||
// delete session to make sure a new row is created in the DB.
|
// delete session to make sure a new row is created in the DB.
|
||||||
|
@ -35,6 +41,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
$this->assertEquals( array( 'cart' => 'new cart' ), wp_cache_get( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP ) );
|
$this->assertEquals( array( 'cart' => 'new cart' ), wp_cache_get( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that save data should replace existing row.
|
||||||
|
*/
|
||||||
public function test_save_data_should_replace_existing_row() {
|
public function test_save_data_should_replace_existing_row() {
|
||||||
$current_session_data = $this->get_session_from_db( $this->session_key );
|
$current_session_data = $this->get_session_from_db( $this->session_key );
|
||||||
|
|
||||||
|
@ -49,23 +58,35 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
$this->assertTrue( is_numeric( $updated_session_data->session_expiry ) );
|
$this->assertTrue( is_numeric( $updated_session_data->session_expiry ) );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that get_setting() should use cache.
|
||||||
|
*/
|
||||||
public function test_get_session_should_use_cache() {
|
public function test_get_session_should_use_cache() {
|
||||||
$session = $this->handler->get_session( $this->session_key );
|
$session = $this->handler->get_session( $this->session_key );
|
||||||
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that get_setting() shouldn't use cache.
|
||||||
|
*/
|
||||||
public function test_get_session_should_not_use_cache() {
|
public function test_get_session_should_not_use_cache() {
|
||||||
wp_cache_delete( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP );
|
wp_cache_delete( $this->cache_prefix . $this->session_key, WC_SESSION_CACHE_GROUP );
|
||||||
$session = $this->handler->get_session( $this->session_key );
|
$session = $this->handler->get_session( $this->session_key );
|
||||||
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
$this->assertEquals( array( 'cart' => 'fake cart' ), $session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that get_setting() should return default value.
|
||||||
|
*/
|
||||||
public function test_get_session_should_return_default_value() {
|
public function test_get_session_should_return_default_value() {
|
||||||
$default_session = array( 'session' => 'default' );
|
$default_session = array( 'session' => 'default' );
|
||||||
$session = $this->handler->get_session( 'non-existent key', $default_session );
|
$session = $this->handler->get_session( 'non-existent key', $default_session );
|
||||||
$this->assertEquals( $default_session, $session );
|
$this->assertEquals( $default_session, $session );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test delete_session().
|
||||||
|
*/
|
||||||
public function test_delete_session() {
|
public function test_delete_session() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
|
@ -82,6 +103,9 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
$this->assertNull( $session_id );
|
$this->assertNull( $session_id );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test update_session_timestamp().
|
||||||
|
*/
|
||||||
public function test_update_session_timestamp() {
|
public function test_update_session_timestamp() {
|
||||||
global $wpdb;
|
global $wpdb;
|
||||||
|
|
||||||
|
@ -98,6 +122,14 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
$this->assertEquals( $timestamp, $session_expiry );
|
$this->assertEquals( $timestamp, $session_expiry );
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Test that nonce of user logged out is only changed by WooCommerce.
|
||||||
|
*/
|
||||||
|
public function test_maybe_update_nonce_user_logged_out() {
|
||||||
|
$this->assertEquals( 1, $this->handler->maybe_update_nonce_user_logged_out( 1, 'wp_rest' ) );
|
||||||
|
$this->assertEquals( $this->handler->get_customer_unique_id(), $this->handler->maybe_update_nonce_user_logged_out( 1, 'woocommerce-something' ) );
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Helper function to create a WC session and save it to the DB.
|
* Helper function to create a WC session and save it to the DB.
|
||||||
*/
|
*/
|
||||||
|
@ -113,7 +145,7 @@ class WC_Tests_Session_Handler extends WC_Unit_Test_Case {
|
||||||
/**
|
/**
|
||||||
* Helper function to get session data from DB.
|
* Helper function to get session data from DB.
|
||||||
*
|
*
|
||||||
* @param string $session_key
|
* @param string $session_key Session key.
|
||||||
* @return stdClass
|
* @return stdClass
|
||||||
*/
|
*/
|
||||||
protected function get_session_from_db( $session_key ) {
|
protected function get_session_from_db( $session_key ) {
|
||||||
|
|
|
@ -14,12 +14,22 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
||||||
* Set up
|
* Set up
|
||||||
*/
|
*/
|
||||||
public function setUp() {
|
public function setUp() {
|
||||||
// set default country to US so that 'payments' task does not get added.
|
// Set default country to non-US so that 'payments' task gets added but 'woocommerce-payments' doesn't,
|
||||||
// we want to remove payment tasks as they depend on installation & activation.
|
// by default it won't be considered completed but we can manually change that as needed.
|
||||||
update_option( 'woocommerce_default_country', 'US' );
|
update_option( 'woocommerce_default_country', 'JP' );
|
||||||
|
|
||||||
parent::setUp();
|
parent::setUp();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tear down
|
||||||
|
*/
|
||||||
|
public function tearDown() {
|
||||||
|
remove_all_filters( 'woocommerce_available_payment_gateways' );
|
||||||
|
|
||||||
|
parent::tearDown();
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Includes widget class and return the class.
|
* Includes widget class and return the class.
|
||||||
*
|
*
|
||||||
|
@ -75,13 +85,21 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests the widget output when 0 task has been completed.
|
* Tests the widget output when 1 task has been completed.
|
||||||
*/
|
*/
|
||||||
public function test_initial_widget_output() {
|
public function test_initial_widget_output() {
|
||||||
|
// Force the "payments" task to be considered incomplete.
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_available_payment_gateways',
|
||||||
|
function() {
|
||||||
|
return array();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
$html = $this->get_widget_output();
|
$html = $this->get_widget_output();
|
||||||
|
|
||||||
$required_strings = array(
|
$required_strings = array(
|
||||||
'Step 0 of 5',
|
'Step 0 of 6',
|
||||||
'You're almost there! Once you complete store setup you can start receiving orders.',
|
'You're almost there! Once you complete store setup you can start receiving orders.',
|
||||||
'Start selling',
|
'Start selling',
|
||||||
'admin.php\?page=wc-admin&path=%2Fsetup-wizard',
|
'admin.php\?page=wc-admin&path=%2Fsetup-wizard',
|
||||||
|
@ -96,9 +114,22 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
||||||
* Tests completed task count as it completes one by one
|
* Tests completed task count as it completes one by one
|
||||||
*/
|
*/
|
||||||
public function test_widget_renders_completed_task_count() {
|
public function test_widget_renders_completed_task_count() {
|
||||||
$completed_tasks = array();
|
// Force the "payments" task to be considered completed
|
||||||
|
// by faking a valid payment gateway.
|
||||||
|
add_filter(
|
||||||
|
'woocommerce_available_payment_gateways',
|
||||||
|
function() {
|
||||||
|
return array(
|
||||||
|
new class() extends WC_Payment_Gateway {
|
||||||
|
},
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
$completed_tasks = array( 'payments' );
|
||||||
$tasks = $this->get_widget()->get_tasks();
|
$tasks = $this->get_widget()->get_tasks();
|
||||||
$tasks_count = count( $tasks );
|
$tasks_count = count( $tasks );
|
||||||
|
unset( $tasks['payments'] ); // That one is completed already.
|
||||||
foreach ( $tasks as $key => $task ) {
|
foreach ( $tasks as $key => $task ) {
|
||||||
array_push( $completed_tasks, $key );
|
array_push( $completed_tasks, $key );
|
||||||
update_option( 'woocommerce_task_list_tracked_completed_tasks', $completed_tasks );
|
update_option( 'woocommerce_task_list_tracked_completed_tasks', $completed_tasks );
|
||||||
|
@ -108,7 +139,7 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
||||||
if ( $completed_tasks_count === $tasks_count ) {
|
if ( $completed_tasks_count === $tasks_count ) {
|
||||||
$this->assertEmpty( $this->get_widget_output() );
|
$this->assertEmpty( $this->get_widget_output() );
|
||||||
} else {
|
} else {
|
||||||
$this->assertRegexp( "/Step ${completed_tasks_count} of 5/", $this->get_widget_output() );
|
$this->assertRegexp( "/Step ${completed_tasks_count} of 6/", $this->get_widget_output() );
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -122,13 +153,13 @@ class WC_Admin_Dashboard_Setup_Test extends WC_Unit_Test_Case {
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
'woocommerce_task_list_complete' => 'yes',
|
'woocommerce_task_list_complete' => 'yes',
|
||||||
'woocommerce_task_list_hidden' => 'no',
|
'woocommerce_task_list_hidden' => 'no',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
array(
|
array(
|
||||||
array(
|
array(
|
||||||
'woocommerce_task_list_complete' => 'no',
|
'woocommerce_task_list_complete' => 'no',
|
||||||
'woocommerce_task_list_hidden' => 'yes',
|
'woocommerce_task_list_hidden' => 'yes',
|
||||||
),
|
),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
|
|
|
@ -0,0 +1,288 @@
|
||||||
|
<?php
|
||||||
|
|
||||||
|
/**
|
||||||
|
* class WC_REST_Taxes_Controller_Tests.
|
||||||
|
* Taxes Controller tests for V3 REST API.
|
||||||
|
*/
|
||||||
|
class WC_REST_Taxes_Controller_Tests extends WC_REST_Unit_Test_Case {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Runs before any test.
|
||||||
|
*/
|
||||||
|
public function setUp() {
|
||||||
|
parent::setUp();
|
||||||
|
$this->user = $this->factory->user->create(
|
||||||
|
array(
|
||||||
|
'role' => 'administrator',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Data provider for test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes.
|
||||||
|
*
|
||||||
|
* @return array
|
||||||
|
*/
|
||||||
|
public function data_provider_for_test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes() {
|
||||||
|
return array(
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'city' => 'Osaka;Kyoto;Kobe',
|
||||||
|
'postcode' => '5555;7777;8888',
|
||||||
|
),
|
||||||
|
'create',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'cities' => array(
|
||||||
|
'Osaka',
|
||||||
|
'Kyoto',
|
||||||
|
'Kobe',
|
||||||
|
),
|
||||||
|
'postcodes' => array(
|
||||||
|
'5555',
|
||||||
|
'7777',
|
||||||
|
'8888',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'create',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'city' => 'Osaka;Kyoto;Kobe',
|
||||||
|
'postcode' => '5555;7777;8888',
|
||||||
|
),
|
||||||
|
'update',
|
||||||
|
),
|
||||||
|
array(
|
||||||
|
array(
|
||||||
|
'cities' => array(
|
||||||
|
'Osaka',
|
||||||
|
'Kyoto',
|
||||||
|
'Kobe',
|
||||||
|
),
|
||||||
|
'postcodes' => array(
|
||||||
|
'5555',
|
||||||
|
'7777',
|
||||||
|
'8888',
|
||||||
|
),
|
||||||
|
),
|
||||||
|
'update',
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox It is possible to create or update a tax rate passing either "city"/"postcode" (strings) or "cities"/"postcodes" (arrays) fields.
|
||||||
|
*
|
||||||
|
* @dataProvider data_provider_for_test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes
|
||||||
|
*
|
||||||
|
* @param array $request_body The body for the REST request.
|
||||||
|
* @param string $action The action to perform, 'create' or 'update'.
|
||||||
|
*/
|
||||||
|
public function test_can_create_and_update_tax_rates_with_multiple_cities_and_postcodes( $request_body, $action ) {
|
||||||
|
global $wpdb;
|
||||||
|
|
||||||
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
|
if ( 'create' === $action ) {
|
||||||
|
$tax_rate_id = null;
|
||||||
|
|
||||||
|
$request_body = array_merge(
|
||||||
|
$request_body,
|
||||||
|
array(
|
||||||
|
'country' => 'JP',
|
||||||
|
'rate' => '1',
|
||||||
|
'name' => 'Fake Tax',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$verb = 'POST';
|
||||||
|
$url = 'taxes';
|
||||||
|
$success_status = 201;
|
||||||
|
} else {
|
||||||
|
$tax_rate_id = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_name' => 'Fake Tax',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
WC_Tax::_update_tax_rate_cities( $tax_rate_id, 'Tokyo' );
|
||||||
|
WC_Tax::_update_tax_rate_postcodes( $tax_rate_id, '0000' );
|
||||||
|
|
||||||
|
$verb = 'PUT';
|
||||||
|
$url = 'taxes/' . $tax_rate_id;
|
||||||
|
$success_status = 200;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->do_rest_request( $url, $verb, $request_body );
|
||||||
|
$this->assertEquals( $success_status, $response->get_status() );
|
||||||
|
if ( ! $tax_rate_id ) {
|
||||||
|
$tax_rate_id = $response->get_data()['id'];
|
||||||
|
}
|
||||||
|
|
||||||
|
$data = $wpdb->get_results(
|
||||||
|
$wpdb->prepare(
|
||||||
|
"SELECT location_type, GROUP_CONCAT(location_code SEPARATOR ';') as items
|
||||||
|
FROM {$wpdb->prefix}woocommerce_tax_rate_locations
|
||||||
|
WHERE tax_rate_id=%d
|
||||||
|
GROUP BY location_type",
|
||||||
|
$tax_rate_id
|
||||||
|
),
|
||||||
|
OBJECT_K
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( 'OSAKA;KYOTO;KOBE', $data['city']->items );
|
||||||
|
$this->assertEquals( '5555;7777;8888', $data['postcode']->items );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox The response for tax rate(s) includes the "city"/"postcode" (strings) and "cities"/"postcodes" (arrays) fields.
|
||||||
|
*
|
||||||
|
* @testWith [true]
|
||||||
|
* [false]
|
||||||
|
*
|
||||||
|
* @param bool $request_one True to request only one tax, false to request all the taxes.
|
||||||
|
*/
|
||||||
|
public function test_get_tax_response_includes_cities_and_postcodes_as_arrays( $request_one ) {
|
||||||
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
|
$tax_id = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_name' => 'Fake Tax',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
WC_Tax::_update_tax_rate_cities( $tax_id, 'Osaka;Kyoto;Kobe' );
|
||||||
|
WC_Tax::_update_tax_rate_postcodes( $tax_id, '5555;7777;8888' );
|
||||||
|
|
||||||
|
if ( $request_one ) {
|
||||||
|
$response = $this->do_rest_get_request( 'taxes/' . $tax_id );
|
||||||
|
} else {
|
||||||
|
$response = $this->do_rest_get_request( 'taxes' );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals( 200, $response->get_status() );
|
||||||
|
$data = $response->get_data();
|
||||||
|
if ( ! $request_one ) {
|
||||||
|
$data = current( $data );
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->assertEquals( 'KOBE', $data['city'] );
|
||||||
|
$this->assertEquals( '8888', $data['postcode'] );
|
||||||
|
$this->assertEquals( array( 'OSAKA', 'KYOTO', 'KOBE' ), $data['cities'] );
|
||||||
|
$this->assertEquals( array( '5555', '7777', '8888' ), $data['postcodes'] );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox The response of a REST API request for taxes can be sorted by priority.
|
||||||
|
*
|
||||||
|
* @testWith ["asc"]
|
||||||
|
* ["desc"]
|
||||||
|
*
|
||||||
|
* @param string $order_type Sort type, 'asc' or 'desc'.
|
||||||
|
*/
|
||||||
|
public function test_get_tax_response_can_be_sorted_by_priority( $order_type ) {
|
||||||
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
|
$tax_id_1 = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_priority' => 1,
|
||||||
|
'tax_rate_name' => 'Fake Tax 1',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$tax_id_3 = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_priority' => 3,
|
||||||
|
'tax_rate_name' => 'Fake Tax 3',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$tax_id_2 = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_priority' => 2,
|
||||||
|
'tax_rate_name' => 'Fake Tax 2',
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$response = $this->do_rest_get_request(
|
||||||
|
'taxes',
|
||||||
|
array(
|
||||||
|
'orderby' => 'priority',
|
||||||
|
'order' => $order_type,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( 200, $response->get_status() );
|
||||||
|
$data = array_values( $response->get_data() );
|
||||||
|
$ids = array_map(
|
||||||
|
function( $item ) {
|
||||||
|
return $item['id'];
|
||||||
|
},
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
|
||||||
|
if ( 'asc' === $order_type ) {
|
||||||
|
$expected = array( $tax_id_1, $tax_id_2, $tax_id_3 );
|
||||||
|
} else {
|
||||||
|
$expected = array( $tax_id_3, $tax_id_2, $tax_id_1 );
|
||||||
|
}
|
||||||
|
$this->assertEquals( $expected, $ids );
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @testdox Tax rates can be queries filtering by tax class.
|
||||||
|
*
|
||||||
|
* @testWith ["standard"]
|
||||||
|
* ["reduced-rate"]
|
||||||
|
* ["zero-rate"]
|
||||||
|
*
|
||||||
|
* @param string $class The tax class name to try getting the taxes for.
|
||||||
|
*/
|
||||||
|
public function test_can_get_taxes_filtering_by_class( $class ) {
|
||||||
|
wp_set_current_user( $this->user );
|
||||||
|
|
||||||
|
$classes = array( 'standard', 'reduced-rate', 'zero-rate' );
|
||||||
|
|
||||||
|
$tax_ids_by_class = array();
|
||||||
|
foreach ( $classes as $class ) {
|
||||||
|
$tax_id = WC_Tax::_insert_tax_rate(
|
||||||
|
array(
|
||||||
|
'tax_rate_country' => 'JP',
|
||||||
|
'tax_rate' => '1',
|
||||||
|
'tax_rate_priority' => 1,
|
||||||
|
'tax_rate_name' => 'Fake Tax',
|
||||||
|
'tax_rate_class' => $class,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
$tax_ids_by_class[ $class ] = $tax_id;
|
||||||
|
}
|
||||||
|
|
||||||
|
$response = $this->do_rest_get_request(
|
||||||
|
'taxes',
|
||||||
|
array(
|
||||||
|
'class' => $class,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( 200, $response->get_status() );
|
||||||
|
$data = array_values( $response->get_data() );
|
||||||
|
$ids = array_map(
|
||||||
|
function( $item ) {
|
||||||
|
return $item['id'];
|
||||||
|
},
|
||||||
|
$data
|
||||||
|
);
|
||||||
|
|
||||||
|
$this->assertEquals( array( $tax_ids_by_class[ $class ] ), $ids );
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue