Make WordPress Core

Changeset 47063


Ignore:
Timestamp:
01/12/2020 01:31:49 PM (5 years ago)
Author:
SergeyBiryukov
Message:

Site Health: Introduce Site Health Status dashboard widget.

The widget informs administrators of any potential issues that should be addressed to improve the performance or security of their website, and directs them to the Site Health screen for more details.

Props Clorith, hedgefield, guddu1315.
See #47606.

Location:
trunk/src
Files:
3 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/wp-admin/includes/class-wp-site-health.php

    r46797 r47063  
    99
    1010class WP_Site_Health {
     11    private static $instance = null;
     12
    1113    private $mysql_min_version_check;
    1214    private $mysql_rec_version_check;
     
    3032     */
    3133    public function __construct() {
     34        $this->maybe_create_scheduled_event();
     35
    3236        $this->prepare_sql_data();
    3337
     
    4347
    4448        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_scripts' ) );
     49        add_action( 'wp_site_health_scheduled_check', array( $this, 'wp_cron_scheduled_check' ) );
     50    }
     51
     52    /**
     53     * Return an instance of the WP_Site_Health class, or create one if none exist yet.
     54     *
     55     * @since 5.4.0
     56     *
     57     * @return WP_Site_Health|null
     58     */
     59    public static function initialize() {
     60        if ( null === self::$instance ) {
     61            self::$instance = new WP_Site_Health();
     62        }
     63
     64        return self::$instance;
    4565    }
    4666
     
    5272    public function enqueue_scripts() {
    5373        $screen = get_current_screen();
    54         if ( 'site-health' !== $screen->id ) {
     74        if ( 'site-health' !== $screen->id && 'dashboard' !== $screen->id ) {
    5575            return;
    5676        }
     
    97117
    98118                    if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
    99                         /**
    100                          * Filter the output of a finished Site Health test.
    101                          *
    102                          * @since 5.3.0
    103                          *
    104                          * @param array $test_result {
    105                          *     An associated array of test result data.
    106                          *
    107                          *     @param string $label  A label describing the test, and is used as a header in the output.
    108                          *     @param string $status The status of the test, which can be a value of `good`, `recommended` or `critical`.
    109                          *     @param array  $badge {
    110                          *         Tests are put into categories which have an associated badge shown, these can be modified and assigned here.
    111                          *
    112                          *         @param string $label The test label, for example `Performance`.
    113                          *         @param string $color Default `blue`. A string representing a color to use for the label.
    114                          *     }
    115                          *     @param string $description A more descriptive explanation of what the test looks for, and why it is important for the end user.
    116                          *     @param string $actions     An action to direct the user to where they can resolve the issue, if one exists.
    117                          *     @param string $test        The name of the test being ran, used as a reference point.
    118                          * }
    119                          */
    120                         $health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( array( $this, $test_function ) ) );
     119                        $health_check_js_variables['site_status']['direct'][] = $this->perform_test( array( $this, $test_function ) );
    121120                        continue;
    122121                    }
     
    124123
    125124                if ( is_callable( $test['test'] ) ) {
    126                     /** This filter is documented in wp-admin/includes/class-wp-site-health.php */
    127                     $health_check_js_variables['site_status']['direct'][] = apply_filters( 'site_status_test_result', call_user_func( $test['test'] ) );
     125                    $health_check_js_variables['site_status']['direct'][] = $this->perform_test( $test['test'] );
    128126                }
    129127            }
     
    140138
    141139        wp_localize_script( 'site-health', 'SiteHealth', $health_check_js_variables );
     140    }
     141
     142    /**
     143     * Run a Site Health test directly.
     144     *
     145     * @since 5.4.0
     146     *
     147     * @param $callback
     148     *
     149     * @return mixed|void
     150     */
     151    private function perform_test( $callback ) {
     152        /**
     153         * Filter the output of a finished Site Health test.
     154         *
     155         * @since 5.3.0
     156         *
     157         * @param array $test_result {
     158         *     An associated array of test result data.
     159         *
     160         *     @param string $label  A label describing the test, and is used as a header in the output.
     161         *     @param string $status The status of the test, which can be a value of `good`, `recommended` or `critical`.
     162         *     @param array  $badge {
     163         *         Tests are put into categories which have an associated badge shown, these can be modified and assigned here.
     164         *
     165         *         @param string $label The test label, for example `Performance`.
     166         *         @param string $color Default `blue`. A string representing a color to use for the label.
     167         *     }
     168         *     @param string $description A more descriptive explanation of what the test looks for, and why it is important for the end user.
     169         *     @param string $actions     An action to direct the user to where they can resolve the issue, if one exists.
     170         *     @param string $test        The name of the test being ran, used as a reference point.
     171         * }
     172         */
     173        return apply_filters( 'site_status_test_result', call_user_func( $callback ) );
    142174    }
    143175
     
    20062038     */
    20072039    public function admin_body_class( $body_class ) {
     2040        $screen = get_current_screen();
     2041        if ( 'site-health' !== $screen->id ) {
     2042            return $body_class;
     2043        }
     2044
    20082045        $body_class .= ' site-health';
    20092046
     
    21682205        );
    21692206    }
     2207
     2208    /**
     2209     * Create a weekly cron event, if one does not already exist.
     2210     *
     2211     * @since 5.4.0
     2212     */
     2213    public function maybe_create_scheduled_event() {
     2214        if ( ! wp_next_scheduled( 'wp_site_health_scheduled_check' ) && ! wp_installing() ) {
     2215            wp_schedule_event( time(), 'weekly', 'wp_site_health_scheduled_check' );
     2216        }
     2217    }
     2218
     2219    /**
     2220     * Run our scheduled event to check and update the latest site health status for the website.
     2221     *
     2222     * @since 5.4.0
     2223     */
     2224    public function wp_cron_scheduled_check() {
     2225        // Bootstrap wp-admin, as WP_Cron doesn't do this for us.
     2226        require_once( trailingslashit( ABSPATH ) . 'wp-admin/includes/admin.php' );
     2227
     2228        $tests = WP_Site_Health::get_tests();
     2229
     2230        $results = array();
     2231
     2232        $site_status = array(
     2233            'good'        => 0,
     2234            'recommended' => 0,
     2235            'critical'    => 0,
     2236        );
     2237
     2238        // Don't run https test on localhost
     2239        if ( 'localhost' === preg_replace( '|https?://|', '', get_site_url() ) ) {
     2240            unset( $tests['direct']['https_status'] );
     2241        }
     2242
     2243        foreach ( $tests['direct'] as $test ) {
     2244
     2245            if ( is_string( $test['test'] ) ) {
     2246                $test_function = sprintf(
     2247                    'get_test_%s',
     2248                    $test['test']
     2249                );
     2250
     2251                if ( method_exists( $this, $test_function ) && is_callable( array( $this, $test_function ) ) ) {
     2252                    $results[] = $this->perform_test( array( $this, $test_function ) );
     2253                    continue;
     2254                }
     2255            }
     2256
     2257            if ( is_callable( $test['test'] ) ) {
     2258                $results[] = $this->perform_test( $test['test'] );
     2259            }
     2260        }
     2261
     2262        foreach ( $tests['async'] as $test ) {
     2263            if ( is_string( $test['test'] ) ) {
     2264                if ( isset( $test['has_rest'] ) && $test['has_rest'] ) {
     2265                    $result_fetch = wp_remote_post(
     2266                        rest_url( $test['test'] ),
     2267                        array(
     2268                            'body' => array(
     2269                                '_wpnonce' => wp_create_nonce( 'wp_rest' ),
     2270                            ),
     2271                        )
     2272                    );
     2273                } else {
     2274                    $result_fetch = wp_remote_post(
     2275                        admin_url( 'admin-ajax.php' ),
     2276                        array(
     2277                            'body' => array(
     2278                                'action'   => $test['test'],
     2279                                '_wpnonce' => wp_create_nonce( 'health-check-site-status' ),
     2280                            ),
     2281                        )
     2282                    );
     2283                }
     2284
     2285                if ( ! is_wp_error( $result_fetch ) ) {
     2286                    $results[] = json_decode( wp_remote_retrieve_body( $result_fetch ) );
     2287                } else {
     2288                    $results[] = array(
     2289                        'status' => 'recommended',
     2290                        'label'  => __( 'A test is unavailable' ),
     2291                    );
     2292                }
     2293            }
     2294        }
     2295
     2296        foreach ( $results as $result ) {
     2297            if ( 'critical' === $result['status'] ) {
     2298                $site_status['critical']++;
     2299            } elseif ( 'recommended' === $result['status'] ) {
     2300                $site_status['recommended']++;
     2301            } else {
     2302                $site_status['good']++;
     2303            }
     2304        }
     2305
     2306        set_transient( 'health-check-site-status-result', wp_json_encode( $site_status ) );
     2307    }
    21702308}
  • trunk/src/wp-admin/includes/dashboard.php

    r47016 r47063  
    4141        add_filter( 'postbox_classes_dashboard_dashboard_php_nag', 'dashboard_php_nag_class' );
    4242        wp_add_dashboard_widget( 'dashboard_php_nag', __( 'PHP Update Required' ), 'wp_dashboard_php_nag' );
     43    }
     44
     45    // Site Health.
     46    if ( current_user_can( 'view_site_health_checks' ) ) {
     47        if ( ! class_exists( 'WP_Site_Health' ) ) {
     48            require_once( ABSPATH . 'wp-admin/includes/class-wp-site-health.php' );
     49        }
     50
     51        WP_Site_Health::initialize();
     52
     53        wp_enqueue_style( 'site-health' );
     54        wp_enqueue_script( 'site-health' );
     55
     56        wp_add_dashboard_widget( 'dashboard_site_health', __( 'Site Health Status' ), 'wp_dashboard_site_health' );
    4357    }
    4458
     
    17491763
    17501764    return $classes;
     1765}
     1766
     1767/**
     1768 * Displays the Site Health Status widget.
     1769 *
     1770 * @since 5.4.0
     1771 */
     1772function wp_dashboard_site_health() {
     1773    $get_issues = get_transient( 'health-check-site-status-result' );
     1774
     1775    $issue_counts = new stdClass();
     1776
     1777    if ( false !== $get_issues ) {
     1778        $issue_counts = json_decode( $get_issues );
     1779    }
     1780
     1781    if ( ! is_object( $issue_counts ) || empty( $issue_counts ) ) {
     1782        $issue_counts = (object) array(
     1783            'good'        => 0,
     1784            'recommended' => 0,
     1785            'critical'    => 0,
     1786        );
     1787    }
     1788
     1789    $issues_total = $issue_counts->recommended + $issue_counts->critical;
     1790    ?>
     1791    <div class="health-check-title-section site-health-progress-wrapper loading hide-if-no-js">
     1792        <div class="site-health-progress">
     1793            <svg role="img" aria-hidden="true" focusable="false" width="100%" height="100%" viewBox="0 0 200 200" version="1.1" xmlns="http://www.w3.org/2000/svg">
     1794                <circle r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
     1795                <circle id="bar" r="90" cx="100" cy="100" fill="transparent" stroke-dasharray="565.48" stroke-dashoffset="0"></circle>
     1796            </svg>
     1797        </div>
     1798        <div class="site-health-progress-label">
     1799            <?php if ( false === $get_issues ) : ?>
     1800                <?php _e( 'No information yet&hellip;' ); ?>
     1801            <?php else : ?>
     1802                <?php _e( 'Results are still loading&hellip;' ); ?>
     1803            <?php endif; ?>
     1804        </div>
     1805    </div>
     1806
     1807    <?php if ( false === $get_issues ) : ?>
     1808        <p>
     1809            <?php _e( 'No Site Health information has been gathered yet, you can do so by visiting the Site Health screen, alternatively the checks will run periodically.' ); ?>
     1810        </p>
     1811
     1812        <p>
     1813            <?php
     1814            printf(
     1815                /* translators: %s: URL to Site Health screen. */
     1816                __( '<a href="%s">Visit the Site Health screen</a> to gather information on about your site.' ),
     1817                esc_url( admin_url( 'site-health.php' ) )
     1818            );
     1819            ?>
     1820        </p>
     1821
     1822    <?php else : ?>
     1823        <p>
     1824            <?php if ( $issue_counts->critical > 0 ) : ?>
     1825                <?php _e( 'Your site has critical issues that should be addressed as soon as possible to improve the performance or security of your website.' ); ?>
     1826            <?php elseif ( $issues_total <= 0 ) : ?>
     1827                <?php _e( 'Great job! Your site currently passes all site health checks.' ); ?>
     1828            <?php else : ?>
     1829                <?php _e( 'Your site health is looking quite good, but there are still some things you can do to improve the performance and security of your website.' ); ?>
     1830            <?php endif; ?>
     1831        </p>
     1832    <?php endif; ?>
     1833
     1834    <?php if ( $issues_total > 0 && false !== $get_issues ) : ?>
     1835        <p>
     1836            <?php
     1837            printf(
     1838                /* translators: 1: Number of issues. 2: URL to Site Health screen. */
     1839                __( 'Take a look at the <strong>%1$d items</strong> on the <a href="%2$s">Site Health Status screen</a>.' ),
     1840                $issues_total,
     1841                esc_url( admin_url( 'site-health.php' ) )
     1842            );
     1843            ?>
     1844        </p>
     1845    <?php endif; ?>
     1846
     1847    <?php
    17511848}
    17521849
  • trunk/src/wp-settings.php

    r47018 r47063  
    352352}
    353353
     354// Create an instance of WP_Site_Health so that Cron events may fire.
     355if ( ! class_exists( 'WP_Site_Health' ) ) {
     356    require_once( ABSPATH . 'wp-admin/includes/class-wp-site-health.php' );
     357}
     358WP_Site_Health::initialize();
     359
    354360// Load active plugins.
    355361foreach ( wp_get_active_and_valid_plugins() as $plugin ) {
Note: See TracChangeset for help on using the changeset viewer.