Add Relevance Weight to More Recently Published Entries by Date
By default SearchWP returns results sorted by the total calculated weight based upon the values entered in your engine configuration. There are times when you might want to dynamically influence the ranking of search results by taking into consideration the publish date of each result.
Using SearchWP’s searchwp\query\mods
hook, we can do just that! There are three different approaches to cover:
Note: This implementation does NOT cause results to be sorted by date, instead more recently published entries will simply be given more weight as calculated by SearchWP. The more recently an entry was published the more weight it gets.
- Bonus weight for recently published
- Bonus weight that decays over time
- Date stored as Custom Field value
- Arbitrary multiplier on date as Custom Field value
See also: Using a Custom Field to Prioritize Search Results
Bonus weight for recently published
To have more recently published entries get a weight boost, add this to your SearchWP Customizations plugin:
All hooks should be added to your custom SearchWP Customizations Plugin.
<?php | |
// Add search weight to more recently published entries in SearchWP. | |
// @link https://searchwp.com/documentation/knowledge-base/add-relevance-weight-date/ | |
add_filter( 'searchwp\query\mods', function( $mods ) { | |
global $wpdb; | |
$mod = new \SearchWP\Mod(); | |
$mod->set_local_table( $wpdb->posts ); | |
$mod->on( 'ID', [ 'column' => 'id' ] ); | |
$mod->relevance( function( $runtime ) use ( $wpdb ) { | |
return " | |
COALESCE( ROUND( ( ( | |
UNIX_TIMESTAMP( {$runtime->get_local_table_alias()}.post_date ) | |
- ( | |
SELECT UNIX_TIMESTAMP( {$wpdb->posts}.post_date ) | |
FROM {$wpdb->posts} | |
WHERE {$wpdb->posts}.post_status = 'publish' | |
ORDER BY {$wpdb->posts}.post_date ASC | |
LIMIT 1 | |
) | |
) / 86400 ), 0 ), 0 )"; | |
} ); | |
$mods[] = $mod; | |
return $mods; | |
} ); |
Bonus weight that decays over time
Alternatively, you can use something like this to have the weight influence taper off as publish dates go further back in time. Only recently published posts will get a boost, the published date for older posts will not influence the weight.
This modification is more aggressive in that the influence tapers off over time, but that may be preferential for you!
All hooks should be added to your custom SearchWP Customizations Plugin.
<?php | |
// Add search weight to more recently published entries in SearchWP. | |
// Weight decays over time and eventually will not add bonus weight. | |
// @link https://searchwp.com/documentation/knowledge-base/add-relevance-weight-date/ | |
add_filter( 'searchwp\query\mods', function( $mods ) { | |
global $wpdb; | |
$weight_adjust = 15; | |
$mod = new \SearchWP\Mod(); | |
$mod->set_local_table( $wpdb->posts ); | |
$mod->on( 'ID', [ 'column' => 'id' ] ); | |
$mod->relevance( function( $runtime_mod ) use ( $weight_adjust ) { | |
$alias = $runtime_mod->get_local_table_alias(); | |
return " | |
( 100 * EXP( | |
( 1 - ABS( ( | |
UNIX_TIMESTAMP( {$alias}.post_date ) | |
- UNIX_TIMESTAMP( NOW() ) | |
) / 86400 ) ) / 100 ) | |
* {$weight_adjust} )"; | |
} ); | |
$mods[] = $mod; | |
return $mods; | |
} ); |
With either in place, entries with more recent published dates will be given more weight than those with older publish dates.
As referenced in the comment, experiment with line 8 to determine what $modifier
value works best for you.
Date stored as Custom Field value
Another example would be to have results sorted by dates stored in a Custom Field. The more recent the date of the Custom Field the more weight the result will receive:
All hooks should be added to your custom SearchWP Customizations Plugin.
<?php | |
// Add bonus weight from Custom Field value in SearchWP. | |
// @link https://searchwp.com/documentation/knowledge-base/add-relevance-weight-date/ | |
add_filter( 'searchwp\query\mods', function( $mods ) { | |
global $wpdb; | |
// Custom Field name. Needs to store data as YYYYMMDD (ACF does this already). | |
$my_meta_key = 'date_field'; | |
$mod = new \SearchWP\Mod(); | |
$mod->set_local_table( $wpdb->postmeta ); | |
$mod->on( 'post_id', [ 'column' => 'id' ] ); | |
$mod->on( 'meta_key', [ 'value' => $my_meta_key ] ); | |
$mod->relevance( function( $runtime ) use ( $wpdb, $my_meta_key ) { return $wpdb->prepare( " | |
COALESCE( ROUND( ( ( | |
UNIX_TIMESTAMP( {$runtime->get_local_table_alias()}.meta_value ) | |
- ( | |
SELECT UNIX_TIMESTAMP( meta_value ) | |
FROM {$wpdb->postmeta} | |
WHERE meta_key = %s | |
ORDER BY meta_value ASC | |
LIMIT 1 | |
) | |
) / 86400 ), 0 ), 0 )", $my_meta_key ); | |
} ); | |
$mods[] = $mod; | |
return $mods; | |
} ); |
Arbitrary multiplier on date as Custom Field value
It is also possible to arbitrarily assign a multiplier to the final, calculated weight (relevance) of results. In other words, the weight manipulation will not be dynamic based on the timestamp, but instead multiplied by a value you determine.
You can apply different multipliers based on whether the Custom Field date is in the past or the future, reducing the calculated relevance if the Custom Field value is in the past, and increasing calculated relevance if it’s in the future for example:
All hooks should be added to your custom SearchWP Customizations Plugin.
<?php | |
// Modify SearchWP calculated relevance using multiplier. | |
// @link https://searchwp.com/documentation/knowledge-base/add-relevance-weight-date/ | |
class My_SearchWP_Date_Modifier { | |
private $post_type = 'post'; | |
private $meta_key = 'event_date'; | |
private $modifier_past = 0.5; | |
private $modifier_future = 1.5; | |
private $alias = 'myswpdm'; | |
function __construct() { | |
global $wpdb; | |
// Modify SearchWP calculated relevance using multiplier. | |
add_filter( 'searchwp\query', function( $query, $args ) use ( $wpdb ) { | |
// Calculate a CUSTOM relevance. | |
$query['select'][] = "( SUM(relevance) * {$this->alias}mod ) AS {$this->alias}rel"; | |
// Implement a custom weight modifier based on date stored as meta value. | |
$query['from']['select'][] = " | |
( | |
CASE | |
WHEN UNIX_TIMESTAMP( {$this->alias}m.meta_value ) < UNIX_TIMESTAMP( NOW() ) | |
THEN {$this->modifier_past} | |
WHEN UNIX_TIMESTAMP( {$this->alias}m.meta_value ) > UNIX_TIMESTAMP( NOW() ) | |
THEN {$this->modifier_future} | |
ELSE 1 | |
END | |
) AS {$this->alias}mod | |
"; | |
// Custom JOINs. | |
$query['from']['from'][] = " | |
LEFT JOIN {$wpdb->posts} {$this->alias}p | |
ON ( {$this->alias}p.ID = {$args['index_alias']}.id | |
AND {$this->alias}p.post_type = '{$this->post_type}' ) | |
"; | |
$query['from']['from'][] = " | |
LEFT JOIN {$wpdb->postmeta} {$this->alias}m | |
ON ( {$this->alias}m.post_id = {$this->alias}p.ID | |
AND {$this->alias}m.meta_key = '{$this->meta_key}' ) | |
"; | |
// Use our custom relevance to sort results by overriding the default ORDERBY. | |
$query['order_by'] = [ "{$this->alias}rel DESC", ]; | |
return $query; | |
}, 20, 2 ); | |
} | |
} | |
new My_SearchWP_Date_Modifier(); |
The overall implementation of the above snippet is that we’re manipulating SearchWP’s query directly to:
- Add a new column to the index query to calculate and store our custom relevance calculation
- Add a modifier calculation based on the
UNIX_TIMESTAMP
of the Custom Field value - Include custom
JOIN
s to ensure we’re retrieving the proper Custom Field values - Override SearchWP’s
ORDERBY
clause to sort results by our custom relevance calculation
By taking this approach we can have full and direct control over how SearchWP’s query runs and in this case adjust the calculated weight for Posts with a Custom Field named event_date
using a direct multiplier, leaving other post types (or Posts without the Custom Field) unaffected by the multiplier.