diff --git a/inc/apbct-sync-react.php b/inc/apbct-sync-react.php index a9f78ae0f..4e107669b 100644 --- a/inc/apbct-sync-react.php +++ b/inc/apbct-sync-react.php @@ -42,7 +42,11 @@ function apbct_react_access_key_check() ); } - $apbct->errorDeleteAll(true); + $clear_all_blogs = APBCT_WPMS + && is_main_site() + && isset($apbct->network_settings['multisite__work_mode']) + && (int) $apbct->network_settings['multisite__work_mode'] === 2; + apbct_settings__clear_errors($clear_all_blogs); $account_is_ok = (bool) ct_account_status_check($apbct->settings['apikey']); $connection_error = ! empty($apbct->errors['account_check']) diff --git a/inc/cleantalk-settings.php b/inc/cleantalk-settings.php index cea88f860..abd9935e0 100644 --- a/inc/cleantalk-settings.php +++ b/inc/cleantalk-settings.php @@ -2397,12 +2397,24 @@ function apbct_settings__validate($incoming_settings) // Set missing network settings from default. $stored_network_options = get_site_option($apbct->option_prefix . '_network_settings', array()); + $incoming_work_mode = isset($incoming_settings['multisite__work_mode']) + ? $incoming_settings['multisite__work_mode'] + : null; $incoming_settings = apbct_settings__set_missed_network_settings( $incoming_settings, is_array($stored_network_options) ? $stored_network_options : array(), $apbct->default_network_settings ); + if ( APBCT_WPMS && is_main_site() && $incoming_work_mode !== null ) { + $previous_work_mode = isset($apbct->network_settings['multisite__work_mode']) + ? (int) $apbct->network_settings['multisite__work_mode'] + : 0; + if ( $previous_work_mode !== (int) $incoming_work_mode ) { + apbct_settings__clear_errors(true); + } + } + /** * -- SFW rules -- */ @@ -2717,6 +2729,40 @@ function apbct_settings__validate($incoming_settings) return $incoming_settings; } +/** + * Clear plugin errors on the current site. + * When $all_blogs is true on WPMS, also wipe errors on every blog. + * + * @param bool $all_blogs + * + * @return void + */ +function apbct_settings__clear_errors($all_blogs = false) +{ + global $apbct, $wpdb; + + $apbct->errorDeleteAll(true); + + if ( ! $all_blogs || ! APBCT_WPMS ) { + return; + } + + $option_name = $apbct->option_prefix . '_errors'; + $current_blog_id = get_current_blog_id(); + $wp_blogs = $wpdb->get_results('SELECT blog_id FROM ' . $wpdb->blogs, OBJECT_K); + + if ( ! is_array($wp_blogs) ) { + return; + } + + foreach ( $wp_blogs as $blog ) { + if ( (int) $blog->blog_id === (int) $current_blog_id ) { + continue; + } + update_blog_option($blog->blog_id, $option_name, array()); + } +} + function apbct_settings__sync($direct_call = false) { if ( ! $direct_call ) { @@ -2734,8 +2780,12 @@ function apbct_settings__sync($direct_call = false) die(json_encode($out)); } - //Clearing all errors - $apbct->errorDeleteAll(true); + // Clearing all errors. Mutual Access Key (mode 2): wipe leftover banners on every blog. + $clear_all_blogs = APBCT_WPMS + && is_main_site() + && isset($apbct->network_settings['multisite__work_mode']) + && (int) $apbct->network_settings['multisite__work_mode'] === 2; + apbct_settings__clear_errors($clear_all_blogs); // Feedback with app_agent ct_send_feedback('0:' . APBCT_AGENT); // 0 - request_id, agent version. diff --git a/tests/StandaloneFunctions/SettingsTest.php b/tests/StandaloneFunctions/SettingsTest.php index c0d6392f0..a9e9c6ca6 100644 --- a/tests/StandaloneFunctions/SettingsTest.php +++ b/tests/StandaloneFunctions/SettingsTest.php @@ -151,4 +151,55 @@ public function test_apbct_settings__set_fields() $this->assertIsArray($fields[$key], "Key '{$key}' should be an array"); } } + + public function test_apbct_settings__clear_errors_current_site() + { + global $apbct; + + $apbct->errorAdd('sfw_outdated', 'SpamFireWall database is outdated.'); + $this->assertTrue($apbct->errorExists('sfw_outdated')); + + apbct_settings__clear_errors(false); + + $this->assertFalse($apbct->errorExists('sfw_outdated')); + $this->assertSame(array(), (array) $apbct->errors); + $this->assertSame(array(), get_option($apbct->option_prefix . '_errors')); + } + + public function test_apbct_settings__clear_errors_all_blogs_on_wpms() + { + global $apbct; + + if ( ! is_multisite() ) { + $this->markTestSkipped('Requires WordPress Multisite'); + } + + $option_name = $apbct->option_prefix . '_errors'; + $stale_error = array( + 'sfw_outdated' => array( + array( + 'error' => 'SpamFireWall database is outdated.', + 'error_time' => time(), + ), + ), + ); + + $apbct->errorAdd('sfw_outdated', 'SpamFireWall database is outdated.'); + + $blogs = get_sites(array('number' => 20)); + foreach ( $blogs as $blog ) { + update_blog_option((int) $blog->blog_id, $option_name, $stale_error); + } + + apbct_settings__clear_errors(true); + + $this->assertFalse($apbct->errorExists('sfw_outdated')); + foreach ( $blogs as $blog ) { + $this->assertSame( + array(), + get_blog_option((int) $blog->blog_id, $option_name), + 'Errors must be cleared on blog ' . $blog->blog_id + ); + } + } }