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 +356 -115 4.2.05.3.5 View file →
@@ -9,9 +9,10 @@
9 9 */
10 10
11 11 namespace ElasticPress;
12 12
13 -use ElasticPress\FeatureRequirementsStatus as FeatureRequirementsStatus;
13 +use ElasticPress\FeatureRequirementsStatus;
14 +use ElasticPress\Utils;
14 15
15 16 if ( ! defined( 'ABSPATH' ) ) {
16 17 exit; // Exit if accessed directly.
17 18 }
@@ -36,8 +37,16 @@
36 37 */
37 38 public $title;
38 39
39 40 /**
41 + * Short title
42 + *
43 + * @var string
44 + * @since 4.4.1
45 + */
46 + public $short_title;
47 +
48 + /**
40 49 * Feature summary
41 50 *
42 51 * @var string
43 52 * @since 4.0.0
@@ -63,13 +72,21 @@
63 72 /**
64 73 * True if the feature requires content reindexing after activating
65 74 *
66 75 * @since 2.1
67 - * @var [type]
76 + * @var bool
68 77 */
69 - public $requires_install_reindex;
78 + public $requires_install_reindex = false;
70 79
71 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 + /**
72 89 * The order in the features screen
73 90 *
74 91 * @var int
75 92 * @since 3.6.0
@@ -93,33 +110,63 @@
93 110 */
94 111 public $available_during_installation = false;
95 112
96 113 /**
97 - * Run on every page load for feature to set itself up
114 + * Whether the feature should be always visible in the dashboard
98 115 *
99 - * @since 2.1
116 + * @since 4.5.0
117 + * @var boolean
100 118 */
101 - abstract public function setup();
119 + protected $is_visible = true;
102 120
103 121 /**
104 - * Output feature box summary
122 + * Settings description
105 123 *
106 - * @since 2.1
124 + * @since 5.0.0
125 + * @var array
107 126 */
108 - public function output_feature_box_summary() {
109 - if ( $this->summary ) {
110 - echo '<p>' . esc_html( $this->summary ) . '</p>';
111 - }
112 - }
127 + protected $settings_schema = [];
113 128
114 129 /**
115 - * Implement to output feature box long text
130 + * The slug, or array of slugs, of a feature that is required to be active.
116 131 *
117 - * @since 3.0
132 + * @since 5.0.0
133 + * @var false|string|array
118 134 */
119 - abstract public function output_feature_box_long();
135 + protected $requires_feature = false;
120 136
121 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 + /**
122 169 * Create feature
123 170 *
124 171 * @since 3.0
125 172 */
@@ -140,14 +187,14 @@
140 187 * @since 2.2
141 188 * @return FeatureRequirementsStatus
142 189 */
143 190 public function requirements_status() {
144 - $status = new FeatureRequirementsStatus( 0 );
191 + $status = new FeatureRequirementsStatus( 0, null, $this );
145 192
146 193 /**
147 194 * Filter feature requirement status
148 195 *
149 - * @hook ep_{indexable_slug}_index_kill
196 + * @hook ep_feature_requirements_status
150 197 * @param {FeatureRequirementStatus} $status Current feature requirement status
151 198 * @param {Feature} $feature Current feature
152 199 * @since 2.2
153 200 * @return {FeatureRequirementStatus} New status
@@ -157,22 +204,35 @@
157 204
158 205 /**
159 206 * Return feature settings
160 207 *
161 - * @since 2.2.1
162 - * @return array|bool
208 + * @since 2.2.1, 4.5.0 started using default settings
209 + * @return array
163 210 */
164 211 public function get_settings() {
165 - if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
166 - $feature_settings = get_site_option( 'ep_feature_settings', [] );
167 - } else {
168 - $feature_settings = get_option( 'ep_feature_settings', [] );
169 - }
212 + $all_settings = Utils\get_option( 'ep_feature_settings', [] );
170 213
171 - 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;
172 219 }
173 220
174 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 + /**
175 235 * Returns true if feature is active
176 236 *
177 237 * @since 2.2
178 238 * @return boolean
@@ -177,18 +237,18 @@
177 237 * @since 2.2
178 238 * @return boolean
179 239 */
180 240 public function is_active() {
181 - if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) {
182 - $feature_settings = get_site_option( 'ep_feature_settings', [] );
183 - } else {
184 - $feature_settings = get_option( 'ep_feature_settings', [] );
185 - }
241 + $feature_settings = Utils\get_option( 'ep_feature_settings', [] );
186 242
187 243 $active = false;
188 244
189 245 if ( ! empty( $feature_settings[ $this->slug ] ) && $feature_settings[ $this->slug ]['active'] ) {
190 - $active = true;
246 + $active = ! in_array(
247 + $this->requirements_status()->get_code(),
248 + [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
249 + true
250 + );
191 251 }
192 252
193 253 /**
194 254 * Filter whether a feature is active or not
@@ -203,8 +263,23 @@
203 263 return apply_filters( 'ep_feature_active', $active, $feature_settings, $this );
204 264 }
205 265
206 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 + /**
207 282 * To be run after initial feature activation
208 283 *
209 284 * @since 2.1
210 285 */
@@ -220,121 +295,287 @@
220 295 do_action( 'ep_feature_post_activation', $this->slug, $this );
221 296 }
222 297
223 298 /**
224 - * Outputs feature box
299 + * To be run after feature deactivation
225 300 *
226 - * @since 2.1
301 + * @since 5.3.2
227 302 */
228 - public function output_feature_box() {
229 - $this->output_feature_box_summary();
230 -
303 + public function post_deactivation() {
231 304 /**
232 - * Fires before feature box summary is shown
305 + * Fires after feature is deactivated
233 306 *
234 - * @hook ep_feature_box_summary
235 - * @param {string} $slug Feature slug
307 + * @hook ep_feature_post_deactivation
308 + * @param {string} $slug Feature slug
236 309 * @param {Feature} $feature Current feature
237 - * @since 2.1
310 + * @since 5.3.2
238 311 */
239 - do_action( 'ep_feature_box_summary', $this->slug, $this );
240 - ?>
312 + do_action( 'ep_feature_post_deactivation', $this->slug, $this );
313 + }
241 314
242 - <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 + }
243 324
244 - <div class="long">
245 - <?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 + }
246 335
247 - <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 + }
248 338
249 - <?php
250 - /**
251 - * Fires after feature long description
252 - *
253 - * @hook ep_feature_box_long
254 - * @param {string} $slug Feature slug
255 - * @param {Feature} $feature Current feature
256 - * @since 2.1
257 - */
258 - do_action( 'ep_feature_box_long', $this->slug, $this );
259 - ?>
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 );
371 + }
260 372
261 - </div>
262 - <?php
373 + /**
374 + * Returns whether the feature is available or not.
375 + *
376 + * @since 4.5.0
377 + * @return boolean
378 + */
379 + public function is_available(): bool {
380 + $requirements_status = $this->requirements_status();
381 + /**
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
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 + );
263 414 }
264 415
265 416 /**
266 - * Output extra feature box settings.
417 + * Get a JSON representation of the feature
267 418 *
268 - * By default this does nothing. Override to add additional settings.
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
269 449 *
270 - * @since 3.0
450 + * @since 5.0.0
451 + * @return array
271 452 */
272 - public function output_feature_box_settings() {
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 +
273 473 /**
274 - * Optionally override
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
275 482 */
483 + return apply_filters( 'ep_feature_settings_schema', $settings_schema, $this->slug, $this );
276 484 }
277 485
278 486 /**
279 - * Output feature settings
487 + * Reset the cached settings schema so it is rebuilt on next access.
280 488 *
281 - * @since 3.0
489 + * @since 5.3.3
282 490 */
283 - public function output_settings_box() {
284 - $requirements_status = $this->requirements_status();
285 - ?>
491 + public function reset_settings_schema() {
492 + $this->settings_schema = [];
493 + }
286 494
287 - <form>
288 - <?php
289 - if ( ! empty( $requirements_status->message ) ) :
290 - $messages = (array) $requirements_status->message;
291 - ?>
292 - <?php foreach ( $messages as $message ) : ?>
293 - <div class="requirements-status-notice">
294 - <?php echo wp_kses_post( $message ); ?>
295 - </div>
296 - <?php endforeach; ?>
297 - <?php endif; ?>
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 + }
298 504
299 - <?php if ( $this->requires_install_reindex ) : ?>
300 - <div class="requirements-status-notice requirements-status-notice--reindex" role="status">
301 - <?php esc_html_e( 'Enabling this feature will require re-indexing your content.', 'elasticpress' ); ?>
302 - </div>
303 - <?php endif; ?>
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 + }
304 513
305 - <h3><?php esc_html_e( 'Settings', 'elasticpress' ); ?></h3>
514 + $this->settings_schema[] = [
515 + 'default' => $default_value,
516 + 'key' => $key,
517 + 'label' => $key,
518 + 'type' => $type,
519 + ];
520 + }
521 + }
306 522
307 - <div class="feature-fields">
308 - <div class="field js-toggle-feature">
309 - <div class="field-name status"><?php esc_html_e( 'Status', 'elasticpress' ); ?></div>
310 - <div class="input-wrap <?php if ( 2 === $requirements_status->code ) : ?>disabled<?php endif; ?>">
311 - <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>
312 - <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>
313 - </div>
314 - </div>
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 + }
315 531
316 - <?php
317 - $this->output_feature_box_settings();
318 - ?>
319 - </div>
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 + }
320 541
321 - <div class="action-wrap">
322 - <span class="no-dash-sync">
323 - <?php esc_html_e( 'Setting adjustments to this feature require a re-sync. Use WP-CLI.', 'elasticpress' ); ?>
324 - </span>
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 + }
325 559
326 - <input type="hidden" name="action" value="ep_save_feature">
327 - <input type="hidden" name="feature" value="<?php echo esc_attr( $this->slug ); ?>">
328 - <input type="hidden" name="requires_reindex" value="<?php echo $this->requires_install_reindex ? '1' : '0'; ?>">
329 - <input type="hidden" name="was_active" value="<?php echo $this->is_active() ? '1' : '0'; ?>">
330 - <?php wp_nonce_field( 'ep_dashboard_nonce', 'nonce' ); ?>
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 + }
331 569
332 - <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">
333 - <?php esc_html_e( 'Save', 'elasticpress' ); ?>
334 - </button>
335 - </div>
336 - </form>
337 -
338 - <?php
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() {
339 580 }
340 581 }