refactor(classes): organize inc/classes into domain folders

Move ~94 root class shells and root *-traits into domain directories
(core, auth, user, credits, content, payment/gateways, forum, shop,
sms, ai, messages, extensions, widgets, settings, admin). Update
bootstrap require paths, co-locate traits with owners, fix forum/user
relative requires, drop duplicate shop controller requires, and wire
home-modules load. Path-only; class names and init order unchanged.
This commit is contained in:
2026-07-17 11:11:57 +08:00
parent 2a8fe68048
commit ce1c13b947
115 changed files with 171 additions and 224 deletions
+397
View File
@@ -0,0 +1,397 @@
<?php
/**
* AKSRT Theme Setup
*
* 主题初始化:注册菜单、侧边栏、图片尺寸、自定义文章类型等
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Setup {
use AKSRT_Setup_Part_1;
use AKSRT_Setup_Part_2;
private static $instance = null;
private function __construct() {}
public static function get_instance(): self {
if (null === self::$instance) {
self::$instance = new self();
}
return self::$instance;
}
public function init(): void {
add_action('after_setup_theme', [$this, 'load_textdomain'], 1);
add_action('after_setup_theme', [$this, 'setup_theme']);
add_action('widgets_init', [$this, 'register_sidebars']);
add_filter('dynamic_sidebar_params', [$this, 'filter_sidebar_widget_params']);
add_action('init', [$this, 'register_nav_menus'], 0);
add_action('init', [$this, 'register_post_types'], 1);
add_action('init', [$this, 'register_meta_fields'], 5);
add_action('init', [$this, 'register_shop_rewrite_rules'], 20);
add_filter('query_vars', [$this, 'register_shop_query_vars']);
add_action('template_redirect', [$this, 'shop_template_redirect']);
// Shop fulfillment hook (§6.5 R68)
if (class_exists('AKSRT_Shop')) {
add_action('aksrt_order_paid', [AKSRT_Shop::get_instance(), 'handle_order_paid'], 10, 2);
}
// Auto-confirm receipt cron (§6.5 R68)
if (!wp_next_scheduled('aksrt_auto_confirm_receipt')) {
wp_schedule_event(time(), 'hourly', 'aksrt_auto_confirm_receipt');
}
if (class_exists('AKSRT_Shop')) {
add_action('aksrt_auto_confirm_receipt', [AKSRT_Shop::get_instance(), 'run_auto_confirm_cron']);
}
// 文章浏览量统计(单次访问)
add_action('wp', 'aksrt_set_post_views');
// 隐藏默认WordPress管理菜单
add_action('admin_menu', [$this, 'hide_default_menus'], 999);
}
public function load_textdomain(): void {
load_theme_textdomain('aksrt', AKSRT_DIR . '/languages');
}
public function setup_theme(): void {
// HTML5 支持
add_theme_support('html5', [
'search-form', 'comment-form', 'comment-list',
'gallery', 'caption', 'style', 'script',
'navigation-widgets',
]);
add_theme_support('title-tag');
add_theme_support('post-thumbnails');
add_theme_support('custom-logo', [
'height' => 120,
'width' => 300,
'flex-height' => true,
'flex-width' => true,
'header-text' => true,
]);
add_theme_support('customize-selective-refresh-widgets');
add_theme_support('align-wide');
add_theme_support('wp-block-styles');
add_theme_support('responsive-embeds');
// 文章格式
add_theme_support('post-formats', ['aside', 'image', 'video', 'quote', 'link', 'gallery']);
// 图片尺寸
add_image_size('aksrt-cover', 1200, 675, true);
add_image_size('aksrt-card', 400, 260, true);
add_image_size('aksrt-thumb', 150, 150, true);
add_image_size('aksrt-banner', 1920, 500, true);
// 内容宽度(用于区块编辑器)
if (!isset($GLOBALS['content_width'])) {
$GLOBALS['content_width'] = 900;
}
}
public function register_nav_menus(): void {
register_nav_menus([
'primary' => __('主导航', 'aksrt'),
'mobile' => __('移动端菜单', 'aksrt'),
'footer' => __('页脚菜单', 'aksrt'),
'social' => __('社交链接', 'aksrt'),
'header_actions' => __('顶部右侧入口', 'aksrt'),
]);
}
/**
* 注册自定义文章类型
*
* 资源不是 CPT:元数据挂在普通 post 上,
* 通过 _aksrt_is_resource meta 标记是否为资源。
*/
public function register_post_types(): void {
// Shop rewrite settings (safe fallback if settings not yet loaded)
$shop_rewrite = [];
if (class_exists('AKSRT_Settings')) {
$shop = AKSRT_Settings::get_shop_settings();
$shop_rewrite = $shop['rewrite'] ?? [];
}
$product_slug = sanitize_key((string) ($shop_rewrite['product_slug'] ?? 'product'));
$suffix_html = !empty($shop_rewrite['suffix_html']);
// Shop admin visibility: align with zibll native sidebar when shop is enabled.
$shop_enabled = true;
if (class_exists('AKSRT_Settings')) {
$shop_settings = AKSRT_Settings::get_shop_settings();
$shop_enabled = !empty($shop_settings['enabled']);
}
// Always register UI in admin so settings/tools remain reachable; hide menu when disabled.
$shop_show_ui = true;
$shop_show_menu = is_admin() ? $shop_enabled : false;
// 商品 CPT — native WP sidebar (zibll: shop_product @ pos 35)
register_post_type('aksrt_product', [
'labels' => [
'name' => __('商城', 'aksrt'),
'singular_name' => __('商品', 'aksrt'),
'add_new' => __('新增商品', 'aksrt'),
'add_new_item' => __('新增商品', 'aksrt'),
'edit_item' => __('编辑商品', 'aksrt'),
'new_item' => __('新商品', 'aksrt'),
'view_item' => __('查看商品', 'aksrt'),
'search_items' => __('搜索商品', 'aksrt'),
'not_found' => __('未找到商品', 'aksrt'),
'not_found_in_trash' => __('回收站中无商品', 'aksrt'),
'all_items' => __('所有商品', 'aksrt'),
'menu_name' => __('商城', 'aksrt'),
],
'public' => true,
'publicly_queryable' => true,
'show_ui' => $shop_show_ui,
'show_in_menu' => $shop_show_menu,
'show_in_rest' => true,
'has_archive' => true,
'hierarchical' => false,
'menu_position' => 35,
'menu_icon' => 'dashicons-store',
'supports' => ['title', 'editor', 'excerpt', 'thumbnail', 'author', 'revisions'],
'rewrite' => ['slug' => $product_slug, 'with_front' => false],
'capability_type' => 'post',
'map_meta_cap' => true,
]);
// 商品分类 taxonomy(独立于文章 category)
register_taxonomy('aksrt_product_cat', 'aksrt_product', [
'labels' => [
'name' => __('商品分类', 'aksrt'),
'singular_name' => __('商品分类', 'aksrt'),
'search_items' => __('搜索商品分类', 'aksrt'),
'all_items' => __('所有商品分类', 'aksrt'),
'parent_item' => __('父级分类', 'aksrt'),
'edit_item' => __('编辑分类', 'aksrt'),
'add_new_item' => __('新增分类', 'aksrt'),
'menu_name' => __('商品分类', 'aksrt'),
],
'public' => true,
'hierarchical' => true,
'show_ui' => $shop_show_ui,
'show_in_menu' => $shop_show_menu,
'show_in_rest' => true,
'show_admin_column' => true,
'rewrite' => ['slug' => 'product-cat', 'with_front' => false],
]);
// 商品标签 taxonomy(独立于文章 post_tag)
register_taxonomy('aksrt_product_tag', 'aksrt_product', [
'labels' => [
'name' => __('商品标签', 'aksrt'),
'singular_name' => __('商品标签', 'aksrt'),
'search_items' => __('搜索商品标签', 'aksrt'),
'all_items' => __('所有商品标签', 'aksrt'),
'edit_item' => __('编辑标签', 'aksrt'),
'add_new_item' => __('新增标签', 'aksrt'),
'menu_name' => __('特色标签', 'aksrt'),
],
'public' => true,
'hierarchical' => false,
'show_ui' => $shop_show_ui,
'show_in_menu' => $shop_show_menu,
'show_in_rest' => true,
'show_admin_column' => true,
'rewrite' => ['slug' => 'product-tag', 'with_front' => false],
]);
// 项目展示
register_post_type('project', [
'labels' => [
'name' => __('项目展示', 'aksrt'),
'singular_name' => __('项目', 'aksrt'),
'add_new' => __('新建项目', 'aksrt'),
'add_new_item' => __('新建项目', 'aksrt'),
'edit_item' => __('编辑项目', 'aksrt'),
'new_item' => __('新项目', 'aksrt'),
'view_item' => __('查看项目', 'aksrt'),
'search_items' => __('搜索项目', 'aksrt'),
'not_found' => __('未找到项目', 'aksrt'),
'not_found_in_trash' => __('回收站中无项目', 'aksrt'),
'menu_name' => __('项目展示', 'aksrt'),
],
'public' => true,
'publicly_queryable' => true,
'show_ui' => true,
'show_in_menu' => false,
'show_in_nav_menus' => false,
'has_archive' => false,
'hierarchical' => false,
'menu_position' => 25,
'menu_icon' => 'dashicons-portfolio',
'supports' => ['title', 'editor', 'excerpt', 'thumbnail', 'author', 'revisions'],
'rewrite' => ['slug' => 'project'],
'capability_type' => 'post',
'map_meta_cap' => true,
]);
}
/**
* 注册资源 post meta + 分类 term meta(aksrt_flow)
*
* 全部 show_in_rest,便于 Block Editor + Vue SPA 读写。
*
* v3.4: 资源元数据全部挂在 post 上,配合 _aksrt_is_resource 开关使用。
*/
public function register_meta_fields(): void {
$post_edit_auth = static function () {
return current_user_can('edit_posts');
};
// Core switch: mark a post as resource.
register_post_meta('post', AKSRT_Domain_Model::RESOURCE_MARKER_KEY, [
'type' => 'boolean',
'description' => 'Whether this post is a resource post.',
'single' => true,
'default' => false,
'show_in_rest' => true,
'sanitize_callback' => static function ($v) { return (bool) $v; },
'auth_callback' => $post_edit_auth,
]);
register_post_meta('post', AKSRT_Domain_Model::PAY_META_KEY, [
'type' => 'object',
'description' => 'Canonical paid content payload.',
'single' => true,
'default' => AKSRT_Domain_Model::default_pay_meta(),
'show_in_rest' => [
'schema' => [
'type' => 'object',
'properties' => [
'pay_type' => [
'type' => 'string',
'enum' => array_keys(AKSRT_Domain_Model::pay_type_labels()),
],
'price' => ['type' => 'number'],
'original_price' => ['type' => 'number'],
'vip1_price' => ['type' => 'number'],
'vip2_price' => ['type' => 'number'],
'version' => ['type' => 'string'],
'size' => ['type' => 'string'],
'license' => ['type' => 'string'],
'compat' => ['type' => 'string'],
'demo_url' => ['type' => 'string', 'format' => 'uri'],
'video_url' => ['type' => 'string', 'format' => 'uri'],
'downloads' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'label' => ['type' => 'string'],
'url' => ['type' => 'string', 'format' => 'uri'],
'type' => ['type' => 'string'],
'extract_code' => ['type' => 'string'],
],
],
],
'attributes' => [
'type' => 'array',
'items' => [
'type' => 'object',
'properties' => [
'key' => ['type' => 'string'],
'value' => ['type' => 'string'],
],
],
],
'gallery' => [
'type' => 'array',
'items' => ['type' => 'string', 'format' => 'uri'],
],
'require_login' => ['type' => 'boolean'],
'require_captcha' => ['type' => 'boolean'],
],
],
],
'sanitize_callback' => [AKSRT_Domain_Model::class, 'sanitize_pay_meta'],
'auth_callback' => $post_edit_auth,
]);
register_post_meta('post', AKSRT_Domain_Model::PAY_TYPE_KEY, [
'type' => 'string',
'description' => 'Query-friendly paid content type.',
'single' => true,
'default' => AKSRT_Domain_Model::PAY_TYPE_NO,
'show_in_rest' => true,
'sanitize_callback' => [AKSRT_Domain_Model::class, 'normalize_pay_type'],
'auth_callback' => $post_edit_auth,
]);
register_post_meta('post', AKSRT_Domain_Model::PAY_PRICE_KEY, [
'type' => 'number',
'description' => 'Query-friendly paid content price.',
'single' => true,
'default' => 0,
'show_in_rest' => true,
'sanitize_callback' => static function ($value) {
return max(0, (float) $value);
},
'auth_callback' => $post_edit_auth,
]);
foreach ([
AKSRT_Domain_Model::RESOURCE_DOWNLOAD_COUNT_KEY => 'Resource download count',
AKSRT_Domain_Model::RESOURCE_VIEW_COUNT_KEY => 'Resource view count',
AKSRT_Domain_Model::POST_VIEW_COUNT_KEY => 'Generic post view count',
] as $meta_key => $description) {
register_post_meta('post', $meta_key, [
'type' => 'integer',
'description' => $description,
'single' => true,
'default' => 0,
'show_in_rest' => true,
'sanitize_callback' => 'absint',
'auth_callback' => $post_edit_auth,
]);
}
register_term_meta('category', 'aksrt_flow', [
'type' => 'string',
'description' => 'Category flow mode: inherit/blog/cms',
'single' => true,
'default' => 'inherit',
'show_in_rest' => true,
'sanitize_callback' => function ($v) {
$v = is_string($v) ? $v : 'inherit';
return in_array($v, ['inherit', 'blog', 'cms'], true) ? $v : 'inherit';
},
'auth_callback' => function () {
return current_user_can('manage_categories');
},
]);
}
public static function sanitize_downloads_meta($value): array {
return AKSRT_Domain_Model::sanitize_downloads($value);
}
/**
* 为 Customizer 小工具实时预览补齐编辑态包裹。
*
* @param array $params Dynamic sidebar params.
* @return array
*/
public function filter_sidebar_widget_params(array $params): array {
if (!is_customize_preview() || empty($params[0]['before_widget']) || empty($params[0]['after_widget'])) {
return $params;
}
$params[0]['before_widget'] = '<div class="customize-preview-widget-box"><div class="customize-preview-widget-edit"></div>' . $params[0]['before_widget'];
$params[0]['after_widget'] = $params[0]['after_widget'] . '</div>';
return $params;
}
/**
* 注册侧边栏
*/
}
return AKSRT_Setup::get_instance();