<strong>My question: </strong>How to exclude events (custom posts) from search results, if the start date has already passed?
I have a query that is used to display search results. The query is in search.php. <em>It shows custom posts and pages in the search result, which is what I want.</em> I have a custom post type called 'event', each post has a date stored in _event_start_date
. I want to compare _event_start_date (a meta key) with the current date and exclude event posts that are in the past from the search result.
My working query:
if ( have_posts() ) : ?>
<h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'shape' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
<?php while ( have_posts() ) : the_post(); ?>
<a href="<?php echo get_permalink( ); ?>"><?php echo the_title(); ?></a>
<?php endwhile; ?>
<?php else : ?>
<p> there were no results </p>
<?php endif; ?>
How can I include _event_start_date in the above code, so that if an event has already started it is not shown in the search result? The date is formatted as 2015-05-01
<strong> Perhaps I need to use a WP_query?</strong>
Dbranes answers:
I would recommend using the pre_get_posts hook if possible.
If your _event_start_date is saved as unix timestamp, then you can try the following (untested):
function wpq_modify_search( $q ) {
if ( ! is_admin() && $q->is_main_query() && $q->is_search() ) {
$meta_query = [
'relation' => 'or',
[
'key' => '_event_start_date',
'value' => current_time( 'timestamp' ),
'compare' => '>=',
'type' => 'NUMERIC',
],
[
'key' => '_event_start_date',
'compare' => 'NOT EXISTS',
],
];
$q->set('meta_query', $meta_query );
}
}
add_action( 'pre_get_posts', 'wpq_modify_search' );
where we assume PHP 5.4+
Matthew Pollard comments:
Thanks, I put that in functions.php and all I get is 'there were no results' , when there are posts to be shown.
Dbranes comments:
aha, I just noticed you mentioned the <em>mysql</em> date format, then you can try:
'value' => current_time( 'mysql' ),
'type' => 'DATETIME',
instead or your own variation to this ;-)
Matthew Pollard comments:
When I echo _event_start_date
it is in the following format 2015-05-01
Dbranes comments:
The reason I use current_time() is that it contains your blog's timezone (local time).
You can also use:
'value' => current_time( 'Y-m-d' ),
'type' => 'DATE',
where we use the default value of current_time() when the input is not 'mysql' or 'timestamp'.
ps: you might also want to change $q->is_search() to $q->is_search
Matthew Pollard comments:
Thanks, just one small issue, if someone does a search for a past event on the site, it doesn't say '
<p> there were no results </p>' . It says nothing.
Dbranes comments:
Not sure why that would happen, but check your logs to make sure there are no errors.
You could also try this on a default theme.
Andrea P answers:
a very quick hack would be to simply set a conditional to don't display them. but this would make your pagination (if you have it) working not as expected. so in case you have pagination, we'll need to hook the query before it is rendered. but if you don't have pagination, this would do the job:
if ( have_posts() ) : ?>
<h1 class="page-title"><?php printf( __( 'Search Results for: %s', 'shape' ), '<span>' . get_search_query() . '</span>' ); ?></h1>
<?php while ( have_posts() ) : the_post(); ?>
<?php // if this is an event post type
if ( get_post_type( get_the_ID() )=='event' ){
// get the star date
$start_date = get_post_meta( get_the_ID(), '_event_start_date', true );
// I assume the date is stored in the classic format YYMMDD so I get the current date in that format
$today = date('Ymd');
// if the event started in the past, set a var to don't print it
if ( $start_date < $today ){
$display_event = "NO";
}
}
// display the post only if display_event has not been set to NO (so any not-event post will be displayed)
if ( $display_event != "NO" ){
?>
<a href="<?php echo get_permalink( ); ?>"><?php echo the_title(); ?></a>
<?php
}
?>
<?php endwhile; ?>
<?php else : ?>
<p> there were no results </p>
<?php endif; ?>
I have assumed that the date is stored in the format of YYMMDD, so if it's not, let me know which other format it is, so I can tweak the code.
if you do have pagination, then we'll need to hook the query. in order to do so, I need to know which template is displaying your events, in order to hook the query only where needed.
*** EDIT ***
sorry, just seen is a search page. so is it the default search? I mean, is this template going to be used for normal posts as well?
anyway, I have edited the code so that if it's not an event post type, it won't consider the date thing.
cheers
Matthew Pollard comments:
Hi,
Thanks for that answer. I am using pagination.
I have two templates to display events:
taxonomy-event-categories.php (my events are in categories. This shows the events that belong to each category on separate category pages)
single-event.php (shows the details for one event on a page)
Hariprasad Vijayan answers:
Hi,
try this in functions.php
add_action( 'pre_get_posts', function( $query ) {
if ( ! is_admin() && $query->is_main_query() && $query->is_search() ) {
$today = date('Y-m-d');
$meta_query = array(
'relation' => 'or',
array(
'key'=>'_event_start_date',
'value'=>$today,
'compare'=>'>=',
'type' => 'DATE'
),
array(
'key' => '_event_start_date',
'compare' => 'NOT EXISTS',
),
);
$query->set('meta_query',$meta_query);
}
});