Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Save a draft version of feature settings #3720

Merged
merged 12 commits into from
Oct 24, 2023
5 changes: 3 additions & 2 deletions assets/js/features/config.js
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
/**
* Window dependencies.
*/
const { apiUrl, epioLogoUrl, features, indexMeta, settings, syncUrl } = window.epDashboard;
const { apiUrl, epioLogoUrl, features, indexMeta, settings, settingsDraft, syncUrl } =
window.epDashboard;

export { apiUrl, epioLogoUrl, features, indexMeta, settings, syncUrl };
export { apiUrl, epioLogoUrl, features, indexMeta, settings, settingsDraft, syncUrl };
12 changes: 10 additions & 2 deletions assets/js/features/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,15 @@ import { __ } from '@wordpress/i18n';
* Internal dependencies.
*/
import { SettingsScreenProvider } from '../settings-screen';
import { apiUrl, epioLogoUrl, features, indexMeta, settings, syncUrl } from './config';
import {
apiUrl,
epioLogoUrl,
features,
indexMeta,
settings,
settingsDraft,
syncUrl,
} from './config';
import { FeatureSettingsProvider } from './provider';
import Features from './apps/features';

Expand All @@ -26,7 +34,7 @@ const App = () => (
<SettingsScreenProvider title={__('Features', 'elasticpress')}>
<FeatureSettingsProvider
apiUrl={apiUrl}
defaultSettings={settings}
defaultSettings={settingsDraft || settings}
epioLogoUrl={epioLogoUrl}
features={features}
indexMeta={indexMeta}
Expand Down
6 changes: 3 additions & 3 deletions assets/js/features/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ export const FeatureSettingsProvider = ({
const [isBusy, setIsBusy] = useState(false);
const [isSyncing, setIsSyncing] = useState(!!indexMeta);
const [settings, setSettings] = useState({ ...defaultSettings });
const [savedSettings, setSavedSettings] = useState({ ...defaultSettings });
const [savedSettings, setSavedSettings] = useState({ ...syncedSettings });

/**
* Get a feature's data by its slug.
Expand Down Expand Up @@ -147,7 +147,7 @@ export const FeatureSettingsProvider = ({
try {
setIsBusy(true);

await apiFetch({
const response = await apiFetch({
body: JSON.stringify(settings),
headers: {
'Content-Type': 'application/json',
Expand All @@ -156,7 +156,7 @@ export const FeatureSettingsProvider = ({
url: apiUrl,
});

setSavedSettings({ ...settings });
setSavedSettings(response.data);
} finally {
setIsBusy(false);
}
Expand Down
2 changes: 1 addition & 1 deletion includes/classes/Command.php
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,7 @@ public function list_features( $args, $assoc_args ) {
$list_all = \WP_CLI\Utils\get_flag_value( $assoc_args, 'all', null );

if ( empty( $list_all ) ) {
$features = Utils\get_option( 'ep_feature_settings', [] );
$features = Features::factory()->get_feature_settings();

WP_CLI::line( esc_html__( 'Active features:', 'elasticpress' ) );

Expand Down
63 changes: 57 additions & 6 deletions includes/classes/Features.php
Original file line number Diff line number Diff line change
Expand Up @@ -89,13 +89,14 @@ public function get_registered_feature( $slug ) {
/**
* Activate or deactivate a feature
*
* @param string $slug Feature slug
* @param string $slug Feature slug
* @param array $settings Array of settings
* @param bool $force Whether to force activate/deactivate
* @since 2.2
* @param bool $force Whether to force activate/deactivate
* @param string $target Whether to update a feature settings' draft or current
* @since 2.2, 5.0.0 added $target
* @return array|bool
*/
public function update_feature( $slug, $settings, $force = true ) {
public function update_feature( $slug, $settings, $force = true, $target = 'current' ) {
/**
* Get the feature being saved.
*/
Expand All @@ -115,10 +116,16 @@ public function update_feature( $slug, $settings, $force = true ) {
/**
* Prepare settings
*/
$saved_settings = Utils\get_option( 'ep_feature_settings', [] );
$saved_settings = 'draft' === $target ? $this->get_feature_settings_draft() : $this->get_feature_settings();
$feature_settings = isset( $saved_settings[ $slug ] ) ? $saved_settings[ $slug ] : [ 'force_inactive' => false ];

$new_feature_settings = wp_parse_args( $feature->default_settings, [ 'force_inactive' => false ] );
$new_feature_settings = wp_parse_args(
$feature->default_settings,
[
'active' => false,
'force_inactive' => false,
]
);
$new_feature_settings = wp_parse_args( $feature_settings, $new_feature_settings );
$new_feature_settings = wp_parse_args( $settings, $new_feature_settings );

Expand All @@ -138,6 +145,11 @@ public function update_feature( $slug, $settings, $force = true ) {
$new_settings = wp_parse_args( [ $slug => $new_feature_settings ], $saved_settings );
$new_settings = apply_filters( 'ep_sanitize_feature_settings', $new_settings, $feature );

if ( 'draft' === $target ) {
Utils\update_option( 'ep_feature_settings_draft', $new_settings );
return true;
}

Utils\update_option( 'ep_feature_settings', $new_settings );

/**
Expand Down Expand Up @@ -316,6 +328,45 @@ public function setup_features() {
}
}

/**
* Return currnt features settings
*
* @since 5.0.0
* @return false|array
*/
public function get_feature_settings() {
return Utils\get_option( 'ep_feature_settings', false );
}

/**
* Get features settings draft
*
* @since 5.0.0
* @return false|array
*/
public function get_feature_settings_draft() {
return Utils\get_option( 'ep_feature_settings_draft', false );
}

/**
* Apply settings draft (if present)
*
* @since 5.0.0
*/
public function apply_draft_feature_settings() {
$draft_settings = Utils\get_option( 'ep_feature_settings_draft', false );
if ( ! $draft_settings ) {
return;
}

foreach ( $draft_settings as $feature => $settings ) {
$this->update_feature( $feature, $settings );
}
$this->setup_features();

Utils\delete_option( 'ep_feature_settings_draft' );
}

/**
* Return singleton instance of class
*
Expand Down
14 changes: 14 additions & 0 deletions includes/classes/IndexHelper.php
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ public function full_index( $args ) {
$this->args = apply_filters( 'ep_sync_args', $args, $this->index_meta );

if ( false === $this->index_meta ) {
$this->maybe_apply_feature_settings();
$this->build_index_meta();
}

Expand Down Expand Up @@ -1510,6 +1511,19 @@ protected function build_message_errors_data( $messages ) : array {
return $errors_list;
}

/**
* If this is a full sync, apply the draft feature settings
*
* @since 5.0.0
*/
protected function maybe_apply_feature_settings() {
if ( empty( $this->args['put_mapping'] ) ) {
return;
}

Features::factory()->apply_draft_feature_settings();
}

/**
* Return singleton instance of class.
*
Expand Down
54 changes: 47 additions & 7 deletions includes/classes/REST/Features.php
Original file line number Diff line number Diff line change
Expand Up @@ -101,42 +101,82 @@ public function check_permission() {
* Update features settings.
*
* @param \WP_REST_Request $request Full details about the request.
* @return void
* @return array
*/
public function update_settings( \WP_REST_Request $request ) {
if ( Utils\is_indexing() ) {
wp_send_json_error( 'is_syncing', 400 );
exit;
}

$settings = [];
$current_settings = FeaturesStore::factory()->get_feature_settings();
$new_settings = $current_settings;

$features = \ElasticPress\Features::factory()->registered_features;

$settings_that_requires_features = [];

foreach ( $features as $slug => $feature ) {
$param = $request->get_param( $slug );

if ( ! $param ) {
continue;
}

$settings[ $slug ] = [];
if ( empty( $current_settings[ $slug ] ) ) {
$current_settings[ $slug ] = [];
$new_settings[ $slug ] = [];
}

$schema = $feature->get_settings_schema();

foreach ( $schema as $schema ) {
$key = $schema['key'];

if ( isset( $param[ $key ] ) ) {
$settings[ $slug ][ $key ] = $param[ $key ];
$new_settings[ $slug ][ $key ] = $param[ $key ];

// Only apply to the current settings if does not require a sync or if it is activating it
if ( ! empty( $schema['requires_sync'] ) && ! empty( $param[ $key ] ) ) {
continue;
}

/*
* If a setting requires another feature, we have to check for it after running through everything,
* as it is possible that the feature will be active after this foreach.
*/
if ( empty( $schema['requires_feature'] ) ) {
$current_settings[ $slug ][ $key ] = $param[ $key ];
} else {
if ( ! isset( $settings_that_requires_features[ $slug ] ) ) {
$settings_that_requires_features[ $slug ] = [];
}
$settings_that_requires_features[ $slug ][ $key ] = [
'required_feature' => $schema['requires_feature'],
'value' => $param[ $key ],
];
}
}
}

FeaturesStore::factory()->update_feature( $slug, $settings[ $slug ] );
FeaturesStore::factory()->update_feature( $slug, $new_settings[ $slug ], true, 'draft' );
}

Utils\update_option( 'ep_feature_settings', $settings );
foreach ( $settings_that_requires_features as $feature => $fields ) {
foreach ( $fields as $field_key => $field_data ) {
if ( ! empty( $current_settings[ $field_data['required_feature'] ]['active'] ) ) {
$current_settings[ $feature ][ $field_key ] = $field_data['value'];
}
}
}

foreach ( $current_settings as $slug => $feature ) {
FeaturesStore::factory()->update_feature( $slug, $feature );
}

wp_send_json_success();
return [
'data' => $current_settings,
'success' => true,
];
}
}
18 changes: 11 additions & 7 deletions includes/classes/Screen/Features.php
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@

namespace ElasticPress\Screen;

use ElasticPress\Features as FeaturesStore;
use ElasticPress\REST;
use ElasticPress\Screen;
use ElasticPress\Utils;
Expand Down Expand Up @@ -59,7 +60,9 @@ public function admin_enqueue_scripts() {
Utils\get_asset_info( 'features-script', 'version' )
);

$features = \ElasticPress\Features::factory()->registered_features;
$store = FeaturesStore::factory();

$features = $store->registered_features;
$features = array_map( fn( $f ) => $f->get_json(), $features );
$features = array_values( $features );

Expand All @@ -68,12 +71,13 @@ public function admin_enqueue_scripts() {
admin_url( 'admin.php?page=elasticpress-sync' );

$data = [
'apiUrl' => rest_url( 'elasticpress/v1/features' ),
'epioLogoUrl' => esc_url( plugins_url( '/images/logo-elasticpress-io.svg', EP_FILE ) ),
'features' => $features,
'indexMeta' => Utils\get_indexing_status(),
'settings' => Utils\get_option( 'ep_feature_settings', [] ),
'syncUrl' => $sync_url,
'apiUrl' => rest_url( 'elasticpress/v1/features' ),
'epioLogoUrl' => esc_url( plugins_url( '/images/logo-elasticpress-io.svg', EP_FILE ) ),
'features' => $features,
'indexMeta' => Utils\get_indexing_status(),
'settings' => $store->get_feature_settings(),
'settingsDraft' => $store->get_feature_settings_draft(),
'syncUrl' => $sync_url,
];

wp_localize_script( 'ep_features_script', 'epDashboard', $data );
Expand Down
Loading
Loading