4

I can use WP_Query to order posts matching my query by menu_order.

But can I also specifically find posts that have a particular menu_order?

Even better, can I find posts with a menu_order larger than a particular number? Or smaller than a particular number?

If so, how?

Note: I can, of course, loop through posts that match my query and find the post I'm looking for in code, but it would be nicer if I can get the result directly from WP_Query.

0

1 Answer 1

5

Matching by menu_order is easy, like this:

$args = array(
   // find posts with menu_order 4 
   'menu_order' => 4,
   'orderby' => 'menu_order',
   'order' => 'ASC',
   'posts_per_page' => 10,
);
$query = new WP_Query( $args );

However, larger or smaller option for menu_order is not provided by default in WP_Query.

You can still filter the where clause to achieve that. Something like this:

$args = array(
   'orderby' => 'menu_order',
   'order' => 'ASC',
   'posts_per_page' => 10,
);

add_filter( 'posts_where', 'wpse_menu_order_filter', 10, 2 );
function wpse_menu_order_filter( $where, $query ) {
    // remove this filter to avoid changing other queries.
    remove_filter( 'posts_where', 'wpse_menu_order_filter' );

    // custom where clause to show only posts with menu_order greater than 4
    return $where . ' AND wp_posts.menu_order > 4 ';
}
$query = new WP_Query( $args );

You can do the same thing for smaller check as well.

More advanced solution:

You can also enhance the menu_order argument so that the greater or lesser sign and the compare value is not hard coded within the filter function. Like this:

$args = array( 
   'post_type' => 'page',
   'menu_order' => array(
        'value' => 5,
        'compare' => '<='
    ),
   'orderby' => 'menu_order',
   'order' => 'ASC',
   'posts_per_page' => 10,
);
add_filter( 'posts_where', 'wpse_menu_order_filter', 10, 2 );

function wpse_menu_order_filter( $where, $wp_query ) {

    remove_filter( 'posts_where', 'wpse_menu_order_filter' );

    $args = $wp_query->query;

    if( isset( $args['menu_order'] ) && is_array( $args['menu_order'] ) ) {

        $menu_order = $args['menu_order'];

        if( isset( $menu_order['value'] )
            && isset( $menu_order['compare'] ) ) {
        
            $compare = $menu_order['compare'];

            // allow only four comparisons: '>', '>=', '<', '<='   
            if( in_array( $compare, array( '>', '>=', '<', '<=' ) ) ) {

                $value = $menu_order['value'];

                if( is_scalar( $value ) && '' !== $value ) {
                    $value = absint( $value );
                }
                else {
                    $value = 0;
                }                      
                return sprintf( $where . ' AND wp_posts.menu_order %s %d ',
                                $compare, $value );
            }
        }
    }
        
    return $where;
}
$query = new WP_Query( $args );

With the above implementation, you can just change the $args to get the desired result. For example:

// menu_order less than or equals 5
$args = array( 
   'post_type' => 'page',
   'menu_order' => array(
        'value' => 5,
        'compare' => '<='
    )
);

// menu_order greater than 10
$args = array( 
   'post_type' => 'page',
   'menu_order' => array(
        'value' => 10,
        'compare' => '>'
    )
);

// equals will still work like before
$args = array( 
   'post_type' => 'page',
   'menu_order' => 6
);

4
  • Thanks. I don't think I ever noticed a mentioning in the docs of being able to match by menu_order. Nice. I can see how the filter would work, but the '4' would need to be parametrised. I can imagine a bit of an ugly hack to define the value outside of the filter and then pulling it in as a global, but are there better ways?
    – MastaBaba
    Jan 31 at 10:46
  • 1
    I'm glad it helped you. Yeah, there is always a better way :) I'm updating the answer, please check.
    – Fayaz
    Jan 31 at 12:27
  • Oh wow, yeah, that makes perfect sense. Very nice. Thanks!
    – MastaBaba
    Jan 31 at 13:20
  • You're most welcome :)
    – Fayaz
    Jan 31 at 14:32

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.