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
elasticpress / includes / classes / Feature.php

Feature.php in ElasticPress 5.3.5, at includes/classes/Feature.php

582 lines 12.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Feature class to be initiated for all features.
4 *
5 * All features extend this class.
6 *
7 * @since 2.1
8 * @package elasticpress
9 */
10
11 namespace ElasticPress;
12
13 use ElasticPress\FeatureRequirementsStatus;
14 use ElasticPress\Utils;
15
16 if ( ! defined( 'ABSPATH' ) ) {
17 exit; // Exit if accessed directly.
18 }
19
20 /**
21 * Feature abstract class
22 */
23 abstract class Feature {
24 /**
25 * Feature slug
26 *
27 * @var string
28 * @since 2.1
29 */
30 public $slug;
31
32 /**
33 * Feature pretty title
34 *
35 * @var string
36 * @since 2.1
37 */
38 public $title;
39
40 /**
41 * Short title
42 *
43 * @var string
44 * @since 4.4.1
45 */
46 public $short_title;
47
48 /**
49 * Feature summary
50 *
51 * @var string
52 * @since 4.0.0
53 */
54 public $summary;
55
56 /**
57 * URL to feature documentation.
58 *
59 * @var string
60 * @since 4.0.0
61 */
62 public $docs_url;
63
64 /**
65 * Optional feature default settings
66 *
67 * @since 2.2
68 * @var array
69 */
70 public $default_settings = [];
71
72 /**
73 * True if the feature requires content reindexing after activating
74 *
75 * @since 2.1
76 * @var bool
77 */
78 public $requires_install_reindex = false;
79
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 /**
89 * The order in the features screen
90 *
91 * @var int
92 * @since 3.6.0
93 */
94 public $order;
95
96 /**
97 * Set if a feature should be on the left or right side
98 *
99 * @var string
100 * @since 3.6.0
101 */
102 public $group_order;
103
104 /**
105 * True if activation of this feature should be available during
106 * installation.
107 *
108 * @since 4.0.0
109 * @var boolean
110 */
111 public $available_during_installation = false;
112
113 /**
114 * Whether the feature should be always visible in the dashboard
115 *
116 * @since 4.5.0
117 * @var boolean
118 */
119 protected $is_visible = true;
120
121 /**
122 * Settings description
123 *
124 * @since 5.0.0
125 * @var array
126 */
127 protected $settings_schema = [];
128
129 /**
130 * The slug, or array of slugs, of a feature that is required to be active.
131 *
132 * @since 5.0.0
133 * @var false|string|array
134 */
135 protected $requires_feature = false;
136
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 /**
169 * Create feature
170 *
171 * @since 3.0
172 */
173 public function __construct() {
174 /**
175 * Fires when Feature object is created
176 *
177 * @hook ep_feature_create
178 * @param {Feature} $feature Current feature
179 * @since 3.0
180 */
181 do_action( 'ep_feature_create', $this );
182 }
183
184 /**
185 * Returns requirements status of feature
186 *
187 * @since 2.2
188 * @return FeatureRequirementsStatus
189 */
190 public function requirements_status() {
191 $status = new FeatureRequirementsStatus( 0, null, $this );
192
193 /**
194 * Filter feature requirement status
195 *
196 * @hook ep_feature_requirements_status
197 * @param {FeatureRequirementStatus} $status Current feature requirement status
198 * @param {Feature} $feature Current feature
199 * @since 2.2
200 * @return {FeatureRequirementStatus} New status
201 */
202 return apply_filters( 'ep_feature_requirements_status', $status, $this );
203 }
204
205 /**
206 * Return feature settings
207 *
208 * @since 2.2.1, 4.5.0 started using default settings
209 * @return array
210 */
211 public function get_settings() {
212 $all_settings = Utils\get_option( 'ep_feature_settings', [] );
213
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;
219 }
220
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 /**
235 * Returns true if feature is active
236 *
237 * @since 2.2
238 * @return boolean
239 */
240 public function is_active() {
241 $feature_settings = Utils\get_option( 'ep_feature_settings', [] );
242
243 $active = false;
244
245 if ( ! empty( $feature_settings[ $this->slug ] ) && $feature_settings[ $this->slug ]['active'] ) {
246 $active = ! in_array(
247 $this->requirements_status()->get_code(),
248 [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
249 true
250 );
251 }
252
253 /**
254 * Filter whether a feature is active or not
255 *
256 * @hook ep_feature_active
257 * @param {bool} $active Whether feature is active or not
258 * @param {array} $feature_settings Current feature settings
259 * @param {Feature} $feature Current feature
260 * @since 2.2
261 * @return {bool} New active value
262 */
263 return apply_filters( 'ep_feature_active', $active, $feature_settings, $this );
264 }
265
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 /**
282 * To be run after initial feature activation
283 *
284 * @since 2.1
285 */
286 public function post_activation() {
287 /**
288 * Fires after feature is activated
289 *
290 * @hook ep_feature_post_activation
291 * @param {string} $slug Feature slug
292 * @param {Feature} $feature Current feature
293 * @since 2.1
294 */
295 do_action( 'ep_feature_post_activation', $this->slug, $this );
296 }
297
298 /**
299 * To be run after feature deactivation
300 *
301 * @since 5.3.2
302 */
303 public function post_deactivation() {
304 /**
305 * Fires after feature is deactivated
306 *
307 * @hook ep_feature_post_deactivation
308 * @param {string} $slug Feature slug
309 * @param {Feature} $feature Current feature
310 * @since 5.3.2
311 */
312 do_action( 'ep_feature_post_deactivation', $this->slug, $this );
313 }
314
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 }
324
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 }
335
336 return $this->get_title();
337 }
338
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 }
372
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 );
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() {
580 }
581 }
582