Sync with trunk, changelog entry, resolve conflicts

This commit is contained in:
Rodel 2021-12-08 14:43:02 +08:00
commit 110266fd9b
24 changed files with 795 additions and 158 deletions

View File

@ -1,3 +1,10 @@
# Unreleased
## Added
- Shipping Zones API Tests
- Shipping Methods API Tests
- Complex Order API Tests
# 0.1.0
- Initial/beta release

View File

@ -11,6 +11,8 @@ const {
groupedProduct,
externalProduct,
} = require( './products-crud' );
const { getShippingZoneExample } = require( './shipping-zone' );
const { getShippingMethodExample } = require( './shipping-method' );
const shared = require( './shared' );
module.exports = {
@ -27,4 +29,6 @@ module.exports = {
virtualProduct,
groupedProduct,
externalProduct,
getShippingZoneExample,
getShippingMethodExample,
};

View File

@ -0,0 +1,27 @@
/**
* Constructs a shipping method based on the given `methodId` and `cost`.
*
* `methodId` should be one of the following:
* - `free_shipping`
* - `flat_rate`
* - `local_pickup`
*
* @returns shipping method object that can serve as a request payload for adding a shipping method to a shipping zone.
*/
const getShippingMethodExample = ( methodId, cost ) => {
const shippingMethodExample = {
method_id: methodId,
};
if ( cost !== undefined ) {
shippingMethodExample.settings = {
cost: cost,
};
}
return shippingMethodExample;
};
module.exports = {
getShippingMethodExample,
};

View File

@ -0,0 +1,24 @@
/**
* Default shipping zone object.
*
* For more details on shipping zone properties, see:
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#shipping-zone-properties
*
*/
const shippingZone = {
name: 'US Domestic',
};
/**
* Constructs a default shipping zone object.
*
* @returns default shipping zone
*/
const getShippingZoneExample = () => {
return shippingZone;
};
module.exports = {
getShippingZoneExample,
};

View File

@ -4,6 +4,8 @@ const { productsApi } = require( './products' );
const { refundsApi } = require( './refunds' );
const { taxRatesApi } = require( './tax-rates' );
const { variationsApi } = require( './variations' );
const { shippingZonesApi } = require( './shipping-zones' );
const { shippingMethodsApi } = require( './shipping-methods' );
module.exports = {
ordersApi,
@ -12,4 +14,6 @@ module.exports = {
refundsApi,
taxRatesApi,
variationsApi,
shippingZonesApi,
shippingMethodsApi,
};

View File

@ -0,0 +1,84 @@
/**
* Internal dependencies
*/
const {
getRequest,
postRequest,
putRequest,
deleteRequest,
} = require( '../utils/request' );
/**
* WooCommerce Shipping method endpoints.
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#shipping-methods
*/
const shippingMethodsApi = {
name: 'Shipping methods',
create: {
name: 'Include a shipping method to a shipping zone',
method: 'POST',
path: 'shipping/zones/<id>/methods',
responseCode: 200,
shippingMethod: async ( shippingZoneId, shippingMethod ) =>
postRequest(
`shipping/zones/${ shippingZoneId }/methods`,
shippingMethod
),
},
retrieve: {
name: 'Retrieve a shipping method from a shipping zone',
method: 'GET',
path: 'shipping/zones/<zone_id>/methods/<id>',
responseCode: 200,
shippingMethod: async ( shippingZoneId, shippingMethodInstanceId ) =>
getRequest(
`shipping/zones/${ shippingZoneId }/methods/${ shippingMethodInstanceId }`
),
},
listAll: {
name: 'List all shipping methods from a shipping zone',
method: 'GET',
path: 'shipping/zones/<id>/methods',
responseCode: 200,
shippingMethods: async ( shippingZoneId, params = {} ) =>
getRequest( `shipping/zones/${ shippingZoneId }/methods`, params ),
},
update: {
name: 'Update a shipping method of a shipping zone',
method: 'PUT',
path: 'shipping/zones/<zone_id>/methods/<id>',
responseCode: 200,
shippingMethod: async (
shippingZoneId,
shippingMethodInstanceId,
updatedShippingMethod
) =>
putRequest(
`shipping/zones/${ shippingZoneId }/methods/${ shippingMethodInstanceId }`,
updatedShippingMethod
),
},
delete: {
name: 'Delete a shipping method from a shipping zone',
method: 'DELETE',
path: 'shipping/zones/<zone_id>/methods/<id>>',
responseCode: 200,
payload: {
force: false,
},
shippingMethod: async (
shippingZoneId,
shippingMethodInstanceId,
deletePermanently
) =>
deleteRequest(
`shipping/zones/${ shippingZoneId }/methods/${ shippingMethodInstanceId }`,
deletePermanently
),
},
};
module.exports = {
shippingMethodsApi,
};

View File

@ -0,0 +1,71 @@
/**
* Internal dependencies
*/
const {
getRequest,
postRequest,
putRequest,
deleteRequest,
} = require( '../utils/request' );
/**
* WooCommerce Shipping zone endpoints.
*
* https://woocommerce.github.io/woocommerce-rest-api-docs/#shipping-zones
*/
const shippingZonesApi = {
name: 'Shipping zones',
create: {
name: 'Create a shipping zone',
method: 'POST',
path: 'shipping/zones',
responseCode: 201,
shippingZone: async ( shippingZone ) =>
postRequest( `shipping/zones`, shippingZone ),
},
retrieve: {
name: 'Retrieve a shipping zone',
method: 'GET',
path: 'shipping/zones/<id>',
responseCode: 200,
shippingZone: async ( shippingZoneId ) =>
getRequest( `shipping/zones/${ shippingZoneId }` ),
},
listAll: {
name: 'List all shipping zones',
method: 'GET',
path: 'shipping/zones',
responseCode: 200,
shippingZones: async ( params = {} ) =>
getRequest( `shipping/zones`, params ),
},
update: {
name: 'Update a shipping zone',
method: 'PUT',
path: 'shipping/zones/<id>',
responseCode: 200,
shippingZone: async ( shippingZoneId, updatedShippingZone ) =>
putRequest(
`shipping/zones/${ shippingZoneId }`,
updatedShippingZone
),
},
delete: {
name: 'Delete a shipping zone',
method: 'DELETE',
path: 'shipping/zones/<id>',
responseCode: 200,
payload: {
force: false,
},
shippingZone: async ( shippingZoneId, deletePermanently ) =>
deleteRequest(
`shipping/zones/${ shippingZoneId }`,
deletePermanently
),
},
};
module.exports = {
shippingZonesApi,
};

View File

@ -1,6 +1,6 @@
const { couponsApi } = require('../../endpoints/coupons');
const { ordersApi } = require('../../endpoints/orders');
const { coupon, order } = require('../../data');
const { couponsApi } = require( '../../endpoints/coupons' );
const { ordersApi } = require( '../../endpoints/orders' );
const { coupon, order } = require( '../../data' );
/**
* Tests for the WooCommerce Coupons API.
@ -9,37 +9,39 @@ const { coupon, order } = require('../../data');
* @group coupons
*
*/
describe('Coupons API tests', () => {
describe( 'Coupons API tests', () => {
let couponId;
it('can create a coupon', async () => {
it( 'can create a coupon', async () => {
const testCoupon = {
...coupon,
code: `${coupon.code}-${Date.now()}`,
code: `${ coupon.code }-${ Date.now() }`,
};
const response = await couponsApi.create.coupon(testCoupon);
const response = await couponsApi.create.coupon( testCoupon );
expect(response.statusCode).toEqual(couponsApi.create.responseCode);
expect(response.body.id).toBeDefined();
expect( response.statusCode ).toEqual( couponsApi.create.responseCode );
expect( response.body.id ).toBeDefined();
couponId = response.body.id;
// Validate the created coupon object has the correct code, amount, and discount type
expect(response.body).toEqual(
expect.objectContaining({
expect( response.body ).toEqual(
expect.objectContaining( {
code: testCoupon.code,
amount: Number(coupon.amount).toFixed(2),
amount: Number( coupon.amount ).toFixed( 2 ),
discount_type: coupon.discount_type,
})
} )
);
});
} );
it('can retrieve a coupon', async () => {
const response = await couponsApi.retrieve.coupon(couponId);
expect(response.statusCode).toEqual(couponsApi.retrieve.responseCode);
expect(response.body.id).toEqual(couponId);
});
it( 'can retrieve a coupon', async () => {
const response = await couponsApi.retrieve.coupon( couponId );
expect( response.statusCode ).toEqual(
couponsApi.retrieve.responseCode
);
expect( response.body.id ).toEqual( couponId );
} );
it('can update a coupon', async () => {
it( 'can update a coupon', async () => {
const updatedCouponDetails = {
description: '10% off storewide',
maximum_amount: '500.00',
@ -50,40 +52,40 @@ describe('Coupons API tests', () => {
couponId,
updatedCouponDetails
);
expect(response.statusCode).toEqual(couponsApi.update.responseCode);
expect(response.body).toEqual(
expect.objectContaining(updatedCouponDetails)
expect( response.statusCode ).toEqual( couponsApi.update.responseCode );
expect( response.body ).toEqual(
expect.objectContaining( updatedCouponDetails )
);
});
} );
it('can permanently delete a coupon', async () => {
const response = await couponsApi.delete.coupon(couponId, true);
it( 'can permanently delete a coupon', async () => {
const response = await couponsApi.delete.coupon( couponId, true );
expect(response.statusCode).toEqual(couponsApi.delete.responseCode);
expect( response.statusCode ).toEqual( couponsApi.delete.responseCode );
const getCouponResponse = await couponsApi.retrieve.coupon(couponId);
expect(getCouponResponse.statusCode).toEqual(404);
});
const getCouponResponse = await couponsApi.retrieve.coupon( couponId );
expect( getCouponResponse.statusCode ).toEqual( 404 );
} );
describe('Batch update coupons', () => {
describe( 'Batch update coupons', () => {
/**
* Coupons to be created, updated, and deleted.
*/
const expectedCoupons = [
{
code: `batchcoupon-${Date.now()}`,
code: `batchcoupon-${ Date.now() }`,
discount_type: 'percent',
amount: '10',
free_shipping: false,
},
{
code: `batchcoupon-${Date.now() + 1}`,
code: `batchcoupon-${ Date.now() + 1 }`,
discount_type: 'percent',
amount: '20',
},
];
it('can batch create coupons', async () => {
it( 'can batch create coupons', async () => {
// Batch create 2 new coupons.
const batchCreatePayload = {
create: expectedCoupons,
@ -91,36 +93,36 @@ describe('Coupons API tests', () => {
const batchCreateResponse = await couponsApi.batch.coupons(
batchCreatePayload
);
expect(batchCreateResponse.status).toEqual(
expect( batchCreateResponse.status ).toEqual(
couponsApi.batch.responseCode
);
// Verify that the 2 new coupons were created
const actualCoupons = batchCreateResponse.body.create;
expect(actualCoupons).toHaveLength(expectedCoupons.length);
for (let i = 0; i < actualCoupons.length; i++) {
const { id, code } = actualCoupons[i];
const expectedCouponCode = expectedCoupons[i].code;
expect( actualCoupons ).toHaveLength( expectedCoupons.length );
for ( let i = 0; i < actualCoupons.length; i++ ) {
const { id, code } = actualCoupons[ i ];
const expectedCouponCode = expectedCoupons[ i ].code;
expect(id).toBeDefined();
expect(code).toEqual(expectedCouponCode);
expect( id ).toBeDefined();
expect( code ).toEqual( expectedCouponCode );
// Save the coupon id
expectedCoupons[i].id = id;
expectedCoupons[ i ].id = id;
}
});
} );
it('can batch update coupons', async () => {
it( 'can batch update coupons', async () => {
// Update the 1st coupon to free shipping.
// Update the amount of the 2nd coupon to 25.
const batchUpdatePayload = {
update: [
{
id: expectedCoupons[0].id,
id: expectedCoupons[ 0 ].id,
free_shipping: true,
},
{
id: expectedCoupons[1].id,
id: expectedCoupons[ 1 ].id,
amount: '25.00',
},
],
@ -131,23 +133,23 @@ describe('Coupons API tests', () => {
// Verify the response code and the number of coupons that were updated.
const updatedCoupons = batchUpdateResponse.body.update;
expect(batchUpdateResponse.status).toEqual(
expect( batchUpdateResponse.status ).toEqual(
couponsApi.batch.responseCode
);
expect(updatedCoupons).toHaveLength(expectedCoupons.length);
expect( updatedCoupons ).toHaveLength( expectedCoupons.length );
// Verify that the 1st coupon was updated to free shipping.
expect(updatedCoupons[0].id).toEqual(expectedCoupons[0].id);
expect(updatedCoupons[0].free_shipping).toEqual(true);
expect( updatedCoupons[ 0 ].id ).toEqual( expectedCoupons[ 0 ].id );
expect( updatedCoupons[ 0 ].free_shipping ).toEqual( true );
// Verify that the amount of the 2nd coupon was updated to 25.
expect(updatedCoupons[1].id).toEqual(expectedCoupons[1].id);
expect(updatedCoupons[1].amount).toEqual('25.00');
});
expect( updatedCoupons[ 1 ].id ).toEqual( expectedCoupons[ 1 ].id );
expect( updatedCoupons[ 1 ].amount ).toEqual( '25.00' );
} );
it('can batch delete coupons', async () => {
it( 'can batch delete coupons', async () => {
// Batch delete the 2 coupons.
const couponIdsToDelete = expectedCoupons.map(({ id }) => id);
const couponIdsToDelete = expectedCoupons.map( ( { id } ) => id );
const batchDeletePayload = {
delete: couponIdsToDelete,
};
@ -157,151 +159,171 @@ describe('Coupons API tests', () => {
// Verify that the response shows the 2 coupons.
const deletedCouponIds = batchDeleteResponse.body.delete.map(
({ id }) => id
( { id } ) => id
);
expect(batchDeleteResponse.status).toEqual(
expect( batchDeleteResponse.status ).toEqual(
couponsApi.batch.responseCode
);
expect(deletedCouponIds).toEqual(couponIdsToDelete);
expect( deletedCouponIds ).toEqual( couponIdsToDelete );
// Verify that the 2 deleted coupons cannot be retrieved.
for (const couponId of couponIdsToDelete) {
const { status } = await couponsApi.retrieve.coupon(couponId);
for ( const couponId of couponIdsToDelete ) {
const { status } = await couponsApi.retrieve.coupon( couponId );
expect(status).toEqual(404);
expect( status ).toEqual( 404 );
}
});
});
} );
} );
describe('List coupons', () => {
describe( 'List coupons', () => {
const allCoupons = [
{
...coupon,
code: `listcoupons-01-${Date.now()}`,
description: `description-01-${Date.now()}`,
code: `listcoupons-01-${ Date.now() }`,
description: `description-01-${ Date.now() }`,
},
{
...coupon,
code: `listcoupons-02-${Date.now()}`,
description: `description-02-${Date.now()}`,
code: `listcoupons-02-${ Date.now() }`,
description: `description-02-${ Date.now() }`,
},
{
...coupon,
code: `listcoupons-03-${Date.now()}`,
description: `description-03-${Date.now()}`,
code: `listcoupons-03-${ Date.now() }`,
description: `description-03-${ Date.now() }`,
},
];
beforeAll(async () => {
beforeAll( async () => {
// Create list of coupons for testing.
const response = await couponsApi.batch.coupons({
const response = await couponsApi.batch.coupons( {
create: allCoupons,
});
} );
const actualCreatedCoupons = response.body.create;
// Save their coupon ID's
for (const coupon of allCoupons) {
for ( const coupon of allCoupons ) {
const { id } = actualCreatedCoupons.find(
({ code }) => coupon.code === code
( { code } ) => coupon.code === code
);
coupon.id = id;
}
});
} );
afterAll(async () => {
afterAll( async () => {
// Clean up created coupons
const batchDeletePayload = {
delete: allCoupons.map(({ id }) => id),
delete: allCoupons.map( ( { id } ) => id ),
};
await couponsApi.batch.coupons(batchDeletePayload);
});
await couponsApi.batch.coupons( batchDeletePayload );
} );
it('can list all coupons by default', async () => {
it( 'can list all coupons by default', async () => {
const response = await couponsApi.listAll.coupons();
const listedCoupons = response.body;
const actualCouponIdsList = listedCoupons.map(({ id }) => id);
const expectedCouponIdsList = allCoupons.map(({ id }) => id);
const actualCouponIdsList = listedCoupons.map( ( { id } ) => id );
const expectedCouponIdsList = allCoupons.map( ( { id } ) => id );
expect(response.status).toEqual(couponsApi.listAll.responseCode);
expect(actualCouponIdsList).toEqual(
expect.arrayContaining(expectedCouponIdsList)
expect( response.status ).toEqual(
couponsApi.listAll.responseCode
);
});
expect( actualCouponIdsList ).toEqual(
expect.arrayContaining( expectedCouponIdsList )
);
} );
it('can limit result set to matching code', async () => {
const matchingCoupon = allCoupons[1];
it( 'can limit result set to matching code', async () => {
const matchingCoupon = allCoupons[ 1 ];
const payload = { code: matchingCoupon.code };
const { status, body } = await couponsApi.listAll.coupons(payload);
const { status, body } = await couponsApi.listAll.coupons(
payload
);
expect(status).toEqual(couponsApi.listAll.responseCode);
expect(body).toHaveLength(1);
expect(body[0].id).toEqual(matchingCoupon.id);
});
expect( status ).toEqual( couponsApi.listAll.responseCode );
expect( body ).toHaveLength( 1 );
expect( body[ 0 ].id ).toEqual( matchingCoupon.id );
} );
it('can paginate results', async () => {
it( 'can paginate results', async () => {
const pageSize = 2;
const payload = {
page: 1,
per_page: pageSize,
};
const { status, body } = await couponsApi.listAll.coupons(payload);
const { status, body } = await couponsApi.listAll.coupons(
payload
);
expect(status).toEqual(couponsApi.listAll.responseCode);
expect(body).toHaveLength(pageSize);
});
expect( status ).toEqual( couponsApi.listAll.responseCode );
expect( body ).toHaveLength( pageSize );
} );
it('can limit results to matching string', async () => {
it( 'can limit results to matching string', async () => {
// Search by description
const matchingCoupon = allCoupons[2];
const matchingCoupon = allCoupons[ 2 ];
const matchingString = matchingCoupon.description;
const payload = {
search: matchingString,
};
const { status, body } = await couponsApi.listAll.coupons(payload);
const { status, body } = await couponsApi.listAll.coupons(
payload
);
expect(status).toEqual(couponsApi.listAll.responseCode);
expect(body).toHaveLength(1);
expect(body[0].id).toEqual(matchingCoupon.id);
});
});
expect( status ).toEqual( couponsApi.listAll.responseCode );
expect( body ).toHaveLength( 1 );
expect( body[ 0 ].id ).toEqual( matchingCoupon.id );
} );
} );
describe('Add coupon to order', () => {
describe( 'Add coupon to order', () => {
const testCoupon = {
code: `coupon-${Date.now()}`,
code: `coupon-${ Date.now() }`,
discount_type: 'percent',
amount: '10',
};
let orderId;
beforeAll(async () => {
beforeAll( async () => {
// Create a coupon
const createCouponResponse = await couponsApi.create.coupon(
testCoupon
);
testCoupon.id = createCouponResponse.body.id;
});
} );
// Clean up created coupon and order
afterAll(async () => {
await couponsApi.delete.coupon(testCoupon.id, true);
await ordersApi.delete.order(orderId, true);
});
afterAll( async () => {
await couponsApi.delete.coupon( testCoupon.id, true );
await ordersApi.delete.order( orderId, true );
} );
it('can add coupon to an order', async () => {
it( 'can add coupon to an order', async () => {
const orderWithCoupon = {
...order,
coupon_lines: [{ code: testCoupon.code }],
coupon_lines: [ { code: testCoupon.code } ],
};
const { status, body } = await ordersApi.create.order(
orderWithCoupon
);
orderId = body.id;
expect(status).toEqual(ordersApi.create.responseCode);
expect(body.coupon_lines).toHaveLength(1);
expect(body.coupon_lines[0].code).toEqual(testCoupon.code);
});
});
});
expect( status ).toEqual( ordersApi.create.responseCode );
expect( body.coupon_lines ).toHaveLength( 1 );
expect( body.coupon_lines[ 0 ].code ).toEqual( testCoupon.code );
// Test that the coupon meta data exists.
// See: https://github.com/woocommerce/woocommerce/issues/28166.
expect( body.coupon_lines[ 0 ].meta_data ).toEqual(
expect.arrayContaining( [
expect.objectContaining( {
key: 'coupon_data',
value: expect.objectContaining( {
code: testCoupon.code,
} ),
} ),
] )
);
} );
} );
} );

View File

@ -0,0 +1,57 @@
const { shippingMethodsApi } = require( '../../endpoints' );
const { getShippingMethodExample } = require( '../../data' );
/**
* Shipping zone id for "Locations not covered by your other zones".
*/
const shippingZoneId = 0;
/**
* Data table for shipping methods.
*/
const shippingMethods = [
[ 'Flat rate', 'flat_rate', '10' ],
[ 'Free shipping', 'free_shipping', undefined ],
[ 'Local pickup', 'local_pickup', '30' ],
];
/**
* Tests for the WooCommerce Shipping methods API.
*
* @group api
* @group shipping-methods
*
*/
describe( 'Shipping methods API tests', () => {
it.each( shippingMethods )(
"can add a '%s' shipping method",
async ( methodTitle, methodId, cost ) => {
const shippingMethod = getShippingMethodExample( methodId, cost );
const {
status,
body,
} = await shippingMethodsApi.create.shippingMethod(
shippingZoneId,
shippingMethod
);
expect( status ).toEqual( shippingMethodsApi.create.responseCode );
expect( typeof body.id ).toEqual( 'number' );
expect( body.method_id ).toEqual( methodId );
expect( body.method_title ).toEqual( methodTitle );
expect( body.enabled ).toEqual( true );
if ( [ 'flat_rate', 'local_pickup' ].includes( methodId ) ) {
expect( body.settings.cost.value ).toEqual( cost );
}
// Cleanup: Delete the shipping method
await shippingMethodsApi.delete.shippingMethod(
shippingZoneId,
body.id,
true
);
}
);
} );

View File

@ -0,0 +1,124 @@
const { shippingZonesApi } = require( '../../endpoints' );
const { getShippingZoneExample } = require( '../../data' );
/**
* Shipping zone to be created, retrieved, updated, and deleted by the tests.
*/
const shippingZone = getShippingZoneExample();
/**
* Tests for the WooCommerce Shipping zones API.
*
* @group api
* @group shipping-zones
*
*/
describe( 'Shipping zones API tests', () => {
it( 'cannot delete the default shipping zone "Locations not covered by your other zones"', async () => {
// Delete all pre-existing shipping zones
const { body } = await shippingZonesApi.listAll.shippingZones( {
_fields: 'id',
} );
const ids = body.map( ( { id } ) => id );
for ( const id of ids ) {
await shippingZonesApi.delete.shippingZone( id, true );
}
// Verify that the default shipping zone remains
const {
body: remainingZones,
} = await shippingZonesApi.listAll.shippingZones( {
_fields: 'id',
} );
expect( remainingZones ).toHaveLength( 1 );
expect( remainingZones[ 0 ].id ).toEqual( 0 );
} );
it( 'cannot update the default shipping zone', async () => {
const newZoneDetails = {
name: 'Default shipping zone',
};
const { status, body } = await shippingZonesApi.update.shippingZone(
0,
newZoneDetails
);
expect( status ).toEqual( 403 );
expect( body.code ).toEqual(
'woocommerce_rest_shipping_zone_invalid_zone'
);
expect( body.message ).toEqual(
'The "locations not covered by your other zones" zone cannot be updated.'
);
} );
it( 'can create a shipping zone', async () => {
const { status, body } = await shippingZonesApi.create.shippingZone(
shippingZone
);
expect( status ).toEqual( shippingZonesApi.create.responseCode );
expect( typeof body.id ).toEqual( 'number' );
expect( body.name ).toEqual( shippingZone.name );
// Save the shipping zone ID. It will be used by other tests.
shippingZone.id = body.id;
} );
it( 'can retrieve a shipping zone', async () => {
const { status, body } = await shippingZonesApi.retrieve.shippingZone(
shippingZone.id
);
expect( status ).toEqual( shippingZonesApi.retrieve.responseCode );
expect( body.id ).toEqual( shippingZone.id );
} );
it( 'can list all shipping zones', async () => {
const param = {
_fields: 'id',
};
const { status, body } = await shippingZonesApi.listAll.shippingZones(
param
);
expect( body ).toHaveLength( 2 ); // the test shipping zone, and the default 'Locations not covered by your other zones'
expect( status ).toEqual( shippingZonesApi.listAll.responseCode );
expect( body ).toEqual(
expect.arrayContaining( [ { id: shippingZone.id } ] )
);
} );
it( 'can update a shipping zone', async () => {
const updatedShippingZone = {
name: 'United States (Domestic)',
};
const { status, body } = await shippingZonesApi.update.shippingZone(
shippingZone.id,
updatedShippingZone
);
expect( status ).toEqual( shippingZonesApi.retrieve.responseCode );
expect( body.id ).toEqual( shippingZone.id );
expect( body.name ).toEqual( updatedShippingZone.name );
} );
it( 'can delete a shipping zone', async () => {
const { status, body } = await shippingZonesApi.delete.shippingZone(
shippingZone.id,
true
);
expect( status ).toEqual( shippingZonesApi.delete.responseCode );
expect( body.id ).toEqual( shippingZone.id );
// Verify that the shipping zone can no longer be retrieved
const {
status: retrieveStatus,
} = await shippingZonesApi.retrieve.shippingZone( shippingZone.id );
expect( retrieveStatus ).toEqual( 404 );
} );
} );

View File

@ -21,7 +21,7 @@
"pelago/emogrifier": "3.1.0",
"psr/container": "1.0.0",
"woocommerce/action-scheduler": "3.4.0",
"woocommerce/woocommerce-admin": "2.9.0",
"woocommerce/woocommerce-admin": "2.9.1",
"woocommerce/woocommerce-blocks": "6.3.3"
},
"require-dev": {

View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "ec7987721f51ed5c0faf6251128ba110",
"content-hash": "20885acd22c0a58cff8852e7cf4ebf20",
"packages": [
{
"name": "automattic/jetpack-autoloader",
@ -51,6 +51,9 @@
"GPL-2.0-or-later"
],
"description": "Creates a custom autoloader for a plugin or theme.",
"support": {
"source": "https://github.com/Automattic/jetpack-autoloader/tree/2.10.1"
},
"time": "2021-03-30T15:15:59+00:00"
},
{
@ -82,6 +85,9 @@
"GPL-2.0-or-later"
],
"description": "A wrapper for defining constants in a more testable way.",
"support": {
"source": "https://github.com/Automattic/jetpack-constants/tree/v1.5.1"
},
"time": "2020-10-28T19:00:31+00:00"
},
{
@ -215,6 +221,10 @@
"zend",
"zikula"
],
"support": {
"issues": "https://github.com/composer/installers/issues",
"source": "https://github.com/composer/installers/tree/v1.12.0"
},
"funding": [
{
"url": "https://packagist.com",
@ -289,6 +299,10 @@
"geolocation",
"maxmind"
],
"support": {
"issues": "https://github.com/maxmind/MaxMind-DB-Reader-php/issues",
"source": "https://github.com/maxmind/MaxMind-DB-Reader-php/tree/v1.6.0"
},
"time": "2019-12-19T22:59:03+00:00"
},
{
@ -363,6 +377,10 @@
"email",
"pre-processing"
],
"support": {
"issues": "https://github.com/MyIntervals/emogrifier/issues",
"source": "https://github.com/MyIntervals/emogrifier"
},
"time": "2019-12-26T19:37:31+00:00"
},
{
@ -412,6 +430,10 @@
"container-interop",
"psr"
],
"support": {
"issues": "https://github.com/php-fig/container/issues",
"source": "https://github.com/php-fig/container/tree/master"
},
"time": "2017-02-14T16:28:37+00:00"
},
{
@ -460,6 +482,9 @@
],
"description": "Symfony CssSelector Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/css-selector/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -510,20 +535,24 @@
],
"description": "Action Scheduler for WordPress and WooCommerce",
"homepage": "https://actionscheduler.org/",
"support": {
"issues": "https://github.com/woocommerce/action-scheduler/issues",
"source": "https://github.com/woocommerce/action-scheduler/tree/3.4.0"
},
"time": "2021-10-28T17:09:12+00:00"
},
{
"name": "woocommerce/woocommerce-admin",
"version": "2.9.0",
"version": "2.9.1",
"source": {
"type": "git",
"url": "https://github.com/woocommerce/woocommerce-admin.git",
"reference": "8040a6ac2af1b217324ae83a4137b0bfe3edbc23"
"reference": "fdffbfef084c65a3e2141f0aff41cef3bad27553"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/8040a6ac2af1b217324ae83a4137b0bfe3edbc23",
"reference": "8040a6ac2af1b217324ae83a4137b0bfe3edbc23",
"url": "https://api.github.com/repos/woocommerce/woocommerce-admin/zipball/fdffbfef084c65a3e2141f0aff41cef3bad27553",
"reference": "fdffbfef084c65a3e2141f0aff41cef3bad27553",
"shasum": ""
},
"require": {
@ -577,7 +606,11 @@
],
"description": "A modern, javascript-driven WooCommerce Admin experience.",
"homepage": "https://github.com/woocommerce/woocommerce-admin",
"time": "2021-11-29T23:28:44+00:00"
"support": {
"issues": "https://github.com/woocommerce/woocommerce-admin/issues",
"source": "https://github.com/woocommerce/woocommerce-admin/tree/v2.9.1"
},
"time": "2021-12-08T02:59:25+00:00"
},
{
"name": "woocommerce/woocommerce-blocks",
@ -687,6 +720,9 @@
"GPL-2.0-or-later"
],
"description": "Jetpack Changelogger tool. Allows for managing changelogs by dropping change files into a changelog directory with each PR.",
"support": {
"source": "https://github.com/Automattic/jetpack-changelogger/tree/v3.0.2"
},
"time": "2021-11-02T14:06:49+00:00"
},
{
@ -733,6 +769,10 @@
"isolation",
"tool"
],
"support": {
"issues": "https://github.com/bamarni/composer-bin-plugin/issues",
"source": "https://github.com/bamarni/composer-bin-plugin/tree/master"
},
"time": "2020-05-03T08:27:20+00:00"
},
{
@ -787,6 +827,10 @@
"constructor",
"instantiate"
],
"support": {
"issues": "https://github.com/doctrine/instantiator/issues",
"source": "https://github.com/doctrine/instantiator/tree/master"
},
"time": "2015-06-14T21:17:01+00:00"
},
{
@ -832,6 +876,10 @@
"object",
"object graph"
],
"support": {
"issues": "https://github.com/myclabs/DeepCopy/issues",
"source": "https://github.com/myclabs/DeepCopy/tree/1.x"
},
"time": "2017-10-19T19:58:43+00:00"
},
{
@ -887,6 +935,10 @@
}
],
"description": "Component for reading phar.io manifest information from a PHP Archive (PHAR)",
"support": {
"issues": "https://github.com/phar-io/manifest/issues",
"source": "https://github.com/phar-io/manifest/tree/master"
},
"time": "2017-03-05T18:14:27+00:00"
},
{
@ -934,6 +986,10 @@
}
],
"description": "Library for handling version information and constraints",
"support": {
"issues": "https://github.com/phar-io/version/issues",
"source": "https://github.com/phar-io/version/tree/master"
},
"time": "2017-03-05T17:38:23+00:00"
},
{
@ -988,6 +1044,10 @@
"reflection",
"static analysis"
],
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionCommon/issues",
"source": "https://github.com/phpDocumentor/ReflectionCommon/tree/master"
},
"time": "2017-09-11T18:02:19+00:00"
},
{
@ -1040,6 +1100,10 @@
}
],
"description": "With this component, a library can provide support for annotations via DocBlocks or otherwise retrieve information that is embedded in a DocBlock.",
"support": {
"issues": "https://github.com/phpDocumentor/ReflectionDocBlock/issues",
"source": "https://github.com/phpDocumentor/ReflectionDocBlock/tree/release/4.x"
},
"time": "2019-12-28T18:55:12+00:00"
},
{
@ -1085,6 +1149,10 @@
"email": "me@mikevanriel.com"
}
],
"support": {
"issues": "https://github.com/phpDocumentor/TypeResolver/issues",
"source": "https://github.com/phpDocumentor/TypeResolver/tree/master"
},
"time": "2017-12-30T13:23:38+00:00"
},
{
@ -1148,6 +1216,10 @@
"spy",
"stub"
],
"support": {
"issues": "https://github.com/phpspec/prophecy/issues",
"source": "https://github.com/phpspec/prophecy/tree/v1.10.3"
},
"time": "2020-03-05T15:02:03+00:00"
},
{
@ -1211,6 +1283,10 @@
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-code-coverage/issues",
"source": "https://github.com/sebastianbergmann/php-code-coverage/tree/5.3"
},
"time": "2018-04-06T15:36:58+00:00"
},
{
@ -1258,6 +1334,11 @@
"filesystem",
"iterator"
],
"support": {
"irc": "irc://irc.freenode.net/phpunit",
"issues": "https://github.com/sebastianbergmann/php-file-iterator/issues",
"source": "https://github.com/sebastianbergmann/php-file-iterator/tree/1.4.5"
},
"time": "2017-11-27T13:52:08+00:00"
},
{
@ -1299,6 +1380,10 @@
"keywords": [
"template"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-text-template/issues",
"source": "https://github.com/sebastianbergmann/php-text-template/tree/1.2.1"
},
"time": "2015-06-21T13:50:34+00:00"
},
{
@ -1348,6 +1433,10 @@
"keywords": [
"timer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-timer/issues",
"source": "https://github.com/sebastianbergmann/php-timer/tree/master"
},
"time": "2017-02-26T11:10:40+00:00"
},
{
@ -1397,6 +1486,10 @@
"keywords": [
"tokenizer"
],
"support": {
"issues": "https://github.com/sebastianbergmann/php-token-stream/issues",
"source": "https://github.com/sebastianbergmann/php-token-stream/tree/master"
},
"abandoned": true,
"time": "2017-11-27T05:48:46+00:00"
},
@ -1482,6 +1575,10 @@
"testing",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit/issues",
"source": "https://github.com/sebastianbergmann/phpunit/tree/6.5.14"
},
"time": "2019-02-01T05:22:47+00:00"
},
{
@ -1541,6 +1638,10 @@
"mock",
"xunit"
],
"support": {
"issues": "https://github.com/sebastianbergmann/phpunit-mock-objects/issues",
"source": "https://github.com/sebastianbergmann/phpunit-mock-objects/tree/5.0.10"
},
"abandoned": true,
"time": "2018-08-09T05:50:03+00:00"
},
@ -1589,6 +1690,9 @@
"psr",
"psr-3"
],
"support": {
"source": "https://github.com/php-fig/log/tree/1.1.4"
},
"time": "2021-05-03T11:20:27+00:00"
},
{
@ -1634,6 +1738,10 @@
],
"description": "Looks up which function or method a line of code belongs to",
"homepage": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/",
"support": {
"issues": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/issues",
"source": "https://github.com/sebastianbergmann/code-unit-reverse-lookup/tree/1.0.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
@ -1704,6 +1812,10 @@
"compare",
"equality"
],
"support": {
"issues": "https://github.com/sebastianbergmann/comparator/issues",
"source": "https://github.com/sebastianbergmann/comparator/tree/master"
},
"time": "2018-02-01T13:46:46+00:00"
},
{
@ -1756,6 +1868,10 @@
"keywords": [
"diff"
],
"support": {
"issues": "https://github.com/sebastianbergmann/diff/issues",
"source": "https://github.com/sebastianbergmann/diff/tree/master"
},
"time": "2017-08-03T08:09:46+00:00"
},
{
@ -1806,6 +1922,10 @@
"environment",
"hhvm"
],
"support": {
"issues": "https://github.com/sebastianbergmann/environment/issues",
"source": "https://github.com/sebastianbergmann/environment/tree/master"
},
"time": "2017-07-01T08:51:00+00:00"
},
{
@ -1873,6 +1993,10 @@
"export",
"exporter"
],
"support": {
"issues": "https://github.com/sebastianbergmann/exporter/issues",
"source": "https://github.com/sebastianbergmann/exporter/tree/3.1.4"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
@ -1930,6 +2054,10 @@
"keywords": [
"global state"
],
"support": {
"issues": "https://github.com/sebastianbergmann/global-state/issues",
"source": "https://github.com/sebastianbergmann/global-state/tree/2.0.0"
},
"time": "2017-04-27T15:39:26+00:00"
},
{
@ -1977,6 +2105,10 @@
],
"description": "Traverses array structures and object graphs to enumerate all referenced objects",
"homepage": "https://github.com/sebastianbergmann/object-enumerator/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-enumerator/issues",
"source": "https://github.com/sebastianbergmann/object-enumerator/tree/3.0.4"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
@ -2028,6 +2160,10 @@
],
"description": "Allows reflection of object attributes, including inherited and non-public ones",
"homepage": "https://github.com/sebastianbergmann/object-reflector/",
"support": {
"issues": "https://github.com/sebastianbergmann/object-reflector/issues",
"source": "https://github.com/sebastianbergmann/object-reflector/tree/1.1.2"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
@ -2087,6 +2223,10 @@
],
"description": "Provides functionality to recursively process PHP variables",
"homepage": "http://www.github.com/sebastianbergmann/recursion-context",
"support": {
"issues": "https://github.com/sebastianbergmann/recursion-context/issues",
"source": "https://github.com/sebastianbergmann/recursion-context/tree/3.0.1"
},
"funding": [
{
"url": "https://github.com/sebastianbergmann",
@ -2135,6 +2275,10 @@
],
"description": "Provides a list of PHP built-in functions that operate on resources",
"homepage": "https://www.github.com/sebastianbergmann/resource-operations",
"support": {
"issues": "https://github.com/sebastianbergmann/resource-operations/issues",
"source": "https://github.com/sebastianbergmann/resource-operations/tree/master"
},
"time": "2015-07-28T20:34:47+00:00"
},
{
@ -2178,6 +2322,10 @@
],
"description": "Library that helps with managing the version number of Git-hosted PHP projects",
"homepage": "https://github.com/sebastianbergmann/version",
"support": {
"issues": "https://github.com/sebastianbergmann/version/issues",
"source": "https://github.com/sebastianbergmann/version/tree/master"
},
"time": "2016-10-03T07:35:21+00:00"
},
{
@ -2245,6 +2393,9 @@
],
"description": "Symfony Console Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/console/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -2310,6 +2461,9 @@
],
"description": "Symfony Debug Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/debug/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -2386,6 +2540,9 @@
"polyfill",
"portable"
],
"support": {
"source": "https://github.com/symfony/polyfill-ctype/tree/v1.19.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -2463,6 +2620,9 @@
"portable",
"shim"
],
"support": {
"source": "https://github.com/symfony/polyfill-mbstring/tree/v1.19.0"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -2521,6 +2681,9 @@
],
"description": "Symfony Process Component",
"homepage": "https://symfony.com",
"support": {
"source": "https://github.com/symfony/process/tree/v3.4.47"
},
"funding": [
{
"url": "https://symfony.com/sponsor",
@ -2575,6 +2738,10 @@
}
],
"description": "A small library for converting tokenized PHP source code into XML and potentially other formats",
"support": {
"issues": "https://github.com/theseer/tokenizer/issues",
"source": "https://github.com/theseer/tokenizer/tree/master"
},
"time": "2019-06-13T22:48:21+00:00"
},
{
@ -2624,6 +2791,10 @@
"check",
"validate"
],
"support": {
"issues": "https://github.com/webmozarts/assert/issues",
"source": "https://github.com/webmozarts/assert/tree/1.9.1"
},
"time": "2020-07-08T17:02:28+00:00"
},
{
@ -2676,6 +2847,9 @@
],
"description": "Safe replacement to @ for suppressing warnings.",
"homepage": "https://www.mediawiki.org/wiki/at-ease",
"support": {
"source": "https://github.com/wikimedia/at-ease/tree/master"
},
"time": "2018-10-10T15:39:06+00:00"
},
{
@ -2733,6 +2907,10 @@
"polyfill",
"testing"
],
"support": {
"issues": "https://github.com/Yoast/PHPUnit-Polyfills/issues",
"source": "https://github.com/Yoast/PHPUnit-Polyfills"
},
"time": "2021-11-23T01:37:03+00:00"
}
],
@ -2748,5 +2926,5 @@
"platform-overrides": {
"php": "7.0.33"
},
"plugin-api-version": "2.1.0"
"plugin-api-version": "2.0.0"
}

View File

@ -1323,6 +1323,16 @@ abstract class WC_Abstract_Order extends WC_Abstract_Legacy_Order {
if ( ! $item_id ) {
$coupon_item = new WC_Order_Item_Coupon();
$coupon_item->set_code( $coupon_code );
// Add coupon data.
$coupon_id = wc_get_coupon_id_by_code( $coupon_code );
$coupon = new WC_Coupon( $coupon_id );
// Avoid storing used_by - it's not needed and can get large.
$coupon_data = $coupon->get_data();
unset( $coupon_data['used_by'] );
$coupon_item->add_meta_data( 'coupon_data', $coupon_data );
} else {
$coupon_item = $this->get_item( $item_id, false );
}

View File

@ -157,7 +157,7 @@ class WC_Admin {
public function prevent_admin_access() {
$prevent_access = false;
if ( apply_filters( 'woocommerce_disable_admin_bar', true ) && ! is_ajax() && isset( $_SERVER['SCRIPT_FILENAME'] ) && basename( sanitize_text_field( wp_unslash( $_SERVER['SCRIPT_FILENAME'] ) ) ) !== 'admin-post.php' ) {
if ( apply_filters( 'woocommerce_disable_admin_bar', true ) && ! wp_doing_ajax() && isset( $_SERVER['SCRIPT_FILENAME'] ) && basename( sanitize_text_field( wp_unslash( $_SERVER['SCRIPT_FILENAME'] ) ) ) !== 'admin-post.php' ) {
$has_cap = false;
$access_caps = array( 'edit_posts', 'manage_woocommerce', 'view_admin_dashboard' );

View File

@ -175,7 +175,7 @@ class WC_Settings_General extends WC_Settings_Page {
'class' => 'wc-enhanced-select',
'options' => array(
'' => __( 'No location by default', 'woocommerce' ),
'base' => __( 'Shop base address', 'woocommerce' ),
'base' => __( 'Shop country/region', 'woocommerce' ),
'geolocation' => __( 'Geolocate', 'woocommerce' ),
'geolocation_ajax' => __( 'Geolocate (with page caching support)', 'woocommerce' ),
),

View File

@ -186,7 +186,7 @@ class WC_Cache_Helper {
* This prevents caching of the wrong data for this request.
*/
public static function geolocation_ajax_redirect() {
if ( 'geolocation_ajax' === get_option( 'woocommerce_default_customer_address' ) && ! is_checkout() && ! is_cart() && ! is_account_page() && ! is_ajax() && empty( $_POST ) ) { // WPCS: CSRF ok, input var ok.
if ( 'geolocation_ajax' === get_option( 'woocommerce_default_customer_address' ) && ! is_checkout() && ! is_cart() && ! is_account_page() && ! wp_doing_ajax() && empty( $_POST ) ) { // WPCS: CSRF ok, input var ok.
$location_hash = self::geolocation_ajax_get_location_hash();
$current_hash = isset( $_GET['v'] ) ? wc_clean( wp_unslash( $_GET['v'] ) ) : ''; // WPCS: sanitization ok, input var ok, CSRF ok.
if ( empty( $current_hash ) || $current_hash !== $location_hash ) {

View File

@ -985,7 +985,7 @@ class WC_Checkout {
$result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id );
if ( ! is_ajax() ) {
if ( ! wp_doing_ajax() ) {
// phpcs:ignore WordPress.Security.SafeRedirect.wp_redirect_wp_redirect
wp_redirect( $result['redirect'] );
exit;
@ -1006,7 +1006,7 @@ class WC_Checkout {
$order->payment_complete();
wc_empty_cart();
if ( ! is_ajax() ) {
if ( ! wp_doing_ajax() ) {
wp_safe_redirect(
apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $order->get_checkout_order_received_url(), $order )
);
@ -1106,7 +1106,7 @@ class WC_Checkout {
* If checkout failed during an AJAX call, send failure response.
*/
protected function send_ajax_failure_response() {
if ( is_ajax() ) {
if ( wp_doing_ajax() ) {
// Only print notices if not reloading the checkout, otherwise they're lost in the page reload.
if ( ! isset( WC()->session->reload_checkout ) ) {
$messages = wc_print_notices( true );

View File

@ -106,7 +106,7 @@ class WC_HTTPS {
return;
}
if ( ! wc_site_is_https() && is_ssl() && $_SERVER['REQUEST_URI'] && ! is_checkout() && ! is_ajax() && ! is_account_page() && apply_filters( 'woocommerce_unforce_ssl_checkout', true ) ) {
if ( ! wc_site_is_https() && is_ssl() && $_SERVER['REQUEST_URI'] && ! is_checkout() && ! wp_doing_ajax() && ! is_account_page() && apply_filters( 'woocommerce_unforce_ssl_checkout', true ) ) {
if ( 0 === strpos( $_SERVER['REQUEST_URI'], 'http' ) ) {
wp_safe_redirect( preg_replace( '|^https://|', 'http://', $_SERVER['REQUEST_URI'] ) );

View File

@ -168,7 +168,7 @@ class WC_Order_Item_Meta {
* @return array
*/
public function get_formatted_legacy( $hideprefix = '_' ) {
if ( ! is_ajax() ) {
if ( ! wp_doing_ajax() ) {
wc_deprecated_argument( 'WC_Order_Item_Meta::get_formatted', '2.4', 'Item Meta Data is being called with legacy arguments' );
}

View File

@ -256,18 +256,6 @@ if ( ! function_exists( 'is_lost_password_page' ) ) {
}
}
if ( ! function_exists( 'is_ajax' ) ) {
/**
* Is_ajax - Returns true when the page is loaded via ajax.
*
* @return bool
*/
function is_ajax() {
return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : Constants::is_defined( 'DOING_AJAX' );
}
}
if ( ! function_exists( 'is_store_notice_showing' ) ) {
/**

View File

@ -45,7 +45,7 @@ function wc_do_deprecated_action( $tag, $args, $version, $replacement = null, $m
*/
function wc_deprecated_function( $function, $version, $replacement = null ) {
// @codingStandardsIgnoreStart
if ( is_ajax() || WC()->is_rest_api_request() ) {
if ( wp_doing_ajax() || WC()->is_rest_api_request() ) {
do_action( 'deprecated_function_run', $function, $replacement, $version );
$log_string = "The {$function} function is deprecated since version {$version}.";
$log_string .= $replacement ? " Replace with {$replacement}." : '';
@ -67,7 +67,7 @@ function wc_deprecated_function( $function, $version, $replacement = null ) {
*/
function wc_deprecated_hook( $hook, $version, $replacement = null, $message = null ) {
// @codingStandardsIgnoreStart
if ( is_ajax() || WC()->is_rest_api_request() ) {
if ( wp_doing_ajax() || WC()->is_rest_api_request() ) {
do_action( 'deprecated_hook_run', $hook, $replacement, $version, $message );
$message = empty( $message ) ? '' : ' ' . $message;
@ -111,7 +111,7 @@ function wc_doing_it_wrong( $function, $message, $version ) {
// @codingStandardsIgnoreStart
$message .= ' Backtrace: ' . wp_debug_backtrace_summary();
if ( is_ajax() || WC()->is_rest_api_request() ) {
if ( wp_doing_ajax() || WC()->is_rest_api_request() ) {
do_action( 'doing_it_wrong_run', $function, $message, $version );
error_log( "{$function} was called incorrectly. {$message}. This message was added in version {$version}." );
} else {
@ -129,7 +129,7 @@ function wc_doing_it_wrong( $function, $message, $version ) {
* @param string $replacement
*/
function wc_deprecated_argument( $argument, $version, $message = null ) {
if ( is_ajax() || WC()->is_rest_api_request() ) {
if ( wp_doing_ajax() || WC()->is_rest_api_request() ) {
do_action( 'deprecated_argument_run', $argument, $message, $version );
error_log( "The {$argument} argument is deprecated since version {$version}. {$message}" );
} else {
@ -1123,3 +1123,17 @@ function get_woocommerce_term_meta( $term_id, $key, $single = true ) {
wc_deprecated_function( 'get_woocommerce_term_meta', '3.6', 'get_term_meta' );
return function_exists( 'get_term_meta' ) ? get_term_meta( $term_id, $key, $single ) : get_metadata( 'woocommerce_term', $term_id, $key, $single );
}
if ( ! function_exists( 'is_ajax' ) ) {
/**
* Is_ajax - Returns true when the page is loaded via ajax.
*
* @deprecated 6.1.0
* @return bool
*/
function is_ajax() {
wc_deprecated_function( 'is_ajax', '6.1.0', 'wp_doing_ajax' );
return function_exists( 'wp_doing_ajax' ) ? wp_doing_ajax() : Constants::is_defined( 'DOING_AJAX' );
}
}

View File

@ -520,7 +520,7 @@ add_action( 'woocommerce_product_set_stock_status', 'wc_recount_after_stock_chan
* @return array
*/
function wc_change_term_counts( $terms, $taxonomies ) {
if ( is_admin() || is_ajax() ) {
if ( is_admin() || wp_doing_ajax() ) {
return $terms;
}

View File

@ -17,7 +17,7 @@
defined( 'ABSPATH' ) || exit;
if ( ! is_ajax() ) {
if ( ! wp_doing_ajax() ) {
do_action( 'woocommerce_review_order_before_payment' );
}
?>
@ -56,6 +56,6 @@ if ( ! is_ajax() ) {
</div>
</div>
<?php
if ( ! is_ajax() ) {
if ( ! wp_doing_ajax() ) {
do_action( 'woocommerce_review_order_after_payment' );
}

View File

@ -246,4 +246,27 @@ class WC_Abstract_Order_Test extends WC_Unit_Test_Case {
$this->assertEquals( 0, ( new WC_Coupon( $coupon_code_2 ) )->get_usage_count() );
$this->assertEquals( 0, ( new WC_Coupon( $coupon_code_3 ) )->get_usage_count() );
}
/**
* Test apply_coupon() stores coupon meta data.
* See: https://github.com/woocommerce/woocommerce/issues/28166.
*/
public function test_apply_coupon_stores_meta_data() {
$coupon_code = 'coupon_test_meta_data';
$coupon = WC_Helper_Coupon::create_coupon( $coupon_code );
$order = WC_Helper_Order::create_order();
$order->set_status( 'processing' );
$order->save();
$order->apply_coupon( $coupon_code );
$coupon_items = $order->get_items( 'coupon' );
$this->assertCount( 1, $coupon_items );
$coupon_data = ( current( $coupon_items ) )->get_meta( 'coupon_data' );
$this->assertNotEmpty( $coupon_data, 'WC_Order_Item_Coupon missing `coupon_data` meta.' );
$this->assertArrayHasKey( 'id', $coupon_data );
$this->assertArrayHasKey( 'code', $coupon_data );
$this->assertEquals( $coupon->get_id(), $coupon_data['id'] );
$this->assertEquals( $coupon_code, $coupon_data['code'] );
}
}