wp/wp-includes/rest-api/endpoints/class-wp-rest-site-health-controller.php
changeset 18 be944660c56a
child 21 48c4eec2b7e6
equal deleted inserted replaced
17:34716fd837a4 18:be944660c56a
       
     1 <?php
       
     2 /**
       
     3  * REST API: WP_REST_Site_Health_Controller class
       
     4  *
       
     5  * @package WordPress
       
     6  * @subpackage REST_API
       
     7  * @since 5.6.0
       
     8  */
       
     9 
       
    10 /**
       
    11  * Core class for interacting with Site Health tests.
       
    12  *
       
    13  * @since 5.6.0
       
    14  *
       
    15  * @see WP_REST_Controller
       
    16  */
       
    17 class WP_REST_Site_Health_Controller extends WP_REST_Controller {
       
    18 
       
    19 	/**
       
    20 	 * An instance of the site health class.
       
    21 	 *
       
    22 	 * @since 5.6.0
       
    23 	 *
       
    24 	 * @var WP_Site_Health
       
    25 	 */
       
    26 	private $site_health;
       
    27 
       
    28 	/**
       
    29 	 * Site Health controller constructor.
       
    30 	 *
       
    31 	 * @since 5.6.0
       
    32 	 *
       
    33 	 * @param WP_Site_Health $site_health An instance of the site health class.
       
    34 	 */
       
    35 	public function __construct( $site_health ) {
       
    36 		$this->namespace = 'wp-site-health/v1';
       
    37 		$this->rest_base = 'tests';
       
    38 
       
    39 		$this->site_health = $site_health;
       
    40 	}
       
    41 
       
    42 	/**
       
    43 	 * Registers API routes.
       
    44 	 *
       
    45 	 * @since 5.6.0
       
    46 	 *
       
    47 	 * @see register_rest_route()
       
    48 	 */
       
    49 	public function register_routes() {
       
    50 		register_rest_route(
       
    51 			$this->namespace,
       
    52 			sprintf(
       
    53 				'/%s/%s',
       
    54 				$this->rest_base,
       
    55 				'background-updates'
       
    56 			),
       
    57 			array(
       
    58 				array(
       
    59 					'methods'             => 'GET',
       
    60 					'callback'            => array( $this, 'test_background_updates' ),
       
    61 					'permission_callback' => function () {
       
    62 						return $this->validate_request_permission( 'background_updates' );
       
    63 					},
       
    64 				),
       
    65 				'schema' => array( $this, 'get_public_item_schema' ),
       
    66 			)
       
    67 		);
       
    68 
       
    69 		register_rest_route(
       
    70 			$this->namespace,
       
    71 			sprintf(
       
    72 				'/%s/%s',
       
    73 				$this->rest_base,
       
    74 				'loopback-requests'
       
    75 			),
       
    76 			array(
       
    77 				array(
       
    78 					'methods'             => 'GET',
       
    79 					'callback'            => array( $this, 'test_loopback_requests' ),
       
    80 					'permission_callback' => function () {
       
    81 						return $this->validate_request_permission( 'loopback_requests' );
       
    82 					},
       
    83 				),
       
    84 				'schema' => array( $this, 'get_public_item_schema' ),
       
    85 			)
       
    86 		);
       
    87 
       
    88 		register_rest_route(
       
    89 			$this->namespace,
       
    90 			sprintf(
       
    91 				'/%s/%s',
       
    92 				$this->rest_base,
       
    93 				'https-status'
       
    94 			),
       
    95 			array(
       
    96 				array(
       
    97 					'methods'             => 'GET',
       
    98 					'callback'            => array( $this, 'test_https_status' ),
       
    99 					'permission_callback' => function () {
       
   100 						return $this->validate_request_permission( 'https_status' );
       
   101 					},
       
   102 				),
       
   103 				'schema' => array( $this, 'get_public_item_schema' ),
       
   104 			)
       
   105 		);
       
   106 
       
   107 		register_rest_route(
       
   108 			$this->namespace,
       
   109 			sprintf(
       
   110 				'/%s/%s',
       
   111 				$this->rest_base,
       
   112 				'dotorg-communication'
       
   113 			),
       
   114 			array(
       
   115 				array(
       
   116 					'methods'             => 'GET',
       
   117 					'callback'            => array( $this, 'test_dotorg_communication' ),
       
   118 					'permission_callback' => function () {
       
   119 						return $this->validate_request_permission( 'dotorg_communication' );
       
   120 					},
       
   121 				),
       
   122 				'schema' => array( $this, 'get_public_item_schema' ),
       
   123 			)
       
   124 		);
       
   125 
       
   126 		register_rest_route(
       
   127 			$this->namespace,
       
   128 			sprintf(
       
   129 				'/%s/%s',
       
   130 				$this->rest_base,
       
   131 				'authorization-header'
       
   132 			),
       
   133 			array(
       
   134 				array(
       
   135 					'methods'             => 'GET',
       
   136 					'callback'            => array( $this, 'test_authorization_header' ),
       
   137 					'permission_callback' => function () {
       
   138 						return $this->validate_request_permission( 'authorization_header' );
       
   139 					},
       
   140 				),
       
   141 				'schema' => array( $this, 'get_public_item_schema' ),
       
   142 			)
       
   143 		);
       
   144 
       
   145 		register_rest_route(
       
   146 			$this->namespace,
       
   147 			sprintf(
       
   148 				'/%s',
       
   149 				'directory-sizes'
       
   150 			),
       
   151 			array(
       
   152 				'methods'             => 'GET',
       
   153 				'callback'            => array( $this, 'get_directory_sizes' ),
       
   154 				'permission_callback' => function() {
       
   155 					return $this->validate_request_permission( 'debug_enabled' ) && ! is_multisite();
       
   156 				},
       
   157 			)
       
   158 		);
       
   159 	}
       
   160 
       
   161 	/**
       
   162 	 * Validates if the current user can request this REST endpoint.
       
   163 	 *
       
   164 	 * @since 5.6.0
       
   165 	 *
       
   166 	 * @param string $check The endpoint check being ran.
       
   167 	 * @return bool
       
   168 	 */
       
   169 	protected function validate_request_permission( $check ) {
       
   170 		$default_capability = 'view_site_health_checks';
       
   171 
       
   172 		/**
       
   173 		 * Filters the capability needed to run a given Site Health check.
       
   174 		 *
       
   175 		 * @since 5.6.0
       
   176 		 *
       
   177 		 * @param string $default_capability The default capability required for this check.
       
   178 		 * @param string $check              The Site Health check being performed.
       
   179 		 */
       
   180 		$capability = apply_filters( "site_health_test_rest_capability_{$check}", $default_capability, $check );
       
   181 
       
   182 		return current_user_can( $capability );
       
   183 	}
       
   184 
       
   185 	/**
       
   186 	 * Checks if background updates work as expected.
       
   187 	 *
       
   188 	 * @since 5.6.0
       
   189 	 *
       
   190 	 * @return array
       
   191 	 */
       
   192 	public function test_background_updates() {
       
   193 		$this->load_admin_textdomain();
       
   194 		return $this->site_health->get_test_background_updates();
       
   195 	}
       
   196 
       
   197 	/**
       
   198 	 * Checks that the site can reach the WordPress.org API.
       
   199 	 *
       
   200 	 * @since 5.6.0
       
   201 	 *
       
   202 	 * @return array
       
   203 	 */
       
   204 	public function test_dotorg_communication() {
       
   205 		$this->load_admin_textdomain();
       
   206 		return $this->site_health->get_test_dotorg_communication();
       
   207 	}
       
   208 
       
   209 	/**
       
   210 	 * Checks that loopbacks can be performed.
       
   211 	 *
       
   212 	 * @since 5.6.0
       
   213 	 *
       
   214 	 * @return array
       
   215 	 */
       
   216 	public function test_loopback_requests() {
       
   217 		$this->load_admin_textdomain();
       
   218 		return $this->site_health->get_test_loopback_requests();
       
   219 	}
       
   220 
       
   221 	/**
       
   222 	 * Checks that the site's frontend can be accessed over HTTPS.
       
   223 	 *
       
   224 	 * @since 5.7.0
       
   225 	 *
       
   226 	 * @return array
       
   227 	 */
       
   228 	public function test_https_status() {
       
   229 		$this->load_admin_textdomain();
       
   230 		return $this->site_health->get_test_https_status();
       
   231 	}
       
   232 
       
   233 	/**
       
   234 	 * Checks that the authorization header is valid.
       
   235 	 *
       
   236 	 * @since 5.6.0
       
   237 	 *
       
   238 	 * @return array
       
   239 	 */
       
   240 	public function test_authorization_header() {
       
   241 		$this->load_admin_textdomain();
       
   242 		return $this->site_health->get_test_authorization_header();
       
   243 	}
       
   244 
       
   245 	/**
       
   246 	 * Gets the current directory sizes for this install.
       
   247 	 *
       
   248 	 * @since 5.6.0
       
   249 	 *
       
   250 	 * @return array|WP_Error
       
   251 	 */
       
   252 	public function get_directory_sizes() {
       
   253 		if ( ! class_exists( 'WP_Debug_Data' ) ) {
       
   254 			require_once ABSPATH . 'wp-admin/includes/class-wp-debug-data.php';
       
   255 		}
       
   256 
       
   257 		$this->load_admin_textdomain();
       
   258 
       
   259 		$sizes_data = WP_Debug_Data::get_sizes();
       
   260 		$all_sizes  = array( 'raw' => 0 );
       
   261 
       
   262 		foreach ( $sizes_data as $name => $value ) {
       
   263 			$name = sanitize_text_field( $name );
       
   264 			$data = array();
       
   265 
       
   266 			if ( isset( $value['size'] ) ) {
       
   267 				if ( is_string( $value['size'] ) ) {
       
   268 					$data['size'] = sanitize_text_field( $value['size'] );
       
   269 				} else {
       
   270 					$data['size'] = (int) $value['size'];
       
   271 				}
       
   272 			}
       
   273 
       
   274 			if ( isset( $value['debug'] ) ) {
       
   275 				if ( is_string( $value['debug'] ) ) {
       
   276 					$data['debug'] = sanitize_text_field( $value['debug'] );
       
   277 				} else {
       
   278 					$data['debug'] = (int) $value['debug'];
       
   279 				}
       
   280 			}
       
   281 
       
   282 			if ( ! empty( $value['raw'] ) ) {
       
   283 				$data['raw'] = (int) $value['raw'];
       
   284 			}
       
   285 
       
   286 			$all_sizes[ $name ] = $data;
       
   287 		}
       
   288 
       
   289 		if ( isset( $all_sizes['total_size']['debug'] ) && 'not available' === $all_sizes['total_size']['debug'] ) {
       
   290 			return new WP_Error( 'not_available', __( 'Directory sizes could not be returned.' ), array( 'status' => 500 ) );
       
   291 		}
       
   292 
       
   293 		return $all_sizes;
       
   294 	}
       
   295 
       
   296 	/**
       
   297 	 * Loads the admin textdomain for Site Health tests.
       
   298 	 *
       
   299 	 * The {@see WP_Site_Health} class is defined in WP-Admin, while the REST API operates in a front-end context.
       
   300 	 * This means that the translations for Site Health won't be loaded by default in {@see load_default_textdomain()}.
       
   301 	 *
       
   302 	 * @since 5.6.0
       
   303 	 */
       
   304 	protected function load_admin_textdomain() {
       
   305 		// Accounts for inner REST API requests in the admin.
       
   306 		if ( ! is_admin() ) {
       
   307 			$locale = determine_locale();
       
   308 			load_textdomain( 'default', WP_LANG_DIR . "/admin-$locale.mo" );
       
   309 		}
       
   310 	}
       
   311 
       
   312 	/**
       
   313 	 * Gets the schema for each site health test.
       
   314 	 *
       
   315 	 * @since 5.6.0
       
   316 	 *
       
   317 	 * @return array The test schema.
       
   318 	 */
       
   319 	public function get_item_schema() {
       
   320 		if ( $this->schema ) {
       
   321 			return $this->schema;
       
   322 		}
       
   323 
       
   324 		$this->schema = array(
       
   325 			'$schema'    => 'http://json-schema.org/draft-04/schema#',
       
   326 			'title'      => 'wp-site-health-test',
       
   327 			'type'       => 'object',
       
   328 			'properties' => array(
       
   329 				'test'        => array(
       
   330 					'type'        => 'string',
       
   331 					'description' => __( 'The name of the test being run.' ),
       
   332 					'readonly'    => true,
       
   333 				),
       
   334 				'label'       => array(
       
   335 					'type'        => 'string',
       
   336 					'description' => __( 'A label describing the test.' ),
       
   337 					'readonly'    => true,
       
   338 				),
       
   339 				'status'      => array(
       
   340 					'type'        => 'string',
       
   341 					'description' => __( 'The status of the test.' ),
       
   342 					'enum'        => array( 'good', 'recommended', 'critical' ),
       
   343 					'readonly'    => true,
       
   344 				),
       
   345 				'badge'       => array(
       
   346 					'type'        => 'object',
       
   347 					'description' => __( 'The category this test is grouped in.' ),
       
   348 					'properties'  => array(
       
   349 						'label' => array(
       
   350 							'type'     => 'string',
       
   351 							'readonly' => true,
       
   352 						),
       
   353 						'color' => array(
       
   354 							'type'     => 'string',
       
   355 							'enum'     => array( 'blue', 'orange', 'red', 'green', 'purple', 'gray' ),
       
   356 							'readonly' => true,
       
   357 						),
       
   358 					),
       
   359 					'readonly'    => true,
       
   360 				),
       
   361 				'description' => array(
       
   362 					'type'        => 'string',
       
   363 					'description' => __( 'A more descriptive explanation of what the test looks for, and why it is important for the user.' ),
       
   364 					'readonly'    => true,
       
   365 				),
       
   366 				'actions'     => array(
       
   367 					'type'        => 'string',
       
   368 					'description' => __( 'HTML containing an action to direct the user to where they can resolve the issue.' ),
       
   369 					'readonly'    => true,
       
   370 				),
       
   371 			),
       
   372 		);
       
   373 
       
   374 		return $this->schema;
       
   375 	}
       
   376 }