Files
wordpress-theme-aksrt/templates/parts/user-center/creator-posts.php
T
kate522andClaude Opus 5 fac4a714e0 feat(creator-studio): 前台 Gutenberg 创作工作台与受保护付费附件
前台投稿页改为沉浸式创作工作台:Gutenberg 负责区块解析与序列化,
React + TypeScript 负责工作台外壳与发布抽屉,Jio 服务端继续作为权限、
审核与付费的唯一权威。

- 新增 assets/creator-studio 独立构建(wp-scripts,锁定 WP 6.4 时代包),
  仅在投稿模板加载,构建缺失或游客访问时回退原有 TinyMCE 表单
- 自动保存(4s 防抖 + rev 冲突 409)、本地快照恢复、发布配置抽屉、
  移动端全屏单列与安全区适配
- 图片插入走现有 front-submit 上传管线,保留能力校验与待认领生命周期
- 已发布文章的改稿写入私有版本,审核通过前线上内容/链接/付费条款不变;
  原生后台「改稿审核」一次性应用或退回,并校验源文章并发指纹
- 私有附件新表 jio_private_asset + jio_dl_token.asset_id,schema 升到 3.4.0;
  文件存放 ABSPATH 之外,未配置私有存储时 fail closed
- 下载令牌绑定文章/附件/用户/IP/UA/次数,每次交付复核 Visibility 的
  订单、VIP 与配额判定;中断传输归还次数
- 付费字段改为写入前校验,非法价格不再留下半保存文章
- 新增 creator-studio 契约测试;更新受影响的 schema/下载/投稿契约

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-06 14:53:23 +08:00

43 lines
4.4 KiB
PHP

<?php
defined('ABSPATH') || exit;
$context = is_array($args['context'] ?? null) ? $args['context'] : [];
extract($context, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_extract
$creator_args = is_array($args['creator_args'] ?? null) ? $args['creator_args'] : [];
$status = (string) ($creator_args['status'] ?? 'all');
$statuses = $status === 'all' ? ['publish', 'draft', 'pending', 'private'] : [$status];
$page = max(1, (int) ($_GET['creator_page'] ?? 1));
$q = new WP_Query(['author' => (int) $user_id, 'post_type' => 'post', 'post_status' => $statuses, 'posts_per_page' => 10, 'paged' => $page, 'no_found_rows' => false]);
$front_submit = class_exists('\\Jio\\Core\\FrontSubmit') ? \Jio\Core\FrontSubmit::get_instance() : null;
$status_labels = ['publish' => __('已发布', 'jio'), 'draft' => __('草稿', 'jio'), 'pending' => __('待审核', 'jio'), 'private' => __('私密', 'jio')];
?>
<?php if ($q->have_posts()) : ?>
<div class="creator-post-list">
<?php while ($q->have_posts()) : $q->the_post();
$post_id = get_the_ID();
$post_status = get_post_status();
$review_note = '';
if ($front_submit && class_exists('\\Jio\\Core\\SubmissionVersion') && \Jio\Core\SubmissionVersion::requires_version((int) $post_id)) {
$working = \Jio\Core\SubmissionVersion::get_working((int) $post_id, (int) $user_id);
if ($working instanceof WP_Post) {
$review_note = \Jio\Core\SubmissionVersion::status_label(\Jio\Core\SubmissionVersion::status((int) $working->ID));
}
}
// 编辑入口始终指向源文章;创作工作台会自行解析作者当前的工作版本。
$edit_url = $front_submit && $front_submit->can_edit_post($post_id, (int) $user_id) ? jio_get_new_post_url((int) $post_id) : '';
$can_delete = $front_submit && $front_submit->can_delete_post($post_id, (int) $user_id);
$price = (float) get_post_meta($post_id, '_jio_pay_price', true);
?>
<article class="creator-post-row" data-post-id="<?php echo esc_attr((string) $post_id); ?>">
<a class="creator-post-row__thumb" href="<?php echo esc_url(get_permalink($post_id)); ?>" aria-label="<?php echo esc_attr(get_the_title()); ?>">
<?php if (has_post_thumbnail($post_id)) : the_post_thumbnail('medium'); else : ?><span><i class="fa fas fa-pen" aria-hidden="true"></i></span><?php endif; ?>
</a>
<div class="creator-post-row__body"><div class="creator-post-row__heading"><h4><a href="<?php echo esc_url(get_permalink($post_id)); ?>"><?php echo esc_html(get_the_title($post_id)); ?></a></h4><span class="creator-post-row__status creator-post-row__status--<?php echo esc_attr($post_status); ?>"><?php echo esc_html($status_labels[$post_status] ?? $post_status); ?></span><?php if ($review_note !== '') : ?><span class="creator-post-row__status creator-post-row__status--review"><?php echo esc_html(sprintf(__('改稿:%s', 'jio'), $review_note)); ?></span><?php endif; ?></div><p><?php echo esc_html(wp_trim_words(get_the_excerpt(), 20, '…')); ?></p><div class="creator-post-row__meta"><time datetime="<?php echo esc_attr(get_the_date('c')); ?>"><?php echo esc_html(get_the_date()); ?></time><span><?php echo $price > 0 ? esc_html__('付费内容', 'jio') : esc_html__('免费内容', 'jio'); ?></span></div></div>
<div class="creator-post-row__actions"><?php if ($edit_url) : ?><a href="<?php echo esc_url($edit_url); ?>" class="creator-post-row__action"><?php esc_html_e('编辑', 'jio'); ?></a><?php endif; ?><a href="<?php echo esc_url(get_permalink($post_id)); ?>" class="creator-post-row__action"><?php esc_html_e('查看', 'jio'); ?></a><?php if ($can_delete) : ?><button type="button" class="creator-post-row__action creator-post-row__action--danger" data-action="delete-post" data-post-id="<?php echo esc_attr((string) $post_id); ?>" data-nonce="<?php echo esc_attr(wp_create_nonce('jio_submit')); ?>"><?php esc_html_e('删除', 'jio'); ?></button><?php endif; ?></div>
</article>
<?php endwhile; ?>
</div>
<?php jio_render_profile_pagination((int) $q->max_num_pages, $page, 'creator_page'); wp_reset_postdata(); ?>
<?php else : ?>
<div class="creator-workspace__empty"><i class="fa fas fa-pen" aria-hidden="true"></i><h4><?php esc_html_e('还没有文章', 'jio'); ?></h4><p><?php esc_html_e('开始创作你的第一篇文章吧。', 'jio'); ?></p><?php if (!empty($new_post_url)) : ?><a class="btn-primary btn-sm" href="<?php echo esc_url($new_post_url); ?>"><?php esc_html_e('写新文章', 'jio'); ?></a><?php endif; ?></div>
<?php endif; ?>