PluginProbe
ElasticPress / 5.3.5
ElasticPress v5.3.5
5.3.5 5.3.4 3.6.5 3.6.6 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.2.2 4.3.0 4.3.1 4.4.0 4.4.1 4.5.0 4.5.1 4.5.2 4.6.0 4.6.1 4.7.0 4.7.1 4.7.2 5.0.0 5.0.1 5.0.2 All 108 releases
← All changes | includes/classes/Feature/Search/Synonyms.php +124 -40 4.7.25.3.5 View file →
@@ -10,8 +10,9 @@
10 10 use ElasticPress\Elasticsearch;
11 11 use ElasticPress\FeatureRequirementsStatus;
12 12 use ElasticPress\Features;
13 13 use ElasticPress\Indexables;
14 +use ElasticPress\REST;
14 15 use ElasticPress\Utils;
15 16
16 17 if ( ! defined( 'ABSPATH' ) ) {
17 18 exit; // Exit if accessed directly.
@@ -81,15 +82,17 @@
81 82 *
82 83 * @return FeatureRequirementsStatus
83 84 */
84 85 public function requirements_status() {
86 + $status = new FeatureRequirementsStatus( 0, null, $this );
85 87 $search = $this->get_search_feature();
86 88
87 89 if ( ! $search->is_active() ) {
88 - return new FeatureRequirementsStatus( 2, esc_html__( 'This feature requires the "Post Search" feature to be enabled', 'elasticpress' ) );
90 + $status->code = 2;
91 + $status->message = esc_html__( 'This feature requires the "Post Search" feature to be enabled', 'elasticpress' );
89 92 }
90 93
91 - return new FeatureRequirementsStatus( 0 );
94 + return $status;
92 95 }
93 96
94 97 /**
95 98 * Setup Feature Functionality
@@ -96,9 +99,9 @@
96 99 *
97 100 * @return bool
98 101 */
99 102 public function setup() {
100 - if ( (bool) $this->requirements_status()->code ) {
103 + if ( (bool) $this->requirements_status()->get_code() ) {
101 104 return false;
102 105 }
103 106
104 107 // Register a post type to hold the synonyms post.
@@ -107,18 +110,14 @@
107 110 // Setup the UI.
108 111 add_action( 'admin_menu', [ $this, 'admin_menu' ], 50 );
109 112 add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
110 113
111 - // Handle the update synonyms action.
112 - $action = $this->get_action();
113 - add_action( "admin_post_$action", [ $this, 'handle_update_synonyms' ] );
114 -
115 - // Handle the admin notices.
116 - add_action( 'admin_notices', [ $this, 'admin_notices' ] );
117 -
118 114 // Add the synonyms to the elasticsearch query.
119 115 add_filter( 'ep_config_mapping', [ $this, 'add_search_synonyms' ], 20, 2 );
120 116
117 + // Register REST routes.
118 + add_action( 'rest_api_init', [ $this, 'setup_endpoint' ] );
119 +
121 120 return true;
122 121 }
123 122
124 123 /**
@@ -143,8 +142,16 @@
143 142
144 143 wp_enqueue_style( 'wp-edit-post' );
145 144
146 145 wp_enqueue_style(
146 + 'ep_synonyms_scripts',
147 + EP_URL . 'dist/css/synonyms-script.css',
148 + [ 'wp-components', 'wp-edit-post' ],
149 + Utils\get_asset_info( 'synonyms-styles', 'version' ),
150 + 'all'
151 + );
152 +
153 + wp_enqueue_style(
147 154 'ep_synonyms_styles',
148 155 EP_URL . 'dist/css/synonyms-styles.css',
149 156 Utils\get_asset_info( 'synonyms-styles', 'dependencies' ),
150 157 Utils\get_asset_info( 'synonyms-styles', 'version' ),
@@ -150,15 +157,20 @@
150 157 Utils\get_asset_info( 'synonyms-styles', 'version' ),
151 158 'all'
152 159 );
153 160
161 + $api_url = rest_url( 'elasticpress/v1/synonyms' );
162 + $sync_url = Utils\get_sync_url();
163 +
154 164 wp_localize_script(
155 165 'ep_synonyms_scripts',
156 166 'epSynonyms',
157 - array(
158 - 'i18n' => $this->get_localized_strings(),
159 - 'data' => $this->get_localized_data(),
160 - )
167 + [
168 + 'apiUrl' => esc_url_raw( $api_url ),
169 + 'defaultIsSolr' => $this->synonyms_editor_mode() === 'advanced',
170 + 'defaultSolr' => $this->get_synonyms_raw(),
171 + 'syncUrl' => esc_url_raw( $sync_url ),
172 + ]
161 173 );
162 174 }
163 175
164 176 /**
@@ -170,9 +182,9 @@
170 182 add_submenu_page(
171 183 'elasticpress',
172 184 esc_html__( 'ElasticPress Synonyms', 'elasticpress' ),
173 185 esc_html__( 'Synonyms', 'elasticpress' ),
174 - Utils\get_capability(),
186 + Utils\get_capability( 'synonyms' ),
175 187 'elasticpress-synonyms',
176 188 [ $this, 'admin_page' ]
177 189 );
178 190 }
@@ -186,12 +198,9 @@
186 198 include EP_PATH . '/includes/partials/header.php';
187 199
188 200 ?>
189 201 <div class="wrap">
190 - <form action="<?php echo esc_url( $this->get_form_action() ); ?>" method="POST">
191 - <?php $this->form_hidden_fields(); ?>
192 - <div id="synonym-root"></div>
193 - </form>
202 + <div id="ep-synonyms"></div>
194 203 </div>
195 204 <?php
196 205 }
197 206
@@ -198,10 +207,13 @@
198 207 /**
199 208 * Admin notices.
200 209 *
201 210 * @return void
211 + * @deprecated 5.1.0
202 212 */
203 213 public function admin_notices() {
214 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::admin_notices', '5.1.0' );
215 +
204 216 if ( ! $this->is_synonym_page() ) {
205 217 return;
206 218 }
207 219
@@ -247,9 +259,9 @@
247 259 'publicly_queryable' => false,
248 260 'show_ui' => false,
249 261 'show_in_menu' => false,
250 262 'query_var' => true,
251 - 'capabilities' => Utils\get_post_map_capabilities(),
263 + 'capabilities' => Utils\get_post_map_capabilities( 'synonyms' ),
252 264 'has_archive' => false,
253 265 'hierarchical' => false,
254 266 'menu_position' => 100,
255 267 'supports' => [ 'title' ],
@@ -308,9 +320,9 @@
308 320 public function get_synonyms() {
309 321 $synonyms_raw = $this->get_synonyms_raw();
310 322 $synonyms = array_values(
311 323 array_filter(
312 - array_map( [ $this, 'validate_synonym' ], explode( PHP_EOL, $synonyms_raw ) )
324 + array_map( [ $this, 'validate_synonym' ], preg_split( '/\r\n|\r|\n/', $synonyms_raw ) )
313 325 )
314 326 );
315 327
316 328 /**
@@ -377,10 +389,10 @@
377 389 return $mapping;
378 390 }
379 391
380 392 // Ensure we have analyzers and that it is an array.
381 - if ( ! isset( $mapping['settings']['analysis']['analyzer']['default']['filter'] )
382 - || ! is_array( $mapping['settings']['analysis']['analyzer']['default']['filter'] )
393 + if ( ! isset( $mapping['settings']['analysis']['analyzer']['default_search']['filter'] )
394 + || ! is_array( $mapping['settings']['analysis']['analyzer']['default_search']['filter'] )
383 395 ) {
384 396 return $mapping;
385 397 }
386 398
@@ -387,12 +399,14 @@
387 399 // Create a custom synonym filter for EP.
388 400 $mapping['settings']['analysis']['filter'][ $filter_name ] = $this->get_synonym_filter();
389 401
390 402 // Tell the analyzer to use our newly created filter.
391 - $mapping['settings']['analysis']['analyzer']['default']['filter'] = array_values(
392 - array_merge(
393 - [ $filter_name ],
394 - $mapping['settings']['analysis']['analyzer']['default']['filter']
403 + $mapping['settings']['analysis']['analyzer']['default_search']['filter'] = $this->maybe_change_filter_position(
404 + array_values(
405 + array_merge(
406 + [ $filter_name ],
407 + $mapping['settings']['analysis']['analyzer']['default_search']['filter'],
408 + )
395 409 )
396 410 );
397 411
398 412 return $mapping;
@@ -401,10 +415,13 @@
401 415 /**
402 416 * Handles updating the synonym list.
403 417 *
404 418 * @return void
419 + * @deprecated 5.1.0
405 420 */
406 421 public function handle_update_synonyms() {
422 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::handle_update_synonyms', '5.1.0' );
423 +
407 424 $nonce = filter_input( INPUT_POST, $this->get_nonce_field(), FILTER_SANITIZE_SPECIAL_CHARS );
408 425 $referer = filter_input( INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_URL );
409 426 $post_id = false;
410 427 $update = false;
@@ -459,13 +476,18 @@
459 476 */
460 477 public function update_synonyms() {
461 478 return array_reduce(
462 479 $this->get_affected_indices(),
463 - function( $success, $index ) {
480 + function ( $success, $index ) {
464 481 $filter = $this->get_synonym_filter();
465 482 $mapping = Elasticsearch::factory()->get_mapping( $index );
466 - $filters = $mapping[ $index ]['settings']['index']['analysis']['analyzer']['default']['filter'];
467 483
484 + if ( empty( $mapping ) || empty( $mapping[ $index ] ) ) {
485 + return false;
486 + }
487 +
488 + $filters = (array) $mapping[ $index ]['settings']['index']['analysis']['analyzer']['default_search']['filter'];
489 +
468 490 /*
469 491 * Due to limitations in Elasticsearch, we can't remove the filter and analyzer
470 492 * once set on the index settings and synonyms array can't be empty. So we set a
471 493 * fallback synonyms array here if the user supplied synonym array is empty.
@@ -477,13 +499,15 @@
477 499 // Construct the synonym filter.
478 500 $setting['index']['analysis']['filter']['ep_synonyms_filter'] = $filter;
479 501
480 502 // Add the analyzer.
481 - $setting['index']['analysis']['analyzer']['default']['filter'] = array_values(
482 - array_unique(
483 - array_merge(
484 - [ $this->get_synonym_filter_name() ],
485 - $filters
503 + $setting['index']['analysis']['analyzer']['default_search']['filter'] = $this->maybe_change_filter_position(
504 + array_values(
505 + array_unique(
506 + array_merge(
507 + [ $this->get_synonym_filter_name() ],
508 + $filters
509 + )
486 510 )
487 511 )
488 512 );
489 513
@@ -509,9 +533,9 @@
509 533 $indices = apply_filters( 'ep_synonyms_affected_indices', $this->affected_indices );
510 534
511 535 return array_filter(
512 536 array_map(
513 - function( $index ) {
537 + function ( $index ) {
514 538 $indexable = Indexables::factory()->get( $index );
515 539 return $indexable ? $indexable->get_index_name() : false;
516 540 },
517 541 $indices
@@ -560,10 +584,13 @@
560 584 * Get form action for admin page.
561 585 *
562 586 * @access protected
563 587 * @return string The admin post form action url.
588 + * @deprecated 5.1.0
564 589 */
565 590 public function get_form_action() {
591 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0' );
592 +
566 593 return esc_url_raw( admin_url( 'admin-post.php' ) );
567 594 }
568 595
569 596 /**
@@ -569,10 +596,13 @@
569 596 /**
570 597 * Render admin page form hidden fields.
571 598 *
572 599 * @return void
600 + * @deprecated 5.1.0
573 601 */
574 602 public function form_hidden_fields() {
603 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0', );
604 +
575 605 wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_field() );
576 606 ?>
577 607 <input type="hidden" name="action" value="<?php echo esc_attr( $this->get_action() ); ?>" />
578 608 <?php
@@ -581,10 +611,13 @@
581 611 /**
582 612 * Get nonce action for admin page form.
583 613 *
584 614 * @return string
615 + * @deprecated 5.1.0
585 616 */
586 617 public function get_nonce_action() {
618 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0', );
619 +
587 620 return $this->get_action();
588 621 }
589 622
590 623 /**
@@ -590,10 +623,13 @@
590 623 /**
591 624 * Get nonce field for admin page form.
592 625 *
593 626 * @return string
627 + * @deprecated 5.1.0
594 628 */
595 629 public function get_nonce_field() {
630 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_nonce_field', '5.1.0', );
631 +
596 632 return 'ep_synonyms_nonce';
597 633 }
598 634
599 635 /**
@@ -599,10 +635,13 @@
599 635 /**
600 636 * Get synonym field name for admin page form.
601 637 *
602 638 * @return string
639 + * @deprecated 5.1.0
603 640 */
604 641 public function get_synonym_field() {
642 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_synonym_field', '5.1.0', );
643 +
605 644 return 'ep_synonyms';
606 645 }
607 646
608 647 /**
@@ -608,10 +647,13 @@
608 647 /**
609 648 * Get the action slug for admin page form.
610 649 *
611 650 * @return string
651 + * @deprecated 5.1.0
612 652 */
613 653 public function get_action() {
654 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_action', '5.1.0', );
655 +
614 656 return 'ep_synonyms_update';
615 657 }
616 658
617 659 /**
@@ -635,13 +677,18 @@
635 677 * @return string
636 678 */
637 679 public function example_synonym_list( $as_array = false ) {
638 680 $lines = [
639 - __( '# Defined sets (equivalent synonyms).', 'elasticpress' ),
640 - 'sneakers, tennis shoes, trainers, runners',
681 + __( '# Defined synonyms.', 'elasticpress' ),
682 + 'runner, running shoe, sneaker, tennis shoe, trainer',
641 683 '',
642 - __( '# Defined alternatives (explicit mappings).', 'elasticpress' ),
643 - 'shoes => sneaker, sandal, boots, high heels',
684 + __( '# Defined hyponyms.', 'elasticpress' ),
685 + 'blue => blue, aqua, azure, cerulean, cyan, ultramarine',
686 + '',
687 + __( '# Defined replacements.', 'elasticpress' ),
688 + 'supposably => supposedly',
689 + 'flustrated => flustered, frustrated',
690 + 'intensive purposes => intents and purposes',
644 691 ];
645 692
646 693 return $as_array ? $lines : implode( PHP_EOL, $lines );
647 694 }
@@ -649,10 +696,13 @@
649 696 /**
650 697 * Gets localized strings for use on the front end.
651 698 *
652 699 * @return array
700 + * @deprecated 5.1.0
653 701 */
654 702 public function get_localized_strings() {
703 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_localized_strings', '5.1.0' );
704 +
655 705 return array(
656 706 'pageHeading' => __( 'Manage Synonyms', 'elasticpress' ),
657 707 'pageDescription' => __( 'Synonyms enable more flexible search results that show relevant results even without an exact match. Synonyms can be defined as a sets where all words are synonyms for each other, or as alternatives where searches for the primary word will also match the rest, but no vice versa.', 'elasticpress' ),
658 708 'pageToggleAdvanceText' => __( 'Switch to Advanced Text Editor', 'elasticpress' ),
@@ -687,10 +737,13 @@
687 737 /**
688 738 * Get data to export to the frontend with localization strings.
689 739 *
690 740 * @return array
741 + * @deprecated 5.1.0
691 742 */
692 743 public function get_localized_data() {
744 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_localized_strings', '5.1.0' );
745 +
693 746 $data = array(
694 747 'sets' => array(),
695 748 'alternatives' => array(),
696 749 'initialMode' => $this->synonyms_editor_mode(),
@@ -771,10 +824,13 @@
771 824 *
772 825 * @param string $token The synonym token to prepare.
773 826 * @param boolean $primary Whether this string is the primary term of an alternative.
774 827 * @return array
828 + * @deprecated 5.1.0
775 829 */
776 830 public static function prepare_localized_token( $token, $primary = false ) {
831 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::prepare_localized_token', '5.1.0' );
832 +
777 833 return array(
778 834 'label' => trim( sanitize_text_field( $token ) ),
779 835 'value' => trim( sanitize_text_field( $token ) ),
780 836 'primary' => $primary,
@@ -801,9 +857,9 @@
801 857 *
802 858 * @param string $content The content post.
803 859 * @return int|WP_Error
804 860 */
805 - private function update_synonym_post( $content ) {
861 + public function update_synonym_post( $content ) {
806 862 $synonym_post_id = $this->get_synonym_post_id();
807 863
808 864 if ( ! $synonym_post_id ) {
809 865 return $synonym_post_id;
@@ -816,6 +872,34 @@
816 872 'post_type' => self::POST_TYPE_NAME,
817 873 ],
818 874 true
819 875 );
876 + }
877 +
878 + /**
879 + * Setup REST endpoints
880 + *
881 + * @since 5.1.0
882 + */
883 + public function setup_endpoint() {
884 + $controller = new REST\Synonyms();
885 + $controller->register_routes();
886 + }
887 +
888 + /**
889 + * Change the position of the lowercase filter to the beginning of the array.
890 + *
891 + * @since 5.1.0
892 + * @param array $filters Array of filters.
893 + * @return array
894 + */
895 + protected function maybe_change_filter_position( array $filters ): array {
896 + $lowercase_filter = array_search( 'lowercase', $filters, true );
897 +
898 + if ( false !== $lowercase_filter ) {
899 + unset( $filters[ $lowercase_filter ] );
900 + array_unshift( $filters, 'lowercase' );
901 + }
902 +
903 + return $filters;
820 904 }
821 905 }