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/Features.php +186 -45 4.7.15.3.5 View file →
@@ -7,9 +7,10 @@
7 7 */
8 8
9 9 namespace ElasticPress;
10 10
11 -use ElasticPress\Utils as Utils;
11 +use ElasticPress\Utils;
12 +use ElasticPress\FeatureRequirementsStatus;
12 13
13 14 if ( ! defined( 'ABSPATH' ) ) {
14 15 exit; // Exit if accessed directly.
15 16 }
@@ -38,15 +39,53 @@
38 39 add_action( 'init', array( $this, 'setup_features' ), 0 );
39 40 }
40 41
41 42 /**
43 + * Get all registered feature groups.
44 + *
45 + * This centralizes group definitions and allows extensibility via a filter.
46 + *
47 + * @since 5.3.0
48 + * @return array Array of group slugs and their labels.
49 + */
50 + public function get_feature_groups() {
51 + $groups = [
52 + 'core-search' => [
53 + 'label' => esc_html__( 'Core Search', 'elasticpress' ),
54 + ],
55 + 'live-search' => [
56 + 'label' => esc_html__( 'Live Search', 'elasticpress' ),
57 + ],
58 + 'indexing-options' => [
59 + 'label' => esc_html__( 'Indexing Options', 'elasticpress' ),
60 + ],
61 + 'woocommerce' => [
62 + 'label' => esc_html__( 'WooCommerce', 'elasticpress' ),
63 + ],
64 + 'third-party-plugins' => [
65 + 'label' => esc_html__( 'Third Party Plugins', 'elasticpress' ),
66 + ],
67 + ];
68 + /**
69 + * Filter available groups.
70 + *
71 + * @hook ep_feature_groups
72 + * @since 5.3.0
73 + * @param {array} $groups Current groups
74 + * @return {array} New groups
75 + */
76 + return apply_filters( 'ep_feature_groups', $groups );
77 + }
78 +
79 + /**
42 80 * Activate a feature
43 81 *
44 - * @param string $slug Feature slug
45 - * @since 2.2
82 + * @param string $slug Feature slug
83 + * @param string $target Whether to update a feature settings' draft or current
84 + * @since 2.2, 5.0.0 added $target
46 85 */
47 - public function activate_feature( $slug ) {
48 - $this->update_feature( $slug, array( 'active' => true ) );
86 + public function activate_feature( $slug, $target = 'current' ) {
87 + $this->update_feature( $slug, array( 'active' => true ), true, $target );
49 88 }
50 89
51 90 /**
52 91 * Deactivate a feature
@@ -88,15 +127,16 @@
88 127
89 128 /**
90 129 * Activate or deactivate a feature
91 130 *
92 - * @param string $slug Feature slug
131 + * @param string $slug Feature slug
93 132 * @param array $settings Array of settings
94 - * @param bool $force Whether to force activate/deactivate
95 - * @since 2.2
133 + * @param bool $force Whether to force activate/deactivate
134 + * @param string $target Whether to update a feature settings' draft or current. Changing current will also save the draft.
135 + * @since 2.2, 5.0.0 added $target
96 136 * @return array|bool
97 137 */
98 - public function update_feature( $slug, $settings, $force = true ) {
138 + public function update_feature( $slug, $settings, $force = true, $target = 'current' ) {
99 139 /**
100 140 * Get the feature being saved.
101 141 */
102 142 $feature = $this->get_registered_feature( $slug );
@@ -114,12 +154,18 @@
114 154
115 155 /**
116 156 * Prepare settings
117 157 */
118 - $saved_settings = Utils\get_option( 'ep_feature_settings', [] );
158 + $saved_settings = 'draft' === $target ? $this->get_feature_settings_draft() : $this->get_feature_settings();
119 159 $feature_settings = isset( $saved_settings[ $slug ] ) ? $saved_settings[ $slug ] : [ 'force_inactive' => false ];
120 160
121 - $new_feature_settings = $feature->default_settings;
161 + $new_feature_settings = wp_parse_args(
162 + $feature->default_settings,
163 + [
164 + 'active' => false,
165 + 'force_inactive' => false,
166 + ]
167 + );
122 168 $new_feature_settings = wp_parse_args( $feature_settings, $new_feature_settings );
123 169 $new_feature_settings = wp_parse_args( $settings, $new_feature_settings );
124 170
125 171 $new_feature_settings['active'] = (bool) $new_feature_settings['active'];
@@ -137,8 +183,15 @@
137 183 */
138 184 $new_settings = wp_parse_args( [ $slug => $new_feature_settings ], $saved_settings );
139 185 $new_settings = apply_filters( 'ep_sanitize_feature_settings', $new_settings, $feature );
140 186
187 + Utils\update_option( 'ep_feature_settings_draft', $new_settings );
188 +
189 + // This is as far as we go if saving just a draft
190 + if ( 'draft' === $target ) {
191 + return true;
192 + }
193 +
141 194 Utils\update_option( 'ep_feature_settings', $new_settings );
142 195
143 196 /**
144 197 * Prepare response.
@@ -161,8 +214,11 @@
161 214 }
162 215
163 216 $feature->post_activation();
164 217 }
218 + if ( $was_active && ! $is_active && method_exists( $feature, 'post_deactivation' ) ) {
219 + $feature->post_deactivation();
220 + }
165 221
166 222 /**
167 223 * If the feature has a setting that requires reindexing, return
168 224 * whether reindexing is required and the new value of the setting.
@@ -210,11 +266,17 @@
210 266 * @since 2.2
211 267 */
212 268 public function handle_feature_activation() {
213 269 /**
270 + * Give a chance to features to modify each other's requirements status before the activation is handled.
271 + */
272 + foreach ( $this->registered_features as $feature ) {
273 + $feature->pre_handle_feature_activation();
274 + }
275 +
276 + /**
214 277 * Save our current requirement statuses for later
215 278 */
216 -
217 279 $old_requirement_statuses = Utils\get_option( 'ep_feature_requirement_statuses', false );
218 280
219 281 $new_requirement_statuses = [];
220 282
@@ -219,9 +281,9 @@
219 281 $new_requirement_statuses = [];
220 282
221 283 foreach ( $this->registered_features as $slug => $feature ) {
222 284 $status = $feature->requirements_status();
223 - $new_requirement_statuses[ $slug ] = (int) $status->code;
285 + $new_requirement_statuses[ $slug ] = (int) $status->get_code();
224 286 }
225 287
226 288 $is_wp_cli = defined( 'WP_CLI' ) && \WP_CLI;
227 289
@@ -238,9 +300,9 @@
238 300 if ( false === $feature_settings ) {
239 301 $registered_features = $this->registered_features;
240 302
241 303 foreach ( $registered_features as $slug => $feature ) {
242 - if ( 0 === $feature->requirements_status()->code ) {
304 + if ( FeatureRequirementsStatus::AUTO_ENABLED === $feature->requirements_status()->get_code() ) {
243 305 $this->activate_feature( $slug );
244 306 }
245 307 }
246 308
@@ -253,44 +315,56 @@
253 315 /**
254 316 * If a requirement status changes, we need to handle that by activating/deactivating/showing notification
255 317 */
256 318
257 - if ( ( $is_wp_cli || is_admin() ) && ! empty( $old_requirement_statuses ) ) {
258 - foreach ( $new_requirement_statuses as $slug => $code ) {
259 - $feature = $this->get_registered_feature( $slug );
319 + if ( ( ! $is_wp_cli && ! is_admin() ) || empty( $old_requirement_statuses ) ) {
320 + return;
321 + }
260 322
261 - // If a feature is forced inactive, do nothing
262 - $feature_settings = $feature->get_settings();
263 - if ( is_array( $feature_settings ) && ! empty( $feature_settings['force_inactive'] ) ) {
264 - continue;
265 - }
323 + foreach ( $new_requirement_statuses as $slug => $code ) {
324 + $feature = $this->get_registered_feature( $slug );
266 325
267 - // This is a new feature
268 - if ( ! isset( $old_requirement_statuses[ $slug ] ) ) {
269 - if ( 0 === $code ) {
270 - $this->activate_feature( $slug );
326 + // If a feature is forced inactive, do nothing
327 + $feature_settings = $feature->get_settings();
328 + if ( is_array( $feature_settings ) && ! empty( $feature_settings['force_inactive'] ) ) {
329 + continue;
330 + }
271 331
272 - if ( $feature->requires_install_reindex ) {
273 - Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
274 - }
332 + // By default we will activate the feature in the current settings. If it requires a sync, we'll only update the draft
333 + $activate_feature_target = 'current';
334 +
335 + // This is a new feature
336 + if ( ! isset( $old_requirement_statuses[ $slug ] ) ) {
337 + if ( FeatureRequirementsStatus::AUTO_ENABLED === $code ) {
338 + if ( $feature->requires_install_reindex ) {
339 + $activate_feature_target = 'draft';
340 + Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
275 341 }
276 - } else {
277 - // This feature has a 0 "ok" code when it did not before
278 - if ( $old_requirement_statuses[ $slug ] !== $code && ( 0 === $code || 2 === $code ) ) {
279 - $active = ( 0 === $code );
280 342
281 - if ( ! $feature->is_active() && $active ) {
282 - $this->activate_feature( $slug );
343 + $this->activate_feature( $slug, $activate_feature_target );
344 + }
345 + } elseif (
346 + $old_requirement_statuses[ $slug ] !== $code
347 + && in_array(
348 + $code,
349 + [ FeatureRequirementsStatus::AUTO_ENABLED, FeatureRequirementsStatus::FORCE_DISABLED ],
350 + true
351 + )
352 + ) {
353 + // This feature has an "ok" code when it did not before
354 + $active = ( FeatureRequirementsStatus::AUTO_ENABLED === $code );
283 355
284 - // Need to activate and maybe set a sync notice
285 - if ( $feature->requires_install_reindex ) {
286 - Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
287 - }
288 - } elseif ( $feature->is_active() && ! $active ) {
289 - // Just deactivate, don't force
290 - $this->deactivate_feature( $slug, false );
291 - }
356 + if ( ! $feature->is_active() && $active ) {
357 + // Need to activate and maybe set a sync notice
358 + if ( $feature->requires_install_reindex ) {
359 + $activate_feature_target = 'draft';
360 + Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) );
292 361 }
362 +
363 + $this->activate_feature( $slug, $activate_feature_target );
364 + } elseif ( $feature->is_active() && ! $active ) {
365 + // Just deactivate, don't force
366 + $this->deactivate_feature( $slug, false );
293 367 }
294 368 }
295 369 }
296 370 }
@@ -308,13 +382,80 @@
308 382 * @since 2.1
309 383 */
310 384 do_action( 'ep_setup_features' );
311 385
312 - foreach ( $this->registered_features as $feature_slug => $feature ) {
313 - if ( $feature->is_active() ) {
386 + foreach ( $this->registered_features as $feature ) {
387 + $feature->set_i18n_strings();
388 +
389 + $required_features = (array) $feature->get_required_feature();
390 + $are_required_features_active = true;
391 + foreach ( $required_features as $required_feature ) {
392 + if ( ! $this->get_registered_feature( $required_feature )->is_active() ) {
393 + $are_required_features_active = false;
394 + break;
395 + }
396 + }
397 +
398 + $should_setup = $feature->is_active()
399 + && $are_required_features_active
400 + && ! in_array(
401 + $feature->requirements_status()->get_code(),
402 + [ FeatureRequirementsStatus::FORCE_DISABLED, FeatureRequirementsStatus::TEMPORARILY_DISABLED ],
403 + true
404 + );
405 +
406 + /**
407 + * Filter whether the feature should be setup.
408 + *
409 + * @since 5.3.0
410 + * @hook ep_should_setup_feature
411 + * @param {bool} $should_setup Whether the feature should be setup.
412 + * @param {Feature} $feature The feature object.
413 + * @return {bool} New should_setup value.
414 + */
415 + if ( apply_filters( 'ep_should_setup_feature', $should_setup, $feature ) ) {
314 416 $feature->setup();
315 417 }
316 418 }
419 + }
420 +
421 + /**
422 + * Return current features settings
423 + *
424 + * @since 5.0.0
425 + * @return false|array
426 + */
427 + public function get_feature_settings() {
428 + return Utils\get_option( 'ep_feature_settings', false );
429 + }
430 +
431 + /**
432 + * Get features settings draft
433 + *
434 + * @since 5.0.0
435 + * @return false|array
436 + */
437 + public function get_feature_settings_draft() {
438 + return Utils\get_option( 'ep_feature_settings_draft', false );
439 + }
440 +
441 + /**
442 + * Apply settings draft (if present)
443 + *
444 + * @since 5.0.0
445 + */
446 + public function apply_draft_feature_settings() {
447 + $draft_settings = Utils\get_option( 'ep_feature_settings_draft', false );
448 + if ( ! $draft_settings ) {
449 + return;
450 + }
451 +
452 + foreach ( $draft_settings as $feature => $settings ) {
453 + $this->update_feature( $feature, $settings );
454 + }
455 + $this->setup_features();
456 +
457 + Utils\delete_option( 'ep_feature_settings_draft' );
317 458 }
318 459
319 460 /**
320 461 * Return singleton instance of class