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 +132 -46 4.2.25.3.5 View file →
@@ -6,14 +6,14 @@
6 6 */
7 7
8 8 namespace ElasticPress\Feature\Search;
9 9
10 -use ElasticPress\Feature;
10 +use ElasticPress\Elasticsearch;
11 +use ElasticPress\FeatureRequirementsStatus;
11 12 use ElasticPress\Features;
12 13 use ElasticPress\Indexables;
13 -use ElasticPress\Elasticsearch;
14 -use ElasticPress\FeatureRequirementsStatus;
15 -use ElasticPress\Utils as Utils;
14 +use ElasticPress\REST;
15 +use ElasticPress\Utils;
16 16
17 17 if ( ! defined( 'ABSPATH' ) ) {
18 18 exit; // Exit if accessed directly.
19 19 }
@@ -82,15 +82,17 @@
82 82 *
83 83 * @return FeatureRequirementsStatus
84 84 */
85 85 public function requirements_status() {
86 + $status = new FeatureRequirementsStatus( 0, null, $this );
86 87 $search = $this->get_search_feature();
87 88
88 89 if ( ! $search->is_active() ) {
89 - 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' );
90 92 }
91 93
92 - return new FeatureRequirementsStatus( 0 );
94 + return $status;
93 95 }
94 96
95 97 /**
96 98 * Setup Feature Functionality
@@ -97,9 +99,9 @@
97 99 *
98 100 * @return bool
99 101 */
100 102 public function setup() {
101 - if ( (bool) $this->requirements_status()->code ) {
103 + if ( (bool) $this->requirements_status()->get_code() ) {
102 104 return false;
103 105 }
104 106
105 107 // Register a post type to hold the synonyms post.
@@ -108,18 +110,14 @@
108 110 // Setup the UI.
109 111 add_action( 'admin_menu', [ $this, 'admin_menu' ], 50 );
110 112 add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
111 113
112 - // Handle the update synonyms action.
113 - $action = $this->get_action();
114 - add_action( "admin_post_$action", [ $this, 'handle_update_synonyms' ] );
115 -
116 - // Handle the admin notices.
117 - add_action( 'admin_notices', [ $this, 'admin_notices' ] );
118 -
119 114 // Add the synonyms to the elasticsearch query.
120 115 add_filter( 'ep_config_mapping', [ $this, 'add_search_synonyms' ], 20, 2 );
121 116
117 + // Register REST routes.
118 + add_action( 'rest_api_init', [ $this, 'setup_endpoint' ] );
119 +
122 120 return true;
123 121 }
124 122
125 123 /**
@@ -133,31 +131,46 @@
133 131 }
134 132
135 133 wp_enqueue_script(
136 134 'ep_synonyms_scripts',
137 - EP_URL . 'dist/js/synonyms-script.min.js',
135 + EP_URL . 'dist/js/synonyms-script.js',
138 136 Utils\get_asset_info( 'synonyms-script', 'dependencies' ),
139 137 Utils\get_asset_info( 'synonyms-script', 'version' ),
140 138 true
141 139 );
142 140
141 + wp_set_script_translations( 'ep_synonyms_scripts', 'elasticpress' );
142 +
143 143 wp_enqueue_style( 'wp-edit-post' );
144 144
145 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(
146 154 'ep_synonyms_styles',
147 - EP_URL . 'dist/css/synonyms-styles.min.css',
155 + EP_URL . 'dist/css/synonyms-styles.css',
148 156 Utils\get_asset_info( 'synonyms-styles', 'dependencies' ),
149 157 Utils\get_asset_info( 'synonyms-styles', 'version' ),
150 158 'all'
151 159 );
152 160
161 + $api_url = rest_url( 'elasticpress/v1/synonyms' );
162 + $sync_url = Utils\get_sync_url();
163 +
153 164 wp_localize_script(
154 165 'ep_synonyms_scripts',
155 166 'epSynonyms',
156 - array(
157 - 'i18n' => $this->get_localized_strings(),
158 - 'data' => $this->get_localized_data(),
159 - )
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 + ]
160 173 );
161 174 }
162 175
163 176 /**
@@ -169,9 +182,9 @@
169 182 add_submenu_page(
170 183 'elasticpress',
171 184 esc_html__( 'ElasticPress Synonyms', 'elasticpress' ),
172 185 esc_html__( 'Synonyms', 'elasticpress' ),
173 - 'manage_options',
186 + Utils\get_capability( 'synonyms' ),
174 187 'elasticpress-synonyms',
175 188 [ $this, 'admin_page' ]
176 189 );
177 190 }
@@ -185,12 +198,9 @@
185 198 include EP_PATH . '/includes/partials/header.php';
186 199
187 200 ?>
188 201 <div class="wrap">
189 - <form action="<?php echo esc_url( $this->get_form_action() ); ?>" method="POST">
190 - <?php $this->form_hidden_fields(); ?>
191 - <div id="synonym-root"></div>
192 - </form>
202 + <div id="ep-synonyms"></div>
193 203 </div>
194 204 <?php
195 205 }
196 206
@@ -197,10 +207,13 @@
197 207 /**
198 208 * Admin notices.
199 209 *
200 210 * @return void
211 + * @deprecated 5.1.0
201 212 */
202 213 public function admin_notices() {
214 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::admin_notices', '5.1.0' );
215 +
203 216 if ( ! $this->is_synonym_page() ) {
204 217 return;
205 218 }
206 219
@@ -246,9 +259,9 @@
246 259 'publicly_queryable' => false,
247 260 'show_ui' => false,
248 261 'show_in_menu' => false,
249 262 'query_var' => true,
250 - 'capability_type' => 'post',
263 + 'capabilities' => Utils\get_post_map_capabilities( 'synonyms' ),
251 264 'has_archive' => false,
252 265 'hierarchical' => false,
253 266 'menu_position' => 100,
254 267 'supports' => [ 'title' ],
@@ -307,9 +320,9 @@
307 320 public function get_synonyms() {
308 321 $synonyms_raw = $this->get_synonyms_raw();
309 322 $synonyms = array_values(
310 323 array_filter(
311 - array_map( [ $this, 'validate_synonym' ], explode( PHP_EOL, $synonyms_raw ) )
324 + array_map( [ $this, 'validate_synonym' ], preg_split( '/\r\n|\r|\n/', $synonyms_raw ) )
312 325 )
313 326 );
314 327
315 328 /**
@@ -376,10 +389,10 @@
376 389 return $mapping;
377 390 }
378 391
379 392 // Ensure we have analyzers and that it is an array.
380 - if ( ! isset( $mapping['settings']['analysis']['analyzer']['default']['filter'] )
381 - || ! 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'] )
382 395 ) {
383 396 return $mapping;
384 397 }
385 398
@@ -386,12 +399,14 @@
386 399 // Create a custom synonym filter for EP.
387 400 $mapping['settings']['analysis']['filter'][ $filter_name ] = $this->get_synonym_filter();
388 401
389 402 // Tell the analyzer to use our newly created filter.
390 - $mapping['settings']['analysis']['analyzer']['default']['filter'] = array_values(
391 - array_merge(
392 - [ $filter_name ],
393 - $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 + )
394 409 )
395 410 );
396 411
397 412 return $mapping;
@@ -400,13 +415,17 @@
400 415 /**
401 416 * Handles updating the synonym list.
402 417 *
403 418 * @return void
419 + * @deprecated 5.1.0
404 420 */
405 421 public function handle_update_synonyms() {
422 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::handle_update_synonyms', '5.1.0' );
423 +
406 424 $nonce = filter_input( INPUT_POST, $this->get_nonce_field(), FILTER_SANITIZE_SPECIAL_CHARS );
407 425 $referer = filter_input( INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_URL );
408 426 $post_id = false;
427 + $update = false;
409 428
410 429 if ( wp_verify_nonce( $nonce, $this->get_nonce_action() ) ) {
411 430 $synonyms = filter_input( INPUT_POST, $this->get_synonym_field(), FILTER_CALLBACK, [ 'options' => 'wp_strip_all_tags' ] );
412 431 $mode = filter_input( INPUT_POST, 'synonyms_editor_mode', FILTER_SANITIZE_SPECIAL_CHARS );
@@ -457,13 +476,18 @@
457 476 */
458 477 public function update_synonyms() {
459 478 return array_reduce(
460 479 $this->get_affected_indices(),
461 - function( $success, $index ) {
480 + function ( $success, $index ) {
462 481 $filter = $this->get_synonym_filter();
463 482 $mapping = Elasticsearch::factory()->get_mapping( $index );
464 - $filters = $mapping[ $index ]['settings']['index']['analysis']['analyzer']['default']['filter'];
465 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 +
466 490 /*
467 491 * Due to limitations in Elasticsearch, we can't remove the filter and analyzer
468 492 * once set on the index settings and synonyms array can't be empty. So we set a
469 493 * fallback synonyms array here if the user supplied synonym array is empty.
@@ -475,13 +499,15 @@
475 499 // Construct the synonym filter.
476 500 $setting['index']['analysis']['filter']['ep_synonyms_filter'] = $filter;
477 501
478 502 // Add the analyzer.
479 - $setting['index']['analysis']['analyzer']['default']['filter'] = array_values(
480 - array_unique(
481 - array_merge(
482 - [ $this->get_synonym_filter_name() ],
483 - $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 + )
484 510 )
485 511 )
486 512 );
487 513
@@ -507,9 +533,9 @@
507 533 $indices = apply_filters( 'ep_synonyms_affected_indices', $this->affected_indices );
508 534
509 535 return array_filter(
510 536 array_map(
511 - function( $index ) {
537 + function ( $index ) {
512 538 $indexable = Indexables::factory()->get( $index );
513 539 return $indexable ? $indexable->get_index_name() : false;
514 540 },
515 541 $indices
@@ -558,10 +584,13 @@
558 584 * Get form action for admin page.
559 585 *
560 586 * @access protected
561 587 * @return string The admin post form action url.
588 + * @deprecated 5.1.0
562 589 */
563 590 public function get_form_action() {
591 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0' );
592 +
564 593 return esc_url_raw( admin_url( 'admin-post.php' ) );
565 594 }
566 595
567 596 /**
@@ -567,10 +596,13 @@
567 596 /**
568 597 * Render admin page form hidden fields.
569 598 *
570 599 * @return void
600 + * @deprecated 5.1.0
571 601 */
572 602 public function form_hidden_fields() {
603 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0', );
604 +
573 605 wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_field() );
574 606 ?>
575 607 <input type="hidden" name="action" value="<?php echo esc_attr( $this->get_action() ); ?>" />
576 608 <?php
@@ -579,10 +611,13 @@
579 611 /**
580 612 * Get nonce action for admin page form.
581 613 *
582 614 * @return string
615 + * @deprecated 5.1.0
583 616 */
584 617 public function get_nonce_action() {
618 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_form_action', '5.1.0', );
619 +
585 620 return $this->get_action();
586 621 }
587 622
588 623 /**
@@ -588,10 +623,13 @@
588 623 /**
589 624 * Get nonce field for admin page form.
590 625 *
591 626 * @return string
627 + * @deprecated 5.1.0
592 628 */
593 629 public function get_nonce_field() {
630 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_nonce_field', '5.1.0', );
631 +
594 632 return 'ep_synonyms_nonce';
595 633 }
596 634
597 635 /**
@@ -597,10 +635,13 @@
597 635 /**
598 636 * Get synonym field name for admin page form.
599 637 *
600 638 * @return string
639 + * @deprecated 5.1.0
601 640 */
602 641 public function get_synonym_field() {
642 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_synonym_field', '5.1.0', );
643 +
603 644 return 'ep_synonyms';
604 645 }
605 646
606 647 /**
@@ -606,10 +647,13 @@
606 647 /**
607 648 * Get the action slug for admin page form.
608 649 *
609 650 * @return string
651 + * @deprecated 5.1.0
610 652 */
611 653 public function get_action() {
654 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_action', '5.1.0', );
655 +
612 656 return 'ep_synonyms_update';
613 657 }
614 658
615 659 /**
@@ -633,13 +677,18 @@
633 677 * @return string
634 678 */
635 679 public function example_synonym_list( $as_array = false ) {
636 680 $lines = [
637 - __( '# Defined sets ( equivalent synonyms).', 'elasticpress' ),
638 - 'sneakers, tennis shoes, trainers, runners',
681 + __( '# Defined synonyms.', 'elasticpress' ),
682 + 'runner, running shoe, sneaker, tennis shoe, trainer',
639 683 '',
640 - __( '# Defined alternatives (explicit mappings).', 'elasticpress' ),
641 - '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',
642 691 ];
643 692
644 693 return $as_array ? $lines : implode( PHP_EOL, $lines );
645 694 }
@@ -647,10 +696,13 @@
647 696 /**
648 697 * Gets localized strings for use on the front end.
649 698 *
650 699 * @return array
700 + * @deprecated 5.1.0
651 701 */
652 702 public function get_localized_strings() {
703 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_localized_strings', '5.1.0' );
704 +
653 705 return array(
654 706 'pageHeading' => __( 'Manage Synonyms', 'elasticpress' ),
655 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' ),
656 708 'pageToggleAdvanceText' => __( 'Switch to Advanced Text Editor', 'elasticpress' ),
@@ -685,10 +737,13 @@
685 737 /**
686 738 * Get data to export to the frontend with localization strings.
687 739 *
688 740 * @return array
741 + * @deprecated 5.1.0
689 742 */
690 743 public function get_localized_data() {
744 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::get_localized_strings', '5.1.0' );
745 +
691 746 $data = array(
692 747 'sets' => array(),
693 748 'alternatives' => array(),
694 749 'initialMode' => $this->synonyms_editor_mode(),
@@ -769,10 +824,13 @@
769 824 *
770 825 * @param string $token The synonym token to prepare.
771 826 * @param boolean $primary Whether this string is the primary term of an alternative.
772 827 * @return array
828 + * @deprecated 5.1.0
773 829 */
774 830 public static function prepare_localized_token( $token, $primary = false ) {
831 + _deprecated_function( 'ElasticPress\Feature\Search\Synonyms::prepare_localized_token', '5.1.0' );
832 +
775 833 return array(
776 834 'label' => trim( sanitize_text_field( $token ) ),
777 835 'value' => trim( sanitize_text_field( $token ) ),
778 836 'primary' => $primary,
@@ -799,9 +857,9 @@
799 857 *
800 858 * @param string $content The content post.
801 859 * @return int|WP_Error
802 860 */
803 - private function update_synonym_post( $content ) {
861 + public function update_synonym_post( $content ) {
804 862 $synonym_post_id = $this->get_synonym_post_id();
805 863
806 864 if ( ! $synonym_post_id ) {
807 865 return $synonym_post_id;
@@ -814,6 +872,34 @@
814 872 'post_type' => self::POST_TYPE_NAME,
815 873 ],
816 874 true
817 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;
818 904 }
819 905 }