Usage
PHP
nebula()->check_warnings()
Parameters
This function does not accept any parameters. Is this incorrect?
Additional Notes
This function will return an array of warnings/errors and other logs, but is only available to admins and developers.
Source File
Located in /libs/Utilities/Warnings.php on line 68.
1 Hook
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_warnings"Need a new filter hook? Request one here.
Actions
This function has no action hooks available. Request one?Note: This function contains 2 to-do comments.
PHP
public function check_warnings(){ if ( $this->is_ajax_request() ){ return false; } if ( $this->is_auditing() || $this->is_warning_level('on') ){ //Check object cache first $nebula_warnings = wp_cache_get('nebula_warnings'); if ( is_array($nebula_warnings) || !empty($nebula_warnings) ){ //If it is an array (meaning it has run before but did not find anything) or if it is false return $nebula_warnings; } $this->timer('Check Warnings'); $nebula_warnings = array(); //Prep the warnings array to fill //Admin warnings only if ( $this->is_admin_page() ){ //Check page slug against taxonomy terms. global $pagenow; if ( $pagenow === 'post.php' || $pagenow === 'edit.php' ){ global $post; if ( !empty($post) ){ //If the listing has results foreach ( get_taxonomies() as $taxonomy ){ //Loop through all taxonomies foreach ( get_terms($taxonomy, array('hide_empty' => false)) as $term ){ //Loop through all terms within each taxonomy if ( $term->slug === $post->post_name ){ //If this page slug matches a taxonomy term $nebula_warnings['slug_conflict'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-link"></i> Slug conflict with ' . ucwords(str_replace('_', ' ', $taxonomy)) . ': <strong>' . $term->slug . '</strong> - Consider changing this page slug.' ); return false; } } } } } //Test the WordPress filesystem method $fs_method_transient = get_transient('nebula_fs_method'); if ( empty($fs_method_transient) || $this->is_debug() ){ if ( file_exists(get_template_directory() . '/style.css') ){ WP_Filesystem(); global $wp_filesystem; $test_file = $wp_filesystem->get_contents(get_template_directory() . '/style.css'); if ( empty($test_file) ){ $nebula_warnings['file_permissions'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-server"></i> File system permissions error. Consider changing the FS_METHOD in wp-config.php.', ); } else { set_transient('nebula_fs_method', true); //On success, set a transient. No expiration. } } } } //If the site is served via HTTPS but the Site URL is still set to HTTP if ( (is_ssl() || isset($this->super->server['HTTPS'])) && (strpos(home_url(), 'http://') !== false || strpos(get_option('siteurl'), 'http://') !== false) ){ //@todo "Nebula" 0: Update strpos() to str_contains() in PHP8 $nebula_warnings['site_url_http'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-lock-open"></i> <a href="options-general.php">Website Address</a> settings are http but the site is served from https.', 'url' => admin_url('options-general.php') ); } //If search indexing is disabled if ( get_option('blog_public') == 0 ){ //Stored as a string $nebula_warnings['search_visibility'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-brands fa-fw fa-searchengin"></i> <a href="options-reading.php">Search Engine Visibility</a> is currently disabled! Therefore, additional SEO checks were not performed.', 'url' => admin_url('options-reading.php') ); } else { if ( $this->is_transients_enabled() ){ //Only check these if transients are not suspended //Check for sitemap $sitemap_transient = get_transient('nebula_check_sitemap'); if ( empty($sitemap_transient) || $this->is_debug() ){ $sitemap_warning = false; if ( is_plugin_active('wordpress-seo/wp-seo.php') ){ //Yoast if ( !$this->is_available(home_url('/') . 'sitemap_index.xml', false, true) ){ $sitemap_warning = true; $nebula_warnings['missing_sitemap'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-sitemap"></i> Missing sitemap XML. Yoast is enabled, but <a href="' . home_url('/') . 'sitemap_index.xml" target="_blank">sitemap_index.xml</a> is unavailable.' ); } } elseif ( is_plugin_active('autodescription/autodescription.php') ){ //The SEO Framework if ( !$this->is_available(home_url('/') . 'sitemap.xml', false, true) ){ $sitemap_warning = true; $nebula_warnings['missing_sitemap'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-sitemap"></i> Missing sitemap XML. The SEO Framework is enabled, but <a href="' . home_url('/') . 'sitemap.xml" target="_blank">sitemap.xml</a> is unavailable.' ); } } else { if ( !$this->is_available(home_url('/') . 'wp-sitemap.xml', false, true) ){ //WordPress Core $sitemap_warning = true; $nebula_warnings['missing_sitemap'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-sitemap"></i> Missing sitemap XML. WordPress core <a href="' . home_url('/') . 'wp-sitemap.xml" target="_blank">sitemap_index.xml</a> is unavailable.' ); //Check if the SimpleXML PHP module is installed on the server (required for WP core sitemap generation) if ( !function_exists('simplexml_load_string') ){ $sitemap_warning = true; $nebula_warnings['simplexml'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-sitemap"></i> SimpleXML PHP module is not available. This is required for WordPress core sitemap generation.' ); } } } //If there is no warning, only check periodically if ( !$sitemap_warning ){ set_transient('nebula_check_sitemap', 'Sitemap Found', WEEK_IN_SECONDS); } } } //If not pinging additional update services (blog must be public for this to be available) if ( !is_multisite() && $this->is_warning_level('verbose') ){ //This option is unavailable on Multisite installs of WP $ping_sites = get_option('ping_sites'); if ( $ping_sites === 'http://rpc.pingomatic.com/' ){ //If it only has the default value (ignore empty value if that is done intentionally) $nebula_warnings['update_services'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-rss"></i> Additional <a href="options-writing.php">Update Services</a> should be pinged. <a href="https://codex.wordpress.org/Update_Services#XML-RPC_Ping_Services" target="_blank" rel="noopener">Recommended update services »</a>', 'url' => admin_url('options-writing.php') ); } } } //Check PHP version $php_version_lifecycle = $this->php_version_support(); if ( !empty($php_version_lifecycle) ){ if ( $php_version_lifecycle['lifecycle'] === 'security' ){ if ( $php_version_lifecycle['end']-time() < MONTH_IN_SECONDS ){ //If end of life is within 1 month $nebula_warnings['php_lifecycle_main'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-brands fa-fw fa-php"></i> PHP <strong>' . PHP_VERSION . '</strong> <a href="http://php.net/supported-versions.php" target="_blank" rel="noopener">is nearing end of life</a>. Security updates end in ' . human_time_diff($php_version_lifecycle['end']) . ' on ' . date('F j, Y', $php_version_lifecycle['end']) . '.', 'url' => 'http://php.net/supported-versions.php', 'meta' => array('target' => '_blank', 'rel' => 'noopener') ); } } elseif ( $php_version_lifecycle['lifecycle'] === 'end' ){ $nebula_warnings['php_lifecycle_end'] = array( 'level' => 'error', 'dismissible' => false, 'description' => '<i class="fa-brands fa-fw fa-php"></i> PHP ' . PHP_VERSION . ' <a href="http://php.net/supported-versions.php" target="_blank" rel="noopener">no longer receives security updates</a>! End of life occurred ' . human_time_diff($php_version_lifecycle['end']) . ' ago on ' . date('F j, Y', $php_version_lifecycle['end']) . '.', 'url' => 'http://php.net/supported-versions.php', 'meta' => array('target' => '_blank', 'rel' => 'noopener') ); } } //Check specific directories for indexing (Apache directory listings) if ( $this->is_transients_enabled() ){ //Don't run these checks without transients because they are too time consuming to run every admin page load $directory_indexing = get_transient('nebula_directory_indexing'); if ( empty($directory_indexing) || nebula()->is_debug() || nebula()->is_auditing() ){ //Use the transient unless ?debug or explicitly auditing $directories = array(includes_url(), content_url()); //Directories to test $found_problem = false; foreach ( $directories as $directory ){ //Get the contents of the directory $directory_request = $this->remote_get($directory, array( 'timeout' => 3, 'limit_response_size' => KB_IN_BYTES*512 //Limit the response to 512kb )); if ( !is_wp_error($directory_request) && !empty($directory_request) ){ //If not an error and response exists if ( $directory_request['response']['code'] <= 400 ){ //Check if the response code is less than 400 (in this case 400+ is good) if ( strpos(strtolower($directory_request['body']), 'index of') ){ //Check if the "Index of" text appears in the body content (bad) //@todo "Nebula" 0: Update strpos() to str_contains() in PHP8 $nebula_warnings['directory_indexing'] = array( 'level' => 'error', 'dismissible' => false, 'description' => '<i class="fa-regular fa-fw fa-list-alt"></i> Directory indexing is not disabled. Visitors can see file listings of directories!', ); $found_problem = true; set_transient('nebula_directory_indexing', 'bad', WEEK_IN_SECONDS); break; //Exit loop since we found an issue } } } } //If we did not find a problem, set a longer transient if ( empty($found_problem) ){ set_transient('nebula_directory_indexing', 'good'); //No expiration so it is not cleared when making new posts } } else { if ( $directory_indexing === 'bad' ){ $nebula_warnings['directory_indexing'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-regular fa-fw fa-list-alt"></i> <strong>Directory indexing not disabled</strong> (at the time last checked). Visitors may be able to see file listings of directories such as the <a href="' . includes_url() . '" target="_blank">Includes URL</a> or <a href="' . content_url() . '" target="_blank">Content URL</a> (and/or others)! <a href="' . home_url('/?audit=true') . '" target="_blank">Run an audit to re-scan »</a>', ); } } } //Check individual files for anything unusual if ( nebula()->is_auditing() ){ //Only check all files when auditing $directories_to_scan = array(ABSPATH . '/wp-admin', ABSPATH . '/wp-includes', get_template_directory(), get_stylesheet_directory()); //Change this to simply ABSPATH to scan the entire WordPress directory foreach ( $directories_to_scan as $directory ){ foreach ( $this->glob_r($directory . '/*') as $file ){ if ( !$this->contains($file, array('/cache', '/uploads')) ){ //Skip certain directories if ( is_file($file) ){ //If file was last modified before the year 2000 if ( filemtime($file) < 946702800 ){ //PHP 7.4 use numeric separators here $nebula_warnings['unusual_filemtime'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-hourglass-start"></i> <strong>' . $file . '</strong> was last modified on ' . date('F j, Y', filemtime($file)) . '. This is somewhat unusual and should be looked into.' ); } //If the file size is larger than 10mb if ( filesize($file) > MB_IN_BYTES*10 ){ $filesize = ( function_exists('bcdiv') )? bcdiv(filesize($file), MB_IN_BYTES, 0) : number_format(filesize($file)/MB_IN_BYTES, 2); $nebula_warnings['large_file'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-file"></i> <strong>' . $file . '</strong> has a large filesize of ' . $filesize . 'mb.' ); } } } } } } else { //Otherwise just check a few files foreach ( $this->get_log_files('all') as $types ){ foreach ( $types as $log_file ){ if ( $log_file['bytes'] > MB_IN_BYTES*25 ){ $nebula_warnings[] = array( //No key on this one so they do not overwrite when multiple are present 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-weight"></i> Large debug file: <strong>' . $log_file['shortpath'] . '</strong> (' . $this->format_bytes($log_file['bytes'], 1) . ') <small><a href="' . esc_url(add_query_arg('debug', 'true')) . '">Re-Scan?</a></small>', ); } } } } //Check for hard Debug Mode //We do not check for WP_DEBUG_LOG as it can intentionally be used on live websites. Nebula does warn when the log file gets large and indicates when it exists in the Developer Info Dashboard Metabox. if ( $this->is_warning_level('verbose') && WP_DEBUG ){ if ( wp_get_environment_type() === 'production' ){ //Do not warn in development environments $nebula_warnings['wp_debug'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-bug"></i> <strong>WP_DEBUG</strong> is enabled <small>(Generally defined in wp-config.php)</small>' ); if ( WP_DEBUG_DISPLAY ){ $nebula_warnings['wp_debug_display'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-bug"></i> Debug errors and warnings are being displayed on the front-end (<Strong>WP_DEBUG_DISPLAY</strong>) <small>(Generally defined in wp-config.php)</small>' ); } } } //Check if logging JavaScript errors if ( $this->get_option('js_error_log') ){ $js_log_file = get_stylesheet_directory() . '/js_error.log'; $js_error_log_filesize = ''; if ( file_exists($js_log_file) ){ $js_error_log_filesize = ' (' . $this->format_bytes(filesize($js_log_file), 1) . ')'; } $nebula_warnings['js_error_log'] = array( 'level' => 'warning', 'dismissible' => false, 'description' => '<i class="fa-solid fa-fw fa-hard-hat"></i> <strong><a href="themes.php?page=nebula_options&tab=administration" target="_blank">JS Error Logging</a></strong> is active: <strong>' . str_replace(ABSPATH, '', $js_log_file) . '</strong>' . $js_error_log_filesize, 'url' => admin_url('themes.php?page=nebula_options&tab=administration') ); } //Check for Safe Mode if ( $this->is_safe_mode() ){ $nebula_warnings['safe_mode'] = array( 'level' => 'error', 'dismissible' => false, 'description' => '<i class="fa-solid fa-fw fa-hard-hat"></i> <strong>Nebula Safe Mode</strong> is active <small>(' . WPMU_PLUGIN_DIR . '/nebula-safe-mode.php)</small>' ); } //Check for Google Analytics Measurement ID if ( !$this->get_option('ga_measurement_id') && !$this->get_option('gtm_id') ){ $nebula_warnings['ga_measurement_id'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-chart-area"></i> A <a href="themes.php?page=nebula_options&tab=analytics&option=ga_measurement_id">Google Analytics tracking ID</a> or <a href="themes.php?page=nebula_options&tab=analytics&option=gtm_id">Google Tag Manager ID</a> is strongly recommended!', 'url' => admin_url('themes.php?page=nebula_options&tab=analytics') ); } //If Enhanced Ecommerce Plugin is missing Google Analytics Tracking ID if ( is_plugin_active('enhanced-e-commerce-for-woocommerce-store/woocommerce-enhanced-ecommerce-google-analytics-integration.php') ){ $ee_ga_settings = get_option('woocommerce_enhanced_ecommerce_google_analytics_settings'); if ( empty($ee_ga_settings['ga_id']) ){ $nebula_warnings['enhanced_ecommerce'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-chart-area"></i> <a href="admin.php?page=wc-settings&tab=integration">WooCommerce Enhanced Ecommerce</a> is missing a Google Analytics ID!', 'url' => admin_url('admin.php?page=wc-settings&tab=integration') ); } } //Child theme checks if ( is_child_theme() ){ //Check if the parent theme template is correctly referenced $active_theme = wp_get_theme(); if ( !file_exists(dirname(get_stylesheet_directory()) . '/' . $active_theme->get('Template')) ){ $nebula_warnings['no_parent_theme'] = array( 'level' => 'error', 'dismissible' => false, 'description' => '<i class="fa-solid fa-fw fa-baby-carriage"></i> A child theme is active, but its parent theme directory <strong>' . $active_theme->get('Template') . '</strong> does not exist!<br/><em>The "Template:" setting in the <a href="' . get_stylesheet_uri() . '" target="_blank" rel="noopener">style.css</a> file of the child theme must match the directory name (above) of the parent theme.</em>' ); } //Check if child theme is missing img meta files if ( is_dir(get_stylesheet_directory() . '/assets/img/meta') && file_exists(get_stylesheet_directory() . '/assets/img/meta/favicon.ico') ){ //Check to ensure that child theme meta graphics are not identical to Nebula parent theme meta graphics foreach( glob(get_stylesheet_directory() . '/assets/img/meta/*.*') as $child_theme_meta_image ){ $parent_theme_meta_image = str_replace(get_stylesheet_directory(), get_template_directory(), $child_theme_meta_image); //Check if the images are the same if ( file_exists($child_theme_meta_image) && file_exists($parent_theme_meta_image) && md5_file($child_theme_meta_image) === md5_file($parent_theme_meta_image) ){ //Compare the two files to see if they are identical $child_filename = str_replace(get_stylesheet_directory(), '', $child_theme_meta_image); $nebula_warnings['child_meta_graphics'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-images"></i> Child theme meta graphics exist, but are identical to the Nebula meta graphics (' . $child_filename . '). Ensure that child theme meta graphics are unique to this website!</em>' ); break; //Exit the loop as soon as we find a match } } } else { $nebula_warnings['child_meta_graphics'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-regular fa-fw fa-images"></i> A child theme is active, but missing meta graphics. Create a <code>/assets/img/meta/</code> directory in the child theme (or copy it over from the Nebula parent theme).</em>' ); } } //Check if Relevanssi has built an index for search if ( is_plugin_active('relevanssi/relevanssi.php') ){ if ( !get_option('relevanssi_indexed') ){ $nebula_warnings['relevanssi_index'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-magnifying-glass-plus"></i> <a href="options-general.php?page=relevanssi%2Frelevanssi.php&tab=indexing">Relevanssi</a> must build an index to search the site. This must be triggered manually.', 'url' => admin_url('options-general.php?page=relevanssi%2Frelevanssi.php&tab=indexing') ); } if ( get_option('relevanssi_index_fields') === 'none' ){ $nebula_warnings['relevanssi_custom_fields'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-magnifying-glass-plus"></i> <a href="options-general.php?page=relevanssi%2Frelevanssi.php&tab=indexing">Relevanssi</a> is not set to search custom fields.', 'url' => admin_url('options-general.php?page=relevanssi%2Frelevanssi.php&tab=indexing') ); } } //Service Worker checks if ( $this->get_option('service_worker') ){ //Check for Service Worker JavaScript file when using Service Worker if ( !file_exists($this->sw_location(false)) ){ $nebula_warnings['sw_missing'] = array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-regular fa-fw fa-file"></i> Service Worker is enabled in <a href="themes.php?page=nebula_options&tab=functions&option=service_worker">Nebula Options</a>, but no Service Worker JavaScript file was found. Either use the <a href="https://github.com/chrisblakley/Nebula/blob/main/Nebula-Child/resources/sw.js" target="_blank">provided sw.js file</a> (by moving it to the root directory), or override the function <a href="https://nebula.gearside.com/functions/sw_location/?utm_campaign=documentation&utm_medium=admin+notice&utm_source=service+worker#override" target="_blank">sw_location()</a> to locate the actual JavaScript file you are using.' ); } //Check for /offline page when using Service Worker if ( $this->is_warning_level('verbose') ){ $offline_page = get_page_by_path('offline'); if ( is_null($offline_page) ){ $nebula_warnings['sw_offline'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-ethernet"></i> It is recommended to make an Offline page when using Service Worker. <a href="post-new.php?post_type=page">Manually add one</a>' ); } } //Check for SSL when using Service Worker if ( !is_ssl() ){ $nebula_warnings['sw_ssl'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-lock-open"></i> Service Worker requires an SSL. Either update the site to https or <a href="themes.php?page=nebula_options&tab=functions&option=service_worker">disable Service Worker</a>.' ); } } //Check for "Just Another WordPress Blog" tagline if ( strtolower(get_bloginfo('description')) === 'just another wordpress site' ){ $nebula_warnings['default_tagline'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<a href="options-general.php">Site Tagline</a> is still "Just Another WordPress Site"!', 'url' => admin_url('options-general.php') ); } //Ensure a privacy policy is set with WordPress core if ( empty(get_privacy_policy_url()) ){ $nebula_warnings['missing_privacy_policy'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-file-alt"></i> <a href="options-privacy.php">Privacy policy</a> is not setup with WordPress.', 'url' => admin_url('options-privacy.php') ); } else { //Ensure a privacy policy is set with WordPress core if ( get_privacy_policy_url() == get_home_url() ){ $nebula_warnings['privacy_policy_is_frontpage'] = array( 'level' => 'warning', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-file-alt"></i> <a href="options-privacy.php">Privacy policy</a> cannot be the Front Page.', 'url' => admin_url('options-privacy.php') ); } } //Check if all Sass files were processed if ( !empty($this->sass_process_status) ){ $nebula_warnings['sass_status'] = array( 'level' => 'log', 'dismissible' => true, 'description' => '<i class="fa-brands fa-fw fa-sass"></i> ' . $this->sass_process_status ); } $all_nebula_warnings = apply_filters('nebula_warnings', $nebula_warnings); //Allow other functions to hook in to add warnings (like Ecommerce) //Check for improper hooks if ( is_null($all_nebula_warnings) ){ $all_nebula_warnings = array(array( 'level' => 'error', 'dismissible' => true, 'description' => '<i class="fa-solid fa-fw fa-skull"></i> <code>$nebula_warnings</code> array is null. When hooking into the <code>nebula_warnings</code> filter be sure that it is returned too!' )); } //Sort by warning level if ( !empty($all_nebula_warnings) ){ usort($all_nebula_warnings, function($itemA, $itemB){ $priorities = array('error', 'warning', 'log'); $a = array_search($itemA['level'], $priorities); $b = array_search($itemB['level'], $priorities); if ( $a === $b ){ return 0; } return ( $a < $b )? -1 : 1; }); } wp_cache_set('nebula_warnings', $all_nebula_warnings); //Store in object cache $this->timer('Check Warnings', 'end'); return $all_nebula_warnings; } return array(); //Return empty array instead of false }
Override
This function can not be short-circuited with an override filter. Request one?