Full-project rename. `git grep -i aksrt` is now empty apart from the
DBMigrator 3.3.0 changelog note that documents the rename itself.
Code identifiers
- PHP namespace AKSRT\ -> Jio\ (composer PSR-4 + 378 declarations)
- global constants AKSRT_* -> JIO_* (VERSION/DIR/URI, PAY_TYPE_*, CAPTCHA_*)
- procedural functions, hooks, options, meta keys, table names,
cookies, query vars, ajax actions and nonces: aksrt_ -> jio_
- text domain aksrt -> jio; Theme Name -> Jio
- JS globals: aksrtData/aksrtAdminData/... -> jioData/jioAdminData/...,
window.AKSRTCaptcha & friends -> window.JioCaptcha, Aksrt* -> Jio*
- Vue components Aks*.vue -> Jio*.vue (15 files renamed + imports)
- CSS classes/data-attrs/custom properties: aksrt- -> jio-
- REST namespace aksrt/v1 -> jio/v1 (incl. payment gateway callbacks)
Storage layer
- DB tables {prefix}aksrt_* -> {prefix}jio_*; SCHEMA_VERSION 3.2.0 -> 3.3.0
so dbDelta creates the new names on install
- widget id_base aksrt_widget_* -> jio_widget_*
- uninstall.php drop list rebuilt from the actual migrator tables
(dropped 3 stale entries, added the 17 missing ones)
Removed
- hardcoded https://api.aksrt.com/version.json default update endpoint;
get_endpoint() now reads the 「更新端点」 setting and do_check() no-ops
when it is empty
Files renamed: inc/helpers/aksrt-*.php -> jio-*.php (54),
assets/admin/src/components/form/Aks*.vue -> Jio*.vue (15).
Build artifacts regenerated: assets/css/build, assets/js/runtime,
assets/admin/build.
Verified: audit-psr4-paths errors=0, audit-admin-contracts errors=0
(warnings=56, unchanged baseline), 813/813 widget-system tests,
44/44 phpunit, php -l clean across all PHP.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
240 lines
9.4 KiB
PHP
240 lines
9.4 KiB
PHP
<?php
|
||
/**
|
||
* Jio Slider Helper — 轮播渲染函数
|
||
*
|
||
* 对标 legacy 的 legacy(),提供服务端轮播 HTML 生成。
|
||
* 支持 data-* 属性驱动配置、视差、懒加载、缩略图分页。
|
||
*
|
||
* @package Jio
|
||
*/
|
||
|
||
defined('ABSPATH') || exit;
|
||
|
||
/**
|
||
* 渲染 Swiper 轮播
|
||
*
|
||
* @param array $args {
|
||
* @type array $slides 幻灯片数据数组
|
||
* @type string $effect 动画效果: slide, fade, cube, coverflow, flip (默认 slide)
|
||
* @type bool $loop 是否循环 (默认 true)
|
||
* @type bool $autoplay 是否自动播放 (默认 true)
|
||
* @type int $interval 自动播放间隔 ms (默认 5000)
|
||
* @type int $speed 动画速度 ms (0=自动计算)
|
||
* @type string $direction 方向: horizontal, vertical (默认 horizontal)
|
||
* @type int $spaceBetween 幻灯片间距 px (默认 0)
|
||
* @type string $pagination_type 分页器类型: bullets, fraction, progressbar, thumbnail (默认 bullets)
|
||
* @type string $pc_height PC 端高度 CSS 值 (默认 auto)
|
||
* @type string $m_height 移动端高度 CSS 值 (默认 auto)
|
||
* @type bool $scale_height 是否使用比例高度 (默认 false)
|
||
* @type float $scale_ratio 比例值 (默认 0.45 = 45%)
|
||
* @type string $scale_extra 比例高度附加量,如 '50px'(用于封面标题预留,默认空)
|
||
* @type string $wrapper_class 额外 wrapper 类
|
||
* @type string $slider_class 额外 slider 类
|
||
* @type bool $show_nav 是否显示导航箭头 (默认 true)
|
||
* @type bool $show_pagination 是否显示分页器 (默认 true)
|
||
* }
|
||
*
|
||
* slide 数据格式:
|
||
* [
|
||
* 'image' => 'https://...',
|
||
* 'link' => 'https://...',
|
||
* 'title' => '标题',
|
||
* 'desc' => '描述',
|
||
* 'alt' => '图片 alt',
|
||
* 'bg_color' => '#f0f0f0', // 背景色
|
||
* 'target' => '_blank',
|
||
* ]
|
||
*
|
||
* @return string HTML
|
||
*/
|
||
function jio_render_slider(array $args = []): string {
|
||
$defaults = [
|
||
'slides' => [],
|
||
'effect' => 'slide',
|
||
'loop' => true,
|
||
'autoplay' => true,
|
||
'interval' => 5000,
|
||
'speed' => 0,
|
||
'direction' => 'horizontal',
|
||
'spaceBetween' => 0,
|
||
'pagination_type' => 'bullets',
|
||
'pc_height' => 'auto',
|
||
'm_height' => 'auto',
|
||
'scale_height' => false,
|
||
'scale_ratio' => 0.45,
|
||
'scale_extra' => '',
|
||
'wrapper_class' => '',
|
||
'slider_class' => '',
|
||
'show_nav' => true,
|
||
'show_pagination' => true,
|
||
// Optional absolute overlay HTML (e.g. single cover title/meta). Not escaped.
|
||
'overlay_html' => '',
|
||
];
|
||
|
||
$args = wp_parse_args($args, $defaults);
|
||
$slides = $args['slides'];
|
||
|
||
if (empty($slides) || !is_array($slides)) {
|
||
return '';
|
||
}
|
||
|
||
// 构建 data 属性
|
||
$data_attrs = [];
|
||
$data_attrs[] = 'data-effect="' . esc_attr($args['effect']) . '"';
|
||
if ($args['loop']) $data_attrs[] = 'data-loop';
|
||
if ($args['autoplay']) {
|
||
$data_attrs[] = 'data-autoplay';
|
||
$data_attrs[] = 'data-interval="' . esc_attr((string) $args['interval']) . '"';
|
||
}
|
||
if ($args['speed'] > 0) $data_attrs[] = 'data-speed="' . esc_attr((string) $args['speed']) . '"';
|
||
if ($args['direction'] !== 'horizontal') $data_attrs[] = 'data-direction="' . esc_attr($args['direction']) . '"';
|
||
if ($args['spaceBetween'] > 0) $data_attrs[] = 'data-spaceBetween="' . esc_attr((string) $args['spaceBetween']) . '"';
|
||
if ($args['pagination_type'] !== 'bullets') $data_attrs[] = 'data-pagination-type="' . esc_attr($args['pagination_type']) . '"';
|
||
|
||
// 高度样式
|
||
$height_style = '';
|
||
$scale_padding = '';
|
||
if ($args['scale_height']) {
|
||
// padding-bottom percentage for ratio box (legacy graphic cover style).
|
||
// 内层 .new-swiper 绝对定位铺满 wrapper,wrapper 决定盒子高度;
|
||
// pc/m-height 100% 让 .swiper-wrapper/.swiper-slide 铺满盒子,
|
||
// 使 object-fit: cover 在确定的盒内居中裁切(对齐单图封面)。
|
||
$ratio_pct = max(10, min(100, (float) $args['scale_ratio'] * 100));
|
||
$scale_padding = $ratio_pct . '%';
|
||
$scale_extra = trim((string) $args['scale_extra']);
|
||
if ($scale_extra !== '') {
|
||
$scale_padding = 'calc(' . $scale_padding . ' + ' . $scale_extra . ')';
|
||
}
|
||
$height_style = '--pc-height:100%;--m-height:100%;';
|
||
} else {
|
||
$height_style = sprintf('--pc-height:%s;--m-height:%s;', esc_attr($args['pc_height']), esc_attr($args['m_height']));
|
||
}
|
||
|
||
// CSS 类
|
||
$slider_classes = ['new-swiper', 'slide-index'];
|
||
if ($args['slider_class']) $slider_classes[] = $args['slider_class'];
|
||
$slider_class_str = implode(' ', $slider_classes);
|
||
|
||
$wrapper_classes = ['jio-slider-wrapper'];
|
||
if ($args['wrapper_class']) $wrapper_classes[] = $args['wrapper_class'];
|
||
if ($args['scale_height']) $wrapper_classes[] = 'jio-slider-wrapper--scale';
|
||
if ((string) $args['overlay_html'] !== '') $wrapper_classes[] = 'jio-slider-wrapper--has-overlay';
|
||
$wrapper_class_str = implode(' ', $wrapper_classes);
|
||
|
||
// 渲染 HTML
|
||
$html = '<div class="' . esc_attr($wrapper_class_str) . '"' . ($args['scale_height'] ? ' style="position:relative;padding-bottom:' . esc_attr($scale_padding) . ';"' : '') . '>';
|
||
$html .= '<div class="' . esc_attr($slider_class_str) . '" ' . implode(' ', $data_attrs) . ' style="' . esc_attr($height_style . ($args['scale_height'] ? 'position:absolute;inset:0;width:100%;height:100%;' : '')) . '">';
|
||
$html .= '<div class="swiper-wrapper">';
|
||
|
||
foreach ($slides as $slide) {
|
||
$image = esc_url($slide['image'] ?? '');
|
||
$link = esc_url($slide['link'] ?? '');
|
||
$title = sanitize_text_field($slide['title'] ?? '');
|
||
$desc = sanitize_text_field($slide['desc'] ?? '');
|
||
$alt = sanitize_text_field($slide['alt'] ?? $title);
|
||
$bg_color = \Jio\Core\Color::sanitize($slide['bg_color'] ?? '');
|
||
$target = ($slide['target'] ?? '') === '_blank' ? '_blank' : '_self';
|
||
|
||
$slide_style = $bg_color ? 'background-color:' . esc_attr($bg_color) . ';' : '';
|
||
|
||
$html .= '<div class="swiper-slide"' . ($slide_style ? ' style="' . esc_attr($slide_style) . '"' : '') . '>';
|
||
|
||
if ($link) {
|
||
$html .= '<a href="' . esc_url($link) . '" target="' . esc_attr($target) . '">';
|
||
}
|
||
|
||
if ($image) {
|
||
$html .= '<img' . jio_get_lazy_attr('lazy_sider', (string) $image, 'fit-cover', jio_get_lazy_thumb('lg')) . ' alt="' . esc_attr($alt) . '">';
|
||
}
|
||
|
||
if ($link) {
|
||
$html .= '</a>';
|
||
}
|
||
|
||
// 文字覆盖层
|
||
if ($title || $desc) {
|
||
$html .= '<div class="jio-slide-text">';
|
||
if ($title) $html .= '<div class="jio-slide-text__title">' . esc_html($title) . '</div>';
|
||
if ($desc) $html .= '<div class="jio-slide-text__desc">' . esc_html($desc) . '</div>';
|
||
$html .= '</div>';
|
||
}
|
||
|
||
$html .= '</div>';
|
||
}
|
||
|
||
$html .= '</div>'; // .swiper-wrapper
|
||
|
||
if ($args['show_nav']) {
|
||
$html .= '<div class="swiper-button-prev"></div>';
|
||
$html .= '<div class="swiper-button-next"></div>';
|
||
}
|
||
|
||
if ($args['show_pagination']) {
|
||
$html .= '<div class="swiper-pagination"></div>';
|
||
}
|
||
|
||
$html .= '</div>'; // .new-swiper
|
||
|
||
// Cover title/meta overlay (trusted HTML from single cover renderer).
|
||
if ((string) $args['overlay_html'] !== '') {
|
||
$html .= '<div class="jio-slider-overlay">' . $args['overlay_html'] . '</div>'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
|
||
}
|
||
|
||
$html .= '</div>'; // .jio-slider-wrapper
|
||
|
||
return $html;
|
||
}
|
||
|
||
/**
|
||
* 渲染水平滚动器(Tab 导航、横向内容列表)
|
||
*
|
||
* @param array $args {
|
||
* @type array $items 内容数组
|
||
* @type string $wrapper_class 额外 wrapper 类
|
||
* @type bool $autoplay 是否自动播放
|
||
* @type int $interval 自动播放间隔
|
||
* @type string $render_item 自定义渲染回调 (callable)
|
||
* }
|
||
* @return string HTML
|
||
*/
|
||
function jio_render_scroll_slider(array $args = []): string {
|
||
$defaults = [
|
||
'items' => [],
|
||
'wrapper_class' => '',
|
||
'autoplay' => false,
|
||
'interval' => 4000,
|
||
'render_item' => null,
|
||
];
|
||
|
||
$args = wp_parse_args($args, $defaults);
|
||
$items = $args['items'];
|
||
|
||
if (empty($items)) return '';
|
||
|
||
$data_attrs = ['class="swiper-scroll' . ($args['wrapper_class'] ? ' ' . esc_attr($args['wrapper_class']) : '') . '"'];
|
||
if ($args['autoplay']) {
|
||
$data_attrs[] = 'data-autoplay';
|
||
$data_attrs[] = 'data-interval="' . esc_attr((string) $args['interval']) . '"';
|
||
}
|
||
|
||
$html = '<div ' . implode(' ', $data_attrs) . '>';
|
||
$html .= '<div class="swiper-wrapper">';
|
||
|
||
foreach ($items as $i => $item) {
|
||
$html .= '<div class="swiper-slide">';
|
||
if (is_callable($args['render_item'])) {
|
||
$html .= call_user_func($args['render_item'], $item, $i);
|
||
} else {
|
||
$html .= '<div class="jio-scroll-item">' . esc_html($item['label'] ?? '') . '</div>';
|
||
}
|
||
$html .= '</div>';
|
||
}
|
||
|
||
$html .= '</div>';
|
||
$html .= '<div class="swiper-button-prev"></div>';
|
||
$html .= '<div class="swiper-button-next"></div>';
|
||
$html .= '</div>';
|
||
|
||
return $html;
|
||
}
|