| @@ -201,16 +201,35 @@ | ||
| 201 | 201 | $serviceOk = true; |
| 202 | 202 | $settingsOk = true; |
| 203 | 203 | |
| 204 | 204 | if( $action === 'cdn' ){ |
| 205 | + // Switching delivery provider resets the previously selected one's own fields | |
| 206 | + // back to their defaults (see ChooseCDN.jsx) — that can include private_path/ | |
| 207 | + // enable_private_media, since those live in a delivery entry's own field list, | |
| 208 | + // so this write needs the same guard the plain settings save uses below. | |
| 209 | + $validation = apply_filters( 'wpmcs_validate_settings_save', ['ok' => true, 'message' => ''], $settings, $action ); | |
| 210 | + if ( empty( $validation['ok'] ) ) { | |
| 211 | + return new WP_REST_Response( [ | |
| 212 | + 'success' => false, | |
| 213 | + 'message' => !empty($validation['message']) ? $validation['message'] : esc_html__('Settings could not be saved.', 'media-cloud-sync') | |
| 214 | + ], 200 ); | |
| 215 | + } | |
| 216 | + | |
| 205 | 217 | $existing = Utils::get_credentials(); |
| 206 | 218 | $existing['cdn'] = $cdn; |
| 207 | - | |
| 219 | + | |
| 208 | 220 | $updated = Utils::update_option('credentials', $existing, Schema::getConstant('GLOBAL_SETTINGS_KEY')); |
| 209 | 221 | $updatedSettings = Utils::update_option('settings', $settings, Schema::getConstant('GLOBAL_SETTINGS_KEY')); |
| 210 | 222 | |
| 211 | 223 | if(!$updated) $serviceOk = false; |
| 212 | 224 | if(!$updatedSettings) $settingsOk = false; |
| 225 | + | |
| 226 | + // Only once both writes actually persisted — a failed credentials write can | |
| 227 | + // leave the object cache holding an unpersisted bucket identity (see | |
| 228 | + // Cache::set_object_cache()), so gating on $settingsOk alone isn't enough. | |
| 229 | + if ($serviceOk && $settingsOk) { | |
| 230 | + do_action('wpmcs_after_settings_save', $settings, $action); | |
| 231 | + } | |
| 213 | 232 | } |
| 214 | 233 | |
| 215 | 234 | |
| 216 | 235 | if($action === 'all' || $action === 'service'){ |
| @@ -247,10 +266,29 @@ | ||
| 247 | 266 | } |
| 248 | 267 | } |
| 249 | 268 | |
| 250 | 269 | if(($action === 'all' || $action === 'settings')) { |
| 270 | + // Extension point for a pro-only settings-save guard (e.g. private media | |
| 271 | + // refusing a private_path/base_path change while items are still private | |
| 272 | + // under the currently-applied path) — free has no opinion here, default | |
| 273 | + // is "allow". ['ok' => bool, 'message' => string]. | |
| 274 | + $validation = apply_filters( 'wpmcs_validate_settings_save', ['ok' => true, 'message' => ''], $settings, $action ); | |
| 275 | + if ( empty( $validation['ok'] ) ) { | |
| 276 | + return new WP_REST_Response( [ | |
| 277 | + 'success' => false, | |
| 278 | + 'message' => !empty($validation['message']) ? $validation['message'] : esc_html__('Settings could not be saved.', 'media-cloud-sync') | |
| 279 | + ], 200 ); | |
| 280 | + } | |
| 281 | + | |
| 251 | 282 | $updatedSettings = Utils::update_option('settings', $settings, Schema::getConstant('GLOBAL_SETTINGS_KEY')); |
| 252 | 283 | if(!$updatedSettings) $settingsOk = false; |
| 284 | + | |
| 285 | + // Only once both writes actually persisted — a failed credentials write can | |
| 286 | + // leave the object cache holding an unpersisted bucket identity (see | |
| 287 | + // Cache::set_object_cache()), so gating on $settingsOk alone isn't enough. | |
| 288 | + if ($serviceOk && $settingsOk) { | |
| 289 | + do_action('wpmcs_after_settings_save', $settings, $action); | |
| 290 | + } | |
| 253 | 291 | } |
| 254 | 292 | |
| 255 | 293 | // Clear plugin caches and refresh counts after any configuration save. |
| 256 | 294 | if(in_array($action, ['all', 'service', 'settings', 'cdn'], true)) { |
| @@ -413,9 +451,10 @@ | ||
| 413 | 451 | 'message' => Utils::get_service_configuration_error() ?: esc_html__('Storage is not configured correctly.', 'media-cloud-sync') |
| 414 | 452 | ]; |
| 415 | 453 | return new WP_REST_Response( $result, 200 ); |
| 416 | 454 | } |
| 417 | - $status = Sync::instance()->start($action); | |
| 455 | + $options = isset($data->get_params()['options']) && is_array($data->get_params()['options']) ? $data->get_params()['options'] : []; | |
| 456 | + $status = Sync::instance()->start($action, $options); | |
| 418 | 457 | |
| 419 | 458 | // Sync::start() passes a job's own precondition-failure array straight through |
| 420 | 459 | // (e.g. no destination configured) instead of masking it as a started status. |
| 421 | 460 | if (is_array($status) && isset($status['success']) && $status['success'] === false) { |