Skip to content

Commit eba3b0d

Browse files
committed
fix: Refine Freemius validation to preserve existing saved rows and only block wizard progression on Freemius step
- Check is_freemius_step before blocking wizard progression on validation errors - Update has_blocking_validation_error to check for freemius_validation_partial code - Preserve existing saved plugin rows when validation fails instead of discarding them - Add resolve_saved_or_submitted_plugin_row to return saved values for invalid rows - Build existing_by_row_id lookup table for efficient row matching
1 parent 7a279fe commit eba3b0d

2 files changed

Lines changed: 72 additions & 19 deletions

File tree

includes/admin/class-settings-wizard.php

Lines changed: 29 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -171,11 +171,12 @@ public function process_step() {
171171
switch ( $action ) {
172172
case 'next_step':
173173
$this->process_current_step();
174-
if ( $this->has_blocking_validation_error() ) {
174+
if ( $this->is_freemius_step() && $this->has_blocking_validation_error() ) {
175+
$this->redirect_to_step( $this->current_step );
176+
} else {
177+
$this->next_step();
175178
$this->redirect_to_step( $this->current_step );
176179
}
177-
$this->next_step();
178-
$this->redirect_to_step( $this->current_step );
179180
break;
180181

181182
case 'previous_step':
@@ -185,11 +186,12 @@ public function process_step() {
185186

186187
case 'finish_setup':
187188
$this->process_current_step();
188-
if ( $this->has_blocking_validation_error() ) {
189+
if ( $this->is_freemius_step() && $this->has_blocking_validation_error() ) {
189190
$this->redirect_to_step( $this->current_step );
191+
} else {
192+
$this->mark_wizard_completed();
193+
$this->redirect_to_step( $this->total_steps + 1 );
190194
}
191-
$this->mark_wizard_completed();
192-
$this->redirect_to_step( $this->total_steps + 1 );
193195
break;
194196

195197
case 'skip_wizard':
@@ -207,19 +209,36 @@ public function process_step() {
207209
* @return bool
208210
*/
209211
private function has_blocking_validation_error(): bool {
210-
$errors = get_settings_errors( $this->prefix . '-notices' );
212+
$errors = get_settings_errors();
211213

212214
foreach ( $errors as $error ) {
213-
$code = (string) $error['code'];
214-
$type = (string) $error['type'];
215-
if ( $this->prefix . '_freemius_validation_failed' === $code && 'error' === $type ) {
215+
$setting = (string) $error['setting'];
216+
$code = (string) $error['code'];
217+
$type = (string) $error['type'];
218+
if (
219+
$this->prefix . '_freemius_validation_partial' === $code
220+
&& 'error' === $type
221+
&& ( '' === $setting || $this->prefix . '-notices' === $setting )
222+
) {
216223
return true;
217224
}
218225
}
219226

220227
return false;
221228
}
222229

230+
/**
231+
* Check whether the current wizard step is the Freemius step.
232+
*
233+
* @return bool
234+
*/
235+
private function is_freemius_step(): bool {
236+
$keys = array_keys( $this->steps );
237+
$index = $this->get_current_step() - 1;
238+
239+
return isset( $keys[ $index ] ) && 'freemius' === $keys[ $index ];
240+
}
241+
223242
/**
224243
* Build settings array for a wizard step from setting keys.
225244
*

includes/admin/class-settings.php

Lines changed: 43 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -744,14 +744,14 @@ public function change_settings_on_save( array $settings, array $input = array()
744744
$validation = $this->validate_freemius_plugins_for_save( $settings );
745745
$errors = $validation['errors'];
746746

747-
// Persist only validated plugin rows.
747+
// Persist validated rows and preserve existing saved rows for invalid entries.
748748
$settings['plugins'] = $validation['plugins'];
749749

750750
if ( ! empty( $errors ) ) {
751751
add_settings_error(
752752
self::$prefix . '-notices',
753753
self::$prefix . '_freemius_validation_partial',
754-
esc_html__( 'Some Freemius plugin rows failed validation and were not saved.', 'freemkit' ),
754+
esc_html__( 'Some Freemius plugin rows failed validation. Existing saved values were kept for those rows.', 'freemkit' ),
755755
'error'
756756
);
757757

@@ -776,9 +776,24 @@ public function change_settings_on_save( array $settings, array $input = array()
776776
* @return array{plugins: array<int,mixed>, errors: array<int,string>} Filtered rows and validation errors.
777777
*/
778778
private function validate_freemius_plugins_for_save( array $settings ): array {
779-
$errors = array();
780-
$valid_plugins = array();
781-
$plugins = isset( $settings['plugins'] ) && is_array( $settings['plugins'] ) ? $settings['plugins'] : array();
779+
$errors = array();
780+
$persisted_plugins = array();
781+
$plugins = isset( $settings['plugins'] ) && is_array( $settings['plugins'] ) ? $settings['plugins'] : array();
782+
$existing_settings = get_option( Options_API::SETTINGS_OPTION, array() );
783+
$existing_plugins = ( is_array( $existing_settings ) && isset( $existing_settings['plugins'] ) && is_array( $existing_settings['plugins'] ) )
784+
? $existing_settings['plugins']
785+
: array();
786+
787+
$existing_by_row_id = array();
788+
foreach ( $existing_plugins as $existing_plugin ) {
789+
if ( ! is_array( $existing_plugin ) ) {
790+
continue;
791+
}
792+
$row_id = isset( $existing_plugin['row_id'] ) ? (string) $existing_plugin['row_id'] : '';
793+
if ( '' !== $row_id ) {
794+
$existing_by_row_id[ $row_id ] = $existing_plugin;
795+
}
796+
}
782797

783798
foreach ( $plugins as $index => $plugin ) {
784799
if ( ! is_array( $plugin ) || ! isset( $plugin['fields'] ) || ! is_array( $plugin['fields'] ) ) {
@@ -798,26 +813,45 @@ private function validate_freemius_plugins_for_save( array $settings ): array {
798813

799814
if ( '' === $plugin_id || '' === $public_key || '' === $secret_key ) {
800815
/* translators: %s: plugin row label. */
801-
$errors[] = sprintf( esc_html__( '%s: Product ID, Public Key, and Secret Key are required.', 'freemkit' ), esc_html( $label ) );
816+
$errors[] = sprintf( esc_html__( '%s: Product ID, Public Key, and Secret Key are required.', 'freemkit' ), esc_html( $label ) );
817+
$persisted_plugins[] = $this->resolve_saved_or_submitted_plugin_row( $plugin, $existing_by_row_id );
802818
continue;
803819
}
804820

805821
$result = $this->validate_freemius_credentials( $plugin_id, $public_key, $secret_key );
806822
if ( is_wp_error( $result ) ) {
807823
/* translators: 1: plugin row label, 2: validation error message. */
808-
$errors[] = sprintf( esc_html__( '%1$s: %2$s', 'freemkit' ), esc_html( $label ), esc_html( $result->get_error_message() ) );
824+
$errors[] = sprintf( esc_html__( '%1$s: %2$s', 'freemkit' ), esc_html( $label ), esc_html( $result->get_error_message() ) );
825+
$persisted_plugins[] = $this->resolve_saved_or_submitted_plugin_row( $plugin, $existing_by_row_id );
809826
continue;
810827
}
811828

812-
$valid_plugins[] = $plugin;
829+
$persisted_plugins[] = $plugin;
813830
}
814831

815832
return array(
816-
'plugins' => array_values( $valid_plugins ),
833+
'plugins' => array_values( $persisted_plugins ),
817834
'errors' => $errors,
818835
);
819836
}
820837

838+
/**
839+
* Return existing saved plugin row when possible, otherwise submitted row.
840+
*
841+
* @param array $submitted_plugin Submitted plugin row.
842+
* @param array $existing_by_row_id Existing rows indexed by row_id.
843+
* @return array
844+
*/
845+
private function resolve_saved_or_submitted_plugin_row( array $submitted_plugin, array $existing_by_row_id ): array {
846+
$row_id = isset( $submitted_plugin['row_id'] ) ? (string) $submitted_plugin['row_id'] : '';
847+
848+
if ( '' !== $row_id && isset( $existing_by_row_id[ $row_id ] ) && is_array( $existing_by_row_id[ $row_id ] ) ) {
849+
return $existing_by_row_id[ $row_id ];
850+
}
851+
852+
return $submitted_plugin;
853+
}
854+
821855
/**
822856
* Handle AJAX search for ConvertKit resources
823857
*

0 commit comments

Comments
 (0)