PluginProbe
ElasticPress / 4.6.1
ElasticPress v4.6.1
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
elasticpress / includes / classes / Feature / Search / Synonyms.php

Synonyms.php in ElasticPress 4.6.1, at includes/classes/Feature/Search/Synonyms.php

823 lines 21.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Synonyms Feature
4 *
5 * @package elasticpress
6 */
7
8 namespace ElasticPress\Feature\Search;
9
10 use ElasticPress\Feature;
11 use ElasticPress\Features;
12 use ElasticPress\Indexables;
13 use ElasticPress\Elasticsearch;
14 use ElasticPress\FeatureRequirementsStatus;
15 use ElasticPress\Utils as Utils;
16
17 if ( ! defined( 'ABSPATH' ) ) {
18 exit; // Exit if accessed directly.
19 }
20
21 /**
22 * Synonyms Feature
23 *
24 * @since 3.4
25 * @package ElasticPress\Feature\Synonyms
26 */
27 class Synonyms {
28
29 /**
30 * Internal name of the post type
31 */
32 const POST_TYPE_NAME = 'ep-synonym';
33
34 /**
35 * Indices that should receive the synonym filter.
36 *
37 * @var array
38 */
39 public $affected_indices;
40
41 /**
42 * Elasticsearch Synonym Filter Name
43 *
44 * @var string
45 */
46 public $filter_name;
47
48 /**
49 * Synonym post id.
50 *
51 * @var int
52 */
53 protected $synonym_post_id;
54
55 /**
56 * Initialize feature setting it's config
57 *
58 * @since 3.4
59 */
60 public function __construct() {
61 $this->filter_name = 'ep_synonyms_filter';
62 $this->affected_indices = [ 'post' ];
63 }
64
65 /**
66 * Get search feature.
67 *
68 * @return Search
69 */
70 public function get_search_feature() {
71 /** Features Class @var Features $features */
72 $features = Features::factory();
73
74 /** Search Feature @var Feature\Search\Search $search */
75 return $features->get_registered_feature( 'search' );
76 }
77
78 /**
79 * Returns requirements status of feature
80 *
81 * Requires the search feature to be activated
82 *
83 * @return FeatureRequirementsStatus
84 */
85 public function requirements_status() {
86 $search = $this->get_search_feature();
87
88 if ( ! $search->is_active() ) {
89 return new FeatureRequirementsStatus( 2, esc_html__( 'This feature requires the "Post Search" feature to be enabled', 'elasticpress' ) );
90 }
91
92 return new FeatureRequirementsStatus( 0 );
93 }
94
95 /**
96 * Setup Feature Functionality
97 *
98 * @return bool
99 */
100 public function setup() {
101 if ( (bool) $this->requirements_status()->code ) {
102 return false;
103 }
104
105 // Register a post type to hold the synonyms post.
106 add_action( 'init', [ $this, 'register_post_type' ] );
107
108 // Setup the UI.
109 add_action( 'admin_menu', [ $this, 'admin_menu' ], 50 );
110 add_action( 'admin_enqueue_scripts', [ $this, 'scripts' ] );
111
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 // Add the synonyms to the elasticsearch query.
120 add_filter( 'ep_config_mapping', [ $this, 'add_search_synonyms' ], 20, 2 );
121
122 return true;
123 }
124
125 /**
126 * Enqueues scripts and styles.
127 *
128 * @return void
129 */
130 public function scripts() {
131 if ( ! $this->is_synonym_page() ) {
132 return;
133 }
134
135 wp_enqueue_script(
136 'ep_synonyms_scripts',
137 EP_URL . 'dist/js/synonyms-script.js',
138 Utils\get_asset_info( 'synonyms-script', 'dependencies' ),
139 Utils\get_asset_info( 'synonyms-script', 'version' ),
140 true
141 );
142
143 wp_set_script_translations( 'ep_synonyms_scripts', 'elasticpress' );
144
145 wp_enqueue_style( 'wp-edit-post' );
146
147 wp_enqueue_style(
148 'ep_synonyms_styles',
149 EP_URL . 'dist/css/synonyms-styles.css',
150 Utils\get_asset_info( 'synonyms-styles', 'dependencies' ),
151 Utils\get_asset_info( 'synonyms-styles', 'version' ),
152 'all'
153 );
154
155 wp_localize_script(
156 'ep_synonyms_scripts',
157 'epSynonyms',
158 array(
159 'i18n' => $this->get_localized_strings(),
160 'data' => $this->get_localized_data(),
161 )
162 );
163 }
164
165 /**
166 * Adds the synonyms settings page to the admin menu.
167 *
168 * @return void
169 */
170 public function admin_menu() {
171 add_submenu_page(
172 'elasticpress',
173 esc_html__( 'ElasticPress Synonyms', 'elasticpress' ),
174 esc_html__( 'Synonyms', 'elasticpress' ),
175 Utils\get_capability(),
176 'elasticpress-synonyms',
177 [ $this, 'admin_page' ]
178 );
179 }
180
181 /**
182 * Renders the synonyms settings page.
183 *
184 * @return void
185 */
186 public function admin_page() {
187 include EP_PATH . '/includes/partials/header.php';
188
189 ?>
190 <div class="wrap">
191 <form action="<?php echo esc_url( $this->get_form_action() ); ?>" method="POST">
192 <?php $this->form_hidden_fields(); ?>
193 <div id="synonym-root"></div>
194 </form>
195 </div>
196 <?php
197 }
198
199 /**
200 * Admin notices.
201 *
202 * @return void
203 */
204 public function admin_notices() {
205 if ( ! $this->is_synonym_page() ) {
206 return;
207 }
208
209 $update = filter_input( INPUT_GET, 'ep_synonym_update', FILTER_SANITIZE_SPECIAL_CHARS );
210
211 if ( ! in_array( $update, [ 'success', 'error-update-post', 'error-update-index' ], true ) ) {
212 return;
213 }
214
215 $class = ( 'success' === $update ? 'notice-success' : 'notice-error' ) . ' notice';
216 $message = '';
217
218 switch ( $update ) {
219 case 'success':
220 $message = __( 'Successfully updated synonym filter.', 'elasticpress' );
221 break;
222 case 'error-update-post':
223 $message = __( 'There was an error storing your synonyms.', 'elasticpress' );
224 break;
225 case 'error-update-index':
226 $message = __( 'There was a problem updating the index with your synonyms. If you have not indexed your data, please run an index.', 'elasticpress' );
227 break;
228 default:
229 $message = __( 'There was an error updating the synonym list.', 'elasticpress' );
230 }
231
232 printf(
233 '<div class="%1$s"><p>%2$s</p></div>',
234 esc_attr( $class ),
235 esc_html( $message )
236 );
237 }
238
239 /**
240 * Registers a post type for our synonyms post storage.
241 *
242 * @return void
243 */
244 public function register_post_type() {
245 $args = [
246 'description' => esc_html__( 'Elasticsearch Synonyms', 'elasticpress' ),
247 'public' => false,
248 'publicly_queryable' => false,
249 'show_ui' => false,
250 'show_in_menu' => false,
251 'query_var' => true,
252 'capabilities' => Utils\get_post_map_capabilities(),
253 'has_archive' => false,
254 'hierarchical' => false,
255 'menu_position' => 100,
256 'supports' => [ 'title' ],
257 ];
258
259 register_post_type( self::POST_TYPE_NAME, $args );
260 }
261
262 /**
263 * Get the post id of the post holding our synonyms.
264 *
265 * @return int The synonym post ID.
266 */
267 public function get_synonym_post_id() {
268 if ( ! $this->synonym_post_id ) {
269 $query_synonym_post = new \WP_Query(
270 array(
271 'fields' => 'ids',
272 'post_type' => self::POST_TYPE_NAME,
273 'posts_per_page' => 1,
274 'orderby' => 'modified',
275 'post_status' => 'any',
276 )
277 );
278
279 $this->synonym_post_id = ( $query_synonym_post->post_count >= 1 ) ? $query_synonym_post->posts[0] : false;
280
281 if ( ! $this->synonym_post_id ) {
282 $this->synonym_post_id = $this->insert_default_synonym_post();
283 }
284 }
285
286 return $this->synonym_post_id;
287 }
288
289 /**
290 * Get synonyms in their raw format.
291 *
292 * @return string
293 */
294 public function get_synonyms_raw() {
295 $post = get_post( $this->get_synonym_post_id() );
296
297 if ( ! $post ) {
298 return '';
299 }
300
301 return $post->post_content;
302 }
303
304 /**
305 * Get an array of user defined synonyms.
306 *
307 * @return array
308 */
309 public function get_synonyms() {
310 $synonyms_raw = $this->get_synonyms_raw();
311 $synonyms = array_values(
312 array_filter(
313 array_map( [ $this, 'validate_synonym' ], explode( PHP_EOL, $synonyms_raw ) )
314 )
315 );
316
317 /**
318 * Filter array of synonyms to add to a custom synonym filter.
319 *
320 * @hook ep_synonyms
321 * @return {array} The new array of search synonyms.
322 */
323 return apply_filters( 'ep_synonyms', $synonyms );
324 }
325
326 /**
327 * Validate a synonym.
328 *
329 * @link https://www.elastic.co/guide/en/elasticsearch/reference/current/analysis-synonym-tokenfilter.html#_solr_synonyms
330 * @param string $synonym The synonym.
331 * @return string|boolean String synonym if valid, boolean false if validation failed.
332 */
333 public function validate_synonym( $synonym ) {
334 // Don't use empty lines.
335 if ( empty( trim( $synonym ) ) ) {
336 return false;
337 }
338
339 // Don't use lines that start with "#", those are comments.
340 if ( 0 === strpos( $synonym, '#' ) ) {
341 return false;
342 }
343
344 // Don't use lines that start with "//" though not in Solr spec.
345 if ( 0 === strpos( $synonym, '//' ) ) {
346 return false;
347 }
348
349 return sanitize_text_field( $synonym, true );
350 }
351
352 /**
353 * Add search synonyms.
354 *
355 * @param array $mapping Elasticsearch mapping.
356 * @param string $index Index name.
357 * @return array
358 */
359 public function add_search_synonyms( $mapping, $index ) {
360 $synonyms = $this->get_synonyms();
361 $indices = $this->get_affected_indices();
362 $filter_name = $this->get_synonym_filter_name();
363
364 // Ensure we should affect this mapping.
365 if ( ! in_array( $index, $indices, true ) ) {
366 return $mapping;
367 }
368
369 // Ensure we have synonyms to add.
370 if ( ! is_array( $synonyms ) || empty( $synonyms ) ) {
371 return $mapping;
372 }
373
374 // Ensure we have filters and that it is an array.
375 if ( ! isset( $mapping['settings']['analysis']['filter'] )
376 || ! is_array( $mapping['settings']['analysis']['filter'] )
377 ) {
378 return $mapping;
379 }
380
381 // Ensure we have analyzers and that it is an array.
382 if ( ! isset( $mapping['settings']['analysis']['analyzer']['default']['filter'] )
383 || ! is_array( $mapping['settings']['analysis']['analyzer']['default']['filter'] )
384 ) {
385 return $mapping;
386 }
387
388 // Create a custom synonym filter for EP.
389 $mapping['settings']['analysis']['filter'][ $filter_name ] = $this->get_synonym_filter();
390
391 // Tell the analyzer to use our newly created filter.
392 $mapping['settings']['analysis']['analyzer']['default']['filter'] = array_values(
393 array_merge(
394 [ $filter_name ],
395 $mapping['settings']['analysis']['analyzer']['default']['filter']
396 )
397 );
398
399 return $mapping;
400 }
401
402 /**
403 * Handles updating the synonym list.
404 *
405 * @return void
406 */
407 public function handle_update_synonyms() {
408 $nonce = filter_input( INPUT_POST, $this->get_nonce_field(), FILTER_SANITIZE_SPECIAL_CHARS );
409 $referer = filter_input( INPUT_POST, '_wp_http_referer', FILTER_SANITIZE_URL );
410 $post_id = false;
411 $update = false;
412
413 if ( wp_verify_nonce( $nonce, $this->get_nonce_action() ) ) {
414 $synonyms = filter_input( INPUT_POST, $this->get_synonym_field(), FILTER_CALLBACK, [ 'options' => 'wp_strip_all_tags' ] );
415 $mode = filter_input( INPUT_POST, 'synonyms_editor_mode', FILTER_SANITIZE_SPECIAL_CHARS );
416 $content = trim( sanitize_textarea_field( $synonyms ) );
417
418 // Content can't be empty.
419 if ( empty( $content ) ) {
420 $lines = $this->example_synonym_list( true );
421 $content = implode( PHP_EOL, [ $lines[0], $lines[2], $lines[3] ] );
422 }
423
424 $post_id = $this->update_synonym_post( $content );
425
426 // Update Elasticsearch
427 $update = $this->update_synonyms();
428
429 // Save editor mode.
430 if ( in_array( $mode, [ 'advanced', 'simple' ], true ) ) {
431 $this->save_editor_mode( $mode );
432 }
433 }
434
435 $result = 'success';
436
437 if ( ! $post_id || is_wp_error( $post_id ) ) {
438 $result = 'error-update-post';
439 }
440
441 if ( ! $update ) {
442 $result = 'error-update-index';
443 }
444
445 wp_safe_redirect(
446 add_query_arg(
447 [
448 'ep_synonym_update' => $result,
449 ],
450 esc_url_raw( $referer )
451 )
452 );
453 exit;
454 }
455
456 /**
457 * Update synonyms.
458 *
459 * @return boolean
460 */
461 public function update_synonyms() {
462 return array_reduce(
463 $this->get_affected_indices(),
464 function( $success, $index ) {
465 $filter = $this->get_synonym_filter();
466 $mapping = Elasticsearch::factory()->get_mapping( $index );
467 $filters = $mapping[ $index ]['settings']['index']['analysis']['analyzer']['default']['filter'];
468
469 /*
470 * Due to limitations in Elasticsearch, we can't remove the filter and analyzer
471 * once set on the index settings and synonyms array can't be empty. So we set a
472 * fallback synonyms array here if the user supplied synonym array is empty.
473 */
474 if ( empty( $filter['synonyms'] ) ) {
475 $filter['synonyms'] = [ 'odd,unusual' ];
476 }
477
478 // Construct the synonym filter.
479 $setting['index']['analysis']['filter']['ep_synonyms_filter'] = $filter;
480
481 // Add the analyzer.
482 $setting['index']['analysis']['analyzer']['default']['filter'] = array_values(
483 array_unique(
484 array_merge(
485 [ $this->get_synonym_filter_name() ],
486 $filters
487 )
488 )
489 );
490
491 // Put it to Elasticsearch.
492 $update = Elasticsearch::factory()->update_index_settings( $index, $setting, true );
493 return $success ? $update : false;
494 },
495 true
496 );
497 }
498
499 /**
500 * Get affected indices.
501 *
502 * @return array
503 */
504 public function get_affected_indices() {
505 /**
506 * Filter the indices that use the synonym filter.
507 *
508 * @return array Array of index names.
509 */
510 $indices = apply_filters( 'ep_synonyms_affected_indices', $this->affected_indices );
511
512 return array_filter(
513 array_map(
514 function( $index ) {
515 $indexable = Indexables::factory()->get( $index );
516 return $indexable ? $indexable->get_index_name() : false;
517 },
518 $indices
519 )
520 );
521 }
522
523 /**
524 * Get synonym filter name.
525 *
526 * @return string
527 */
528 public function get_synonym_filter_name() {
529 /**
530 * Filter name of the synonym filter set in elasticsearch.
531 *
532 * @hook ep_synonyms_filter_name
533 * @return {string} The name of the synonyms filter.
534 */
535 return apply_filters( 'ep_synonyms_filter_name', $this->filter_name );
536 }
537
538 /**
539 * Get synonym filter.
540 *
541 * @return array
542 */
543 public function get_synonym_filter() {
544 /**
545 * Filter the synonym filter set in elasticsearch.
546 *
547 * @hook ep_synonyms_filter
548 * @return {array} The synonym search filter.
549 */
550 return apply_filters(
551 'ep_synonyms_filter',
552 [
553 'type' => 'synonym_graph',
554 'lenient' => true,
555 'synonyms' => $this->get_synonyms(),
556 ]
557 );
558 }
559
560 /**
561 * Get form action for admin page.
562 *
563 * @access protected
564 * @return string The admin post form action url.
565 */
566 public function get_form_action() {
567 return esc_url_raw( admin_url( 'admin-post.php' ) );
568 }
569
570 /**
571 * Render admin page form hidden fields.
572 *
573 * @return void
574 */
575 public function form_hidden_fields() {
576 wp_nonce_field( $this->get_nonce_action(), $this->get_nonce_field() );
577 ?>
578 <input type="hidden" name="action" value="<?php echo esc_attr( $this->get_action() ); ?>" />
579 <?php
580 }
581
582 /**
583 * Get nonce action for admin page form.
584 *
585 * @return string
586 */
587 public function get_nonce_action() {
588 return $this->get_action();
589 }
590
591 /**
592 * Get nonce field for admin page form.
593 *
594 * @return string
595 */
596 public function get_nonce_field() {
597 return 'ep_synonyms_nonce';
598 }
599
600 /**
601 * Get synonym field name for admin page form.
602 *
603 * @return string
604 */
605 public function get_synonym_field() {
606 return 'ep_synonyms';
607 }
608
609 /**
610 * Get the action slug for admin page form.
611 *
612 * @return string
613 */
614 public function get_action() {
615 return 'ep_synonyms_update';
616 }
617
618 /**
619 * Is this our synonym page.
620 *
621 * @return boolean
622 */
623 public function is_synonym_page() {
624 if ( ! function_exists( '\get_current_screen' ) ) {
625 return false;
626 }
627
628 $screen = get_current_screen();
629 return ( 'elasticpress_page_elasticpress-synonyms' === $screen->base );
630 }
631
632 /**
633 * An example synonym that we initialize new synonyms lists with.
634 *
635 * @param bool $as_array Optional. Return an array of synonym lines. Default false.
636 * @return string
637 */
638 public function example_synonym_list( $as_array = false ) {
639 $lines = [
640 __( '# Defined sets (equivalent synonyms).', 'elasticpress' ),
641 'sneakers, tennis shoes, trainers, runners',
642 '',
643 __( '# Defined alternatives (explicit mappings).', 'elasticpress' ),
644 'shoes => sneaker, sandal, boots, high heels',
645 ];
646
647 return $as_array ? $lines : implode( PHP_EOL, $lines );
648 }
649
650 /**
651 * Gets localized strings for use on the front end.
652 *
653 * @return array
654 */
655 public function get_localized_strings() {
656 return array(
657 'pageHeading' => __( 'Manage Synonyms', 'elasticpress' ),
658 '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' ),
659 'pageToggleAdvanceText' => __( 'Switch to Advanced Text Editor', 'elasticpress' ),
660 'pageToggleSimpleText' => __( 'Switch to Visual Editor', 'elasticpress' ),
661
662 'setsTitle' => __( 'Sets', 'elasticpress' ),
663 'setsDescription' => __( 'Sets are terms that will all match each other for search results. This is useful where all words are considered equivalent, such as product renaming or regional variations like sneakers, tennis shoes, trainers, and runners.', 'elasticpress' ),
664 'setsInputHeading' => __( 'Comma separated list of terms', 'elasticpress' ),
665 'setsAddButtonText' => __( 'Add Set', 'elasticpress' ),
666 'setsErrorMessage' => __( 'This set must contain at least 2 terms.', 'elasticpress' ),
667
668 'alternativesTitle' => __( 'Alternatives', 'elasticpress' ),
669 'alternativesDescription' => __( 'Alternatives are terms that will also be matched when you search for the primary term. For instance, a search for shoes can also include results for sneaker, sandals, boots, and high heels.', 'elasticpress' ),
670 'alternativesPrimaryHeading' => __( 'Primary term', 'elasticpress' ),
671 'alternativesInputHeading' => __( 'Comma separated list of alternatives', 'elasticpress' ),
672 'alternativesAddButtonText' => __( 'Add Alternative', 'elasticpress' ),
673 'alternativesErrorMessage' => __( 'You must enter both a primary term and at least one alternative term.', 'elasticpress' ),
674
675 'solrTitle' => __( 'Advanced Synonym Editor', 'elasticpress' ),
676 'solrDescription' => __( 'When you add Sets and Alternatives above, we reduce them to SolrSynonyms which Elasticsearch can understand. If you are an advanced user, you can edit synonyms directly using Solr synonym formatting. This is beneficial if you want to import a large dictionary of synonyms, or want to export this site\'s synonyms for use on another site.', 'elasticpress' ),
677 'solrInputHeading' => __( 'SolrSynonym Text', 'elasticpress' ),
678 'solrAlternativesErrorMessage' => __( 'Alternatives must have both a primary term and at least one alternative term.', 'elasticpress' ),
679 'solrSetsErrorMessage' => __( 'Sets must contain at least 2 terms.', 'elasticpress' ),
680
681 'removeItemText' => __( 'Remove', 'elasticpress' ),
682 'submitText' => __( 'Update Synonyms', 'elasticpress' ),
683
684 'synonymsTextareaInputName' => $this->get_synonym_field(),
685 );
686 }
687
688 /**
689 * Get data to export to the frontend with localization strings.
690 *
691 * @return array
692 */
693 public function get_localized_data() {
694 $data = array(
695 'sets' => array(),
696 'alternatives' => array(),
697 'initialMode' => $this->synonyms_editor_mode(),
698 );
699 $synonyms = $this->get_synonyms();
700
701 foreach ( $synonyms as $line ) {
702 $synonym = array();
703 if ( strpos( $line, '=>' ) ) {
704 $tokens = explode( '=>', $line );
705 array_push( $synonym, self::prepare_localized_token( $tokens[0], true ) );
706 array_push(
707 $synonym,
708 ...array_map(
709 array( __CLASS__, 'prepare_localized_token' ),
710 explode( ',', $tokens[1] )
711 )
712 );
713 array_push( $data['alternatives'], $synonym );
714 } else {
715 array_push(
716 $synonym,
717 ...array_map(
718 array( __CLASS__, 'prepare_localized_token' ),
719 explode( ',', $line )
720 )
721 );
722 array_push( $data['sets'], $synonym );
723 }
724 }
725
726 return $data;
727 }
728
729 /**
730 * Saves the editor mode.
731 *
732 * @param string $mode The mode, one of "advanced" or "simple".
733 * @return void
734 */
735 public function save_editor_mode( $mode ) {
736 $search = $this->get_search_feature();
737 $settings = $search->get_settings();
738
739 if ( isset( $settings['synonyms_editor_mode'] ) && $settings['synonyms_editor_mode'] === $mode ) {
740 return;
741 }
742
743 $settings['synonyms_editor_mode'] = $mode;
744 $features = Features::factory();
745 $features->update_feature( $search->slug, $settings, false );
746 }
747
748 /**
749 * Get the stored editor mode. Default simple.
750 *
751 * @return boolean
752 */
753 public function synonyms_editor_mode() {
754 $search = $this->get_search_feature();
755 $settings = $search->get_settings();
756 $settings = wp_parse_args( is_array( $settings ) ? $settings : [], $search->default_settings );
757 $mode = $settings['synonyms_editor_mode'];
758
759 /**
760 * Filter the default synonyms editor mode.
761 *
762 * @hook ep_synonyms_editor_mode
763 * @return {string} One of 'simple' or 'advanced'.
764 */
765 $filtered = apply_filters( 'ep_synonyms_editor_mode', $mode );
766
767 return in_array( $filtered, [ 'simple', 'advanced' ], true ) ? $filtered : 'simple';
768 }
769
770 /**
771 * Prepare localized token.
772 *
773 * @param string $token The synonym token to prepare.
774 * @param boolean $primary Whether this string is the primary term of an alternative.
775 * @return array
776 */
777 public static function prepare_localized_token( $token, $primary = false ) {
778 return array(
779 'label' => trim( sanitize_text_field( $token ) ),
780 'value' => trim( sanitize_text_field( $token ) ),
781 'primary' => $primary,
782 );
783 }
784
785 /**
786 * Insert default synonym post
787 *
788 * @return int|WP_Error
789 */
790 private function insert_default_synonym_post() {
791 return wp_insert_post(
792 [
793 'post_content' => $this->example_synonym_list(),
794 'post_type' => self::POST_TYPE_NAME,
795 ],
796 true
797 );
798 }
799
800 /**
801 * Update synonym post
802 *
803 * @param string $content The content post.
804 * @return int|WP_Error
805 */
806 private function update_synonym_post( $content ) {
807 $synonym_post_id = $this->get_synonym_post_id();
808
809 if ( ! $synonym_post_id ) {
810 return $synonym_post_id;
811 }
812
813 return wp_insert_post(
814 [
815 'ID' => $synonym_post_id,
816 'post_content' => $content,
817 'post_type' => self::POST_TYPE_NAME,
818 ],
819 true
820 );
821 }
822 }
823