Skip to content
wiki.fftac.org

Class Uai1 Membership - Source Excerpt 03

Back to Class Uai1 Membership

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}
     */