Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
666 lines
25 KiB
PHP
666 lines
25 KiB
PHP
<?php
|
|
/**
|
|
* Jio Creator Studio 的 REST 接口。
|
|
*
|
|
* 只做前台创作体验需要的编排:读取编辑上下文、保存/自动保存、提交审核、
|
|
* 预览链接、私有资料上传。所有文章写入仍复用 FrontSubmit 的权限、字段清洗
|
|
* 与状态机;已发布文章的改动走 SubmissionVersion,不直接覆盖线上内容。
|
|
*
|
|
* @package Jio
|
|
*/
|
|
|
|
namespace Jio\Core;
|
|
|
|
use Jio\Content\PrivateAssets;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
final class CreatorRest {
|
|
|
|
public const NS = 'jio/v1';
|
|
|
|
public function register_routes(): void {
|
|
register_rest_route(self::NS, '/creator/bootstrap', [
|
|
'methods' => \WP_REST_Server::READABLE,
|
|
'callback' => [$this, 'rest_bootstrap'],
|
|
'permission_callback' => [$this, 'can_use_studio'],
|
|
'args' => [
|
|
'post_id' => ['default' => 0, 'sanitize_callback' => 'absint'],
|
|
],
|
|
]);
|
|
|
|
register_rest_route(self::NS, '/creator/save', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_save'],
|
|
'permission_callback' => [$this, 'can_use_studio'],
|
|
]);
|
|
|
|
register_rest_route(self::NS, '/creator/submit', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_submit'],
|
|
'permission_callback' => [$this, 'can_use_studio'],
|
|
]);
|
|
|
|
register_rest_route(self::NS, '/creator/preview', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_preview'],
|
|
'permission_callback' => [$this, 'can_use_studio'],
|
|
]);
|
|
|
|
register_rest_route(self::NS, '/creator/private-upload', [
|
|
'methods' => 'POST',
|
|
'callback' => [$this, 'rest_private_upload'],
|
|
'permission_callback' => [$this, 'can_upload_private'],
|
|
]);
|
|
|
|
register_rest_route(self::NS, '/creator/private-uploads', [
|
|
'methods' => \WP_REST_Server::READABLE,
|
|
'callback' => [$this, 'rest_list_private_uploads'],
|
|
'permission_callback' => [$this, 'can_upload_private'],
|
|
]);
|
|
}
|
|
|
|
public function can_use_studio($request = null): bool {
|
|
$user_id = get_current_user_id();
|
|
if ($user_id <= 0) {
|
|
return false;
|
|
}
|
|
$front = FrontSubmit::get_instance();
|
|
if (empty($front->settings()['enabled'])) {
|
|
return false;
|
|
}
|
|
$post_id = 0;
|
|
if ($request instanceof \WP_REST_Request) {
|
|
$post_id = absint($request->get_param('post_id'));
|
|
} elseif (isset($_REQUEST['post_id'])) {
|
|
$post_id = absint(wp_unslash($_REQUEST['post_id']));
|
|
}
|
|
if ($post_id > 0) {
|
|
return $front->can_edit_post($post_id, $user_id);
|
|
}
|
|
return $front->can_submit($user_id);
|
|
}
|
|
|
|
public function can_upload_private(): bool {
|
|
$user_id = get_current_user_id();
|
|
if ($user_id <= 0) {
|
|
return false;
|
|
}
|
|
return FrontSubmit::get_instance()->user_can_cap('new_post_pay_download', $user_id);
|
|
}
|
|
|
|
/**
|
|
* 编辑上下文:作者打开创作页时的一切初始数据。
|
|
*/
|
|
public function rest_bootstrap(\WP_REST_Request $request): \WP_REST_Response {
|
|
$post_id = absint($request->get_param('post_id'));
|
|
$user_id = get_current_user_id();
|
|
|
|
return new \WP_REST_Response($this->bootstrap_payload($post_id, $user_id), 200);
|
|
}
|
|
|
|
/**
|
|
* @return array<string, mixed>
|
|
*/
|
|
public function bootstrap_payload(int $post_id, int $user_id): array {
|
|
$front = FrontSubmit::get_instance();
|
|
$settings = $front->settings();
|
|
$source = $post_id > 0 ? get_post($post_id) : null;
|
|
$version = null;
|
|
$version_id = 0;
|
|
|
|
if ($source instanceof \WP_Post && SubmissionVersion::requires_version($post_id)) {
|
|
$version = SubmissionVersion::get_working($post_id, $user_id);
|
|
$version_id = $version instanceof \WP_Post ? (int) $version->ID : 0;
|
|
}
|
|
|
|
$editable = $version instanceof \WP_Post
|
|
? $version
|
|
: ($source instanceof \WP_Post ? $source : null);
|
|
|
|
$pay_meta = $editable instanceof \WP_Post && function_exists('jio_get_pay_meta')
|
|
? jio_get_pay_meta($editable->ID)
|
|
: DomainModel::default_pay_meta();
|
|
$snapshot = $version_id > 0 ? SubmissionVersion::snapshot($version_id) : [];
|
|
|
|
$post_meta = $source instanceof \WP_Post
|
|
? (array) get_post_meta($source->ID, DomainModel::POST_META_KEY, true)
|
|
: [];
|
|
|
|
$terms = $this->term_payload($settings, $source, $snapshot);
|
|
|
|
return [
|
|
'sourceId' => $post_id,
|
|
'versionId' => $version_id,
|
|
'versionRev' => $version_id > 0 ? SubmissionVersion::revision($version_id) : 0,
|
|
'status' => $version_id > 0 ? SubmissionVersion::status($version_id) : ($source->post_status ?? ''),
|
|
'reviewNote' => $version_id > 0 ? (string) get_post_meta($version_id, SubmissionVersion::META_NOTE, true) : '',
|
|
'title' => $editable instanceof \WP_Post ? $editable->post_title : '',
|
|
'excerpt' => $editable instanceof \WP_Post ? $editable->post_excerpt : '',
|
|
'content' => $editable instanceof \WP_Post ? $editable->post_content : '',
|
|
'permalink' => $source instanceof \WP_Post ? get_permalink($source) : '',
|
|
'isPublished'=> $source instanceof \WP_Post && $source->post_status === 'publish',
|
|
'categories' => $terms['categories'],
|
|
'tags' => $terms['tags'],
|
|
'custom' => $terms['custom'],
|
|
'customDefs' => $terms['customDefs'],
|
|
'featured' => $this->creator_featured_payload($source, $post_meta),
|
|
'pay' => $this->pay_payload((array) $pay_meta, $snapshot, $settings),
|
|
'capabilities' => $this->capability_payload($front, $user_id, $post_id),
|
|
'limits' => [
|
|
'titleMin' => (int) $settings['title_min'],
|
|
'titleMax' => (int) $settings['title_max'],
|
|
'titlePlaceholder' => (string) $settings['title_placeholder'],
|
|
'contentPlaceholder' => (string) $settings['content_placeholder'],
|
|
],
|
|
'privateUploads' => $this->private_upload_rows($user_id, $post_id),
|
|
'privateStorage' => PrivateAssets::is_available(),
|
|
'media' => [
|
|
'listUrl' => esc_url_raw(rest_url(self::NS . '/front-submit/media')),
|
|
'uploadUrl' => [
|
|
'image' => esc_url_raw(rest_url(self::NS . '/front-submit/upload/image')),
|
|
],
|
|
'maxBytes' => FrontSubmit::upload_limit_bytes('image'),
|
|
'batch' => class_exists('\Jio\Attachment\UploadLimits') ? \Jio\Attachment\UploadLimits::image_batch_limit() : 6,
|
|
],
|
|
'rest' => [
|
|
'root' => esc_url_raw(rest_url()),
|
|
'nonce' => wp_create_nonce('wp_rest'),
|
|
],
|
|
'urls' => [
|
|
'submit' => function_exists('jio_get_new_post_url') ? jio_get_new_post_url() : '',
|
|
'newPost' => function_exists('jio_get_new_post_url') ? jio_get_new_post_url() : '',
|
|
'center' => function_exists('jio_get_user_center_url') ? jio_get_user_center_url('posts') : '',
|
|
],
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 保存或自动保存。已发布文章写入版本记录;新文章走既有 persist()。
|
|
*/
|
|
public function rest_save(\WP_REST_Request $request) {
|
|
$user_id = get_current_user_id();
|
|
$post_id = absint($request->get_param('post_id'));
|
|
$is_auto = (bool) $request->get_param('autosave');
|
|
$payload = [
|
|
'title' => (string) $request->get_param('title'),
|
|
'content' => (string) $request->get_param('content'),
|
|
'categories' => (array) $request->get_param('categories'),
|
|
'tags' => (array) $request->get_param('tags'),
|
|
'custom' => (array) $request->get_param('custom'),
|
|
'featured' => (array) $request->get_param('featured'),
|
|
'schedule' => (array) $request->get_param('schedule'),
|
|
'pay' => (array) $request->get_param('pay'),
|
|
];
|
|
|
|
if ($post_id > 0 && SubmissionVersion::requires_version($post_id)) {
|
|
$result = SubmissionVersion::get_instance()->save_working($post_id, $user_id, [
|
|
'title' => $payload['title'] !== '' ? $payload['title'] : null,
|
|
'content' => $payload['content'],
|
|
'base_rev' => absint($request->get_param('rev')),
|
|
'snapshot' => $this->snapshot_from_payload($payload),
|
|
], false);
|
|
if (is_wp_error($result)) {
|
|
return $result;
|
|
}
|
|
$result['autosave'] = $is_auto;
|
|
return new \WP_REST_Response($result, 200);
|
|
}
|
|
|
|
$front = FrontSubmit::get_instance();
|
|
$data = [
|
|
'posts_id' => $post_id,
|
|
'post_title' => $payload['title'],
|
|
'post_content' => $payload['content'],
|
|
'category' => $payload['categories'],
|
|
'tags' => implode(',', array_map('strval', $payload['tags'])),
|
|
'featured_data'=> $payload['featured'],
|
|
'schedule' => $payload['schedule'],
|
|
];
|
|
foreach ($payload['custom'] as $key => $value) {
|
|
$data['cf_' . sanitize_key((string) $key)] = $value;
|
|
}
|
|
if ($payload['pay'] !== []) {
|
|
$data['pay_enabled'] = !empty($payload['pay']['enabled']) ? '1' : '';
|
|
$data['jio_pay'] = (array) ($payload['pay']['fields'] ?? []);
|
|
}
|
|
|
|
$result = $front->persist($data, 'posts_draft');
|
|
if (empty($result['success'])) {
|
|
return new \WP_Error('jio_creator_save_failed', (string) ($result['message'] ?? __('保存失败', 'jio')), ['status' => 400]);
|
|
}
|
|
$result['autosave'] = $is_auto;
|
|
$result['versionRev'] = max(1, (int) ($result['rev'] ?? 1));
|
|
return new \WP_REST_Response($result, 200);
|
|
}
|
|
|
|
/**
|
|
* 提交审核 / 直接发布。
|
|
*/
|
|
public function rest_submit(\WP_REST_Request $request) {
|
|
$user_id = get_current_user_id();
|
|
$post_id = absint($request->get_param('post_id'));
|
|
$front = FrontSubmit::get_instance();
|
|
|
|
// 与 admin-ajax 投稿入口保持同一道人机验证闸门(启用 front_submit 场景时)。
|
|
if (function_exists('jio_require_captcha')) {
|
|
$captcha = jio_require_captcha('front_submit', [
|
|
'jio_captcha_proof' => sanitize_text_field((string) $request->get_param('captcha_proof')),
|
|
]);
|
|
if ($captcha !== true) {
|
|
$message = is_wp_error($captcha) ? $captcha->get_error_message() : __('人机验证失败,请重试', 'jio');
|
|
return new \WP_Error('jio_captcha_failed', $message, ['status' => 400]);
|
|
}
|
|
}
|
|
|
|
$payload = [
|
|
'title' => (string) $request->get_param('title'),
|
|
'content' => (string) $request->get_param('content'),
|
|
'categories' => (array) $request->get_param('categories'),
|
|
'tags' => (array) $request->get_param('tags'),
|
|
'custom' => (array) $request->get_param('custom'),
|
|
'featured' => (array) $request->get_param('featured'),
|
|
'schedule' => (array) $request->get_param('schedule'),
|
|
'pay' => (array) $request->get_param('pay'),
|
|
];
|
|
|
|
if ($post_id > 0 && SubmissionVersion::requires_version($post_id)) {
|
|
$invalid = $this->validate_submission($payload, $user_id);
|
|
if ($invalid !== '') {
|
|
return new \WP_Error('jio_creator_invalid', $invalid, ['status' => 400]);
|
|
}
|
|
$version = SubmissionVersion::get_instance()->save_working($post_id, $user_id, [
|
|
'title' => $payload['title'],
|
|
'content' => $payload['content'],
|
|
'base_rev' => absint($request->get_param('rev')),
|
|
'snapshot' => $this->snapshot_from_payload($payload),
|
|
], true);
|
|
if (is_wp_error($version)) {
|
|
return $version;
|
|
}
|
|
|
|
// 具备免审发布权限且明确选择立即发布时,才直接应用到线上文章。
|
|
if ($request->get_param('publish_now') && $front->user_can_cap('new_post_audit_no', $user_id)) {
|
|
$applied = SubmissionVersion::get_instance()->publish_working($post_id, $user_id);
|
|
if (empty($applied['success'])) {
|
|
return new \WP_Error('jio_creator_publish_failed', (string) ($applied['message'] ?? __('发布失败', 'jio')), ['status' => 400]);
|
|
}
|
|
return new \WP_REST_Response($applied, 200);
|
|
}
|
|
|
|
return new \WP_REST_Response($version, 200);
|
|
}
|
|
|
|
$data = [
|
|
'posts_id' => $post_id,
|
|
'post_title' => $payload['title'],
|
|
'post_content' => $payload['content'],
|
|
'category' => $payload['categories'],
|
|
'tags' => implode(',', array_map('strval', $payload['tags'])),
|
|
'featured_data' => $payload['featured'],
|
|
'schedule' => $payload['schedule'],
|
|
];
|
|
foreach ($payload['custom'] as $key => $value) {
|
|
$data['cf_' . sanitize_key((string) $key)] = $value;
|
|
}
|
|
if ($payload['pay'] !== []) {
|
|
$data['pay_enabled'] = !empty($payload['pay']['enabled']) ? '1' : '';
|
|
$data['jio_pay'] = (array) ($payload['pay']['fields'] ?? []);
|
|
}
|
|
|
|
$result = $front->persist($data, 'posts_save');
|
|
if (empty($result['success'])) {
|
|
return new \WP_Error('jio_creator_submit_failed', (string) ($result['message'] ?? __('提交失败', 'jio')), ['status' => 400]);
|
|
}
|
|
|
|
$this->claim_private_assets($payload, (int) ($result['post_id'] ?? 0), $user_id);
|
|
return new \WP_REST_Response($result, 200);
|
|
}
|
|
|
|
/**
|
|
* 预览链接:已发布文章的改稿版本使用一次性签名地址,不公开版本内容。
|
|
*/
|
|
public function rest_preview(\WP_REST_Request $request) {
|
|
$user_id = get_current_user_id();
|
|
$post_id = absint($request->get_param('post_id'));
|
|
$version_id = absint($request->get_param('version_id'));
|
|
|
|
if ($version_id > 0) {
|
|
$version = get_post($version_id);
|
|
if (!$version instanceof \WP_Post || $version->post_type !== SubmissionVersion::POST_TYPE) {
|
|
return new \WP_Error('jio_review_preview_missing', __('改稿不存在。', 'jio'), ['status' => 404]);
|
|
}
|
|
if ((int) $version->post_author !== $user_id && !SubmissionVersion::can_review($user_id)) {
|
|
return new \WP_Error('jio_review_preview_forbidden', __('没有预览权限。', 'jio'), ['status' => 403]);
|
|
}
|
|
$token = PreviewToken::issue($version_id, $user_id);
|
|
$source_id = SubmissionVersion::source_id($version_id);
|
|
$source = $source_id > 0 ? get_post($source_id) : null;
|
|
$base = $source instanceof \WP_Post ? (string) get_permalink($source) : home_url('/');
|
|
return new \WP_REST_Response([
|
|
'url' => add_query_arg('jio_studio_preview', $token, $base),
|
|
], 200);
|
|
}
|
|
|
|
if ($post_id <= 0) {
|
|
return new \WP_Error('jio_review_preview_missing', __('尚未保存文章。', 'jio'), ['status' => 400]);
|
|
}
|
|
$post = get_post($post_id);
|
|
if (!$post instanceof \WP_Post) {
|
|
return new \WP_Error('jio_review_preview_missing', __('文章不存在。', 'jio'), ['status' => 404]);
|
|
}
|
|
return new \WP_REST_Response([
|
|
'url' => (string) get_preview_post_link($post),
|
|
], 200);
|
|
}
|
|
|
|
/**
|
|
* 私有资料上传(付费附件)。
|
|
*/
|
|
public function rest_private_upload(\WP_REST_Request $request) {
|
|
$file = $request->get_file_params()['file'] ?? null;
|
|
if (!is_array($file)) {
|
|
return new \WP_Error('jio_private_upload_failed', __('请选择要上传的资料文件。', 'jio'), ['status' => 400]);
|
|
}
|
|
$post_id = absint($request->get_param('post_id'));
|
|
$result = PrivateAssets::get_instance()->store_upload($file, get_current_user_id(), $post_id);
|
|
if (is_wp_error($result)) {
|
|
return $result;
|
|
}
|
|
return new \WP_REST_Response($result, 201);
|
|
}
|
|
|
|
public function rest_list_private_uploads(\WP_REST_Request $request): \WP_REST_Response {
|
|
return new \WP_REST_Response([
|
|
'items' => $this->private_upload_rows(get_current_user_id(), absint($request->get_param('post_id'))),
|
|
], 200);
|
|
}
|
|
|
|
/**
|
|
* @return list<array<string,mixed>>
|
|
*/
|
|
private function private_upload_rows(int $user_id, int $post_id): array {
|
|
global $wpdb;
|
|
$table = DBMigrator::table('private_asset');
|
|
if ($table === '' || $user_id <= 0) {
|
|
return [];
|
|
}
|
|
$rows = $wpdb->get_results($wpdb->prepare(
|
|
"SELECT asset_key, post_id, file_name, mime, size_bytes, created_at FROM {$table}
|
|
WHERE owner_id = %d AND (post_id = %d OR post_id = 0) ORDER BY id DESC LIMIT 50",
|
|
$user_id,
|
|
$post_id
|
|
), ARRAY_A);
|
|
|
|
$items = [];
|
|
foreach (is_array($rows) ? $rows : [] as $row) {
|
|
$items[] = [
|
|
'assetKey' => (string) $row['asset_key'],
|
|
'postId' => (int) $row['post_id'],
|
|
'fileName' => (string) $row['file_name'],
|
|
'mime' => (string) $row['mime'],
|
|
'sizeBytes' => (int) $row['size_bytes'],
|
|
'sizeLabel' => size_format((int) $row['size_bytes']),
|
|
];
|
|
}
|
|
return $items;
|
|
}
|
|
|
|
/**
|
|
* 提交前的必填校验,与 FrontSubmitSave 保持同一口径。
|
|
*
|
|
* @param array<string, mixed> $payload
|
|
*/
|
|
private function validate_submission(array $payload, int $user_id): string {
|
|
$settings = FrontSubmit::get_instance()->settings();
|
|
$title = trim(wp_strip_all_tags((string) ($payload['title'] ?? '')));
|
|
$content = trim(wp_strip_all_tags((string) ($payload['content'] ?? '')));
|
|
if ($title === '') {
|
|
return __('请填写文章标题', 'jio');
|
|
}
|
|
$length = function_exists('mb_strlen') ? mb_strlen($title) : strlen($title);
|
|
if ($length < (int) $settings['title_min']) {
|
|
return __('标题太短!', 'jio');
|
|
}
|
|
if ($length > (int) $settings['title_max']) {
|
|
return sprintf(__('标题太长了,不能超过%d个字', 'jio'), (int) $settings['title_max']);
|
|
}
|
|
if ((function_exists('mb_strlen') ? mb_strlen($content) : strlen($content)) < 10) {
|
|
return __('文章内容过少', 'jio');
|
|
}
|
|
if (empty($payload['categories'])) {
|
|
return __('请选择文章分类', 'jio');
|
|
}
|
|
return '';
|
|
}
|
|
|
|
/**
|
|
* 组合提交时的版本快照(分类、标签、封面、付费)。
|
|
*
|
|
* @param array<string, mixed> $payload
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function snapshot_from_payload(array $payload): array {
|
|
$downloads = [];
|
|
foreach ((array) ($payload['pay']['fields']['downloads'] ?? []) as $row) {
|
|
if (!is_array($row)) {
|
|
continue;
|
|
}
|
|
$key = PrivateAssets::sanitize_asset_key((string) ($row['asset_key'] ?? ''));
|
|
if ($key !== '') {
|
|
$asset = PrivateAssets::get($key);
|
|
if ($asset === null || $asset['owner_id'] !== get_current_user_id()) {
|
|
continue;
|
|
}
|
|
$downloads[] = [
|
|
'type' => 'protected',
|
|
'asset_key' => $key,
|
|
'file_name' => $asset['file_name'],
|
|
'size_bytes' => $asset['size_bytes'],
|
|
'label' => (string) ($row['label'] ?? ''),
|
|
];
|
|
continue;
|
|
}
|
|
$url = esc_url_raw((string) ($row['url'] ?? ''));
|
|
if ($url !== '') {
|
|
$downloads[] = [
|
|
'type' => 'direct',
|
|
'url' => $url,
|
|
'label' => (string) ($row['label'] ?? ''),
|
|
'extract_code' => (string) ($row['extract_code'] ?? ''),
|
|
];
|
|
}
|
|
}
|
|
|
|
return [
|
|
'categories' => array_values(array_filter(array_map('absint', (array) $payload['categories']))),
|
|
'tags' => array_values(array_filter(array_map('sanitize_text_field', (array) $payload['tags']))),
|
|
'custom' => is_array($payload['custom']) ? $payload['custom'] : [],
|
|
'featured' => is_array($payload['featured']) ? $payload['featured'] : [],
|
|
'pay' => [
|
|
'enabled' => !empty($payload['pay']['enabled']),
|
|
'fields' => array_merge(
|
|
(array) ($payload['pay']['fields'] ?? []),
|
|
['downloads' => $downloads]
|
|
),
|
|
],
|
|
];
|
|
}
|
|
|
|
private function claim_private_assets(array $payload, int $post_id, int $user_id): void {
|
|
if ($post_id <= 0) {
|
|
return;
|
|
}
|
|
$keys = [];
|
|
foreach ((array) ($payload['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, $post_id, $user_id);
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $settings
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function term_payload(array $settings, ?\WP_Post $source, array $snapshot): array {
|
|
$cat_args = [
|
|
'taxonomy' => 'category',
|
|
'hide_empty' => false,
|
|
'orderby' => 'name',
|
|
'order' => 'ASC',
|
|
];
|
|
if (!empty($settings['allowed_cat_ids'])) {
|
|
$cat_args['include'] = $settings['allowed_cat_ids'];
|
|
} else {
|
|
$cat_args['parent'] = 0;
|
|
}
|
|
$terms = get_terms($cat_args);
|
|
$categories = [];
|
|
foreach (is_array($terms) ? $terms : [] as $term) {
|
|
$categories[] = ['id' => (int) $term->term_id, 'name' => (string) $term->name];
|
|
}
|
|
|
|
$current = $source instanceof \WP_Post && $snapshot === []
|
|
? array_map('intval', wp_get_post_categories($source->ID))
|
|
: array_map('intval', (array) ($snapshot['categories'] ?? []));
|
|
$tags = $source instanceof \WP_Post && $snapshot === []
|
|
? wp_get_post_tags($source->ID, ['fields' => 'names'])
|
|
: array_map('strval', (array) ($snapshot['tags'] ?? []));
|
|
|
|
$custom_defs = [];
|
|
$custom = [];
|
|
if (!empty($settings['custom_filter_s']) && class_exists('\Jio\Settings\Settings')) {
|
|
$filter_all = \Jio\Settings\Settings::get_post_filter_settings();
|
|
$dims = is_array($filter_all['custom_filter'] ?? null) ? $filter_all['custom_filter'] : [];
|
|
foreach ($dims as $dim) {
|
|
$key = sanitize_key((string) ($dim['key'] ?? ''));
|
|
if ($key === '') {
|
|
continue;
|
|
}
|
|
$vals = [];
|
|
foreach ((array) ($dim['vals'] ?? []) as $value) {
|
|
$vkey = (string) ($value['key'] ?? '');
|
|
if ($vkey === '') {
|
|
continue;
|
|
}
|
|
$vals[] = ['key' => $vkey, 'name' => (string) ($value['name'] ?? $vkey)];
|
|
}
|
|
$custom_defs[] = ['key' => $key, 'name' => (string) ($dim['name'] ?? $key), 'values' => $vals];
|
|
$saved = $snapshot !== [] ? ($snapshot['custom'][$key] ?? []) : ($source instanceof \WP_Post ? get_post_meta($source->ID, '_jio_cf_' . $key, true) : []);
|
|
$custom[$key] = is_array($saved) ? array_values(array_map('strval', $saved)) : ($saved !== '' ? [(string) $saved] : []);
|
|
}
|
|
}
|
|
|
|
return [
|
|
'categories' => ['items' => $categories, 'selected' => $current],
|
|
'tags' => ['items' => is_array($tags) ? array_values($tags) : [], 'enabled' => !empty($settings['allow_tags'])],
|
|
'custom' => $custom,
|
|
'customDefs' => $custom_defs,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $post_meta
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function creator_featured_payload(?\WP_Post $source, array $post_meta): array {
|
|
$type = '';
|
|
$data = [];
|
|
$id = 0;
|
|
if ($source instanceof \WP_Post) {
|
|
$thumb_id = (int) get_post_thumbnail_id($source->ID);
|
|
$url = $thumb_id > 0 ? (string) wp_get_attachment_image_url($thumb_id, 'full') : (string) ($post_meta['thumbnail_url'] ?? '');
|
|
if ($url !== '') {
|
|
$type = 'image';
|
|
$id = $thumb_id;
|
|
$data = ['url' => $url, 'id' => $thumb_id];
|
|
}
|
|
}
|
|
$front = FrontSubmit::get_instance();
|
|
$user = get_current_user_id();
|
|
return [
|
|
'type' => $type,
|
|
'data' => $data,
|
|
'mediaId' => $id,
|
|
'canImage' => $front->user_can_cap('new_post_image_cover', $user),
|
|
'canSlide' => $front->user_can_cap('new_post_slide_cover', $user),
|
|
'canVideo' => $front->user_can_cap('new_post_video_cover', $user),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @param array<string, mixed> $pay_meta
|
|
* @param array<string, mixed> $settings
|
|
* @return array<string, mixed>
|
|
*/
|
|
private function pay_payload(array $pay_meta, array $snapshot, array $settings): array {
|
|
$front = FrontSubmit::get_instance();
|
|
$user = get_current_user_id();
|
|
$pay = $snapshot['pay']['fields'] ?? $pay_meta;
|
|
$enabled = $snapshot !== [] ? !empty($snapshot['pay']['enabled']) : (($pay_meta['pay_type'] ?? 'no') !== 'no');
|
|
|
|
$downloads = [];
|
|
foreach ((array) ($pay['downloads'] ?? []) as $row) {
|
|
if (!is_array($row)) {
|
|
continue;
|
|
}
|
|
$key = PrivateAssets::sanitize_asset_key((string) ($row['asset_key'] ?? ''));
|
|
$downloads[] = [
|
|
'type' => $key !== '' ? 'protected' : (string) ($row['type'] ?? 'direct'),
|
|
'assetKey' => $key,
|
|
'url' => $key !== '' ? '' : (string) ($row['url'] ?? ''),
|
|
'label' => (string) ($row['label'] ?? ''),
|
|
'fileName' => (string) ($row['file_name'] ?? ''),
|
|
'sizeBytes' => (int) ($row['size_bytes'] ?? 0),
|
|
];
|
|
}
|
|
|
|
return [
|
|
'enabled' => (bool) $enabled,
|
|
'canPay' => $front->user_can_cap('new_post_pay', $user),
|
|
'canDownload' => $front->user_can_cap('new_post_pay_download', $user),
|
|
'payModo' => (($pay['pay_modo'] ?? '0') === 'points') ? 'points' : 'cash',
|
|
'price' => (string) ($pay['price'] ?? '0.00'),
|
|
'points' => (int) ($pay['points_price'] ?? 0),
|
|
'vip1Price' => (string) ($pay['vip1_price'] ?? '0.00'),
|
|
'vip2Price' => (string) ($pay['vip2_price'] ?? '0.00'),
|
|
'payLimit' => (int) ($pay['pay_limit'] ?? 0),
|
|
'downloads' => $downloads,
|
|
'freeAllowed' => !empty($settings['pay_free_s']),
|
|
'priceMin' => (int) ($settings['pay_price_min'] ?? 0),
|
|
'priceMax' => (int) ($settings['pay_price_max'] ?? 0),
|
|
'pointsMin' => (int) ($settings['pay_points_min'] ?? 0),
|
|
'pointsMax' => (int) ($settings['pay_points_max'] ?? 0),
|
|
'privateStorage' => PrivateAssets::is_available(),
|
|
];
|
|
}
|
|
|
|
/**
|
|
* @return array<string, bool>
|
|
*/
|
|
private function capability_payload(FrontSubmit $front, int $user_id, int $post_id): array {
|
|
$cap = static function (string $name) use ($front, $user_id, $post_id): bool {
|
|
return $front->user_can_cap($name, $user_id, $post_id > 0 ? $post_id : null);
|
|
};
|
|
return [
|
|
'canUploadImage' => $cap('upload_submit_image'),
|
|
'canUploadVideo' => $cap('new_post_upload_video'),
|
|
'canUploadFile' => $cap('upload_resource_attachment'),
|
|
'canEmbed' => $cap('new_post_iframe_video'),
|
|
'canHide' => $cap('new_post_hide'),
|
|
'canPay' => $cap('new_post_pay'),
|
|
'canPayDownload' => $cap('new_post_pay_download'),
|
|
'canPublishNow' => $cap('new_post_audit_no'),
|
|
// 定时发布只有能直接发布的账号可用;其余账号提交后仍走审核队列。
|
|
'canSchedule' => $cap('new_post_audit_no'),
|
|
'canEdit' => $post_id > 0 ? $front->can_edit_post($post_id, $user_id) : $front->can_submit($user_id),
|
|
'isLoggedIn' => $user_id > 0,
|
|
];
|
|
}
|
|
}
|