PluginProbe
ElasticPress / 4.3.1
ElasticPress v4.3.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.3.1, at includes/classes/Feature/Search/Synonyms.php

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