PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.1
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.1
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 | includes/rest-api/controller/version2/class-mainwp-rest-monitors-controller.php +104 -9 6.0.12 → 6.2.1 View file →
@@ -366,10 +366,11 @@
366 366 $incidents_7d = (int) $this->db->count_site_incidents_stats( $monitor_id, $one_week_ago, $today );
367 367 $incidents_30d = (int) $this->db->count_site_incidents_stats( $monitor_id, $one_month_ago, $today );
368 368
369 369 // Get monitor type & check frequency.
370 - $type = $this->get_apply_setting( 'type', $monitor->type ?? '', 'useglobal', 'http' );
371 - $interval_min = (int) $this->get_apply_setting( 'interval', (int) ( $monitor->interval ?? 0 ), -1, 60 );
370 + $type = $this->get_apply_setting( 'type', $monitor->type ?? '', 'useglobal', 'http' );
371 + $interval_min = (int) $this->get_apply_setting( 'interval', (int) ( $monitor->interval ?? 0 ), -1, 60 );
372 + $bypass_cache_opt = (int) $this->get_apply_setting( 'bypass_cache', (int) ( $monitor->bypass_cache ?? -1 ), -1, 0 );
372 373
373 374 $record = array(
374 375 'id' => $monitor_id,
375 376 'url' => $monitor->url ?? '',
@@ -385,8 +386,9 @@
385 386 'response_time_max_ms' => (int) ( $reports_data['max_time_ms'] ?? 0 ),
386 387 'last_check_at' => ! empty( $monitor->lasttime_check ) ? gmdate( 'Y-m-d H:i:s', (int) $monitor->lasttime_check ) : '',
387 388 'last_status_code' => ! empty( $monitor->last_http_code ) ? (int) $monitor->last_http_code : '',
388 389 'last_status' => $this->uptime_status( $monitor->last_status ?? null ),
390 + 'bypass_cache' => $bypass_cache_opt,
389 391 );
390 392
391 393 // Filter data by allowed fields.
392 394 $data[] = $this->filter_response_data_by_allowed_fields( $record, 'view' );
@@ -530,10 +532,11 @@
530 532 // Get full heartbeat data.
531 533 $heartbeat_data = $this->db->get_uptime_monitoring_stats( $monitor_id, $one_month_ago, $today );
532 534
533 535 // Get monitor type & check frequency.
534 - $type = $this->get_apply_setting( 'type', $monitor->type ?? '', 'useglobal', 'http' );
535 - $interval_min = (int) $this->get_apply_setting( 'interval', (int) ( $monitor->interval ?? 0 ), -1, 60 );
536 + $type = $this->get_apply_setting( 'type', $monitor->type ?? '', 'useglobal', 'http' );
537 + $interval_min = (int) $this->get_apply_setting( 'interval', (int) ( $monitor->interval ?? 0 ), -1, 60 );
538 + $bypass_cache_opt = (int) $this->get_apply_setting( 'bypass_cache', (int) ( $monitor->bypass_cache ?? -1 ), -1, 0 );
536 539
537 540 $record = array(
538 541 'id' => $monitor_id,
539 542 'name' => $monitor->name ?? '',
@@ -551,8 +554,9 @@
551 554 'heartbeats' => $heartbeat_data ?? array(),
552 555 'last_check_at' => ! empty( $monitor->lasttime_check ) ? gmdate( 'Y-m-d H:i:s', (int) $monitor->lasttime_check ) : '',
553 556 'last_status_code' => ! empty( $monitor->last_http_code ) ? (int) $monitor->last_http_code : '',
554 557 'last_status' => $this->uptime_status( $monitor->last_status ?? null ),
558 + 'bypass_cache' => $bypass_cache_opt,
555 559 );
556 560
557 561 return rest_ensure_response(
558 562 array(
@@ -879,8 +883,16 @@
879 883 */
880 884 public function update_global_monitoring_settings( $request ) {
881 885 // Get request body.
882 886 $body = $request->get_json_params();
887 +
888 + // A JSON scalar or list body carries none of the settings keys: array_intersect_key() below
889 + // fatals on the scalar, and the list would intersect down to nothing and answer as a
890 + // successful no-op, so both are treated as no body at all.
891 + if ( ! is_array( $body ) || ( array() !== $body && array_keys( $body ) === range( 0, count( $body ) - 1 ) ) ) {
892 + $body = array();
893 + }
894 +
883 895 if ( empty( $body ) ) {
884 896 return new WP_Error(
885 897 'empty_body',
886 898 __( 'Request body is empty.', 'mainwp' ),
@@ -896,10 +908,27 @@
896 908 __( 'Invalid content type. Expected application/json.', 'mainwp' ),
897 909 );
898 910 }
899 911
912 + // Reject a key the route does not declare. get_sanitized_settings_params() drops it, so a
913 + // misspelled setting would otherwise reach the processor as an empty settings array and
914 + // answer as a successful no-op. The individual route reports the same mistake through its
915 + // schema, so it gets the same error code here.
916 + $unknown_keys = array_diff( array_keys( $body ), array_keys( $this->get_global_monitor_settings_allowed_fields() ) );
917 + if ( ! empty( $unknown_keys ) ) {
918 + return new WP_Error(
919 + 'rest_additional_properties_forbidden',
920 + sprintf(
921 + /* translators: %s: comma separated list of request body keys the route does not accept. */
922 + __( 'Unknown settings: %s.', 'mainwp' ),
923 + implode( ', ', $unknown_keys )
924 + ),
925 + array( 'status' => 400 )
926 + );
927 + }
928 +
900 929 // Process global monitoring settings update.
901 - $result = $this->process_global_monitoring_settings_update( $body );
930 + $result = $this->process_global_monitoring_settings_update( $this->get_sanitized_settings_params( $request, $body ) );
902 931 if ( is_wp_error( $result ) ) {
903 932 return $result;
904 933 }
905 934
@@ -934,12 +963,20 @@
934 963
935 964 // Get request body.
936 965 $body = $request->get_json_params();
937 966
967 + // A JSON scalar or list body carries none of the settings keys: array_intersect_key() below
968 + // fatals on the scalar, and the list would intersect down to nothing and answer as a
969 + // successful no-op, so both are treated as no body at all.
970 + if ( ! is_array( $body ) || ( array() !== $body && array_keys( $body ) === range( 0, count( $body ) - 1 ) ) ) {
971 + $body = array();
972 + }
973 +
938 974 if ( empty( $body ) ) {
939 975 return new WP_Error(
940 976 'empty_body',
941 977 __( 'Request body is empty.', 'mainwp' ),
978 + array( 'status' => 400 )
942 979 );
943 980 }
944 981
945 982 // Check content type.
@@ -950,17 +987,22 @@
950 987 __( 'Invalid content type. Expected application/json.', 'mainwp' ),
951 988 );
952 989 }
953 990
954 - // Validate request body against schema.
991 + // Validate request body against schema. The schema has to see the raw body: the sanitized
992 + // params keep only the keys the route registered, so a misspelled key would be filtered out
993 + // before additionalProperties could reject it.
955 994 $schema = $this->get_monitor_settings_schema(); // Get default schema.
956 995 $valid = rest_validate_value_from_schema( $body, $schema, 'body' );
957 996 if ( is_wp_error( $valid ) ) {
997 + // A schema error carries no status of its own and REST falls back to 500 for one that
998 + // has none, which is the wrong answer for a body the caller got wrong.
999 + $valid->add_data( array( 'status' => 400 ) );
958 1000 return $valid;
959 1001 }
960 1002
961 1003 // Sanitize request body.
962 - $data = rest_sanitize_value_from_schema( $body, $schema );
1004 + $data = rest_sanitize_value_from_schema( $this->get_sanitized_settings_params( $request, $body ), $schema );
963 1005
964 1006 // Process individual monitor settings update.
965 1007 $result = $this->process_individual_monitor_settings_update( $monitor, $data );
966 1008
@@ -1013,9 +1055,18 @@
1013 1055 // Check website.
1014 1056 $error_msg = '';
1015 1057 $result = '';
1016 1058 try {
1017 - $result = MainWP_Monitoring_Handler::handle_check_website( $website );
1059 + if ( ! empty( $monitor->issub ) ) {
1060 + $result = MainWP_Uptime_Monitoring_Handle::check_website_uptime_monitoring_status(
1061 + $monitor,
1062 + array(
1063 + 'ignore_compatible_save' => 1, // compatible.
1064 + )
1065 + );
1066 + } else {
1067 + $result = MainWP_Monitoring_Handler::handle_check_website( $website );
1068 + }
1018 1069 } catch ( \Exception $e ) {
1019 1070 $error_msg = $e->getMessage();
1020 1071 }
1021 1072
@@ -1044,8 +1095,30 @@
1044 1095 );
1045 1096 }
1046 1097
1047 1098 /**
1099 + * Get the settings the request carries, as the registered callbacks sanitized them.
1100 + *
1101 + * @param WP_REST_Request $request Full details about the request.
1102 + * @param array $body Raw request body.
1103 + *
1104 + * @return array Sanitized settings, keyed by the keys the body carried.
1105 + */
1106 + private function get_sanitized_settings_params( $request, $body ) {
1107 + // The registered sanitize_callbacks produce the request params, so the persisted value is
1108 + // read from there rather than from the raw body; WordPress currently writes the sanitized
1109 + // value back into the JSON body too, but that is internal to sanitize_params(), not a
1110 + // contract. get_params() also carries auth, query and route params, so keep only the
1111 + // settings keys the route declares and only the ones this body actually sent. It merges in
1112 + // the reverse of get_parameter_order(), so a JSON body value beats a query parameter of the
1113 + // same name rather than the other way round.
1114 + $allowed = $this->get_global_monitor_settings_allowed_fields();
1115 + $params = array_intersect_key( $request->get_params(), $allowed );
1116 +
1117 + return array_intersect_key( $params, $body );
1118 + }
1119 +
1120 + /**
1048 1121 * Process global monitoring settings update with all business logic.
1049 1122 *
1050 1123 * @param array $settings Settings to update.
1051 1124 *
@@ -1109,8 +1182,12 @@
1109 1182 if ( isset( $settings['keyword'] ) ) {
1110 1183 $updated_settings['keyword'] = $settings['keyword'];
1111 1184 }
1112 1185
1186 + if ( isset( $settings['bypass_cache'] ) && in_array( (int) $settings['bypass_cache'], array( 1, 0 ), true ) ) {
1187 + $updated_settings['bypass_cache'] = $settings['bypass_cache'];
1188 + }
1189 +
1113 1190 // Apply filters to allow customization.
1114 1191 $updated_settings = apply_filters( 'mainwp_uptime_monitoring_update_global_settings', $updated_settings );
1115 1192
1116 1193 // Save the updated settings.
@@ -1189,8 +1266,16 @@
1189 1266
1190 1267 // Update the monitor.
1191 1268 $result = $this->db->update_wp_monitor( $update_data );
1192 1269
1270 + if ( isset( $settings['bypass_cache'] ) ) {
1271 + $bypass_cache = (int) $settings['bypass_cache'];
1272 + if ( in_array( $bypass_cache, array( -1, 1, 0 ), true ) ) {
1273 + MainWP_DB_Uptime_Monitoring::instance()->update_website_option( $monitor->wpid, 'bypass_cache', $bypass_cache );
1274 + $update_data['bypass_cache'] = $bypass_cache;
1275 + }
1276 + }
1277 +
1193 1278 if ( false === $result ) {
1194 1279 return new WP_Error(
1195 1280 'update_failed',
1196 1281 __( 'Failed to update monitor settings.', 'mainwp' ),
@@ -1501,9 +1586,9 @@
1501 1586 'validate_callback' => array( $this, 'settings_validate_method_param' ),
1502 1587 ),
1503 1588 'expected_status' => array(
1504 1589 'required' => false,
1505 - 'type' => 'array',
1590 + 'type' => 'string',
1506 1591 'description' => __( 'Expected HTTP status codes.', 'mainwp' ),
1507 1592 'sanitize_callback' => array( $this, 'sanitize_expected_status_text_field' ),
1508 1593 'validate_callback' => array( $this, 'settings_validate_expected_status_param' ),
1509 1594 ),
@@ -2207,8 +2292,13 @@
2207 2292 'timeout' => array( 'type' => 'integer' ),
2208 2293 'interval' => array( 'type' => 'string' ),
2209 2294 'expected_status' => array( 'type' => array( 'string' ) ),
2210 2295 'keyword' => array( 'type' => 'string' ),
2296 + 'bypass_cache' => array(
2297 + 'type' => 'integer',
2298 + 'enum' => array( -1, 0, 1 ),
2299 + 'description' => __( 'Cache bypass setting. -1 uses the global setting, 0 disables it, and 1 enables it.', 'mainwp' ),
2300 + ),
2211 2301 ),
2212 2302 );
2213 2303 }
2214 2304
@@ -2255,8 +2345,13 @@
2255 2345 ),
2256 2346 'type' => array(
2257 2347 'type' => 'string',
2258 2348 'description' => __( 'Monitor type.', 'mainwp' ),
2349 + 'context' => array( 'view', 'monitor_view' ),
2350 + ),
2351 + 'bypass_cache' => array(
2352 + 'type' => 'integer',
2353 + 'description' => __( 'Attempt to bypass page cache.', 'mainwp' ),
2259 2354 'context' => array( 'view', 'monitor_view' ),
2260 2355 ),
2261 2356 'last_status' => array(
2262 2357 'type' => 'string',