Show random WooCommerce products from other categories as related products if only one product in a category

By default WooCommerce adds below a single product details page related products that have the same categories and/or tags.

These products are not controlled by the shop manager – WooCommerce automatically lists random related products in this area. If there is only one product in a category nothing shows up.

Any idea how to modify the arguments array of the woocommerce_output_related_products to check if there is only one product in the current category and then show products from other categories as "related" ones?

Sample code to modify the arguments below:

function woocommerce_output_related_products(){
        $args = array( 
            'posts_per_page' => 3,  
            'columns' => 3,  
            'orderby' => 'rand'     
     ); 
        woocommerce_related_products( apply_filters( 'woocommerce_output_related_products_args', $args ) ); 
}

Solution 1:

You won't be able to change this via the $args, but you can via the woocommerce_related_products hook.

It comes down to if an empty array would be displayed (so no result) we will fill the empty array with the results we chose.

Initially we obtain all categoryIDs and based on that all productIDs (except the exluded productIDs) that belong to the categoryIDs.

Then we return the number of desired results via $show_products

So you get:

function filter_woocommerce_related_products( $related_posts, $product_id, $args ) {
    // Show products
    $show_products = 4;
    
    // Initialize
    $taxonomy = 'product_cat';
    
    // When empty
    if ( empty( $related_posts ) ) {
        // Get WooCommerce product categories WP_Term objects
        $product_cats_ids = get_terms( array(
            'taxonomy'  => $taxonomy,
            'fields'    => 'ids',
        ) );
        
        // Get product id(s) from a certain category, by category-id
        $product_ids_from_cats_ids = get_posts( array(
            'post_type'   => 'product',
            'numberposts' => $show_products + count( $args['excluded_ids'] ),
            'post_status' => 'publish',
            'fields'      => 'ids',
            'tax_query'   => array(
                array(
                    'taxonomy' => $taxonomy,
                    'field'    => 'id',
                    'terms'    => $product_cats_ids,
                    'operator' => 'IN',
                )
            ),
            'orderby'     => 'rand',
            'exclude'     => $args['excluded_ids'],
        ));

        // Extract a slice of the array
        $related_posts = array_slice( $product_ids_from_cats_ids, 0, $show_products );
    }

    // Return
    return $related_posts;
}
add_filter( 'woocommerce_related_products', 'filter_woocommerce_related_products', 10, 3 );

Related/based on: Show cross-sells before same category on related products in WooCommerce