I ended up finding two solutions within WordPress’ capabilities.
Storing available rather than unavailable dates
The first solution would be to have the agency select all available dates rather than selecting unavailable dates. Our example listing would then have a custom field listing_available
:
update_post_meta($post_id, "listing_available", "/20140101/20140102/20140103/20140104/");
I would then be able to run the following LIKE
query on the field:
$dates = [];
for($i = $arrival_date; $i <= $departure_date; $i++)
$dates[] = $i;
$meta = array(
"key" => "listing_available",
"value" => "https://wordpress.stackexchange.com/".implode("https://wordpress.stackexchange.com/", $dates)."https://wordpress.stackexchange.com/",
"compare" => "LIKE"
);
All dates between arrival and departure would have to be present in the listing_available
field for the listing to show up. For the example case presented in the question, the query would as intended not find the listing, because it is not available during all given dates.
Though this works, it means the agency has to update all posts regularly since posts are now set to unavailable by default. Also the dates have to be ordered for this to work.
Using the REGEXP comparison type
While digging into the core code of WP_Meta_Query
(the backbone for meta queries) I found two additional comparison types that have not yet been documented: REGEXP
and NOT REGEXP
.
These comparison types solved my issue instantly as I could now look for different values in a single meta field without having to mess with the actual query. Using the $dates
array from the code above:
$regexp = "(/".implode("https://wordpress.stackexchange.com/"https://wordpress.stackexchange.com/", $dates)."/)";
$meta = array(
"key" => "listing_unavailable",
"value" => $regexp,
"compare" => "NOT REGEXP"
);
Now I can regex for any date within the given range and (by using NOT
) drop the result if a date matches.
If WP_Meta_Query
would support setting an OR
relationship for a single meta query with multiple values, I would’ve been able to do the same using LIKE
.
I’m still wondering whether this is the most efficient way to filter available rentals without heavy SQL queries or complex query-altering functions. If anyone knows of a more efficient way to solve the issue I’ll pick it as a ‘best anwer’.