' . esc_html__( 'AdminTrace Activity Logger stores an activity journal in the site database. Entries can include the display name and username of the account that made a change, a short description of the change, the related content title, and the time of the event. A post edit can also include a short line-by-line preview of the changed text. The full post is not copied into the journal. When IP recording is left at its default, only a masked address is stored: the last part of an IPv4 address is removed, and only the first half of an IPv6 address is kept. The plugin does not store passwords, application passwords, API keys, or the contents of private messages.', 'admintrace-activity-logger' ) . '
'; $content .= '' . esc_html__( 'Events are kept for the retention period chosen in AdminTrace Activity Logger settings, then deleted. A site administrator can export or delete the journal sooner. If a webhook or email notification is enabled, the summary of an event is sent to the address the administrator configured. AdminTrace Activity Logger does not send the journal anywhere else and does not look up IP addresses with an external service.', 'admintrace-activity-logger' ) . '
'; wp_add_privacy_policy_content( 'AdminTrace Activity Logger', wp_kses_post( $content ) ); } /** * Register the exporter. * * @param array $exporters Exporters. * @return array */ public static function exporters( $exporters ) { $exporters['admintrace-activity-logger'] = array( 'exporter_friendly_name' => __( 'AdminTrace Activity Logger', 'admintrace-activity-logger' ), 'callback' => array( __CLASS__, 'export_personal_data' ), ); return $exporters; } /** * Register the eraser. * * @param array $erasers Erasers. * @return array */ public static function erasers( $erasers ) { $erasers['admintrace-activity-logger'] = array( 'eraser_friendly_name' => __( 'AdminTrace Activity Logger', 'admintrace-activity-logger' ), 'callback' => array( __CLASS__, 'erase_personal_data' ), ); return $erasers; } /** * Export events tied to an email address. * * @param string $email Email address. * @param int $page Page number. * @return array */ public static function export_personal_data( $email, $page = 1 ) { $user = get_user_by( 'email', $email ); $page = max( 1, (int) $page ); if ( ! $user ) { return array( 'data' => array(), 'done' => true, ); } $result = Query::search( array( 'user_id' => (int) $user->ID, 'page' => $page, 'per_page' => 50, 'unrestricted' => true, 'internal_limit' => true, ) ); $data = array(); foreach ( $result['rows'] as $row ) { $data[] = array( 'group_id' => 'admintrace-activity-logger', 'group_label' => __( 'Activity journal', 'admintrace-activity-logger' ), 'item_id' => 'event-' . (int) $row['id'], 'data' => array( array( 'name' => __( 'Time (UTC)', 'admintrace-activity-logger' ), 'value' => $row['created_gmt'], ), array( 'name' => __( 'Activity', 'admintrace-activity-logger' ), 'value' => $row['summary'], ), array( 'name' => __( 'Category', 'admintrace-activity-logger' ), 'value' => $row['category'], ), array( 'name' => __( 'Masked network', 'admintrace-activity-logger' ), 'value' => $row['ip_masked'], ), ), ); } return array( 'data' => $data, 'done' => count( $result['rows'] ) < 50, ); } /** * Delete events tied to an email address. * * @param string $email Email address. * @param int $page Page number. * @return array */ public static function erase_personal_data( $email, $page = 1 ) { unset( $page ); $user = get_user_by( 'email', $email ); if ( ! $user ) { return array( 'items_removed' => false, 'items_retained' => false, 'messages' => array(), 'done' => true, ); } global $wpdb; // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- the plugin's own events table has no WordPress API; journal reads must be live. $wpdb->query( $wpdb->prepare( 'DELETE FROM %i WHERE blog_id = %d AND (user_id = %d OR (user_id = 0 AND user_login = %s))', Installer::table(), get_current_blog_id(), (int) $user->ID, $user->user_login ) ); return array( 'items_removed' => (int) $wpdb->rows_affected > 0, 'items_retained' => false, 'messages' => array(), 'done' => true, ); } }