Pregunta

My products have no in-stock status, just a quantity in stock. Is there any way to make meta query to treat its value as 0 or 1? Like, first the values that are not 0, then that are 0.

My query as it is right now:

'meta_query' => array(
   'relation' => 'AND',
   'quantity_total' => array(
            'key'     => 'total_quantity',
            'type'    => 'NUMERIC',
            'compare' => 'EXISTS',
   ),
   'price_lowest_first' => array(
            'key'     => 'main_price',
            'type'    => 'NUMERIC',
            'compare' => 'EXISTS',
    )
),
'orderby' => array(
   'quantity_total' => 'DESC',
   'price_lowest_first' => 'ASC'
)

EDIT:

For now, I ended up using an 'in-stock' flag, and here's my code:

//sort by total quantity
if($sort !== '4'){      
    $args['meta_query']['in_stock'] = array(
            'key' => '1C_in_stock',
           'type' => 'NUMERIC',
        'compare' => 'EXISTS'
    );
    $args['orderby']  = array( 
        'in_stock' => 'DESC'
    );
}

//apply sort preferences to arguments
switch($sort){
    #by stock status
    case '1':
        // '1' is default, do not want to move it to the default clause yet.
        break;

   #sort by price: lower first
    case '2':
        $args['meta_query']['price_lowest_first'] = array(
                'key' => '1C_price'
               'type' => 'NUMERIC',
            'compare' => 'EXISTS'
        );  
        $args['orderby']['price_lowest_first']  = 'ASC';
        break;

    #sort by price:higher first
    case '3':
        $args['meta_query']['price_highest_first'] = array(
            'key' => '1C_price',
            'type'    => 'NUMERIC',
            'compare' => 'EXISTS',
        );
        $args['orderby']['price_highest_first']  = 'DESC';
        break;

    #sort randomly
    case '4':
        $args['orderby'] = 'rand';
        break;
}

But is there a query to order items by non-zero and zero quantity? And then, order each group by price.

¿Fue útil?

Solución

If I understand it correctly..

What you're looking for can be achieved using the CASE statement in MySQL, where you would use the following in the ORDER BY clause:

# group the quantity meta into two groups
CASE
    # group one - all quantities that are 1 or more; we flag them as "1"
    WHEN wp_postmeta.meta_value+0 > 0 THEN 1

    # group two - all quantities that are 0 or less; we flag them as "2"
    WHEN wp_postmeta.meta_value+0 <= 0 THEN 2
END ASC

Where wp_postmeta.meta_value is the value of the total_quantity meta which is the first one in your meta query, and the +0 means we're casting the meta value as a number.

And to add that CASE statement to the ORDER BY clause, you can use the posts_orderby hook. Here's an example using closure with a private variable:

// *Private variable used with the closure below.
$_do_filter = true;

add_filter( 'posts_orderby',
    function ( $orderby ) use ( &$_do_filter ) {
        if ( $_do_filter ) {
            $orderby = "CASE\n" .
                "  WHEN wp_postmeta.meta_value+0 > 0 THEN 1\n" .
                "  WHEN wp_postmeta.meta_value+0 <= 0 THEN 2\n" .
            "END ASC, $orderby";
        }

        return $orderby;
    }
);

$query = new WP_Query( array(
    'meta_query' => array(
        'relation'          => 'AND',
        'quantity_total'    => array(
            'key'     => 'total_quantity',
            'type'    => 'NUMERIC',
            'compare' => 'EXISTS',
        ),
        'price_lowest_first' => array(
            'key'     => 'main_price',
            'type'    => 'DECIMAL(5, 2)',
            'compare' => 'EXISTS',
        ),
    ),
    'orderby'    => array(
        // we already have the CASE statement, so this is no longer needed
//      'quantity_total'     => 'DESC',
        'price_lowest_first' => 'ASC',
    ),
    // ... your other args.
) );

// Disable the filter.
$_do_filter = false;

// Then run your loop here..
// while ( $query->have_posts() ) ...

And note that for the main_price meta, I set the type to DECIMAL(5, 2) so that the prices would be sorted by taking into account the decimal.

Licenciado bajo: CC-BY-SA con atribución
scroll top