Files
wordpress-theme-aksrt/inc/classes/widgets/class-aksrt-yiyan-widget.php
T
kate522 6bd7676b73 fix(yiyan): stop invalid Hitokoto category requests
Public hitokoto v1 rejects c=hitokoto (and ignores batch count). Whitelist
categories a–l, multi-fetch for carousel, and share full markup via
aksrt_render_yiyan_block so single-post shells actually render quotes.
2026-07-17 10:33:00 +08:00

154 lines
6.0 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
/**
* AKSRT Yiyan Widget — 一言轮播组件
*
* Fetches random quotes from hitokoto.cn API and displays with auto-rotation.
* Category values map to Hitokoto `c` letters a–l; empty = mixed random.
*
* @package AKSRT
*/
defined('ABSPATH') || exit;
class AKSRT_Widget_Yiyan extends WP_Widget {
/**
* Hitokoto category codes → labels (API `c` param).
*
* @return array<string,string>
*/
private static function type_labels(): array {
return [
'' => __('随机', 'aksrt'),
'a' => __('动画', 'aksrt'),
'b' => __('漫画', 'aksrt'),
'c' => __('游戏', 'aksrt'),
'd' => __('文学', 'aksrt'),
'e' => __('原创', 'aksrt'),
'f' => __('来自网络', 'aksrt'),
'g' => __('其他', 'aksrt'),
'h' => __('影视', 'aksrt'),
'i' => __('诗词', 'aksrt'),
'j' => __('网易云', 'aksrt'),
'k' => __('哲学', 'aksrt'),
'l' => __('抖机灵', 'aksrt'),
];
}
/**
* Sanitize stored type to a valid Hitokoto category letter or empty.
*/
private static function sanitize_type(string $type): string {
$type = strtolower(trim($type));
return preg_match('/^[a-l]$/', $type) ? $type : '';
}
public function __construct() {
parent::__construct(
'aksrt_yiyan',
__('一言轮播', 'aksrt'),
['description' => __('显示随机一言/每日语录,支持自动轮播。', 'aksrt')]
);
}
public function widget($args, $instance): void {
$title = !empty($instance['title']) ? $instance['title'] : '';
$count = !empty($instance['count']) ? max(1, min(10, (int) $instance['count'])) : 5;
$interval = !empty($instance['interval']) ? max(3, min(30, (int) $instance['interval'])) : 5;
$type = self::sanitize_type((string) ($instance['type'] ?? ''));
$icon = !empty($instance['icon']) ? $instance['icon'] : 'fas fa-quote-left';
echo $args['before_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
if ($title) {
echo $args['before_title'] . esc_html($title) . $args['after_title']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
if (function_exists('aksrt_render_yiyan_block')) {
aksrt_render_yiyan_block([
'class' => 'aksrt-yiyan',
'type' => $type,
'count' => $count,
'interval' => $interval,
'icon' => $icon,
]);
} else {
// Fallback if single-render helpers are not loaded.
?>
<div class="aksrt-yiyan"
data-aksrt-yiyan
data-count="<?php echo esc_attr((string) $count); ?>"
data-interval="<?php echo esc_attr((string) $interval); ?>"
<?php echo $type !== '' ? ' data-type="' . esc_attr($type) . '"' : ''; ?>>
<div class="aksrt-yiyan__content">
<i class="<?php echo esc_attr($icon); ?> aksrt-yiyan__icon" aria-hidden="true"></i>
<p class="aksrt-yiyan__text"><?php esc_html_e('加载中…', 'aksrt'); ?></p>
<p class="aksrt-yiyan__from"></p>
</div>
<div class="aksrt-yiyan__dots" aria-hidden="true"></div>
</div>
<?php
}
echo $args['after_widget']; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
}
public function form($instance): void {
$title = !empty($instance['title']) ? $instance['title'] : '一言';
$count = !empty($instance['count']) ? (int) $instance['count'] : 5;
$interval = !empty($instance['interval']) ? (int) $instance['interval'] : 5;
$type = self::sanitize_type((string) ($instance['type'] ?? ''));
$icon = !empty($instance['icon']) ? $instance['icon'] : 'fas fa-quote-left';
$labels = self::type_labels();
// Curated subset for the form (full map still used for sanitization).
$form_types = ['', 'a', 'd', 'i', 'k', 'h', 'j'];
?>
<p>
<label for="<?php echo esc_attr($this->get_field_id('title')); ?>"><?php esc_html_e('标题', 'aksrt'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('title')); ?>"
name="<?php echo esc_attr($this->get_field_name('title')); ?>" type="text"
value="<?php echo esc_attr($title); ?>">
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('count')); ?>"><?php esc_html_e('轮播条数', 'aksrt'); ?></label>
<input id="<?php echo esc_attr($this->get_field_id('count')); ?>"
name="<?php echo esc_attr($this->get_field_name('count')); ?>" type="number"
min="1" max="10" value="<?php echo esc_attr((string) $count); ?>" style="width:80px;">
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('interval')); ?>"><?php esc_html_e('切换间隔(秒)', 'aksrt'); ?></label>
<input id="<?php echo esc_attr($this->get_field_id('interval')); ?>"
name="<?php echo esc_attr($this->get_field_name('interval')); ?>" type="number"
min="3" max="30" value="<?php echo esc_attr((string) $interval); ?>" style="width:80px;">
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('type')); ?>"><?php esc_html_e('分类', 'aksrt'); ?></label>
<select id="<?php echo esc_attr($this->get_field_id('type')); ?>"
name="<?php echo esc_attr($this->get_field_name('type')); ?>">
<?php foreach ($form_types as $code) : ?>
<option value="<?php echo esc_attr($code); ?>" <?php selected($type, $code); ?>>
<?php echo esc_html($labels[$code] ?? $code); ?>
</option>
<?php endforeach; ?>
</select>
</p>
<p>
<label for="<?php echo esc_attr($this->get_field_id('icon')); ?>"><?php esc_html_e('图标', 'aksrt'); ?></label>
<input class="widefat" id="<?php echo esc_attr($this->get_field_id('icon')); ?>"
name="<?php echo esc_attr($this->get_field_name('icon')); ?>" type="text"
value="<?php echo esc_attr($icon); ?>">
</p>
<?php
}
public function update($new_instance, $old_instance): array {
$instance = [];
$instance['title'] = sanitize_text_field($new_instance['title'] ?? '');
$instance['count'] = max(1, min(10, absint($new_instance['count'] ?? 5)));
$instance['interval'] = max(3, min(30, absint($new_instance['interval'] ?? 5)));
$instance['type'] = self::sanitize_type((string) ($new_instance['type'] ?? ''));
$instance['icon'] = sanitize_text_field($new_instance['icon'] ?? 'fas fa-quote-left');
return $instance;
}
}