WordPress.org

Making WordPress.org

Ticket #1516: 1516.1.patch

File 1516.1.patch, 4.3 KB (added by keesiemeijer, 3 years ago)

Order with shortest matches first

  • sites/trunk/wordpress.org/public_html/wp-content/themes/pub/wporg-developer/functions.php

     
    9797
    9898        add_filter( 'post_type_link', __NAMESPACE__ . '\\method_permalink', 10, 2 );
    9999        add_filter( 'term_link', __NAMESPACE__ . '\\taxonomy_permalink', 10, 3 );
     100        add_filter( 'posts_orderby', __NAMESPACE__ . '\\search_posts_orderby', 10, 2 );
    100101        add_filter( 'the_posts', __NAMESPACE__ . '\\rerun_empty_exact_search', 10, 2 );
    101102
    102103        add_theme_support( 'automatic-feed-links' );
     
    202203
    203204        if ( $query->is_search() ) {
    204205
    205                 // Order searches by title first.
    206                 $query->set( 'orderby', '' );
    207                 $query->set( 'search_orderby_title', 1 );
    208 
    209206                // If user has '()' at end of a search string, assume they want a specific function/method.
    210207                $s = htmlentities( $query->get( 's' ) );
    211208                if ( '()' === substr( $s, -2 ) ) {
     
    220217}
    221218
    222219/**
     220 * Filter the SQL for the ORDER BY clause for search queries.
     221 * Adds ORDER BY condition with spaces replaced with underscores in 'post_title'.
     222 * Adds ORDER BY condition to order by title length.
     223 *
     224 * @param string  $orderby The ORDER BY clause of the query.
     225 * @param WP_Query $query   The WP_Query instance (passed by reference).
     226 * @return string  Filtered order by clause
     227 */
     228function search_posts_orderby( $orderby, $query ) {
     229        global $wpdb;
     230
     231        if ( $query->is_main_query() && is_search() && !$query->get( 'exact' ) ) {
     232
     233                $search_order_by_title = $query->get( 'search_orderby_title' );
     234
     235                // Check if search_orderby_title is set by WP_Query::parse_search
     236                if ( is_array( $search_order_by_title ) && !empty( $search_order_by_title ) ) {
     237
     238                        // Get search orderby query.
     239                        $orderby = parse_search_order( $query->query_vars );
     240
     241                        // Add order by title length.
     242                        $orderby .= " , CHAR_LENGTH( $wpdb->posts.post_title ) ASC, $wpdb->posts.post_title ASC";
     243                }
     244        }
     245
     246        return $orderby;
     247}
     248
     249/**
     250 * Generate SQL for the ORDER BY condition based on passed search terms.
     251 * Similar to WP_Query::parse_search_order.
     252 * Adds ORDER BY condition with spaces replaced with underscores in 'post_title'.
     253 *
     254 * @global wpdb $wpdb WordPress database abstraction object.
     255 *
     256 * @param array   $q Query variables.
     257 * @return string ORDER BY clause.
     258 */
     259function parse_search_order( $q ) {
     260        global $wpdb;
     261
     262        if ( $q['search_terms_count'] > 1 ) {
     263                $num_terms = count( $q['search_orderby_title'] );
     264
     265                // If the search terms contain negative queries, don't bother ordering by sentence matches.
     266                $like = $_like = '';
     267                if ( ! preg_match( '/(?:\s|^)\-/', $q['s'] ) ) {
     268                        $like = '%' . $wpdb->esc_like( $q['s'] ) . '%';
     269                }
     270
     271                $search_orderby = '';
     272
     273                // Sentence match in 'post_title'.
     274                if ( $like ) {
     275                        $search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_title LIKE %s THEN 1 ", $like );
     276                        $_like =  str_replace( '-', '_', sanitize_title_with_dashes( $q['s'] ) );
     277                        $_like = '%' . $wpdb->esc_like( $_like ) . '%';
     278                        if ( $_like !== $like ) {
     279                                // Sentence match in 'post_title' with spaces replaced with underscores.
     280                                $search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_title LIKE %s THEN 2 ", $_like );
     281                        }
     282                }
     283
     284                // Sanity limit, sort as sentence when more than 6 terms.
     285                // (few searches are longer than 6 terms and most titles are not)
     286                if ( $num_terms < 7 ) {
     287                        // all words in title
     288                        $search_orderby .= 'WHEN ' . implode( ' AND ', $q['search_orderby_title'] ) . ' THEN 3 ';
     289                        // any word in title, not needed when $num_terms == 1
     290                        if ( $num_terms > 1 )
     291                                $search_orderby .= 'WHEN ' . implode( ' OR ', $q['search_orderby_title'] ) . ' THEN 4 ';
     292                }
     293
     294                // Sentence match in 'post_content'.
     295                if ( $like ) {
     296                        $search_orderby .= $wpdb->prepare( "WHEN $wpdb->posts.post_content LIKE %s THEN 5 ", $like );
     297                }
     298
     299                if ( $search_orderby ) {
     300                        $search_orderby = '(CASE ' . $search_orderby . 'ELSE 6 END)';
     301                }
     302        } else {
     303                // Single word or sentence search.
     304                $search_orderby = reset( $q['search_orderby_title'] ) . ' DESC';
     305        }
     306
     307        return $search_orderby;
     308}
     309
     310/**
    223311 * Rerun an exact search with the same criteria except exactness if no posts
    224312 * were found.
    225313 *