Show products with images first - WooCommerce catalog ordering args

69 Views Asked by At

I'm attempting to create a custom sorting option on product category pages that will show products with images before products that don't have one.

In child theme functions.php

function custom_woocommerce_images_first_ordering_args( $args ) {
    $orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
    if ( 'images_first' == $orderby_value ) {
        $args['meta_key'] = '_thumbnail_id';
        $args['orderby'] = 'meta_value';
        $args['order'] = 'DESC';
    }
    return $args;
}
add_filter( 'woocommerce_get_catalog_ordering_args', 'custom_woocommerce_images_first_ordering_args' );

function custom_woocommerce_catalog_orderby_images_first( $sortby ) {
    $sortby['images_first'] = 'Default';
    return $sortby;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'custom_woocommerce_catalog_orderby_images_first' );
add_filter( 'woocommerce_catalog_orderby', 'custom_woocommerce_catalog_orderby_images_first' );

This seems to only show products with images. Not only that, if multiple products share the same image, it only show one of them.

I'm assuming this will have to be done with a meta query, something like:

$args['meta_query'] = array(  'relation' => 'OR', array(
            'orderby' => 'meta_value',
            'order' => 'DESC',
            'key' => '_thumbnail_id',
            'compare' => 'EXISTS',
            //  'value' => '0'       

            ),
            array(
                'orderby' => 'meta_value',
                'order' => 'DESC',
                'key' => '_thumbnail_id',
                'compare' => 'NOT EXISTS',
            )
        );

Removing other args and just adding the meta query doesn't work either. As soon as

$args['meta_key'] = '_thumbnail_id';

is added, the products without images are removed.

1

There are 1 best solutions below

0
Seb G On

I got this working entirely thanks to this post.

Here is the working code for my example:

function custom_woocommerce_images_first_ordering_args( $q ) {
    $orderby_value = isset( $_GET['orderby'] ) ? wc_clean( $_GET['orderby'] ) : apply_filters( 'woocommerce_default_catalog_orderby', get_option( 'woocommerce_default_catalog_orderby' ) );
    if ( 'images_first' == $orderby_value ) {
        $q->get( 'meta_key', '_thumbnail_id' );
        $q->set('orderby', 'meta_value');
        $q->set('order', 'DESC');
        $q->set( 'meta_query', array(  'relation' => 'OR', array(

            'orderby' => 'meta_value',
            'order' => 'DESC',
            'key' => '_thumbnail_id',
            'compare' => 'NOT EXISTS',
            //  'value' => '0'       

            ),
            array(
                'key' => '_thumbnail_id',
                'compare' => '>=',
                'value' => '0',       
                'orderby' => 'meta_value',
                'order' => 'DESC'
            )),
        ); 
    }
    return $q;
}
add_filter( 'woocommerce_product_query', 'custom_woocommerce_images_first_ordering_args' );

function custom_woocommerce_catalog_orderby_images_first( $sortby ) {
    $sortby['images_first'] = 'Default';
    return $sortby;
}
add_filter( 'woocommerce_default_catalog_orderby_options', 'custom_woocommerce_catalog_orderby_images_first' );
add_filter( 'woocommerce_catalog_orderby', 'custom_woocommerce_catalog_orderby_images_first' );