Files
wordpress-theme-aksrt/inc/helpers/jio-yiyan.php
T
kate522andClaude Opus 5 f80ca1e27d fix(widgets): restore single-card reference UI for search and quote widgets
The 搜索框 and 一言 sidebar widgets fell into the generic renderer branch, so
they rendered a .jio-panel card wrapping a second bespoke card
(.jio-widget-search / .jio-widget-quote). In-article 一言 also used
divergent modifier classes and an extra hover rule.

- search: render through the shared jio_get_search_box() (legacy keyword,
  history and category pickers) inside one reference card, mirroring the
  reference widget's markup and title default 「搜索」
- quote: render the reference .yiyan-box card itself as the click root; the
  shell now emits only the reference widget-container/title wrapper
- article 一言: adopt the reference class lists for header, footer and the
  standalone after-article box; drop the invented yiyan--* modifiers and
  the duplicate hover/opacity rules
- client: fill .cn/.en in the reference order (first line .cn, second .en)
  and drop the stale window.JioYiyan bridge plus the dead qv-yiyan.php AJAX
  path in runtime main.js
- schema: replace the ad-hoc search_style radio with the reference switches
  (keywords, history, input category, more_cats) and default title
- assets: enqueue assets/js/yiyan.js through the quote widget's asset list

Tests: widget-system suite 820/821 (the one failure is the pre-existing
frontend-lifecycle theme-init stub); new search/quote card contracts pass.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-11-03 15:56:52 +08:00

77 lines
2.6 KiB
PHP

<?php
/**
* 一言 (Hitokoto) markup helper.
*
* Shared shell for single-post placements and the yiyan widget.
*
* @package Jio
*/
defined('ABSPATH') || exit;
add_action('wp_ajax_jio_yiyan', 'jio_ajax_yiyan');
add_action('wp_ajax_nopriv_jio_yiyan', 'jio_ajax_yiyan');
if (!function_exists('jio_ajax_yiyan')) :
/** Return one random Chinese/English pair from the theme quote file. */
function jio_ajax_yiyan(): void {
$custom_file = WP_CONTENT_DIR . '/yiyan.txt';
$theme_file = get_template_directory() . '/yiyan/qv-yiyan.txt';
$file = is_readable($custom_file) ? $custom_file : $theme_file;
$lines = is_readable($file) ? file($file, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES) : false;
$pairs = [];
if (is_array($lines)) {
// The first line is the reference file's title; the rest alternate EN/CN.
array_shift($lines);
$lines = array_values(array_map('trim', $lines));
for ($i = 0, $length = count($lines); $i + 1 < $length; $i += 2) {
if ($lines[$i] !== '' && $lines[$i + 1] !== '') {
$pairs[] = ['en' => $lines[$i], 'cn' => $lines[$i + 1]];
}
}
}
if (!$pairs) {
wp_send_json_error(['message' => __('一言内容暂不可用', 'jio')], 503);
}
wp_send_json_success($pairs[array_rand($pairs)]);
}
endif;
if (!function_exists('jio_render_yiyan_block')) :
/**
* Shared 一言 shell for single-post placements (and reusable markup).
*
* Reads bilingual pairs from the bundled reference file and supports the
* same optional wp-content/yiyan.txt override used by the reference theme.
*
* @param array<string,mixed> $args {
* @type string $class Extra CSS classes on the root.
* }
*/
function jio_render_yiyan_block(array $args = []): void {
echo jio_get_yiyan_markup($args); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Escaped by the markup helper.
}
function jio_get_yiyan_markup(array $args = []): string {
$class = trim((string) ($args['class'] ?? 'jio-yiyan'));
if (strpos($class, 'jio-yiyan') === false) {
$class = trim($class . ' jio-yiyan');
}
// 与参考结构一致:.yiyan 初始为空,由脚本写入 .cn(首行)与 .en(次行)。
$html = '<div class="' . esc_attr($class) . '"'
. ' data-jio-yiyan'
. ' data-endpoint="' . esc_url(admin_url('admin-ajax.php')) . '"'
. ' data-toggle="tooltip"'
. ' title="' . esc_attr__('点击切换一言', 'jio') . '"'
. ' role="button" tabindex="0"'
. ' aria-label="' . esc_attr__('点击切换一言', 'jio') . '"'
. ' aria-live="polite">'
. '<div class="yiyan"></div>'
. '</div>';
return $html;
}
endif;