384 lines
16 KiB
PHP
384 lines
16 KiB
PHP
<?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']);
|
||
|
||
// 商品 CPT
|
||
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'),
|
||
'menu_name' => __('商品', 'aksrt'),
|
||
],
|
||
'public' => true,
|
||
'publicly_queryable' => true,
|
||
'show_ui' => true,
|
||
'show_in_menu' => false,
|
||
'show_in_rest' => true,
|
||
'has_archive' => true,
|
||
'hierarchical' => false,
|
||
'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' => false,
|
||
'show_in_rest' => true,
|
||
'show_admin_column' => false,
|
||
'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' => false,
|
||
'show_in_rest' => true,
|
||
'show_admin_column' => false,
|
||
'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();
|