forum->get_config(); $vote_max = (int) ($config['other']['vote_max'] ?? 8); if ($vote_max > 0 && count($labels) > $vote_max) { $labels = array_slice($labels, 0, $vote_max); } $vote_type = sanitize_key((string) ($data['vote_type'] ?? 'standard')); if ($vote_type === 'pk' && count($labels) !== 2) { $vote_type = 'standard'; } if ($vote_type === 'pk') { $multiple = false; } if (count($labels) < 2) { $enabled = false; } $expiry_days = (int) ($data['vote_expiry_days'] ?? 0); $options = []; foreach ($labels as $index => $label) { $options[] = [ 'id' => 'option_' . ($index + 1), 'label' => $label, 'count' => 0, ]; } return [ 'enabled' => $enabled, 'title' => $title, 'multiple' => $multiple, 'vote_type' => $vote_type, 'expiry_days' => $expiry_days, 'options' => $options, ]; } /** * Save vote meta while preserving counts when possible. */ public function save_vote_meta(int $topic_id, array $vote_meta): void { $existing_options = get_post_meta($topic_id, '_aksrt_vote_options', true); $existing_options = is_array($existing_options) ? $existing_options : []; $existing_by_label = []; foreach ($existing_options as $existing_option) { if (!empty($existing_option['label'])) { $existing_by_label[(string) $existing_option['label']] = $existing_option; } } $options = []; foreach ($vote_meta['options'] as $index => $option) { $label = (string) ($option['label'] ?? ''); if ($label === '') { continue; } $existing = $existing_by_label[$label] ?? null; $options[] = [ 'id' => $existing['id'] ?? ('option_' . ($index + 1)), 'label' => $label, 'count' => (int) ($existing['count'] ?? 0), ]; } update_post_meta($topic_id, '_aksrt_vote_enabled', !empty($vote_meta['enabled']) ? '1' : '0'); update_post_meta($topic_id, '_aksrt_vote_title', sanitize_text_field((string) ($vote_meta['title'] ?? ''))); update_post_meta($topic_id, '_aksrt_vote_multiple', !empty($vote_meta['multiple']) ? '1' : '0'); update_post_meta($topic_id, '_aksrt_vote_options', $options); $vote_type = in_array($vote_meta['vote_type'] ?? '', ['standard', 'pk'], true) ? $vote_meta['vote_type'] : 'standard'; update_post_meta($topic_id, '_aksrt_vote_type', $vote_type); $expiry_days = (int) ($vote_meta['expiry_days'] ?? 0); if (!in_array($expiry_days, [0, 1, 7, 30], true)) { $expiry_days = 0; } update_post_meta($topic_id, '_aksrt_vote_expiry_days', $expiry_days); if ($expiry_days > 0 && !get_post_meta($topic_id, '_aksrt_vote_started_at', true)) { update_post_meta($topic_id, '_aksrt_vote_started_at', current_time('mysql')); } if (empty($vote_meta['enabled'])) { delete_post_meta($topic_id, '_aksrt_vote_records'); } } /** * Get vote payload for a topic. */ public function get_vote_payload(int $topic_id, int $user_id = 0): array { $enabled = get_post_meta($topic_id, '_aksrt_vote_enabled', true) === '1'; $options = get_post_meta($topic_id, '_aksrt_vote_options', true); $options = is_array($options) ? $options : []; $records = get_post_meta($topic_id, '_aksrt_vote_records', true); $records = is_array($records) ? $records : []; $vote_type = sanitize_key((string) get_post_meta($topic_id, '_aksrt_vote_type', true)); if (!in_array($vote_type, ['standard', 'pk'], true)) { $vote_type = 'standard'; } $expiry_days = (int) get_post_meta($topic_id, '_aksrt_vote_expiry_days', true); $started_at = (string) get_post_meta($topic_id, '_aksrt_vote_started_at', true); $expired = false; if ($expiry_days > 0 && $started_at !== '') { $expire_time = strtotime($started_at) + ($expiry_days * DAY_IN_SECONDS); $expired = time() >= $expire_time; } $config = $this->forum->get_config(); $display_mode = $config['other']['vote_number_type'] ?? 'percent'; $selected = $user_id > 0 && isset($records[(string) $user_id]) && is_array($records[(string) $user_id]) ? array_values(array_map('strval', $records[(string) $user_id])) : []; $total_votes = 0; foreach ($options as &$option) { $count = max(0, (int) ($option['count'] ?? 0)); $option['count'] = $count; $option['selected'] = in_array((string) ($option['id'] ?? ''), $selected, true); $total_votes += $count; } unset($option); return [ 'enabled' => $enabled && !empty($options), 'title' => (string) get_post_meta($topic_id, '_aksrt_vote_title', true), 'multiple' => get_post_meta($topic_id, '_aksrt_vote_multiple', true) === '1', 'vote_type' => $vote_type, 'expiry_days' => $expiry_days, 'expired' => $expired, 'display_mode' => $display_mode, 'options' => $options, 'total_votes' => $total_votes, 'has_voted' => !empty($selected), 'selected' => $selected, ]; } // ================================================================ // Content processing // ================================================================ /** * Save governance meta fields from an editable payload. */ public function save_topic_governance_meta(int $topic_id, array $data): void { if (isset($data['visibility'])) { $visibility = sanitize_key((string) $data['visibility']); if (isset($this->get_visibility_map()[$visibility])) { update_post_meta($topic_id, '_aksrt_visibility', $visibility); } } if (array_key_exists('special_topic', $data)) { update_post_meta($topic_id, '_aksrt_special_topic', sanitize_text_field((string) $data['special_topic'])); } if (array_key_exists('vote_enabled', $data) || array_key_exists('vote_options', $data) || array_key_exists('vote_options_text', $data)) { $this->save_vote_meta($topic_id, $this->prepare_vote_meta($data)); } } public function save_cover_meta(int $post_id, array $data): void { $cover_type = sanitize_key((string) ($data['cover_type'] ?? '')); if (!in_array($cover_type, ['image', 'slide', 'video'], true)) { delete_post_meta($post_id, '_aksrt_cover_type'); return; } update_post_meta($post_id, '_aksrt_cover_type', $cover_type); if ($cover_type === 'image') { $url = esc_url_raw((string) ($data['cover_image'] ?? '')); update_post_meta($post_id, '_aksrt_cover_image', $url); } elseif ($cover_type === 'slide') { $raw = $data['featured_slide'] ?? ''; $slides = is_array($raw) ? $raw : json_decode((string) $raw, true); if (!is_array($slides)) { $slides = []; } $slides = array_values(array_filter(array_map('esc_url_raw', array_slice($slides, 0, 9)))); update_post_meta($post_id, '_aksrt_featured_slide', $slides); } elseif ($cover_type === 'video') { $url = esc_url_raw((string) ($data['featured_video'] ?? '')); update_post_meta($post_id, '_aksrt_featured_video', $url); } } /** * Sanitize topic content based on user's compose capabilities. * * Strips ,