Files
wordpress-theme-aksrt/src/Widgets/WidgetHighlights.php
T
kate522 8c5b1555c9 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).
2026-08-02 22:06:06 +08:00

212 lines
8.2 KiB
PHP
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<?php
/**
* Highlights cards (zibll zib_widget_highlights) with scroll animation + go_link.
*
* @package AKSRT
*/
namespace AKSRT\Widgets;
use AKSRT\Widgets\Traits\CommonWidgetFields;
defined('ABSPATH') || exit;
class WidgetHighlights extends \WP_Widget {
use CommonWidgetFields;
public function __construct() {
parent::__construct(
'aksrt_highlights',
esc_html__('AKSRT 亮点卡片', 'aksrt'),
[
'description' => esc_html__('大中小尺寸亮点/卖点卡片栅格。', 'aksrt'),
'classname' => 'widget_aksrt_highlights',
]
);
}
/**
* @param array<string,mixed> $args
* @param array<string,mixed> $instance
*/
public function widget($args, $instance): void {
$cards = $this->normalize($instance['cards'] ?? []);
if (!$cards) {
if (current_user_can('manage_options')) {
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo function_exists('aksrt_get_widget_null')
? aksrt_get_widget_null(__('请添加至少一张亮点卡片', 'aksrt')) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
: '<p class="widget-empty">' . esc_html__('请添加至少一张亮点卡片', 'aksrt') . '</p>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
return;
}
$go_link = !empty($instance['go_link']);
$anim = sanitize_key((string) ($instance['obs_animation'] ?? 'slideup'));
$anim_repeat = !empty($instance['animation_repeat']);
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$title = apply_filters('widget_title', (string) ($instance['title'] ?? ''), $instance, $this->id_base);
if ($title !== '') {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
$large = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'large'));
$medium = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'medium'));
$small = array_values(array_filter($cards, static fn($c) => ($c['size'] ?? 'medium') === 'small'));
if (!$large && !$medium && !$small) {
$medium = $cards;
}
echo '<div class="aksrt-highlights">';
$idx = 0;
foreach (['large' => $large, 'medium' => $medium, 'small' => $small] as $size => $group) {
if (!$group) {
continue;
}
echo '<div class="aksrt-highlights__row is-' . esc_attr($size) . '">';
foreach ($group as $c) {
$pack = function_exists('aksrt_obs_animate_attrs')
? aksrt_obs_animate_attrs($anim, $anim_repeat, $idx * 0.08)
: ['class' => '', 'attr' => ''];
echo $this->card($c, $size, $go_link, $pack); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
$idx++;
}
echo '</div>';
}
echo '</div>';
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
/**
* @param array<string,mixed> $c
* @param array{class:string,attr:string} $pack
*/
private function card(array $c, string $size, bool $go_link, array $pack): string {
$color = sanitize_key((string) ($c['color'] ?? 'blue'));
if (!in_array($color, ['blue', 'pink', 'purple', 'green', 'orange', 'cyan'], true)) {
$color = 'blue';
}
$url = (string) ($c['url'] ?? '');
if ($url !== '' && $go_link && function_exists('aksrt_go_link')) {
$url = aksrt_go_link($url, true);
}
$tag = $url !== '' ? 'a' : 'div';
$href = $url !== '' ? ' href="' . esc_url($url) . '"' : '';
$img = (string) ($c['image'] ?? '');
$cls = 'aksrt-hl-card size-' . esc_attr($size) . ' color-' . esc_attr($color) . $pack['class'];
$html = '<' . $tag . ' class="' . esc_attr(trim($cls)) . '"' . $href . $pack['attr'] . '>';
if ($img !== '') {
$placeholder = get_template_directory_uri() . '/assets/img/placeholder.svg';
$html .= '<div class="aksrt-hl-card__media"><img class="fit-cover aksrt-lazy lazyload" data-src="' . esc_url($img) . '" src="' . esc_url($placeholder) . '" alt="" loading="lazy" /></div>';
}
$html .= '<div class="aksrt-hl-card__body">';
if (!empty($c['icon'])) {
$html .= '<div class="aksrt-hl-card__icon"><i class="' . esc_attr((string) $c['icon']) . '" aria-hidden="true"></i></div>';
}
if ($c['title'] !== '') {
$html .= '<div class="aksrt-hl-card__title">' . esc_html($c['title']) . '</div>';
}
if ($c['desc'] !== '') {
$html .= '<div class="aksrt-hl-card__desc">' . esc_html($c['desc']) . '</div>';
}
$html .= '</div></' . $tag . '>';
return $html;
}
/**
* @param mixed $raw
* @return array<int, array<string,mixed>>
*/
private function normalize($raw): array {
if (is_string($raw)) {
$decoded = json_decode($raw, true);
$raw = is_array($decoded) ? $decoded : [];
}
if (!is_array($raw)) {
return [];
}
$out = [];
foreach ($raw as $row) {
if (!is_array($row)) {
continue;
}
$title = sanitize_text_field((string) ($row['title'] ?? ''));
$desc = sanitize_text_field((string) ($row['desc'] ?? ''));
if ($title === '' && $desc === '') {
continue;
}
$size = sanitize_key((string) ($row['size'] ?? 'medium'));
if (!in_array($size, ['large', 'medium', 'small'], true)) {
$size = 'medium';
}
$out[] = [
'title' => $title,
'desc' => $desc,
'icon' => sanitize_text_field((string) ($row['icon'] ?? '')),
'image' => esc_url_raw(trim((string) ($row['image'] ?? ''))),
'url' => esc_url_raw(trim((string) ($row['url'] ?? ''))),
'color' => sanitize_key((string) ($row['color'] ?? 'blue')),
'size' => $size,
];
if (count($out) >= 12) {
break;
}
}
return $out;
}
/**
* @param array<string,mixed> $instance
*/
public function form($instance): void {
$json = is_string($instance['cards'] ?? null)
? (string) $instance['cards']
: wp_json_encode($this->normalize($instance['cards'] ?? []), JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
?>
<p>
<label><?php esc_html_e('标题', 'aksrt'); ?>
<input class="widefat" type="text" name="<?php echo esc_attr($this->get_field_name('title')); ?>" value="<?php echo esc_attr((string) ($instance['title'] ?? '')); ?>">
</label>
</p>
<p>
<label><?php esc_html_e('卡片 JSON', 'aksrt'); ?>
<textarea class="widefat" rows="8" name="<?php echo esc_attr($this->get_field_name('cards')); ?>" placeholder='[{"title":"高速","desc":"…","size":"large","color":"blue","icon":"fas fa-bolt"}]'><?php echo esc_textarea((string) $json); ?></textarea>
</label>
<small><?php esc_html_e('size: large|medium|small;color: blue/pink/…', 'aksrt'); ?></small>
</p>
<p>
<label><?php esc_html_e('入场动画', 'aksrt'); ?>
<select name="<?php echo esc_attr($this->get_field_name('obs_animation')); ?>">
<option value="" <?php selected(($instance['obs_animation'] ?? 'slideup'), ''); ?>><?php esc_html_e('无', 'aksrt'); ?></option>
<option value="fade" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'fade'); ?>><?php esc_html_e('淡入', 'aksrt'); ?></option>
<option value="slideup" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'slideup'); ?>><?php esc_html_e('上滑', 'aksrt'); ?></option>
<option value="zoomin" <?php selected(($instance['obs_animation'] ?? 'slideup'), 'zoomin'); ?>><?php esc_html_e('放大', 'aksrt'); ?></option>
</select>
</label>
</p>
<p>
<label><input type="checkbox" name="<?php echo esc_attr($this->get_field_name('go_link')); ?>" value="1" <?php checked(!empty($instance['go_link'])); ?>> <?php esc_html_e('外链跳转页', 'aksrt'); ?></label>
</p>
<?php
$this->render_common_form_section($instance);
}
/**
* @param array<string,mixed> $new_instance
* @param array<string,mixed> $old_instance
* @return array<string,mixed>
*/
public function update($new_instance, $old_instance): array {
$business = [
'title' => sanitize_text_field((string) ($new_instance['title'] ?? '')),
'cards' => $this->normalize($new_instance['cards'] ?? []),
'go_link' => !empty($new_instance['go_link']) ? 1 : 0,
'obs_animation' => sanitize_key((string) ($new_instance['obs_animation'] ?? 'slideup')),
'animation_repeat' => !empty($new_instance['animation_repeat']) ? 1 : 0,
]; return $this->update_common_fields($new_instance, $old_instance, $business);
}
}