update_feature( $slug, array( 'active' => true ) ); } /** * Dectivate a feature * * @param string $slug Feature slug * @param bool $force Whether to force deactivation * @since 2.2 */ public function deactivate_feature( $slug, $force = true ) { $this->update_feature( $slug, array( 'active' => false ), $force ); } /** * Registers a feature for use in ElasticPress * * @param Feature $feature An instance of the Feature class * @since 3.0 * @return boolean */ public function register_feature( Feature $feature ) { $feature_args['slug'] = $feature->slug; $this->registered_features[ $feature->slug ] = $feature; return true; } /** * Easy access function to get a Feature object from a slug * * @param string $slug Feature slug * @since 2.1 * @return Feature */ public function get_registered_feature( $slug ) { if ( empty( $this->registered_features[ $slug ] ) ) { return false; } return $this->registered_features[ $slug ]; } /** * Activate or deactivate a feature * * @param string $slug Feature slug * @param array $settings Array of settings * @param bool $force Whether to force activate/deactivate * @since 2.2 * @return array|bool */ public function update_feature( $slug, $settings, $force = true ) { $feature = $this->get_registered_feature( $slug ); if ( empty( $feature ) ) { return false; } $original_state = $feature->is_active(); if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { $feature_settings = get_site_option( 'ep_feature_settings', [] ); } else { $feature_settings = get_option( 'ep_feature_settings', [] ); } if ( empty( $feature_settings[ $slug ] ) ) { // If doesn't exist, merge with feature defaults $feature_settings[ $slug ] = wp_parse_args( $settings, $feature->default_settings ); } else { // If exist just merge changed values into current $feature_settings[ $slug ] = wp_parse_args( $settings, $feature_settings[ $slug ] ); } // Make sure active is a proper bool $feature_settings[ $slug ]['active'] = (bool) $feature_settings[ $slug ]['active']; if ( $feature_settings[ $slug ]['active'] ) { $feature_settings[ $slug ]['force_inactive'] = false; } // This means someone has explicitly deactivated the feature if ( $force ) { if ( ! (bool) $settings['active'] && $original_state ) { $feature_settings[ $slug ]['force_inactive'] = true; } } $sanitize_feature_settings = apply_filters( 'ep_sanitize_feature_settings', $feature_settings, $feature ); if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { update_site_option( 'ep_feature_settings', $sanitize_feature_settings ); } else { update_option( 'ep_feature_settings', $sanitize_feature_settings ); } $data = array( 'active' => $sanitize_feature_settings[ $slug ]['active'], 'reindex' => false, ); if ( $feature_settings[ $slug ]['active'] && ! $original_state ) { if ( ! empty( $feature->requires_install_reindex ) ) { $data['reindex'] = true; } $feature->post_activation(); } /** * Fires after activating, inactivating, or just updating a feature. * * @hook ep_after_update_feature * @param {string} $feature Feature slug * @param {array} $settings Feature settings * @param {array} $data Feature activation data * * @since 3.5.5 */ do_action( 'ep_after_update_feature', $slug, $settings, $data ); return $data; } /** * When plugins are adjusted, we need to determine how to activate/deactivate features * * @since 2.2 */ public function handle_feature_activation() { /** * Save our current requirement statuses for later */ if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { $old_requirement_statuses = get_site_option( 'ep_feature_requirement_statuses', false ); } else { $old_requirement_statuses = get_option( 'ep_feature_requirement_statuses', false ); } $new_requirement_statuses = []; foreach ( $this->registered_features as $slug => $feature ) { $status = $feature->requirements_status(); $new_requirement_statuses[ $slug ] = (int) $status->code; } $is_wp_cli = defined( 'WP_CLI' ) && \WP_CLI; if ( $is_wp_cli || is_admin() ) { if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { update_site_option( 'ep_feature_requirement_statuses', $new_requirement_statuses ); } else { update_option( 'ep_feature_requirement_statuses', $new_requirement_statuses ); } } /** * If feature settings aren't created, let's create them and finish */ if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { $feature_settings = get_site_option( 'ep_feature_settings', false ); } else { $feature_settings = get_option( 'ep_feature_settings', false ); } if ( false === $feature_settings ) { $registered_features = $this->registered_features; foreach ( $registered_features as $slug => $feature ) { if ( 0 === $feature->requirements_status()->code ) { $this->activate_feature( $slug ); } } /** * Nothing else to do since we are doing initial activation */ return; } /** * If a requirement status changes, we need to handle that by activating/deactivating/showing notification */ if ( ( $is_wp_cli || is_admin() ) && ! empty( $old_requirement_statuses ) ) { foreach ( $new_requirement_statuses as $slug => $code ) { $feature = $this->get_registered_feature( $slug ); // If a feature is forced inactive, do nothing $feature_settings = $feature->get_settings(); if ( is_array( $feature_settings ) && ! empty( $feature_settings['force_inactive'] ) ) { continue; } // This is a new feature if ( ! isset( $old_requirement_statuses[ $slug ] ) ) { if ( 0 === $code ) { $this->activate_feature( $slug ); if ( $feature->requires_install_reindex ) { if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { update_site_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); } else { update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); } } } } else { // This feature has a 0 "ok" code when it did not before if ( $old_requirement_statuses[ $slug ] !== $code && ( 0 === $code || 2 === $code ) ) { $active = ( 0 === $code ); if ( ! $feature->is_active() && $active ) { $this->activate_feature( $slug ); // Need to activate and maybe set a sync notice if ( $feature->requires_install_reindex ) { if ( defined( 'EP_IS_NETWORK' ) && EP_IS_NETWORK ) { update_site_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); } else { update_option( 'ep_feature_auto_activated_sync', sanitize_text_field( $slug ) ); } } } elseif ( $feature->is_active() && ! $active ) { // Just deactivate, don't force $this->deactivate_feature( $slug, false ); } } } } } } /** * Set up all active features * * @since 2.1 */ public function setup_features() { /** * Fires before features are setup * * @hook ep_setup_features * @since 2.1 */ do_action( 'ep_setup_features' ); foreach ( $this->registered_features as $feature_slug => $feature ) { if ( $feature->is_active() ) { $feature->setup(); } } } /** * Return singleton instance of class * * @return object * @since 2.1 */ public static function factory() { static $instance = false; if ( ! $instance ) { $instance = new self(); $instance->setup(); } return $instance; } }