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.php +232 -157 4.6.05.3.5 View file →
@@ -9,10 +9,10 @@
9 9 */
10 10
11 11 namespace ElasticPress;
12 12
13 -use ElasticPress\FeatureRequirementsStatus as FeatureRequirementsStatus;
14 -use ElasticPress\Utils as Utils;
13 +use ElasticPress\FeatureRequirementsStatus;
14 +use ElasticPress\Utils;
15 15
16 16 if ( ! defined( 'ABSPATH' ) ) {
17 17 exit; // Exit if accessed directly.
18 18 }
@@ -118,33 +118,55 @@
118 118 */
119 119 protected $is_visible = true;
120 120
121 121 /**
122 - * Run on every page load for feature to set itself up
122 + * Settings description
123 123 *
124 - * @since 2.1
124 + * @since 5.0.0
125 + * @var array
125 126 */
126 - abstract public function setup();
127 + protected $settings_schema = [];
127 128
128 129 /**
129 - * Output feature box summary
130 + * The slug, or array of slugs, of a feature that is required to be active.
130 131 *
131 - * @since 2.1
132 + * @since 5.0.0
133 + * @var false|string|array
132 134 */
133 - public function output_feature_box_summary() {
134 - if ( $this->summary ) {
135 - echo '<p>' . esc_html( $this->summary ) . '</p>';
136 - }
137 - }
135 + protected $requires_feature = false;
138 136
139 137 /**
140 - * Implement to output feature box long text
138 + * Whether the feature is using ElasticPress.io.
141 139 *
142 - * @since 3.0
140 + * @since 5.0.0
141 + * @var boolean
143 142 */
144 - abstract public function output_feature_box_long();
143 + protected $is_powered_by_epio = false;
145 144
146 145 /**
146 + * The name of a group that a feature may belong to.
147 + *
148 + * @since 5.3.0
149 + * @var false|string
150 + */
151 + public $group = false;
152 +
153 + /**
154 + * Field groups available to a feature
155 + *
156 + * @since 5.3.0
157 + * @var array
158 + */
159 + protected $field_group_map = [];
160 +
161 + /**
162 + * Run on every page load for feature to set itself up
163 + *
164 + * @since 2.1
165 + */
166 + abstract public function setup();
167 +
168 + /**
147 169 * Create feature
148 170 *
149 171 * @since 3.0
150 172 */
@@ -165,14 +187,14 @@
165 187 * @since 2.2
166 188 * @return FeatureRequirementsStatus
167 189 */
168 190 public function requirements_status() {
169 - $status = new FeatureRequirementsStatus( 0 );
191 + $status = new FeatureRequirementsStatus( 0, null, $this );
170 192
171 193 /**
172 194 * Filter feature requirement status
173 195 *
174 - * @hook ep_{indexable_slug}_index_kill
196 + * @hook ep_feature_requirements_status
175 197 * @param {FeatureRequirementStatus} $status Current feature requirement status
176 198 * @param {Feature} $feature Current feature
177 199 * @since 2.2
178 200 * @return {FeatureRequirementStatus} New status
@@ -220,9 +242,13 @@
220 242
221 243 $active = false;
222 244
223 245 if ( ! empty( $feature_settings[ $this->slug ] ) && $feature_settings[ $this->slug ]['active'] ) {
224 - $active = true;
246 + $active = ! in_array(
247 + $this->requirements_status()->get_code(),
248 + [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
249 + true
250 + );
225 251 }
226 252
227 253 /**
228 254 * Filter whether a feature is active or not
@@ -269,158 +295,31 @@
269 295 do_action( 'ep_feature_post_activation', $this->slug, $this );
270 296 }
271 297
272 298 /**
273 - * Outputs feature box
299 + * To be run after feature deactivation
274 300 *
275 - * @since 2.1
301 + * @since 5.3.2
276 302 */
277 - public function output_feature_box() {
278 - $this->output_feature_box_summary();
279 -
303 + public function post_deactivation() {
280 304 /**
281 - * Fires before feature box summary is shown
305 + * Fires after feature is deactivated
282 306 *
283 - * @hook ep_feature_box_summary
284 - * @param {string} $slug Feature slug
307 + * @hook ep_feature_post_deactivation
308 + * @param {string} $slug Feature slug
285 309 * @param {Feature} $feature Current feature
286 - * @since 2.1
310 + * @since 5.3.2
287 311 */
288 - do_action( 'ep_feature_box_summary', $this->slug, $this );
289 - ?>
290 -
291 - <button aria-expanded="false" class="learn-more button button-secondary button-small" type="button"><?php esc_html_e( 'Learn more', 'elasticpress' ); ?></button>
292 -
293 - <div class="long">
294 - <?php $this->output_feature_box_long(); ?>
295 -
296 - <p><button aria-expanded="true" class="collapse button button-secondary button-small" type="button"><?php esc_html_e( 'Collapse', 'elasticpress' ); ?></button></p>
297 -
298 - <?php
299 - /**
300 - * Fires after feature long description
301 - *
302 - * @hook ep_feature_box_long
303 - * @param {string} $slug Feature slug
304 - * @param {Feature} $feature Current feature
305 - * @since 2.1
306 - */
307 - do_action( 'ep_feature_box_long', $this->slug, $this );
308 - ?>
309 -
310 - </div>
311 - <?php
312 + do_action( 'ep_feature_post_deactivation', $this->slug, $this );
312 313 }
313 314
314 315 /**
315 - * Output extra feature box settings.
316 - *
317 - * By default this does nothing. Override to add additional settings.
318 - *
319 - * @since 3.0
320 - */
321 - public function output_feature_box_settings() {
322 - /**
323 - * Optionally override
324 - */
325 - }
326 -
327 - /**
328 - * Output feature settings
329 - *
330 - * @since 3.0
331 - */
332 - public function output_settings_box() {
333 - $requirements_status = $this->requirements_status();
334 - $sync_url = ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK )
335 - ? network_admin_url( 'admin.php?page=elasticpress-sync' )
336 - : admin_url( 'admin.php?page=elasticpress-sync' );
337 - ?>
338 -
339 - <form>
340 - <?php
341 - if ( ! empty( $requirements_status->message ) ) :
342 - $messages = (array) $requirements_status->message;
343 - ?>
344 - <?php foreach ( $messages as $message ) : ?>
345 - <div class="requirements-status-notice">
346 - <?php echo wp_kses_post( $message ); ?>
347 - </div>
348 - <?php endforeach; ?>
349 - <?php endif; ?>
350 -
351 - <?php if ( $this->requires_install_reindex || $this->setting_requires_install_reindex ) : ?>
352 - <div class="requirements-status-notice requirements-status-notice--reindex" role="status">
353 - <?php esc_html_e( 'Enabling this feature will require re-syncing your content.', 'elasticpress' ); ?>
354 - </div>
355 - <?php endif; ?>
356 -
357 - <div class="requirements-status-notice requirements-status-notice--syncing" role="alert">
358 - <?php
359 - printf(
360 - '%1$s <a href="%2$s">%3$s</a>',
361 - esc_html__( 'Settings not saved. Cannot save settings while a sync is in progress.', 'elasticpress' ),
362 - esc_url( $sync_url ),
363 - esc_html__( 'View sync status.', 'elasticpress' )
364 - );
365 - ?>
366 - </div>
367 -
368 - <h3><?php esc_html_e( 'Settings', 'elasticpress' ); ?></h3>
369 -
370 - <div class="feature-fields">
371 - <div class="field js-toggle-feature">
372 - <div class="field-name status"><?php esc_html_e( 'Status', 'elasticpress' ); ?></div>
373 - <div class="input-wrap <?php if ( 2 === $requirements_status->code ) : ?>disabled<?php endif; ?>">
374 - <label><input name="settings[active]" <?php disabled( 2 === $requirements_status->code ); ?> type="radio" <?php checked( $this->is_active() ); ?> value="1"><?php esc_html_e( 'Enabled', 'elasticpress' ); ?></label><br>
375 - <label><input name="settings[active]" <?php disabled( 2 === $requirements_status->code ); ?> type="radio" <?php checked( ! $this->is_active() ); ?> value="0"><?php esc_html_e( 'Disabled', 'elasticpress' ); ?></label>
376 - </div>
377 - </div>
378 -
379 - <?php
380 - $this->output_feature_box_settings();
381 - ?>
382 - </div>
383 -
384 - <div class="action-wrap">
385 - <span class="no-dash-sync">
386 - <?php esc_html_e( 'Setting adjustments to this feature require a re-sync. Use WP-CLI.', 'elasticpress' ); ?>
387 - </span>
388 -
389 - <input type="hidden" name="action" value="ep_save_feature">
390 - <input type="hidden" name="feature" value="<?php echo esc_attr( $this->slug ); ?>">
391 - <input type="hidden" name="requires_reindex" value="<?php echo $this->requires_install_reindex ? '1' : '0'; ?>">
392 - <input type="hidden" name="was_active" value="<?php echo $this->is_active() ? '1' : '0'; ?>">
393 - <input type="hidden" name="setting_requires_reindex" value="<?php echo esc_attr( $this->setting_requires_install_reindex ); ?>">
394 - <input type="hidden" name="setting_requires_reindex_was" value="<?php echo esc_attr( $this->get_reindex_setting() ); ?>">
395 - <?php wp_nonce_field( 'ep_dashboard_nonce', 'nonce' ); ?>
396 -
397 - <button name="submit" <?php disabled( 2 === $requirements_status->code || ( $this->requires_install_reindex && defined( 'EP_DASHBOARD_SYNC' ) && ! EP_DASHBOARD_SYNC ) ); ?> class="button button-primary" type="submit">
398 - <?php esc_html_e( 'Save', 'elasticpress' ); ?>
399 - </button>
400 - </div>
401 - </form>
402 -
403 - <?php
404 - }
405 -
406 - /**
407 - * Returns the ElasticPress.io logo.
408 - *
409 - * @since 4.4.1
410 - * @return string
411 - */
412 - public function get_epio_logo() : string {
413 - return sprintf( '<img class="feature-epio-logo" alt="ElasticPresss.io logo" src="%s" width="110" height="20">', esc_url( plugins_url( '/images/logo-elasticpress-io.svg', EP_FILE ) ) );
414 - }
415 -
416 - /**
417 316 * Returns the feature title.
418 317 *
419 318 * @since 4.4.1
420 319 * @return string
421 320 */
422 - public function get_title() : string {
321 + public function get_title(): string {
423 322 return $this->title;
424 323 }
425 324
426 325 /**
@@ -428,9 +327,9 @@
428 327 *
429 328 * @since 4.4.1
430 329 * @return string
431 330 */
432 - public function get_short_title() : string {
331 + public function get_short_title(): string {
433 332 if ( ! empty( $this->short_title ) ) {
434 333 return $this->short_title;
435 334 }
436 335
@@ -476,9 +375,9 @@
476 375 *
477 376 * @since 4.5.0
478 377 * @return boolean
479 378 */
480 - public function is_available() : bool {
379 + public function is_available(): bool {
481 380 $requirements_status = $this->requirements_status();
482 381 /**
483 382 * Filter whether a feature is available or not.
484 383 *
@@ -500,7 +399,183 @@
500 399 * @param {Feature} $feature Feature object
501 400 * @since 4.5.0
502 401 * @return {bool} New $is_available value
503 402 */
504 - return apply_filters( 'ep_feature_is_available', $this->is_visible && 2 !== $requirements_status->code, $this->slug, $this );
403 + return apply_filters(
404 + 'ep_feature_is_available',
405 + $this->is_visible()
406 + && ! in_array(
407 + $requirements_status->get_code(),
408 + [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
409 + true
410 + ),
411 + $this->slug,
412 + $this
413 + );
414 + }
415 +
416 + /**
417 + * Get a JSON representation of the feature
418 + *
419 + * @since 5.0.0
420 + * @return string
421 + */
422 + public function get_json() {
423 + $requirements_status = $this->requirements_status();
424 +
425 + $feature_desc = [
426 + 'slug' => $this->slug,
427 + 'title' => $this->get_title(),
428 + 'shortTitle' => $this->get_short_title(),
429 + 'summary' => $this->summary,
430 + 'docsUrl' => $this->docs_url,
431 + 'defaultSettings' => $this->default_settings,
432 + 'order' => $this->order,
433 + 'isAvailable' => $this->is_available(),
434 + 'isPoweredByEpio' => $this->is_powered_by_epio,
435 + 'isVisible' => $this->is_visible(),
436 + 'reqStatusCode' => $requirements_status->get_code(),
437 + 'reqStatusMessages' => (array) $requirements_status->get_message(),
438 + 'settingsSchema' => $this->get_settings_schema(),
439 + 'group' => $this->group,
440 + 'requiredFeature' => $this->get_required_feature(),
441 + 'fieldGroups' => $this->get_field_group_map(),
442 + ];
443 +
444 + return $feature_desc;
445 + }
446 +
447 + /**
448 + * Return the feature settings schema
449 + *
450 + * @since 5.0.0
451 + * @return array
452 + */
453 + public function get_settings_schema() {
454 + // Settings were not set yet.
455 + if ( [] === $this->settings_schema ) {
456 + $this->set_settings_schema();
457 + }
458 +
459 + $active = [
460 + 'default' => false,
461 + 'key' => 'active',
462 + 'label' => __( 'Enable', 'elasticpress' ),
463 + 'requires_feature' => $this->get_required_feature(),
464 + 'requires_sync' => $this->requires_install_reindex,
465 + 'type' => 'toggle',
466 + ];
467 +
468 + $settings_schema = [
469 + $active,
470 + ...$this->settings_schema,
471 + ];
472 +
473 + /**
474 + * Filter the settings schema of a feature
475 + *
476 + * @hook ep_feature_is_available
477 + * @since 5.0.0
478 + * @param {array} $settings_schema True if the feature is available
479 + * @param {string} $feature_slug Feature slug
480 + * @param {Feature} $feature Feature object
481 + * @return {array} New $settings_schema value
482 + */
483 + return apply_filters( 'ep_feature_settings_schema', $settings_schema, $this->slug, $this );
484 + }
485 +
486 + /**
487 + * Reset the cached settings schema so it is rebuilt on next access.
488 + *
489 + * @since 5.3.3
490 + */
491 + public function reset_settings_schema() {
492 + $this->settings_schema = [];
493 + }
494 +
495 + /**
496 + * Default implementation of `set_settings_schema` based on the `default_settings` attribute
497 + *
498 + * @since 5.0.0
499 + */
500 + protected function set_settings_schema() {
501 + if ( [] === $this->default_settings ) {
502 + return;
503 + }
504 +
505 + foreach ( $this->default_settings as $key => $default_value ) {
506 + $type = 'text';
507 + if ( in_array( $default_value, [ '0', '1' ], true ) ) {
508 + $type = 'checkbox';
509 + }
510 + if ( is_bool( $default_value ) ) {
511 + $type = 'toggle';
512 + }
513 +
514 + $this->settings_schema[] = [
515 + 'default' => $default_value,
516 + 'key' => $key,
517 + 'label' => $key,
518 + 'type' => $type,
519 + ];
520 + }
521 + }
522 +
523 + /**
524 + * Sets the i18n strings for the feature.
525 + *
526 + * @return void
527 + * @since 5.2.0
528 + */
529 + public function set_i18n_strings(): void {
530 + }
531 +
532 + /**
533 + * Get all features required by this feature
534 + *
535 + * @since 5.3.0
536 + * @return array List of required feature slugs
537 + */
538 + public function get_required_feature() {
539 + return $this->requires_feature ? array_unique( (array) $this->requires_feature ) : [];
540 + }
541 +
542 + /**
543 + * Get the field group map for the feature.
544 + *
545 + * @since 5.3.0
546 + * @return array
547 + */
548 + public function get_field_group_map(): array {
549 + /**
550 + * Filter available field groups.
551 + *
552 + * @hook ep_feature_field_groups
553 + * @since 5.3.0
554 + * @param {array} $field_groups Current field groups
555 + * @return {array} New field groups
556 + */
557 + return apply_filters( 'ep_feature_field_groups', $this->field_group_map );
558 + }
559 +
560 + /**
561 + * Get the feature slug.
562 + *
563 + * @since 5.3.0
564 + * @return string Feature slug.
565 + */
566 + public function get_feature_slug(): string {
567 + return $this->slug;
568 + }
569 +
570 + /**
571 + * Pre-handle feature activation
572 + *
573 + * This method is called before features are setup and is intended to be used
574 + * to modify features requirements status.
575 + *
576 + * @since 5.3.3
577 + * @return void
578 + */
579 + public function pre_handle_feature_activation() {
505 580 }
506 581 }