[Product Block Editor]: fallback with random products when no related products (#43584)

* add fallbackToRandomProducts option to getRelatedProducts()

* fallback to random when there isn't related products

* changelog

* update and tweak doc

* introduce POSTS_NUMBER_TO_PICK const
This commit is contained in:
Damián Suárez 2024-01-16 09:13:55 -03:00 committed by GitHub
parent c776fb63bc
commit 68fa0dd338
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 99 additions and 11 deletions

View File

@ -0,0 +1,4 @@
Significance: patch
Type: update
[Product Block Editor]: fallback with random products when there isn't related products in the Linked Products tab

View File

@ -133,9 +133,9 @@ export function LinkedProductListBlockEdit( {
},
} );
const relatedProducts = ( await getRelatedProducts(
productId
) ) as Product[];
const relatedProducts = ( await getRelatedProducts( productId, {
fallbackToRandomProducts: true,
} ) ) as Product[];
dispatch( {
type: 'LOADING_LINKED_PRODUCTS',

View File

@ -0,0 +1,38 @@
# Get Related Products
Helper function to retrieve related products for a given product.
## Usage
`getRelatedProducts` is an asynchronous function that returns related products for a specified product ID.
If no related products are found, and the `fallbackToRandomProducts` flag is set to `true`, it returns a random set of products.
### Syntax
```es6
getRelatedProducts( productId, options )
```
#### Parameters
- `productId` (number): The ID of the product for which related products are to be fetched.
- `options` (Object): An object containing the following property:
+ `fallbackToRandomProducts` (boolean): Optional. If set to `true`, the function will return random products if no related products are found. Default is `false`.
#### Return
- Promise<Product[] | undefined>: A promise that resolves to an array of related products or `undefined` if none are found and `fallbackToRandomProducts` is `false`.
### Example
```javascript
import getRelatedProducts from './path-to-getRelatedProducts';
getRelatedProducts( 123, { fallbackToRandomProducts: true } )
.then( relatedProducts => {
console.log( relatedProducts );
} )
.catch( error => {
console.error( 'Error fetching related products:', error );
} );
```

View File

@ -4,20 +4,66 @@
import { select, resolveSelect } from '@wordpress/data';
import type { Product } from '@woocommerce/data';
export default async function getRelatedProducts( productId: number ) {
type getRelatedProductsOptions = {
// If true, return random products if no related products are found.
fallbackToRandomProducts?: boolean;
};
const POSTS_NUMBER_TO_RANDOMIZE = 30;
const POSTS_NUMBER_TO_PICK = 5;
/**
* Return related products for a given product ID.
* If fallbackToRandomProducts is true,
* return random products if no related products are found.
*
* @param {number} productId - Product ID.
* @param {getRelatedProductsOptions} options - Options.
* @return {Promise<Product[] | undefined>} Related products.
*/
export default async function getRelatedProducts(
productId: number,
options: getRelatedProductsOptions = {}
): Promise< Product[] | undefined > {
const { getEntityRecord } = select( 'core' );
const product = getEntityRecord( 'postType', 'product', productId );
if ( ! product ) {
return;
}
const relatedProductIds = product?.related_ids;
if ( ! relatedProductIds ) {
return;
let relatedProductIds = product?.related_ids;
if ( ! relatedProductIds?.length ) {
if ( ! options?.fallbackToRandomProducts ) {
return;
}
// Pick the last `POSTS_NUMBER_TO_RANDOMIZE` posts
const lastPost = ( await resolveSelect( 'core' ).getEntityRecords(
'postType',
'product',
{
_fields: [ 'id' ],
per_page: POSTS_NUMBER_TO_RANDOMIZE,
}
) ) as Product[];
if ( ! lastPost?.length ) {
return;
}
const lastPostIds = lastPost.map( ( post ) => post.id );
// Pick POSTS_NUMBER_TO_PICK random post IDs
relatedProductIds = lastPostIds
.sort( () => Math.random() - 0.5 )
.slice( 0, POSTS_NUMBER_TO_PICK );
}
const { getEntityRecords } = resolveSelect( 'core' );
return ( await getEntityRecords( 'postType', 'product', {
include: relatedProductIds,
} ) ) as Product[];
return ( await resolveSelect( 'core' ).getEntityRecords(
'postType',
'product',
{
include: relatedProductIds,
}
) ) as Product[];
}