PluginProbe
Themify Builder / trunk
Themify Builder vtrunk
7.8.1 7.8.0 7.7.9 7.7.8 7.7.7 7.7.6 7.7.5 7.7.4 7.7.3 7.7.2 trunk 7.6.0 7.6.1 7.6.2 7.6.3 7.6.4 7.6.5 7.6.6 7.6.7 7.6.8 7.6.9 7.7.0 7.7.1
themify-builder / themify / themify-status.php

themify-status.php in Themify Builder trunk, at themify/themify-status.php

776 lines 35.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Generate reports of various system variables and configs, useful for debugging.
4 * This only available to administrators.
5 *
6 * @package Themify
7 */
8 class Themify_System_Status {
9
10 /**
11 * User meta keys (boolean) for non-critical admin notices: "do not show again".
12 */
13 const USER_META_DISMISS_MIV = 'tf_status_dismiss_miv';
14 const USER_META_DISMISS_UPLOADS = 'tf_status_dismiss_uploads';
15 const USER_META_DISMISS_CRITICAL = 'tf_status_dismiss_critical';
16 /** WordPress upload path / createDir failure (post edit screen notice). */
17 const USER_META_DISMISS_UPLOAD_DIR = 'tf_status_dismiss_upload_dir';
18
19 public static function init() {
20 add_action( 'admin_init', array( __CLASS__, 'handle_optional_notice_dismiss' ) );
21 add_action( 'admin_menu', array( __CLASS__, 'admin_menu' ) );
22 add_action( 'admin_notices', array( __CLASS__, 'uploads_not_writable_admin_notice' ), 5 );
23 add_action( 'admin_notices', array( __CLASS__, 'critical_requirements_admin_notice' ), 6 );
24 add_action( 'admin_notices', array( __CLASS__, 'max_input_vars_admin_notice' ), 7 );
25 add_action( 'admin_head', array( __CLASS__, 'print_notice_dismiss_styles' ) );
26 add_action( 'admin_head', array( __CLASS__, 'print_status_table_styles' ) );
27 }
28
29 /**
30 * @return array<string,string> Short slug => user meta key.
31 */
32 private static function optional_notice_dismiss_meta_map() {
33 return array(
34 'miv' => self::USER_META_DISMISS_MIV,
35 'uploads' => self::USER_META_DISMISS_UPLOADS,
36 'critical' => self::USER_META_DISMISS_CRITICAL,
37 'updir' => self::USER_META_DISMISS_UPLOAD_DIR,
38 );
39 }
40
41 /**
42 * Permanently hide optional notices per user.
43 */
44 public static function handle_optional_notice_dismiss() {
45 if ( ! is_admin() || ! isset( $_GET['tf_status_dismiss'], $_GET['_wpnonce'] ) || ! current_user_can( 'manage_options' ) ) {
46 return;
47 }
48 $key = sanitize_key( wp_unslash( $_GET['tf_status_dismiss'] ) );
49 $map = self::optional_notice_dismiss_meta_map();
50 if ( ! isset( $map[ $key ] ) ) {
51 return;
52 }
53 $action = 'tf_status_dismiss_' . $key;
54 if ( ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_GET['_wpnonce'] ) ), $action ) ) {
55 return;
56 }
57 update_user_meta( get_current_user_id(), $map[ $key ], '1' );
58 $redirect = wp_get_referer();
59 if ( ! $redirect ) {
60 $redirect = admin_url();
61 }
62 $redirect = remove_query_arg( array( 'tf_status_dismiss', '_wpnonce' ), $redirect );
63 wp_safe_redirect( $redirect );
64 exit;
65 }
66
67 /**
68 * @param string $meta_key self::USER_META_* constant.
69 */
70 private static function is_optional_notice_dismissed( $meta_key ) {
71 return (string) get_user_meta( get_current_user_id(), $meta_key, true ) === '1';
72 }
73
74 /**
75 * @param string $dismiss_key Short key from optional_notice_dismiss_meta_map().
76 */
77 public static function get_optional_notice_dismiss_url( $dismiss_key ) {
78 $map = self::optional_notice_dismiss_meta_map();
79 if ( ! isset( $map[ $dismiss_key ] ) ) {
80 return '';
81 }
82 $url = add_query_arg(
83 'tf_status_dismiss',
84 $dismiss_key,
85 self_admin_url( 'index.php' )
86 );
87 return wp_nonce_url( $url, 'tf_status_dismiss_' . $dismiss_key );
88 }
89
90 /**
91 * Whether this optional notice was dismissed for the current user.
92 *
93 * @param string $dismiss_key Short slug (e.g. updir, uploads).
94 */
95 public static function is_optional_notice_dismissed_for_key( $dismiss_key ) {
96 $map = self::optional_notice_dismiss_meta_map();
97 return isset( $map[ $dismiss_key ] ) && self::is_optional_notice_dismissed( $map[ $dismiss_key ] );
98 }
99
100 /**
101 * Scoped dismiss-link spacing on any admin screen that shows Themify notices.
102 */
103 public static function print_notice_dismiss_styles() {
104 if ( ! is_admin() || ! current_user_can( 'manage_options' ) ) {
105 return;
106 }
107 echo '<style id="tf-status-notice-dismiss">.notice .tf-status-notice-dismiss{margin:.65em 0 0}</style>';
108 }
109
110 /**
111 * Neither fsockopen nor cURL — HTTP to external services may fail (same check as System Status).
112 */
113 public static function is_fsockopen_and_curl_unavailable() {
114 return ! ( function_exists( 'fsockopen' ) || function_exists( 'curl_init' ) );
115 }
116
117 /**
118 * No WP image editor (GD / Imagick) available.
119 */
120 public static function is_wp_image_editor_unavailable() {
121 if ( ! function_exists( '_wp_image_editor_choose' ) && defined( 'ABSPATH' ) ) {
122 $media = ABSPATH . 'wp-includes/media.php';
123 if ( is_readable( $media ) ) {
124 require_once $media;
125 }
126 }
127 if ( ! function_exists( '_wp_image_editor_choose' ) ) {
128 return true;
129 }
130 return empty( _wp_image_editor_choose() );
131 }
132
133 /**
134 * TF storage table could not be created (same check as "Custom Tables Allowed" on System Status).
135 */
136 public static function is_themify_custom_tables_unavailable() {
137 if ( ! class_exists( 'Themify_Storage', false ) ) {
138 return true;
139 }
140 return Themify_Storage::init() === false;
141 }
142
143 /**
144 * @return bool True when max_input_vars is set and below 1000 (WordPress / large forms often need 1000+).
145 */
146 public static function is_max_input_vars_low() {
147 if ( ! function_exists( 'ini_get' ) ) {
148 return false;
149 }
150 $v = (int) ini_get( 'max_input_vars' );
151 return $v > 0 && $v < 1000;
152 }
153
154 /**
155 * @return bool True when PHP is below 8.2 (Themify recommends 8.2+; same as System Status notice).
156 */
157 public static function is_php_below_82() {
158 return version_compare( PHP_VERSION, '8.2', '<' );
159 }
160
161 public static function critical_requirements_admin_notice() {
162 if ( ! is_admin() || ! current_user_can( 'manage_options' ) || self::is_optional_notice_dismissed( self::USER_META_DISMISS_CRITICAL ) ) {
163 return;
164 }
165 $items = array();
166 if ( self::is_themify_custom_tables_unavailable() ) {
167 $items[] = esc_html__( 'The theme could not create its custom database table (caching and some features that depend on it may not work).', 'themify' );
168 }
169 if ( self::is_fsockopen_and_curl_unavailable() ) {
170 $items[] = esc_html__( 'Neither fsockopen nor cURL is available, so the site may not be able to connect to external services.', 'themify' );
171 }
172 if ( self::is_wp_image_editor_unavailable() ) {
173 $items[] = esc_html__( 'No image processing library (such as GD or Imagick) is available, so image editing and thumbnail generation can fail.', 'themify' );
174 }
175 if ( empty( $items ) ) {
176 return;
177 }
178 $url = admin_url( 'admin.php?page=tf-status' );
179 $link = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'System Status', 'themify' ) . '</a>';
180 $intro = esc_html__( 'Themify: your server is missing one or more critical requirements.', 'themify' );
181 ?>
182 <div class="notice notice-error"><p><strong><?php echo esc_html( $intro ); ?></strong></p>
183 <ul style="margin:0 0 0 1.25em;list-style:disc;padding-left:1em">
184 <?php
185 foreach ( $items as $text ) {
186 echo '<li>' . $text . '</li>';
187 }
188 ?>
189 </ul>
190 <p>
191 <?php
192 echo wp_kses(
193 /* translators: %s: "System Status" page link. */
194 sprintf( __( 'View %s for full details and next steps.', 'themify' ), $link ),
195 array( 'a' => array( 'href' => array() ) )
196 );
197 ?>
198 </p>
199 <p class="tf-status-notice-dismiss">
200 <a href="<?php echo esc_url( self::get_optional_notice_dismiss_url( 'critical' ) ); ?>"><?php esc_html_e( 'Dismiss (do not show again)', 'themify' ); ?></a>
201 </p>
202 </div>
203 <?php
204 }
205
206 public static function max_input_vars_admin_notice() {
207 if ( ! is_admin() || ! current_user_can( 'manage_options' ) || ! self::is_max_input_vars_low() || self::is_optional_notice_dismissed( self::USER_META_DISMISS_MIV ) ) {
208 return;
209 }
210 $url = admin_url( 'admin.php?page=tf-status' );
211 $link = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'System Status', 'themify' ) . '</a>';
212 ?>
213 <div class="notice notice-warning"><p>
214 <?php
215 echo wp_kses(
216 /* translators: %s: "System Status" page link. */
217 sprintf( __( 'Themify: PHP <code>max_input_vars</code> is low (%1$d). Large pages or the Builder can fail to save. Increase it (often to 2000 or more) in your PHP configuration, or see %2$s for context.', 'themify' ), (int) ini_get( 'max_input_vars' ), $link ),
218 array( 'a' => array( 'href' => array() ), 'code' => array() )
219 );
220 ?>
221 </p>
222 <p class="tf-status-notice-dismiss">
223 <a href="<?php echo esc_url( self::get_optional_notice_dismiss_url( 'miv' ) ); ?>"><?php esc_html_e( 'Dismiss (do not show again)', 'themify' ); ?></a>
224 </p>
225 </div>
226 <?php
227 }
228
229 /**
230 * Same check as the "Concate CSS folder" row: generated CSS (concat/customizer) is stored under wp-content/uploads.
231 *
232 * @return bool True when the active Themify concate path is not writable (styling file generation can fail).
233 */
234 public static function is_themify_concat_css_dir_unwritable() {
235 if ( ! class_exists( 'Themify_Enqueue_Assets', false ) || ! class_exists( 'Themify_Filesystem', false ) ) {
236 return false;
237 }
238 $dir = trailingslashit( Themify_Enqueue_Assets::getCurrentVersionFolder() );
239 clearstatcache( true, $dir );
240 $concate_parent = trailingslashit( dirname( $dir ) );
241 $basedir = trailingslashit( themify_upload_dir( 'basedir' ) );
242 clearstatcache( true, $concate_parent );
243 clearstatcache( true, $basedir );
244
245 if ( ! function_exists( 'wp_is_writable' ) && defined( 'ABSPATH' ) ) {
246 require_once ABSPATH . 'wp-admin/includes/file.php';
247 }
248 $writable = static function ( $path ) {
249 return function_exists( 'wp_is_writable' ) ? wp_is_writable( $path ) : Themify_Filesystem::is_writable( $path );
250 };
251 /* Versioned folder is created on demand; is_writable(false) on a missing path is a common false negative. */
252 if ( Themify_Filesystem::is_dir( $dir ) ) {
253 return ! $writable( $dir );
254 }
255 if ( Themify_Filesystem::is_dir( $concate_parent ) ) {
256 return ! $writable( $concate_parent );
257 }
258 return ! $writable( $basedir );
259 }
260
261 public static function uploads_not_writable_admin_notice() {
262 if ( ! is_admin() || ! current_user_can( 'manage_options' ) || self::is_optional_notice_dismissed( self::USER_META_DISMISS_UPLOADS ) || ! self::is_themify_concat_css_dir_unwritable() ) {
263 return;
264 }
265 $url = admin_url( 'admin.php?page=tf-status' );
266 ?>
267 <div class="notice notice-error"><p>
268 <?php
269 $link = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'System Status', 'themify' ) . '</a>';
270 echo wp_kses(
271 /* translators: %s: "System Status" link. */
272 sprintf( __( 'Themify: the "uploads" folder is not write-able (the theme might not able to generate the styling). View %s for more details.', 'themify' ), $link ),
273 array( 'a' => array( 'href' => array() ) )
274 );
275 ?>
276 </p>
277 <p class="tf-status-notice-dismiss">
278 <a href="<?php echo esc_url( self::get_optional_notice_dismiss_url( 'uploads' ) ); ?>"><?php esc_html_e( 'Dismiss (do not show again)', 'themify' ); ?></a>
279 </p>
280 </div>
281 <?php
282 }
283
284 /**
285 * @return bool True when WP_MEMORY_LIMIT is below 128MB.
286 */
287 private static function is_wp_memory_limit_low() {
288 if ( ! defined( 'WP_MEMORY_LIMIT' ) ) {
289 return false;
290 }
291 $bytes = wp_convert_hr_to_bytes( WP_MEMORY_LIMIT );
292 return $bytes < 128 * MB_IN_BYTES;
293 }
294
295 /**
296 * External help article: raising WP_MEMORY_LIMIT.
297 *
298 * @return string Safe HTML (paragraph content).
299 */
300 private static function get_low_wp_memory_learn_more_markup() {
301 $article_url = 'https://themify.me/blog/increase-wordpress-memory-limit';
302 return wp_kses(
303 sprintf(
304 /* translators: %s: HTML anchor linking to Themify article on increasing WordPress memory limit */
305 __( 'Learn how to %s.', 'themify' ),
306 '<a href="' . esc_url( $article_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html__( 'increase WP memory', 'themify' ) . '</a>'
307 ),
308 array(
309 'a' => array(
310 'href' => true,
311 'target' => true,
312 'rel' => true,
313 ),
314 )
315 );
316 }
317
318 /**
319 * Error styling for System Status (eg. mark.error, low memory line).
320 */
321 public static function print_status_table_styles() {
322 if ( ! is_admin() || ! isset( $_GET['page'] ) || 'tf-status' !== $_GET['page'] || ! current_user_can( 'manage_options' ) ) {
323 return;
324 }
325 ?>
326 <style id="tf-status-table-ui">
327 .tf_status_table th[scope="row"] { vertical-align: top; }
328 .tf_status_table mark.error { background: transparent; color: #b32d2e; font-weight: 600; padding: 0; }
329 .tf_status_table mark.error .dashicons { color: #b32d2e; }
330 .tf_status_table .tf_status-wp-memory-bad { color: #b32d2e; font-weight: 600; }
331 .tf_status_table .tf_status-wp-memory-bad strong { color: #b32d2e; }
332 .tf_status_table td br + mark.error { display: block; margin-top: 6px; }
333 </style>
334 <?php
335 }
336
337 public static function admin_menu() {
338 $parent = is_plugin_active( 'themify-builder/themify-builder.php' ) ? 'themify-builder' : 'themify';
339 add_submenu_page ( $parent, __( 'System Status', 'themify' ), __( 'System Status', 'themify' ), 'manage_options', 'tf-status', array( __CLASS__, 'admin' ) );
340 }
341
342 private static function extract_ip_from_string( $value ) {
343 $value = trim( (string) $value );
344 if ( $value === '' ) {
345 return '';
346 }
347
348 if ( strpos( $value, ',' ) !== false ) {
349 $parts = explode( ',', $value );
350 foreach ( $parts as $part ) {
351 $ip = self::extract_ip_from_string( $part );
352 if ( $ip !== '' ) {
353 return $ip;
354 }
355 }
356 return '';
357 }
358
359 if ( preg_match( '/^\[([0-9a-fA-F:\.]+)\](?::\d+)?$/', $value, $matches ) ) {
360 $value = $matches[1];
361 } elseif ( preg_match( '/^((?:\d{1,3}\.){3}\d{1,3})(?::\d+)?$/', $value, $matches ) ) {
362 $value = $matches[1];
363 }
364
365 return filter_var( $value, FILTER_VALIDATE_IP ) ? $value : '';
366 }
367
368 private static function resolve_hostname_ip( $hostname ) {
369 if ( ! is_string( $hostname ) ) {
370 return '';
371 }
372
373 $hostname = trim( $hostname );
374 if ( $hostname === '' ) {
375 return '';
376 }
377
378 if ( function_exists( 'dns_get_record' ) ) {
379 $records = @dns_get_record( $hostname, DNS_AAAA );
380 if ( is_array( $records ) ) {
381 foreach ( $records as $record ) {
382 if ( ! empty( $record['ipv6'] ) ) {
383 $ip = self::extract_ip_from_string( $record['ipv6'] );
384 if ( $ip !== '' ) {
385 return $ip;
386 }
387 }
388 }
389 }
390
391 $records = @dns_get_record( $hostname, DNS_A );
392 if ( is_array( $records ) ) {
393 foreach ( $records as $record ) {
394 if ( ! empty( $record['ip'] ) ) {
395 $ip = self::extract_ip_from_string( $record['ip'] );
396 if ( $ip !== '' ) {
397 return $ip;
398 }
399 }
400 }
401 }
402 }
403
404 $resolved = @gethostbyname( $hostname );
405 $ip = self::extract_ip_from_string( $resolved );
406 return $ip !== '' ? $ip : '';
407 }
408
409 private static function get_server_ip() {
410 $candidates = array(
411 'SERVER_ADDR',
412 'LOCAL_ADDR',
413 'SERVER_IP',
414 );
415
416 foreach ( $candidates as $key ) {
417 if ( isset( $_SERVER[ $key ] ) && is_string( $_SERVER[ $key ] ) ) {
418 $ip = self::extract_ip_from_string( $_SERVER[ $key ] );
419 if ( $ip !== '' ) {
420 return $ip;
421 }
422 }
423 }
424
425 $hostnames = array();
426 if ( isset( $_SERVER['SERVER_NAME'] ) && is_string( $_SERVER['SERVER_NAME'] ) ) {
427 $hostnames[] = wp_unslash( $_SERVER['SERVER_NAME'] );
428 }
429 if ( function_exists( 'gethostname' ) ) {
430 $hostname = gethostname();
431 if ( is_string( $hostname ) && $hostname !== '' ) {
432 $hostnames[] = $hostname;
433 }
434 }
435
436 $hostnames = array_unique( array_filter( array_map( 'trim', $hostnames ) ) );
437 foreach ( $hostnames as $hostname ) {
438 $ip = self::resolve_hostname_ip( $hostname );
439 if ( $ip !== '' ) {
440 return $ip;
441 }
442 }
443
444 return '';
445 }
446
447 public static function admin() {
448 global $wpdb;
449 $server_info = isset( $_SERVER['SERVER_SOFTWARE'] ) ? self::sanitize_deep( wp_unslash( $_SERVER['SERVER_SOFTWARE'] ) ) : '';
450 $r=false;
451 foreach(array('/etc/lsb-release','/etc/os-release','/etc/redhat-release') as $dist){
452 if(@is_readable($dist)){
453 $r=@parse_ini_file($dist);
454 break;
455 }
456 }
457 $tables=array(
458 $wpdb->posts,
459 $wpdb->postmeta,
460 $wpdb->options,
461 $wpdb->terms,
462 $wpdb->term_taxonomy,
463 $wpdb->term_relationships
464 );
465
466 ?>
467 <div class="wrap">
468 <h1><?php _e( 'System Status', 'themify' ); ?></h1>
469 <table class="tf_status_table widefat" cellspacing="0">
470 <thead>
471 <tr>
472 <td colspan="3"><h2><?php esc_html_e( 'Server environment', 'themify' ); ?></h2></td>
473 </tr>
474 </thead>
475 <tbody>
476 <tr>
477 <th scope="row"><?php esc_html_e( 'OS', 'themify' ); ?>:</th>
478 <td>
479 <?php
480 if ( is_array( $r ) && ( isset( $r['PRETTY_NAME'] ) || isset( $r['NAME'] ) ) ) {
481 if ( isset( $r['PRETTY_NAME'] ) ) {
482 echo $r['PRETTY_NAME'];
483 } else {
484 echo $r['NAME'];
485 }
486 } elseif ( function_exists( 'php_uname' ) ) {
487 echo php_uname('s');
488 } else {
489 echo '<span class="dashicons dashicons-warning"></span>', __( 'Cannot be determined.', 'themify' );
490 }
491 ?>
492 </td>
493 </tr>
494 <tr>
495 <th scope="row"><?php esc_html_e( 'Server info', 'themify' ); ?>:</th>
496 <td>
497 <?php
498 $server_ip = self::get_server_ip();
499 echo esc_html( $server_info );
500 ?>
501 <br>
502 <strong><?php esc_html_e( 'Server IP', 'themify' ); ?></strong>: <?php echo esc_html( $server_ip !== '' ? $server_ip : __( 'Unknown', 'themify' ) ); ?>
503 </td>
504 </tr>
505 <tr>
506 <th scope="row"><?php esc_html_e( 'PHP version', 'themify' ); ?>:</th>
507 <td>
508 <?php
509 echo esc_html( PHP_VERSION );
510 if ( self::is_php_below_82() ) {
511 echo ' <span class="dashicons dashicons-warning"></span> ' . esc_html__( 'We recommend using PHP version 8.2 or above for greater performance and security. Please contact your web hosting provider.', 'themify' );
512 }
513 ?>
514 </td>
515 </tr>
516 <tr>
517 <th scope="row"><?php esc_html_e( 'HTTPS (site address)', 'themify' ); ?>:</th>
518 <td>
519 <?php
520 $tf_home = (string) get_option( 'home' );
521 if ( $tf_home !== '' && strpos( $tf_home, 'https://' ) === 0 ) {
522 echo '<span class="dashicons dashicons-yes"></span> ';
523 } else {
524 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Use a full https:// site URL in Settings → General when your site is served over SSL. Plain http or relative URLs can cause mixed-content and asset issues.', 'themify' ) . '</mark><br>';
525 }
526 echo esc_html( $tf_home !== '' ? $tf_home : __( '(not set)', 'themify' ) );
527 ?>
528 </td>
529 </tr>
530 <tr>
531 <th scope="row"><?php esc_html_e( 'WordPress Version', 'themify' ); ?>:</th>
532 <td>
533 <?php
534 global $wp_version;
535 echo $wp_version;
536 ?>
537 </td>
538 </tr>
539 <tr>
540 <th scope="row"><?php esc_html_e( 'Database', 'themify' ); ?>:</th>
541 <td><?php echo $wpdb->db_server_info(); ?></td>
542 </tr>
543 <tr>
544 <th scope="row"><?php esc_html_e( 'Debug Mode', 'themify' ); ?>:</th>
545 <td><?php echo ( defined( 'WP_DEBUG' ) && WP_DEBUG ) ? __( 'Enabled', 'themify' ) : __( 'Disabled', 'themify' ); ?></td>
546 </tr>
547 <?php if ( function_exists( 'ini_get' ) ) : ?>
548 <tr>
549 <th scope="row"><?php esc_html_e( 'PHP post max size', 'themify' ); ?>:</th>
550 <td><?php echo esc_html( size_format( wp_convert_hr_to_bytes( ini_get( 'post_max_size' ) ) ) ); ?></td>
551 </tr>
552 <tr>
553 <th scope="row"><?php esc_html_e( 'PHP time limit', 'themify' ); ?>:</th>
554 <td><?php echo esc_html( (int) ini_get( 'max_execution_time' ) ); ?></td>
555 </tr>
556 <tr>
557 <th scope="row"><?php esc_html_e( 'PHP memory limit', 'themify' ); ?>:</th>
558 <td>
559 <?php
560 $tf_wp_mem_low = self::is_wp_memory_limit_low();
561 $tf_wp_mem_fmt = size_format( wp_convert_hr_to_bytes( WP_MEMORY_LIMIT ) );
562 if ( $tf_wp_mem_low ) {
563 echo '<span class="tf_status-wp-memory-bad"><strong>WP_MEMORY_LIMIT</strong>: ' . esc_html( $tf_wp_mem_fmt ) . '</span><br>';
564 } else {
565 echo '<strong>WP_MEMORY_LIMIT</strong>: ' . esc_html( $tf_wp_mem_fmt ) . '<br>';
566 }
567 ?>
568 <strong><?php _e( 'PHP Memory Limit', 'themify' ); ?></strong>: <?php echo esc_html( size_format( wp_convert_hr_to_bytes( ini_get( 'memory_limit' ) ) ) ); ?>
569 <?php if ( $tf_wp_mem_low ) : ?>
570 <br>
571 <mark class="error"><span class="dashicons dashicons-warning"></span><?php echo esc_html__( 'Your WordPress PHP memory limit is low. If you are experiencing issues, try increasing it to 256 MB or higher.', 'themify' ); ?></mark>
572 <br>
573 <?php echo self::get_low_wp_memory_learn_more_markup(); ?>
574 <?php endif; ?>
575 </td>
576 </tr>
577 <tr>
578 <th scope="row"><?php esc_html_e( 'PHP max input vars', 'themify' ); ?>:</th>
579 <td>
580 <?php
581 $tf_miv = (int) ini_get( 'max_input_vars' );
582 echo esc_html( (string) $tf_miv );
583 if ( self::is_max_input_vars_low() ) {
584 echo '<br><mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Value is below 1000. WordPress, large menus, and the Builder can exceed this. Ask your host to raise max_input_vars (2000+ is often used).', 'themify' ) . '</mark>';
585 }
586 ?>
587 </td>
588 </tr>
589 <tr>
590 <th scope="row"><?php esc_html_e( 'cURL version', 'themify' ); ?>:</th>
591 <td><?php echo esc_html( self::get_curl_version() ); ?></td>
592 </tr>
593 <tr>
594 <th scope="row"><?php esc_html_e( 'SUHOSIN installed', 'themify' ); ?>:</th>
595 <td><?php echo extension_loaded( 'suhosin' ) ? '<span class="dashicons dashicons-yes"></span>' : '&ndash;'; ?></td>
596 </tr>
597 <?php endif; ?>
598 <tr>
599 <th scope="row"><?php esc_html_e( 'Max upload size', 'themify' ); ?>:</th>
600 <td><?php echo esc_html( size_format( wp_max_upload_size() ) ); ?></td>
601 </tr>
602 <tr>
603 <th scope="row"><?php esc_html_e( 'fsockopen/cURL', 'themify' ); ?>:</th>
604 <td>
605 <?php
606 if ( ! self::is_fsockopen_and_curl_unavailable() ) {
607 echo '<span class="dashicons dashicons-yes"></span>';
608 } else {
609 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Your server does not have fsockopen or cURL enabled - some features that require connecting to external web services may not work. Contact your hosting provider.', 'themify' ) . '</mark>';
610 }
611 ?>
612 </td>
613 </tr>
614 <tr>
615 <th scope="row"><?php esc_html_e( 'Custom Tables Allowed', 'themify' ); ?>:</th>
616 <td>
617 <?php
618 if ( ! self::is_themify_custom_tables_unavailable() ) {
619 echo '<span class="dashicons dashicons-yes"></span>';
620 } else {
621 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Your server does not have have permissions to create custom tables in DB', 'themify' ) . '</mark>';
622 }
623 ?>
624 </td>
625 </tr>
626 <tr>
627 <th scope="row"><?php esc_html_e( 'GZip', 'themify' ); ?>:</th>
628 <td>
629 <?php
630 $gzip = TFCache::get_available_gzip();
631 if ( false !== $gzip ) {
632 $gzip = current( $gzip );
633 echo '<span class="dashicons dashicons-yes"></span> ' . $gzip['f'];
634 } else {
635 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '<a href="%s">GZIP</a> is recommended for better performance.', 'themify' ), 'https://php.net/manual/en/zlib.installation.php' ) . '</mark>';
636 }
637 ?>
638 </td>
639 </tr>
640 <tr>
641 <th scope="row"><?php esc_html_e( 'PHP Zip', 'themify' ); ?>:</th>
642 <td><?php
643 echo extension_loaded('zip') ? '<span class="dashicons dashicons-yes"></span>' : '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( '<a href="%s">PHP Zip extension</a> is recommended, this enables export/import of various data (settings, Builder content, etc.).', 'themify' ), 'https://www.php.net/manual/en/zip.setup.php' ) . '</mark>';
644 ?>
645 </td>
646 </tr>
647 <tr>
648 <th scope="row"><?php esc_html_e( 'Multibyte string', 'themify' ); ?>:</th>
649 <td>
650 <?php
651 if ( extension_loaded( 'mbstring' ) ) {
652 echo '<span class="dashicons dashicons-yes"></span>';
653 } else {
654 /* Translators: %s: classname and link. */
655 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( esc_html__( 'Your server does not support the %s functions - this is required for better character encoding. Some fallbacks will be used instead for it.', 'themify' ), '<a href="https://php.net/manual/en/mbstring.installation.php">mbstring</a>' ) . '</mark>';
656 }
657 ?>
658 </td>
659 </tr>
660 <tr>
661 <th scope="row"><?php esc_html_e( 'Uploads folder', 'themify' ); ?>:</th>
662 <td>
663 <?php
664 $dir = themify_upload_dir();
665 echo '<p><strong>' . __( 'Base Dir ', 'themify' ) . '</strong>: ' . $dir['basedir'] . '<br>' . '<strong>' . __( 'Base URL ', 'themify' ) . '</strong>: ' . $dir['baseurl'] . '</p>';
666 if ( strpos( $dir['baseurl'], 'http' ) === false ) {
667 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Relative paths detected. URLs <a href="%s">should be full paths</a>. Assets may not load properly.', 'themify' ), 'https://developer.wordpress.org/plugins/plugin-basics/determining-plugin-and-content-directories/#constants' ) . '</mark>';
668 }
669 ?>
670 </td>
671 </tr>
672 <tr>
673 <th scope="row"><?php esc_html_e( 'Concate CSS folder', 'themify' ); ?>:</th>
674 <td>
675 <?php
676 $dir = Themify_Enqueue_Assets::getCurrentVersionFolder();
677 echo esc_html( $dir ) . ' - ';
678 if ( ! self::is_themify_concat_css_dir_unwritable() ) {
679 echo '<span class="dashicons dashicons-yes"></span>';
680 } else {
681 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'Uploads folder is not writeable, your CSS may not display correctly.', 'themify' ) . '</mark>';
682 }
683 ?>
684 </td>
685 </tr>
686 <tr>
687 <th scope="row"><?php esc_html_e( 'Image Processing Library', 'themify' ); ?>:</th>
688 <td>
689 <?php
690 if ( self::is_wp_image_editor_unavailable() ) {
691 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . esc_html__( 'No image processing library found. Please contact your web hosting to enable this.', 'themify' ) . '</mark>';
692 } else {
693 echo '<span class="dashicons dashicons-yes"></span>' . esc_html( _wp_image_editor_choose() );
694 }
695 ?>
696 </td>
697 </tr>
698 <tr>
699 <th scope="row"><?php esc_html_e( 'Mysql version', 'themify' ); ?>:</th>
700 <td>
701 <?php echo $wpdb->db_version();?>
702 </td>
703 </tr>
704 <tr>
705 <th scope="row"><?php esc_html_e( 'Database Encoding', 'themify' ); ?>:</th>
706 <td>
707 <?php
708 $dbcharset = $wpdb->get_var("SELECT @@character_set_database");
709 ?>
710 <strong><?php _e( 'Charset', 'themify' ); ?></strong>: <?php echo esc_html( $dbcharset ); ?>
711 <?php if ( strtolower( $dbcharset ) !== 'utf8mb4' ) : ?>
712 <mark class="error"><span class="dashicons dashicons-warning"></span><?php _e( 'Your database does not support 4-byte characters like emojis.', 'themify' ); ?></mark>
713 <?php endif; ?>
714 <br>
715 <strong><?php _e( 'Collation', 'themify' ); ?></strong>: <?php echo esc_html( $wpdb->get_var("SELECT @@collation_database") ); ?>
716 </td>
717 </tr>
718 <tr>
719 <th scope="row"><?php esc_html_e( 'Storage engine', 'themify' ); ?>:</th>
720 <td>
721 <table>
722 <?php foreach($tables as $t):?>
723 <tr>
724 <th scope="row"><?php echo $t?></th>
725 <td>
726 <?php $engine=$wpdb->get_row( $wpdb->prepare( "SHOW TABLE STATUS WHERE Name = '%s'", $t ));
727 echo $engine->Engine;
728 if($engine->Engine==='InnoDB'){
729 echo '<span class="dashicons dashicons-yes"></span>';
730 }
731 else{
732 echo '<mark class="error"><span class="dashicons dashicons-warning"></span> ' . sprintf( __( 'Please consider using <a href="%s" target="_blank">InnoDB engine</a> which offers a lot of advantages and keeps your data safe. You can contact your web hosting to upgrade this for you.', 'themify' ), 'https://core.trac.wordpress.org/ticket/9422' ) . '</mark>';
733 }
734 ?></td>
735 </tr>
736 <?php endforeach;?>
737 </table>
738 </td>
739 </tr>
740 <?php if ( method_exists( 'WpeCommon', 'instance' ) && ! WpeCommon::instance()->is_rand_enabled() ) { // WP Engine ?>
741 <tr>
742 <th scope="row"><?php esc_html_e( 'Random Post Order', 'themify' ); ?>:</th>
743 <td><mark class="error"><span class="dashicons dashicons-warning"></span> <?php esc_html_e( 'Random post order is disabled in your WPEngine settings page.', 'themify' ) ?></mark></td>
744 </tr>
745 <?php } ?>
746 </tbody>
747 </table>
748 </div>
749 <?php
750 }
751
752 public static function get_curl_version() {
753 $curl_version = '';
754 if ( function_exists( 'curl_version' ) ) {
755 $curl_version = curl_version();
756 $curl_version = $curl_version['version'] . ', ' . $curl_version['ssl_version'];
757 } elseif ( extension_loaded( 'curl' ) ) {
758 $curl_version = __( 'cURL installed but unable to retrieve version.', 'themify' );
759 }
760 return $curl_version;
761 }
762
763 /**
764 * Applies sanitize_ function on multidimensional array
765 *
766 * @return mixed
767 */
768 public static function sanitize_deep( $value ) {
769 if ( is_array( $value ) ) {
770 return array_map( 'wc_clean', $value );
771 } else {
772 return is_scalar( $value ) ? sanitize_text_field( $value ) : $value;
773 }
774 }
775 }
776 Themify_System_Status::init();