1+ <?php
2+ /**
3+ * Sorts unpaginated search results more intutiviely.
4+ *
5+ * If the search terms exactly match an item's title, that item is first. Then, general
6+ * matches occur on the title, excerpt, and content fields, sorted in that order.
7+ */
8+
9+ add_filter ( 'the_posts ' , function ( $ posts , $ query ) {
10+ if ( ! $ query ->is_main_query () || ! $ query ->is_search () )
11+ return $ posts ;
12+
13+ $ priorities = array_fill ( 0 , 4 , array () );
14+
15+ $ search_terms = $ query ->query_vars ['search_terms ' ];
16+ $ search_terms = array_map ( 'strtolower ' , $ search_terms );
17+ foreach ( $ posts as $ post ) {
18+ if ( strtolower ( $ post ->post_title ) === implode ( ' ' , $ search_terms ) ) {
19+ // Perfect title match: Priority 0.
20+ $ priorities [0 ][] = $ post ;
21+ continue ;
22+ }
23+
24+ foreach ( array ( 1 => 'post_title ' , 2 => 'post_excerpt ' ) as $ priority => $ field ) {
25+ foreach ( $ search_terms as $ search_term ) {
26+ // A search term is not present in the field, so move to the next field.
27+ if ( false === stripos ( $ post ->$ field , $ search_term ) )
28+ continue 2 ;
29+ }
30+
31+ // Found all matching terms in this field, so add it to the respective priority.
32+ $ priorities [ $ priority ][] = $ post ;
33+ continue 2 ;
34+ }
35+
36+ // No matches in a priority field, so assume the post got here via the content.
37+ $ priorities [3 ][] = $ post ;
38+ }
39+
40+ return array_merge ( $ priorities [0 ], $ priorities [1 ], $ priorities [2 ], $ priorities [3 ] );
41+ }, 10 , 2 );
0 commit comments