refactor: flatten src/AKSRT → src (drop theme-identifier dir)
Move all domain folders from src/AKSRT/{Domain} to src/{Domain}; remap
Composer PSR-4 "AKSRT\\": "src/"; update audit script + README + ADR
paths; remove dead tools/build-psr4-map.php (scanned deleted inc/classes).
This commit is contained in:
@@ -0,0 +1,354 @@
|
||||
<?php
|
||||
/**
|
||||
* @package AKSRT
|
||||
*/
|
||||
|
||||
namespace AKSRT\Core;
|
||||
|
||||
defined('ABSPATH') || exit;
|
||||
|
||||
/**
|
||||
* Create / update / status machine for front-end article submit.
|
||||
*/
|
||||
trait FrontSubmitSave {
|
||||
|
||||
/**
|
||||
* Persist a front-end submission (new or edit).
|
||||
*
|
||||
* @param array<string, mixed> $data Request payload.
|
||||
* @param string $action posts_save|posts_draft
|
||||
* @return array{success:bool,message:string,post_id?:int,url?:string,goto?:string,reload?:bool,time?:string,posts_id?:int}
|
||||
*/
|
||||
public function persist(array $data, string $action = 'posts_save'): array {
|
||||
$user_id = get_current_user_id();
|
||||
$settings = $this->settings();
|
||||
$posts_id = absint($data['posts_id'] ?? $data['edit_id'] ?? $data['post_id'] ?? 0);
|
||||
$is_guest = $user_id <= 0;
|
||||
$is_edit = $posts_id > 0;
|
||||
$is_draft = $action === 'posts_draft';
|
||||
|
||||
if (empty($settings['enabled'])) {
|
||||
return ['success' => false, 'message' => __('投稿功能已关闭', 'aksrt')];
|
||||
}
|
||||
|
||||
if ($is_guest) {
|
||||
if (empty($settings['guest_enabled']) || (int) $settings['default_user_id'] <= 0) {
|
||||
return ['success' => false, 'message' => __('请先登录', 'aksrt')];
|
||||
}
|
||||
if ($is_draft) {
|
||||
return ['success' => false, 'message' => __('未登录无法保存草稿', 'aksrt')];
|
||||
}
|
||||
if ($is_edit) {
|
||||
return ['success' => false, 'message' => __('未登录无法编辑文章', 'aksrt')];
|
||||
}
|
||||
}
|
||||
|
||||
if ($is_edit) {
|
||||
if (!$this->can_edit_post($posts_id, $user_id)) {
|
||||
return ['success' => false, 'message' => __('没有编辑权限', 'aksrt')];
|
||||
}
|
||||
} elseif (!$this->can_submit($is_guest ? 0 : $user_id)) {
|
||||
return ['success' => false, 'message' => __('没有投稿权限', 'aksrt')];
|
||||
}
|
||||
|
||||
$title = sanitize_text_field((string) ($data['post_title'] ?? $data['title'] ?? ''));
|
||||
$content = (string) ($data['post_content'] ?? $data['content'] ?? '');
|
||||
$excerpt = sanitize_textarea_field((string) ($data['excerpt'] ?? $data['post_excerpt'] ?? ''));
|
||||
|
||||
if ($title === '') {
|
||||
return ['success' => false, 'message' => __('请填写文章标题', 'aksrt')];
|
||||
}
|
||||
if (trim(wp_strip_all_tags($content)) === '') {
|
||||
return ['success' => false, 'message' => __('还未填写任何内容', 'aksrt')];
|
||||
}
|
||||
|
||||
$categories = $this->normalize_category_ids($data);
|
||||
$tags_raw = (string) ($data['tags'] ?? '');
|
||||
|
||||
if (!$is_draft) {
|
||||
$title_len = $this->text_length($title);
|
||||
if ($title_len < (int) $settings['title_min']) {
|
||||
return ['success' => false, 'message' => __('标题太短!', 'aksrt')];
|
||||
}
|
||||
if ($title_len > (int) $settings['title_max']) {
|
||||
return [
|
||||
'success' => false,
|
||||
'message' => sprintf(
|
||||
/* translators: %d: max title length */
|
||||
__('标题太长了,不能超过%d个字', 'aksrt'),
|
||||
(int) $settings['title_max']
|
||||
),
|
||||
];
|
||||
}
|
||||
if ($this->text_length(wp_strip_all_tags($content)) < 10) {
|
||||
return ['success' => false, 'message' => __('文章内容过少', 'aksrt')];
|
||||
}
|
||||
if (!empty($settings['allow_category']) && empty($categories)) {
|
||||
return ['success' => false, 'message' => __('请选择文章分类', 'aksrt')];
|
||||
}
|
||||
if (!empty($settings['cover_required']) && empty($data['featured_data']) && empty($data['thumbnail'])) {
|
||||
return ['success' => false, 'message' => __('请设置封面图', 'aksrt')];
|
||||
}
|
||||
}
|
||||
|
||||
// Allowed category whitelist.
|
||||
$allowed = $settings['allowed_cat_ids'] ?? [];
|
||||
if (!empty($allowed) && !empty($categories)) {
|
||||
$categories = array_values(array_intersect($categories, $allowed));
|
||||
if (!$is_draft && empty($categories) && !empty($settings['allow_category'])) {
|
||||
return ['success' => false, 'message' => __('所选分类不可用', 'aksrt')];
|
||||
}
|
||||
}
|
||||
|
||||
$author_id = $user_id;
|
||||
if ($is_guest) {
|
||||
$guest_name = sanitize_text_field((string) ($data['user_name'] ?? ''));
|
||||
if ($guest_name === '') {
|
||||
return ['success' => false, 'message' => __('请输入昵称', 'aksrt')];
|
||||
}
|
||||
$contact = sanitize_text_field((string) ($data['contact_details'] ?? ''));
|
||||
$suffix = $contact !== ''
|
||||
? sprintf(__('[投稿-姓名:%1$s,联系:%2$s]', 'aksrt'), $guest_name, $contact)
|
||||
: sprintf(__('[投稿-姓名:%s]', 'aksrt'), $guest_name);
|
||||
$title = $title . $suffix;
|
||||
$author_id = (int) $settings['default_user_id'];
|
||||
}
|
||||
|
||||
$status = 'draft';
|
||||
if (!$is_draft) {
|
||||
$status = $this->resolve_publish_status($user_id, $settings);
|
||||
}
|
||||
|
||||
$can_iframe = $this->user_can_cap('new_post_iframe_video', $user_id);
|
||||
if ($can_iframe) {
|
||||
add_filter('wp_kses_allowed_html', [$this, 'allow_iframe_kses'], 99, 2);
|
||||
}
|
||||
$content = wp_kses_post($content);
|
||||
if ($can_iframe) {
|
||||
remove_filter('wp_kses_allowed_html', [$this, 'allow_iframe_kses'], 99);
|
||||
}
|
||||
|
||||
$postarr = [
|
||||
'post_type' => 'post',
|
||||
'post_title' => $title,
|
||||
'post_content' => $content,
|
||||
'post_status' => $status,
|
||||
'comment_status' => 'open',
|
||||
];
|
||||
if ($excerpt !== '' || array_key_exists('excerpt', $data) || array_key_exists('post_excerpt', $data)) {
|
||||
$postarr['post_excerpt'] = $excerpt;
|
||||
}
|
||||
if (!empty($settings['allow_tags']) && $tags_raw !== '') {
|
||||
$tag_names = preg_split('/[,,\n]+/u', $tags_raw) ?: [];
|
||||
$tag_names = array_values(array_filter(array_map('trim', $tag_names)));
|
||||
$postarr['tags_input'] = $tag_names;
|
||||
}
|
||||
if (!empty($categories)) {
|
||||
$postarr['post_category'] = $categories;
|
||||
}
|
||||
|
||||
if ($is_edit) {
|
||||
$postarr['ID'] = $posts_id;
|
||||
$in_id = wp_update_post($postarr, true);
|
||||
} else {
|
||||
$postarr['post_author'] = $author_id;
|
||||
$in_id = wp_insert_post($postarr, true);
|
||||
}
|
||||
|
||||
if (is_wp_error($in_id)) {
|
||||
return ['success' => false, 'message' => $in_id->get_error_message()];
|
||||
}
|
||||
if (!$in_id) {
|
||||
return ['success' => false, 'message' => __('文章保存失败,请稍后再试', 'aksrt')];
|
||||
}
|
||||
|
||||
// Re-apply categories when empty update should clear (logged-in only).
|
||||
if (!empty($settings['allow_category']) && isset($data['category'])) {
|
||||
wp_set_post_categories((int) $in_id, $categories);
|
||||
}
|
||||
if (!empty($settings['allow_tags']) && array_key_exists('tags', $data) && $tags_raw === '') {
|
||||
wp_set_post_tags((int) $in_id, []);
|
||||
}
|
||||
|
||||
$this->apply_topics_and_filters((int) $in_id, $data, $settings);
|
||||
|
||||
$pay_result = $this->save_pay_meta((int) $in_id, $data, $user_id, $settings);
|
||||
if (!$pay_result['success']) {
|
||||
$pay_result['post_id'] = (int) $in_id;
|
||||
$pay_result['posts_id'] = (int) $in_id;
|
||||
return $pay_result;
|
||||
}
|
||||
|
||||
$this->save_featured_meta((int) $in_id, $data, $user_id);
|
||||
|
||||
// Legacy thumbnail URL fallback.
|
||||
$thumbnail_url = esc_url_raw((string) ($data['thumbnail'] ?? ''));
|
||||
if ($thumbnail_url !== '' && empty($data['featured_data'])) {
|
||||
$this->set_thumbnail_from_url((int) $in_id, $thumbnail_url);
|
||||
}
|
||||
|
||||
$post = get_post((int) $in_id);
|
||||
if ($post instanceof \WP_Post) {
|
||||
do_action($is_edit ? 'aksrt_new_edit_posts' : 'aksrt_new_add_posts', $post);
|
||||
if ($status === 'pending') {
|
||||
do_action('aksrt_new_posts_pending', $post);
|
||||
}
|
||||
}
|
||||
|
||||
$url = get_permalink((int) $in_id) ?: '';
|
||||
$send = [
|
||||
'success' => true,
|
||||
'post_id' => (int) $in_id,
|
||||
'posts_id' => (int) $in_id,
|
||||
'url' => $url,
|
||||
];
|
||||
|
||||
switch ($status) {
|
||||
case 'pending':
|
||||
$send['message'] = __('内容已提交,正在等待审核', 'aksrt');
|
||||
if ($user_id > 0 && function_exists('aksrt_get_user_home_url')) {
|
||||
$send['reload'] = true;
|
||||
$send['goto'] = add_query_arg(
|
||||
['tab' => 'post', 'post_status' => 'pending'],
|
||||
aksrt_get_user_home_url($user_id)
|
||||
);
|
||||
}
|
||||
break;
|
||||
case 'draft':
|
||||
$send['message'] = __('草稿已保存', 'aksrt');
|
||||
$send['time'] = current_time('mysql');
|
||||
break;
|
||||
default:
|
||||
$send['message'] = __('文章已发布', 'aksrt');
|
||||
$send['reload'] = true;
|
||||
$send['goto'] = $url;
|
||||
break;
|
||||
}
|
||||
|
||||
return $send;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $settings
|
||||
*/
|
||||
private function resolve_publish_status(int $user_id, array $settings): string {
|
||||
$mode = (string) ($settings['review_mode'] ?? 'pending');
|
||||
if ($mode === 'draft') {
|
||||
return 'draft';
|
||||
}
|
||||
if ($mode === 'publish') {
|
||||
return 'publish';
|
||||
}
|
||||
// pending mode: skip audit when capability grants it.
|
||||
if ($this->user_can_cap('new_post_audit_no', $user_id)) {
|
||||
return 'publish';
|
||||
}
|
||||
return 'pending';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string, mixed> $data
|
||||
* @return int[]
|
||||
*/
|
||||
private function normalize_category_ids(array $data): array {
|
||||
$raw = $data['category'] ?? $data['categories'] ?? [];
|
||||
if (!is_array($raw)) {
|
||||
$raw = $raw === '' || $raw === null ? [] : [$raw];
|
||||
}
|
||||
$ids = array_values(array_unique(array_filter(array_map('absint', $raw))));
|
||||
return $ids;
|
||||
}
|
||||
|
||||
private function text_length(string $text): int {
|
||||
$text = trim(wp_strip_all_tags($text));
|
||||
if (function_exists('mb_strlen')) {
|
||||
return (int) mb_strlen($text);
|
||||
}
|
||||
return strlen($text);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,mixed> $data
|
||||
* @param array<string,mixed> $settings
|
||||
*/
|
||||
private function apply_topics_and_filters(int $post_id, array $data, array $settings): void {
|
||||
if (!empty($settings['topics_s']) && taxonomy_exists('topics')) {
|
||||
$topics = $data['topics'] ?? [];
|
||||
if (!is_array($topics)) {
|
||||
$topics = $topics === '' || $topics === null ? [] : [$topics];
|
||||
}
|
||||
$topic_ids = array_values(array_filter(array_map('absint', $topics)));
|
||||
wp_set_object_terms($post_id, $topic_ids, 'topics');
|
||||
}
|
||||
|
||||
if (empty($settings['custom_filter_s'])) {
|
||||
return;
|
||||
}
|
||||
|
||||
$dims = [];
|
||||
if (class_exists('\AKSRT\Settings\Settings')) {
|
||||
$filter_all = \AKSRT\Settings\Settings::get_post_filter_settings();
|
||||
$dims = is_array($filter_all['custom_filter'] ?? null) ? $filter_all['custom_filter'] : [];
|
||||
}
|
||||
|
||||
$allowed_keys = [];
|
||||
foreach ($dims as $dim) {
|
||||
if (!empty($dim['key'])) {
|
||||
$allowed_keys[] = sanitize_key((string) $dim['key']);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($data as $key => $val) {
|
||||
$dim_key = '';
|
||||
if (strpos((string) $key, 'cf_') === 0) {
|
||||
$dim_key = sanitize_key(substr((string) $key, 3));
|
||||
} elseif (strpos((string) $key, '_aksrt_cf_') === 0) {
|
||||
$dim_key = sanitize_key(substr((string) $key, 10));
|
||||
} elseif (in_array(sanitize_key((string) $key), $allowed_keys, true)) {
|
||||
$dim_key = sanitize_key((string) $key);
|
||||
}
|
||||
if ($dim_key === '' || (!empty($allowed_keys) && !in_array($dim_key, $allowed_keys, true))) {
|
||||
continue;
|
||||
}
|
||||
$meta_key = '_aksrt_cf_' . $dim_key;
|
||||
if (is_array($val)) {
|
||||
$vals = array_values(array_filter(array_map('sanitize_key', $val)));
|
||||
if ($vals) {
|
||||
update_post_meta($post_id, $meta_key, $vals);
|
||||
} else {
|
||||
delete_post_meta($post_id, $meta_key);
|
||||
}
|
||||
} else {
|
||||
$cf_val = sanitize_key((string) $val);
|
||||
if ($cf_val !== '') {
|
||||
update_post_meta($post_id, $meta_key, $cf_val);
|
||||
} else {
|
||||
delete_post_meta($post_id, $meta_key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @param array<string,string> $tags
|
||||
* @return array<string,string>
|
||||
*/
|
||||
public function allow_iframe_kses(array $tags, $context = ''): array {
|
||||
if ($context !== 'post' && $context !== '') {
|
||||
return $tags;
|
||||
}
|
||||
$tags['iframe'] = [
|
||||
'src' => true,
|
||||
'width' => true,
|
||||
'height' => true,
|
||||
'frameborder' => true,
|
||||
'allowfullscreen' => true,
|
||||
'allow' => true,
|
||||
'style' => true,
|
||||
'class' => true,
|
||||
'id' => true,
|
||||
'scrolling' => true,
|
||||
];
|
||||
return $tags;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user