Changeset 13640
- Timestamp:
- 05/01/2024 02:37:31 AM (10 months ago)
- Location:
- sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-directory.php
r13636 r13640 992 992 993 993 $wp_query->set( 's', $s ); 994 995 // If the search is in the block directory, require that. 996 if ( $wp_query->get( 'block_search' ) ) { 997 $wp_query->query_vars['tax_query']['plugin_section'][] = array( 998 'taxonomy' => 'plugin_section', 999 'field' => 'slug', 1000 'terms' => 'block', 1001 ); 1002 } 994 1003 } 995 1004 -
sites/trunk/wordpress.org/public_html/wp-content/plugins/plugin-directory/class-plugin-search.php
r13332 r13640 135 135 136 136 return $module; 137 } 138 139 140 /** 141 * Localise the ES fields searched for localised queries. 142 */ 143 public function localise_es_fields( $fields ) { 144 $localised_prefixes = [ 145 'all_content', 146 'title', 147 'excerpt', 148 'description', 149 ]; 150 151 $localised_fields = array(); 152 153 foreach ( (array) $fields as $field ) { 154 // title.ngram 155 list( $field, $type ) = explode( '.', $field . '.' ); 156 if ( $type ) { 157 $type = ".{$type}"; 158 } 159 160 if ( ! in_array( $field, $localised_prefixes ) ) { 161 $localised_fields[] = $field . $type; 162 continue; 163 } 164 165 if ( $this->is_english ) { 166 $localised_fields[] = $field . '_en' . $type; 167 continue; 168 } 169 170 $boost = ''; 171 $en_boost = '^' . $this->en_boost; 172 if ( 'description' === $field ) { 173 $boost = '^' . $this->desc_boost; 174 $en_boost = '^' . $this->desc_en_boost; 175 } 176 177 $localised_fields[] = $field . '_' . $this->locale . $type . $boost; 178 $localised_fields[] = $field . '_en' . $type . $en_boost; 179 } 180 181 return $localised_fields; 137 182 } 138 183 … … 164 209 $this->is_english = ( ! $this->locale || str_starts_with( $this->locale, 'en_' ) ); 165 210 166 if ( $this->is_english ) { 167 $matching_fields = array( 168 'all_content_en', 169 ); 170 } else { 171 $matching_fields = array( 172 'all_content_' . $this->locale, 173 'all_content_en^' . $this->en_boost, 174 ); 175 } 176 177 $args['query_fields'] = $matching_fields; 211 $args['query_fields'] = $this->localise_es_fields( 'all_content' ); 178 212 179 213 return $args; … … 205 239 } 206 240 207 // Set boost on the match query 208 241 // The should match is where we add the fields to be searched in, and the weighting of them (boost). 242 $should_match = []; 243 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ] ) ) { 244 $should_match = & $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ]; 245 } 246 247 $search_phrase = $should_match[0][ 'multi_match' ][ 'query' ] ?? ''; 248 249 // The function score is where calculations on fields occur. 250 $function_score = []; 251 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'functions' ] ) ) { 252 $function_score = & $es_query_args[ 'query' ][ 'function_score' ][ 'functions' ]; 253 } 254 255 // Set boost on the match query, from jetpack_search_es_wp_query_args. 209 256 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'must' ][0][ 'multi_match' ] ) ) { 210 257 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'must' ][0][ 'multi_match' ][ 'boost' ] = 0.1; 211 258 } 212 259 213 // Old version had one less level here. Probably unimportant but this makes the unit tests pass. 214 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'must' ][0] ) ) { 215 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'must' ] = $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'must' ][0]; 216 } 217 218 // Not sure if this matters, but again it's in the tests 219 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ][ 'operator' ] ) ) { 220 unset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ][ 'operator' ] ); 221 } 222 223 // Some extra fields here 224 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ] ) ) { 225 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ][ 'boost' ] = 2; 226 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ][ 'fields' ] = ( $this->is_english ? [ 227 0 => 'title_en', 228 1 => 'excerpt_en', 229 2 => 'description_en^1', 230 3 => 'taxonomy.plugin_tags.name', 231 ] : [ 232 'title_' . $this->locale, 233 'excerpt_' . $this->locale, 234 'description_' . $this->locale . '^' . $this->desc_boost, 235 'title_en^' . $this->en_boost, 236 'excerpt_en^' . $this->en_boost, 237 'description_en^' . $this->desc_en_boost, 260 // This extends the search to additionally search in the title, excerpt, description and plugin_tags. 261 if ( isset( $should_match[0][ 'multi_match' ] ) ) { 262 $should_match[0][ 'multi_match' ][ 'boost' ] = 2; 263 $should_match[0][ 'multi_match' ][ 'fields' ] = $this->localise_es_fields( [ 264 'title', 265 'excerpt', 266 'description', 238 267 'taxonomy.plugin_tags.name', 239 268 ] ); 240 269 } 241 270 242 // And some more fancy bits here 243 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ] ) && 1 === count( $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ] ) ) { 244 $search_phrase = $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][0][ 'multi_match' ][ 'query' ]; 245 246 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][] = [ 247 'multi_match' => [ 248 'query' => $search_phrase, 249 'fields' => ( $this->is_english ? [ 250 0 => 'title_en.ngram', 251 ] : [ 252 'title_' . $this->locale . '.ngram', 253 'title_en.ngram^' . $this->en_boost, 271 // Setup the boosting for various fields. 272 $should_match[] = [ 273 'multi_match' => [ 274 'query' => $search_phrase, 275 'fields' => $this->localise_es_fields( [ 'title.ngram' ] ), 276 'type' => 'phrase', 277 'boost' => 2, 278 ], 279 ]; 280 281 // A direct slug match 282 $should_match[] = [ 283 'multi_match' => [ 284 'query' => $search_phrase, 285 'fields' => $this->localise_es_fields( 'title', 'slug_text' ), 286 'type' => 'most_fields', 287 'boost' => 5, 288 ], 289 ]; 290 291 $should_match[] = [ 292 'multi_match' => [ 293 'query' => $search_phrase, 294 'fields' => $this->localise_es_fields( [ 295 'excerpt', 296 'description', 297 'taxonomy.plugin_tags.name', 254 298 ] ), 255 'type' => 'phrase', 256 'boost' => 2, 257 ], 258 ]; 259 260 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][] = [ 261 'multi_match' => [ 262 'query' => $search_phrase, 263 'fields' => ( $this->is_english ? [ 264 0 => 'title_en', 265 1 => 'slug_text', 266 ] : [ 267 'title_' . $this->locale, 268 'title_en^' . $this->en_boost, 269 'slug_text', 270 ] ), 271 'type' => 'most_fields', 272 'boost' => 5, 273 ], 274 ]; 275 276 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][] = [ 277 'multi_match' => [ 278 'query' => $search_phrase, 279 'fields' => ( $this->is_english ? [ 280 0 => 'excerpt_en', 281 1 => 'description_en^1', 282 2 => 'taxonomy.plugin_tags.name', 283 ] : [ 284 'excerpt_' . $this->locale, 285 'description_' . $this->locale . '^' . $this->desc_boost, 286 'excerpt_en^' . $this->en_boost, 287 'description_en^' . $this->desc_en_boost, 288 'taxonomy.plugin_tags.name', 289 ] ), 290 'type' => 'best_fields', 291 'boost' => 2, 292 ], 293 ]; 294 295 $es_query_args[ 'query' ][ 'function_score' ][ 'query' ][ 'bool' ][ 'should' ][] = [ 296 'multi_match' => [ 297 'query' => $search_phrase, 298 'fields' => [ 299 0 => 'author', 300 1 => 'contributors', 301 ], 302 'type' => 'best_fields', 303 'boost' => 2, 304 ], 305 ]; 306 } 307 308 if ( isset( $es_query_args[ 'query' ][ 'function_score' ][ 'functions' ] ) ) { 309 $es_query_args[ 'query' ][ 'function_score' ][ 'functions' ] = [ 310 0 => [ 311 'exp' => [ 299 'type' => 'best_fields', 300 'boost' => 2, 301 ], 302 ]; 303 304 $should_match[] = [ 305 'multi_match' => [ 306 'query' => $search_phrase, 307 'fields' => $this->localise_es_fields( [ 308 'author', 309 'contributor' 310 ] ), 311 'type' => 'best_fields', 312 'boost' => 3, 313 ], 314 ]; 315 316 // We'll overwrite the default Jetpack Search function scoring with our own. 317 $function_score = [ 318 [ 319 // The more recent a plugin was updated, the more relevant it is. 320 'exp' => [ 312 321 'plugin_modified' => [ 313 314 315 'scale'=> '360d',316 'decay'=> 0.5,322 'origin' => date('Y-m-d'), 323 'offset' => '180d', 324 'scale' => '360d', 325 'decay' => 0.5, 317 326 ], 318 ], 319 ], 320 1 => [ 321 'exp' => [ 327 ] 328 ], 329 [ 330 // The older a plugins tested-up-to is, the less likely it's relevant. 331 'exp' => [ 322 332 'tested' => [ 323 324 325 'scale'=> 0.4,326 'decay'=> 0.6,333 'origin' => '5.0', 334 'offset' => 0.1, 335 'scale' => 0.4, 336 'decay' => 0.6, 327 337 ], 328 ], 329 ], 330 2 => [ 331 'field_value_factor' => [ 332 'field' => 'active_installs', 333 'factor' => 0.375, 338 ], 339 ], 340 [ 341 // A higher install base is a sign that the plugin will be relevant to the searcher. 342 'field_value_factor' => [ 343 'field' => 'active_installs', 344 'factor' => 0.375, 334 345 'modifier' => 'log2p', 335 'missing' => 1, 336 ], 337 ], 338 3 => [ 339 'filter' => [ 346 'missing' => 1, 347 ], 348 ], 349 [ 350 // For plugins with less than 1 million installs, we need to adjust their scores a bit more. 351 'filter' => [ 340 352 'range' => [ 341 'active_installs' => [ 342 'lte' => 1000000, 343 ], 353 'active_installs' => [ 354 'lte' => 1000000, 355 ], 356 ], 344 357 ], 345 ], 346 'exp' => [ 358 'exp' => [ 347 359 'active_installs' => [ 348 349 350 'scale'=> 900000,351 'decay'=> 0.75,360 'origin' => 1000000, 361 'offset' => 0, 362 'scale' => 900000, 363 'decay' => 0.75, 352 364 ], 353 ], 354 ], 355 4 => [ 356 'field_value_factor' => [ 357 'field' => 'support_threads_resolved', 358 'factor' => 0.25, 365 ], 366 ], 367 [ 368 // The more resolved support threads (as a percentage) a plugin has, the more responsive the developer is, and the better experience the end-user will have. 369 'field_value_factor' => [ 370 'field' => 'support_threads_resolved', 371 'factor' => 0.25, 359 372 'modifier' => 'log2p', 360 'missing' => 0.5, 361 ], 362 ], 363 5 => [ 364 'field_value_factor' => [ 365 'field' => 'rating', 366 'factor' => 0.25, 373 'missing' => 0.5, 374 ], 375 ], 376 [ 377 // A higher rated plugin is more likely to be preferred. 378 'field_value_factor' => [ 379 'field' => 'rating', 380 'factor' => 0.25, 367 381 'modifier' => 'sqrt', 368 'missing' => 2.5, 369 ], 370 ], 371 ]; 372 } 373 374 // Old version didn't have these 382 'missing' => 2.5, 383 ], 384 ], 385 ]; 386 375 387 unset( $es_query_args[ 'query' ][ 'function_score' ][ 'score_mode' ] ); 376 unset( $es_query_args[ 'query' ][ 'function_score' ][ 'max_boost' ] ); 377 unset( $es_query_args[ 'aggregations' ] ); 388 unset( $es_query_args[ 'query' ][ 'function_score' ][ 'boost_mode' ] ); 378 389 379 390 // Couple of extra fields wanted in the response, mainly for debugging 380 391 $es_query_args[ 'fields' ] = [ 381 0 => 'slug', 382 1 => 'post_id', 383 2 => 'blog_id', 384 ]; 385 386 // Old version had things wrapped in an extra query => filtered layer. 387 $es_query_args[ 'query' ] = [ 388 'filtered' => [ 389 'query' => $es_query_args[ 'query' ] 390 ] 392 'slug', 393 'post_id', 391 394 ]; 392 395
Note: See TracChangeset
for help on using the changeset viewer.