Support

Account

Home Forums Front-end Issues pre_get_posts – order posts by two different meta_keys (ACF select field)

Solved

pre_get_posts – order posts by two different meta_keys (ACF select field)

  • Hello – I hope this is the right place! I wonder if you can help. I’ve had a good search around, but can’t find anything that fits my specific case. I’m hoping it’s an easy fix!

    I’m putting together an archive page for an ‘exhibition’ custom post type. Simply put, I need the posts to be ordered first by ‘year’, then by ‘month’. I am using the ACF select field for these, providing options to choose from (2004-2020, and January-December respectively). I don’t want to use the datepicker field as days of the month aren’t needed.

    So far, following an example from the docs, I have managed to order posts by year using pre_get_posts:

    function exhibition_pre_get_posts( $query ) {
    	
    	// do not modify queries in the admin
    	if( is_admin() ) {
    		return $query;
    	}
    	
    	if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'exhibition' ) {
    		$query->set('orderby', array('meta_value_num' => 'DESC'));	
    		$query->set('meta_key', 'year');
    	}
    
    	// return
    	return $query;
    }
    
    add_action('pre_get_posts', 'exhibition_pre_get_posts');
    

    But I also need the posts to be organized by month, in a descending order (so October 2004 appears before January 2004 etc). My ACF select field for ‘month’ uses the format 1 : January / 2 : February / 3 : March, etc. The ‘value’ is numerical so that I can sort them using meta_value_num.

    What I essentially need to do is somehow use two meta_keys – first ‘year’ and then ‘month’ – but I just can’t figure out a way to do that!

    Any help would be amazing and very much appreciated. Thank you!

  • Thank you for your reply, John. I did find this post, but couldn’t figure out how to use this in pre_get_posts.

    Here’s what I have tried, but of course it doesn’t work:

    function exhibition_pre_get_posts( $query ) {
    	
    	// do not modify queries in the admin
    	if( is_admin() ) {
    		return $query;
    	}
    	
    	if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'exhibition' ) {
    		$query = new WP_Query( array(
        'meta_query' => array(
            'relation' => 'AND',
            'year' => array(
                'key' => 'year',
            ),
            'month' => array(
                'key' => 'month',
                'compare' => 'EXISTS',
            ), 
        ),
        'orderby' => array(
            'year' => 'DESC',
            'month' => 'DESC',
        ) 
    ) );
    	}
    
    	// return
    	return $query;
    }
    
    add_action('pre_get_posts', 'exhibition_pre_get_posts');

    I’m sure this is a rookie mistake and a misunderstanding of the fundamentals – I’m still very much a beginner, I’m afraid!

  • You need to set the meta_query just like you set the other query parameters in your filter.

    
    $meta_query = array(
      array(
        'year_clause' => array(
          'key' => 'year',
          'compare' => 'EXISTS'
        )
      ),
      array(
        'month_clause' => array(
          'key' => 'month',
          'compare' => 'EXISTS'
        )
      )
    );
    $query->set('meta_query', $meta_query);
    $query->set('orderby', array('year_clause' => 'DESC', 'month_clause' => 'DESC'));
    
    
  • Thank you SO much, John – you have been a great help and this seems to be working really well. How then do I apply meta_value_num (so that month ’10’ is greater than month ‘2’ etc?) Adding ‘meta_value_num’ to the orderby array doesn’t seem to work. Here’s what I have now:

    function exhibition_pre_get_posts( $query ) {
    
    	if( is_admin() ) {
    		return $query;
    	}
    	
    	if( isset($query->query_vars['post_type']) && $query->query_vars['post_type'] == 'exhibition' ) {
    
    $meta_query = array(
      array(
        'year_clause' => array(
          'key' => 'year',
          'compare' => 'EXISTS'
        )
      ),
      array(
        'month_clause' => array(
          'key' => 'month',
          'compare' => 'EXISTS'
        )
      )
    );
    $query->set('meta_query', $meta_query);
    $query->set('orderby', array('year_clause' => 'DESC', 'month_clause' => 'DESC'));
    
    	}
    
    	// return
    	return $query;
    }
    
    add_action('pre_get_posts', 'exhibition_pre_get_posts');
  • I don’t know if this will work or not

    
    $meta_query = array(
      array(
        'year_clause' => array(
          'key' => 'year',
          'compare' => 'EXISTS',
          'type' => 'NUMERIC'
        )
      ),
      array(
        'month_clause' => array(
          'key' => 'month',
          'compare' => 'EXISTS',
          'type' => 'NUMERIC'
        )
      )
    );
    
  • It absolutely does – thank you very much indeed for all your help!

  • How do I apply this to dynamic filtering parameters?

    This all seem very hardcoded. I’ve added to filtering dropdowns to my (custom) posts in the admin for filtering on Office and Division. How do I get the paramst from the query ($_GET[‘offices] and $_GET[‘divisions’]) and add them to the query!?

Viewing 8 posts - 1 through 8 (of 8 total)

The topic ‘pre_get_posts – order posts by two different meta_keys (ACF select field)’ is closed to new replies.