| @@ -8,8 +8,9 @@ | ||
| 8 | 8 | |
| 9 | 9 | namespace ElasticPress; |
| 10 | 10 | |
| 11 | 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,8 +39,45 @@ | ||
| 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 | 82 | * @param string $slug Feature slug |
| 45 | 83 | * @param string $target Whether to update a feature settings' draft or current |
| @@ -176,8 +214,11 @@ | ||
| 176 | 214 | } |
| 177 | 215 | |
| 178 | 216 | $feature->post_activation(); |
| 179 | 217 | } |
| 218 | + if ( $was_active && ! $is_active && method_exists( $feature, 'post_deactivation' ) ) { | |
| 219 | + $feature->post_deactivation(); | |
| 220 | + } | |
| 180 | 221 | |
| 181 | 222 | /** |
| 182 | 223 | * If the feature has a setting that requires reindexing, return |
| 183 | 224 | * whether reindexing is required and the new value of the setting. |
| @@ -225,11 +266,17 @@ | ||
| 225 | 266 | * @since 2.2 |
| 226 | 267 | */ |
| 227 | 268 | public function handle_feature_activation() { |
| 228 | 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 | + /** | |
| 229 | 277 | * Save our current requirement statuses for later |
| 230 | 278 | */ |
| 231 | - | |
| 232 | 279 | $old_requirement_statuses = Utils\get_option( 'ep_feature_requirement_statuses', false ); |
| 233 | 280 | |
| 234 | 281 | $new_requirement_statuses = []; |
| 235 | 282 | |
| @@ -234,9 +281,9 @@ | ||
| 234 | 281 | $new_requirement_statuses = []; |
| 235 | 282 | |
| 236 | 283 | foreach ( $this->registered_features as $slug => $feature ) { |
| 237 | 284 | $status = $feature->requirements_status(); |
| 238 | - $new_requirement_statuses[ $slug ] = (int) $status->code; | |
| 285 | + $new_requirement_statuses[ $slug ] = (int) $status->get_code(); | |
| 239 | 286 | } |
| 240 | 287 | |
| 241 | 288 | $is_wp_cli = defined( 'WP_CLI' ) && \WP_CLI; |
| 242 | 289 | |
| @@ -253,9 +300,9 @@ | ||
| 253 | 300 | if ( false === $feature_settings ) { |
| 254 | 301 | $registered_features = $this->registered_features; |
| 255 | 302 | |
| 256 | 303 | foreach ( $registered_features as $slug => $feature ) { |
| 257 | - if ( 0 === $feature->requirements_status()->code ) { | |
| 304 | + if ( FeatureRequirementsStatus::AUTO_ENABLED === $feature->requirements_status()->get_code() ) { | |
| 258 | 305 | $this->activate_feature( $slug ); |
| 259 | 306 | } |
| 260 | 307 | } |
| 261 | 308 | |
| @@ -286,9 +333,9 @@ | ||
| 286 | 333 | $activate_feature_target = 'current'; |
| 287 | 334 | |
| 288 | 335 | // This is a new feature |
| 289 | 336 | if ( ! isset( $old_requirement_statuses[ $slug ] ) ) { |
| 290 | - if ( 0 === $code ) { | |
| 337 | + if ( FeatureRequirementsStatus::AUTO_ENABLED === $code ) { | |
| 291 | 338 | if ( $feature->requires_install_reindex ) { |
| 292 | 339 | $activate_feature_target = 'draft'; |
| 293 | 340 | Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); |
| 294 | 341 | } |
| @@ -294,25 +341,30 @@ | ||
| 294 | 341 | } |
| 295 | 342 | |
| 296 | 343 | $this->activate_feature( $slug, $activate_feature_target ); |
| 297 | 344 | } |
| 298 | - } else { | |
| 299 | - // This feature has a 0 "ok" code when it did not before | |
| 300 | - if ( $old_requirement_statuses[ $slug ] !== $code && ( 0 === $code || 2 === $code ) ) { | |
| 301 | - $active = ( 0 === $code ); | |
| 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 ); | |
| 302 | 355 | |
| 303 | - if ( ! $feature->is_active() && $active ) { | |
| 304 | - // Need to activate and maybe set a sync notice | |
| 305 | - if ( $feature->requires_install_reindex ) { | |
| 306 | - $activate_feature_target = 'draft'; | |
| 307 | - Utils\update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); | |
| 308 | - } | |
| 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 ) ); | |
| 361 | + } | |
| 309 | 362 | |
| 310 | - $this->activate_feature( $slug, $activate_feature_target ); | |
| 311 | - } elseif ( $feature->is_active() && ! $active ) { | |
| 312 | - // Just deactivate, don't force | |
| 313 | - $this->deactivate_feature( $slug, false ); | |
| 314 | - } | |
| 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 ); | |
| 315 | 367 | } |
| 316 | 368 | } |
| 317 | 369 | } |
| 318 | 370 | } |
| @@ -330,10 +382,38 @@ | ||
| 330 | 382 | * @since 2.1 |
| 331 | 383 | */ |
| 332 | 384 | do_action( 'ep_setup_features' ); |
| 333 | 385 | |
| 334 | - foreach ( $this->registered_features as $feature_slug => $feature ) { | |
| 335 | - 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 ) ) { | |
| 336 | 416 | $feature->setup(); |
| 337 | 417 | } |
| 338 | 418 | } |
| 339 | 419 | } |
| @@ -338,9 +418,9 @@ | ||
| 338 | 418 | } |
| 339 | 419 | } |
| 340 | 420 | |
| 341 | 421 | /** |
| 342 | - * Return currnt features settings | |
| 422 | + * Return current features settings | |
| 343 | 423 | * |
| 344 | 424 | * @since 5.0.0 |
| 345 | 425 | * @return false|array |
| 346 | 426 | */ |