*/ public function settings(): array { if (class_exists('\AKSRT\Settings\Settings')) { return \AKSRT\Settings\Settings::get_submit_settings(); } return [ 'enabled' => true, 'title_min' => 5, 'title_max' => 30, 'allowed_cat_ids' => [], 'default_user_id' => 0, 'guest_enabled' => false, 'allow_category' => true, 'allow_tags' => true, 'allow_cover' => true, 'topics_s' => false, 'custom_filter_s' => true, 'review_mode' => 'pending', 'pay_free_s' => true, 'pay_price_min' => 0, 'pay_price_max' => 100, 'pay_vip_price_s' => true, 'pay_vip_1_discount' => 80, 'pay_vip_2_discount' => 50, ]; } /** * Whether the user (or guest) may open / create a submission. */ public function can_submit(?int $user_id = null): bool { $settings = $this->settings(); if (empty($settings['enabled'])) { return false; } if ($user_id === null) { $user_id = get_current_user_id(); } if ($user_id <= 0) { return !empty($settings['guest_enabled']) && (int) ($settings['default_user_id'] ?? 0) > 0; } return $this->user_can_cap('new_post_add', $user_id); } public function can_edit_post(int $post_id, ?int $user_id = null): bool { if ($post_id <= 0) { return false; } if ($user_id === null) { $user_id = get_current_user_id(); } if ($user_id <= 0) { return false; } if (user_can($user_id, 'manage_options') || user_can($user_id, 'edit_others_posts')) { return true; } $post = get_post($post_id); if (!$post || $post->post_type !== 'post') { return false; } if ((int) $post->post_author !== $user_id) { return false; } // Own drafts always editable when user can add posts. if ($post->post_status === 'draft' && $this->user_can_cap('new_post_add', $user_id)) { return true; } return $this->user_can_cap('new_post_edit', $user_id, $post_id); } public function can_delete_post(int $post_id, ?int $user_id = null): bool { if ($user_id === null) { $user_id = get_current_user_id(); } if ($user_id <= 0) { return false; } if (user_can($user_id, 'manage_options')) { return true; } $post = get_post($post_id); if (!$post || $post->post_type !== 'post') { return false; } if ((int) $post->post_author !== $user_id) { return false; } if ($post->post_status === 'draft' && $this->user_can_cap('new_post_add', $user_id)) { return true; } return $this->user_can_cap('new_post_delete', $user_id, $post_id); } public function user_can_cap(string $cap, int $user_id = 0, ?int $context = null): bool { if ($user_id > 0 && user_can($user_id, 'manage_options')) { return true; } if (function_exists('aksrt_user_can')) { return aksrt_user_can($cap, $user_id, $context); } if (class_exists('\AKSRT\Settings\Settings') && method_exists('\AKSRT\Settings\Settings', 'user_can')) { return \AKSRT\Settings\Settings::user_can($cap, $user_id, $context); } return $user_id > 0; } /** * @param array $data * @return array{success:bool,message:string,post_id?:int} */ public function submit(array $data): array { $action = sanitize_key((string) ($data['action_type'] ?? $data['submit_action'] ?? 'posts_save')); if ($action === 'aksrt_save_draft' || ($data['status'] ?? '') === 'draft') { $action = 'posts_draft'; } else { $action = 'posts_save'; } return $this->persist($data, $action); } /** * @param array $data * @return array{success:bool,message:string,post_id?:int} */ public function update(int $post_id, array $data): array { $data['posts_id'] = $post_id; $action = (($data['status'] ?? '') === 'draft') ? 'posts_draft' : 'posts_save'; return $this->persist($data, $action); } public function ajax_submit_post(): void { $this->verify_nonce(); $this->maybe_verify_captcha(); $data = wp_unslash($_POST); $result = $this->persist(is_array($data) ? $data : [], 'posts_save'); $this->send_result($result); } public function ajax_save_draft(): void { $this->verify_nonce(); if (!is_user_logged_in()) { wp_send_json_error(['message' => __('请先登录', 'aksrt')]); } $data = wp_unslash($_POST); $result = $this->persist(is_array($data) ? $data : [], 'posts_draft'); $this->send_result($result); } public function ajax_update_post(): void { $this->verify_nonce(); $data = wp_unslash($_POST); if (!is_array($data)) { $data = []; } $post_id = absint($data['posts_id'] ?? $data['post_id'] ?? $data['edit_id'] ?? 0); if ($post_id <= 0) { wp_send_json_error(['message' => __('文章 ID 无效', 'aksrt')]); } $data['posts_id'] = $post_id; $action = (($data['status'] ?? '') === 'draft') ? 'posts_draft' : 'posts_save'; $result = $this->persist($data, $action); $this->send_result($result); } public function ajax_delete_draft(): void { $this->verify_nonce(); $user_id = get_current_user_id(); if ($user_id <= 0) { wp_send_json_error(['message' => __('请先登录', 'aksrt')]); } $post_id = absint($_POST['draft_id'] ?? $_POST['post_id'] ?? $_POST['id'] ?? 0); if ($post_id <= 0) { wp_send_json_error(['message' => __('草稿 ID 无效', 'aksrt')]); } $post = get_post($post_id); if (!$post || (int) $post->post_author !== $user_id) { wp_send_json_error(['message' => __('没有删除权限', 'aksrt')]); } if ($post->post_status !== 'draft' && !$this->can_delete_post($post_id, $user_id)) { wp_send_json_error(['message' => __('只能删除草稿', 'aksrt')]); } if ($post->post_status === 'draft') { $ok = wp_delete_post($post_id, true); } else { $ok = wp_trash_post($post_id); } if ($ok) { wp_send_json_success(['message' => __('已删除', 'aksrt')]); } wp_send_json_error(['message' => __('删除失败', 'aksrt')]); } public function ajax_delete_post(): void { $this->verify_nonce(); $user_id = get_current_user_id(); $post_id = absint($_POST['id'] ?? $_POST['post_id'] ?? 0); if (!$this->can_delete_post($post_id, $user_id)) { wp_send_json_error(['message' => __('您没有删除此内容的权限', 'aksrt')]); } $post = get_post($post_id); if (!$post || $post->post_status === 'trash') { wp_send_json_success(['message' => __('文章已经删除', 'aksrt'), 'reload' => true]); } wp_trash_post($post_id); wp_send_json_success([ 'message' => __('文章已经删除', 'aksrt'), 'reload' => true, 'goto' => home_url('/'), ]); } private function verify_nonce(): void { $nonce = (string) ($_REQUEST['_nonce'] ?? $_REQUEST['nonce'] ?? $_REQUEST['_wpnonce'] ?? ''); if ($nonce === '' || ( !wp_verify_nonce($nonce, 'aksrt_submit') && !wp_verify_nonce($nonce, 'aksrt_submit_nonce') )) { wp_send_json_error(['message' => __('安全验证失败,请刷新页面重试', 'aksrt')], 403); } } private function maybe_verify_captcha(): void { $settings = $this->settings(); if (empty($settings['captcha'])) { return; } if (!function_exists('aksrt_require_captcha')) { return; } $payload = []; if (isset($_POST['captcha']) && is_array($_POST['captcha'])) { $payload = wp_unslash($_POST['captcha']); } $verify = aksrt_require_captcha('submit', is_array($payload) ? $payload : []); if (is_wp_error($verify)) { wp_send_json_error(['message' => $verify->get_error_message()]); } } /** * @param array{success:bool,message?:string} $result */ private function send_result(array $result): void { if (!empty($result['success'])) { wp_send_json_success($result); } wp_send_json_error($result); } /** * Downloads image URL into media library as featured image. */ private function set_thumbnail_from_url(int $post_id, string $url): void { if ($url === '' || !filter_var($url, FILTER_VALIDATE_URL)) { return; } if (!function_exists('media_sideload_image')) { require_once ABSPATH . 'wp-admin/includes/media.php'; require_once ABSPATH . 'wp-admin/includes/file.php'; require_once ABSPATH . 'wp-admin/includes/image.php'; } $ext = strtolower(pathinfo((string) (parse_url($url, PHP_URL_PATH) ?? ''), PATHINFO_EXTENSION)); $allowed = ['jpg', 'jpeg', 'png', 'gif', 'webp']; if ($ext !== '' && !in_array($ext, $allowed, true)) { return; } $attachment_id = media_sideload_image($url, $post_id, '', 'id'); if (!is_wp_error($attachment_id)) { set_post_thumbnail($post_id, (int) $attachment_id); } } /** * @param string[] $classes * @return string[] */ public function body_class(array $classes): array { if ($this->is_submit_template()) { $classes[] = 'aksrt-page-submit'; $classes[] = 'aksrt-hide-float'; $classes[] = 'aksrt-hide-tabbar'; } return $classes; } /** * @param array $robots * @return array */ public function robots_noindex(array $robots): array { if ($this->is_submit_template()) { $robots['noindex'] = true; $robots['nofollow'] = true; } return $robots; } /** * @param mixed $enabled * @return mixed */ public function disable_chrome_on_submit($enabled) { if ($this->is_submit_template()) { return false; } return $enabled; } public function is_submit_template(): bool { return is_page_template('templates/pages/page-submit.php'); } }