'Users excluded from the log', self::OPTION_ROLES => 'Roles excluded from the log', ); /** * Whether events attributed to this user are left out of the log. */ public static function excludes( int $user_id ): bool { if ( $user_id <= 0 ) { return false; } if ( in_array( $user_id, self::users(), true ) ) { return true; } $roles = self::roles(); if ( array() === $roles ) { return false; } $user = get_userdata( $user_id ); if ( ! $user instanceof \WP_User ) { return false; } return array() !== array_intersect( $roles, array_map( 'strval', (array) $user->roles ) ); } /** * Whether this event is the record of a change to the exclusion lists, * which is written whoever makes it. * * @param array|null $details The event's details. */ public static function is_change_to_exclusions( string $event_type, ?array $details ): bool { return 'setting_changed' === $event_type && is_array( $details ) && isset( self::LABELS[ (string) ( $details['option'] ?? '' ) ] ); } /** * The excluded user IDs. * * @return int[] */ public static function users(): array { return self::ids( get_option( self::OPTION_USERS, array() ) ); } /** * The excluded role slugs. * * @return string[] */ public static function roles(): array { $stored = get_option( self::OPTION_ROLES, array() ); if ( ! is_array( $stored ) ) { return array(); } $roles = array(); foreach ( $stored as $role ) { if ( is_string( $role ) && '' !== $role && ! in_array( $role, $roles, true ) ) { $roles[] = $role; } } return $roles; } /** * Role slugs as posted, kept to the roles the site has. * * @param mixed $posted The ticked slugs, or anything else for none. * @return string[] */ public static function sanitize_roles( $posted ): array { if ( ! is_array( $posted ) ) { return array(); } $known = array_keys( wp_roles()->get_names() ); $roles = array(); foreach ( $posted as $role ) { $role = is_string( $role ) ? sanitize_key( $role ) : ''; if ( in_array( $role, $known, true ) && ! in_array( $role, $roles, true ) ) { $roles[] = $role; } } return $roles; } /** * Usernames typed one per line (or comma-separated), resolved to the IDs * of the users that exist. Stored by ID, so renaming a user does not * quietly lift their exclusion; a name that matches nobody is dropped. * * @return int[] */ public static function ids_from_logins( string $typed ): array { $ids = array(); $lines = preg_split( '/[\r\n,]+/', $typed ); foreach ( is_array( $lines ) ? $lines : array() as $login ) { $login = sanitize_user( trim( $login ), true ); if ( '' === $login ) { continue; } $user = get_user_by( 'login', $login ); if ( $user instanceof \WP_User && ! in_array( (int) $user->ID, $ids, true ) ) { $ids[] = (int) $user->ID; } } return $ids; } /** * The excluded users' logins, one per line, for the settings screen. * A deleted user has no login to show and cannot act anyway. */ public static function logins(): string { $logins = array(); foreach ( self::users() as $id ) { $user = get_userdata( $id ); if ( $user instanceof \WP_User ) { $logins[] = (string) $user->user_login; } } return implode( "\n", $logins ); } /** * @param mixed $stored An option value. * @return int[] */ private static function ids( $stored ): array { if ( ! is_array( $stored ) ) { return array(); } $ids = array(); foreach ( $stored as $id ) { $id = is_numeric( $id ) ? (int) $id : 0; if ( $id > 0 && ! in_array( $id, $ids, true ) ) { $ids[] = $id; } } return $ids; } }