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 +354 -120 4.4.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 }
@@ -37,8 +37,16 @@
37 37 */
38 38 public $title;
39 39
40 40 /**
41 + * Short title
42 + *
43 + * @var string
44 + * @since 4.4.1
45 + */
46 + public $short_title;
47 +
48 + /**
41 49 * Feature summary
42 50 *
43 51 * @var string
44 52 * @since 4.0.0
@@ -64,13 +72,21 @@
64 72 /**
65 73 * True if the feature requires content reindexing after activating
66 74 *
67 75 * @since 2.1
68 - * @var [type]
76 + * @var bool
69 77 */
70 - public $requires_install_reindex;
78 + public $requires_install_reindex = false;
71 79
72 80 /**
81 + * The slug of a setting that requires content reindexing after activating.
82 + *
83 + * @since 4.5.0
84 + * @var string
85 + */
86 + public $setting_requires_install_reindex = '';
87 +
88 + /**
73 89 * The order in the features screen
74 90 *
75 91 * @var int
76 92 * @since 3.6.0
@@ -94,33 +110,63 @@
94 110 */
95 111 public $available_during_installation = false;
96 112
97 113 /**
98 - * Run on every page load for feature to set itself up
114 + * Whether the feature should be always visible in the dashboard
99 115 *
100 - * @since 2.1
116 + * @since 4.5.0
117 + * @var boolean
101 118 */
102 - abstract public function setup();
119 + protected $is_visible = true;
103 120
104 121 /**
105 - * Output feature box summary
122 + * Settings description
106 123 *
107 - * @since 2.1
124 + * @since 5.0.0
125 + * @var array
108 126 */
109 - public function output_feature_box_summary() {
110 - if ( $this->summary ) {
111 - echo '<p>' . esc_html( $this->summary ) . '</p>';
112 - }
113 - }
127 + protected $settings_schema = [];
114 128
115 129 /**
116 - * Implement to output feature box long text
130 + * The slug, or array of slugs, of a feature that is required to be active.
117 131 *
118 - * @since 3.0
132 + * @since 5.0.0
133 + * @var false|string|array
119 134 */
120 - abstract public function output_feature_box_long();
135 + protected $requires_feature = false;
121 136
122 137 /**
138 + * Whether the feature is using ElasticPress.io.
139 + *
140 + * @since 5.0.0
141 + * @var boolean
142 + */
143 + protected $is_powered_by_epio = false;
144 +
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 + /**
123 169 * Create feature
124 170 *
125 171 * @since 3.0
126 172 */
@@ -141,14 +187,14 @@
141 187 * @since 2.2
142 188 * @return FeatureRequirementsStatus
143 189 */
144 190 public function requirements_status() {
145 - $status = new FeatureRequirementsStatus( 0 );
191 + $status = new FeatureRequirementsStatus( 0, null, $this );
146 192
147 193 /**
148 194 * Filter feature requirement status
149 195 *
150 - * @hook ep_{indexable_slug}_index_kill
196 + * @hook ep_feature_requirements_status
151 197 * @param {FeatureRequirementStatus} $status Current feature requirement status
152 198 * @param {Feature} $feature Current feature
153 199 * @since 2.2
154 200 * @return {FeatureRequirementStatus} New status
@@ -158,18 +204,35 @@
158 204
159 205 /**
160 206 * Return feature settings
161 207 *
162 - * @since 2.2.1
163 - * @return array|bool
208 + * @since 2.2.1, 4.5.0 started using default settings
209 + * @return array
164 210 */
165 211 public function get_settings() {
166 - $feature_settings = Utils\get_option( 'ep_feature_settings', [] );
212 + $all_settings = Utils\get_option( 'ep_feature_settings', [] );
167 213
168 - return ( ! empty( $feature_settings[ $this->slug ] ) ) ? $feature_settings[ $this->slug ] : false;
214 + $feature_settings = ( ! empty( $all_settings[ $this->slug ] ) ) ? (array) $all_settings[ $this->slug ] : [];
215 +
216 + $feature_settings = wp_parse_args( $feature_settings, $this->default_settings );
217 +
218 + return $feature_settings;
169 219 }
170 220
171 221 /**
222 + * Return a specific setting of the feature
223 + *
224 + * @since 4.5.0
225 + * @param string $setting_name The setting name
226 + * @return mixed
227 + */
228 + public function get_setting( string $setting_name ) {
229 + $settings = $this->get_settings();
230 +
231 + return isset( $settings[ $setting_name ] ) ? $settings[ $setting_name ] : null;
232 + }
233 +
234 + /**
172 235 * Returns true if feature is active
173 236 *
174 237 * @since 2.2
175 238 * @return boolean
@@ -179,9 +242,13 @@
179 242
180 243 $active = false;
181 244
182 245 if ( ! empty( $feature_settings[ $this->slug ] ) && $feature_settings[ $this->slug ]['active'] ) {
183 - $active = true;
246 + $active = ! in_array(
247 + $this->requirements_status()->get_code(),
248 + [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
249 + true
250 + );
184 251 }
185 252
186 253 /**
187 254 * Filter whether a feature is active or not
@@ -196,8 +263,23 @@
196 263 return apply_filters( 'ep_feature_active', $active, $feature_settings, $this );
197 264 }
198 265
199 266 /**
267 + * Get the value of the setting that requires a reindex, if it exists.
268 + *
269 + * @since 4.5.0
270 + * @return mixed
271 + */
272 + public function get_reindex_setting() {
273 + $settings = $this->get_settings();
274 + $setting = $this->setting_requires_install_reindex;
275 +
276 + return $settings && $setting && ! empty( $settings[ $setting ] )
277 + ? $settings[ $setting ]
278 + : '';
279 + }
280 +
281 + /**
200 282 * To be run after initial feature activation
201 283 *
202 284 * @since 2.1
203 285 */
@@ -213,135 +295,287 @@
213 295 do_action( 'ep_feature_post_activation', $this->slug, $this );
214 296 }
215 297
216 298 /**
217 - * Outputs feature box
299 + * To be run after feature deactivation
218 300 *
219 - * @since 2.1
301 + * @since 5.3.2
220 302 */
221 - public function output_feature_box() {
222 - $this->output_feature_box_summary();
223 -
303 + public function post_deactivation() {
224 304 /**
225 - * Fires before feature box summary is shown
305 + * Fires after feature is deactivated
226 306 *
227 - * @hook ep_feature_box_summary
228 - * @param {string} $slug Feature slug
307 + * @hook ep_feature_post_deactivation
308 + * @param {string} $slug Feature slug
229 309 * @param {Feature} $feature Current feature
230 - * @since 2.1
310 + * @since 5.3.2
231 311 */
232 - do_action( 'ep_feature_box_summary', $this->slug, $this );
233 - ?>
312 + do_action( 'ep_feature_post_deactivation', $this->slug, $this );
313 + }
234 314
235 - <button aria-expanded="false" class="learn-more button button-secondary button-small" type="button"><?php esc_html_e( 'Learn more', 'elasticpress' ); ?></button>
315 + /**
316 + * Returns the feature title.
317 + *
318 + * @since 4.4.1
319 + * @return string
320 + */
321 + public function get_title(): string {
322 + return $this->title;
323 + }
236 324
237 - <div class="long">
238 - <?php $this->output_feature_box_long(); ?>
325 + /**
326 + * Returns the feature short title.
327 + *
328 + * @since 4.4.1
329 + * @return string
330 + */
331 + public function get_short_title(): string {
332 + if ( ! empty( $this->short_title ) ) {
333 + return $this->short_title;
334 + }
239 335
240 - <p><button aria-expanded="true" class="collapse button button-secondary button-small" type="button"><?php esc_html_e( 'Collapse', 'elasticpress' ); ?></button></p>
336 + return $this->get_title();
337 + }
241 338
242 - <?php
243 - /**
244 - * Fires after feature long description
245 - *
246 - * @hook ep_feature_box_long
247 - * @param {string} $slug Feature slug
248 - * @param {Feature} $feature Current feature
249 - * @since 2.1
250 - */
251 - do_action( 'ep_feature_box_long', $this->slug, $this );
252 - ?>
253 -
254 - </div>
255 - <?php
339 + /**
340 + * Returns whether the feature is visible in the dashboard or not.
341 + *
342 + * By default, all active features are visible.
343 + *
344 + * @since 4.5.0
345 + * @return boolean
346 + */
347 + public function is_visible() {
348 + /**
349 + * Filter whether a feature is visible or not in the dashboard.
350 + *
351 + * Example:
352 + * ```
353 + * add_filter(
354 + * 'ep_feature_is_visible',
355 + * function ( $is_visible, $feature_slug ) {
356 + * return 'terms' === $feature_slug ? true : $is_visible;
357 + * },
358 + * 10,
359 + * 2
360 + * );
361 + * ```
362 + *
363 + * @hook ep_feature_is_visible
364 + * @param {bool} $is_visible True to display the feature
365 + * @param {string} $feature_slug Feature slug
366 + * @param {Feature} $feature Feature object
367 + * @since 4.5.0
368 + * @return {bool} New $is_visible value
369 + */
370 + return apply_filters( 'ep_feature_is_visible', $this->is_visible || $this->is_active(), $this->slug, $this );
256 371 }
257 372
258 373 /**
259 - * Output extra feature box settings.
374 + * Returns whether the feature is available or not.
260 375 *
261 - * By default this does nothing. Override to add additional settings.
262 - *
263 - * @since 3.0
376 + * @since 4.5.0
377 + * @return boolean
264 378 */
265 - public function output_feature_box_settings() {
379 + public function is_available(): bool {
380 + $requirements_status = $this->requirements_status();
266 381 /**
267 - * Optionally override
382 + * Filter whether a feature is available or not.
383 + *
384 + * Example:
385 + * ```
386 + * add_filter(
387 + * 'ep_feature_is_available',
388 + * function ( $is_available, $feature_slug ) {
389 + * return 'terms' === $feature_slug ? true : $is_available;
390 + * },
391 + * 10,
392 + * 2
393 + * );
394 + * ```
395 + *
396 + * @hook ep_feature_is_available
397 + * @param {bool} $is_available True if the feature is available
398 + * @param {string} $feature_slug Feature slug
399 + * @param {Feature} $feature Feature object
400 + * @since 4.5.0
401 + * @return {bool} New $is_available value
268 402 */
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 + );
269 414 }
270 415
271 416 /**
272 - * Output feature settings
417 + * Get a JSON representation of the feature
273 418 *
274 - * @since 3.0
419 + * @since 5.0.0
420 + * @return string
275 421 */
276 - public function output_settings_box() {
422 + public function get_json() {
277 423 $requirements_status = $this->requirements_status();
278 - $sync_url = ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK )
279 - ? network_admin_url( 'admin.php?page=elasticpress-sync' )
280 - : admin_url( 'admin.php?page=elasticpress-sync' );
281 - ?>
282 424
283 - <form>
284 - <?php
285 - if ( ! empty( $requirements_status->message ) ) :
286 - $messages = (array) $requirements_status->message;
287 - ?>
288 - <?php foreach ( $messages as $message ) : ?>
289 - <div class="requirements-status-notice">
290 - <?php echo wp_kses_post( $message ); ?>
291 - </div>
292 - <?php endforeach; ?>
293 - <?php endif; ?>
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 + ];
294 443
295 - <?php if ( $this->requires_install_reindex ) : ?>
296 - <div class="requirements-status-notice requirements-status-notice--reindex" role="status">
297 - <?php esc_html_e( 'Enabling this feature will require re-indexing your content.', 'elasticpress' ); ?>
298 - </div>
299 - <?php endif; ?>
444 + return $feature_desc;
445 + }
300 446
301 - <div class="requirements-status-notice requirements-status-notice--syncing" role="alert">
302 - <?php
303 - printf(
304 - '%1$s <a href="%2$s">%3$s</a>',
305 - esc_html__( 'Settings not saved. Cannot save settings while a sync is in progress.', 'elasticpress' ),
306 - esc_url( $sync_url ),
307 - esc_html__( 'View sync status.', 'elasticpress' )
308 - );
309 - ?>
310 - </div>
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 + }
311 458
312 - <h3><?php esc_html_e( 'Settings', 'elasticpress' ); ?></h3>
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 + ];
313 467
314 - <div class="feature-fields">
315 - <div class="field js-toggle-feature">
316 - <div class="field-name status"><?php esc_html_e( 'Status', 'elasticpress' ); ?></div>
317 - <div class="input-wrap <?php if ( 2 === $requirements_status->code ) : ?>disabled<?php endif; ?>">
318 - <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>
319 - <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>
320 - </div>
321 - </div>
468 + $settings_schema = [
469 + $active,
470 + ...$this->settings_schema,
471 + ];
322 472
323 - <?php
324 - $this->output_feature_box_settings();
325 - ?>
326 - </div>
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 + }
327 485
328 - <div class="action-wrap">
329 - <span class="no-dash-sync">
330 - <?php esc_html_e( 'Setting adjustments to this feature require a re-sync. Use WP-CLI.', 'elasticpress' ); ?>
331 - </span>
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 + }
332 494
333 - <input type="hidden" name="action" value="ep_save_feature">
334 - <input type="hidden" name="feature" value="<?php echo esc_attr( $this->slug ); ?>">
335 - <input type="hidden" name="requires_reindex" value="<?php echo $this->requires_install_reindex ? '1' : '0'; ?>">
336 - <input type="hidden" name="was_active" value="<?php echo $this->is_active() ? '1' : '0'; ?>">
337 - <?php wp_nonce_field( 'ep_dashboard_nonce', 'nonce' ); ?>
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 + }
338 504
339 - <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">
340 - <?php esc_html_e( 'Save', 'elasticpress' ); ?>
341 - </button>
342 - </div>
343 - </form>
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 + }
344 513
345 - <?php
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() {
346 580 }
347 581 }