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 | pages/page-mainwp-server-information-handler.php +2228 -53 5.1 → 6.2.1 View file →
@@ -6,8 +6,13 @@
6 6 */
7 7
8 8 namespace MainWP\Dashboard;
9 9
10 +// Exit if accessed directly.
11 +if ( ! defined( 'ABSPATH' ) ) {
12 + exit;
13 +}
14 +
10 15 /**
11 16 * Class MainWP Server_Information_Handler
12 17 */
13 18 class MainWP_Server_Information_Handler { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
@@ -105,14 +110,30 @@
105 110 */
106 111 public static function curlssl_compare( $version, $operator ) {
107 112 if ( function_exists( 'curl_version' ) ) {
108 113 $ver = static::get_curl_ssl_version();
109 - return version_compare( $ver, $version, $operator );
114 + return version_compare( static::extract_version( $ver ), static::extract_version( $version ), $operator );
110 115 }
111 116 return false;
112 117 }
113 118
114 119 /**
120 + * Method extract_version()
121 + *
122 + * Function to extract version from string for both OpenSSL and LibreSSL
123 + *
124 + * @param string $version_string Version OpenSSL and LibreSSL.
125 + *
126 + * @return mixed null|string
127 + */
128 + public static function extract_version( $version_string ) {
129 + if ( preg_match( '/(?:LibreSSL|OpenSSL)[\/ ]([\d.]+)/', $version_string, $matches ) ) {
130 + return $matches[1];
131 + }
132 + return null;
133 + }
134 +
135 + /**
115 136 * Gets file system method.
116 137 *
117 138 * @return string $fs File System Method.
118 139 */
@@ -439,27 +460,8 @@
439 460 return ini_get( 'pcre.backtrack_limit' );
440 461 }
441 462
442 463 /**
443 - * Method get_php_safe_mode()
444 - *
445 - * Get PHP Safe Mode.
446 - *
447 - * @return bool true|false.
448 - */
449 - public static function get_php_safe_mode() {
450 - if ( version_compare( static::get_php_version(), '5.3.0' ) >= 0 ) {
451 - return true;
452 - }
453 -
454 - if ( ini_get( 'safe_mode' ) ) {
455 - return false;
456 - }
457 -
458 - return true;
459 - }
460 -
461 - /**
462 464 * Method get_sql_mode()
463 465 *
464 466 * Get SQL Mode.
465 467 */
@@ -472,9 +474,14 @@
472 474 */
473 475 global $wpdb;
474 476
475 477 $sql_mode = '';
476 - $mysqlinfo = $wpdb->get_results( "SHOW VARIABLES LIKE 'sql_mode'" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- ok.
478 + $cache_key = 'mainwp_sql_mode';
479 + $mysqlinfo = wp_cache_get( $cache_key );
480 + if ( false === $mysqlinfo ) {
481 + $mysqlinfo = $wpdb->get_results( "SHOW VARIABLES LIKE 'sql_mode'" ); //phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery -- ok.
482 + wp_cache_set( $cache_key, $mysqlinfo, '', DAY_IN_SECONDS );
483 + }
477 484 if ( is_array( $mysqlinfo ) ) {
478 485 $sql_mode = $mysqlinfo[0]->Value;
479 486 }
480 487 if ( empty( $sql_mode ) ) {
@@ -644,9 +651,9 @@
644 651 /**
645 652 * Gets complete URL.
646 653 */
647 654 public static function get_complete_url() {
648 - echo isset( $_SERVER['HTTP_REFERER'] ) ? esc_html( sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ) : '';
655 + echo isset( $_SERVER['HTTP_REFERER'] ) ? esc_url( sanitize_text_field( wp_unslash( $_SERVER['HTTP_REFERER'] ) ) ) : '';
649 656 }
650 657
651 658 /**
652 659 * Gets user agent.
@@ -690,16 +697,19 @@
690 697 );
691 698 $response = wp_remote_post( $url, $args );
692 699 $test_result = '';
693 700 if ( is_wp_error( $response ) ) {
701 + /* translators: %s: error message */
694 702 $test_result .= sprintf( esc_html__( 'The HTTP response test get an error "%s"', 'mainwp' ), $response->get_error_message() );
695 703 }
696 704 $response_code = wp_remote_retrieve_response_code( $response );
697 705 if ( 200 > $response_code && 204 < $response_code ) {
706 + /* translators: %s: HTTP status code */
698 707 $test_result .= sprintf( esc_html__( 'The HTTP response test get a false http status (%s)', 'mainwp' ), wp_remote_retrieve_response_code( $response ) );
699 708 } else {
700 709 $response_body = wp_remote_retrieve_body( $response );
701 710 if ( false === strstr( $response_body, 'MainWP Test' ) ) {
711 + /* translators: %s: response body */
702 712 $test_result .= sprintf( esc_html__( 'Not expected HTTP response body: %s', 'mainwp' ), esc_attr( wp_strip_all_tags( $response_body ) ) );
703 713 }
704 714 }
705 715 if ( empty( $test_result ) ) {
@@ -842,29 +852,30 @@
842 852 * @uses \MainWP\Dashboard\MainWP_DB::get_websites_count()
843 853 */
844 854 public static function mainwp_options() { // phpcs:ignore -- NOSONAR - current complexity required to achieve desired results. Pull request solutions appreaciated.
845 855 $mainwp_options = array(
846 - 'mainwp_number_of_child_sites' => esc_html__( 'Number of connected sites', 'mainwp' ),
847 - 'mainwp_wp_cron' => esc_html__( 'Use WP Cron', 'mainwp' ),
848 - 'mainwp_optimize' => esc_html__( 'Optimize data loading', 'mainwp' ),
849 - 'mainwp_automaticDailyUpdate' => esc_html__( 'WP Core advanced automatic updates enabled', 'mainwp' ),
850 - 'mainwp_pluginAutomaticDailyUpdate' => esc_html__( 'Plugin advanced automatic updates enabled', 'mainwp' ),
851 - 'mainwp_themeAutomaticDailyUpdate' => esc_html__( 'Theme advanced automatic updates enabled', 'mainwp' ),
852 - 'mainwp_numberdays_Outdate_Plugin_Theme' => esc_html__( 'Abandoned plugins/themes tolerance', 'mainwp' ),
853 - 'mainwp_maximumPosts' => esc_html__( 'Maximum number of posts to return', 'mainwp' ),
854 - 'mainwp_maximumPages' => esc_html__( 'Maximum number of pages to return', 'mainwp' ),
855 - 'mainwp_maximumComments' => esc_html__( 'Maximum number of comments', 'mainwp' ),
856 - 'mainwp_enableLegacyBackupFeature' => esc_html__( 'MainWP legacy backups enabled', 'mainwp' ),
857 - 'mainwp_primaryBackup' => esc_html__( 'Primary backup system', 'mainwp' ),
858 - 'mainwp_disableSitesChecking' => esc_html__( 'Basic uptime monitoring enabled', 'mainwp' ),
859 - 'mainwp_disableSitesHealthMonitoring' => esc_html__( 'Site health monitoring enabled', 'mainwp' ),
860 - 'mainwp_maximumRequests' => esc_html__( 'Maximum simultaneous requests', 'mainwp' ),
861 - 'mainwp_minimumDelay' => esc_html__( 'Minimum delay between requests', 'mainwp' ),
862 - 'mainwp_maximumIPRequests' => esc_html__( 'Maximum simultaneous requests per ip', 'mainwp' ),
863 - 'mainwp_minimumIPDelay' => esc_html__( 'Minimum delay between requests to the same ip', 'mainwp' ),
864 - 'mainwp_maximumSyncRequests' => esc_html__( 'Maximum simultaneous sync requests', 'mainwp' ),
865 - 'mainwp_maximumInstallUpdateRequests' => esc_html__( 'Maximum simultaneous install and update requests', 'mainwp' ),
866 - 'mainwp_auto_purge_cache' => esc_html__( 'Cache control enabled', 'mainwp' ),
856 + 'mainwp_number_of_child_sites' => esc_html__( 'Number of connected sites', 'mainwp' ),
857 + 'mainwp_wp_cron' => esc_html__( 'Use WP Cron', 'mainwp' ),
858 + 'mainwp_optimize' => esc_html__( 'Optimize data loading', 'mainwp' ),
859 + 'mainwp_automaticDailyUpdate' => esc_html__( 'WP Core advanced automatic updates enabled', 'mainwp' ),
860 + 'mainwp_pluginAutomaticDailyUpdate' => esc_html__( 'Plugin advanced automatic updates enabled', 'mainwp' ),
861 + 'mainwp_themeAutomaticDailyUpdate' => esc_html__( 'Theme advanced automatic updates enabled', 'mainwp' ),
862 + 'mainwp_numberdays_Outdate_Plugin_Theme' => esc_html__( 'Abandoned plugins/themes tolerance', 'mainwp' ),
863 + 'mainwp_maximumPosts' => esc_html__( 'Maximum number of posts to return', 'mainwp' ),
864 + 'mainwp_maximumPages' => esc_html__( 'Maximum number of pages to return', 'mainwp' ),
865 + 'mainwp_maximumComments' => esc_html__( 'Maximum number of comments', 'mainwp' ),
866 + 'mainwp_enableLegacyBackupFeature' => esc_html__( 'MainWP legacy backups enabled', 'mainwp' ),
867 + 'mainwp_primaryBackup' => esc_html__( 'Primary backup system', 'mainwp' ),
868 + 'is_enable_automatic_check_uptime_monitoring' => esc_html__( 'Enable Uptime Monitoring', 'mainwp' ),
869 + 'mainwp_disableSitesHealthMonitoring' => esc_html__( 'Site health monitoring enabled', 'mainwp' ),
870 + 'mainwp_maximumRequests' => esc_html__( 'Maximum simultaneous requests', 'mainwp' ),
871 + 'mainwp_minimumDelay' => esc_html__( 'Minimum delay between requests', 'mainwp' ),
872 + 'mainwp_maximumIPRequests' => esc_html__( 'Maximum simultaneous requests per ip', 'mainwp' ),
873 + 'mainwp_minimumIPDelay' => esc_html__( 'Minimum delay between requests to the same ip', 'mainwp' ),
874 + 'mainwp_maximumSyncRequests' => esc_html__( 'Maximum simultaneous sync requests', 'mainwp' ),
875 + 'mainwp_maximumInstallUpdateRequests' => esc_html__( 'Maximum simultaneous install and update requests', 'mainwp' ),
876 + 'mainwp_maximum_uptime_monitoring_requests' => esc_html__( 'Maximum simultaneous uptime monitoring requests (Default: 10)', 'mainwp' ),
877 + 'mainwp_auto_purge_cache' => esc_html__( 'Cache control enabled', 'mainwp' ),
867 878 );
868 879
869 880 if ( ! is_plugin_active( 'mainwp-comments-extension/mainwp-comments-extension.php' ) ) {
870 881 unset( $mainwp_options['mainwp_maximumComments'] );
@@ -871,9 +882,15 @@
871 882 }
872 883
873 884 $options_value = array();
874 885 foreach ( $mainwp_options as $opt => $label ) {
875 - $value = get_option( $opt, false );
886 + if ( 'is_enable_automatic_check_uptime_monitoring' === $opt ) {
887 + $global = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
888 + $value = $global['active'];
889 + } else {
890 + $value = get_option( $opt, false );
891 + }
892 + $save_value = $value;
876 893 switch ( $opt ) {
877 894 case 'mainwp_number_of_child_sites':
878 895 $value = MainWP_DB::instance()->get_websites_count();
879 896 break;
@@ -902,11 +919,14 @@
902 919 break;
903 920 case 'mainwp_maximumInstallUpdateRequests':
904 921 $value = ( false === $value ) ? 3 : $value;
905 922 break;
906 - case 'mainwp_disableSitesChecking':
907 - $value = empty( $value ) ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' );
923 + case 'mainwp_maximum_uptime_monitoring_requests':
924 + $value = ( false === $value ) ? 10 : $value;
908 925 break;
926 + case 'is_enable_automatic_check_uptime_monitoring':
927 + $value = ! empty( $value ) ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' );
928 + break;
909 929 case 'mainwp_disableSitesHealthMonitoring':
910 930 $value = empty( $value ) ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' );
911 931 break;
912 932 default:
@@ -913,16 +933,20 @@
913 933 $value = empty( $value ) ? esc_html__( 'No', 'mainwp' ) : esc_html__( 'Yes', 'mainwp' );
914 934 break;
915 935 }
916 936 $options_value[ $opt ] = array(
917 - 'label' => $label,
918 - 'value' => $value,
937 + 'label' => $label,
938 + 'value' => $value,
939 + 'save_value' => $save_value,
940 + 'name' => $opt,
919 941 );
920 942 }
921 943
922 - $options_value[ $opt ] = array(
923 - 'label' => esc_html__( 'REST API enabled', 'mainwp' ),
924 - 'value' => Rest_Api::instance()->is_rest_api_enabled() ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' ),
944 + $options_value['mainwp_rest_api_enabled'] = array(
945 + 'label' => esc_html__( 'REST API enabled', 'mainwp' ),
946 + 'value' => Rest_Api_V1::instance()->is_rest_api_enabled() ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' ),
947 + 'save_value' => '',
948 + 'name' => 'mainwp_rest_api_enabled',
925 949 );
926 950
927 951 /**
928 952 * Filter: mainwp_getprimarybackup_methods
@@ -950,12 +974,2163 @@
950 974 }
951 975 }
952 976 if ( $chk ) {
953 977 $options_value['mainwp_primaryBackup'] = array(
954 - 'label' => esc_html__( 'Primary Backup System', 'mainwp' ),
955 - 'value' => $value,
978 + 'label' => esc_html__( 'Primary Backup System', 'mainwp' ),
979 + 'value' => $value,
980 + 'save_value' => $primaryBackup,
981 + 'name' => 'mainwp_primaryBackup',
956 982 );
957 983 }
958 984 }
959 985 return $options_value;
986 + }
987 +
988 + /**
989 + * Get primary issues summary.
990 + *
991 + * @return array<int,array<string,string>>
992 + */
993 + public static function get_primary_issues() {
994 + $issues = array();
995 +
996 + if ( ! static::filesize_compare( static::get_wordpress_memory_limit(), '64M', '>=' ) ) {
997 + $issues[] = array(
998 + 'severity' => 'warning',
999 + 'title' => esc_html__( 'Low WordPress memory limit', 'mainwp' ),
1000 + 'detail' => sprintf(
1001 + /* translators: 1: detected memory limit, 2: recommended memory limit */
1002 + esc_html__( 'Detected %1$s. MainWP recommends at least %2$s.', 'mainwp' ),
1003 + static::get_wordpress_memory_limit(),
1004 + '64M'
1005 + ),
1006 + 'anchor' => 'mainwp-system-report-wordpress-table',
1007 + 'kb_url' => 'https://docs.mainwp.com/troubleshooting/resolve-system-requirement-issues/',
1008 + );
1009 + }
1010 +
1011 + if ( ! version_compare( (string) static::get_curl_timeout(), '300', '>=' ) ) {
1012 + $issues[] = array(
1013 + 'severity' => 'warning',
1014 + 'title' => esc_html__( 'Low cURL timeout', 'mainwp' ),
1015 + 'detail' => sprintf(
1016 + /* translators: 1: detected timeout, 2: recommended timeout */
1017 + esc_html__( 'Detected %1$s seconds. MainWP recommends at least %2$s seconds.', 'mainwp' ),
1018 + (string) static::get_curl_timeout(),
1019 + '300'
1020 + ),
1021 + 'anchor' => 'mainwp-system-report-php-table',
1022 + 'kb_url' => 'https://docs.mainwp.com/troubleshooting/resolve-system-requirement-issues/',
1023 + );
1024 + }
1025 +
1026 + $rest_api = static::get_rest_api_reachability_data();
1027 + if ( 'pass' !== $rest_api['status'] ) {
1028 + $issues[] = array(
1029 + 'severity' => $rest_api['status'],
1030 + 'title' => esc_html__( 'WordPress REST API is not fully reachable', 'mainwp' ),
1031 + 'detail' => $rest_api['value'],
1032 + 'anchor' => 'mainwp-system-report-connectivity-table',
1033 + 'kb_url' => 'https://docs.mainwp.com/troubleshooting/wordpress-rest-api-does-not-respond/',
1034 + );
1035 + }
1036 +
1037 + $permalink = static::get_permalink_structure_data();
1038 + if ( 'pass' !== $permalink['status'] ) {
1039 + $issues[] = array(
1040 + 'severity' => $permalink['status'],
1041 + 'title' => esc_html__( 'Plain permalinks detected', 'mainwp' ),
1042 + 'detail' => esc_html__( 'MainWP features that depend on the WordPress REST API may not work correctly with plain permalinks.', 'mainwp' ),
1043 + 'anchor' => 'mainwp-system-report-connectivity-table',
1044 + 'kb_url' => 'https://docs.mainwp.com/troubleshooting/wordpress-rest-api-does-not-respond/',
1045 + );
1046 + }
1047 +
1048 + $self_connect = static::get_server_self_connect_data();
1049 + if ( 'pass' !== $self_connect['status'] ) {
1050 + $issue_title = esc_html__( 'Dashboard self-connect check failed', 'mainwp' );
1051 + $issue_detail = $self_connect['value'];
1052 + $issue_html = '';
1053 +
1054 + if ( isset( $self_connect['code'] ) && 'unexpected_body' === $self_connect['code'] ) {
1055 + $issue_title = esc_html__( 'Dashboard self-connect returned an unexpected body', 'mainwp' );
1056 + $issue_detail = esc_html__( 'Unexpected response body. Note: This is common and usually not a problem unless WP-Cron or loopback requests are failing.', 'mainwp' );
1057 + $issue_html = sprintf(
1058 + '%1$s <em>%2$s</em>',
1059 + esc_html__( 'Unexpected response body.', 'mainwp' ),
1060 + esc_html__( 'Note: This is common and usually not a problem unless WP-Cron or loopback requests are failing.', 'mainwp' )
1061 + );
1062 + }
1063 +
1064 + $issues[] = array(
1065 + 'severity' => $self_connect['status'],
1066 + 'title' => $issue_title,
1067 + 'detail' => $issue_detail,
1068 + 'detail_html' => $issue_html,
1069 + 'anchor' => 'mainwp-system-report-connectivity-table',
1070 + 'kb_url' => ( isset( $self_connect['code'] ) && 'unexpected_body' === $self_connect['code'] ) ? '' : 'https://docs.mainwp.com/troubleshooting/potential-issues/',
1071 + );
1072 + }
1073 +
1074 + $db_issues = MainWP_Database_Schema_Checker::get_detected_db_issues();
1075 +
1076 + return array_merge( $issues, is_array( $db_issues ) ? $db_issues : array() );
1077 + }
1078 +
1079 + /**
1080 + * Add English export labels to localized report rows.
1081 + *
1082 + * @param array<int,array<string,mixed>> $rows Report rows.
1083 + * @param array<int,string> $english_labels English labels to map.
1084 + *
1085 + * @return array<int,array<string,mixed>>
1086 + */
1087 + private static function add_export_labels_to_rows( $rows, $english_labels ) {
1088 + if ( empty( $rows ) || empty( $english_labels ) ) {
1089 + return $rows;
1090 + }
1091 +
1092 + $localized_map = array();
1093 + foreach ( $english_labels as $english_label ) {
1094 + $localized_map[ esc_html__( $english_label, 'mainwp' ) ] = $english_label;
1095 + }
1096 +
1097 + foreach ( $rows as $index => $row ) {
1098 + if ( ! is_array( $row ) || empty( $row['label'] ) || ! empty( $row['export_label'] ) ) {
1099 + continue;
1100 + }
1101 +
1102 + if ( isset( $localized_map[ $row['label'] ] ) ) {
1103 + $rows[ $index ]['export_label'] = $localized_map[ $row['label'] ];
1104 + }
1105 + }
1106 +
1107 + return $rows;
1108 + }
1109 +
1110 + /**
1111 + * Get English export label for notification type.
1112 + *
1113 + * @param string $type Notification type.
1114 + * @param string $fallback_label Fallback localized label.
1115 + *
1116 + * @return string
1117 + */
1118 + private static function get_notification_type_export_label( $type, $fallback_label ) {
1119 + $labels = array(
1120 + 'daily_digest' => 'Daily Digest Email',
1121 + 'uptime' => 'Uptime Monitoring Email',
1122 + 'site_health' => 'Site Health Monitoring Email',
1123 + 'deactivated_license_alert' => 'Extension License Deactivation Notification Email',
1124 + 'http_check' => 'After Updates HTTP Check Email',
1125 + );
1126 +
1127 + /**
1128 + * Filter: mainwp_notification_type_export_labels
1129 + *
1130 + * Filters English export labels for notification types used in the Server Information report export.
1131 + *
1132 + * @since 6.1
1133 + *
1134 + * @param array $labels Notification type => English export label map.
1135 + * @param string $type Notification type currently being resolved.
1136 + * @param string $fallback_label Localized fallback label.
1137 + */
1138 + $labels = apply_filters( 'mainwp_notification_type_export_labels', $labels, $type, $fallback_label );
1139 + if ( ! is_array( $labels ) ) {
1140 + $labels = array();
1141 + }
1142 +
1143 + return isset( $labels[ $type ] ) ? $labels[ $type ] : $fallback_label;
1144 + }
1145 +
1146 + /**
1147 + * Get MainWP overview rows.
1148 + *
1149 + * @return array<int,array<string,mixed>>
1150 + */
1151 + public static function get_mainwp_overview_report_rows() {
1152 + $current_version = static::get_current_version();
1153 + $latest_version = static::get_mainwp_version();
1154 + $version_value = false !== $latest_version
1155 + ? sprintf(
1156 + /* translators: 1: latest version, 2: current version */
1157 + esc_html__( 'Latest: %1$s | Detected: %2$s', 'mainwp' ),
1158 + $latest_version,
1159 + $current_version
1160 + )
1161 + : sprintf(
1162 + /* translators: %s: current version */
1163 + esc_html__( 'Detected: %s', 'mainwp' ),
1164 + $current_version
1165 + );
1166 +
1167 + $upload_directory = static::get_mainwp_upload_directory_data();
1168 +
1169 + return self::add_export_labels_to_rows(
1170 + array(
1171 + array(
1172 + 'label' => esc_html__( 'MainWP Dashboard Version', 'mainwp' ),
1173 + 'value' => $version_value,
1174 + 'status' => ( false !== $latest_version && $current_version === $latest_version ) ? 'pass' : 'warning',
1175 + ),
1176 + array(
1177 + 'label' => esc_html__( 'Number of connected sites', 'mainwp' ),
1178 + 'value' => (string) MainWP_DB::instance()->get_websites_count(),
1179 + ),
1180 + array(
1181 + 'label' => esc_html__( 'MainWP upload directory', 'mainwp' ),
1182 + 'value' => $upload_directory['value'],
1183 + 'status' => $upload_directory['status'],
1184 + ),
1185 + array(
1186 + 'label' => esc_html__( 'MainWP REST API enabled', 'mainwp' ),
1187 + 'value' => static::format_boolean_label( Rest_Api_V1::instance()->is_rest_api_enabled() ),
1188 + 'status' => Rest_Api_V1::instance()->is_rest_api_enabled() ? 'pass' : 'warning',
1189 + ),
1190 + ),
1191 + array(
1192 + 'MainWP Dashboard Version',
1193 + 'Number of connected sites',
1194 + 'MainWP upload directory',
1195 + 'MainWP REST API enabled',
1196 + )
1197 + );
1198 + }
1199 +
1200 + /**
1201 + * Get connectivity rows.
1202 + *
1203 + * @return array<int,array<string,mixed>>
1204 + */
1205 + public static function get_connectivity_report_rows() {
1206 + $permalink = static::get_permalink_structure_data();
1207 + $rest_api = static::get_rest_api_reachability_data();
1208 + $self_connect = static::get_server_self_connect_data();
1209 + $public_ip = static::get_public_dashboard_ip_data();
1210 + $ssl_verify = ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || 1 === (int) get_option( 'mainwp_sslVerifyCertificate', 1 );
1211 + $verify_con = (int) get_option( 'mainwp_verify_connection_method', 1 );
1212 + $signature = static::get_signature_algorithm_label();
1213 +
1214 + return self::add_export_labels_to_rows(
1215 + array(
1216 + array(
1217 + 'label' => esc_html__( 'Dashboard home URL', 'mainwp' ),
1218 + 'value' => home_url( '/' ),
1219 + 'visibility' => 'full_only',
1220 + ),
1221 + array(
1222 + 'label' => esc_html__( 'Dashboard site URL', 'mainwp' ),
1223 + 'value' => site_url( '/' ),
1224 + 'visibility' => 'full_only',
1225 + ),
1226 + array(
1227 + 'label' => esc_html__( 'Public Dashboard IP', 'mainwp' ),
1228 + 'value' => $public_ip['value'],
1229 + 'status' => $public_ip['status'],
1230 + 'visibility' => 'community_masked',
1231 + 'community_value' => $public_ip['community_value'],
1232 + ),
1233 + array(
1234 + 'label' => esc_html__( 'HTTPS', 'mainwp' ),
1235 + 'value' => is_ssl() ? esc_html__( 'Enabled', 'mainwp' ) : esc_html__( 'Disabled', 'mainwp' ),
1236 + ),
1237 + array(
1238 + 'label' => esc_html__( 'Permalink structure', 'mainwp' ),
1239 + 'value' => $permalink['value'],
1240 + 'status' => $permalink['status'],
1241 + ),
1242 + array(
1243 + 'label' => esc_html__( 'WordPress REST API endpoint', 'mainwp' ),
1244 + 'value' => rest_url(),
1245 + 'visibility' => 'full_only',
1246 + ),
1247 + array(
1248 + 'label' => esc_html__( 'WordPress REST API reachability', 'mainwp' ),
1249 + 'value' => $rest_api['value'],
1250 + 'status' => $rest_api['status'],
1251 + ),
1252 + array(
1253 + 'label' => esc_html__( 'Server self connect', 'mainwp' ),
1254 + 'value' => $self_connect['value'],
1255 + 'status' => $self_connect['status'],
1256 + ),
1257 + array(
1258 + 'label' => esc_html__( 'Verify SSL certificate', 'mainwp' ),
1259 + 'value' => static::format_boolean_label( $ssl_verify ),
1260 + ),
1261 + array(
1262 + 'label' => esc_html__( 'Verify connection method', 'mainwp' ),
1263 + 'value' => 2 === $verify_con ? esc_html__( 'PHPSECLIB (fallback)', 'mainwp' ) : esc_html__( 'OpenSSL (default)', 'mainwp' ),
1264 + ),
1265 + array(
1266 + 'label' => esc_html__( 'OpenSSL signature algorithm', 'mainwp' ),
1267 + 'value' => $signature,
1268 + ),
1269 + array(
1270 + 'label' => esc_html__( 'Force IPv4', 'mainwp' ),
1271 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_forceUseIPv4', 0 ) ),
1272 + ),
1273 + ),
1274 + array(
1275 + 'Dashboard home URL',
1276 + 'Dashboard site URL',
1277 + 'Public Dashboard IP',
1278 + 'HTTPS',
1279 + 'Permalink structure',
1280 + 'WordPress REST API endpoint',
1281 + 'WordPress REST API reachability',
1282 + 'Server self connect',
1283 + 'Verify SSL certificate',
1284 + 'Verify connection method',
1285 + 'OpenSSL signature algorithm',
1286 + 'Force IPv4',
1287 + )
1288 + );
1289 + }
1290 +
1291 + /**
1292 + * Get scheduler rows.
1293 + *
1294 + * @return array<int,array<string,mixed>>
1295 + */
1296 + public static function get_scheduler_report_rows() {
1297 + $daily_frequency = (int) get_option( 'mainwp_frequencyDailyUpdate', 2 );
1298 + if ( $daily_frequency <= 0 ) {
1299 + $daily_frequency = 1;
1300 + }
1301 +
1302 + $rows = array(
1303 + array(
1304 + 'label' => esc_html__( 'Use WP Cron', 'mainwp' ),
1305 + 'value' => static::format_boolean_label( ( false === get_option( 'mainwp_wp_cron' ) ) || 1 === (int) get_option( 'mainwp_wp_cron', 1 ) ),
1306 + ),
1307 + array(
1308 + 'label' => esc_html__( 'Daily update frequency', 'mainwp' ),
1309 + 'value' => MainWP_Server_Information::get_schedule_auto_update_label( $daily_frequency ),
1310 + ),
1311 + array(
1312 + 'label' => esc_html__( 'Daily update time', 'mainwp' ),
1313 + 'value' => (string) get_option( 'mainwp_timeDailyUpdate', '00:00' ),
1314 + ),
1315 + array(
1316 + 'label' => esc_html__( 'Advanced automatic updates schedule', 'mainwp' ),
1317 + 'value' => static::get_automatic_updates_schedule_label(),
1318 + ),
1319 + );
1320 +
1321 + $updates_check = static::get_cron_job_summary( 'mainwp_updatescheck_start_last_timestamp', 'mainwp_cronupdatescheck_action', '' );
1322 + $rows[] = array(
1323 + 'label' => esc_html__( 'Check for available updates', 'mainwp' ),
1324 + 'value' => sprintf(
1325 + /* translators: 1: last run, 2: next run */
1326 + esc_html__( 'Last run: %1$s | Next run: %2$s', 'mainwp' ),
1327 + $updates_check['last'],
1328 + $updates_check['next']
1329 + ),
1330 + );
1331 +
1332 + $reconnect = static::get_cron_job_summary( 'mainwp_cron_last_stats', 'mainwp_cronreconnect_action', 'hourly' );
1333 + $rows[] = array(
1334 + 'label' => esc_html__( 'Reconnect sites', 'mainwp' ),
1335 + 'value' => sprintf(
1336 + /* translators: 1: last run, 2: next run */
1337 + esc_html__( 'Last run: %1$s | Next run: %2$s', 'mainwp' ),
1338 + $reconnect['last'],
1339 + $reconnect['next']
1340 + ),
1341 + );
1342 +
1343 + $monitoring = static::get_uptime_monitoring_summary();
1344 + if ( ! empty( $monitoring ) ) {
1345 + $rows[] = $monitoring;
1346 + }
1347 +
1348 + return self::add_export_labels_to_rows(
1349 + $rows,
1350 + array(
1351 + 'Use WP Cron',
1352 + 'Daily update frequency',
1353 + 'Daily update time',
1354 + 'Advanced automatic updates schedule',
1355 + 'Check for available updates',
1356 + 'Reconnect sites',
1357 + 'Uptime monitoring schedule',
1358 + )
1359 + );
1360 + }
1361 +
1362 + /**
1363 + * Get general settings rows.
1364 + *
1365 + * @return array<int,array<string,mixed>>
1366 + */
1367 + public static function get_general_settings_report_rows() {
1368 + $default_setting = MainWP_Settings_Indicator::get_defaults_value();
1369 + $sidebar = get_user_option( 'mainwp_sidebarPosition' );
1370 + if ( false === $sidebar ) {
1371 + $sidebar = 1;
1372 + }
1373 +
1374 + $time_auto_update = get_option( 'mainwp_time_AutoUpdate', '00:00' );
1375 + $frequency_auto_update = get_option( 'mainwp_frequency_AutoUpdate', 'daily' );
1376 + if ( empty( $time_auto_update ) ) {
1377 + $time_auto_update = '00:00';
1378 + }
1379 + if ( ! in_array( $frequency_auto_update, array( 'daily', 'weekly', 'monthly' ), true ) ) {
1380 + $frequency_auto_update = 'daily';
1381 + }
1382 +
1383 + $show_widgets = get_user_option( 'mainwp_settings_show_widgets' );
1384 + if ( ! is_array( $show_widgets ) ) {
1385 + $show_widgets = array();
1386 + }
1387 +
1388 + return self::add_export_labels_to_rows(
1389 + array(
1390 + array(
1391 + 'label' => esc_html__( 'Timezone', 'mainwp' ),
1392 + 'value' => static::get_timezone_label(),
1393 + ),
1394 + array(
1395 + 'label' => esc_html__( 'Date format', 'mainwp' ),
1396 + 'value' => (string) get_option( 'date_format', $default_setting['date_format'] ),
1397 + ),
1398 + array(
1399 + 'label' => esc_html__( 'Time format', 'mainwp' ),
1400 + 'value' => (string) get_option( 'time_format', $default_setting['time_format'] ),
1401 + ),
1402 + array(
1403 + 'label' => esc_html__( 'Sidebar position', 'mainwp' ),
1404 + 'value' => 0 === (int) $sidebar ? esc_html__( 'Left', 'mainwp' ) : esc_html__( 'Right', 'mainwp' ),
1405 + ),
1406 + array(
1407 + 'label' => esc_html__( 'Hide Update Everything', 'mainwp' ),
1408 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_hide_update_everything', $default_setting['mainwp_hide_update_everything'] ) ),
1409 + ),
1410 + array(
1411 + 'label' => esc_html__( 'Dashboard widgets shown', 'mainwp' ),
1412 + 'value' => sprintf(
1413 + /* translators: %d: visible widget count */
1414 + esc_html__( '%d visible', 'mainwp' ),
1415 + count( $show_widgets )
1416 + ),
1417 + ),
1418 + array(
1419 + 'label' => esc_html__( 'WP Core advanced automatic updates', 'mainwp' ),
1420 + 'value' => static::get_trusted_update_mode_label( get_option( 'mainwp_automaticDailyUpdate', $default_setting['mainwp_automaticDailyUpdate'] ) ),
1421 + ),
1422 + array(
1423 + 'label' => esc_html__( 'Plugin advanced automatic updates', 'mainwp' ),
1424 + 'value' => static::get_trusted_update_mode_label( get_option( 'mainwp_pluginAutomaticDailyUpdate', $default_setting['mainwp_pluginAutomaticDailyUpdate'] ) ),
1425 + ),
1426 + array(
1427 + 'label' => esc_html__( 'Theme advanced automatic updates', 'mainwp' ),
1428 + 'value' => static::get_trusted_update_mode_label( get_option( 'mainwp_themeAutomaticDailyUpdate', $default_setting['mainwp_themeAutomaticDailyUpdate'] ) ),
1429 + ),
1430 + array(
1431 + 'label' => esc_html__( 'Translation advanced automatic updates', 'mainwp' ),
1432 + 'value' => static::get_trusted_update_mode_label( get_option( 'mainwp_transAutomaticDailyUpdate', 0 ) ),
1433 + ),
1434 + array(
1435 + 'label' => esc_html__( 'Automatic updates frequency', 'mainwp' ),
1436 + 'value' => ucfirst( (string) $frequency_auto_update ),
1437 + ),
1438 + array(
1439 + 'label' => esc_html__( 'Automatic updates time', 'mainwp' ),
1440 + 'value' => (string) $time_auto_update,
1441 + ),
1442 + array(
1443 + 'label' => esc_html__( 'Automatic updates day', 'mainwp' ),
1444 + 'value' => static::get_automatic_updates_day_label( $frequency_auto_update ),
1445 + ),
1446 + array(
1447 + 'label' => esc_html__( 'Advanced automatic updates delay', 'mainwp' ),
1448 + 'value' => static::format_delay_label( (int) get_option( 'mainwp_delay_autoupdate', 1 ) ),
1449 + ),
1450 + array(
1451 + 'label' => esc_html__( 'Show language updates', 'mainwp' ),
1452 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_show_language_updates', $default_setting['mainwp_show_language_updates'] ) ),
1453 + ),
1454 + array(
1455 + 'label' => esc_html__( 'Disable update confirmations', 'mainwp' ),
1456 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_disable_update_confirmations', $default_setting['mainwp_disable_update_confirmations'] ) ),
1457 + ),
1458 + array(
1459 + 'label' => esc_html__( 'After updates HTTP response check', 'mainwp' ),
1460 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_check_http_response', $default_setting['mainwp_check_http_response'] ) ),
1461 + ),
1462 + array(
1463 + 'label' => esc_html__( 'After updates HTTP response method', 'mainwp' ),
1464 + 'value' => strtoupper( (string) get_option( 'mainwp_check_http_response_method', $default_setting['mainwp_check_http_response_method'] ) ),
1465 + ),
1466 + array(
1467 + 'label' => esc_html__( 'Backup before update', 'mainwp' ),
1468 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_backup_before_upgrade', $default_setting['mainwp_backup_before_upgrade'] ) ),
1469 + ),
1470 + array(
1471 + 'label' => esc_html__( 'Full backup tolerance before update', 'mainwp' ),
1472 + 'value' => sprintf(
1473 + /* translators: %d: days */
1474 + esc_html__( '%d days', 'mainwp' ),
1475 + (int) get_option( 'mainwp_backup_before_upgrade_days', $default_setting['mainwp_backup_before_upgrade_days'] )
1476 + ),
1477 + ),
1478 + array(
1479 + 'label' => esc_html__( 'Abandoned plugins/themes tolerance', 'mainwp' ),
1480 + 'value' => sprintf(
1481 + /* translators: %d: days */
1482 + esc_html__( '%d days', 'mainwp' ),
1483 + (int) get_option( 'mainwp_numberdays_Outdate_Plugin_Theme', $default_setting['mainwp_numberdays_Outdate_Plugin_Theme'] )
1484 + ),
1485 + ),
1486 + array(
1487 + 'label' => esc_html__( 'Primary backup system', 'mainwp' ),
1488 + 'value' => static::get_primary_backup_method_label(),
1489 + ),
1490 + array(
1491 + 'label' => esc_html__( 'MainWP legacy backups enabled', 'mainwp' ),
1492 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_enableLegacyBackupFeature', 0 ) ),
1493 + ),
1494 + array(
1495 + 'label' => esc_html__( 'Backups kept on server', 'mainwp' ),
1496 + 'value' => (string) ( false === get_option( 'mainwp_backupsOnServer' ) ? 1 : intval( get_option( 'mainwp_backupsOnServer' ) ) ),
1497 + ),
1498 + array(
1499 + 'label' => esc_html__( 'Backup to external sources', 'mainwp' ),
1500 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_backupOnExternalSources', 0 ) ),
1501 + ),
1502 + array(
1503 + 'label' => esc_html__( 'Archive format', 'mainwp' ),
1504 + 'value' => static::format_archive_format_label( get_option( 'mainwp_archiveFormat', 'tar.gz' ) ),
1505 + ),
1506 + array(
1507 + 'label' => esc_html__( 'Auto detect maximum file descriptors on child sites', 'mainwp' ),
1508 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_maximumFileDescriptorsAuto', 1 ) ),
1509 + ),
1510 + array(
1511 + 'label' => esc_html__( 'Maximum file descriptors fallback value', 'mainwp' ),
1512 + 'value' => (string) ( false === get_option( 'mainwp_maximumFileDescriptors' ) ? 150 : intval( get_option( 'mainwp_maximumFileDescriptors' ) ) ),
1513 + ),
1514 + array(
1515 + 'label' => esc_html__( 'Load files in memory before zipping', 'mainwp' ),
1516 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_options_loadFilesBeforeZip', 1 ) ),
1517 + ),
1518 + array(
1519 + 'label' => esc_html__( 'Send email when backup fails', 'mainwp' ),
1520 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_notificationOnBackupFail', 1 ) ),
1521 + ),
1522 + array(
1523 + 'label' => esc_html__( 'Send email when backup starts', 'mainwp' ),
1524 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_notificationOnBackupStart', 1 ) ),
1525 + ),
1526 + array(
1527 + 'label' => esc_html__( 'Execute backup tasks in chunks', 'mainwp' ),
1528 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_chunkedBackupTasks', 1 ) ),
1529 + ),
1530 + ),
1531 + array(
1532 + 'Timezone',
1533 + 'Date format',
1534 + 'Time format',
1535 + 'Sidebar position',
1536 + 'Hide Update Everything',
1537 + 'Dashboard widgets shown',
1538 + 'WP Core advanced automatic updates',
1539 + 'Plugin advanced automatic updates',
1540 + 'Theme advanced automatic updates',
1541 + 'Translation advanced automatic updates',
1542 + 'Automatic updates frequency',
1543 + 'Automatic updates time',
1544 + 'Automatic updates day',
1545 + 'Advanced automatic updates delay',
1546 + 'Show language updates',
1547 + 'Disable update confirmations',
1548 + 'After updates HTTP response check',
1549 + 'After updates HTTP response method',
1550 + 'Backup before update',
1551 + 'Full backup tolerance before update',
1552 + 'Abandoned plugins/themes tolerance',
1553 + 'Primary backup system',
1554 + 'MainWP legacy backups enabled',
1555 + 'Backups kept on server',
1556 + 'Backup to external sources',
1557 + 'Archive format',
1558 + 'Auto detect maximum file descriptors on child sites',
1559 + 'Maximum file descriptors fallback value',
1560 + 'Load files in memory before zipping',
1561 + 'Send email when backup fails',
1562 + 'Send email when backup starts',
1563 + 'Execute backup tasks in chunks',
1564 + )
1565 + );
1566 + }
1567 +
1568 + /**
1569 + * Get advanced settings rows.
1570 + *
1571 + * @return array<int,array<string,mixed>>
1572 + */
1573 + public static function get_advanced_settings_report_rows() {
1574 + $default_setting = MainWP_Settings_Indicator::get_defaults_value();
1575 + $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
1576 + $signature_algo = (int) get_option( 'mainwp_connect_signature_algo', $default_setting['mainwp_connect_signature_algo'] );
1577 + $sync_defaults = MainWP_Settings::get_data_sync_default();
1578 + $sync_data = get_option( 'mainwp_settings_sync_data', array() );
1579 + $sync_data = ! empty( $sync_data ) ? json_decode( (string) $sync_data, true ) : array();
1580 + if ( ! is_array( $sync_data ) ) {
1581 + $sync_data = array();
1582 + }
1583 +
1584 + $enabled_sync = 0;
1585 + foreach ( array_keys( $sync_defaults ) as $sync_name ) {
1586 + if ( ! isset( $sync_data[ $sync_name ] ) || ! empty( $sync_data[ $sync_name ] ) ) {
1587 + ++$enabled_sync;
1588 + }
1589 + }
1590 +
1591 + return self::add_export_labels_to_rows(
1592 + array(
1593 + array(
1594 + 'label' => esc_html__( 'Maximum simultaneous requests', 'mainwp' ),
1595 + 'value' => (string) ( false === get_option( 'mainwp_maximumRequests' ) ? 4 : intval( get_option( 'mainwp_maximumRequests' ) ) ),
1596 + ),
1597 + array(
1598 + 'label' => esc_html__( 'Minimum delay between requests', 'mainwp' ),
1599 + 'value' => sprintf(
1600 + /* translators: %d: milliseconds */
1601 + esc_html__( '%d ms', 'mainwp' ),
1602 + (int) ( false === get_option( 'mainwp_minimumDelay' ) ? 200 : intval( get_option( 'mainwp_minimumDelay' ) ) )
1603 + ),
1604 + ),
1605 + array(
1606 + 'label' => esc_html__( 'Maximum simultaneous requests per IP', 'mainwp' ),
1607 + 'value' => (string) ( false === get_option( 'mainwp_maximumIPRequests' ) ? 1 : intval( get_option( 'mainwp_maximumIPRequests' ) ) ),
1608 + ),
1609 + array(
1610 + 'label' => esc_html__( 'Minimum delay between requests to the same IP', 'mainwp' ),
1611 + 'value' => sprintf(
1612 + /* translators: %d: milliseconds */
1613 + esc_html__( '%d ms', 'mainwp' ),
1614 + (int) ( false === get_option( 'mainwp_minimumIPDelay' ) ? 1000 : intval( get_option( 'mainwp_minimumIPDelay' ) ) )
1615 + ),
1616 + ),
1617 + array(
1618 + 'label' => esc_html__( 'Maximum simultaneous sync requests', 'mainwp' ),
1619 + 'value' => (string) ( false === get_option( 'mainwp_maximumSyncRequests' ) ? 8 : intval( get_option( 'mainwp_maximumSyncRequests' ) ) ),
1620 + ),
1621 + array(
1622 + 'label' => esc_html__( 'Maximum simultaneous install and update requests', 'mainwp' ),
1623 + 'value' => (string) ( false === get_option( 'mainwp_maximumInstallUpdateRequests' ) ? 3 : intval( get_option( 'mainwp_maximumInstallUpdateRequests' ) ) ),
1624 + ),
1625 + array(
1626 + 'label' => esc_html__( 'Maximum simultaneous uptime monitoring requests', 'mainwp' ),
1627 + 'value' => (string) ( false === get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ? 10 : intval( get_option( 'mainwp_maximum_uptime_monitoring_requests' ) ) ),
1628 + ),
1629 + array(
1630 + 'label' => esc_html__( 'Sites processed per sync batch', 'mainwp' ),
1631 + 'value' => (string) ( false === get_option( 'mainwp_chunksitesnumber' ) ? 10 : intval( get_option( 'mainwp_chunksitesnumber' ) ) ),
1632 + ),
1633 + array(
1634 + 'label' => esc_html__( 'Sync batch sleep interval', 'mainwp' ),
1635 + 'value' => sprintf(
1636 + /* translators: %d: seconds */
1637 + esc_html__( '%d seconds', 'mainwp' ),
1638 + (int) ( false === get_option( 'mainwp_chunksleepinterval' ) ? 5 : intval( get_option( 'mainwp_chunksleepinterval' ) ) )
1639 + ),
1640 + ),
1641 + array(
1642 + 'label' => esc_html__( 'Optimize data loading', 'mainwp' ),
1643 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_optimize', $default_setting['mainwp_optimize'] ) ),
1644 + ),
1645 + array(
1646 + 'label' => esc_html__( 'Browser cache expiration time', 'mainwp' ),
1647 + 'value' => sprintf(
1648 + /* translators: %d: minutes */
1649 + esc_html__( '%d minutes', 'mainwp' ),
1650 + (int) get_option( 'mainwp_warm_cache_pages_ttl', 10 )
1651 + ),
1652 + ),
1653 + array(
1654 + 'label' => esc_html__( 'Verify SSL certificate', 'mainwp' ),
1655 + 'value' => static::format_boolean_label( ( false === get_option( 'mainwp_sslVerifyCertificate' ) ) || 1 === (int) get_option( 'mainwp_sslVerifyCertificate', 1 ) ),
1656 + ),
1657 + array(
1658 + 'label' => esc_html__( 'Verify connection method', 'mainwp' ),
1659 + 'value' => 2 === (int) get_option( 'mainwp_verify_connection_method', 1 ) ? esc_html__( 'PHPSECLIB (fallback)', 'mainwp' ) : esc_html__( 'OpenSSL (default)', 'mainwp' ),
1660 + ),
1661 + array(
1662 + 'label' => esc_html__( 'OpenSSL signature algorithm', 'mainwp' ),
1663 + 'value' => isset( $sign_algs[ $signature_algo ] ) ? $sign_algs[ $signature_algo ] : (string) $signature_algo,
1664 + ),
1665 + array(
1666 + 'label' => esc_html__( 'Force IPv4', 'mainwp' ),
1667 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_forceUseIPv4', 0 ) ),
1668 + ),
1669 + array(
1670 + 'label' => esc_html__( 'Selected data to sync', 'mainwp' ),
1671 + 'value' => sprintf(
1672 + /* translators: 1: enabled count, 2: total count */
1673 + esc_html__( '%1$d of %2$d enabled', 'mainwp' ),
1674 + $enabled_sync,
1675 + count( $sync_defaults )
1676 + ),
1677 + ),
1678 + ),
1679 + array(
1680 + 'Maximum simultaneous requests',
1681 + 'Minimum delay between requests',
1682 + 'Maximum simultaneous requests per IP',
1683 + 'Minimum delay between requests to the same IP',
1684 + 'Maximum simultaneous sync requests',
1685 + 'Maximum simultaneous install and update requests',
1686 + 'Maximum simultaneous uptime monitoring requests',
1687 + 'Sites processed per sync batch',
1688 + 'Sync batch sleep interval',
1689 + 'Optimize data loading',
1690 + 'Browser cache expiration time',
1691 + 'Verify SSL certificate',
1692 + 'Verify connection method',
1693 + 'OpenSSL signature algorithm',
1694 + 'Force IPv4',
1695 + 'Selected data to sync',
1696 + )
1697 + );
1698 + }
1699 +
1700 + /**
1701 + * Get monitoring settings rows.
1702 + *
1703 + * @return array<int,array<string,mixed>>
1704 + */
1705 + public static function get_monitoring_settings_report_rows() {
1706 + $monitoring_settings = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
1707 + $global_option = get_option( 'mainwp_global_uptime_monitoring_settings', array() );
1708 + if ( ! is_array( $global_option ) ) {
1709 + $global_option = array();
1710 + }
1711 +
1712 + $interval_values = MainWP_Uptime_Monitoring_Edit::get_interval_values( false );
1713 + $timeout_values = MainWP_Uptime_Monitoring_Edit::get_timeout_values( false );
1714 + $interval_key = $monitoring_settings['interval'] ?? 60;
1715 + $timeout_key = $monitoring_settings['timeout'] ?? 60;
1716 + $interval_value = isset( $interval_values[ $interval_key ] ) ? $interval_values[ $interval_key ] : $interval_key;
1717 + $timeout_value = isset( $timeout_values[ $timeout_key ] ) ? $timeout_values[ $timeout_key ] : $timeout_key;
1718 + $retention_days = isset( $global_option['retention_limits'] ) ? intval( $global_option['retention_limits'] ) : 180;
1719 + $site_health = empty( get_option( 'mainwp_disableSitesHealthMonitoring', 1 ) );
1720 + $threshold = (int) get_option( 'mainwp_sitehealthThreshold', 80 );
1721 +
1722 + return self::add_export_labels_to_rows(
1723 + array(
1724 + array(
1725 + 'label' => esc_html__( 'Enable uptime monitoring', 'mainwp' ),
1726 + 'value' => static::format_boolean_label( ! empty( $monitoring_settings['active'] ) ),
1727 + ),
1728 + array(
1729 + 'label' => esc_html__( 'Monitor type', 'mainwp' ),
1730 + 'value' => static::format_monitor_type_label( $monitoring_settings['type'] ?? 'http' ),
1731 + ),
1732 + array(
1733 + 'label' => esc_html__( 'Method', 'mainwp' ),
1734 + 'value' => strtoupper( (string) ( $monitoring_settings['method'] ?? 'get' ) ),
1735 + ),
1736 + array(
1737 + 'label' => esc_html__( 'Interval', 'mainwp' ),
1738 + 'value' => (string) $interval_value,
1739 + ),
1740 + array(
1741 + 'label' => esc_html__( 'Timeout', 'mainwp' ),
1742 + 'value' => (string) $timeout_value,
1743 + ),
1744 + array(
1745 + 'label' => esc_html__( 'Up HTTP codes', 'mainwp' ),
1746 + 'value' => ! empty( $monitoring_settings['up_status_codes'] ) ? (string) $monitoring_settings['up_status_codes'] : esc_html__( 'Default', 'mainwp' ),
1747 + ),
1748 + array(
1749 + 'label' => esc_html__( 'Down confirmation check', 'mainwp' ),
1750 + 'value' => ! empty( $monitoring_settings['maxretries'] ) ? esc_html__( 'Enabled', 'mainwp' ) : esc_html__( 'Disabled', 'mainwp' ),
1751 + ),
1752 + array(
1753 + 'label' => esc_html__( 'Keyword monitoring value', 'mainwp' ),
1754 + 'value' => ! empty( $monitoring_settings['keyword'] ) ? (string) $monitoring_settings['keyword'] : esc_html__( 'Not configured', 'mainwp' ),
1755 + ),
1756 + array(
1757 + 'label' => esc_html__( 'Monitoring data retention', 'mainwp' ),
1758 + 'value' => static::format_retention_days_label( $retention_days ),
1759 + ),
1760 + array(
1761 + 'label' => esc_html__( 'Enable site health monitoring', 'mainwp' ),
1762 + 'value' => static::format_boolean_label( $site_health ),
1763 + ),
1764 + array(
1765 + 'label' => esc_html__( 'Site Health threshold', 'mainwp' ),
1766 + 'value' => 100 === $threshold ? esc_html__( 'Good', 'mainwp' ) : esc_html__( 'Should be improved', 'mainwp' ),
1767 + ),
1768 + ),
1769 + array(
1770 + 'Enable uptime monitoring',
1771 + 'Monitor type',
1772 + 'Method',
1773 + 'Interval',
1774 + 'Timeout',
1775 + 'Up HTTP codes',
1776 + 'Down confirmation check',
1777 + 'Keyword monitoring value',
1778 + 'Monitoring data retention',
1779 + 'Enable site health monitoring',
1780 + 'Site Health threshold',
1781 + )
1782 + );
1783 + }
1784 +
1785 + /**
1786 + * Get email settings rows.
1787 + *
1788 + * @return array<int,array<string,mixed>>
1789 + */
1790 + public static function get_email_settings_report_rows() {
1791 + $rows = array();
1792 + $types = MainWP_Notification_Settings::get_notification_types();
1793 +
1794 + foreach ( $types as $type => $label ) {
1795 + $settings = MainWP_Notification_Settings::get_general_email_settings( $type );
1796 + $recipients = isset( $settings['recipients'] ) ? trim( (string) $settings['recipients'] ) : '';
1797 + $recipient_count = static::count_recipients( $recipients );
1798 + $subject_config = ! empty( $settings['subject'] ) ? esc_html__( 'Subject set', 'mainwp' ) : esc_html__( 'Subject empty', 'mainwp' );
1799 + $heading_config = ! empty( $settings['heading'] ) ? esc_html__( 'Heading set', 'mainwp' ) : esc_html__( 'Heading empty', 'mainwp' );
1800 + $enabled_disabled = empty( $settings['disable'] ) ? esc_html__( 'Enabled', 'mainwp' ) : esc_html__( 'Disabled', 'mainwp' );
1801 +
1802 + $value = sprintf(
1803 + /* translators: 1: enabled state, 2: recipients count, 3: subject state, 4: heading state */
1804 + esc_html__( '%1$s | %2$d recipient(s) | %3$s | %4$s', 'mainwp' ),
1805 + $enabled_disabled,
1806 + $recipient_count,
1807 + $subject_config,
1808 + $heading_config
1809 + );
1810 +
1811 + $rows[] = array(
1812 + 'label' => $label,
1813 + 'export_label' => self::get_notification_type_export_label( $type, $label ),
1814 + 'value' => $value,
1815 + );
1816 + }
1817 +
1818 + return $rows;
1819 + }
1820 +
1821 + /**
1822 + * Get cost tracker rows.
1823 + *
1824 + * @return array<int,array<string,mixed>>
1825 + */
1826 + public static function get_cost_tracker_report_rows() {
1827 + if ( ! class_exists( '\MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility' ) || ! class_exists( '\MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Admin' ) ) {
1828 + return array();
1829 + }
1830 +
1831 + $selected_currency = \MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility::get_instance()->get_option( 'currency', 'USD' );
1832 + $currency_format = \MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility::get_instance()->get_option( 'currency_format', array() );
1833 + $currency_format = array_merge( \MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility::default_currency_settings(), is_array( $currency_format ) ? $currency_format : array() );
1834 + $custom_payment_methods = \MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Utility::get_instance()->get_option( 'custom_payment_methods', array(), true );
1835 + $product_types = \MainWP\Dashboard\Module\CostTracker\Cost_Tracker_Admin::get_product_type_icons();
1836 +
1837 + if ( ! is_array( $custom_payment_methods ) ) {
1838 + $custom_payment_methods = array();
1839 + }
1840 + if ( ! is_array( $product_types ) ) {
1841 + $product_types = array();
1842 + }
1843 +
1844 + return self::add_export_labels_to_rows(
1845 + array(
1846 + array(
1847 + 'label' => esc_html__( 'Currency', 'mainwp' ),
1848 + 'value' => (string) $selected_currency,
1849 + ),
1850 + array(
1851 + 'label' => esc_html__( 'Currency position', 'mainwp' ),
1852 + 'value' => (string) $currency_format['currency_position'],
1853 + ),
1854 + array(
1855 + 'label' => esc_html__( 'Thousand separator', 'mainwp' ),
1856 + 'value' => '' === (string) $currency_format['thousand_separator'] ? esc_html__( 'None', 'mainwp' ) : (string) $currency_format['thousand_separator'],
1857 + ),
1858 + array(
1859 + 'label' => esc_html__( 'Decimal separator', 'mainwp' ),
1860 + 'value' => (string) $currency_format['decimal_separator'],
1861 + ),
1862 + array(
1863 + 'label' => esc_html__( 'Decimals', 'mainwp' ),
1864 + 'value' => (string) intval( $currency_format['decimals'] ),
1865 + ),
1866 + array(
1867 + 'label' => esc_html__( 'Product categories', 'mainwp' ),
1868 + 'value' => sprintf(
1869 + /* translators: %d: count */
1870 + esc_html__( '%d configured', 'mainwp' ),
1871 + count( $product_types )
1872 + ),
1873 + ),
1874 + array(
1875 + 'label' => esc_html__( 'Payment methods', 'mainwp' ),
1876 + 'value' => sprintf(
1877 + /* translators: %d: count */
1878 + esc_html__( '%d configured', 'mainwp' ),
1879 + count( $custom_payment_methods )
1880 + ),
1881 + ),
1882 + ),
1883 + array(
1884 + 'Currency',
1885 + 'Currency position',
1886 + 'Thousand separator',
1887 + 'Decimal separator',
1888 + 'Decimals',
1889 + 'Product categories',
1890 + 'Payment methods',
1891 + )
1892 + );
1893 + }
1894 +
1895 + /**
1896 + * Get insights rows.
1897 + *
1898 + * @return array<int,array<string,mixed>>
1899 + */
1900 + public static function get_insights_report_rows() {
1901 + $options = get_option( 'mainwp_module_log_settings', array() );
1902 + if ( ! is_array( $options ) ) {
1903 + $options = array();
1904 + }
1905 +
1906 + $dashboard_disabled = 0;
1907 + $child_disabled = 0;
1908 + $changes_disabled = 0;
1909 +
1910 + if ( class_exists( '\MainWP\Dashboard\Module\Log\Log_Settings' ) ) {
1911 + $dashboard_disabled = count( \MainWP\Dashboard\Module\Log\Log_Settings::get_disabled_logs_type( 'dashboard' ) );
1912 + $child_disabled = count( \MainWP\Dashboard\Module\Log\Log_Settings::get_disabled_logs_type( 'nonmainwpchanges' ) );
1913 + $changes_disabled = count( \MainWP\Dashboard\Module\Log\Log_Settings::get_disabled_logs_type( 'changeslogs' ) );
1914 + }
1915 +
1916 + return self::add_export_labels_to_rows(
1917 + array(
1918 + array(
1919 + 'label' => esc_html__( 'Enable Network Activity logging', 'mainwp' ),
1920 + 'value' => static::format_boolean_label( ! empty( $options['enabled'] ) ),
1921 + ),
1922 + array(
1923 + 'label' => esc_html__( 'Automatically archive logs', 'mainwp' ),
1924 + 'value' => static::format_boolean_label( ! empty( $options['auto_archive'] ) ),
1925 + ),
1926 + array(
1927 + 'label' => esc_html__( 'Data retention period', 'mainwp' ),
1928 + 'value' => static::format_log_retention_label( isset( $options['records_logs_ttl'] ) ? intval( $options['records_logs_ttl'] ) : 3 * YEAR_IN_SECONDS ),
1929 + ),
1930 + array(
1931 + 'label' => esc_html__( 'Child-site Network Activity retention', 'mainwp' ),
1932 + 'value' => static::format_retention_days_label( isset( $options['child_logs_ttl'] ) ? intval( $options['child_logs_ttl'] ) : 7 ),
1933 + ),
1934 + array(
1935 + 'label' => esc_html__( 'Disabled dashboard event types', 'mainwp' ),
1936 + 'value' => (string) $dashboard_disabled,
1937 + ),
1938 + array(
1939 + 'label' => esc_html__( 'Disabled child-site event types', 'mainwp' ),
1940 + 'value' => (string) $child_disabled,
1941 + ),
1942 + array(
1943 + 'label' => esc_html__( 'Disabled change-log event types', 'mainwp' ),
1944 + 'value' => (string) $changes_disabled,
1945 + ),
1946 + ),
1947 + array(
1948 + 'Enable Network Activity logging',
1949 + 'Automatically archive logs',
1950 + 'Data retention period',
1951 + 'Child-site Network Activity retention',
1952 + 'Disabled dashboard event types',
1953 + 'Disabled child-site event types',
1954 + 'Disabled change-log event types',
1955 + )
1956 + );
1957 + }
1958 +
1959 + /**
1960 + * Get API backups rows.
1961 + *
1962 + * @return array<int,array<string,mixed>>
1963 + */
1964 + public static function get_api_backups_report_rows() {
1965 + if ( ! class_exists( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party' ) ) {
1966 + return array();
1967 + }
1968 +
1969 + $definitions = array(
1970 + 'cloudways' => array(
1971 + 'label' => 'Cloudways',
1972 + 'enabled_option' => 'mainwp_enable_cloudways_api',
1973 + 'options' => array( 'mainwp_cloudways_api_account_email' ),
1974 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_cloudways_api_key' ) ),
1975 + ),
1976 + 'gridpane' => array(
1977 + 'label' => 'GridPane',
1978 + 'enabled_option' => 'mainwp_enable_gridpane_api',
1979 + 'options' => array(),
1980 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_gridpane_api_key' ) ),
1981 + ),
1982 + 'vultr' => array(
1983 + 'label' => 'Vultr',
1984 + 'enabled_option' => 'mainwp_enable_vultr_api',
1985 + 'options' => array(),
1986 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_vultr_api_key' ) ),
1987 + ),
1988 + 'linode' => array(
1989 + 'label' => 'Akamai (Linode)',
1990 + 'enabled_option' => 'mainwp_enable_linode_api',
1991 + 'options' => array(),
1992 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_linode_api_key' ) ),
1993 + ),
1994 + 'digitalocean' => array(
1995 + 'label' => 'DigitalOcean',
1996 + 'enabled_option' => 'mainwp_enable_digitalocean_api',
1997 + 'options' => array(),
1998 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_digitalocean_api_key' ) ),
1999 + ),
2000 + 'cpanel' => array(
2001 + 'label' => 'cPanel (WP Toolkit)',
2002 + 'enabled_option' => 'mainwp_enable_cpanel_api',
2003 + 'options' => array( 'mainwp_cpanel_url', 'mainwp_cpanel_site_path', 'mainwp_cpanel_account_username' ),
2004 + 'secrets' => array(),
2005 + ),
2006 + 'plesk' => array(
2007 + 'label' => 'Plesk',
2008 + 'enabled_option' => 'mainwp_enable_plesk_api',
2009 + 'options' => array( 'mainwp_plesk_api_url' ),
2010 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_plesk_api_key' ) ),
2011 + ),
2012 + 'kinsta' => array(
2013 + 'label' => 'Kinsta',
2014 + 'enabled_option' => 'mainwp_enable_kinsta_api',
2015 + 'options' => array( 'mainwp_kinsta_api_account_email', 'mainwp_kinsta_company_id' ),
2016 + 'secrets' => array( array( '\MainWP\Dashboard\Module\ApiBackups\Api_Backups_3rd_Party', 'get_kinsta_api_key' ) ),
2017 + ),
2018 + );
2019 +
2020 + $rows = array();
2021 +
2022 + foreach ( $definitions as $provider ) {
2023 + $enabled = ! empty( get_option( $provider['enabled_option'], 0 ) );
2024 + $details = array();
2025 +
2026 + foreach ( $provider['options'] as $option_name ) {
2027 + if ( '' !== trim( (string) get_option( $option_name, '' ) ) ) {
2028 + $details[] = esc_html__( 'profile configured', 'mainwp' );
2029 + break;
2030 + }
2031 + }
2032 +
2033 + foreach ( $provider['secrets'] as $secret_callback ) {
2034 + $secret = call_user_func( $secret_callback );
2035 + if ( ! empty( $secret ) ) {
2036 + $details[] = esc_html__( 'secret configured', 'mainwp' );
2037 + break;
2038 + }
2039 + }
2040 +
2041 + $summary = $enabled ? esc_html__( 'Enabled', 'mainwp' ) : esc_html__( 'Disabled', 'mainwp' );
2042 + if ( ! empty( $details ) ) {
2043 + $summary .= ' | ' . implode( ', ', array_unique( $details ) );
2044 + }
2045 +
2046 + $rows[] = array(
2047 + 'label' => $provider['label'],
2048 + 'value' => $summary,
2049 + );
2050 + }
2051 +
2052 + return $rows;
2053 + }
2054 +
2055 + /**
2056 + * Get tools rows.
2057 + *
2058 + * @return array<int,array<string,mixed>>
2059 + */
2060 + public static function get_tools_report_rows() {
2061 + return self::add_export_labels_to_rows(
2062 + array(
2063 + array(
2064 + 'label' => esc_html__( 'Current MainWP theme', 'mainwp' ),
2065 + 'value' => MainWP_Settings::get_instance()->get_current_user_theme(),
2066 + ),
2067 + array(
2068 + 'label' => esc_html__( 'Guided tours', 'mainwp' ),
2069 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_enable_guided_tours', 0 ) ),
2070 + ),
2071 + array(
2072 + 'label' => esc_html__( 'Chatbase', 'mainwp' ),
2073 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_enable_guided_chatbase', 0 ) ),
2074 + ),
2075 + array(
2076 + 'label' => esc_html__( 'Guided video', 'mainwp' ),
2077 + 'value' => static::format_boolean_label( (int) get_option( 'mainwp_enable_guided_video', 0 ) ),
2078 + ),
2079 + ),
2080 + array(
2081 + 'Current MainWP theme',
2082 + 'Guided tours',
2083 + 'Chatbase',
2084 + 'Guided video',
2085 + )
2086 + );
2087 + }
2088 +
2089 + /**
2090 + * Get debug rows.
2091 + *
2092 + * @return array<int,array<string,mixed>>
2093 + */
2094 + public static function get_debug_report_rows() {
2095 + $error_log_path = ini_get( 'error_log' );
2096 + $log_readable = ! empty( $error_log_path ) && file_exists( $error_log_path ) ? is_readable( $error_log_path ) : false;
2097 +
2098 + return self::add_export_labels_to_rows(
2099 + array(
2100 + array(
2101 + 'label' => esc_html__( 'WP_DEBUG', 'mainwp' ),
2102 + 'value' => static::format_boolean_label( defined( 'WP_DEBUG' ) && WP_DEBUG ),
2103 + ),
2104 + array(
2105 + 'label' => esc_html__( 'WP_DEBUG_LOG', 'mainwp' ),
2106 + 'value' => static::format_boolean_label( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ),
2107 + ),
2108 + array(
2109 + 'label' => esc_html__( 'WP_DEBUG_DISPLAY', 'mainwp' ),
2110 + 'value' => static::format_boolean_label( defined( 'WP_DEBUG_DISPLAY' ) && WP_DEBUG_DISPLAY ),
2111 + ),
2112 + array(
2113 + 'label' => esc_html__( 'PHP log_errors', 'mainwp' ),
2114 + 'value' => static::format_boolean_label( filter_var( ini_get( 'log_errors' ), FILTER_VALIDATE_BOOLEAN ) ),
2115 + ),
2116 + array(
2117 + 'label' => esc_html__( 'PHP error_log path', 'mainwp' ),
2118 + 'value' => ! empty( $error_log_path ) ? $error_log_path : esc_html__( 'Not set', 'mainwp' ),
2119 + 'visibility' => 'community_masked',
2120 + 'community_value' => ! empty( $error_log_path ) ? esc_html__( 'Configured', 'mainwp' ) : esc_html__( 'Not set', 'mainwp' ),
2121 + ),
2122 + array(
2123 + 'label' => esc_html__( 'PHP error_log readable', 'mainwp' ),
2124 + 'value' => static::format_boolean_label( $log_readable ),
2125 + ),
2126 + ),
2127 + array(
2128 + 'WP_DEBUG',
2129 + 'WP_DEBUG_LOG',
2130 + 'WP_DEBUG_DISPLAY',
2131 + 'PHP log_errors',
2132 + 'PHP error_log path',
2133 + 'PHP error_log readable',
2134 + )
2135 + );
2136 + }
2137 +
2138 + /**
2139 + * Get conflict signal rows.
2140 + *
2141 + * @return array<int,array<string,mixed>>
2142 + */
2143 + public static function get_conflict_signal_report_rows() {
2144 + $caching_plugins = static::get_active_plugins_by_keyword_group(
2145 + array(
2146 + 'cache',
2147 + 'rocket',
2148 + 'litespeed',
2149 + 'autoptimize',
2150 + 'wp-optimize',
2151 + 'perfmatters',
2152 + 'flyingpress',
2153 + 'sg optimizer',
2154 + 'breeze',
2155 + 'nitropack',
2156 + 'hummingbird',
2157 + )
2158 + );
2159 + $security_plugins = static::get_active_plugins_by_keyword_group(
2160 + array(
2161 + 'wordfence',
2162 + 'sucuri',
2163 + 'solid security',
2164 + 'ithemes security',
2165 + 'all-in-one wp security',
2166 + 'shield security',
2167 + 'disable rest api',
2168 + 'rest api control',
2169 + 'wp hide',
2170 + 'cloudflare',
2171 + 'limit login',
2172 + )
2173 + );
2174 +
2175 + $maintenance_mode = static::get_maintenance_mode_indicators();
2176 + $dropins = static::get_dropin_conflict_indicators();
2177 +
2178 + return self::add_export_labels_to_rows(
2179 + array(
2180 + array(
2181 + 'label' => esc_html__( 'Caching / performance plugins', 'mainwp' ),
2182 + 'value' => static::format_conflict_items_label( $caching_plugins ),
2183 + ),
2184 + array(
2185 + 'label' => esc_html__( 'Security / access-control plugins', 'mainwp' ),
2186 + 'value' => static::format_conflict_items_label( $security_plugins ),
2187 + ),
2188 + array(
2189 + 'label' => esc_html__( 'Maintenance mode indicators', 'mainwp' ),
2190 + 'value' => static::format_conflict_items_label( $maintenance_mode ),
2191 + 'status' => empty( $maintenance_mode ) ? '' : 'warning',
2192 + ),
2193 + array(
2194 + 'label' => esc_html__( 'Drop-ins / object cache', 'mainwp' ),
2195 + 'value' => static::format_conflict_items_label( $dropins ),
2196 + ),
2197 + ),
2198 + array(
2199 + 'Caching / performance plugins',
2200 + 'Security / access-control plugins',
2201 + 'Maintenance mode indicators',
2202 + 'Drop-ins / object cache',
2203 + )
2204 + );
2205 + }
2206 +
2207 +
2208 + /**
2209 + * Get database rows.
2210 + *
2211 + * @return array<int,array<string,mixed>>
2212 + */
2213 + public static function get_database_report_rows() { // phpcs:ignore -- NOSONAR - complex function.
2214 +
2215 + $db_info = MainWP_Database_Schema_Checker::get_database_info();
2216 +
2217 + $database_size = isset( $db_info['database_size'] ) ? $db_info['database_size'] : array();
2218 +
2219 + $data_size = isset( $database_size['data'] ) ? $database_size['data'] : 0;
2220 + $index_size = isset( $database_size['index'] ) ? $database_size['index'] : 0;
2221 +
2222 + $db_privileges_info = MainWP_Database_Schema_Checker::get_database_privileges();
2223 +
2224 + $db_privileges = ! empty( $db_privileges_info['database_grants'] ) && is_array( $db_privileges_info['database_grants'] ) ? implode( ', ', $db_privileges_info['database_grants'] ) . '.' : '';
2225 +
2226 + $db_privileges_status = 'pass';
2227 + if ( ! empty( $db_privileges_info['database_missing_privileges'] ) && is_array( $db_privileges_info['database_missing_privileges'] ) ) {
2228 + $db_privileges .= ' ' . esc_html__( 'Missing database privileges:', 'mainwp' ) . ' ' . implode( ', ', $db_privileges_info['database_missing_privileges'] );
2229 + $db_privileges_status = 'error';
2230 + }
2231 +
2232 + $db_rows_info = array(
2233 + array(
2234 + 'label' => esc_html__( 'MainWP database version', 'mainwp' ),
2235 + 'value' => $db_info['mainwp_database_version'],
2236 + ),
2237 + array(
2238 + 'label' => esc_html__( 'Database prefix', 'mainwp' ),
2239 + 'value' => $db_info['database_prefix'],
2240 + ),
2241 + array(
2242 + 'label' => esc_html__( 'Total Database Size', 'mainwp' ),
2243 + 'value' => esc_html( sprintf( __( '%sMB', 'mainwp' ), $data_size + $index_size ) ),
2244 + ),
2245 + array(
2246 + 'label' => esc_html__( 'Database Data Size', 'mainwp' ),
2247 + 'value' => esc_html( sprintf( __( '%sMB', 'mainwp' ), $data_size ) ),
2248 + ),
2249 + array(
2250 + 'label' => esc_html__( 'Database Index Size', 'mainwp' ),
2251 + 'value' => esc_html( sprintf( __( '%sMB', 'mainwp' ), $index_size ) ),
2252 + ),
2253 + array(
2254 + 'status' => $db_privileges_status,
2255 + 'label' => esc_html__( 'Database privileges', 'mainwp' ),
2256 + 'value' => $db_privileges,
2257 + ),
2258 + );
2259 +
2260 + $db_rows = array();
2261 + $db_rows_missing = array();
2262 +
2263 + if ( isset( $db_info['database_tables'] ) && is_array( $db_info['database_tables'] ) ) {
2264 +
2265 + $missing_db_tables = MainWP_Database_Schema_Checker::detect_missing_tables( $db_info['database_tables'] );
2266 +
2267 + if ( is_array( $missing_db_tables ) ) {
2268 + foreach ( array( 'core', 'extensions' ) as $type ) {
2269 + $miss_tables = isset( $missing_db_tables[ $type ] ) ? $missing_db_tables[ $type ] : array();
2270 + if ( ! empty( $miss_tables ) && is_array( $miss_tables ) ) {
2271 + if ( 'core' === $type ) {
2272 + foreach ( $miss_tables as $tb_name ) {
2273 + $db_rows_missing[] = array(
2274 + 'label' => $tb_name,
2275 + 'value' => esc_html__( 'Missing core table', 'mainwp' ),
2276 + 'status' => 'error',
2277 + );
2278 + }
2279 + } else {
2280 + foreach ( $miss_tables as $ext_slug => $miss_ext_tables ) {
2281 + $title = MainWP_Database_Schema_Checker::get_loaded_extension_title( $ext_slug );
2282 + foreach ( $miss_ext_tables as $tb_name ) {
2283 + $db_rows_missing[] = array(
2284 + 'label' => $tb_name,
2285 + 'value' => sprintf( esc_html__( 'Missing extension table: %1s', 'mainwp' ), $title ),
2286 + 'status' => 'error',
2287 + );
2288 + }
2289 + }
2290 + }
2291 + }
2292 + }
2293 + }
2294 +
2295 + foreach ( array( 'core', 'other' ) as $type ) {
2296 + $type_tables = isset( $db_info['database_tables'][ $type ] ) ? $db_info['database_tables'][ $type ] : array();
2297 + if ( is_array( $type_tables ) ) {
2298 + foreach ( $type_tables as $tb_name => $info ) {
2299 +
2300 + if ( empty( $info ) ) {
2301 + continue; // Missing table, so skip column detection.
2302 + }
2303 +
2304 + $status = 'pass';
2305 +
2306 + $detect_cols_issues = array();
2307 +
2308 + /**
2309 + * Filter to disable detection of missing table columns. Useful for slow hosts.
2310 + *
2311 + * @since 6.1.3.
2312 + */
2313 + if ( apply_filters( 'mainwp_detect_table_column_issues', true ) ) {
2314 + $detect_cols_issues = MainWP_Database_Schema_Checker::detect_table_columns_issues( $tb_name, $type );
2315 + }
2316 +
2317 + $missing_cols = is_array( $detect_cols_issues ) && isset( $detect_cols_issues['missing_columns'] ) ? $detect_cols_issues['missing_columns'] : array();
2318 + $invalid_cols = is_array( $detect_cols_issues ) && isset( $detect_cols_issues['invalid_columns'] ) ? $detect_cols_issues['invalid_columns'] : array();
2319 +
2320 + $issues_cols_info = array();
2321 +
2322 + if ( ! empty( $missing_cols ) && is_array( $missing_cols ) ) {
2323 + $issues_cols_info[] = sprintf( esc_html__( 'Missing columns: %1s;', 'mainwp' ), implode( ', ', $missing_cols ) );
2324 + $status = 'error';
2325 + }
2326 +
2327 + if ( ! empty( $invalid_cols ) && is_array( $invalid_cols ) && isset( $invalid_cols[0]['column'] ) ) {
2328 +
2329 + $issues_string = implode(
2330 + '; ',
2331 + array_map(
2332 + static function ( $issue ) {
2333 + return sprintf(
2334 + 'column: "%s" - expected: "%s" - actual: "%s"',
2335 + $issue['column'],
2336 + $issue['expected'],
2337 + $issue['actual']
2338 + );
2339 + },
2340 + $invalid_cols
2341 + )
2342 + );
2343 +
2344 + $issues_cols_info[] = sprintf(
2345 + esc_html__( 'Incorrect column definitions found: %s;', 'mainwp' ),
2346 + $issues_string
2347 + );
2348 +
2349 + if ( 'pass' === $status ) {
2350 + $status = 'error'; // warning - incorrect column definition.
2351 + }
2352 + }
2353 +
2354 + $tbl_info = '';
2355 + if ( is_array( $info ) && isset( $info['data'] ) ) {
2356 + $tbl_info = sprintf( __( 'Data: %sMB + Index: %sMB + Engine %s', 'mainwp' ), $info['data'], $info['index'], $info['engine'] );
2357 + }
2358 +
2359 + $db_rows[] = array(
2360 + 'label' => esc_html( $tb_name ),
2361 + 'value' => esc_html(
2362 + $tbl_info . ( ! empty( $issues_cols_info ) ? ' (' . implode( '; ', $issues_cols_info ) . ') ' : '' ),
2363 + ),
2364 + 'status' => $status,
2365 + );
2366 +
2367 + }
2368 + }
2369 + }
2370 +
2371 + MainWP_Database_Schema_Checker::prepare_db_and_tables_issues( $missing_db_tables );
2372 + }
2373 +
2374 + return self::add_export_labels_to_rows(
2375 + array_merge( $db_rows_info, $db_rows_missing, $db_rows ),
2376 + array(
2377 + 'Database',
2378 + 'Database privileges',
2379 + 'MainWP database version',
2380 + 'Database prefix',
2381 + 'Total Database Size',
2382 + 'Database Data Size',
2383 + 'Database Index Size',
2384 + 'Missing core table',
2385 + )
2386 + );
2387 + }
2388 +
2389 +
2390 + /**
2391 + * Format boolean label.
2392 + *
2393 + * @param mixed $value True-ish value.
2394 + *
2395 + * @return string
2396 + */
2397 + private static function format_boolean_label( $value ) {
2398 + return ! empty( $value ) ? esc_html__( 'Yes', 'mainwp' ) : esc_html__( 'No', 'mainwp' );
2399 + }
2400 +
2401 + /**
2402 + * Get timezone label.
2403 + *
2404 + * @return string
2405 + */
2406 + private static function get_timezone_label() {
2407 + $timezone = wp_timezone_string();
2408 + if ( ! empty( $timezone ) ) {
2409 + return $timezone;
2410 + }
2411 +
2412 + $gmt_offset = (float) get_option( 'gmt_offset', 0 );
2413 + $tz_sign = $gmt_offset >= 0 ? '+' : '-';
2414 + $tz_value = (string) abs( $gmt_offset );
2415 +
2416 + return sprintf( 'UTC%s%s', $tz_sign, $tz_value );
2417 + }
2418 +
2419 + /**
2420 + * Get trusted update mode label.
2421 + *
2422 + * @param mixed $value Setting value.
2423 + *
2424 + * @return string
2425 + */
2426 + private static function get_trusted_update_mode_label( $value ) {
2427 + return 1 === (int) $value ? esc_html__( 'Install Trusted Updates', 'mainwp' ) : esc_html__( 'Disabled', 'mainwp' );
2428 + }
2429 +
2430 + /**
2431 + * Get archive format label.
2432 + *
2433 + * @param mixed $format Archive format.
2434 + *
2435 + * @return string
2436 + */
2437 + private static function format_archive_format_label( $format ) {
2438 + $format = empty( $format ) ? 'tar.gz' : (string) $format;
2439 + return $format;
2440 + }
2441 +
2442 + /**
2443 + * Get delay label.
2444 + *
2445 + * @param int $days Days.
2446 + *
2447 + * @return string
2448 + */
2449 + private static function format_delay_label( $days ) {
2450 + if ( $days <= 0 ) {
2451 + return esc_html__( 'Delay off', 'mainwp' );
2452 + }
2453 +
2454 + return sprintf(
2455 + /* translators: %d: day count */
2456 + _n( '%d day', '%d days', $days, 'mainwp' ),
2457 + $days
2458 + );
2459 + }
2460 +
2461 + /**
2462 + * Get automatic update day label.
2463 + *
2464 + * @param string $frequency Frequency.
2465 + *
2466 + * @return string
2467 + */
2468 + private static function get_automatic_updates_day_label( $frequency ) {
2469 + switch ( $frequency ) {
2470 + case 'weekly':
2471 + $days = array(
2472 + 0 => esc_html__( 'Mon', 'mainwp' ),
2473 + 1 => esc_html__( 'Tue', 'mainwp' ),
2474 + 2 => esc_html__( 'Wed', 'mainwp' ),
2475 + 3 => esc_html__( 'Thu', 'mainwp' ),
2476 + 4 => esc_html__( 'Fri', 'mainwp' ),
2477 + 5 => esc_html__( 'Sat', 'mainwp' ),
2478 + 6 => esc_html__( 'Sun', 'mainwp' ),
2479 + );
2480 + $day = (int) get_option( 'mainwp_dayinweek_AutoUpdate', 0 );
2481 + return isset( $days[ $day ] ) ? $days[ $day ] : esc_html__( 'Mon', 'mainwp' );
2482 + case 'monthly':
2483 + return sprintf(
2484 + /* translators: %d: day of month */
2485 + esc_html__( 'Day %d of the month', 'mainwp' ),
2486 + (int) get_option( 'mainwp_dayinmonth_AutoUpdate', 1 )
2487 + );
2488 + default:
2489 + return esc_html__( 'Every day', 'mainwp' );
2490 + }
2491 + }
2492 +
2493 + /**
2494 + * Get automatic updates schedule label.
2495 + *
2496 + * @return string
2497 + */
2498 + private static function get_automatic_updates_schedule_label() {
2499 + $frequency = (string) get_option( 'mainwp_frequency_AutoUpdate', 'daily' );
2500 + $time = (string) get_option( 'mainwp_time_AutoUpdate', '00:00' );
2501 + if ( empty( $time ) ) {
2502 + $time = '00:00';
2503 + }
2504 +
2505 + if ( 'weekly' === $frequency ) {
2506 + return sprintf(
2507 + /* translators: 1: day label, 2: time */
2508 + esc_html__( 'Weekly on %1$s at %2$s', 'mainwp' ),
2509 + static::get_automatic_updates_day_label( 'weekly' ),
2510 + $time
2511 + );
2512 + }
2513 +
2514 + if ( 'monthly' === $frequency ) {
2515 + return sprintf(
2516 + /* translators: 1: day label, 2: time */
2517 + esc_html__( 'Monthly on %1$s at %2$s', 'mainwp' ),
2518 + static::get_automatic_updates_day_label( 'monthly' ),
2519 + $time
2520 + );
2521 + }
2522 +
2523 + return sprintf(
2524 + /* translators: %s: time */
2525 + esc_html__( 'Daily at %s', 'mainwp' ),
2526 + $time
2527 + );
2528 + }
2529 +
2530 + /**
2531 + * Count recipients.
2532 + *
2533 + * @param string $recipients Recipients string.
2534 + *
2535 + * @return int
2536 + */
2537 + private static function count_recipients( $recipients ) {
2538 + if ( empty( $recipients ) ) {
2539 + return 0;
2540 + }
2541 +
2542 + $emails = preg_split( '/\s*,\s*/', trim( $recipients ) );
2543 + $emails = array_filter( (array) $emails );
2544 +
2545 + return count( $emails );
2546 + }
2547 +
2548 + /**
2549 + * Get public dashboard IP data.
2550 + *
2551 + * @return array<string,string>
2552 + */
2553 + private static function get_public_dashboard_ip_data() {
2554 + $server_ip = static::get_server_ip_value();
2555 +
2556 + if ( static::is_public_ip_address( $server_ip ) ) {
2557 + return array(
2558 + 'value' => $server_ip,
2559 + 'status' => 'pass',
2560 + 'community_value' => esc_html__( 'Detected', 'mainwp' ),
2561 + );
2562 + }
2563 +
2564 + $cached_data = get_transient( 'mainwp_public_dashboard_ip_data' );
2565 + if ( is_array( $cached_data ) && isset( $cached_data['value'], $cached_data['status'], $cached_data['community_value'] ) ) {
2566 + return $cached_data;
2567 + }
2568 +
2569 + $response = wp_safe_remote_get(
2570 + 'https://api.ipify.org?format=json',
2571 + array(
2572 + 'timeout' => 3,
2573 + 'sslverify' => true,
2574 + )
2575 + );
2576 +
2577 + if ( ! is_wp_error( $response ) ) {
2578 + $response_code = (int) wp_remote_retrieve_response_code( $response );
2579 + $body = json_decode( (string) wp_remote_retrieve_body( $response ), true );
2580 + $public_ip = is_array( $body ) && isset( $body['ip'] ) ? trim( (string) $body['ip'] ) : '';
2581 +
2582 + if ( $response_code >= 200 && $response_code < 300 && static::is_public_ip_address( $public_ip ) ) {
2583 + $data = array(
2584 + 'value' => $public_ip,
2585 + 'status' => 'pass',
2586 + 'community_value' => esc_html__( 'Detected', 'mainwp' ),
2587 + );
2588 + set_transient( 'mainwp_public_dashboard_ip_data', $data, 12 * HOUR_IN_SECONDS );
2589 +
2590 + return $data;
2591 + }
2592 + }
2593 +
2594 + $data = array(
2595 + 'value' => esc_html__( 'Unavailable. Contact your host if the Server IP is local or private.', 'mainwp' ),
2596 + 'status' => 'warning',
2597 + 'community_value' => esc_html__( 'Unavailable', 'mainwp' ),
2598 + );
2599 + set_transient( 'mainwp_public_dashboard_ip_data', $data, HOUR_IN_SECONDS );
2600 +
2601 + return $data;
2602 + }
2603 +
2604 + /**
2605 + * Get server IP value.
2606 + *
2607 + * @return string
2608 + */
2609 + private static function get_server_ip_value() {
2610 + return isset( $_SERVER['SERVER_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['SERVER_ADDR'] ) ) : '';
2611 + }
2612 +
2613 + /**
2614 + * Check if IP address is public.
2615 + *
2616 + * @param string $ip_address IP address.
2617 + *
2618 + * @return bool
2619 + */
2620 + private static function is_public_ip_address( $ip_address ) {
2621 + return ! empty( $ip_address ) && false !== filter_var( $ip_address, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE );
2622 + }
2623 +
2624 + /**
2625 + * Get active plugins matching a keyword group.
2626 + *
2627 + * @param array<int,string> $keywords Keywords.
2628 + *
2629 + * @return array<int,string>
2630 + */
2631 + private static function get_active_plugins_by_keyword_group( $keywords ) {
2632 + $matches = array();
2633 + $plugins = get_plugins();
2634 +
2635 + foreach ( $plugins as $slug => $plugin ) {
2636 + if ( ! is_plugin_active( $slug ) ) {
2637 + continue;
2638 + }
2639 +
2640 + $plugin_name = isset( $plugin['Name'] ) ? (string) $plugin['Name'] : '';
2641 + $haystack = strtolower( $slug . ' ' . $plugin_name );
2642 +
2643 + if ( false !== strpos( $haystack, 'mainwp' ) ) {
2644 + continue;
2645 + }
2646 +
2647 + foreach ( $keywords as $keyword ) {
2648 + if ( false !== strpos( $haystack, strtolower( $keyword ) ) ) {
2649 + $matches[] = ! empty( $plugin_name ) ? $plugin_name : $slug;
2650 + break;
2651 + }
2652 + }
2653 + }
2654 +
2655 + return array_values( array_unique( $matches ) );
2656 + }
2657 +
2658 + /**
2659 + * Get maintenance mode indicators.
2660 + *
2661 + * @return array<int,string>
2662 + */
2663 + private static function get_maintenance_mode_indicators() {
2664 + $indicators = static::get_active_plugins_by_keyword_group(
2665 + array(
2666 + 'maintenance',
2667 + 'coming soon',
2668 + 'seedprod',
2669 + 'lightstart',
2670 + )
2671 + );
2672 +
2673 + if ( file_exists( ABSPATH . '.maintenance' ) ) {
2674 + $indicators[] = esc_html__( '.maintenance file present', 'mainwp' );
2675 + }
2676 +
2677 + return array_values( array_unique( $indicators ) );
2678 + }
2679 +
2680 + /**
2681 + * Get drop-in conflict indicators.
2682 + *
2683 + * @return array<int,string>
2684 + */
2685 + private static function get_dropin_conflict_indicators() {
2686 + $dropins = array();
2687 +
2688 + if ( function_exists( 'get_dropins' ) ) {
2689 + $dropin_files = get_dropins();
2690 + if ( is_array( $dropin_files ) ) {
2691 + $dropins = array_keys( $dropin_files );
2692 + }
2693 + }
2694 +
2695 + if ( wp_using_ext_object_cache() && ! in_array( 'object-cache.php', $dropins, true ) ) {
2696 + $dropins[] = 'object-cache.php';
2697 + }
2698 +
2699 + return array_values( array_unique( $dropins ) );
2700 + }
2701 +
2702 + /**
2703 + * Format conflict items label.
2704 + *
2705 + * @param array<int,string> $items Items.
2706 + *
2707 + * @return string
2708 + */
2709 + private static function format_conflict_items_label( $items ) {
2710 + if ( empty( $items ) ) {
2711 + return esc_html__( 'None detected', 'mainwp' );
2712 + }
2713 +
2714 + return implode( ', ', $items );
2715 + }
2716 +
2717 + /**
2718 + * Get permalink structure data.
2719 + *
2720 + * @return array<string,string>
2721 + */
2722 + private static function get_permalink_structure_data() {
2723 + $structure = (string) get_option( 'permalink_structure', '' );
2724 +
2725 + if ( empty( $structure ) ) {
2726 + return array(
2727 + 'value' => esc_html__( 'Plain', 'mainwp' ),
2728 + 'status' => 'warning',
2729 + );
2730 + }
2731 +
2732 + return array(
2733 + 'value' => $structure,
2734 + 'status' => 'pass',
2735 + );
2736 + }
2737 +
2738 + /**
2739 + * Get REST API reachability data.
2740 + *
2741 + * @return array<string,string>
2742 + */
2743 + private static function get_rest_api_reachability_data() {
2744 + static $cached_data = null;
2745 + if ( null !== $cached_data ) {
2746 + return $cached_data;
2747 + }
2748 +
2749 + $url = rest_url();
2750 + $response = wp_remote_get(
2751 + esc_url_raw( $url ),
2752 + array(
2753 + 'blocking' => true,
2754 + 'sslverify' => apply_filters( 'https_local_ssl_verify', true ),
2755 + 'timeout' => 15,
2756 + )
2757 + );
2758 +
2759 + if ( is_wp_error( $response ) ) {
2760 + $cached_data = array(
2761 + 'value' => sprintf(
2762 + /* translators: %s: error message */
2763 + esc_html__( 'Request failed: %s', 'mainwp' ),
2764 + $response->get_error_message()
2765 + ),
2766 + 'status' => 'error',
2767 + 'code' => 'request_failed',
2768 + );
2769 + return $cached_data;
2770 + }
2771 +
2772 + $response_code = (int) wp_remote_retrieve_response_code( $response );
2773 + $body = wp_remote_retrieve_body( $response );
2774 + $data = json_decode( $body, true );
2775 +
2776 + if ( $response_code >= 200 && $response_code < 300 && is_array( $data ) && isset( $data['namespaces'] ) ) {
2777 + $cached_data = array(
2778 + 'value' => sprintf(
2779 + /* translators: %d: HTTP status code */
2780 + esc_html__( 'Reachable (HTTP %d)', 'mainwp' ),
2781 + $response_code
2782 + ),
2783 + 'status' => 'pass',
2784 + );
2785 + return $cached_data;
2786 + }
2787 +
2788 + if ( $response_code >= 200 && $response_code < 300 ) {
2789 + $cached_data = array(
2790 + 'value' => sprintf(
2791 + /* translators: %d: HTTP status code */
2792 + esc_html__( 'Unexpected non-REST response (HTTP %d)', 'mainwp' ),
2793 + $response_code
2794 + ),
2795 + 'status' => 'warning',
2796 + );
2797 + return $cached_data;
2798 + }
2799 +
2800 + if ( 401 === $response_code ) {
2801 + $cached_data = array(
2802 + 'value' => esc_html__( 'Auth challenge detected (HTTP 401)', 'mainwp' ),
2803 + 'status' => 'error',
2804 + );
2805 + return $cached_data;
2806 + }
2807 +
2808 + if ( 403 === $response_code ) {
2809 + $cached_data = array(
2810 + 'value' => esc_html__( 'Forbidden or blocked (HTTP 403)', 'mainwp' ),
2811 + 'status' => 'error',
2812 + );
2813 + return $cached_data;
2814 + }
2815 +
2816 + if ( 404 === $response_code ) {
2817 + $cached_data = array(
2818 + 'value' => esc_html__( 'Not found (HTTP 404)', 'mainwp' ),
2819 + 'status' => 'error',
2820 + );
2821 + return $cached_data;
2822 + }
2823 +
2824 + $cached_data = array(
2825 + 'value' => sprintf(
2826 + /* translators: %d: HTTP status code */
2827 + esc_html__( 'Unexpected response (HTTP %d)', 'mainwp' ),
2828 + $response_code
2829 + ),
2830 + 'status' => 'warning',
2831 + );
2832 +
2833 + return $cached_data;
2834 + }
2835 +
2836 + /**
2837 + * Get self-connect data.
2838 + *
2839 + * @return array<string,string>
2840 + */
2841 + private static function get_server_self_connect_data() {
2842 + static $cached_data = null;
2843 + if ( null !== $cached_data ) {
2844 + return $cached_data;
2845 + }
2846 +
2847 + $url = admin_url( 'admin-ajax.php' );
2848 +
2849 + $response = MainWP_System_Utility::test_self_connect( $url );
2850 +
2851 + if ( is_wp_error( $response ) ) {
2852 + $cached_data = array(
2853 + 'value' => sprintf(
2854 + /* translators: %s: error message */
2855 + esc_html__( 'Request failed: %s', 'mainwp' ),
2856 + $response->get_error_message()
2857 + ),
2858 + 'status' => 'error',
2859 + );
2860 + return $cached_data;
2861 + }
2862 +
2863 + $response_code = (int) wp_remote_retrieve_response_code( $response );
2864 + if ( 401 === $response_code ) {
2865 + $cached_data = array(
2866 + 'value' => esc_html__( 'Auth challenge detected (HTTP 401)', 'mainwp' ),
2867 + 'status' => 'error',
2868 + 'code' => 'auth_challenge',
2869 + );
2870 + return $cached_data;
2871 + }
2872 + if ( 403 === $response_code ) {
2873 + $cached_data = array(
2874 + 'value' => esc_html__( 'Forbidden or blocked (HTTP 403)', 'mainwp' ),
2875 + 'status' => 'error',
2876 + 'code' => 'forbidden',
2877 + );
2878 + return $cached_data;
2879 + }
2880 + if ( $response_code < 200 || $response_code > 204 ) {
2881 + $cached_data = array(
2882 + 'value' => sprintf(
2883 + /* translators: %d: HTTP status code */
2884 + esc_html__( 'Unexpected response (HTTP %d)', 'mainwp' ),
2885 + $response_code
2886 + ),
2887 + 'status' => 'warning',
2888 + 'code' => 'unexpected_status',
2889 + );
2890 + return $cached_data;
2891 + }
2892 +
2893 + $response_body = wp_remote_retrieve_body( $response );
2894 + if ( 'MainWP Self Connect OK' !== trim( $response_body ) ) {
2895 + $cached_data = array(
2896 + 'value' => esc_html__( 'Unexpected response body. Note: This is common and usually not a problem unless WP-Cron or loopback requests are failing.', 'mainwp' ),
2897 + 'status' => 'warning',
2898 + 'code' => 'unexpected_body',
2899 + );
2900 + return $cached_data;
2901 + }
2902 +
2903 + $cached_data = array(
2904 + 'value' => sprintf(
2905 + /* translators: %d: HTTP status code */
2906 + esc_html__( 'Response test O.K. (HTTP %d)', 'mainwp' ),
2907 + $response_code
2908 + ),
2909 + 'status' => 'pass',
2910 + 'code' => 'pass',
2911 + );
2912 +
2913 + return $cached_data;
2914 + }
2915 +
2916 + /**
2917 + * Get upload directory data.
2918 + *
2919 + * @return array<string,string>
2920 + */
2921 + private static function get_mainwp_upload_directory_data() {
2922 + $dirs = MainWP_System_Utility::get_mainwp_dir();
2923 + $path = isset( $dirs[0] ) ? $dirs[0] : '';
2924 +
2925 + if ( empty( $path ) || ! is_dir( dirname( $path ) ) || ! is_dir( $path ) ) {
2926 + return array(
2927 + 'value' => esc_html__( 'Not found', 'mainwp' ),
2928 + 'status' => 'error',
2929 + );
2930 + }
2931 +
2932 + if ( is_writable( $path ) ) {
2933 + return array(
2934 + 'value' => esc_html__( 'Writable', 'mainwp' ),
2935 + 'status' => 'pass',
2936 + );
2937 + }
2938 +
2939 + return array(
2940 + 'value' => esc_html__( 'Not writable', 'mainwp' ),
2941 + 'status' => 'error',
2942 + );
2943 + }
2944 +
2945 + /**
2946 + * Get primary backup method label.
2947 + *
2948 + * @return string
2949 + */
2950 + private static function get_primary_backup_method_label() {
2951 + $primary_backup = get_option( 'mainwp_primaryBackup' );
2952 + $primary_methods = apply_filters_deprecated( 'mainwp-getprimarybackup-methods', array( array() ), '4.0.7.2', 'mainwp_getprimarybackup_methods' ); // NOSONAR - not IP.
2953 + $primary_methods = apply_filters( 'mainwp_getprimarybackup_methods', $primary_methods );
2954 +
2955 + if ( is_array( $primary_methods ) ) {
2956 + foreach ( $primary_methods as $method ) {
2957 + if ( isset( $method['value'], $method['title'] ) && $primary_backup === $method['value'] ) {
2958 + return (string) $method['title'];
2959 + }
2960 + }
2961 + }
2962 +
2963 + return esc_html__( 'Native backups', 'mainwp' );
2964 + }
2965 +
2966 + /**
2967 + * Get signature algorithm label.
2968 + *
2969 + * @return string
2970 + */
2971 + private static function get_signature_algorithm_label() {
2972 + $default_setting = MainWP_Settings_Indicator::get_defaults_value();
2973 + $sign_algs = MainWP_System_Utility::get_open_ssl_sign_algos();
2974 + $signature_algo = (int) get_option( 'mainwp_connect_signature_algo', $default_setting['mainwp_connect_signature_algo'] );
2975 +
2976 + return isset( $sign_algs[ $signature_algo ] ) ? $sign_algs[ $signature_algo ] : (string) $signature_algo;
2977 + }
2978 +
2979 + /**
2980 + * Get cron job summary.
2981 + *
2982 + * @param string $last_run_option Last run option name.
2983 + * @param string $hook Cron hook.
2984 + * @param string $fallback_freq Fallback frequency.
2985 + *
2986 + * @return array<string,string>
2987 + */
2988 + private static function get_cron_job_summary( $last_run_option, $hook, $fallback_freq ) {
2989 + $local_timestamp = MainWP_Utility::get_timestamp();
2990 + $use_wp_cron = ( false === get_option( 'mainwp_wp_cron' ) ) || ( 1 === (int) get_option( 'mainwp_wp_cron', 1 ) );
2991 +
2992 + if ( 'mainwp_updatescheck_start_last_timestamp' === $last_run_option ) {
2993 + $update_time = MainWP_Settings::get_websites_automatic_update_time();
2994 + return array(
2995 + 'last' => isset( $update_time['last'] ) ? $update_time['last'] : esc_html__( 'Never', 'mainwp' ),
2996 + 'next' => isset( $update_time['next'] ) ? $update_time['next'] : esc_html__( 'Unknown', 'mainwp' ),
2997 + );
2998 + }
2999 +
3000 + $lasttime_run = get_option( $last_run_option );
3001 + if ( false === $lasttime_run || empty( $lasttime_run ) ) {
3002 + $last_run = esc_html__( 'Never', 'mainwp' );
3003 + } elseif ( 'mainwp_uptimecheck_auto_main_counter_lasttime_started' === $last_run_option ) {
3004 + $last_run = MainWP_Utility::format_timestamp( $lasttime_run );
3005 + } else {
3006 + $last_run = MainWP_Utility::format_timestamp( MainWP_Utility::get_timestamp( $lasttime_run ) );
3007 + }
3008 +
3009 + $next_run = '';
3010 + if ( $use_wp_cron ) {
3011 + $scheduled = wp_next_scheduled( $hook );
3012 + if ( ! empty( $scheduled ) ) {
3013 + $next_run = MainWP_Utility::format_timestamp( MainWP_Utility::get_timestamp( $scheduled ) );
3014 + }
3015 + }
3016 +
3017 + if ( empty( $next_run ) && ! empty( $fallback_freq ) ) {
3018 + $nexttime_run = MainWP_Server_Information::get_schedule_next_time_to_show( $fallback_freq, is_numeric( $lasttime_run ) ? (int) $lasttime_run : 0, $local_timestamp );
3019 + if ( $nexttime_run < $local_timestamp + 3 * MINUTE_IN_SECONDS ) {
3020 + $next_run = esc_html__( 'Any minute', 'mainwp' );
3021 + } else {
3022 + $next_run = MainWP_Utility::format_timestamp( MainWP_Utility::get_timestamp( $nexttime_run ) );
3023 + }
3024 + }
3025 +
3026 + if ( empty( $next_run ) ) {
3027 + $next_run = esc_html__( 'Unknown', 'mainwp' );
3028 + }
3029 +
3030 + return array(
3031 + 'last' => $last_run,
3032 + 'next' => $next_run,
3033 + );
3034 + }
3035 +
3036 + /**
3037 + * Get uptime monitoring summary row.
3038 + *
3039 + * @return array<string,string>|array<mixed>
3040 + */
3041 + private static function get_uptime_monitoring_summary() {
3042 + $global = MainWP_Uptime_Monitoring_Handle::get_global_monitoring_settings();
3043 + if ( empty( $global['active'] ) && ! get_option( 'mainwp_individual_uptime_monitoring_schedule_enabled' ) ) {
3044 + return array();
3045 + }
3046 +
3047 + $summary = static::get_cron_job_summary( 'mainwp_uptimecheck_auto_main_counter_lasttime_started', 'mainwp_cronuptimemonitoringcheck_action', 'minutely' );
3048 +
3049 + return array(
3050 + 'label' => esc_html__( 'Uptime monitoring schedule', 'mainwp' ),
3051 + 'value' => sprintf(
3052 + /* translators: 1: last run, 2: next run */
3053 + esc_html__( 'Last run: %1$s | Next run: %2$s', 'mainwp' ),
3054 + $summary['last'],
3055 + $summary['next']
3056 + ),
3057 + );
3058 + }
3059 +
3060 + /**
3061 + * Format retention label from days.
3062 + *
3063 + * @param int $days Days.
3064 + *
3065 + * @return string
3066 + */
3067 + private static function format_retention_days_label( $days ) {
3068 + if ( $days <= 0 ) {
3069 + return esc_html__( 'Keep forever', 'mainwp' );
3070 + }
3071 +
3072 + return sprintf(
3073 + /* translators: %d: days */
3074 + _n( '%d day', '%d days', $days, 'mainwp' ),
3075 + $days
3076 + );
3077 + }
3078 +
3079 + /**
3080 + * Format monitoring type label.
3081 + *
3082 + * @param string $type Monitor type.
3083 + *
3084 + * @return string
3085 + */
3086 + private static function format_monitor_type_label( $type ) {
3087 + switch ( $type ) {
3088 + case 'ping':
3089 + return esc_html__( 'Ping', 'mainwp' );
3090 + case 'keyword':
3091 + return esc_html__( 'Keyword Monitoring', 'mainwp' );
3092 + default:
3093 + return esc_html__( 'HTTP(s)', 'mainwp' );
3094 + }
3095 + }
3096 +
3097 + /**
3098 + * Format log retention label.
3099 + *
3100 + * @param int $seconds Retention in seconds.
3101 + *
3102 + * @return string
3103 + */
3104 + private static function format_log_retention_label( $seconds ) {
3105 + if ( $seconds <= 0 ) {
3106 + return esc_html__( 'Forever', 'mainwp' );
3107 + }
3108 + if ( 3 * YEAR_IN_SECONDS === $seconds ) {
3109 + return esc_html__( 'Three years', 'mainwp' );
3110 + }
3111 + if ( 2 * YEAR_IN_SECONDS === $seconds ) {
3112 + return esc_html__( 'Two years', 'mainwp' );
3113 + }
3114 + if ( YEAR_IN_SECONDS === $seconds ) {
3115 + return esc_html__( 'Year', 'mainwp' );
3116 + }
3117 + if ( 6 * MONTH_IN_SECONDS === $seconds ) {
3118 + return esc_html__( 'Half a year', 'mainwp' );
3119 + }
3120 + if ( 3 * MONTH_IN_SECONDS === $seconds ) {
3121 + return esc_html__( 'Three months', 'mainwp' );
3122 + }
3123 + if ( 2 * MONTH_IN_SECONDS === $seconds ) {
3124 + return esc_html__( 'Two months', 'mainwp' );
3125 + }
3126 + if ( MONTH_IN_SECONDS === $seconds ) {
3127 + return esc_html__( 'One month', 'mainwp' );
3128 + }
3129 +
3130 + return sprintf(
3131 + /* translators: %d: days */
3132 + _n( '%d day', '%d days', max( 1, (int) floor( $seconds / DAY_IN_SECONDS ) ), 'mainwp' ),
3133 + max( 1, (int) floor( $seconds / DAY_IN_SECONDS ) )
3134 + );
960 3135 }
961 3136 }