| Current File : /home/digitaw/www/wp-content/plugins/simple-history/inc/class-wp-rest-stats-controller.php |
<?php
namespace Simple_History;
use WP_Error;
use WP_REST_Controller;
use WP_REST_Server;
use Simple_History\Date_Helper;
/**
* REST API controller for stats.
*/
class WP_REST_Stats_Controller extends WP_REST_Controller {
/**
* Simple History instance.
*
* @var Simple_History
*/
protected Simple_History $simple_history;
/**
* Constructor.
*/
public function __construct() {
$this->namespace = 'simple-history/v1';
$this->rest_base = 'stats';
$this->simple_history = Simple_History::get_instance();
}
/**
* Register the routes for the objects of the controller.
*/
public function register_routes() {
// GET /wp-json/simple-history/v1/stats/summary.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/summary',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_summary' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/users.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/users',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_users_stats' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/content.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/content',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_content_stats' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/media.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/media',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_media_stats' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/plugins.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/plugins',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_plugins_stats' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/core.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/core',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_core_stats' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/peak-days.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/peak-days',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_peak_days' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/peak-times.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/peak-times',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_peak_times' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
// GET /wp-json/simple-history/v1/stats/activity-overview.
register_rest_route(
$this->namespace,
'/' . $this->rest_base . '/activity-overview',
[
[
'methods' => WP_REST_Server::READABLE,
'callback' => [ $this, 'get_activity_overview' ],
'permission_callback' => [ $this, 'get_items_permissions_check' ],
'args' => $this->get_collection_params(),
],
'schema' => [ $this, 'get_public_item_schema' ],
]
);
}
/**
* Checks if a given request has access to read stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return true|\WP_Error True if the request has read access, WP_Error object otherwise.
*/
public function get_items_permissions_check( $request ) {
// User must be logged in and have manage_options capability.
if ( ! current_user_can( 'manage_options' ) ) {
return new WP_Error(
'rest_forbidden_context',
__( 'Sorry, you are not allowed to view stats.', 'simple-history' ),
array( 'status' => rest_authorization_required_code() )
);
}
return true;
}
/**
* Retrieves the query params for the collection.
*
* @return array Collection parameters.
*/
public function get_collection_params() {
$params = parent::get_collection_params();
$params['date_from'] = array(
// translators: %d is the number of days.
'description' => sprintf( __( 'Start date as Unix timestamp. If not provided, defaults to %d days ago.', 'simple-history' ), Date_Helper::DAYS_PER_MONTH ),
'type' => 'integer',
'required' => false,
);
$params['date_to'] = array(
'description' => __( 'End date as Unix timestamp. If not provided, defaults to end of today.', 'simple-history' ),
'type' => 'integer',
'required' => false,
);
$params['limit'] = array(
'description' => __( 'Maximum number of items to be returned in result set.', 'simple-history' ),
'type' => 'integer',
'default' => 50,
'minimum' => 1,
'maximum' => 100,
);
$params['include_details'] = array(
'description' => __( 'Whether to include detailed stats.', 'simple-history' ),
'type' => 'boolean',
'default' => false,
);
return $params;
}
/**
* Get default date range for last month.
*
* Uses WordPress timezone from Settings > General.
*
* @return array Array with 'from' and 'to' timestamps for last month.
*/
private function get_default_date_range() {
return Date_Helper::get_default_date_range();
}
/**
* Get date range from request or default to today.
*
* @param \WP_REST_Request $request Full details about the request.
* @return array Array with 'from' and 'to' timestamps.
*/
private function get_date_range_from_request( $request ) {
$date_from = $request->get_param( 'date_from' );
$date_to = $request->get_param( 'date_to' );
if ( ! $date_from || ! $date_to ) {
$default_range = $this->get_default_date_range();
if ( ! $date_from ) {
$date_from = $default_range['from'];
}
if ( ! $date_to ) {
$date_to = $default_range['to'];
}
}
return array(
'from' => $date_from,
'to' => $date_to,
);
}
/**
* Format date range with human-readable dates.
*
* @param int $from Unix timestamp for start date.
* @param int $to Unix timestamp for end date.
* @return array Array with timestamps, formatted dates, and duration.
*/
private function format_date_range( $from, $to ) {
$date_format = get_option( 'date_format' );
$time_format = get_option( 'time_format' );
$datetime_format = $date_format . ' ' . $time_format;
return array(
'from' => $from,
'to' => $to,
'from_formatted' => date_i18n( $datetime_format, $from ),
'to_formatted' => date_i18n( $datetime_format, $to ),
'duration_days' => ceil( ( $to - $from ) / DAY_IN_SECONDS ),
);
}
/**
* Get summary stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_summary( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$events_stats = new Events_Stats();
$summary = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'total_events' => $events_stats->get_total_events( $date_from, $date_to ),
'total_events_since_install' => Helpers::get_total_logged_events_count(),
'totals' => array(
'users' => array(
'logins' => $events_stats->get_successful_logins_count( $date_from, $date_to ),
'failed_logins' => $events_stats->get_failed_logins_count( $date_from, $date_to ),
'profile_updates' => $events_stats->get_user_updated_count( $date_from, $date_to ),
'total' => $events_stats->get_user_total_count( $date_from, $date_to ),
),
'content' => array(
'created' => $events_stats->get_posts_pages_created( $date_from, $date_to ),
'updated' => $events_stats->get_posts_pages_updated( $date_from, $date_to ),
'deleted' => $events_stats->get_posts_pages_deleted( $date_from, $date_to ),
'total' => $events_stats->get_content_total_count( $date_from, $date_to ),
),
'media' => array(
'uploads' => $events_stats->get_media_uploads_count( $date_from, $date_to ),
'edits' => $events_stats->get_media_edits_count( $date_from, $date_to ),
'deletions' => $events_stats->get_media_deletions_count( $date_from, $date_to ),
'total' => $events_stats->get_media_total_count( $date_from, $date_to ),
),
'plugins' => array(
'updates' => $events_stats->get_plugin_updates_count( $date_from, $date_to ),
'installations' => $events_stats->get_plugin_installs_count( $date_from, $date_to ),
'activations' => $events_stats->get_plugin_activations_count( $date_from, $date_to ),
'total' => $events_stats->get_plugin_total_count( $date_from, $date_to ),
),
'core' => array(
'updates' => $events_stats->get_wordpress_core_updates_count( $date_from, $date_to ),
'available_updates' => $events_stats->get_wordpress_core_updates_found_count( $date_from, $date_to ),
'total' => $events_stats->get_core_total_count( $date_from, $date_to ),
),
),
);
return rest_ensure_response( $summary );
}
/**
* Get user stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_users_stats( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$limit = $request->get_param( 'limit' );
$include_details = $request->get_param( 'include_details' );
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'summary' => array(
'logins' => $events_stats->get_successful_logins_count( $date_from, $date_to ),
'failed_logins' => $events_stats->get_failed_logins_count( $date_from, $date_to ),
'profile_updates' => $events_stats->get_user_updated_count( $date_from, $date_to ),
'total' => $events_stats->get_user_total_count( $date_from, $date_to ),
),
);
if ( $include_details ) {
$stats['details'] = $events_stats->get_detailed_user_stats( $date_from, $date_to, $limit );
}
return rest_ensure_response( $stats );
}
/**
* Get content stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_content_stats( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$limit = $request->get_param( 'limit' );
$include_details = $request->get_param( 'include_details' );
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'summary' => array(
'created' => $events_stats->get_posts_pages_created( $date_from, $date_to ),
'updated' => $events_stats->get_posts_pages_updated( $date_from, $date_to ),
'deleted' => $events_stats->get_posts_pages_deleted( $date_from, $date_to ),
'total' => $events_stats->get_content_total_count( $date_from, $date_to ),
),
);
if ( $include_details ) {
$stats['details'] = $events_stats->get_detailed_content_stats( $date_from, $date_to, $limit );
}
return rest_ensure_response( $stats );
}
/**
* Get media stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_media_stats( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$include_details = $request->get_param( 'include_details' );
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'summary' => array(
'uploads' => $events_stats->get_media_uploads_count( $date_from, $date_to ),
'edits' => $events_stats->get_media_edits_count( $date_from, $date_to ),
'deletions' => $events_stats->get_media_deletions_count( $date_from, $date_to ),
'total' => $events_stats->get_media_total_count( $date_from, $date_to ),
),
);
if ( $include_details ) {
$stats['details'] = array(
'uploads' => $events_stats->get_media_uploaded_details( $date_from, $date_to ),
'edits' => $events_stats->get_media_edited_details( $date_from, $date_to ),
'deletions' => $events_stats->get_media_deleted_details( $date_from, $date_to ),
);
}
return rest_ensure_response( $stats );
}
/**
* Get plugins stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_plugins_stats( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$limit = $request->get_param( 'limit' );
$include_details = $request->get_param( 'include_details' );
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'summary' => array(
'updates' => $events_stats->get_plugin_updates_count( $date_from, $date_to ),
'installations' => $events_stats->get_plugin_installs_count( $date_from, $date_to ),
'activations' => $events_stats->get_plugin_activations_count( $date_from, $date_to ),
'available_updates' => $events_stats->get_available_plugin_updates(),
'total' => $events_stats->get_plugin_total_count( $date_from, $date_to ),
),
);
if ( $include_details ) {
$stats['details'] = array(
'updates' => $events_stats->get_plugin_details( 'updated', $date_from, $date_to, $limit ),
'installations' => $events_stats->get_plugin_details( 'installed', $date_from, $date_to, $limit ),
'activations' => $events_stats->get_plugin_details( 'activated', $date_from, $date_to, $limit ),
'available_updates' => $events_stats->get_plugins_with_updates(),
);
}
return rest_ensure_response( $stats );
}
/**
* Get core stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_core_stats( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'summary' => array(
'updates' => $events_stats->get_wordpress_core_updates_count( $date_from, $date_to ),
'available_updates' => $events_stats->get_wordpress_core_updates_found_count( $date_from, $date_to ),
'total' => $events_stats->get_core_total_count( $date_from, $date_to ),
),
);
return rest_ensure_response( $stats );
}
/**
* Get peak days stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_peak_days( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'peak_days' => $events_stats->get_peak_days( $date_from, $date_to ),
);
return rest_ensure_response( $stats );
}
/**
* Get peak activity times stats.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_peak_times( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'peak_times' => $events_stats->get_peak_activity_times( $date_from, $date_to ),
);
return rest_ensure_response( $stats );
}
/**
* Get activity overview by date.
*
* @param \WP_REST_Request $request Full details about the request.
* @return \WP_REST_Response|\WP_Error Response object on success, or WP_Error object on failure.
*/
public function get_activity_overview( $request ) {
$date_range = $this->get_date_range_from_request( $request );
$date_from = $date_range['from'];
$date_to = $date_range['to'];
$events_stats = new Events_Stats();
$stats = array(
'date_range' => $this->format_date_range( $date_from, $date_to ),
'activity_by_date' => $events_stats->get_activity_overview_by_date( $date_from, $date_to ),
);
return rest_ensure_response( $stats );
}
/**
* Retrieves the post's schema, conforming to JSON Schema.
*
* @return array Item schema data.
*/
public function get_item_schema() {
if ( $this->schema ) {
return $this->add_additional_fields_schema( $this->schema );
}
$schema = array(
'$schema' => 'http://json-schema.org/draft-04/schema#',
'title' => 'simple-history-stats',
'type' => 'object',
'properties' => array(
'date_range' => array(
'description' => __( 'Date range for the stats.', 'simple-history' ),
'type' => 'object',
'properties' => array(
'from' => array(
'description' => __( 'Start date as Unix timestamp.', 'simple-history' ),
'type' => 'integer',
),
'to' => array(
'description' => __( 'End date as Unix timestamp.', 'simple-history' ),
'type' => 'integer',
),
),
),
'summary' => array(
'description' => __( 'Summary of stats.', 'simple-history' ),
'type' => 'object',
),
'details' => array(
'description' => __( 'Detailed stats.', 'simple-history' ),
'type' => 'object',
),
),
);
$this->schema = $schema;
return $this->add_additional_fields_schema( $this->schema );
}
}