Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Show cross-sells before same category on related products in WooCommerce

I'm writing some code to modify the related products section as follows:

  • If a product has cross sell products, show those first, and fill up to 4 total products with others from the same category*

Or

  • If a product has no cross sell products, show 4 products from the same category*

Here's my function to filter the related products so far:

add_filter( 'woocommerce_related_products', 'fivem_add_linked_to_related_products', 9999, 3 );
function fivem_add_linked_to_related_products( $related_posts, $product_id, $args ) {

    $product = wc_get_product( $product_id );
    $cross_sell_ids = $product->get_cross_sell_ids();
    $product_categories = $product->get_category_ids();

    // Get cross sell products
    $cross_sell_products = get_posts( array(
        'post_type' => 'product',
        'post_status' => 'publish',
        'fields' => 'ids',
        'post__in' => $cross_sell_ids,
        'posts_per_page' => 4,
        'exclude' => array( $product_id ),
    ));

    // Calculate how many filler products are needed
    $category_product_count = 4 - count( $cross_sell_products );

    // Exclude main product and cross sell products
    $excluded_products = array_push( $cross_sell_ids, $product_id );

    // Get filler products from same category
    $category_products = get_posts( array(
        'post_type' => 'product',
        'post_status' => 'publish',
        'orderby' => 'rand',
        'fields' => 'ids',
        'post__not_in' => $excluded_products,
        'posts_per_page' => $category_product_count,
        'tax_query' => array(
            array(
                'taxonomy' => 'product_cat',
                'field' => 'id',
                'terms' => $product_categories,
                'operator' => 'IN',
            )
        )
    ));

    // Merge cross sell products with filler products
    $related_products = array_merge( $cross_sell_products, $category_products );

    // Return related products
    return $related_products;

}

Currently, the above code mostly works.

  • If cross-sells are set, it only displays those cross-sell products- ie. does not fill out to 4 total
  • If no cross-sells are set, it displays products from the same category as expected.

There are two problems I'm trying to solve:

  1. Code above doesn't fill with category products. If I remove the post__not_in and tax_query arguments, it fills out, but obviously not with products from the same category.
  2. I want to show cross-sell products first, then the category-related products. There appears to be another randomization somewhere that mixes the order up, and I can't work out where that comes from.

Any ideas how I can fix this? Thanks in advance.

like image 405
warm__tape Avatar asked Jun 09 '20 23:06

warm__tape


People also ask

How do I rearrange the order of products in WooCommerce?

Click 'Sorting' and then drag and drop products to reorder them according to your custom requirement. You can click sorting and then simply drag and drop to rearrange the order of your products.

Where are cross sell products displayed?

Cross-sells are displayed at the bottom of the checkout page. For example, when your customer is buying a CPU, they might need a monitor and something else.


1 Answers

Code contains

  • If a product has cross sell products, show those first, and fill up to 4 total products with others from the same category
  • If a product has no cross sell products, show 4 products from the same category
function filter_woocommerce_related_products( $related_posts, $product_id, $args ) {    
    // Taxonomy
    $taxonomy = 'product_cat';

    // Show products
    $show_products = 4;

    // Get product
    $product = wc_get_product( $product_id );

    // Get cross sell IDs
    $cross_sell_ids = $product->get_cross_sell_ids();

    // Calculate how many filler products are needed
    $category_product_needed_count = $show_products - count( $cross_sell_ids );

    // If category product needed 
    if ( $category_product_needed_count >= 1 ) {
        // Retrieves product term ids for a taxonomy.
        $product_cats_ids = wc_get_product_term_ids( $product_id, $taxonomy );

        // Get product id(s) from a certain category, by category-id
        $product_ids_from_cats_ids = get_posts( array(
            'post_type'   => 'product',
            'numberposts' => $category_product_needed_count,
            'post_status' => 'publish',
            'fields'      => 'ids',
            'tax_query'   => array(
                array(
                    'taxonomy' => $taxonomy,
                    'field'    => 'id',
                    'terms'    => $product_cats_ids,
                    'operator' => 'IN',
                )
            ),
        )); 

        // Merge array
        $related_posts = array_merge( $cross_sell_ids, $product_ids_from_cats_ids );
    } else {
        // Slice array until show products
        $related_posts = array_slice( $cross_sell_ids, 0, $show_products );
    }   

    // Return
    return $related_posts;

}
add_filter( 'woocommerce_related_products', 'filter_woocommerce_related_products', 10, 3 );

// Order by
function filter_woocommerce_output_related_products_args( $args ) { 
    $args['orderby'] = 'id';
    $args['order'] = 'ASC';

    return $args;
}
add_filter( 'woocommerce_output_related_products_args', 'filter_woocommerce_output_related_products_args', 10, 1 );
like image 168
7uc1f3r Avatar answered Oct 17 '22 20:10

7uc1f3r