1

I have two post types, news and events :

  • A news has no custom fields.
  • An event has two custom fields : start-date and end-date.

I want to display news and events on the same page, ideally with one single query.

One important fact is that events have to be ordered by end-date and that only future or current events have to be displayed.

Here's the query args I am trying :

$args = array(
    'post_type' => array( 'news', 'events' ),
    'meta_key' => 'end-date',
    'orderby' => 'meta_value',
    'order' => 'ASC',
    'meta_query' => array(
        array( 
            'key' => 'end-date',
            'value' => date ( 'Ymd' ),
            'type' => 'NUMERIC',
            'compare' => '>='
        )
    )
);

That works fine for events alone, but doesn't when I add news to the post types.

The problem seems to be that I specified 'meta_key' and 'meta_query' parameters which are only present on events, as a result all the news are left out in the results.

So my question is, is there a way to target a meta_query to one specific post_type in one same query ?

  • Have you tried with the relation parameter, link to the docs?. You could run into problems with the orderby – Tomás Cot Sep 4 '14 at 22:12
  • Indeed, as I order by a meta field that exists only on events, all news are discarded from the results. – mike23 Sep 5 '14 at 12:32
  • why not create 2 loops? – Tomás Cot Sep 5 '14 at 12:34
  • I'd like to have one loop so I can show the two kinds of posts in the same list with pagination. – mike23 Sep 9 '14 at 7:31
3

You can add another array into your meta_query to include all posts from your second post type.

Given in your example, you have 2 post types

  1. events
  2. news

If you can pick a meta_key that only exists for news but doesn't exist on events, then this set of args would return all news post types and still filter on events.

$args = array(
    'post_type' => array( 'news', 'events' ),
    'meta_key'  => 'end-date',
    'orderby'   => 'meta_value',
    'order'     => 'ASC',
    'meta_query' => array(
        array( 
          'key'   => 'end-date',
          'value' => date ( 'Ymd' ),
          'type'  => 'NUMERIC',
          'compare' => '>='
        ),
        array(
          'key'      => 'my_unique_key_for_news',
          'compare'  => 'EXISTS'
        ),
        'relation' => 'OR',
    )
);

The relation => OR is important. It says please return results that fit your end-dates that are >= today, OR all the items that match up on the key for news (which would be all news items).

This way you are getting specific about the meta_values for events, but returning all results for news, and thus the filter leaves the second post type alone.

| improve this answer | |
0

Since news has no custom fields, you'll probably have better luck with this:

$args = array(
    'post_type' => array( 'news', 'events' ),
    'orderby' => 'end-date date',
    'meta_query' => array(
        'relation' => 'OR',
        array( 
          'key'   => 'end-date',
          'value' => date ( 'Ymd' ),
          'type'  => 'NUMERIC',
          'compare' => '>='
        ),
        array(
          'key'      => 'end-date',
          'compare'  => 'NOT EXISTS'
        )
    )
);

Similar to italiansoda's answer, the "OR" relationship will look for any results that satisfy either meta query with the first being specific to your events post type that use the end-date meta field, and the other will happily pull in any news post types where that meta field doesn't exist.

Furthermore, I've found that by including "meta_key" => "end-date" in the top-level array of $args also excludes the news post type. I can't tell if it's working or just coincidence that my results are ordered correctly when using "orderby" => "end-date date", essentially setting preference to order results first by the end-date meta field and then the post's publish date. But it's not breaking or excluding results with it.

Alternatively, you could do "multiple loops" to have specific control. It's not my favorite method by all means, but it works and gives you more control over the parameters for specific post types.

The first loop would be getting all of your news posts and returning them as an array of post IDs. How they're ordered or sorted doesn't matter here.

$news_ids = get_posts( array(
    'fields' => 'ids',
    'posts_per_page' => -1,
    'post_type' => 'news',
    'post_status' => 'publish',
    //Add any additional parameters specific to news here
));//Returns an array of IDs

The second loop would be getting all of your events posts and returning them as an array of post IDs. How they're ordered or sorted doesn't matter here either.

$events_ids = get_posts( array(
    'fields' => 'ids',
    'posts_per_page' => -1,
    'post_type' => 'events',
    'post_status' => 'publish',
    'meta_query' => array( array(
        'type' => 'NUMERIC',
        'key' => 'end-date',
        'value' => date( 'Ymd' ),
        'compare' => '>='
    ) ),
    //Add any additional parameters specific to events here
));//Returns an array of IDs

Using those two arrays, you can merge them into a "master list" of post IDs to then use as the value for post__in in the $args array. The order of the IDs still don't matter here.

$all_ids = array_merge( $news_ids, $event_ids );//Combine all of the post IDs together into one array

$args = array(
    'post_type' => array( 'news', 'events' ),//Specify both post types here still
    'post__in' => $all_ids,//Only display posts from the "master list" of IDs
    //Add any additional parameters for sorting all of them here like...
    'orderby' => 'end-date date',
    'order' => 'ASC'
);

Order and sorting will be applied in your final and third "loop" when you define them in your $args array.

| improve this answer | |

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.