565 lines
21 KiB
PHP
565 lines
21 KiB
PHP
<?php
|
||
/**
|
||
* 已发布文章的改稿版本(Jio Creator Studio)。
|
||
*
|
||
* 作者修改一篇已发布文章时,改动不会直接写入线上文章,而是写入一个私有的
|
||
* 投稿版本(私有 post type)。线上文章的内容、永久链接与付费条款在审核通过
|
||
* 前保持不变;审核通过后由本类一次性把版本内容应用到源文章。
|
||
*
|
||
* 新文章仍走既有 FrontSubmit::persist() 的 draft → pending/publish 流程;只有
|
||
* 源文章已发布时才进入版本流程,避免线上内容被静默改写。
|
||
*
|
||
* @package Jio
|
||
*/
|
||
|
||
namespace Jio\Core;
|
||
|
||
use Jio\Content\PrivateAssets;
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
final class SubmissionVersion {
|
||
|
||
public const POST_TYPE = 'jio_submission';
|
||
|
||
/** 版本记录上的 meta。 */
|
||
public const META_SOURCE = '_jio_source_post';
|
||
public const META_SOURCE_REV = '_jio_source_rev';
|
||
public const META_REV = '_jio_version_rev';
|
||
public const META_STATUS = '_jio_review_status';
|
||
public const META_NOTE = '_jio_review_note';
|
||
public const META_SNAPSHOT = '_jio_snapshot';
|
||
public const META_SUBMITTED_AT = '_jio_submitted_at';
|
||
|
||
public const STATUS_WORKING = 'working';
|
||
public const STATUS_PENDING = 'pending';
|
||
public const STATUS_APPROVED = 'approved';
|
||
public const STATUS_REJECTED = 'rejected';
|
||
|
||
private static $instance = null;
|
||
|
||
public static function get_instance(): self {
|
||
if (null === self::$instance) {
|
||
self::$instance = new self();
|
||
}
|
||
return self::$instance;
|
||
}
|
||
|
||
public function init(): void {
|
||
add_action('init', [$this, 'register_post_type'], 2);
|
||
add_action('admin_post_jio_submission_approve', [$this, 'admin_post_approve']);
|
||
add_action('admin_post_jio_submission_reject', [$this, 'admin_post_reject']);
|
||
add_filter('wp_robots', [$this, 'robots_noindex']);
|
||
}
|
||
|
||
public function admin_post_approve(): void {
|
||
$this->handle_review_action('approve');
|
||
}
|
||
|
||
public function admin_post_reject(): void {
|
||
$this->handle_review_action('reject');
|
||
}
|
||
|
||
private function handle_review_action(string $action): void {
|
||
if (!SubmissionVersion::can_review(get_current_user_id())) {
|
||
wp_die(esc_html__('没有审核权限。', 'jio'), '', ['response' => 403]);
|
||
}
|
||
$version_id = absint($_POST['version_id'] ?? 0);
|
||
check_admin_referer('jio_review_' . $action . '_' . $version_id);
|
||
|
||
$result = $action === 'approve'
|
||
? $this->approve($version_id, get_current_user_id(), !empty($_POST['force']))
|
||
: $this->reject($version_id, get_current_user_id(), (string) ($_POST['note'] ?? ''));
|
||
|
||
$ok = !is_wp_error($result) && !empty($result['success']);
|
||
$msg = is_wp_error($result) ? $result->get_error_message() : (string) ($result['message'] ?? '');
|
||
|
||
$redirect = add_query_arg(
|
||
['jio_review_notice' => $ok ? 'ok' : 'error', 'jio_review_message' => rawurlencode($msg)],
|
||
wp_get_referer() ?: admin_url('edit.php?post_type=' . self::POST_TYPE)
|
||
);
|
||
wp_safe_redirect($redirect);
|
||
exit;
|
||
}
|
||
|
||
public function register_post_type(): void {
|
||
register_post_type(self::POST_TYPE, [
|
||
'labels' => [
|
||
'name' => __('投稿版本', 'jio'),
|
||
'singular_name' => __('投稿版本', 'jio'),
|
||
],
|
||
'public' => false,
|
||
'publicly_queryable' => false,
|
||
'exclude_from_search' => true,
|
||
'show_ui' => false,
|
||
'show_in_rest' => false,
|
||
'rewrite' => false,
|
||
'query_var' => false,
|
||
'capability_type' => 'post',
|
||
'map_meta_cap' => true,
|
||
'supports' => ['title', 'editor', 'revisions', 'author'],
|
||
'can_export' => false,
|
||
]);
|
||
}
|
||
|
||
/**
|
||
* @param array<string, bool> $robots
|
||
* @return array<string, bool>
|
||
*/
|
||
public function robots_noindex(array $robots): array {
|
||
if (is_singular(self::POST_TYPE)) {
|
||
$robots['noindex'] = true;
|
||
$robots['nofollow'] = true;
|
||
}
|
||
return $robots;
|
||
}
|
||
|
||
/**
|
||
* 该源文章是否需要走版本流程(仅已发布文章)。
|
||
*/
|
||
public static function requires_version(int $source_id): bool {
|
||
$post = get_post($source_id);
|
||
return $post instanceof \WP_Post
|
||
&& $post->post_type === 'post'
|
||
&& $post->post_status === 'publish';
|
||
}
|
||
|
||
/**
|
||
* 作者针对某篇源文章当前可见的工作版本(工作 / 待审 / 被退回)。
|
||
*/
|
||
public static function get_working(int $source_id, int $user_id): ?\WP_Post {
|
||
if ($source_id <= 0 || $user_id <= 0) {
|
||
return null;
|
||
}
|
||
$posts = get_posts([
|
||
'post_type' => self::POST_TYPE,
|
||
'post_status' => ['draft', 'pending', 'publish', 'private'],
|
||
'author' => $user_id,
|
||
'posts_per_page' => 1,
|
||
'orderby' => 'modified',
|
||
'order' => 'DESC',
|
||
'no_found_rows' => true,
|
||
'meta_key' => self::META_SOURCE,
|
||
'meta_value' => (string) $source_id,
|
||
]);
|
||
foreach ($posts as $post) {
|
||
if (!in_array(self::status((int) $post->ID), [self::STATUS_APPROVED], true)) {
|
||
return $post;
|
||
}
|
||
}
|
||
return null;
|
||
}
|
||
|
||
public static function status(int $version_id): string {
|
||
$status = (string) get_post_meta($version_id, self::META_STATUS, true);
|
||
return in_array($status, [self::STATUS_WORKING, self::STATUS_PENDING, self::STATUS_APPROVED, self::STATUS_REJECTED], true)
|
||
? $status
|
||
: self::STATUS_WORKING;
|
||
}
|
||
|
||
/**
|
||
* @return array<string, mixed>
|
||
*/
|
||
public static function snapshot(int $version_id): array {
|
||
$raw = get_post_meta($version_id, self::META_SNAPSHOT, true);
|
||
return is_array($raw) ? $raw : [];
|
||
}
|
||
|
||
public static function revision(int $version_id): int {
|
||
return max(0, (int) get_post_meta($version_id, self::META_REV, true));
|
||
}
|
||
|
||
public static function source_id(int $version_id): int {
|
||
return max(0, (int) get_post_meta($version_id, self::META_SOURCE, true));
|
||
}
|
||
|
||
/**
|
||
* 源文章的版本指纹:改动后用于检测审核期间的并发修改。
|
||
*/
|
||
public static function source_revision(int $source_id): string {
|
||
$post = get_post($source_id);
|
||
if (!$post instanceof \WP_Post) {
|
||
return '';
|
||
}
|
||
return sha1(implode('|', [
|
||
$post->post_modified_gmt,
|
||
(string) strlen((string) $post->post_content),
|
||
md5((string) $post->post_content),
|
||
md5((string) $post->post_title),
|
||
]));
|
||
}
|
||
|
||
/**
|
||
* 创建或更新作者的工作版本。
|
||
*
|
||
* @param array{title?:string,content?:string,excerpt?:string,snapshot?:array<string,mixed>,base_rev?:int,autosave?:bool} $data
|
||
* @return array{success:bool,message?:string,version_id?:int,rev?:int,conflict?:bool}|\WP_Error
|
||
*/
|
||
public function save_working(int $source_id, int $user_id, array $data, bool $submit = false) {
|
||
if (!self::requires_version($source_id)) {
|
||
return new \WP_Error('jio_version_not_required', __('该文章不需要版本流程。', 'jio'), ['status' => 400]);
|
||
}
|
||
$source = get_post($source_id);
|
||
if (!$source instanceof \WP_Post || (int) $source->post_author !== $user_id) {
|
||
return new \WP_Error('jio_version_forbidden', __('没有编辑此文章的权限。', 'jio'), ['status' => 403]);
|
||
}
|
||
|
||
$version = self::get_working($source_id, $user_id);
|
||
$base_rev = max(0, (int) ($data['base_rev'] ?? 0));
|
||
|
||
if ($version instanceof \WP_Post) {
|
||
$current_rev = self::revision((int) $version->ID);
|
||
if ($base_rev !== 0 && $base_rev !== $current_rev) {
|
||
return new \WP_Error(
|
||
'jio_version_conflict',
|
||
__('该文章已在其他页面更新,请刷新后再保存。', 'jio'),
|
||
['status' => 409, 'current_rev' => $current_rev, 'version_id' => (int) $version->ID]
|
||
);
|
||
}
|
||
$version_id = (int) $version->ID;
|
||
} else {
|
||
$version_id = wp_insert_post([
|
||
'post_type' => self::POST_TYPE,
|
||
'post_status' => 'draft',
|
||
'post_author' => $user_id,
|
||
'post_title' => (string) $source->post_title,
|
||
'post_content' => (string) $source->post_content,
|
||
'post_excerpt' => (string) $source->post_excerpt,
|
||
'meta_input' => [
|
||
self::META_SOURCE => $source_id,
|
||
self::META_SOURCE_REV => self::source_revision($source_id),
|
||
self::META_REV => 0,
|
||
self::META_STATUS => self::STATUS_WORKING,
|
||
],
|
||
], true);
|
||
if (is_wp_error($version_id) || !$version_id) {
|
||
return new \WP_Error('jio_version_failed', __('无法创建改稿版本,请稍后再试。', 'jio'), ['status' => 500]);
|
||
}
|
||
}
|
||
|
||
$title = isset($data['title']) ? sanitize_text_field((string) $data['title']) : (string) $source->post_title;
|
||
$excerpt = isset($data['excerpt']) ? sanitize_textarea_field((string) $data['excerpt']) : (string) $source->post_excerpt;
|
||
$content = isset($data['content']) ? (string) $data['content'] : (string) $source->post_content;
|
||
|
||
$can_iframe = $this->user_can_cap('new_post_iframe_video', $user_id);
|
||
if ($can_iframe) {
|
||
add_filter('wp_kses_allowed_html', [FrontSubmit::get_instance(), 'allow_iframe_kses'], 99, 2);
|
||
}
|
||
$content = wp_kses_post($content);
|
||
if ($can_iframe) {
|
||
remove_filter('wp_kses_allowed_html', [FrontSubmit::get_instance(), 'allow_iframe_kses'], 99);
|
||
}
|
||
|
||
$next_rev = $base_rev > 0 ? $base_rev + 1 : ($version instanceof \WP_Post ? self::revision($version_id) + 1 : 1);
|
||
|
||
// 已经在审核队列中的改稿:作者继续编辑(含自动保存)时保持 pending,
|
||
// 否则一次自动保存会把待审内容悄悄移出审核队列。
|
||
$current_status = $version instanceof \WP_Post ? self::status($version_id) : self::STATUS_WORKING;
|
||
$stays_pending = !$submit && $current_status === self::STATUS_PENDING;
|
||
$next_status = $submit || $stays_pending ? self::STATUS_PENDING : self::STATUS_WORKING;
|
||
|
||
$update = [
|
||
'ID' => $version_id,
|
||
'post_title' => $title,
|
||
'post_content' => $content,
|
||
'post_excerpt' => $excerpt,
|
||
'post_status' => $next_status === self::STATUS_PENDING ? 'pending' : 'draft',
|
||
];
|
||
// 自动保存不建 revision:几秒一次地写版本表会把改稿记录撑满,
|
||
// 需要回滚的节点由手动保存与提交产生。
|
||
$is_auto = !empty($data['autosave']);
|
||
if ($is_auto) {
|
||
remove_action('post_updated', 'wp_save_post_revision');
|
||
}
|
||
$updated = wp_update_post($update, true);
|
||
if ($is_auto) {
|
||
add_action('post_updated', 'wp_save_post_revision');
|
||
}
|
||
if (is_wp_error($updated)) {
|
||
return new \WP_Error('jio_version_failed', $updated->get_error_message(), ['status' => 500]);
|
||
}
|
||
|
||
if (isset($data['snapshot']) && is_array($data['snapshot'])) {
|
||
$snapshot = $this->sanitize_snapshot($data['snapshot']);
|
||
update_post_meta($version_id, self::META_SNAPSHOT, $snapshot);
|
||
// 私有资料在上传后即绑定到源文章:审核通过后可直接交付,也不会被
|
||
// 未关联附件的定时清理误删。
|
||
$this->claim_snapshot_assets($snapshot, $source_id, $user_id);
|
||
}
|
||
update_post_meta($version_id, self::META_REV, $next_rev);
|
||
update_post_meta($version_id, self::META_STATUS, $next_status);
|
||
if ($submit) {
|
||
update_post_meta($version_id, self::META_SUBMITTED_AT, current_time('mysql'));
|
||
update_post_meta($version_id, self::META_SOURCE_REV, self::source_revision($source_id));
|
||
delete_post_meta($version_id, self::META_NOTE);
|
||
}
|
||
|
||
return [
|
||
'success' => true,
|
||
'version_id' => $version_id,
|
||
'rev' => $next_rev,
|
||
'status' => $next_status,
|
||
'message' => $submit
|
||
? __('改稿已提交审核,线上文章保持不变。', 'jio')
|
||
: ($stays_pending ? __('待审改稿已更新', 'jio') : __('改稿已保存', 'jio')),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 审核通过:把版本快照一次性应用到源文章。
|
||
*
|
||
* @return array{success:bool,message?:string,post_id?:int}|\WP_Error
|
||
*/
|
||
public function approve(int $version_id, int $reviewer_id, bool $force = false) {
|
||
$version = get_post($version_id);
|
||
if (!$version instanceof \WP_Post || $version->post_type !== self::POST_TYPE) {
|
||
return new \WP_Error('jio_version_missing', __('改稿版本不存在。', 'jio'), ['status' => 404]);
|
||
}
|
||
if (!self::can_review($reviewer_id)) {
|
||
return new \WP_Error('jio_review_forbidden', __('没有审核权限。', 'jio'), ['status' => 403]);
|
||
}
|
||
|
||
$source_id = self::source_id($version_id);
|
||
$source = $source_id > 0 ? get_post($source_id) : null;
|
||
if (!$source instanceof \WP_Post || $source->post_type !== 'post') {
|
||
return new \WP_Error('jio_version_source_missing', __('原文章不存在。', 'jio'), ['status' => 404]);
|
||
}
|
||
|
||
$snapshot_rev = (string) get_post_meta($version_id, self::META_SOURCE_REV, true);
|
||
if (!$force && $snapshot_rev !== '' && $snapshot_rev !== self::source_revision($source_id)) {
|
||
return new \WP_Error(
|
||
'jio_version_source_changed',
|
||
__('原文章在审核期间已被修改,请先确认后再应用。', 'jio'),
|
||
['status' => 409]
|
||
);
|
||
}
|
||
|
||
$snapshot = self::snapshot($version_id);
|
||
$update = [
|
||
'ID' => $source_id,
|
||
'post_title' => (string) $version->post_title,
|
||
'post_content' => (string) $version->post_content,
|
||
'post_excerpt' => (string) $version->post_excerpt,
|
||
];
|
||
$result = wp_update_post($update, true);
|
||
if (is_wp_error($result)) {
|
||
return new \WP_Error('jio_version_apply_failed', $result->get_error_message(), ['status' => 500]);
|
||
}
|
||
|
||
$this->apply_snapshot($source_id, $snapshot, (int) $source->post_author);
|
||
|
||
wp_update_post([
|
||
'ID' => $version_id,
|
||
'post_status' => 'private',
|
||
]);
|
||
update_post_meta($version_id, self::META_STATUS, self::STATUS_APPROVED);
|
||
update_post_meta($version_id, self::META_REV, self::revision($version_id) + 1);
|
||
|
||
do_action('jio_submission_version_approved', $source_id, $version_id, $reviewer_id);
|
||
|
||
return [
|
||
'success' => true,
|
||
'post_id' => $source_id,
|
||
'message' => __('改稿已应用到线上文章。', 'jio'),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 作者直接应用自己的改稿(具备免审发布权限时)。
|
||
*/
|
||
public function publish_working(int $source_id, int $user_id): array {
|
||
$version = self::get_working($source_id, $user_id);
|
||
if (!$version instanceof \WP_Post) {
|
||
return ['success' => false, 'message' => __('没有待应用的改稿。', 'jio')];
|
||
}
|
||
$source = get_post($source_id);
|
||
if (!$source instanceof \WP_Post || (int) $source->post_author !== $user_id) {
|
||
return ['success' => false, 'message' => __('没有编辑此文章的权限。', 'jio')];
|
||
}
|
||
|
||
$result = wp_update_post([
|
||
'ID' => $source_id,
|
||
'post_title' => (string) $version->post_title,
|
||
'post_content' => (string) $version->post_content,
|
||
'post_excerpt' => (string) $version->post_excerpt,
|
||
], true);
|
||
if (is_wp_error($result)) {
|
||
return ['success' => false, 'message' => $result->get_error_message()];
|
||
}
|
||
|
||
$this->apply_snapshot($source_id, self::snapshot((int) $version->ID), $user_id);
|
||
|
||
wp_update_post(['ID' => (int) $version->ID, 'post_status' => 'private']);
|
||
update_post_meta((int) $version->ID, self::META_STATUS, self::STATUS_APPROVED);
|
||
update_post_meta((int) $version->ID, self::META_REV, self::revision((int) $version->ID) + 1);
|
||
|
||
return [
|
||
'success' => true,
|
||
'post_id' => $source_id,
|
||
'message' => __('改稿已发布。', 'jio'),
|
||
'url' => get_permalink($source_id),
|
||
];
|
||
}
|
||
|
||
/**
|
||
* 退回改稿。
|
||
*/
|
||
public function reject(int $version_id, int $reviewer_id, string $note = ''): array {
|
||
if (!self::can_review($reviewer_id)) {
|
||
return ['success' => false, 'message' => __('没有审核权限。', 'jio')];
|
||
}
|
||
$version = get_post($version_id);
|
||
if (!$version instanceof \WP_Post || $version->post_type !== self::POST_TYPE) {
|
||
return ['success' => false, 'message' => __('改稿版本不存在。', 'jio')];
|
||
}
|
||
|
||
wp_update_post(['ID' => $version_id, 'post_status' => 'draft']);
|
||
update_post_meta($version_id, self::META_STATUS, self::STATUS_REJECTED);
|
||
update_post_meta($version_id, self::META_NOTE, sanitize_textarea_field($note));
|
||
update_post_meta($version_id, self::META_REV, self::revision($version_id) + 1);
|
||
|
||
do_action('jio_submission_version_rejected', $version_id, $reviewer_id, $note);
|
||
|
||
return ['success' => true, 'message' => __('已退回改稿,线上文章未变动。', 'jio')];
|
||
}
|
||
|
||
/**
|
||
* 写入版本快照中的分类、标签、自定义筛选、封面与付费设置。
|
||
*
|
||
* @param array<string, mixed> $snapshot
|
||
*/
|
||
private function apply_snapshot(int $post_id, array $snapshot, int $author_id): void {
|
||
if ($snapshot === []) {
|
||
return;
|
||
}
|
||
$settings = FrontSubmit::get_instance()->settings();
|
||
|
||
if (isset($snapshot['categories']) && is_array($snapshot['categories'])) {
|
||
$cats = array_values(array_unique(array_filter(array_map('absint', $snapshot['categories']))));
|
||
if ($cats !== []) {
|
||
$cats = SubmitCategories::filter_ids($cats, $settings);
|
||
}
|
||
wp_set_post_categories($post_id, $cats);
|
||
}
|
||
if (!empty($settings['allow_topics']) && array_key_exists('topics', $snapshot)) {
|
||
$topics = is_array($snapshot['topics']) ? $snapshot['topics'] : [];
|
||
wp_set_post_terms($post_id, SubmitTopics::filter_ids($topics, $settings), 'topics');
|
||
}
|
||
if (array_key_exists('tags', $snapshot)) {
|
||
$tags = is_array($snapshot['tags']) ? $snapshot['tags'] : [];
|
||
wp_set_post_tags($post_id, array_values(array_filter(array_map('sanitize_text_field', $tags))));
|
||
}
|
||
if (isset($snapshot['custom']) && is_array($snapshot['custom'])) {
|
||
foreach ($snapshot['custom'] as $key => $value) {
|
||
$meta_key = '_jio_cf_' . sanitize_key((string) $key);
|
||
if (is_array($value)) {
|
||
$vals = array_values(array_filter(array_map('sanitize_key', $value)));
|
||
$vals ? update_post_meta($post_id, $meta_key, $vals) : delete_post_meta($post_id, $meta_key);
|
||
} else {
|
||
$val = sanitize_key((string) $value);
|
||
$val !== '' ? update_post_meta($post_id, $meta_key, $val) : delete_post_meta($post_id, $meta_key);
|
||
}
|
||
}
|
||
}
|
||
|
||
$front = FrontSubmit::get_instance();
|
||
if (isset($snapshot['featured']) && is_array($snapshot['featured'])) {
|
||
$front->apply_creator_featured($post_id, $snapshot['featured'], $author_id);
|
||
}
|
||
if (isset($snapshot['pay']) && is_array($snapshot['pay'])) {
|
||
$pay_data = [
|
||
'pay_enabled' => !empty($snapshot['pay']['enabled']) ? '1' : '',
|
||
'jio_pay' => is_array($snapshot['pay']['fields'] ?? null) ? $snapshot['pay']['fields'] : [],
|
||
];
|
||
$front->apply_pay_payload($post_id, $pay_data, $author_id, $settings);
|
||
}
|
||
}
|
||
|
||
/**
|
||
* @param array<string, mixed> $snapshot
|
||
* @return array<string, mixed>
|
||
*/
|
||
private function sanitize_snapshot(array $snapshot): array {
|
||
$clean = [];
|
||
if (isset($snapshot['categories']) && is_array($snapshot['categories'])) {
|
||
$clean['categories'] = array_values(array_unique(array_filter(array_map('absint', $snapshot['categories']))));
|
||
}
|
||
if (isset($snapshot['topics']) && is_array($snapshot['topics'])) {
|
||
$clean['topics'] = array_values(array_unique(array_filter(array_map('absint', $snapshot['topics']))));
|
||
}
|
||
if (isset($snapshot['tags'])) {
|
||
$tags = is_array($snapshot['tags']) ? $snapshot['tags'] : preg_split('/[,,\n]+/u', (string) $snapshot['tags']);
|
||
$clean['tags'] = array_values(array_filter(array_map('sanitize_text_field', (array) $tags)));
|
||
}
|
||
if (isset($snapshot['custom']) && is_array($snapshot['custom'])) {
|
||
$custom = [];
|
||
foreach ($snapshot['custom'] as $key => $value) {
|
||
$key = sanitize_key((string) $key);
|
||
if ($key === '') {
|
||
continue;
|
||
}
|
||
$custom[$key] = is_array($value)
|
||
? array_values(array_filter(array_map('sanitize_key', $value)))
|
||
: sanitize_key((string) $value);
|
||
}
|
||
$clean['custom'] = $custom;
|
||
}
|
||
if (isset($snapshot['featured']) && is_array($snapshot['featured'])) {
|
||
$clean['featured'] = $snapshot['featured'];
|
||
}
|
||
if (isset($snapshot['pay']) && is_array($snapshot['pay'])) {
|
||
$clean['pay'] = [
|
||
'enabled' => !empty($snapshot['pay']['enabled']),
|
||
'fields' => is_array($snapshot['pay']['fields'] ?? null) ? $snapshot['pay']['fields'] : [],
|
||
];
|
||
}
|
||
return $clean;
|
||
}
|
||
|
||
/**
|
||
* 把版本快照里引用的私有资料绑定到源文章。
|
||
*
|
||
* @param array<string, mixed> $snapshot
|
||
*/
|
||
private function claim_snapshot_assets(array $snapshot, int $source_id, int $user_id): void {
|
||
$keys = [];
|
||
foreach ((array) ($snapshot['pay']['fields']['downloads'] ?? []) as $row) {
|
||
if (is_array($row)) {
|
||
$key = PrivateAssets::sanitize_asset_key((string) ($row['asset_key'] ?? ''));
|
||
if ($key !== '') {
|
||
$keys[] = $key;
|
||
}
|
||
}
|
||
}
|
||
PrivateAssets::claim_many($keys, $source_id, $user_id);
|
||
}
|
||
|
||
/**
|
||
* 是否具备审核权限。
|
||
*/
|
||
public static function can_review(int $user_id = 0): bool {
|
||
$user_id = $user_id > 0 ? $user_id : get_current_user_id();
|
||
if ($user_id <= 0) {
|
||
return false;
|
||
}
|
||
return user_can($user_id, 'manage_options') || user_can($user_id, 'edit_others_posts');
|
||
}
|
||
|
||
public static function status_label(string $status): string {
|
||
switch ($status) {
|
||
case self::STATUS_PENDING:
|
||
return __('待审核', 'jio');
|
||
case self::STATUS_APPROVED:
|
||
return __('已应用', 'jio');
|
||
case self::STATUS_REJECTED:
|
||
return __('已退回', 'jio');
|
||
default:
|
||
return __('草稿', 'jio');
|
||
}
|
||
}
|
||
|
||
private function user_can_cap(string $cap, int $user_id): bool {
|
||
return FrontSubmit::get_instance()->user_can_cap($cap, $user_id);
|
||
}
|
||
}
|