PluginProbe
MainWP Dashboard: Self-hosted WordPress Management for Agencies / 6.2.2
MainWP Dashboard: Self-hosted WordPress Management for Agencies v6.2.2
6.2.2 6.2.1 6.2 6.1.8 6.1.7 6.1.6 6.1.5 6.1.4 6.1.3 6.1.2 6.1.1 6.1 6.0.12 6.0.11 4.6.0.1 5.0 5.0.1 5.0.2 5.0.3 5.0.3.1 5.0.3.2 5.1 5.1.1 5.2 5.2.1 All 155 releases
← All changes | class/class-mainwp-utility.php +335 -17 6.1.5 → 6.2.2 View file →
@@ -21,8 +21,26 @@
21 21 */
22 22 class MainWP_Utility { // phpcs:ignore Generic.Classes.OpeningBraceSameLine.ContentAfterBrace -- NOSONAR.
23 23
24 24 /**
25 + * Prefix for short-term notice options.
26 + */
27 + const SHORT_TERM_NOTICE_OPTION_PREFIX = '_mainwp_temp_notice_';
28 +
29 +
30 + /**
31 + * Prefix for per-user short-term notice options.
32 + */
33 + const USER_SHORT_TERM_NOTICE_OPTION_PREFIX = '_mainwp_user_temp_notice_';
34 +
35 +
36 + /**
37 + * New short term notice TTL.
38 + */
39 + const SHORT_TERM_NOTICE_TTL = MONTH_IN_SECONDS;
40 +
41 +
42 + /**
25 43 * Yoast SEO is enabled return true else return null.
26 44 *
27 45 * @static
28 46 * @var boolean $enabled_wp_seo If Yoast SEO is enabled return true else return null.
@@ -115,18 +133,17 @@
115 133 return substr( $haystack, - $length ) === $needle;
116 134 }
117 135
118 136 /**
119 - * Method get_nice_url()
137 + * Get a nice URL.
120 138 *
121 - * Grab url.
139 + * @param string $pUrl Website URL.
140 + * @param bool $showHttp Whether to show HTTP.
141 + * @param bool $removeTrailingSlash Whether to removev the trailing slash.
122 142 *
123 - * @param string $pUrl Website URL.
124 - * @param bool $showHttp Show HTTP.
125 - *
126 - * @return string $url.
143 + * @return string The formatted URL.
127 144 */
128 - public static function get_nice_url( $pUrl, $showHttp = false ) {
145 + public static function get_nice_url( $pUrl, $showHttp = false, $removeTrailingSlash = false ) {
129 146 $url = $pUrl;
130 147
131 148 if ( static::starts_with( $url, 'http://' ) ) {
132 149 if ( ! $showHttp ) {
@@ -131,14 +148,14 @@
131 148 if ( static::starts_with( $url, 'http://' ) ) {
132 149 if ( ! $showHttp ) {
133 150 $url = substr( $url, 7 );
134 151 }
135 - } elseif ( static::starts_with( $pUrl, 'https://' ) ) {
152 + } elseif ( static::starts_with( $url, 'https://' ) ) {
136 153 if ( ! $showHttp ) {
137 154 $url = substr( $url, 8 );
138 155 }
139 156 } elseif ( $showHttp ) {
140 - $url = 'http://' . $url;
157 + $url = 'http://' . $url; // phpcs:ignore -- NOSONAR -compatible.
141 158 }
142 159
143 160 if ( static::ends_with( $url, '/' ) ) {
144 161 if ( ! $showHttp ) {
@@ -144,11 +161,15 @@
144 161 if ( ! $showHttp ) {
145 162 $url = substr( $url, 0, strlen( $url ) - 1 );
146 163 }
147 164 } else {
148 - $url = $url . '/';
165 + $url .= '/';
149 166 }
150 167
168 + if ( $removeTrailingSlash ) {
169 + $url = rtrim( $url, '/' );
170 + }
171 +
151 172 return $url;
152 173 }
153 174
154 175 /**
@@ -862,8 +883,22 @@
862 883 return false;
863 884 }
864 885
865 886 /**
887 + * Method delete_user_option()
888 + *
889 + * @param string $option_name Option name.
890 + *
891 + * @return void.
892 + */
893 + public static function delete_user_option( $option_name ) {
894 + $user = wp_get_current_user();
895 + if ( $user ) {
896 + delete_user_option( $user->ID, $option_name );
897 + }
898 + }
899 +
900 + /**
866 901 * Method remove_preslash_spaces()
867 902 *
868 903 * Remove spaces before slashes.
869 904 *
@@ -1189,8 +1224,38 @@
1189 1224 return true;
1190 1225 }
1191 1226
1192 1227 /**
1228 + * Un-hide a MainWP message for the current user.
1229 + *
1230 + * Removes the notice ID from the saved notice status so the message
1231 + * can be displayed again.
1232 + *
1233 + * @param mixed $notice_id Notice ID.
1234 + *
1235 + * @return bool True if the notice was un-hidden, otherwise false.
1236 + */
1237 + public static function unhide_mainwp_message( $notice_id ) {
1238 + $status = get_user_option( 'mainwp_notice_saved_status' );
1239 +
1240 + if ( ! is_array( $status ) || ! isset( $status[ $notice_id ] ) ) {
1241 + return false;
1242 + }
1243 +
1244 + unset( $status[ $notice_id ] );
1245 +
1246 + if ( empty( $status ) ) {
1247 + return delete_user_option( get_current_user_id(), 'mainwp_notice_saved_status' );
1248 + }
1249 +
1250 + return update_user_option(
1251 + get_current_user_id(),
1252 + 'mainwp_notice_saved_status',
1253 + $status
1254 + );
1255 + }
1256 +
1257 + /**
1193 1258 * Method get_hide_notice_status()
1194 1259 *
1195 1260 * Check whenther or not to show the MainWP Message.
1196 1261 *
@@ -1235,8 +1300,241 @@
1235 1300 return $content;
1236 1301 }
1237 1302
1238 1303 /**
1304 + * Method set_short_term_notice()
1305 + *
1306 + * Set new temporary notice.
1307 + *
1308 + * @param string $monitor Monitor.
1309 + * @param string $noti_key Notice key.
1310 + * @param int $checked_at Notice checked at.
1311 + *
1312 + * @return void.
1313 + */
1314 + public static function set_short_term_notice( $monitor, $noti_key, $checked_at ) {
1315 + if ( empty( $monitor ) || empty( $noti_key ) ) {
1316 + return;
1317 + }
1318 + $noti_handle_name = static::SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor . '_' . $noti_key;
1319 + static::update_option( $noti_handle_name, $checked_at );
1320 + }
1321 +
1322 +
1323 + /**
1324 + * Method is_short_term_notice()
1325 + *
1326 + * Check whether the short-term notice is still active.
1327 + *
1328 + * @param string $monitor Monitor name.
1329 + * @param string $noti_key Notice key.
1330 + *
1331 + * @return boolean true|false.
1332 + */
1333 + public static function is_short_term_notice( $monitor, $noti_key ) {
1334 +
1335 + if ( empty( $monitor ) || empty( $noti_key ) ) {
1336 + return false;
1337 + }
1338 +
1339 + $noti_handle_name = static::SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor . '_' . $noti_key;
1340 +
1341 + $notice_time = get_option( $noti_handle_name );
1342 +
1343 + if ( false === $notice_time ) {
1344 + return false;
1345 + }
1346 +
1347 + if ( ! is_numeric( $notice_time ) ) {
1348 + delete_option( $noti_handle_name );
1349 + }
1350 +
1351 + if ( time() - (int) $notice_time < self::SHORT_TERM_NOTICE_TTL ) {
1352 + if ( static::is_short_term_dismissed_notice( $monitor, $noti_key ) ) {
1353 + return false;
1354 + }
1355 + return true;
1356 + } else {
1357 + delete_option( $noti_handle_name );
1358 + }
1359 + return false;
1360 + }
1361 +
1362 +
1363 + /**
1364 + * Method is_short_term_dismissed_notice()
1365 + *
1366 + * Check whether the short-term notice is user dismissed.
1367 + *
1368 + * @param string $monitor Monitor.
1369 + * @param string $noti_key Notice key.
1370 + *
1371 + * @return boolean true|false.
1372 + */
1373 + public static function is_short_term_dismissed_notice( $monitor, $noti_key ) {
1374 + if ( empty( $monitor ) || empty( $noti_key ) ) {
1375 + return false;
1376 + }
1377 + $user_noti_handle = static::USER_SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor . '_' . $noti_key;
1378 + $user = wp_get_current_user();
1379 + if ( $user && ! empty( $user->ID ) ) {
1380 + return 'dismissed' === get_option( $user_noti_handle . '_user_' . $user->ID );
1381 + }
1382 + return false;
1383 + }
1384 +
1385 +
1386 + /**
1387 + * Purge short-term notices.
1388 + *
1389 + * @param string $monitor Optional monitor name. When provided, only
1390 + * notices for the specified monitor are purged.
1391 + * @param bool $expired_only Whether to purge only expired notices.
1392 + *
1393 + * @return void
1394 + */
1395 + public static function purge_short_term_notices( $monitor = '', $expired_only = true ) { // phpcs:ignore -- NOSONAR - complex.
1396 +
1397 + $opt_prefix = self::SHORT_TERM_NOTICE_OPTION_PREFIX;
1398 +
1399 + $prefix = '' !== $monitor ? $monitor . '_' : '';
1400 +
1401 + $timeout = time() - self::SHORT_TERM_NOTICE_TTL;
1402 +
1403 + $db = MainWP_DB::instance()->get_wpdb_instance();
1404 +
1405 + $sql = $db->prepare(
1406 + "
1407 + SELECT option_name
1408 + FROM {$db->options}
1409 + WHERE option_name LIKE %s
1410 + ",
1411 + $db->esc_like( $opt_prefix . (string) $prefix ) . '%',
1412 + );
1413 +
1414 + if ( $expired_only ) {
1415 + $sql .= $db->prepare(
1416 + ' AND CAST(option_value AS UNSIGNED) <= %d ',
1417 + $timeout
1418 + );
1419 + }
1420 +
1421 + $options = $db->get_col( $sql );
1422 +
1423 + foreach ( $options as $option_name ) {
1424 + delete_option( $option_name );
1425 + }
1426 + }
1427 +
1428 +
1429 + /**
1430 + * Purge short-term notices for a specific issue.
1431 + *
1432 + * @param string $monitor Monitor name.
1433 + * @param string $issue_code Issue code.
1434 + *
1435 + * @return bool True if the operation completed, false if the input is invalid.
1436 + */
1437 + public static function delete_short_term_notices_for_issue( $monitor, $issue_code ) {
1438 +
1439 + if ( empty( $monitor ) || empty( $issue_code ) ) {
1440 + return false;
1441 + }
1442 +
1443 + $opt_prefix = self::SHORT_TERM_NOTICE_OPTION_PREFIX;
1444 + $prefix = $monitor . '_' . $issue_code;
1445 +
1446 + $db = MainWP_DB::instance()->get_wpdb_instance();
1447 +
1448 + $sql = $db->prepare(
1449 + "
1450 + SELECT option_name
1451 + FROM {$db->options}
1452 + WHERE option_name LIKE %s
1453 + ",
1454 + $db->esc_like( $opt_prefix . $prefix ) . '%'
1455 + );
1456 +
1457 + $options = $db->get_col( $sql );
1458 +
1459 + foreach ( $options as $option_name ) {
1460 + delete_option( $option_name ); // Delete options and cache.
1461 + }
1462 +
1463 + return true;
1464 + }
1465 +
1466 + /**
1467 + * Method dismiss_short_term_notice()
1468 + *
1469 + * Hide short term notice.
1470 + *
1471 + * @param string $monitor_noti_key Notice key.
1472 + *
1473 + * @return void.
1474 + */
1475 + public static function dismiss_short_term_notice( $monitor_noti_key ) {
1476 + $noti_handle_name = static::USER_SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor_noti_key;
1477 + $user = wp_get_current_user();
1478 + if ( $user && ! empty( $user->ID ) ) {
1479 + static::update_option( $noti_handle_name . '_user_' . $user->ID, 'dismissed' );
1480 + }
1481 + }
1482 +
1483 + /**
1484 + * Delete user short-term notice options for the specified monitor.
1485 + *
1486 + * Optionally preserves the dismissed state for the specified issue codes.
1487 + *
1488 + * @param string $monitor Monitor name.
1489 + * @param array $preserved_issues Issue codes whose dismissed state should be preserved.
1490 + *
1491 + * @return void
1492 + */
1493 + public static function delete_short_term_notice_options( $monitor, $preserved_issues = array() ) {
1494 +
1495 + if ( empty( $monitor ) ) {
1496 + return;
1497 + }
1498 +
1499 + $db = MainWP_DB::instance()->get_wpdb_instance();
1500 +
1501 + $sql = "
1502 + SELECT option_name
1503 + FROM {$db->options}
1504 + WHERE option_name LIKE %s
1505 + ";
1506 +
1507 + $args = array(
1508 + $db->esc_like(
1509 + static::USER_SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor . '_'
1510 + ) . '%',
1511 + );
1512 +
1513 + // Preserve the user's dismissed state for the specified issues.
1514 + if ( ! empty( $preserved_issues ) && is_array( $preserved_issues ) ) {
1515 + foreach ( $preserved_issues as $issue_code ) {
1516 + $sql .= ' AND option_name NOT LIKE %s';
1517 + $args[] = $db->esc_like(
1518 + static::USER_SHORT_TERM_NOTICE_OPTION_PREFIX . $monitor . '_' . $issue_code . '_user_'
1519 + ) . '%';
1520 + }
1521 + }
1522 +
1523 + $option_names = $db->get_col(
1524 + $db->prepare( $sql, ...$args )
1525 + );
1526 +
1527 + if ( empty( $option_names ) ) {
1528 + return;
1529 + }
1530 +
1531 + foreach ( $option_names as $option_name ) {
1532 + delete_option( $option_name );
1533 + }
1534 + }
1535 +
1536 + /**
1239 1537 * Method update_flash_message()
1240 1538 *
1241 1539 * Check whenther or not to show the MainWP Message.
1242 1540 *
@@ -1394,19 +1692,30 @@
1394 1692 * @return array Health status value.
1395 1693 */
1396 1694 public static function get_site_health( $issue_counts ) {
1397 1695
1398 - if ( empty( $issue_counts ) ) {
1399 - $issue_counts = array(
1696 + // Coerce non-array/empty/partial input to a full set of counts so a scalar
1697 + // (e.g. a JSON-decoded string) or a missing key never fatals or warns.
1698 + $issue_counts = array_merge(
1699 + array(
1400 1700 'good' => 0,
1401 1701 'recommended' => 0,
1402 1702 'critical' => 0,
1403 - );
1404 - }
1703 + ),
1704 + is_array( $issue_counts ) ? $issue_counts : array()
1705 + );
1405 1706
1406 - $totalTests = intval( $issue_counts['good'] ) + intval( $issue_counts['recommended'] ) + intval( $issue_counts['critical'] ) * 1.5;
1407 - $failedTests = intval( $issue_counts['recommended'] ) * 0.5 + $issue_counts['critical'] * 1.5;
1707 + // Normalize each counter to a non-negative integer before arithmetic so a
1708 + // non-numeric or negative stored value cannot fatal or skew the score.
1709 + // is_numeric() first: intval() maps a non-empty array to 1, which would
1710 + // count a malformed nested value as a real issue.
1711 + $good = is_numeric( $issue_counts['good'] ) ? max( 0, intval( $issue_counts['good'] ) ) : 0;
1712 + $recommended = is_numeric( $issue_counts['recommended'] ) ? max( 0, intval( $issue_counts['recommended'] ) ) : 0;
1713 + $critical = is_numeric( $issue_counts['critical'] ) ? max( 0, intval( $issue_counts['critical'] ) ) : 0;
1408 1714
1715 + $totalTests = $good + $recommended + $critical * 1.5;
1716 + $failedTests = $recommended * 0.5 + $critical * 1.5;
1717 +
1409 1718 if ( empty( $totalTests ) ) {
1410 1719 $val = 100;
1411 1720 } else {
1412 1721 $val = 100 - ceil( ( $failedTests / $totalTests ) * 100 );
@@ -1421,9 +1730,9 @@
1421 1730 }
1422 1731
1423 1732 return array(
1424 1733 'val' => $val,
1425 - 'critical' => $issue_counts['critical'],
1734 + 'critical' => $critical,
1426 1735 );
1427 1736 }
1428 1737
1429 1738
@@ -2321,6 +2630,15 @@
2321 2630 */
2322 2631 public static function get_decoded_array( $data ) {
2323 2632 $decoded = ! empty( $data ) ? json_decode( $data, true ) : array();
2324 2633 return is_array( $decoded ) ? $decoded : array();
2634 + }
2635 +
2636 + /**
2637 + * Method get_use_cron()
2638 + *
2639 + * @return bool Whether use cron.
2640 + */
2641 + public static function get_use_cron() {
2642 + return ( get_option( 'mainwp_wp_cron' ) === false ) || ( (int) get_option( 'mainwp_wp_cron' ) === 1 ) ? 1 : 0;
2325 2643 }
2326 2644 }