oont-contents/plugins/wp-rocket/inc/Engine/CriticalPath/RESTWP.php
2025-02-08 15:10:23 +01:00

322 lines
7.4 KiB
PHP

<?php
namespace WP_Rocket\Engine\CriticalPath;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;
use WP_Rocket\Admin\Options_Data;
/**
* Class RESTWP
*
* @package WP_Rocket\Engine\CriticalPath
*/
abstract class RESTWP implements RESTWPInterface {
/**
* Namespace for REST Route.
*/
const ROUTE_NAMESPACE = 'wp-rocket/v1';
/**
* Part of route namespace for this inherited class item type.
*
* @var string $route_namespace to be set with like post, term.
*/
protected $route_namespace;
/**
* CPCSS generation and deletion service.
*
* @var ProcessorService instance for this service.
*/
private $cpcss_service;
/**
* WP Rocket options instance.
*
* @var Options_Data
*/
private $options;
/**
* RESTWP constructor.
*
* @since 3.6
*
* @param ProcessorService $cpcss_service Has the logic for cpcss generation and deletion.
* @param Options_Data $options Instance of options data handler.
*/
public function __construct( ProcessorService $cpcss_service, Options_Data $options ) {
$this->cpcss_service = $cpcss_service;
$this->options = $options;
}
/**
* Registers the generate route in the WP REST API
*
* @since 3.6
*
* @return void
*/
public function register_generate_route() {
register_rest_route(
self::ROUTE_NAMESPACE,
'cpcss/' . $this->route_namespace . '/(?P<id>[\d]+)',
[
'methods' => 'POST',
'callback' => [ $this, 'generate' ],
'permission_callback' => [ $this, 'check_permissions' ],
]
);
}
/**
* Register Delete CPCSS route in the WP REST API.
*
* @since 3.6
*/
public function register_delete_route() {
register_rest_route(
self::ROUTE_NAMESPACE,
'cpcss/' . $this->route_namespace . '/(?P<id>[\d]+)',
[
'methods' => 'DELETE',
'callback' => [ $this, 'delete' ],
'permission_callback' => [ $this, 'check_permissions' ],
]
);
}
/**
* Checks user's permissions. This is a callback registered to REST route's "permission_callback" parameter.
*
* @since 3.6
*
* @return bool true if the user has permission; else false.
*/
public function check_permissions() {
return current_user_can( 'rocket_regenerate_critical_css' );
}
/**
* Clean post cache files on CPCSS generation or deletion.
*
* @since 3.6.1
*
* @param int $item_id ID for this item to get Url for.
*/
private function clean_post_cache( $item_id ) {
rocket_clean_files( $this->get_url( $item_id ) );
}
/**
* Generates the CPCSS for the requested post ID.
*
* @since 3.6
*
* @param WP_REST_Request $request WP REST request response.
*
* @return WP_REST_Response
*/
public function generate( WP_REST_Request $request ) {
$item_id = (int) $request->get_param( 'id' );
$is_mobile = (bool) $request->get_param( 'is_mobile' );
// Bailout in case mobile CPCSS generation is called but this option is disabled.
if (
$is_mobile
&&
(
! $this->options->get( 'async_css_mobile', 0 )
||
! $this->options->get( 'do_caching_mobile_files', 0 )
)
) {
return rest_ensure_response(
$this->return_error(
new WP_Error(
'mobile_cpcss_not_enabled',
__( 'Mobile CPCSS generation not enabled.', 'rocket' ),
[
'status' => 400,
]
)
)
);
}
// validate item.
$validated = $this->validate_item_for_generate( $item_id );
if ( is_wp_error( $validated ) ) {
return rest_ensure_response( $this->return_error( $validated ) );
}
// get item url.
$item_url = $this->get_url( $item_id );
$timeout = ( isset( $request['timeout'] ) && ! empty( $request['timeout'] ) );
$item_path = $this->get_path( $item_id, $is_mobile );
$additional_params = [
'timeout' => $timeout,
'is_mobile' => $is_mobile,
'item_type' => 'custom',
];
$generated = $this->cpcss_service->process_generate( $item_url, $item_path, $additional_params );
if ( is_wp_error( $generated ) ) {
return rest_ensure_response(
$this->return_error( $generated )
);
}
$this->clean_post_cache( $item_id );
return rest_ensure_response(
$this->return_success( $generated )
);
}
/**
* Validate the item to be sent to generate CPCSS.
*
* @since 3.6
*
* @param int $item_id ID for this item to be validated.
*
* @return true|WP_Error
*/
abstract protected function validate_item_for_generate( $item_id );
/**
* Validate the item to be sent to Delete CPCSS.
*
* @since 3.6
*
* @param int $item_id ID for this item to be validated.
*
* @return true|WP_Error
*/
abstract protected function validate_item_for_delete( $item_id );
/**
* Get url for this item.
*
* @since 3.6
*
* @param int $item_id ID for this item to get Url for.
*
* @return false|string
*/
abstract protected function get_url( $item_id );
/**
* Get CPCSS file path to save CPCSS code into.
*
* @since 3.6
*
* @param int $item_id ID for this item to get the path for.
* @param bool $is_mobile Bool identifier for is_mobile CPCSS generation.
*
* @return string
*/
abstract protected function get_path( $item_id, $is_mobile = false );
/**
* Delete Post ID CPCSS file.
*
* @since 3.6
*
* @param WP_REST_Request $request the WP Rest Request object.
*
* @return WP_REST_Response
*/
public function delete( WP_REST_Request $request ) {
$item_id = (int) $request->get_param( 'id' );
// validate item.
$validated = $this->validate_item_for_delete( $item_id );
if ( is_wp_error( $validated ) ) {
return rest_ensure_response( $this->return_error( $validated ) );
}
if ( $this->options->get( 'async_css_mobile', 0 ) ) {
$mobile_item_path = $this->get_path( $item_id, true );
$this->cpcss_service->process_delete( $mobile_item_path );
}
$item_path = $this->get_path( $item_id );
$deleted = $this->cpcss_service->process_delete( $item_path );
if ( is_wp_error( $deleted ) ) {
return rest_ensure_response( $this->return_error( $deleted ) );
}
$this->clean_post_cache( $item_id );
return rest_ensure_response( $this->return_success( $deleted ) );
}
/**
* Returns the formatted array response
*
* @since 3.6
*
* @param bool $success True for success, false otherwise.
* @param string $code The code to use for the response.
* @param string $message The message to send in the response.
* @param int $status The status code to send for the response.
*
* @return array
*/
protected function return_array_response( $success = false, $code = '', $message = '', $status = 200 ) {
return [
'success' => $success,
'code' => $code,
'message' => $message,
'data' => [
'status' => $status,
],
];
}
/**
* Convert WP_Error into array to be used in response.
*
* @since 3.6
*
* @param WP_Error $error Error that will be converted to array.
*
* @return array
*/
protected function return_error( $error ) {
$error_data = $error->get_error_data();
return $this->return_array_response(
false,
$error->get_error_code(),
$error->get_error_message(),
isset( $error_data['status'] ) ? $error_data['status'] : 400
);
}
/**
* Return success to be used in response.
*
* @since 3.6
*
* @param array $data which has success parameters with two keys: code and message.
*
* @return array
*/
protected function return_success( $data ) {
return $this->return_array_response(
true,
$data['code'],
$data['message'],
200
);
}
}