PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | class/class-mainwp-system-handler.php +154 -5 6.1.5 → 6.2.2 View file →
@@ -32,9 +32,9 @@
32 32
33 33 /**
34 34 * Private variable to hold the upgrade version info.
35 35 *
36 - * @var null Version info.
36 + * @var \stdClass|null Version info.
37 37 */
38 38 private $upgradeVersionInfo = null;
39 39
40 40 /**
@@ -1023,18 +1023,167 @@
1023 1023 *
1024 1024 * @uses \MainWP\Dashboard\MainWP_API_Handler::check_exts_upgrade()
1025 1025 * @uses \MainWP\Dashboard\MainWP_Utility::update_option()
1026 1026 */
1027 - private function check_upgrade() {
1028 - $result = MainWP_API_Handler::check_exts_upgrade();
1027 + private function check_upgrade() { // phpcs:ignore -- NOSONAR - validates and preserves per-extension update state.
1028 + $expected_extensions = $this->get_expected_extension_updates();
1029 + $has_full_scope = $this->has_full_extension_update_scope( $expected_extensions );
1030 +
1029 1031 if ( null === $this->upgradeVersionInfo ) {
1030 1032 $this->upgradeVersionInfo = new \stdClass();
1031 1033 }
1034 +
1032 1035 $this->upgradeVersionInfo->updated = time();
1033 - if ( ! empty( $result ) ) {
1034 - $this->upgradeVersionInfo->result = $result;
1036 +
1037 + if ( empty( $expected_extensions ) ) {
1038 + if ( $has_full_scope ) {
1039 + $this->clear_extension_update_failure();
1040 + }
1041 + MainWP_Utility::update_option( 'mainwp_upgradeVersionInfo', $this->upgradeVersionInfo );
1042 + return $has_full_scope;
1035 1043 }
1044 +
1045 + $result = MainWP_API_Handler::check_exts_upgrade();
1046 + $previous_result = property_exists( $this->upgradeVersionInfo, 'result' ) && is_array( $this->upgradeVersionInfo->result ) ? $this->upgradeVersionInfo->result : array();
1047 + $fresh_result = array();
1048 + $failed = ! is_array( $result );
1049 +
1050 + foreach ( $expected_extensions as $api_slug => $installed_version ) {
1051 + $fresh = is_array( $result ) && isset( $result[ $api_slug ] ) ? $result[ $api_slug ] : null;
1052 + if ( $this->is_usable_extension_update_result( $fresh, $api_slug, $installed_version ) ) {
1053 + $fresh_result[ $api_slug ] = $fresh;
1054 + } else {
1055 + $failed = true;
1056 + }
1057 + }
1058 +
1059 + if ( ! $failed ) {
1060 + $this->upgradeVersionInfo->result = $has_full_scope ? $fresh_result : array_merge( $previous_result, $fresh_result );
1061 + }
1062 +
1063 + if ( $has_full_scope ) {
1064 + if ( $failed ) {
1065 + $this->record_extension_update_failure();
1066 + } else {
1067 + $this->clear_extension_update_failure();
1068 + }
1069 + }
1070 +
1036 1071 MainWP_Utility::update_option( 'mainwp_upgradeVersionInfo', $this->upgradeVersionInfo );
1072 + return ! $failed;
1073 + }
1074 +
1075 + /**
1076 + * Get Add-ons expected in an update-check response.
1077 + *
1078 + * @return array API slugs keyed to installed versions.
1079 + */
1080 + private function get_expected_extension_updates() {
1081 + $expected = array();
1082 +
1083 + foreach ( MainWP_Extensions_Handler::get_extensions() as $extension ) {
1084 + if ( ! isset( $extension['activated_key'] ) || 'Activated' !== $extension['activated_key'] || empty( $extension['api'] ) ) {
1085 + continue;
1086 + }
1087 +
1088 + $expected[ $extension['api'] ] = isset( $extension['version'] ) ? (string) $extension['version'] : '';
1089 + }
1090 +
1091 + return $expected;
1092 + }
1093 +
1094 + /**
1095 + * Check whether visible Add-ons cover the shared update cache.
1096 + *
1097 + * @param array $expected Visible Add-ons expected in the response.
1098 + *
1099 + * @return bool Whether this request covers every activated Add-on.
1100 + */
1101 + private function has_full_extension_update_scope( $expected ) {
1102 + $all_expected = array();
1103 +
1104 + foreach ( get_option( 'mainwp_extensions', array() ) as $extension ) {
1105 + if ( isset( $extension['activated_key'], $extension['api'] ) && 'Activated' === $extension['activated_key'] && '' !== $extension['api'] ) {
1106 + $all_expected[] = $extension['api'];
1107 + }
1108 + }
1109 +
1110 + $visible = array_keys( $expected );
1111 + sort( $all_expected );
1112 + sort( $visible );
1113 +
1114 + return $all_expected === $visible;
1115 + }
1116 +
1117 + /**
1118 + * Check whether an Add-on update result is safe to persist.
1119 + *
1120 + * @param mixed $result Update result.
1121 + * @param string $api_slug Expected API slug.
1122 + * @param string $installed_version Installed Add-on version.
1123 + *
1124 + * @return bool Whether the result is usable.
1125 + */
1126 + private function is_usable_extension_update_result( $result, $api_slug, $installed_version ) {
1127 + if ( ! is_object( $result ) || ! isset( $result->slug ) || $api_slug !== $result->slug || ! property_exists( $result, 'new_version' ) || ! is_string( $result->new_version ) ) {
1128 + return false;
1129 + }
1130 +
1131 + $new_version = trim( $result->new_version );
1132 + if ( '' === $new_version || ( property_exists( $result, 'error' ) && ! empty( $result->error ) ) ) {
1133 + return false;
1134 + }
1135 +
1136 + if ( version_compare( $new_version, $installed_version, '>' ) ) {
1137 + return property_exists( $result, 'package' ) && is_string( $result->package ) && '' !== trim( $result->package );
1138 + }
1139 +
1140 + return true;
1141 + }
1142 +
1143 + /**
1144 + * Record a failed Add-on update-check attempt.
1145 + */
1146 + private function record_extension_update_failure() {
1147 + $failure_count = property_exists( $this->upgradeVersionInfo, 'extension_update_failure_count' ) ? (int) $this->upgradeVersionInfo->extension_update_failure_count : 0;
1148 +
1149 + if ( $failure_count < 1 || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_episode' ) || empty( $this->upgradeVersionInfo->extension_update_failure_episode ) ) {
1150 + $this->upgradeVersionInfo->extension_update_failure_episode = wp_generate_uuid4();
1151 + }
1152 +
1153 + $this->upgradeVersionInfo->extension_update_failure_count = $failure_count + 1;
1154 + }
1155 +
1156 + /**
1157 + * Clear Add-on update-check failure state after a complete response.
1158 + */
1159 + private function clear_extension_update_failure() {
1160 + unset( $this->upgradeVersionInfo->extension_update_failure_count, $this->upgradeVersionInfo->extension_update_failure_episode );
1161 + }
1162 +
1163 + /**
1164 + * Get the active repeated-failure notice ID.
1165 + *
1166 + * @return string Notice ID, or an empty string before the second consecutive failure.
1167 + */
1168 + public function get_extension_update_failure_notice_id() {
1169 + if ( ! $this->has_full_extension_update_scope( $this->get_expected_extension_updates() ) || ! is_object( $this->upgradeVersionInfo ) || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_count' ) || 2 > (int) $this->upgradeVersionInfo->extension_update_failure_count || ! property_exists( $this->upgradeVersionInfo, 'extension_update_failure_episode' ) ) {
1170 + return '';
1171 + }
1172 +
1173 + $episode = sanitize_key( $this->upgradeVersionInfo->extension_update_failure_episode );
1174 + return '' !== $episode ? 'mainwp-extension-update-check-failure-' . $episode : '';
1175 + }
1176 +
1177 + /**
1178 + * Retry the Add-on update check and refresh WordPress update data.
1179 + *
1180 + * @return bool Whether every expected Add-on returned a usable result.
1181 + */
1182 + public function retry_extension_update_check() {
1183 + $success = $this->check_upgrade();
1184 + delete_site_transient( 'update_plugins' );
1185 + return $success;
1037 1186 }
1038 1187
1039 1188 /**
1040 1189 * Method pre_check_update_custom()