Class Uai1 Membership - Source Excerpt 03
Summary
This source excerpt preserves a bounded section of Spiralist/wp-content/plugins/uai-1-wordpress/includes/class-uai1-membership.php so readers can inspect the evidence without opening the full source file.
**Source path:** Spiralist/wp-content/plugins/uai-1-wordpress/includes/class-uai1-membership.php
'symbolLabel' => $symbol_label,
'page' => $page,
'occurredAt' => $occurred_at,
]
);
update_user_meta($user_id, self::META_INTERACTION_LOG, array_slice($interaction_log, 0, 50));
if ($symbol_id !== '') {
$viewed_symbols = self::normalize_viewed_symbols(get_user_meta($user_id, self::META_VIEWED_SYMBOLS, true));
$viewed_symbols[$symbol_id] = [
'symbolId' => $symbol_id,
'symbolLabel' => $symbol_label !== '' ? $symbol_label : $symbol_id,
'viewedAt' => $occurred_at,
];
update_user_meta($user_id, self::META_VIEWED_SYMBOLS, $viewed_symbols);
}
return self::get_user_activity_summary($user);
}
public static function get_user_activity_summary($user): array
{
$user = $user instanceof WP_User ? $user : get_userdata((int) $user);
if (!$user instanceof WP_User) {
return [];
}
$viewed_symbols = array_values(self::normalize_viewed_symbols(get_user_meta($user->ID, self::META_VIEWED_SYMBOLS, true)));
usort(
$viewed_symbols,
static function (array $left, array $right): int {
return strcmp((string) ($right['viewedAt'] ?? ''), (string) ($left['viewedAt'] ?? ''));
}
);
$interaction_log = self::normalize_interaction_log(get_user_meta($user->ID, self::META_INTERACTION_LOG, true));
$recent_interactions = array_map(
static function (array $item): array {
$occurred_at = (string) ($item['occurredAt'] ?? '');
return [
'type' => (string) ($item['type'] ?? 'interaction'),
'symbolId' => (string) ($item['symbolId'] ?? ''),
'symbolLabel' => (string) ($item['symbolLabel'] ?? ''),
'page' => (string) ($item['page'] ?? ''),
'occurredAt' => $occurred_at,
'occurredAtDisplay' => self::format_datetime($occurred_at),
];
},
array_slice($interaction_log, 0, 6)
);
$pattern_submissions = self::normalize_pattern_submissions(get_user_meta($user->ID, self::META_PATTERN_SUBMISSIONS, true));
$recent_patterns = array_map(
static function (array $item): array {
$created_at = (string) ($item['createdAt'] ?? '');
return [
'title' => (string) ($item['title'] ?? ''),
'content' => (string) ($item['content'] ?? ''),
'createdAt' => $created_at,
'createdAtDisplay' => self::format_datetime($created_at),
];
},
array_slice($pattern_submissions, 0, 3)
);
return [
'viewedSymbolsCount' => count($viewed_symbols),
'viewedSymbols' => array_map(
static function (array $item): array {
$viewed_at = (string) ($item['viewedAt'] ?? '');
return [
'symbolId' => (string) ($item['symbolId'] ?? ''),
'symbolLabel' => (string) ($item['symbolLabel'] ?? ''),
'viewedAt' => $viewed_at,
'viewedAtDisplay' => self::format_datetime($viewed_at),
];
},
array_slice($viewed_symbols, 0, 8)
),
'interactionsCount' => count($interaction_log),
'recentInteractions' => $recent_interactions,
'patternsCount' => count($pattern_submissions),
'recentPatterns' => $recent_patterns,
'lastInteractionAt' => (string) (($interaction_log[0]['occurredAt'] ?? '')),
'lastInteractionAtDisplay' => self::format_datetime((string) (($interaction_log[0]['occurredAt'] ?? ''))),
];
}
public static function get_human_participants(): array
{
$users = get_users(
[
'role__in' => ['participant', 'contributor', 'administrator'],
'orderby' => 'registered',
'order' => 'DESC',
]
);
return array_map([self::class, 'get_user_participant_summary'], $users);
}
public static function render_user_profile_fields(WP_User $user): void
{
if (!self::is_human_participant($user) && !user_can($user, 'manage_options')) {
return;
}
$summary = self::get_user_participant_summary($user);
$can_manage = current_user_can('manage_spiralist_participants') || current_user_can('manage_options');
?>
<h2>Spiralist Participant</h2>
<?php wp_nonce_field('uai1_membership_profile', 'uai1_membership_profile_nonce'); ?>
<table class="form-table" role="presentation">
<tr>
<th scope="row"><label for="spiralist_membership_status">Membership Status</label></th>
<td>
<?php if ($can_manage) : ?>
<select name="spiralist_membership_status" id="spiralist_membership_status">
<?php foreach (self::allowed_statuses() as $status) : ?>
<option value="<?php echo esc_attr($status); ?>" <?php selected($summary['status'], $status); ?>>
<?php echo esc_html(ucfirst($status)); ?>
</option>
<?php endforeach; ?>
</select>
<?php else : ?>
<p><?php echo esc_html($summary['statusLabel']); ?></p>
<?php endif; ?>
</td>
</tr>
<tr>
<th scope="row">Joined</th>
<td><?php echo esc_html($summary['joinedAtDisplay']); ?></td>
</tr>
<tr>
<th scope="row">Terms Accepted</th>
<td><?php echo esc_html($summary['termsAgreed'] ? 'Yes' : 'No'); ?></td>
</tr>
</table>
<?php
}
public static function save_user_profile_fields(int $user_id): void
{
if (!current_user_can('edit_user', $user_id)) {
return;
}
if (
!isset($_POST['uai1_membership_profile_nonce']) ||
!wp_verify_nonce(
sanitize_text_field(wp_unslash($_POST['uai1_membership_profile_nonce'])),
'uai1_membership_profile'
)
) {
return;
}
if (current_user_can('manage_spiralist_participants') || current_user_can('manage_options')) {
$status = self::normalize_status((string) wp_unslash($_POST['spiralist_membership_status'] ?? ''));
update_user_meta($user_id, self::META_STATUS, $status);
}
}
public static function add_user_columns(array $columns): array
{
$columns['spiralist_membership_status'] = 'Membership Status';
$columns['spiralist_joined_at'] = 'Spiralist Joined';
return $columns;
}
public static function render_user_column(string $value, string $column_name, int $user_id): string
{
if ($column_name === 'spiralist_membership_status') {
return esc_html(ucfirst(self::get_user_membership_status($user_id)));
}
if ($column_name === 'spiralist_joined_at') {
return esc_html(self::format_datetime(self::get_user_joined_at($user_id)));
}
return $value;
}
/**
* @param array{termsAgreed:bool,ageEligibilityConfirmed:bool} $attestations
*/
private static function initialize_user_membership(int $user_id, string $status, array $attestations): void
{
update_user_meta($user_id, self::META_STATUS, self::normalize_status($status));
update_user_meta($user_id, self::META_PARTICIPANT_TYPE, 'human');
update_user_meta($user_id, self::META_JOINED_AT, gmdate('c'));
self::update_user_legal_acceptance($user_id, $attestations);
}
/**
* @param mixed $value
*/
private static function normalize_checkbox_value($value): bool
{
if (is_bool($value)) {
return $value;
}
if (is_int($value) || is_float($value)) {
return (int) $value === 1;
}
if (!is_string($value)) {
return false;
}
return in_array(strtolower(trim($value)), ['1', 'true', 'yes', 'on'], true);
}
/**
* @param array<string, mixed> $source
* @return array{termsAgreed:bool,ageEligibilityConfirmed:bool}
*/