2019-04-12 15:47:29 +00:00
|
|
|
/**
|
|
|
|
* External dependencies
|
|
|
|
*/
|
|
|
|
import { addQueryArgs } from '@wordpress/url';
|
|
|
|
import apiFetch from '@wordpress/api-fetch';
|
2021-04-22 11:37:27 +00:00
|
|
|
import { getSetting } from '@woocommerce/settings';
|
|
|
|
import { blocksConfig } from '@woocommerce/block-settings';
|
2019-04-12 15:47:29 +00:00
|
|
|
|
2019-12-10 17:17:46 +00:00
|
|
|
/**
|
2020-04-24 13:36:47 +00:00
|
|
|
* Get product query requests for the Store API.
|
2019-12-10 17:17:46 +00:00
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {Object} request A query object with the list of selected products and search term.
|
|
|
|
* @param {number[]} request.selected Currently selected products.
|
|
|
|
* @param {string=} request.search Search string.
|
2021-08-06 13:25:12 +00:00
|
|
|
* @param {(Record<string, unknown>)=} request.queryArgs Query args to pass in.
|
2019-12-10 17:17:46 +00:00
|
|
|
*/
|
2019-09-05 15:09:31 +00:00
|
|
|
const getProductsRequests = ( {
|
|
|
|
selected = [],
|
|
|
|
search = '',
|
2021-08-06 13:25:12 +00:00
|
|
|
queryArgs = {},
|
2019-09-05 15:09:31 +00:00
|
|
|
} ) => {
|
2021-04-22 11:37:27 +00:00
|
|
|
const isLargeCatalog = blocksConfig.productCount > 100;
|
2019-08-15 14:55:57 +00:00
|
|
|
const defaultArgs = {
|
2021-04-22 11:37:27 +00:00
|
|
|
per_page: isLargeCatalog ? 100 : 0,
|
2019-08-15 14:55:57 +00:00
|
|
|
catalog_visibility: 'any',
|
|
|
|
search,
|
|
|
|
orderby: 'title',
|
|
|
|
order: 'asc',
|
|
|
|
};
|
2019-04-12 15:47:29 +00:00
|
|
|
const requests = [
|
2022-02-23 12:00:45 +00:00
|
|
|
addQueryArgs( '/wc/store/v1/products', {
|
|
|
|
...defaultArgs,
|
|
|
|
...queryArgs,
|
|
|
|
} ),
|
2019-04-12 15:47:29 +00:00
|
|
|
];
|
|
|
|
|
|
|
|
// If we have a large catalog, we might not get all selected products in the first page.
|
2021-04-22 11:37:27 +00:00
|
|
|
if ( isLargeCatalog && selected.length ) {
|
2019-04-12 15:47:29 +00:00
|
|
|
requests.push(
|
2022-02-23 12:00:45 +00:00
|
|
|
addQueryArgs( '/wc/store/v1/products', {
|
2019-08-12 11:54:51 +00:00
|
|
|
catalog_visibility: 'any',
|
2019-04-12 15:47:29 +00:00
|
|
|
include: selected,
|
2021-08-06 13:25:12 +00:00
|
|
|
per_page: 0,
|
2019-04-12 15:47:29 +00:00
|
|
|
} )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return requests;
|
|
|
|
};
|
|
|
|
|
2023-04-28 10:29:45 +00:00
|
|
|
const uniqBy = ( array, iteratee ) => {
|
|
|
|
const seen = new Map();
|
|
|
|
return array.filter( ( item ) => {
|
|
|
|
const key = iteratee( item );
|
|
|
|
if ( ! seen.has( key ) ) {
|
|
|
|
seen.set( key, item );
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2019-04-12 15:47:29 +00:00
|
|
|
/**
|
2020-04-24 13:36:47 +00:00
|
|
|
* Get a promise that resolves to a list of products from the Store API.
|
2019-04-12 15:47:29 +00:00
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {Object} request A query object with the list of selected products and search term.
|
|
|
|
* @param {number[]} request.selected Currently selected products.
|
|
|
|
* @param {string=} request.search Search string.
|
2021-08-06 13:25:12 +00:00
|
|
|
* @param {(Record<string, unknown>)=} request.queryArgs Query args to pass in.
|
|
|
|
* @return {Promise<unknown>} Promise resolving to a Product list.
|
|
|
|
* @throws Exception if there is an error.
|
2019-04-12 15:47:29 +00:00
|
|
|
*/
|
2019-09-05 15:09:31 +00:00
|
|
|
export const getProducts = ( {
|
|
|
|
selected = [],
|
|
|
|
search = '',
|
2021-08-06 13:25:12 +00:00
|
|
|
queryArgs = {},
|
2019-09-05 15:09:31 +00:00
|
|
|
} ) => {
|
2019-08-15 14:55:57 +00:00
|
|
|
const requests = getProductsRequests( { selected, search, queryArgs } );
|
2019-04-12 15:47:29 +00:00
|
|
|
|
2019-08-30 09:36:06 +00:00
|
|
|
return Promise.all( requests.map( ( path ) => apiFetch( { path } ) ) )
|
2019-09-25 14:22:36 +00:00
|
|
|
.then( ( data ) => {
|
2023-04-28 10:29:45 +00:00
|
|
|
const flatData = data.flat();
|
|
|
|
const products = uniqBy( flatData, ( item ) => item.id );
|
2019-09-25 14:22:36 +00:00
|
|
|
const list = products.map( ( product ) => ( {
|
|
|
|
...product,
|
|
|
|
parent: 0,
|
|
|
|
} ) );
|
|
|
|
return list;
|
|
|
|
} )
|
2019-08-30 09:36:06 +00:00
|
|
|
.catch( ( e ) => {
|
|
|
|
throw e;
|
|
|
|
} );
|
2019-04-12 15:47:29 +00:00
|
|
|
};
|
2019-07-09 13:42:22 +00:00
|
|
|
|
2019-08-02 11:56:53 +00:00
|
|
|
/**
|
2020-04-24 13:36:47 +00:00
|
|
|
* Get a promise that resolves to a product object from the Store API.
|
2019-08-02 11:56:53 +00:00
|
|
|
*
|
2019-08-15 09:36:24 +00:00
|
|
|
* @param {number} productId Id of the product to retrieve.
|
2019-08-02 11:56:53 +00:00
|
|
|
*/
|
|
|
|
export const getProduct = ( productId ) => {
|
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `/wc/store/v1/products/${ productId }`,
|
2019-08-02 11:56:53 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2020-04-24 13:36:47 +00:00
|
|
|
/**
|
|
|
|
* Get a promise that resolves to a list of attribute objects from the Store API.
|
|
|
|
*/
|
|
|
|
export const getAttributes = () => {
|
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `wc/store/v1/products/attributes`,
|
2020-04-24 13:36:47 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get a promise that resolves to a list of attribute term objects from the Store API.
|
|
|
|
*
|
|
|
|
* @param {number} attribute Id of the attribute to retrieve terms for.
|
|
|
|
*/
|
|
|
|
export const getTerms = ( attribute ) => {
|
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `wc/store/v1/products/attributes/${ attribute }/terms`,
|
2020-04-24 13:36:47 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get product tag query requests for the Store API.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {Object} request A query object with the list of selected products and search term.
|
|
|
|
* @param {Array} request.selected Currently selected tags.
|
|
|
|
* @param {string} request.search Search string.
|
2020-04-24 13:36:47 +00:00
|
|
|
*/
|
2019-07-09 13:42:22 +00:00
|
|
|
const getProductTagsRequests = ( { selected = [], search } ) => {
|
2021-04-22 11:37:27 +00:00
|
|
|
const limitTags = getSetting( 'limitTags', false );
|
2019-07-09 13:42:22 +00:00
|
|
|
const requests = [
|
2022-02-23 12:00:45 +00:00
|
|
|
addQueryArgs( `wc/store/v1/products/tags`, {
|
2021-04-22 11:37:27 +00:00
|
|
|
per_page: limitTags ? 100 : 0,
|
|
|
|
orderby: limitTags ? 'count' : 'name',
|
|
|
|
order: limitTags ? 'desc' : 'asc',
|
2019-07-09 13:42:22 +00:00
|
|
|
search,
|
|
|
|
} ),
|
|
|
|
];
|
|
|
|
|
|
|
|
// If we have a large catalog, we might not get all selected products in the first page.
|
2021-04-22 11:37:27 +00:00
|
|
|
if ( limitTags && selected.length ) {
|
2019-07-09 13:42:22 +00:00
|
|
|
requests.push(
|
2022-02-23 12:00:45 +00:00
|
|
|
addQueryArgs( `wc/store/v1/products/tags`, {
|
2019-07-09 13:42:22 +00:00
|
|
|
include: selected,
|
|
|
|
} )
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
return requests;
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2020-04-24 13:36:47 +00:00
|
|
|
* Get a promise that resolves to a list of tags from the Store API.
|
2019-07-09 13:42:22 +00:00
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {Object} props A query object with the list of selected products and search term.
|
|
|
|
* @param {Array} props.selected
|
2020-09-20 23:54:08 +00:00
|
|
|
* @param {string} props.search
|
2019-07-09 13:42:22 +00:00
|
|
|
*/
|
|
|
|
export const getProductTags = ( { selected = [], search } ) => {
|
|
|
|
const requests = getProductTagsRequests( { selected, search } );
|
|
|
|
|
2019-09-05 15:09:31 +00:00
|
|
|
return Promise.all( requests.map( ( path ) => apiFetch( { path } ) ) ).then(
|
|
|
|
( data ) => {
|
2023-04-28 10:29:45 +00:00
|
|
|
const flatData = data.flat();
|
|
|
|
return uniqBy( flatData, ( item ) => item.id );
|
2019-09-05 15:09:31 +00:00
|
|
|
}
|
|
|
|
);
|
2019-07-09 13:42:22 +00:00
|
|
|
};
|
2019-08-15 09:36:24 +00:00
|
|
|
|
|
|
|
/**
|
2020-04-24 13:36:47 +00:00
|
|
|
* Get a promise that resolves to a list of category objects from the Store API.
|
2019-12-10 17:17:46 +00:00
|
|
|
*
|
|
|
|
* @param {Object} queryArgs Query args to pass in.
|
2019-09-04 16:07:00 +00:00
|
|
|
*/
|
2019-11-19 15:22:16 +00:00
|
|
|
export const getCategories = ( queryArgs ) => {
|
2019-09-04 16:07:00 +00:00
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: addQueryArgs( `wc/store/v1/products/categories`, {
|
2020-04-24 13:36:47 +00:00
|
|
|
per_page: 0,
|
2019-11-19 15:22:16 +00:00
|
|
|
...queryArgs,
|
2019-09-05 15:09:31 +00:00
|
|
|
} ),
|
2019-09-04 16:07:00 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2020-04-24 13:36:47 +00:00
|
|
|
/**
|
|
|
|
* Get a promise that resolves to a category object from the API.
|
|
|
|
*
|
|
|
|
* @param {number} categoryId Id of the product to retrieve.
|
|
|
|
*/
|
|
|
|
export const getCategory = ( categoryId ) => {
|
2019-09-25 14:22:36 +00:00
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: `wc/store/v1/products/categories/${ categoryId }`,
|
2019-09-25 14:22:36 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2020-04-24 13:36:47 +00:00
|
|
|
/**
|
|
|
|
* Get a promise that resolves to a list of variation objects from the Store API.
|
|
|
|
*
|
|
|
|
* @param {number} product Product ID.
|
|
|
|
*/
|
|
|
|
export const getProductVariations = ( product ) => {
|
2019-09-04 16:07:00 +00:00
|
|
|
return apiFetch( {
|
2022-02-23 12:00:45 +00:00
|
|
|
path: addQueryArgs( `wc/store/v1/products`, {
|
2020-04-24 13:36:47 +00:00
|
|
|
per_page: 0,
|
|
|
|
type: 'variation',
|
|
|
|
parent: product,
|
2019-09-05 15:09:31 +00:00
|
|
|
} ),
|
2019-09-04 16:07:00 +00:00
|
|
|
} );
|
|
|
|
};
|
|
|
|
|
2020-04-22 16:44:12 +00:00
|
|
|
/**
|
|
|
|
* Given a page object and an array of page, format the title.
|
|
|
|
*
|
2022-04-08 13:47:19 +00:00
|
|
|
* @param {Object} page Page object.
|
|
|
|
* @param {Object} page.title Page title object.
|
|
|
|
* @param {string} page.title.raw Page title.
|
|
|
|
* @param {string} page.slug Page slug.
|
|
|
|
* @param {Array} pages Array of all pages.
|
2020-04-22 16:44:12 +00:00
|
|
|
* @return {string} Formatted page title to display.
|
|
|
|
*/
|
|
|
|
export const formatTitle = ( page, pages ) => {
|
|
|
|
if ( ! page.title.raw ) {
|
|
|
|
return page.slug;
|
|
|
|
}
|
|
|
|
const isUnique =
|
|
|
|
pages.filter( ( p ) => p.title.raw === page.title.raw ).length === 1;
|
|
|
|
return page.title.raw + ( ! isUnique ? ` - ${ page.slug }` : '' );
|
|
|
|
};
|