PluginProbe
ElasticPress / 5.0.1
ElasticPress v5.0.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 / AdminNotices.php

AdminNotices.php in ElasticPress 5.0.1, at includes/classes/AdminNotices.php

901 lines 23.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * ElasticPress admin notice handler
4 *
5 * phpcs:disable WordPress.WP.I18n.MissingTranslatorsComment
6 *
7 * @since 3.0
8 * @package elasticpress
9 */
10
11 namespace ElasticPress;
12
13 use ElasticPress\Utils;
14 use ElasticPress\Elasticsearch;
15 use ElasticPress\Screen;
16 use ElasticPress\Features;
17 use ElasticPress\Indexables;
18 use ElasticPress\Stats;
19
20 if ( ! defined( 'ABSPATH' ) ) {
21 exit; // Exit if accessed directly.
22 }
23
24 /**
25 * Admin notices class
26 */
27 class AdminNotices {
28
29 /**
30 * Notice keys
31 *
32 * @since 3.0
33 * @var array
34 */
35 protected $notice_keys = [
36 'host_error',
37 'es_below_compat',
38 'es_above_compat',
39 'different_server_type',
40 'need_setup',
41 'no_sync',
42 'upgrade_sync',
43 'auto_activate_sync',
44 'using_autosuggest_defaults',
45 'maybe_wrong_mapping',
46 'yellow_health',
47 'too_many_fields',
48 ];
49
50 /**
51 * Notices that should be shown on a screen
52 *
53 * @var array
54 * @since 3.0
55 */
56 protected $notices = [];
57
58 /**
59 * Process all notifications and prepare ones that should be displayed
60 *
61 * @since 3.0
62 */
63 public function process_notices() {
64 $this->notices = [];
65
66 foreach ( $this->notice_keys as $notice ) {
67 $output = call_user_func( [ $this, 'process_' . $notice . '_notice' ] );
68
69 if ( ! empty( $output ) ) {
70 $this->notices[ $notice ] = $output;
71 }
72 }
73 }
74
75 /**
76 * Autosuggest defaults are being used. Feature must be active.
77 *
78 * Type: notice
79 * Dismiss: Everywhere
80 * Show: Settings and dashboard only
81 *
82 * @since 3.0
83 * @return array|bool
84 */
85 protected function process_using_autosuggest_defaults_notice() {
86 $feature = Features::factory()->get_registered_feature( 'autosuggest' );
87 if ( ! $feature instanceof Feature ) {
88 return false;
89 }
90
91 if ( ! $feature->is_active() ) {
92 return false;
93 }
94
95 $last_sync = Utils\get_option( 'ep_last_sync', false );
96
97 if ( empty( $last_sync ) ) {
98 return false;
99 }
100
101 $host = Utils\get_host();
102
103 if ( empty( $host ) ) {
104 return false;
105 }
106
107 $dismiss = Utils\get_option( 'ep_hide_using_autosuggest_defaults_notice', false );
108
109 if ( $dismiss ) {
110 return false;
111 }
112
113 $screen = Screen::factory()->get_current_screen();
114
115 if ( ! in_array( $screen, [ 'dashboard', 'settings' ], true ) ) {
116 return false;
117 }
118
119 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
120 $url = admin_url( 'network/admin.php?page=elasticpress&do_sync' );
121 } else {
122 $url = admin_url( 'admin.php?page=elasticpress&do_sync' );
123 }
124
125 return [
126 'html' => sprintf( esc_html__( 'Autosuggest feature is enabled. If documents feature is enabled, your media will also become searchable in the frontend.', 'elasticpress' ) ),
127 'type' => 'info',
128 'dismiss' => true,
129 ];
130 }
131
132 /**
133 * An EP feature was auto-activated that requires a sync.
134 *
135 * Type: warning
136 * Dismiss: Everywhere except ep dash and settings
137 * Show: All screens except install. Dont show during sync ever
138 *
139 * @since 3.0
140 * @return array|bool
141 */
142 protected function process_auto_activate_sync_notice() {
143 $need_upgrade_sync = Utils\get_option( 'ep_need_upgrade_sync', false );
144
145 // need_upgrade_sync takes priority over this notice
146 if ( $need_upgrade_sync ) {
147 return false;
148 }
149
150 $auto_activate_sync = Utils\get_option( 'ep_feature_auto_activated_sync', false );
151
152 if ( ! $auto_activate_sync ) {
153 return false;
154 }
155
156 $last_sync = Utils\get_option( 'ep_last_sync', false );
157
158 if ( empty( $last_sync ) ) {
159 return false;
160 }
161
162 $host = Utils\get_host();
163
164 if ( empty( $host ) ) {
165 return false;
166 }
167
168 $dismiss = Utils\get_option( 'ep_hide_auto_activate_sync_notice', false );
169
170 $screen = Screen::factory()->get_current_screen();
171
172 if ( 'install' === $screen ) {
173 return false;
174 }
175
176 if ( $dismiss && ! in_array( $screen, [ 'dashboard', 'settings' ], true ) ) {
177 return false;
178 }
179
180 if ( isset( $_GET['do_sync'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
181 return false;
182 }
183
184 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
185 $url = admin_url( 'network/admin.php?page=elasticpress-sync&do_sync=features' );
186 } else {
187 $url = admin_url( 'admin.php?page=elasticpress-sync&do_sync=features' );
188 }
189
190 $feature = Features::factory()->get_registered_feature( $auto_activate_sync );
191
192 if ( defined( 'EP_DASHBOARD_SYNC' ) && ! EP_DASHBOARD_SYNC ) {
193 $html = sprintf(
194 /* translators: Feature name */
195 esc_html__( 'Dashboard sync is disabled. The ElasticPress %s feature has been auto-activated! You will need to reindex using WP-CLI for it to work.', 'elasticpress' ),
196 esc_html( is_object( $feature ) ? $feature->get_short_title() : '' )
197 );
198 } else {
199 $html = sprintf(
200 /* translators: 1. Feature name; 2: Sync page URL */
201 __( 'The ElasticPress %1$s feature has been auto-activated! You will need to <a href="%2$s">run a sync</a> for it to work.', 'elasticpress' ),
202 esc_html( is_object( $feature ) ? $feature->get_short_title() : '' ),
203 esc_url( $url )
204 );
205 }
206
207 return [
208 'html' => $html,
209 'type' => 'warning',
210 'dismiss' => ! in_array( $screen, [ 'dashboard', 'settings' ], true ),
211 ];
212 }
213
214 /**
215 * EP was upgraded to or past a version that requires a sync.
216 *
217 * Type: warning
218 * Dismiss: Everywhere except ep dash and settings
219 * Show: All screens except install. Dont show during sync ever
220 *
221 * @since 3.0
222 * @return array|bool
223 */
224 protected function process_upgrade_sync_notice() {
225 $need_upgrade_sync = Utils\get_option( 'ep_need_upgrade_sync', false );
226
227 if ( ! $need_upgrade_sync ) {
228 return false;
229 }
230
231 $last_sync = Utils\get_option( 'ep_last_sync', false );
232
233 if ( empty( $last_sync ) ) {
234 return false;
235 }
236
237 $host = Utils\get_host();
238
239 if ( empty( $host ) ) {
240 return false;
241 }
242
243 $dismiss = Utils\get_option( 'ep_hide_upgrade_sync_notice', false );
244
245 $screen = Screen::factory()->get_current_screen();
246
247 if ( 'install' === $screen ) {
248 return false;
249 }
250
251 if ( $dismiss && ! in_array( $screen, [ 'dashboard', 'settings' ], true ) ) {
252 return false;
253 }
254
255 if ( isset( $_GET['do_sync'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
256 return false;
257 }
258
259 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
260 $url = admin_url( 'network/admin.php?page=elasticpress-sync&do_sync=upgrade' );
261 } else {
262 $url = admin_url( 'admin.php?page=elasticpress-sync&do_sync=upgrade' );
263 }
264
265 if ( defined( 'EP_DASHBOARD_SYNC' ) && ! EP_DASHBOARD_SYNC ) {
266 $html = esc_html__( 'Dashboard sync is disabled. The new version of ElasticPress requires that you delete all data and start a fresh sync using WP-CLI.', 'elasticpress' );
267 } else {
268 $html = sprintf(
269 /* translators: Sync Page URL */
270 __( 'The new version of ElasticPress requires that you <a href="%s">delete all data and start a fresh sync</a>.', 'elasticpress' ),
271 esc_url( $url )
272 );
273 }
274
275 $notice = esc_html__( 'Please note that some ElasticPress functionality may be impaired and/or content may not be searchable until the full sync has been performed.', 'elasticpress' );
276
277 return [
278 'html' => '<span class="dashicons dashicons-warning"></span> ' . $html . ' ' . $notice,
279 'type' => 'error',
280 'dismiss' => ! in_array( $screen, [ 'dashboard', 'settings' ], true ),
281 ];
282 }
283
284 /**
285 * EP has no never had a sync. We assume the user is on step 3 of the install.
286 *
287 * Type: notice
288 * Dismiss: Everywhere except ep dash and settings
289 * Show: All screens except install. Dont show during sync ever
290 *
291 * @since 3.0
292 * @return array|bool
293 */
294 protected function process_no_sync_notice() {
295 $last_sync = Utils\get_option( 'ep_last_sync', false );
296
297 if ( ! empty( $last_sync ) ) {
298 return false;
299 }
300
301 $host = Utils\get_host();
302
303 if ( empty( $host ) ) {
304 return false;
305 }
306
307 $dismiss = Utils\get_option( 'ep_hide_no_sync_notice', false );
308
309 $screen = Screen::factory()->get_current_screen();
310
311 if ( 'install' === $screen ) {
312 return false;
313 }
314
315 if ( $dismiss && ! in_array( $screen, [ 'dashboard', 'settings' ], true ) ) {
316 return false;
317 }
318
319 if ( isset( $_GET['do_sync'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification
320 return false;
321 }
322
323 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
324 $url = admin_url( 'network/admin.php?page=elasticpress-sync' );
325 } else {
326 $url = admin_url( 'admin.php?page=elasticpress-sync' );
327 }
328
329 if ( defined( 'EP_DASHBOARD_SYNC' ) && ! EP_DASHBOARD_SYNC ) {
330 $html = esc_html__( 'Dashboard sync is disabled, but ElasticPress is almost ready to go. Trigger a sync from WP-CLI.', 'elasticpress' );
331 } else {
332 $html = sprintf(
333 /* translators: Sync Page URL */
334 __( 'ElasticPress is almost ready to go. You just need to <a href="%s">sync your content</a>.', 'elasticpress' ),
335 esc_url( $url )
336 );
337 }
338
339 return [
340 'html' => $html,
341 'type' => 'info',
342 'dismiss' => ! in_array( $screen, [ 'dashboard', 'settings' ], true ),
343 ];
344 }
345
346 /**
347 * EP has no host set. We assume the user needs to run an install.
348 *
349 * Type: notice
350 * Dismiss: Anywhere except EP dashboard
351 * Show: All screens except settings and install
352 *
353 * @since 3.0
354 * @return array|bool
355 */
356 protected function process_need_setup_notice() {
357 $host = Utils\get_host();
358
359 if ( ! empty( $host ) ) {
360 return false;
361 }
362
363 $dismiss = Utils\get_option( 'ep_hide_need_setup_notice', false );
364
365 $screen = Screen::factory()->get_current_screen();
366
367 if ( in_array( $screen, [ 'settings', 'install' ], true ) ) {
368 return false;
369 }
370
371 if ( $dismiss && 'dashboard' !== $screen ) {
372 return false;
373 }
374
375 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
376 $url = admin_url( 'network/admin.php?page=elasticpress-settings' );
377 } else {
378 $url = admin_url( 'admin.php?page=elasticpress-settings' );
379 }
380
381 return [
382 'type' => 'info',
383 'dismiss' => 'dashboard' !== $screen,
384 'html' => sprintf(
385 /* translators: Sync Page URL */
386 __( 'ElasticPress is almost ready to go. You just need to <a href="%s">enter your settings</a>.', 'elasticpress' ),
387 esc_url( $url )
388 ),
389 ];
390 }
391
392 /**
393 * Below ES compat error.
394 *
395 * Type: error
396 * Dismiss: Anywhere
397 * Show: All screens
398 *
399 * @since 3.0
400 * @return array|bool
401 */
402 protected function process_es_below_compat_notice() {
403 if ( Utils\is_epio() ) {
404 return false;
405 }
406
407 $host = Utils\get_host();
408
409 if ( empty( $host ) ) {
410 return false;
411 }
412
413 $es_version = Elasticsearch::factory()->get_elasticsearch_version();
414
415 if ( false === $es_version ) {
416 return false;
417 }
418
419 $dismiss = Utils\get_option( 'ep_hide_es_below_compat_notice', false );
420
421 if ( $dismiss ) {
422 return false;
423 }
424
425 // First reduce version to major version i.e. 7.10 not 7.10.1.
426 $major_es_version = preg_replace( '#^([0-9]+\.[0-9]+).*#', '$1', $es_version );
427
428 // pad a version to have at least two parts (7 -> 7.0)
429 $parts = explode( '.', $major_es_version );
430
431 if ( 1 === count( $parts ) ) {
432 $parts[] = 0;
433 }
434
435 $major_es_version = implode( '.', $parts );
436
437 if ( 1 === version_compare( EP_ES_VERSION_MIN, $major_es_version ) ) {
438 return [
439 'type' => 'error',
440 'dismiss' => true,
441 'html' => sprintf(
442 /* translators: 1. Current Elasticsearch version; 2. Minimum required ES version */
443 __( 'Your Elasticsearch version %1$s is below the minimum required Elasticsearch version %2$s. ElasticPress may or may not work properly.', 'elasticpress' ),
444 esc_html( $es_version ),
445 esc_html( EP_ES_VERSION_MIN )
446 ),
447 ];
448 }
449
450 return false;
451 }
452
453 /**
454 * Above ES compat error.
455 *
456 * Type: error
457 * Dismiss: Anywhere
458 * Show: All screens
459 *
460 * @since 3.0
461 * @return array|bool
462 */
463 protected function process_es_above_compat_notice() {
464 if ( Utils\is_epio() ) {
465 return false;
466 }
467
468 $host = Utils\get_host();
469
470 if ( empty( $host ) ) {
471 return false;
472 }
473
474 $es_version = Elasticsearch::factory()->get_elasticsearch_version();
475
476 if ( false === $es_version ) {
477 return false;
478 }
479
480 $dismiss = Utils\get_option( 'ep_hide_es_above_compat_notice', false );
481
482 if ( $dismiss ) {
483 return false;
484 }
485
486 // First reduce version to major version i.e. 7.10 not 7.10.1.
487 $major_es_version = preg_replace( '#^([0-9]+\.[0-9]+).*#', '$1', $es_version );
488
489 if ( -1 === version_compare( EP_ES_VERSION_MAX, $major_es_version ) ) {
490 return [
491 'type' => 'warning',
492 'dismiss' => true,
493 'html' => sprintf(
494 /* translators: 1. Current Elasticsearch version; 2. Maximum supported ES version */
495 __( 'Your Elasticsearch version %1$s is above the maximum required Elasticsearch version %2$s. ElasticPress may or may not work properly.', 'elasticpress' ),
496 esc_html( $es_version ),
497 esc_html( EP_ES_VERSION_MAX )
498 ),
499 ];
500 }
501 }
502
503 /**
504 * Server software different from Elasticsearch warning.
505 *
506 * Type: warning
507 * Dismiss: Anywhere
508 * Show: All screens
509 *
510 * @since 4.2.1
511 * @return array|bool
512 */
513 protected function process_different_server_type_notice() {
514 if ( Utils\is_epio() ) {
515 return false;
516 }
517
518 $host = Utils\get_host();
519
520 if ( empty( $host ) ) {
521 return false;
522 }
523
524 $server_type = Elasticsearch::factory()->get_server_type();
525
526 if ( false === $server_type || 'elasticsearch' === $server_type ) {
527 return false;
528 }
529
530 $dismiss = Utils\get_option( 'ep_hide_different_server_type_notice', false );
531
532 if ( $dismiss ) {
533 return false;
534 }
535
536 $doc_url = 'https://10up.github.io/ElasticPress/tutorial-compatibility.html';
537 $html = sprintf(
538 /* translators: Document page URL */
539 __( 'Your server software is not supported. To learn more about server compatibility please <a href="%s">visit our documentation</a>.', 'elasticpress' ),
540 esc_url( $doc_url )
541 );
542
543 return [
544 'html' => $html,
545 'type' => 'warning',
546 'dismiss' => true,
547 ];
548 }
549
550 /**
551 * Host error notification. Shows when EP can't reach ES host.
552 *
553 * Type: error
554 * Dismiss: Only on non-EP screens
555 * Show: All screens except install
556 *
557 * @since 3.0
558 * @return array|bool
559 */
560 protected function process_host_error_notice() {
561 $host = Utils\get_host();
562
563 if ( empty( $host ) ) {
564 return false;
565 }
566
567 $screen = Screen::factory()->get_current_screen();
568
569 if ( 'install' === $screen ) {
570 return false;
571 }
572
573 $es_version = Elasticsearch::factory()->get_elasticsearch_version( false );
574
575 if ( false !== $es_version ) {
576 return false;
577 }
578
579 // Only dismissable on non-EP screens
580 if ( ! in_array( $screen, [ 'settings', 'dashboard' ], true ) ) {
581 $dismiss = Utils\get_option( 'ep_hide_host_error_notice', false );
582
583 if ( $dismiss ) {
584 return false;
585 }
586 }
587
588 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
589 $url = admin_url( 'network/admin.php?page=elasticpress-settings' );
590 $response_code = get_site_transient( 'ep_es_info_response_code' );
591 $response_error = get_site_transient( 'ep_es_info_response_error' );
592 } else {
593 $url = admin_url( 'admin.php?page=elasticpress-settings' );
594 $response_code = get_transient( 'ep_es_info_response_code' );
595 $response_error = get_transient( 'ep_es_info_response_error' );
596 }
597
598 $html = sprintf(
599 /* translators: 1. Current URL with retry parameter; 2. Settings Page URL */
600 __( 'There is a problem with connecting to your Elasticsearch host. ElasticPress can <a href="%1$s">try your host again</a>, or you may need to <a href="%2$s">change your settings</a>.', 'elasticpress' ),
601 esc_url( add_query_arg( 'ep-retry', 1 ) ),
602 esc_url( $url )
603 );
604
605 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
606 if ( ! empty( $response_code ) ) {
607 /* translators: Response Code Number */
608 $html .= '<span class="notice-error-es-response-code"> ' . sprintf( __( 'Response Code: %s', 'elasticpress' ), esc_html( $response_code ) ) . '</span>';
609 }
610
611 if ( ! empty( $response_error ) ) {
612 /* translators: Response Code Message */
613 $html .= '<span class="notice-error-es-response-error"> ' . sprintf( __( 'Response error: %s', 'elasticpress' ), esc_html( $response_error ) ) . '</span>';
614 }
615 }
616
617 return [
618 'html' => $html,
619 'type' => 'error',
620 'dismiss' => ( ! in_array( Screen::factory()->get_current_screen(), [ 'settings', 'dashboard' ], true ) ) ? true : false,
621 ];
622 }
623
624 /**
625 * Determine if the wrong mapping might be installed
626 *
627 * Type: error
628 * Dismiss: Always dismissable per es_version as custom mapping could exist
629 * Show: All screens
630 *
631 * @since 3.6.2
632 * @return array|bool
633 */
634 protected function process_maybe_wrong_mapping_notice() {
635 $screen = Screen::factory()->get_current_screen();
636
637 if ( 'install' === $screen ) {
638 return false;
639 }
640
641 // we might have this dismissed
642 $dismiss = Utils\get_option( 'ep_hide_maybe_wrong_mapping_notice', false );
643
644 // we need a host
645 $host = Utils\get_host();
646 if ( empty( $host ) ) {
647 return false;
648 }
649
650 // we also need a version
651 $es_version = Elasticsearch::factory()->get_elasticsearch_version( false );
652
653 if ( false === $es_version || $dismiss === $es_version ) {
654 return false;
655 }
656
657 // we also likely need a sync to have a mapping
658 $last_sync = Utils\get_option( 'ep_last_sync', false );
659
660 if ( empty( $last_sync ) ) {
661 return false;
662 }
663
664 $post_indexable = Indexables::factory()->get( 'post' );
665
666 $mapping_file_wanted = $post_indexable->get_mapping_name();
667 $mapping_file_current = $post_indexable->determine_mapping_version();
668 if ( is_wp_error( $mapping_file_current ) ) {
669 return false;
670 }
671
672 if ( ! $mapping_file_current || $mapping_file_wanted !== $mapping_file_current ) {
673 $html = sprintf(
674 /* translators: 1. <em>; 2. </em> */
675 esc_html__( 'It seems the mapping data in your index does not match the Elasticsearch version used. We recommend to reindex your content using the sync button on the top of the screen or through wp-cli by adding the %1$s--setup%2$s flag', 'elasticpress' ),
676 '<em>',
677 '</em>'
678 );
679
680 if ( defined( 'WP_DEBUG' ) && WP_DEBUG ) {
681 /* translators: 1. Current mapping file; 2. Mapping file that should be used */
682 $html .= '<span class="notice-error-es-response-code"> ' . sprintf( esc_html__( 'Current mapping: %1$s. Expected mapping: %2$s', 'elasticpress' ), esc_html( $mapping_file_current ), esc_html( $mapping_file_wanted ) ) . '</span>';
683 }
684
685 return [
686 'html' => $html,
687 'type' => 'error',
688 'dismiss' => true,
689 ];
690
691 }
692
693 }
694
695 /**
696 * Single node notification. Shows when index health is yellow.
697 *
698 * Type: warning
699 * Dismiss: Anywhere
700 * Show: All screens except install
701 *
702 * @since 3.2
703 * @return array|bool
704 */
705 protected function process_yellow_health_notice() {
706 $host = Utils\get_host();
707
708 if ( empty( $host ) ) {
709 return false;
710 }
711
712 $last_sync = Utils\get_option( 'ep_last_sync', false );
713
714 if ( empty( $last_sync ) ) {
715 return false;
716 }
717
718 $dismiss = Utils\get_option( 'ep_hide_yellow_health_notice', false );
719
720 $screen = Screen::factory()->get_current_screen();
721
722 if ( ! in_array( $screen, [ 'dashboard', 'settings' ], true ) || $dismiss ) {
723 return false;
724 }
725
726 $nodes = Stats::factory()->get_nodes();
727
728 if ( false !== $nodes && $nodes < 2 && $nodes > 0 ) {
729 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
730 $url = network_admin_url( 'admin.php?page=elasticpress-health' );
731 } else {
732 $url = admin_url( 'admin.php?page=elasticpress-health' );
733 }
734
735 return [
736 'type' => 'warning',
737 'dismiss' => true,
738 'html' => sprintf(
739 /* translators: Index Health URL */
740 __( 'It looks like one or more of your indices are running on a single node. While this won\'t prevent you from using ElasticPress, depending on your site\'s specific needs this can represent a performance issue. Please check the <a href="%s">Index Health</a> page where you can check the health of all of your indices.', 'elasticpress' ),
741 $url
742 ),
743 ];
744 }
745 }
746
747 /**
748 * Too many fields notification. Shows when the site has potentially more fields than ES could handle.
749 *
750 * Type: warning|error
751 * Dismiss: Anywhere
752 * Show: Sync and Install page
753 *
754 * @since 4.4.0
755 * @return array|bool
756 */
757 protected function process_too_many_fields_notice() {
758 $host = Utils\get_host();
759
760 if ( empty( $host ) ) {
761 return false;
762 }
763
764 $dismiss = Utils\get_option( 'ep_hide_too_many_fields_notice', false );
765
766 $screen = Screen::factory()->get_current_screen();
767
768 if ( ! in_array( $screen, [ 'install', 'sync' ], true ) || $dismiss ) {
769 return false;
770 }
771
772 $has_error = false;
773 $has_warning = false;
774
775 if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
776 $sites = Utils\get_sites( 0, true );
777 foreach ( $sites as $site ) {
778 switch_to_blog( $site['blog_id'] );
779
780 list( $has_error, $site_has_warning ) = $this->check_field_count();
781
782 restore_current_blog();
783
784 $has_warning = $has_warning || $site_has_warning;
785 if ( $has_error ) {
786 break;
787 }
788 }
789 } else {
790 list( $has_error, $has_warning ) = $this->check_field_count();
791 }
792
793 if ( $has_error ) {
794 $message = sprintf(
795 /* translators: Elasticsearch or ElasticPress.io; 2. Link to article; 3. Link to article */
796 __( 'Your website content has more public custom fields than %1$s is able to store. Check our articles about <a href="%2$s">Elasticsearch field limitations</a> and <a href="%3$s">how to index just the custom fields you need</a> before trying to sync.', 'elasticpress' ),
797 Utils\is_epio() ? __( 'ElasticPress.io', 'elasticpress' ) : __( 'Elasticsearch', 'elasticpress' ),
798 'https://elasticpress.zendesk.com/hc/en-us/articles/360051401212-I-get-the-error-Limit-of-total-fields-in-index-has-been-exceeded-',
799 'https://elasticpress.zendesk.com/hc/en-us/articles/360052019111'
800 );
801
802 return [
803 'type' => 'error',
804 'dismiss' => true,
805 'html' => $message,
806 ];
807 }
808
809 if ( $has_warning ) {
810 $message = sprintf(
811 /* translators: Elasticsearch or ElasticPress.io; 2. Link to article; 3. Link to article */
812 __( 'Your website content seems to have more public custom fields than %1$s is able to store. Check our articles about <a href="%2$s">Elasticsearch field limitations</a> and <a href="%3$s">how to index just the custom fields you need</a> if you receive any errors while syncing.', 'elasticpress' ),
813 Utils\is_epio() ? __( 'ElasticPress.io', 'elasticpress' ) : __( 'Elasticsearch', 'elasticpress' ),
814 'https://elasticpress.zendesk.com/hc/en-us/articles/360051401212-I-get-the-error-Limit-of-total-fields-in-index-has-been-exceeded-',
815 'https://elasticpress.zendesk.com/hc/en-us/articles/360052019111'
816 );
817
818 return [
819 'type' => 'warning',
820 'dismiss' => true,
821 'html' => $message,
822 ];
823 }
824
825 return false;
826 }
827
828 /**
829 * Get notices that should be displayed
830 *
831 * @since 3.0
832 * @return array
833 */
834 public function get_notices() {
835 /**
836 * Filter admin notices
837 *
838 * @hook ep_admin_notices
839 * @param {array} $notices Admin notices
840 * @return {array} New notices
841 */
842 return apply_filters( 'ep_admin_notices', $this->notices );
843 }
844
845 /**
846 * Dismiss a notice given a notice key.
847 *
848 * @param string $notice Notice key
849 * @since 3.0
850 */
851 public function dismiss_notice( $notice ) {
852 $value = true;
853 // allow version dependent dismissal
854 if ( in_array( $notice, [ 'maybe_wrong_mapping' ], true ) ) {
855 $value = Elasticsearch::factory()->get_elasticsearch_version( false );
856 }
857
858 Utils\update_option( 'ep_hide_' . $notice . '_notice', $value );
859 }
860
861 /**
862 * Return singleton instance of class
863 *
864 * @return object
865 * @since 0.1.0
866 */
867 public static function factory() {
868 static $instance = false;
869
870 if ( ! $instance ) {
871 $instance = new self();
872 }
873
874 return $instance;
875 }
876
877 /**
878 * Compare the number of fields in the site and the number of allowed fields in ES
879 *
880 * @since 4.4.0
881 * @return array
882 */
883 protected function check_field_count() {
884 $post_indexable = Indexables::factory()->get( 'post' );
885
886 $indexable_fields = $post_indexable->get_predicted_indexable_meta_keys();
887 $count_fields_db = count( $indexable_fields );
888
889 $index_name = $post_indexable->get_index_name();
890 $es_field_limit = Elasticsearch::factory()->get_index_total_fields_limit( $index_name );
891 $es_field_limit = $es_field_limit ?? apply_filters( 'ep_total_field_limit', 5000 );
892
893 $predicted_es_field_count = $count_fields_db * 8;
894
895 return [
896 $predicted_es_field_count > $es_field_limit,
897 $predicted_es_field_count * 1.2 > $es_field_limit,
898 ];
899 }
900 }
901