Linux webm002.cluster126.gra.hosting.ovh.net 6.18.39-ovh-vps-grsec-zfs+ #1 SMP PREEMPT_DYNAMIC Tue Jul 21 12:03:15 CEST 2026 x86_64
/
home
/
ariannadhf
/
www
/
wp-content
/
plugins
/
simple-history
/
inc
/
/home/ariannadhf/www/wp-content/plugins/simple-history/inc/class-wp-rest-user-card-controller.php
<?php namespace Simple_History; use WP_Error; use WP_REST_Controller; use WP_REST_Server; /** * REST API controller for user card data. * * Provides user identity info for the avatar/name popover card. * The response is structured with filterable `details` and `actions` arrays * so add-ons can extend the card content. */ class WP_REST_User_Card_Controller extends WP_REST_Controller { /** * Constructor. */ public function __construct() { $this->namespace = 'simple-history/v1'; $this->rest_base = 'users'; } /** * Valid non-user initiator types for the initiator card endpoint. * * @var array<string> */ const INITIATOR_TYPES = [ 'wp', 'wp_cli', 'web_user', 'other' ]; /** * Register the routes for user card data. */ public function register_routes() { // GET /wp-json/simple-history/v1/users/<id>/card. register_rest_route( $this->namespace, '/' . $this->rest_base . '/(?P<id>\d+)/card', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_user_card' ], 'permission_callback' => [ $this, 'get_user_card_permissions_check' ], 'args' => [ 'id' => [ 'description' => __( 'WordPress user ID.', 'simple-history' ), 'type' => 'integer', 'required' => true, 'sanitize_callback' => 'absint', ], ], ], ] ); // GET /wp-json/simple-history/v1/initiators/<type>/card. register_rest_route( $this->namespace, '/initiators/(?P<type>[a-z_]+)/card', [ [ 'methods' => WP_REST_Server::READABLE, 'callback' => [ $this, 'get_initiator_card' ], 'permission_callback' => [ $this, 'get_user_card_permissions_check' ], 'args' => [ 'type' => [ 'description' => __( 'Initiator type (wp, wp_cli, web_user, other).', 'simple-history' ), 'type' => 'string', 'required' => true, 'enum' => self::INITIATOR_TYPES, 'sanitize_callback' => 'sanitize_key', ], ], ], ] ); } /** * Checks if the current user has permission to view user card data. * * @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_user_card_permissions_check( $request ) { // phpcs:ignore WordPress.WP.Capabilities.Undetermined -- Dynamic capability from Helpers::get_view_history_capability(). if ( ! current_user_can( Helpers::get_view_history_capability() ) ) { return new WP_Error( 'rest_forbidden_context', __( 'Sorry, you are not allowed to view user card data.', 'simple-history' ), array( 'status' => rest_authorization_required_code() ) ); } return true; } /** * Get user card data. * * @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_user_card( $request ) { $user_id = $request->get_param( 'id' ); $user = get_userdata( $user_id ); if ( ! $user ) { return new WP_Error( 'rest_user_not_found', __( 'User not found.', 'simple-history' ), array( 'status' => 404 ) ); } $avatar_data = get_avatar_data( $user_id, [ 'size' => 96 ] ); // Core identity fields. $data = [ 'user_id' => $user->ID, 'display_name' => $user->display_name, 'user_login' => $user->user_login, 'user_email' => $user->user_email, 'avatar_url' => $avatar_data['url'] ?? '', 'profile_url' => get_edit_user_link( $user->ID ), 'roles' => array_values( $user->roles ), 'has_premium_add_on' => Helpers::is_premium_add_on_active(), ]; // Details: key-value items shown below identity info. // Each item: [ 'key' => string, 'label' => string, 'value' => string, 'type' => string ]. // Core provides no details; add-ons use the filter to add items like // last login time, last activity, login count, IP address, etc. // Supported types: 'text' (default), 'date' (rendered as relative time on the frontend). $details = []; /** * Filters the user card detail items. * * Add-ons can add detail items shown in the user card popover. * Each item should have: key (string), label (string), value (string), and optionally type (string). * * Example — adding last login time: * $details[] = [ * 'key' => 'last_login', * 'label' => __( 'Logged in', 'simple-history' ), * 'value' => '2026-03-01 14:30:00', // Local time. * 'type' => 'date', * ]; * * @since 5.24.0 * * @param array $details Array of detail items. * @param \WP_User $user The WordPress user object. */ $data['details'] = apply_filters( 'simple_history/user_card/details', $details, $user ); // Actions: links shown in the actions section of the card. // Each item: [ 'key' => string, 'label' => string, 'url' => string ]. // Core provides "View user profile". Add-ons use the filter to add // links like "View all user activity". $actions = [ [ 'key' => 'view_profile', 'label' => __( 'View user profile', 'simple-history' ), 'url' => get_edit_user_link( $user->ID ), ], ]; /** * Filters the user card action links. * * Add-ons can add action links shown in the user card popover. * Each item should have: key (string), label (string), url (string). * * Example — adding an activity filter link: * $actions[] = [ * 'key' => 'view_activity', * 'label' => __( 'View all user activity', 'my-plugin' ), * 'url' => admin_url( '...' ), * ]; * * @since 5.24.0 * * @param array $actions Array of action link items. * @param \WP_User $user The WordPress user object. */ $data['actions'] = apply_filters( 'simple_history/user_card/actions', $actions, $user ); return rest_ensure_response( $data ); } /** * Get card data for a non-user initiator type. * * Returns a filterable response so add-ons can extend it * (e.g., adding "View all activity" action links). * * @param \WP_REST_Request $request Full details about the request. * @return \WP_REST_Response Response object. */ public function get_initiator_card( $request ) { $type = $request->get_param( 'type' ); $actions = []; /** * Filters the initiator card action links. * * Add-ons can add action links shown in the non-user initiator card popover. * Each item should have: key (string), label (string), url (string). * * @since 5.24.0 * * @param array $actions Array of action link items. * @param string $type The initiator type (wp, wp_cli, web_user, other). */ $actions = apply_filters( 'simple_history/initiator_card/actions', $actions, $type ); // Build stats details for this initiator type. $details = [ [ 'key' => 'events_today', 'label' => __( 'Today', 'simple-history' ), 'value' => self::get_initiator_event_count( $type, 1 ), 'type' => 'stat', ], [ 'key' => 'events_7_days', 'label' => __( 'Last 7 days', 'simple-history' ), 'value' => self::get_initiator_event_count( $type, 7 ), 'type' => 'stat', ], [ 'key' => 'events_total', 'label' => __( 'Total', 'simple-history' ), 'value' => self::get_initiator_total_event_count( $type ), 'type' => 'stat', ], ]; /** * Filters the initiator card detail items. * * Add-ons can add detail items shown in the non-user initiator card popover. * Each item should have: key (string), label (string), value (string|int), * and optionally type (string: 'text', 'date', or 'stat'). * * @since 5.25.0 * * @param array $details Array of detail items. * @param string $type The initiator type (wp, wp_cli, web_user, other). */ $details = apply_filters( 'simple_history/initiator_card/details', $details, $type ); $data = [ 'initiator' => $type, 'has_premium_add_on' => Helpers::is_premium_add_on_active(), 'details' => $details, 'actions' => $actions, ]; return rest_ensure_response( $data ); } /** * Get the last login date for a user from Simple History logs. * * Useful for add-ons that want to show login time in the user card * via the 'simple_history/user_card/details' filter. * * @param int $user_id WordPress user ID. * @return string|null Date string in site local timezone, or null if no login found. */ public static function get_last_login( $user_id ) { return self::get_most_recent_event_date( $user_id, 'SimpleUserLogger:user_logged_in' ); } /** * Get the number of events for a user within a given number of days. * * Useful for add-ons that want to show activity counts in the user card * via the 'simple_history/user_card/details' filter. * * @param int $user_id WordPress user ID. * @param int $period_days Number of days to look back (including today). * @return int Number of events found. */ public static function get_user_event_count( $user_id, $period_days ) { $log_query = new Log_Query(); $date_from = Date_Helper::get_last_n_days_start_timestamp( $period_days ); $query_result = $log_query->query( [ 'user' => $user_id, 'posts_per_page' => 1, 'date_from' => $date_from, 'ungrouped' => true, ] ); return $query_result['total_row_count'] ?? 0; } /** * Get the total number of logged events for a user (all time). * * @param int $user_id WordPress user ID. * @return int Number of events found. */ public static function get_user_total_event_count( $user_id ) { $log_query = new Log_Query(); $query_result = $log_query->query( [ 'user' => $user_id, 'posts_per_page' => 1, 'ungrouped' => true, ] ); return $query_result['total_row_count'] ?? 0; } /** * Get the most recent event date for a user from Simple History logs. * * Useful for add-ons that want to show last activity in the user card * via the 'simple_history/user_card/details' filter. * * @param int $user_id WordPress user ID. * @return string|null Date string in site local timezone, or null if no events found. */ public static function get_last_event( $user_id ) { return self::get_most_recent_event_date( $user_id ); } /** * Get the number of events for a non-user initiator within a given number of days. * * @param string $initiator_type Initiator type (wp, wp_cli, web_user, other). * @param int $period_days Number of days to look back (including today). * @return int Number of events found. */ public static function get_initiator_event_count( $initiator_type, $period_days ) { $log_query = new Log_Query(); $date_from = Date_Helper::get_last_n_days_start_timestamp( $period_days ); $query_result = $log_query->query( [ 'initiator' => $initiator_type, 'posts_per_page' => 1, 'date_from' => $date_from, 'ungrouped' => true, ] ); return $query_result['total_row_count'] ?? 0; } /** * Get the total number of logged events for a non-user initiator (all time). * * @param string $initiator_type Initiator type (wp, wp_cli, web_user, other). * @return int Number of events found. */ public static function get_initiator_total_event_count( $initiator_type ) { $log_query = new Log_Query(); $query_result = $log_query->query( [ 'initiator' => $initiator_type, 'posts_per_page' => 1, 'ungrouped' => true, ] ); return $query_result['total_row_count'] ?? 0; } /** * Get the most recent event date for a user, optionally filtered by message type. * * @param int $user_id WordPress user ID. * @param string|null $messages Optional message filter (e.g. 'SimpleUserLogger:user_logged_in'). * @return string|null Date string in site local timezone, or null if no events found. */ private static function get_most_recent_event_date( $user_id, $messages = null ) { $log_query = new Log_Query(); $args = [ 'user' => $user_id, 'posts_per_page' => 1, 'skip_count_query' => true, 'ungrouped' => true, ]; if ( $messages !== null ) { $args['messages'] = $messages; } $query_result = $log_query->query( $args ); $events = $query_result['log_rows'] ?? []; if ( empty( $events ) ) { return null; } return get_date_from_gmt( $events[0]->date ); } }