- Replace transfer modal/admin-post flow with reference-style AJAX export/import/template dialogs (admin-transfer.js, TransferController) - Customizer "移出模块" action, reference lazy form loading with t-notice - Common fields use reference labels, dependencies, compact/inline rows, top/bottom-only extra spacing; form header with description/reminder - Remove placement hint, template preview and legacy transfer code - Fix widget audit (current_datetime stub, honor catalog common flags) and regenerate stale golden fixtures for posts_toc, quote, posts Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
113 lines
6.1 KiB
PHP
113 lines
6.1 KiB
PHP
<?php
|
|
|
|
namespace AKSRT\WidgetSystem;
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
/**
|
|
* Lazy widget form endpoint and admin-only assets.
|
|
*/
|
|
final class AdminFormController {
|
|
public const AJAX_ACTION = 'aksrt_widget_form';
|
|
private const NONCE_ACTION = 'aksrt_widget_form';
|
|
|
|
public static function register_hooks(): void {
|
|
add_action('wp_ajax_' . self::AJAX_ACTION, [self::class, 'ajax_form']);
|
|
add_action('admin_enqueue_scripts', [self::class, 'enqueue']);
|
|
add_action('customize_controls_enqueue_scripts', [self::class, 'enqueue']);
|
|
}
|
|
|
|
public static function enqueue(): void {
|
|
$screen = function_exists('get_current_screen') ? get_current_screen() : null;
|
|
$is_customizer = current_filter() === 'customize_controls_enqueue_scripts';
|
|
if (!$is_customizer && (!$screen || !in_array($screen->id, ['widgets', 'customize'], true))) {
|
|
return;
|
|
}
|
|
wp_enqueue_media();
|
|
wp_enqueue_style('wp-color-picker');
|
|
wp_enqueue_script('jquery-ui-sortable');
|
|
wp_enqueue_style('aksrt-widget-admin', AKSRT_URI . '/assets/widgets/admin.css', ['wp-color-picker'], AKSRT_VERSION);
|
|
wp_enqueue_style('aksrt-widget-preview', AKSRT_URI . '/assets/widgets/frontend.css', [], AKSRT_VERSION);
|
|
aksrt_icon_picker_assets(['wp-color-picker']);
|
|
wp_enqueue_script('aksrt-widget-admin-core', AKSRT_URI . '/assets/widgets/admin-core.js', [], AKSRT_VERSION, true);
|
|
wp_enqueue_script('aksrt-widget-admin', AKSRT_URI . '/assets/widgets/admin.js', ['jquery', 'jquery-ui-sortable', 'wp-color-picker', 'aksrt-widget-admin-core'], AKSRT_VERSION, true);
|
|
wp_enqueue_script('aksrt-widget-admin-transfer', AKSRT_URI . '/assets/widgets/admin-transfer.js', ['jquery', 'aksrt-widget-admin'], AKSRT_VERSION, true);
|
|
wp_localize_script('aksrt-widget-admin', 'aksrtWidgetAdmin', [
|
|
'ajaxUrl' => admin_url('admin-ajax.php'),
|
|
'action' => self::AJAX_ACTION,
|
|
'nonce' => wp_create_nonce(self::NONCE_ACTION),
|
|
'transferNonce' => wp_create_nonce(TransferController::NONCE),
|
|
'i18n' => self::i18n(),
|
|
]);
|
|
}
|
|
|
|
/** @return array<string,string> */
|
|
private static function i18n(): array {
|
|
return [
|
|
'loading' => __('正在加载模块配置…', 'aksrt'),
|
|
'error' => __('加载失败,请刷新页面后重试', 'aksrt'),
|
|
'confirmImportReplace' => __('将覆盖当前容器中已有的全部模块,导入内容将替换该侧栏;确定继续?', 'aksrt'),
|
|
'confirmImportAppend' => __('将在当前容器已有模块列表末尾追加导入内容,不会删除原有模块;确定继续?', 'aksrt'),
|
|
'importModeLabel' => __('导入方式', 'aksrt'),
|
|
'importModeReplace' => __('覆盖(替换现有)', 'aksrt'),
|
|
'importModeAppend' => __('追加(保留现有)', 'aksrt'),
|
|
'loadingExport' => __('正在生成 JSON…', 'aksrt'),
|
|
'loadingImport' => __('正在导入…', 'aksrt'),
|
|
'copyDone' => __('已复制', 'aksrt'),
|
|
'copyFail' => __('复制失败,请手动全选复制', 'aksrt'),
|
|
'exportTitle' => __('导出 JSON(可复制)', 'aksrt'),
|
|
'importTitle' => __('导入 JSON(粘贴后确认)', 'aksrt'),
|
|
'importHint' => __('将导出得到的 JSON 粘贴到下方文本框以导入。注意:不同主题版本或非同站的的模块导入后可能会出现错误,此时可以重新配置一下有错误的模块,即可恢复正常', 'aksrt'),
|
|
'exportHint' => __('以下为当前容器模块数据,可直接全选复制保存。', 'aksrt'),
|
|
'close' => __('关闭', 'aksrt'),
|
|
'copy' => __('复制全部', 'aksrt'),
|
|
'submitImport' => __('确认导入', 'aksrt'),
|
|
'reloadPage' => __('刷新页面', 'aksrt'),
|
|
'templateModalTitle' => __('从模板导入', 'aksrt'),
|
|
'templateHint' => __('使用模板可快速配置网站布局,选择对应的模板点击导入即可。', 'aksrt') . '<div class="aksrt-wie-remind"><b>' . __('注意事项:', 'aksrt') . '</b>' . __('1.导入模板必须对容器位置对应,例如不能将侧边栏模板导入到全宽度中!', 'aksrt') . '<br>' . __('2.导入模板需已经有对应的内容,例如:导入文章相关的模板,那么至少已经有多篇文章和文章分类', 'aksrt') . '</div>',
|
|
'templateLoadingList' => __('正在加载模板列表…', 'aksrt'),
|
|
'templateEmpty' => __('暂无可用模板。', 'aksrt'),
|
|
'templateSubmit' => __('导入所选模板', 'aksrt'),
|
|
'confirmTemplate' => __('确定导入模板「{title}」吗?导入方式:{mode}', 'aksrt'),
|
|
'templatePick' => __('请选择一个模板。', 'aksrt'),
|
|
'exportFailed' => __('导出失败', 'aksrt'),
|
|
'importSuccess' => __('导入成功', 'aksrt'),
|
|
'importFailed' => __('导入失败', 'aksrt'),
|
|
'pasteJsonFirst' => __('请先粘贴 JSON', 'aksrt'),
|
|
'exportModules' => __('导出模块', 'aksrt'),
|
|
'importModules' => __('导入模块', 'aksrt'),
|
|
'importTemplate' => __('模板导入', 'aksrt'),
|
|
'removeModule' => __('移出模块', 'aksrt'),
|
|
'networkError' => __('网络错误,请刷新页面后重试', 'aksrt'),
|
|
];
|
|
}
|
|
|
|
public static function ajax_form(): void {
|
|
check_ajax_referer(self::NONCE_ACTION, 'nonce');
|
|
if (!current_user_can('edit_theme_options')) {
|
|
wp_send_json_error(['message' => __('权限不足。', 'aksrt')], 403);
|
|
}
|
|
|
|
$id_base = isset($_POST['id_base']) ? sanitize_key(wp_unslash($_POST['id_base'])) : '';
|
|
$number = isset($_POST['widget_number']) ? absint($_POST['widget_number']) : 0;
|
|
$definition = WidgetRegistry::get_by_id_base($id_base);
|
|
if (!$definition || $number < 1) {
|
|
wp_send_json_error(['message' => __('无效的小工具实例。', 'aksrt')], 400);
|
|
}
|
|
|
|
$widget = new SchemaWidget($definition);
|
|
$widget->_set($number);
|
|
$settings = $widget->get_settings();
|
|
$instance = isset($settings[$number]) && is_array($settings[$number]) ? $settings[$number] : [];
|
|
$instance = apply_filters('widget_form_callback', $instance, $widget);
|
|
if (!is_array($instance)) {
|
|
$instance = [];
|
|
}
|
|
ob_start();
|
|
$widget->render_full_form($instance);
|
|
$html = (string) ob_get_clean();
|
|
wp_send_json_success(['html' => $html]);
|
|
}
|
|
}
|
|
|