You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Currently search results in the media modal are force sorted by date by the backbone JS model. Elasticsearch gives us a relevancy score that is not being used.
Acceptance criteria:
Media search results are sorted by relevancy score rather than date
1. Add _score to ep_post_formatted_args for media search
/**
* Modifies Sort Order From Media Search.
*
* @hook ep_post_formatted_args
*
* @param array $query The ElasticSearch query.
* @param array $args The WP_Query args for the current query.
*
* @return array New query
*/
function modifies_sort_order_for_media_search( array $query, array $args ) : array {
// Check we have a search query and only apply to attachment.
if ( empty( $args['s'] ) || $args['post_type'] !== 'attachment' ) {
return $query;
}
unset( $query['sort'] );
$query['sort'] = [
[
'_score' => [
'order' => 'DESC',
],
],
];
return $query;
}
add_filter( 'ep_post_formatted_args', __NAMESPACE__ . '\\modifies_sort_order_for_media_search', 11, 2 );
2. Add _score as return args in ElasticPress
/**
* Add _score field to post return fields.
*
* @hook ep_search_post_return_args
* @param array $return_fields Post Fields
* @return array Post Fields
*/
function add_score_to_post_return( array $return_fields ) : array {
$return_fields[] = '_score';
return $return_fields;
}
add_filter( 'ep_search_post_return_args', __NAMESPACE__ . '\\add_score_to_post_return', 10 );
3. Add _score as part of post object in ElasticPress
/**
* Add _score to posts result from ES query.
*
* @hook ep_retrieve_the_{index_type}
*
* @param array $document Document retrieved from Elasticsearch
* @param array $hit Raw Elasticsearch hit
*/
function add_score_to_post( array $document, array $hit ) : array {
$document['_score'] = $hit['_score'] ?? '';
return $document;
}
add_filter( 'ep_retrieve_the_post', __NAMESPACE__ . '\\add_score_to_post', 10, 2 );
4. Pass down the _score value to attachment data JavaScript object
/**
* Filters the attachment data prepared for JavaScript.
*
* @hook wp_prepare_attachment_for_js
*
* @param array $response Array of prepared attachment data.
* @see wp_prepare_attachment_for_js().
* @param WP_Post $attachment Attachment object.
*
* @return array
*/
function add_score_to_media_search_results( array $response, WP_Post $attachment ) : array {
// The _score attribute come from the mapping added in add_score_to_post function.
$response['_score'] = property_exists( $attachment, '_score' ) ? $attachment->_score : '';
return $response;
}
add_filter( 'wp_prepare_attachment_for_js', __NAMESPACE__ . '\\add_score_to_media_search_results', 10, 2 );
5. Modify Media Library Backbone Model & View to use _score as the sort order.
Media Query
/**
* Override media query.
*
* This is to switch orderby between date or _score during page load.
* When search query string exists, use _score.
*
* @param {object} [props] Query props.
* @returns {wp.media.model.Attachments} Attachment collection query.
*/
wp.media.query = function ( props ) {
return new wp.media.model.Attachments(
null, {
props: _.extend(
_.defaults(
props || {},
{ orderby: _.isUndefined( props.search ) ? 'date' : '_score' }
), { query: true }
),
} );
};
Media Model
/**
* Override wp.media.model.Query
*
* This is to add _score to allowed orderby and the props mapping.
*/
_.extend(
wp.media.model.Query,
{
orderby: {
allowed: [ ...wp.media.model.Query.orderby.allowed, '_score' ],
valuemap: { ...wp.media.model.Query.orderby.valuemap },
},
propmap: {
...wp.media.model.Query.propmap,
'_score': '_score',
},
}
);
Media View
/**
* Override wp.media.view.Search.prototype.search
*
* This is to enable sort by _score when doing search, and
* sort by date when not.
*/
_.extend(
wp.media.view.Search.prototype,
{
search: _.debounce( function ( event ) {
let searchTerm = event.target.value.trim();
const attributes = { ...this.model.attributes };
// Trigger the search only after 2 ASCII characters.
if ( searchTerm && searchTerm.length > 1 ) {
attributes['search'] = searchTerm;
attributes['orderby'] = '_score';
this.model.set( attributes );
} else {
// Directly change the orderby without using `set` in purpose.
// If we use `set` here, it will trigger double rendering.
this.model.attributes['orderby'] = 'date';
// Only need this to trigger the render.
this.model.unset( 'search' );
}
}, 500 ),
}
);
The text was updated successfully, but these errors were encountered:
Currently search results in the media modal are force sorted by date by the backbone JS model. Elasticsearch gives us a relevancy score that is not being used.
Acceptance criteria:
There is an writeup with the solution for implementing this here: https://dev.hmn.md/2022/06/16/increase-media-search-relevancy-with-elasticsearch/comment-page-1/#comment-6523
Copying in the details here:
The Solution
1. Add _score to ep_post_formatted_args for media search
2. Add _score as return args in ElasticPress
3. Add _score as part of post object in ElasticPress
4. Pass down the _score value to attachment data JavaScript object
5. Modify Media Library Backbone Model & View to use _score as the sort order.
Media Query
Media Model
Media View
The text was updated successfully, but these errors were encountered: