Usage
This function runs automatically, so it is not called manually. Is this incorrect?
Additional Notes
This dashboard metabox must be enabled in Nebula Options, and either a developer IP or email domain must be entered!
Source File
Located in /libs/Admin/Dashboard.php on line 692.
5 Hooks
Find these filters and actions in the source code below to hook into them. Use do_action() and add_filter() in your functions file or plugin.
Filters
"nebula_dashboard_server_ip""nebula_cpu_cores"
"nebula_directory_search_options"
Need a new filter hook? Request one here.
Actions
"nebula_developer_info""nebula_dev_dashboard_directories"
Need a new action hook? Request one here.
PHP
public function dashboard_developer_info(){
$this->timer('Nebula Developer Dashboard Metabox', 'start', '[Nebula] Dashboard Metaboxes');
do_action('nebula_developer_info');
echo '<ul class="nebula-fa-ul serverdetections ' . $this->get_simplify_dashboard_class() . '">';
echo '<li class="cookie_notification text_ad ads advertisement ads_content ads_div ads_google adsbygoogle adscontainer adsense-box nebula-adb-tester"></li>'; //Alert developers if their ad-blocker is still active
//Environment Type
if ( function_exists('wp_get_environment_type') ){ //New as of WP 5.5 (August 2020). Remove this conditional eventually.
$environment_type = ucwords(wp_get_environment_type());
$environment_type_icon = 'fa-industry'; //Assume "Production" by default
if ( $environment_type === 'Staging' ){
$environment_type_icon = 'fa-pencil-ruler';
} elseif ( $environment_type === 'Development' ){
$environment_type_icon = 'fa-hard-hat';
} elseif ( $environment_type === 'Test' ){
$environment_type_icon = 'fa-flask';
}
echo '<li><i class="fa-solid ' . $environment_type_icon . '"></i> Environment Type: <strong>' . $environment_type . '</strong></li>';
}
//Domain
//Note: It is not currently feasible to check domain expiration dates as all reputable WHOIS services require an API key to retrieve that data.
$domain = $this->url_components('domain');
$domain ??= '<small>(None)</small>';
echo '<li class="essential"><i class="fa-solid fa-info-circle"></i> <a href="http://whois.domaintools.com/' . $this->super->server['SERVER_NAME'] . '" target="_blank" rel="noopener noreferrer" title="WHOIS Lookup">Domain</a>: <strong>' . $domain . '</strong></li>';
//Host
function top_domain_name($url){
$alldomains = explode('.', $url);
if ( count($alldomains) > 1 ){
return $alldomains[count($alldomains)-2] . "." . $alldomains[count($alldomains)-1];
}
return $url;
}
if ( function_exists('gethostname') ){
set_error_handler(function(){ /* ignore errors */ });
$dnsrecord = ( dns_get_record(top_domain_name(gethostname()), DNS_NS) )? dns_get_record(top_domain_name(gethostname()), DNS_NS) : '';
restore_error_handler();
echo '<li><i class="fa-regular fa-hdd"></i> Host: <strong>' . top_domain_name(gethostname()) . '</strong>';
if ( !empty($dnsrecord[0]['target']) ){
echo ' <small>(' . top_domain_name($dnsrecord[0]['target']) . ')</small>';
}
echo '</li>';
}
//Get the network gateway if it exists
if ( $this->get_network_gateway() ){
echo '<li><i class="fa-solid fa-diagram-project"></i> Network Gateway: <strong>' . $this->get_network_gateway() . '</strong></li>';
}
//Server IP address (and connection security)
$secure_server = '<small class="unsecured-connection essential"><i class="fa-solid fa-unlock"></i>Unsecured Connection</small>';
if ( (!empty($this->super->server['HTTPS']) && $this->super->server['HTTPS'] !== 'off') || $this->super->server['SERVER_PORT'] === 443 ){
$secure_server = '<small class="secured-connection"><i class="fa-solid fa-lock"></i>Secured Connection</small>';
}
$public_local_ip = ( preg_match('/^(127\.|192\.168|172\.|10\.)/', $this->super->server['SERVER_ADDR']) )? 'Local' : 'Public'; //Check if the server IP is likely local (private) or public (this is not perfectly exact)
echo '<li><i class="fa-solid fa-upload"></i> ' . $public_local_ip . ' Server IP: <strong><a href="http://whatismyipaddress.com/ip/' . $this->super->server['SERVER_ADDR'] . '" target="_blank" rel="noopener noreferrer">' . apply_filters('nebula_dashboard_server_ip', $this->super->server['SERVER_ADDR']) . '</a></strong> ' . $secure_server . '</li>';
//SSL Connection
if ( !is_ssl() ){
echo '<li><i class="fa-solid fa-unlock"></i> <strong class="essential text-danger">Non-SSL Connection!</strong></li>';
}
//Server Time Zone
if ( !empty(get_option('timezone_string')) && date_default_timezone_get() === get_option('timezone_string') && wp_timezone_string() === get_option('timezone_string') ){
echo '<li><i class="fa-solid fa-globe-americas"></i> Timezone: <strong>' . date_default_timezone_get() . '</strong></li>';
} else {
echo '<li class="essential"><i class="fa-solid fa-globe-americas"></i> Server Timezone: <strong>' . date_default_timezone_get() . '</strong></li>';
echo '<li class="essential"><i class="fa-solid fa-globe-americas"></i> WordPress Timezone Option: <strong>' . get_option('timezone_string') . '</strong></li>';
echo '<li class="essential"><i class="fa-solid fa-globe-americas"></i> WordPress Timezone String: <strong>' . wp_timezone_string() . '</strong></li>';
}
//Server operating system
if ( str_contains(strtolower(PHP_OS), 'linux') ){
$php_os_icon = 'fa-brands fa-linux';
} elseif ( str_contains(strtolower(PHP_OS), 'windows') ){
$php_os_icon = 'fa-brands fa-windows essential';
} else {
$php_os_icon = 'fa-solid fa-upload';
}
echo '<li><i class="' . $php_os_icon . '"></i> Server OS: <strong>' . PHP_OS . '</strong></li>';
//Server software
$server_software = $this->super->server['SERVER_SOFTWARE'];
if ( strlen($server_software) > 10 ){
$server_software = strtok($this->super->server['SERVER_SOFTWARE'], ' '); //Shorten to until the first space
}
echo '<li><i class="fa-solid fa-server"></i> Server Software: <strong title="' . $this->super->server['SERVER_SOFTWARE'] . '">' . $server_software . '</strong></li>';
echo '<li><i class="fa-solid fa-ethernet"></i> Server Protocol: <strong>' . $this->super->server['SERVER_PROTOCOL'] . '</strong></li>';
//MySQL version
global $wpdb;
$mysql_version = mysqli_get_client_version();
echo '<li><i class="fa-solid fa-database"></i> MySQL Version: <strong title="Raw: ' . $mysql_version . '">' . floor($mysql_version/10000) . '.' . floor(($mysql_version%10000)/100) . '.' . ($mysql_version%10000)%100 . '</strong> <small>(' . get_class($wpdb->dbh) . ')</small></li>'; //PHP 7.4 use numeric separators here
//PHP version
$php_version_class = '';
$php_version_info = '';
$php_version_cursor = 'normal';
$php_version_lifecycle = $this->php_version_support();
if ( !empty($php_version_lifecycle) ){
if ( $php_version_lifecycle['lifecycle'] === 'security' ){
$php_version_class = 'text-caution essential'; //Warning (orange)
$php_version_info = 'This version is nearing end of life. Security updates end on ' . date('F j, Y', $php_version_lifecycle['end']) . '.';
$php_version_cursor = 'help';
} elseif ( $php_version_lifecycle['lifecycle'] === 'end' ){
$php_version_class = 'text-danger essential'; //Danger (red)
$php_version_info = 'This version no longer receives security updates! End of life occurred on ' . date('F j, Y', $php_version_lifecycle['end']) . '.';
$php_version_cursor = 'help';
}
}
echo '<li class="essential"><i class="fa-solid fa-wrench"></i> PHP Version: <a class="' . $php_version_class . '" href="https://www.php.net/supported-versions.php" target="_blank" rel="noopener noreferrer" style="cursor: ' . $php_version_cursor . ';" title="' . $php_version_info . '"><strong>' . PHP_VERSION . '</strong></a> <small>(SAPI: <strong>' . php_sapi_name() . '</strong>)</small></li>';
//PHP memory limit
echo '<li><i class="fa-solid fa-memory"></i> PHP Memory Limit: <strong>' . ini_get('memory_limit') . '</strong></li>';
//Persistent Object Caching (Memcached or Redis)
$memory_cache_enabled = '<strong class="text-caution essential">Disabled</strong>';
if ( extension_loaded('memcache') ){
$memory_cache_enabled = '<strong>Memcache</strong>';
} elseif ( extension_loaded('memcached') ){
$memory_cache_enabled = '<strong>Memcached</strong>';
} elseif ( extension_loaded('redis') ){
$memory_cache_enabled = '<strong>Redis</strong>';
}
echo '<li title="This does not indicate that this memory cache extension is actually being used, just that it is loaded."><i class="fa-solid fa-box"></i> Memory Cache Ext.: ' . $memory_cache_enabled . '</li>';
$object_cache_hit_output = '';
if ( is_object($this->super->globals['wp_object_cache']) ){
$object_cache_hits = $this->super->globals['wp_object_cache']->cache_hits ?? null;
$object_cache_misses = $this->super->globals['wp_object_cache']->cache_misses ?? null;
if ( $object_cache_hits+$object_cache_misses > 0 ){
$object_cache_hit_rate = round(($object_cache_hits/($object_cache_hits+$object_cache_misses))*100, 1);
$object_cache_hit_rate_class = ( $object_cache_hit_rate < 80 )? 'text-caution' : '';
$object_cache_hit_output = ' <small class="' . $object_cache_hit_rate_class . '">(Hit Rate: ' . $object_cache_hit_rate . '%)</small>';
}
}
$using_wp_persistent_cache = ( wp_using_ext_object_cache() )? '<strong title="Caching will work across multiple pages">⚡ Persistent</strong>' : '<strong title="Caching will only happen on individual page request (not across multiple pages)">Non-Persistent</strong>';
echo '<li><i class="fa-solid fa-box"></i> WP Object Cache: ' . $using_wp_persistent_cache . $object_cache_hit_output . ' </li>';
//Bytecode Caching aka Opcode Cache (Zend Opcache)
$opcode_cache_name = '<strong class="text-danger essential">None</strong>';
if ( extension_loaded('Zend OPcache') ){
$opcode_cache_name = '<strong>Zend OPcache</strong>';
} elseif ( extension_loaded('opcache') ){
$opcode_cache_name = '<strong>OPcache</strong>';
}
$opcache_hit_rate = '';
if ( function_exists('opcache_get_status') ){
$opcache_status = @opcache_get_status(); //Using @ to suppress restriction errors by returning false instead
if ( is_array($opcache_status) && isset($opcache_status['opcache_enabled']) ){
$opcache_stats = null;
if ( isset($opcache_status['statistics']) && is_array($opcache_status['statistics']) ){
$opcache_stats = $opcache_status['statistics'];
} else if ( isset($opcache_status['opcache_statistics']) && is_array($opcache_status['opcache_statistics']) ){
$opcache_stats = $opcache_status['opcache_statistics'];
}
if ( $opcache_stats && isset($opcache_stats['opcache_hit_rate']) ){
$opcache_hit_rate_class = ( $opcache_stats['opcache_hit_rate'] < 85 )? 'text-caution' : '';
$opcache_hit_rate = ' <small class="' . $opcache_hit_rate_class . '" title="When the hit rate is low, PHP must recompile code more often, which increases page load time.">(Hit Rate: ' . round($opcache_stats['opcache_hit_rate'], 1) . '%)</small>';
}
if ( isset($opcache_status['opcache_enabled']) && $opcache_status['opcache_enabled'] == 0 ){
echo '<li class="essential text-caution"><i class="fa-solid fa-box"></i> Opcache Disabled</li>';
}
}
}
echo '<li><i class="fa-solid fa-box"></i> Opcode Cache: ' . $opcode_cache_name . $opcache_hit_rate . '</li>';
if ( function_exists('sys_getloadavg') ){
$load = sys_getloadavg();
if ( is_array($load) && count($load) >= 3 ){
list($load_1m, $load_5m, $load_15m) = $load;
//Check each value against the warning threshold
//Note: The thresholds are really dependent on how many CPU cores the server has. 1 process with 1 core = 100% utilization. However 1 process with 4 cores = 25% utilization.
$cpu_cores = apply_filters('nebula_cpu_cores', 1); //Allow developers to designate the number of CPU cores their server has to better reflect warning states for load averages
$caution_threshold = $cpu_cores*1; //100% utilization
$warning_threshold = $cpu_cores*2; //200% utilization
//Check each value against the thresholds and assign classes accordingly
//Note: Removing text color classes using "-off" until better thresholding is possible
$class_1m = '';
if ( $load_1m > $warning_threshold ){
$class_1m = 'essential text-danger-off';
} elseif ( $load_1m > $caution_threshold ){
$class_1m = 'essential text-caution-off';
}
$class_5m = '';
if ( $load_5m > $warning_threshold ){
$class_5m = 'essential text-danger-off';
} elseif ( $load_5m > $caution_threshold ){
$class_5m = 'essential text-caution-off';
}
$class_15m = '';
if ( $load_15m > $warning_threshold ){
$class_15m = 'essential text-danger-off';
} elseif ( $load_15m > $caution_threshold ){
$class_15m = 'essential text-caution-off';
}
//Increasing or decreasing load
$load_icon = '<i class="fa-solid fa-network-wired"></i>'; //Default for steady traffic
if ( $load_1m > $load_5m && $load_5m > $load_15m ){
$load_icon = '<i class="fa-solid fa-arrow-trend-up caution-color" title="Traffic increasing"></i>';
}else if ( $load_1m < $load_5m && $load_5m < $load_15m ){
$load_icon = '<i class="fa-solid fa-arrow-trend-down caution-color" title="Traffic decreasing"></i>';
}
echo '<li title="Average number of processes waiting for CPU (higher = busier). Caution thresholds depend on the amount of CPU cores (which can be set with a Nebula hook).">' . $load_icon . ' Load Avg: <span class="' . $class_1m . '" title="1 minute"><strong>' . number_format($load_1m, 2) . '</strong> <em>(1 min)</em></span>, <span class="' . $class_5m . '" title="5 minutes"><strong>' . number_format($load_5m, 2) . '</strong> <em>(5 min)</em></span>, <span class="' . $class_15m . '" title="15 minutes"><strong>' . number_format($load_15m, 2) . '</strong> <em>(15 min)</em></span></li>';
}
}
//Count total WordPress updates available
require_once ABSPATH . 'wp-admin/includes/update.php';
$update_data = wp_get_update_data();
$updates_count = $update_data['counts']['total'];
if ( $updates_count > 0 ){
$updates_class = '';
if ( $updates_count > 10 ){ //If there are many updates available
$updates_class = 'text-danger essential';
} elseif ( $updates_count >= 1 ){ //If even 1 update is available
$updates_class = 'essential';
}
$updates_count = '<a class="' . $updates_class . '" href="update-core.php">' . $updates_count . ' »</a>';
echo '<li><i class="fa-regular fa-circle-up"></i> Updates Available: <strong>' . $updates_count . '</strong></li>';
}
//Check SMTP mail status
$smtp_status = $this->check_smtp_status();
$smtp_status_output = ''; //Empty unless there is a problem
if ( strpos(strtolower($smtp_status), 'error') != false ){
$smtp_status_output = '<a href="edit.php?post_type=nebula_cf7_submits"><strong class="text-danger essential"><i class="fa-solid fa-exclamation-triangle"></i> ' . $smtp_status . '</strong></a>';
} elseif ( strtolower($smtp_status) == 'unknown' ){
$smtp_status_output = '<a href="edit.php?post_type=nebula_cf7_submits"><em class="text-caution">Unable to Check</em></a>';
}
if ( !empty($smtp_status_output) ){
echo '<li><i class="fa-solid fa-envelope"></i> SMTP Status: ' . $smtp_status_output . '</li>';
}
//404 Counts
$nebula_404_count = $this->get_404_count();
$redirection_404_count = 0;
if ( is_plugin_active('redirection/redirection.php') ){
$redirection_404_count = $this->transient('redirection_404_count', function(){
global $wpdb;
//Count the rows in PHP (instead of MySQL) to avoid processing the entire DB table
$results = $wpdb->get_col($wpdb->prepare(
'SELECT http_code FROM ' . $wpdb->prefix . 'redirection_404
WHERE http_code = 404
AND created >= %s
LIMIT 1000',
date('Y-m-d H:i:s', strtotime('-24 hours'))
));
return count($results);
}, HOUR_IN_SECONDS);
}
if ( !empty($nebula_404_count) || !empty($redirection_404_count) ){ //If either 404 counter has non-0 data, output it
$redirection_404_description = '';
$nebula_404_description = '';
$need_404_labels = ( isset($nebula_404_count) && !empty($redirection_404_count) )? true : false; //If both systems are active, we need to label the outputs
if ( !empty($redirection_404_count) ){
if ( $redirection_404_count >= 999 ){ //If we reached the limit from the above query, assume there are more that weren't counted
$redirection_404_count = '<span class="text-danger"><i class="fa-solid fa-exclamation-triangle"></i> 1,000+</span>';
} elseif ( $redirection_404_count >= 500 ){
$redirection_404_count = '<span class="text-caution">' . $redirection_404_count . '</span>';
}
$total_label = ( $need_404_labels )? ' total' : '';
$redirection_404_description = '<strong title="Total count is from the Redirection plugin."><a href="tools.php?page=redirection.php&sub=404s&groupby=url">' . $redirection_404_count . $total_label . '</a></strong>';
}
if ( isset($nebula_404_count) ){ //Even if it is 0
$user_label = ( $need_404_labels )? ' user' : '';
$output_404_delimiter = ( !empty($redirection_404_count) )? ', ' : ''; //If we also have Redirection 404s we need a delimiter
$user_label_color = ( $nebula_404_count > 500 )? 'text-danger' : '';
$nebula_404_description = $output_404_delimiter . '<a class="' . $user_label_color . '" href="' . admin_url('?log-viewer=nebula_analytics_404_views') . '" title="This Nebula count attempts to track only human 404 views.">' . number_format($nebula_404_count) . $user_label . '</a>'; //Note that Nebula only performs surface level bot detection, so this metric will likely still include some/many bots
}
echo '<li class="essential"><i class="fa-regular fa-file-excel"></i> 404s: ' . $redirection_404_description . $nebula_404_description . ' <small>(Last 24 hours)</small></li>';
}
//Check if parent theme files have been modified (this is in the developer info metabox, but also happens in the Nebula metabox)
$modified_files = get_transient('nebula_theme_modified_files');
if ( !empty($modified_files) ){
$file_count = count($modified_files);
$title_attr = implode("\n", $modified_files); //Join file names with new lines for the title attribute
$time_ago = human_time_diff(get_transient('nebula_theme_file_changes_check'));
$title_attr .= "\n\n Last checked " . $time_ago . " ago";
echo '<li><i class="fa-solid fa-square-binary"></i> <span class="essential text-caution cursor-help" title="' . esc_attr($title_attr) . '"><strong>' . $file_count . '</strong> Parent theme ' . $this->singular_plural($file_count, 'file has', 'files have') . ' been modified</span></li>';
}
if ( $this->is_transients_enabled() ){
//Theme directory size(s)
if ( is_child_theme() ){
$nebula_parent_size = $this->transient('nebula_directory_size_parent_theme', function(){
return $this->foldersize(get_template_directory());
}, DAY_IN_SECONDS);
$nebula_child_size = $this->transient('nebula_directory_size_child_theme', function(){
return $this->foldersize(get_stylesheet_directory());
}, DAY_IN_SECONDS);
echo '<li><i class="fa-solid fa-code"></i> Parent theme directory size: <strong>' . $this->format_bytes($nebula_parent_size, 1) . '</strong> </li>';
echo '<li><i class="fa-solid fa-code"></i> Child theme directory size: <strong>' . $this->format_bytes($nebula_child_size, 1) . '</strong> </li>';
} else {
$nebula_size = $this->transient('nebula_directory_size_theme', function(){
return $this->foldersize(get_stylesheet_directory());
}, DAY_IN_SECONDS);
echo '<li><i class="fa-solid fa-code"></i> Theme directory size: <strong>' . $this->format_bytes($nebula_size, 1) . '</strong> </li>';
}
//Plugins directory size (and count)
$plugins_size = $this->transient('nebula_directory_size_plugins', function(){
$plugins_dir = WP_CONTENT_DIR . '/plugins';
return $this->foldersize($plugins_dir);
}, HOUR_IN_SECONDS*36);
$all_plugins = $this->transient('nebula_count_plugins', function(){
return get_plugins();
}, WEEK_IN_SECONDS);
$active_plugins = get_option('active_plugins', array());
echo '<li><i class="fa-solid fa-plug"></i> Plugins directory size: <strong>' . $this->format_bytes($plugins_size, 1) . '</strong> <small>(' . count($active_plugins) . ' active of ' . count($all_plugins) . ' installed)</small></li>';
}
do_action('nebula_dev_dashboard_directories');
//Uploads directory size (and max upload size)
if ( $this->is_transients_enabled() ){
$uploads_size = $this->transient('nebula_directory_size_uploads', function(){
$upload_dir = wp_upload_dir();
return $this->foldersize($upload_dir['basedir']);
}, HOUR_IN_SECONDS*36);
}
if ( function_exists('wp_max_upload_size') ){
$upload_max = '<small>(Max upload: <strong>' . $this->format_bytes(((int) wp_max_upload_size())) . '</strong>)</small>';
} elseif ( ini_get('upload_max_filesize') ){
$upload_max = '<small>(Max upload: <strong>' . ini_get('upload_max_filesize') . '</strong>)</small>';
} else {
$upload_max = '';
}
echo '<li><i class="fa-solid fa-images"></i> Uploads directory size: <strong>' . $this->format_bytes($uploads_size, 1) . '</strong> ' . $upload_max . '</li>';
//PHP Disk Space
if ( function_exists('disk_total_space') && function_exists('disk_free_space') ){
$disk_total_space = disk_total_space(ABSPATH);
$disk_free_space = disk_free_space(ABSPATH);
if ( !empty($disk_total_space) ){ //Ignore when this results in 0 bytes total
$disk_space_percent_used = round((($disk_total_space-$disk_free_space)/$disk_total_space)*100);
$disk_usage_class = '';
if ( $disk_free_space/GB_IN_BYTES < 10 || $disk_space_percent_used > 85 ){
$disk_usage_class = 'text-caution'; //Warning
if ( $disk_free_space/GB_IN_BYTES < 5 || $disk_space_percent_used > 95 ){
$disk_usage_class = 'text-danger'; //Danger
}
}
echo '<li><i class="fa-solid fa-hdd"></i> Disk Space Available: <strong class="' . $disk_usage_class . '">' . $this->format_bytes($disk_free_space, 1) . '</strong> <small class="' . $disk_usage_class . '">(Using ' . $disk_space_percent_used . '% of <strong>' . $this->format_bytes($disk_total_space) . '</strong> total)</small></li>';
}
}
//WP Database Size
echo '<li><i class="fa-solid fa-database"></i> WP Database Size: <strong>' . $this->format_bytes($this->get_database_size()) . '</strong></li>';
//Link to Query Monitor Environment Panel
//if ( is_plugin_active('query-monitor/query-monitor.php') ){
//echo '<li><i class="fa-solid fa-table"></i> <a href="#qm-environment">Additional Server Information <small>(Query Monitor)</small></a></li>'; //Not currently possible: https://github.com/johnbillion/query-monitor/issues/622
//}
//Log Files
foreach ( $this->get_log_files('all', true) as $types ){ //Always get fresh data here
foreach ( $types as $log_file ){
if ( file_exists($log_file['path']) && !empty($log_file['bytes']) && $log_file['bytes'] > 999 ){ //Only show the file if it has a size and is at least 1kb
//If it was recently modified, that means there was a recent error/entry
$log_file_modified_time = filemtime($log_file['path']);
$log_file_classes = '';
$log_file_icon = '';
if ( time()-$log_file_modified_time <= HOUR_IN_SECONDS*8 ){
$log_file_classes .= ' text-caution';
$log_file_icon = '<i class="fa-regular fa-clock"></i>';
}
echo '<li class="essential"><i class="fa-regular fa-file-alt"></i> <a href="' . admin_url('?log-viewer=' . $log_file['shortpath']) . '"><code title="' . $log_file['shortpath'] . ' (Click to show in Log Viewer)" style="cursor: help;">' . $log_file['name'] . '</code></a> <strong>' . $this->format_bytes($log_file['bytes']) . '</strong> <small class="' . $log_file_classes . '">(Latest: ' . human_time_diff($log_file_modified_time) . ' ago)</small></li>';
}
}
}
//Fatal error count
if ( $this->is_transients_enabled() ){
$fatal_error_count = $this->transient('fatal_error_count', function(){
return $this->count_fatal_errors();
}, HOUR_IN_SECONDS);
if ( !empty($fatal_error_count) ){
$fatal_error_count_description = '';
if ( intval($fatal_error_count) ){ //If the result is a number (not a string which represents a problem)
$fatal_error_count_description = ' <small>(last 7 days)</small>';
}
echo '<li class="essential text-danger"><i class="fa-solid fa-bug"></i> Fatal Errors: <strong><a class="text-danger" href="' . ini_get('error_log') . '" target="_blank">' . $fatal_error_count . '</a></strong>' . $fatal_error_count_description . '</li>'; //The <a> tag is just to show the location of the error log file
}
}
//Service Worker
if ( $this->get_option('service_worker') ){
if ( !is_ssl() ){
echo '<li><i class="fa-solid fa-microchip" class="text-danger"></i> <strong>Not</strong> using service worker. No SSL.</li>';
} elseif ( !file_exists($this->sw_location(false)) ){
echo '<li><i class="fa-solid fa-microchip" class="text-danger"></i> <strong>Not</strong> using service worker. Service worker file does not exist.</li>';
} else {
echo '<li><i class="fa-solid fa-microchip"></i> Using service worker</li>';
}
}
//Initial installation date
function initial_install_date(){
$nebula_initialized = nebula()->get_option('initialized'); //Keep this as nebula() because it is a nested function, so $this is scoped differently here.
if ( !empty($nebula_initialized) && $nebula_initialized < getlastmod() ){
$install_date = '<span title="' . date('F j, Y', $nebula_initialized) . ' @ ' . date('g:ia', $nebula_initialized) . '" style="cursor: help;"><strong>' . human_time_diff($nebula_initialized) . ' ago</strong></span>';
} else { //Use the last modified time of the admin page itself
$install_date = '<span title="' . date("F j, Y", getlastmod()) . ' @ ' . date("g:ia", getlastmod()) . '" style="cursor: help;"><strong>' . human_time_diff(getlastmod()) . ' ago</strong></span>';
}
return $install_date;
}
echo '<li><i class="fa-regular fa-calendar"></i> Installed: ' . initial_install_date() . '</li>';
$latest_file = $this->last_modified();
echo '<li class="essential"><i class="fa-regular fa-calendar"></i> <span title="' . $latest_file['path'] . '" style="cursor: help;">Modified:</span> <span title="' . date("F j, Y", $latest_file['date']) . ' @ ' . date("g:ia", $latest_file['date']) . '" style="cursor: help;"><strong>' . human_time_diff($latest_file['date']) . ' ago</strong></span></li>';
//SCSS last processed date
if ( $this->get_data('scss_last_processed') ){
$sass_option = ( $this->get_option('scss') )? '' : ' <small><em><a href="themes.php?page=nebula_options&tab=functions&option=scss">Sass is currently <strong>disabled</strong> »</a></em></small>';
echo '<li class="essential"><i class="fa-brands fa-sass"></i> Sass Processed: <span title="' . date("F j, Y", $this->get_data('scss_last_processed')) . ' @ ' . date("g:i:sa", $this->get_data('scss_last_processed')) . '" style="cursor: help;"><strong>' . human_time_diff($this->get_data('scss_last_processed')) . ' ago</strong></span> ' . $sass_option . '</li>';
}
echo '<li><i class="fa-brands fa-wordpress"></i> <a href="site-health.php?tab=debug">WP Site Info »</a></li>'; //Link to WP Health Check Info page
echo '<li class="expand-simplified-view essential"><a href="#">...Expand full list <i class="fa-solid fa-caret-down"></i></a></li>';
echo '</ul>';
//Directory search
$directory_search_options = array('uploads' => '<option value="uploads">Uploads</option>');
if ( is_child_theme() ){
$directory_search_options['child'] = '<option value="child" selected="selected">Child Theme</option>';
$directory_search_options['parent'] = '<option value="parent">Parent Theme</option>';
} else {
$directory_search_options['theme'] = '<option value="theme" selected="selected">Theme</option>';
}
//Must-Use Plugins (if any exist)
if ( is_dir(WPMU_PLUGIN_DIR) && is_array(scandir(WPMU_PLUGIN_DIR)) ){
$directory_search_options['mu_plugins'] = '<option value="mu_plugins">Must-Use Plugins</option>';
}
//Add active plugins to search list
$directory_search_options['all_plugins'] = '<option value="all_plugins">All Plugins</option>';
$all_plugins = get_plugins();
foreach ( $all_plugins as $plugin => $plugin_data ){
$plugin_name = $plugin_data['Name'];
$safe_plugin_name = str_replace(array(' ', '-', '/'), '_', strtolower($plugin_name));
$inactive_indicator = ( is_plugin_active($plugin) )? '' : ' (Inactive)';
$directory_search_options[$safe_plugin_name] = '<option value="' . $safe_plugin_name . '">' . $plugin_name . $inactive_indicator . '</option>';
}
$all_directory_search_options = apply_filters('nebula_directory_search_options', $directory_search_options); //Allow other functions to hook in to add directories to search
echo '<form id="theme" class="searchfiles"><i id="searchprogress" class="fa-solid fa-magnifying-glass"></i> <input class="findterm" type="text" placeholder="Search files" autocorrect="off" autocapitalize="off" spellcheck="false" /><select class="searchdirectory">';
foreach ( $all_directory_search_options as $name => $option_html ){
echo $option_html;
}
echo '</select><input class="searchterm button button-primary button-disabled" type="submit" value="Search" title="Still loading... Please wait." /></form>';
echo '<div class="search_results"></div>';
$this->timer('Nebula Developer Dashboard Metabox', 'end');
}
Override
This function can not be short-circuited with an override filter. Request one?