0

I have a custom field (advanced custom field) called custom_order and I want WordPress to sort all posts by the field values.

The custom_order field's values can be written in 3 ways:

  • numbers only (3, 400, 6424)
  • numbers, then strings (3A, 3B, 5000A)
  • numbers, then strings, then numbers (3A1, 3A2, 401AZ1, 9000A3, 9000A1)

More examples of custom_order values:

Wanted order:

1, 2, 3, 3A, 3B, 3C, 3CA, 4, 400, 401, 401A, 401AZ, 401Z, 9000, 9000A, 9000A1, 9000A3

Conditions:

  • 3 should come before 200 (numeric order)
  • 3 should come before 3A (number and strings)
  • 3A should come before 3A1 (numbers, strings, numbers)

My try:

My current code is sorting by numbers (condition 1), but ignores condition 2 and condition 3.

Therefore, my code gives me this order:

1, 2, 3A, 3, 3C, 3B, 4 <-- all 3's are not ordered, which is bad

The code I'm using (in functions.php):

add_action('pre_get_posts', function ($q) {
    if (
        !is_admin() // Target only front end queries
        && $q->is_main_query() // Target the main query only
        && ($q->is_search() || $q->is_post_type_archive('data-base'))
    ) {
        $q->set('meta_key', 'custom_order');
        $q->set('order',    'DESC');
        $q->set('orderby',  'meta_value_num');
    }
});
Elron
  • 1,235
  • 1
  • 13
  • 26
  • If you start by imagining how you would write a MySQL query that follows those rules, it becomes apparent pretty quickly that while it's possible, it would be difficult to do, and is not likely to be something that WordPress has built into it. It would be cool if you could provide a sort function to the query object, but there's nothing like that in the docs. I think you are going to have to sort your results after the query is run. – Jerry May 13 '20 at 23:37
  • Hey Jerry, Thanks, I do believe that is possible through MySQL but my knowledge is limited in that area. I found a neat solution that is built into WordPress, see my answer below. – Elron May 13 '20 at 23:41
  • 1
    Maybe this hook? https://developer.wordpress.org/reference/hooks/posts_results/ – Jerry May 13 '20 at 23:44
  • I think it will be problematic on search results where there is pagination involved (because it will force to fetch all posts and that's a heavy task), however, this is a very cool hook! Thanks for sharing – Elron May 13 '20 at 23:47

1 Answers1

0

I found a neat solution!

$q->set(
    'meta_query',
    array(
        'relation' => 'OR', //**** Use AND or OR as per your required Where Clause
        'clause1' => array(
            'key'     => 'custom_order',
            'compare' => 'EXISTS',
        ),
    )
);
$q->set(
    'orderby',
    array(
        'meta_value_num'  => 'ASC', // this reorders by numbers
        'meta_value'  => 'ASC', // this reorders by strings after sorting numbers
    )
);
Elron
  • 1,235
  • 1
  • 13
  • 26
  • I will test what you're saying right now and tell you my result, hold on – Elron May 13 '20 at 23:49
  • 1
    You could always pad the second number with a sufficient number of lead zeroes, so it's 1A022 and 1A003 – Jerry May 13 '20 at 23:50
  • You are right. This is not the best solution, but what you suggested with padding the second number did the trick! Awesome. – Elron May 13 '20 at 23:51
  • Or you could split the custom_order field into three, and order on them sequentially. – Jerry May 13 '20 at 23:55
  • I have actually tried this before but run into problems where it sorted the fields by string and not numbers, resulting "8" to come after "41". here's my post on that: https://stackoverflow.com/questions/61708882/wordpress-order-posts-by-2-custom-fields-at-once/61708941?noredirect=1#comment109216252_61708941 – Elron May 13 '20 at 23:56