the most clicked item should be first and the items that haven’t been clicked yet should be last, but they are not showing up at all
They aren’t showing up because your posts query is only selecting posts that have the number_clicks meta, and thus MySQL ignores all posts which do not have that meta.
So what you need is two meta query clauses with an OR relation — the 1st clause will select posts that have the number_clicks meta, whereas the 2nd clause will select posts without that meta.
And for that, you can instead use the meta_query arg, so in your code, just replace the $query->set('meta_key', 'number_clicks' ); with:
$query->set( 'meta_query', array(
'relation' => 'OR',
'number_clicks' => array( // 1st clause
'key' => 'number_clicks',
),
'number_clicks2' => array( // 2nd clause
'key' => 'number_clicks',
'compare' => 'NOT EXISTS',
'type' => 'NUMERIC',
),
) );
Then to sort the results by the number_clicks value, set the orderby to the array key (number_clicks2) for the 2nd clause above, i.e. $query->set( 'orderby', 'number_clicks2' ).
And note that the 2nd clause above uses NUMERIC as the type so that MySQL will convert the meta value to a number which then gives us the correct numerical sorting.
-
Remember that meta values are stored as strings/text in the database, hence for example (these individual values — )
10, 4, 1, 3, 2will be sorted into1, 10, 2, 3, 4instead of1, 2, 3, 4, 10. Because that’s what happen when the values are sorted as strings. -
So actually, you should’ve used
$query->set( 'orderby', 'meta_value_num' )so that the meta value is converted to a number prior to sorting. But now you no longer need to use that because the meta value type is already set in the 2nd clause above.