Posted on

Searching between dates

If you want to have a search with a date range, that’s possible with Relevanssi. It takes a bit of handling, though, as Relevanssi expects date ranges in the date query format, and getting to that from search form can be tricky.

Here’s the code you need for date range searches:

add_filter( 'relevanssi_modify_wp_query', 'rlv_date_between' );
function rlv_date_between( $query ) {
	$from_date = null;
	$to_date   = null;

	// Get the dates from parameters "from" and "to", and parse to make sure they are dates.
	if ( isset( $_GET['from'] ) ) {
		$from_date = date_parse( $_GET['from'] );
	if ( isset( $_GET['to'] ) ) {
		$to_date   = date_parse( $_GET['to'] );

	$after  = null;
	$before = null;

	// If the "from" date checks as a valid date, create a parameter set for it.
	if ( $from_date && checkdate( $from_date['month'], $from_date['day'], $from_date['year'] ) ) {
		$after = array(
			'year'  => $from_date['year'],
		 	'month' => $from_date['month'],
		 	'day'   => $from_date['day'],
	// Same for the "to" date.
	if ( $to_date && checkdate( $to_date['month'], $to_date['day'], $to_date['year'] ) ) {
		$before = array(
			'year'  => $to_date['year'],
		 	'month' => $to_date['month'],
		 	'day'   => $to_date['day'],

	// Create the date query array and add the parameter sets to it if they were created.
	$date_query = array();
	if ( $after ) {
		$date_query['after'] = $after;
	if ( $before ) {
		$date_query['before'] = $before;
	if ( $after || $before ) {
		$date_query['inclusive'] = true;
	// If there's something in the date query array, add it to the query.
	if ( ! empty( $date_query ) ) {
		$query->date_query = $date_query;

	return $query;

Add this code to your theme (preferably child theme) functions.php file. This is a bit wordy, but also fairly safe: it checks that the parameters are actually dates before they are passed to anywhere. I’m not sure how necessary that is, but it’s best to be safe.

Using this would look like this: would show posts starting from January 1st. would show posts in January 2018.

To get this on the search form, just add two input fields:

From: [input type="text" name="from" /] to [input type="text" name="to" /]

(Replace the square brackets with angled brackets.)

17 comments Searching between dates

  1. Hi!

    IIs this possible, without too heavy workarounds, to tweak this so that the date range would instead just be dropdowns searching “from Month / year to month/year” ? So it would look in the relevant monthly/yearly wp archives for example? Would be better ux than having user type in dates in a specific format in my case.

    1. Yes, you can use dropdowns. Instead of using one from field and one to field, you can have four fields: from_month and from_year for the from date and to_month and to_year for the to date. Those fields can be dropdowns, no problems with that. Then just parse those to form a date.

      Something like this:

      // Get the dates from parameters "from" and "to", and parse to make sure they are dates.
      if ( isset( $_GET['from_month'] ) && isset( $_GET['from_year'] ) ) {
      	$from_date = date_parse( $_GET['from_year'] . '-' . $_GET['from_month'] . '-01' );
      if ( isset( $_GET['to'] ) ) {
      	$to_date = date_parse( $_GET['to_year'] . '-' . $_GET['to_month'] . '-31' );

      Something like that, with perhaps a bit more checking that the month option makes sense and so on.

  2. This works perfectly, thanks!
    Is there a way of showing ALL the posts for those dates, without looking for a word in them?

    1. Carmen, you can do a search without a search term. However, if you don’t have a search term, there’s no point using Relevanssi, you can just use WP_Query directly, it’s more efficient that way.

      1. Excuse my bad English…:)…
        I do have conditions on my search (dates, category_name, tags…)
        I’m just not looking for posts that incluye a specific word. So the URL looks like this:

        The result is 0 posts.
        I know there are several posts with this condition, because if I look for
        it finds several posts that include the word “stone”

        Thanks in advance!

        1. That should work with Relevanssi: I tried this on my test blog and it worked exactly as expected.

          If you look at the query generated by Relevanssi with Query Monitor, what does it look like?

          (Your English is flawless.)

          1. These are the queries if I use ?s=&from=2020-01-01&to=2020-05-11&category_name=Noticias

            SELECT COUNT(DISTINCT(relevanssi.doc))
            FROM wpstg0_relevanssi AS relevanssi
            WHERE relevanssi.term = relevanssi.term
            AND relevanssi.doc IN (
            SELECT DISTINCT(tr.object_id)
            FROM wpstg0_term_relationships AS tr
            WHERE tr.term_taxonomy_id IN (14))
            AND relevanssi.doc IN (
            FROM wpstg0_posts
            WHERE 1
            AND ( ( wpstg0_posts.post_date >= ‘2020-01-01 00:00:00’
            AND wpstg0_posts.post_date = ‘2020-01-01 00:00:00’
            AND wpstg0_posts.post_date = ‘2020-01-01 00:00:00’
            AND wpstg0_posts.post_date = ‘2020-01-01 00:00:00’
            AND wpstg0_posts.post_date <= '2020-05-11 23:59:59' ) ) )
            AND ( relevanssi.doc IN (
            SELECT DISTINCT(posts.ID)
            FROM wpstg0_posts AS posts
            WHERE posts.post_type IN ('post', 'page', 'attachment', 'revision', 'nav_menu_item', 'custom_css', 'customize_changeset', 'oembed_cache', 'user_request', 'wp_block', 'mailmunch_page', 'tribe_venue', 'tribe_organizer', 'tribe_events', 'tribe-ea-record', 'deleted_event', 'cool_timeline', 'portfolio', 'avia_framework_post') ) )
            ORDER BY tf DESC
            LIMIT 500

            I suppose the problem is here
            WHERE posts.post_type IN ('fake_search_no_results') ) )
            but I can't find where this is coming from.

            Thanks in advance!


          2. Hi Mikko,
            I was able to find the line WHERE posts.post_type IN (‘fake_search_no_results’) ) )
            inside a file in the theme I’m using.
            As you said, Relevanssi was working perfectly, forget about my question, thanks for your amazing guidance and plugin.

  3. Hey there, is it possible to just search for years? For example “?s=&from=2008&to=2023” it seems to return everything rather than filtering the results.

    Thank you 🙂

    1. Dani, the current code expects a full date. So you can do &from=2008-01-01&to=2023-12-31. One easy solution would be a filter that runs before this filter and completes the dates if they’re just years. Something like this:

      add_filter( 'relevanssi_modify_wp_query', function( $query ) {
        if ( isset( $_GET['from'] ) && strlen( $_GET['from'] ) === 4 && intval( $_GET['from'] ) > 0 ) {
          $_GET['from'] .= '-01-01';
        if ( isset( $_GET['to'] ) && strlen( $_GET['to'] ) === 4 && intval( $_GET['to'] ) > 0 ) {
          $_GET['to'] .= '-12-31';
        return $query;
      }, 9 );
  4. Thank you so much, I’m a bit of a newbie to this and it’s not looking like it works. I’ve tried putting it before and after the date range filter and nothing!

    Thanks again

  5. Hmmm, it breaks the site when I upload it!

    WordPress says: There has been a critical error on this website.

    Thanks again.

    1. That’s what I get for posting untested code thoughts, I suppose… I’ve edited the code now so that it works, try copying it again from the comment above.

      1. Website’s not returning errors which is awesome but it seems to just return “&from=2001&to=2024” and doesn’t return the correct posts within that date range. It’s like the filter isn’t applying!

        1. Sorry, I’m out of ideas here – when I have the filter and the original filter described in the post, this works fine. If you want to debug this, you can see what kind of values $from_date and $to_date get in the original filter (var_dump($from_date); prints out the value).

Leave a Reply

Are you a Relevanssi Premium customer looking for support? Please use the Premium support form.

Your email address will not be published. Required fields are marked *