Skip to Content
Menu

dashboard_developer_info()

PHP October 10, 2017

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!

Was this page helpful? Yes No


    A feedback message is required to submit this form.


    Please check that you have entered a valid email address.

    Enter your email address if you would like a response.

    Thank you for your feedback!

    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 . ' &raquo;</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> &raquo;</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 &raquo;</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?