Files
wordpress-theme-aksrt/src/WidgetSystem/Renderers/GeneralRenderer.php
T

298 lines
17 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
namespace AKSRT\WidgetSystem\Renderers;
use AKSRT\WidgetSystem\RendererHelpers;
use AKSRT\WidgetSystem\PostQuery;
defined('ABSPATH') || exit;
/** Render the 17 general and decorative widgets. */
final class GeneralRenderer {
public static function render(string $slug, array $instance, array $context = []): string {
$method = 'render_' . $slug;
return is_callable([self::class, $method]) ? (string) self::$method($instance, $context) : '';
}
private static function render_search(array $i): string {
$action = esc_url(home_url('/'));
$placeholder = esc_attr((string) $i['placeholder']);
$style = sanitize_html_class((string) $i['search_style']);
return '<form class="aksrt-widget-search aksrt-widget-search--' . $style . '" role="search" method="get" action="' . $action . '"><label><span class="screen-reader-text">' . esc_html__('搜索:', 'aksrt') . '</span><input type="search" name="s" placeholder="' . $placeholder . '" autocomplete="off"></label><button type="submit" aria-label="' . esc_attr__('搜索', 'aksrt') . '"><i class="fa fas fa-search" aria-hidden="true"></i><span>' . esc_html__('搜索', 'aksrt') . '</span></button></form>';
}
private static function render_posts_toc(array $i): string {
if (!is_singular('post')) {
return '';
}
return '<nav class="aksrt-widget-toc' . (!empty($i['collapsed']) ? ' is-collapsed' : '') . '" data-min-headings="' . (int) $i['min_headings'] . '" data-scroll-offset="' . (int) $i['offset'] . '" aria-label="' . esc_attr__('文章目录', 'aksrt') . '"><button class="aksrt-widget-toc__toggle" type="button" aria-expanded="' . (empty($i['collapsed']) ? 'true' : 'false') . '"><span>' . esc_html__('文章目录', 'aksrt') . '</span><i class="fa fas fa-chevron-down" aria-hidden="true"></i></button><ol class="aksrt-widget-toc__list"></ol><p class="aksrt-widget-toc__empty">' . esc_html__('正在生成目录…', 'aksrt') . '</p></nav>';
}
private static function render_quote(array $i): string {
$quotes = RendererHelpers::lines((string) $i['quotes']);
$text = $quotes ? $quotes[array_rand($quotes)] : __('保持好奇,持续创造。', 'aksrt');
return '<figure class="aksrt-widget-quote" data-source="' . esc_attr((string) $i['source']) . '" data-interval="' . (int) $i['interval'] . '"><i class="fa fas fa-quote-left" aria-hidden="true"></i><blockquote>' . esc_html($text) . '</blockquote><button type="button" aria-label="' . esc_attr__('换一句', 'aksrt') . '"><i class="fa fas fa-sync-alt" aria-hidden="true"></i></button></figure>';
}
private static function render_icon_cards(array $i): string {
return self::icon_cards($i, false);
}
private static function render_icon_cover_cards(array $i): string {
return self::icon_cards($i, true);
}
private static function icon_cards(array $instance, bool $cover): string {
$pc = max(1, (int) ($instance['pc_row'] ?? 4));
$mobile = max(1, (int) ($instance['m_row'] ?? 2));
$cards = (array) ($instance['cards'] ?? []);
$is_row = count($cards) > 1;
$row_class = 'col-sm-' . max(1, (int) (12 / $pc));
if ($mobile > 1) $row_class .= ' col-xs-' . max(1, (int) (12 / $mobile));
$items = '';
foreach ($cards as $card) {
if (!is_array($card)) {
continue;
}
$icon_size = !$cover && !empty($instance['size']) ? 16 + (int) $instance['size'] : ($cover ? 25 : 0);
$class = $cover ? (!empty($instance['show_widget_bg']) ? 'padding-10' : 'zib-widget mb10') : (!empty($instance['show_widget_bg']) ? 'box-body nopw-sm' : 'mb20');
$args = [
'icon' => $card['icon'] ?? '',
'customize_icon' => $card['customize_icon'] ?? '',
'icon_size' => $icon_size,
'icon_radius' => !empty($card['icon_radius']) || ($cover && !empty($instance['icon_radius4'])),
'icon_color' => $card['icon_color'] ?? '',
'icon_custom_color' => $card['icon_custom_color'] ?? '',
'icon_class' => $card['icon_class'] ?? '',
'title' => $card['title'] ?? '',
'desc' => $card['desc'] ?? '',
'link' => $card['link'] ?? [],
'class' => $class,
];
$item = '';
if ($cover && function_exists('aksrt_icon_cover_card')) {
$item = aksrt_icon_cover_card($args);
} elseif (!$cover && function_exists('aksrt_icon_card')) {
$item = aksrt_icon_card($args);
} else {
$item = '';
}
$items .= $is_row ? '<div class="' . esc_attr($row_class) . '">' . $item . '</div>' : $item;
}
if ($items === '') return '';
$inner = $is_row ? '<div class="row gutters-5">' . $items . '</div>' : $items;
if ($cover) return '<div class="' . ($instance['show_widget_bg'] ?? false ? 'zib-widget padding-10' : 'mb10') . '">' . $inner . '</div>';
return '<div class="clearfix">' . (!empty($instance['show_widget_bg']) ? '<div class="zib-widget nobottom notop">' : '') . $inner . (!empty($instance['show_widget_bg']) ? '</div>' : '') . '</div>';
}
private static function render_video(array $i): string {
$url = esc_url((string) $i['url']);
if ($url === '') {
return RendererHelpers::empty_state(__('请配置视频地址', 'aksrt'));
}
$ratio = (string) $i['ratio'];
if (aksrt_is_lazy('lazy_other')) {
$video_attr = ' class="lazyload" src="" data-src="' . $url . '"';
$poster_attr = !empty($i['poster']) ? ' data-poster="' . esc_url((string) $i['poster']) . '"' : '';
} else {
$video_attr = ' src="' . $url . '"';
$poster_attr = !empty($i['poster']) ? ' poster="' . esc_url((string) $i['poster']) . '"' : '';
}
return '<div class="aksrt-widget-video aksrt-widget-video--' . esc_attr(str_replace(':', '-', $ratio)) . '" data-video-url="' . $url . '" data-video-poster="' . esc_url((string) $i['poster']) . '" data-autoplay="' . (!empty($i['autoplay']) ? '1' : '0') . '" data-muted="' . (!empty($i['muted']) ? '1' : '0') . '"><video controls playsinline preload="metadata"' . $video_attr . $poster_attr . (!empty($i['autoplay']) ? ' autoplay' : '') . (!empty($i['muted']) ? ' muted' : '') . '></video><p class="aksrt-widget-media-error" role="alert" aria-live="assertive" hidden>' . esc_html__('视频加载失败,请稍后重试。', 'aksrt') . '</p></div>';
}
private static function render_embed(array $i): string {
if (empty($i['url'])) {
return RendererHelpers::empty_state(__('请配置嵌入地址', 'aksrt'));
}
$src_attr = aksrt_is_lazy('lazy_other')
? ' class="lazyload" src="" data-src="' . esc_url((string) $i['url']) . '"'
: ' src="' . esc_url((string) $i['url']) . '"';
return '<div class="aksrt-widget-embed" style="--aksrt-embed-ratio:' . esc_attr((string) (float) $i['ratio']) . '%"><iframe' . $src_attr . ' referrerpolicy="strict-origin-when-cross-origin"' . (!empty($i['allow_fullscreen']) ? ' allowfullscreen' : '') . ' title="' . esc_attr__('嵌入内容', 'aksrt') . '"></iframe></div>';
}
private static function render_media_cards(array $i): string {
return self::media_grid((array) $i['cards']);
}
private static function media_grid(array $items, string $class = ''): string {
$html = '<div class="aksrt-widget-grid aksrt-widget-media-cards ' . esc_attr($class) . '">';
foreach ($items as $item) {
if (is_array($item)) {
$html .= RendererHelpers::card_media($item);
}
}
return $html . '</div>';
}
private static function render_partners(array $i): string {
$items = '';
foreach ((array) $i['items'] as $item) {
if (is_array($item)) {
$items .= RendererHelpers::card_media($item, 'aksrt-partner');
}
}
return '<div class="aksrt-widget-partners" style="--aksrt-partner-rows:' . (int) $i['rows_pc'] . ';--aksrt-partner-rows-m:' . (int) $i['rows_mobile'] . ';--aksrt-partner-speed:' . (int) $i['speed'] . 's"><div class="aksrt-widget-partners__track">' . $items . $items . '</div></div>';
}
private static function render_combo_info(array $i): string {
$html = '<div class="aksrt-widget-grid aksrt-widget-combo">';
foreach ((array) $i['items'] as $item) {
if (!is_array($item)) {
continue;
}
$tags = '';
foreach (preg_split('/\s*[,,]\s*/', (string) ($item['tags'] ?? '')) ?: [] as $tag) {
if ($tag !== '') {
$tags .= '<span>' . esc_html($tag) . '</span>';
}
}
$html .= '<article class="aksrt-combo-card">' . RendererHelpers::card_media($item) . ($tags ? '<div class="aksrt-combo-card__tags">' . $tags . '</div>' : '') . '</article>';
}
return $html . '</div>';
}
private static function render_text_title(array $i): string {
return '<div class="aksrt-widget-text-title is-' . esc_attr((string) $i['alignment']) . '"><h2>' . nl2br(esc_html((string) $i['heading'])) . '</h2><p>' . nl2br(esc_html((string) $i['description'])) . '</p></div>';
}
private static function render_buttons(array $i): string {
$padding_pc = in_array((string) ($i['pc_padding'] ?? 'large'), ['small', 'medium', 'large'], true) ? (string) $i['pc_padding'] : 'large';
$padding_m = in_array((string) ($i['m_padding'] ?? 'medium'), ['small', 'medium', 'large'], true) ? (string) $i['m_padding'] : 'medium';
$align = in_array((string) ($i['align'] ?? 'center'), ['left', 'center', 'right'], true) ? (string) $i['align'] : 'center';
$style = '';
foreach (['pc_width' => '--pc-width', 'm_width' => '--m-width', 'pc_gap' => '--pc-gap', 'm_gap' => '--m-gap'] as $key => $property) {
if (!empty($i[$key]) && is_numeric($i[$key])) $style .= $property . ':' . (float) $i[$key] . 'px;';
}
$button_class = 'but' . (!empty($i['radius']) ? ' radius' : '') . (!empty($i['hollow']) ? ' hollow' : '');
$buttons = '';
foreach ((array) ($i['items'] ?? []) as $index => $item) {
if (!is_array($item) || trim((string) ($item['text'] ?? '')) === '') continue;
$link = RendererHelpers::link((array) ($item['link'] ?? []));
$url = $link['url'] !== '' ? $link['url'] : 'javascript:void(0)';
if (!empty($i['go_link']) && $link['url'] !== '' && function_exists('aksrt_go_link')) $url = esc_url(aksrt_go_link($link['url'], true));
$target = $link['target'] === '_blank' ? ' target="_blank" rel="noopener noreferrer"' : '';
$color = sanitize_html_class((string) ($item['color'] ?? ''));
$item_class = trim($button_class . ' ' . $color);
$icon_left = !empty($item['icon_left']) ? self::icon_markup((string) $item['icon_left']) : '';
$icon_right = !empty($item['icon_right']) ? '<span class="ml6">' . self::icon_markup((string) $item['icon_right']) . '</span>' : '';
$animation = '';
$attr = '';
if (!empty($i['obs_animation'])) {
$animation = ' obs-animate ani-' . sanitize_html_class((string) $i['obs_animation']);
$attr = ' data-animation="' . esc_attr((string) $i['obs_animation']) . '" style="--delay:' . (float) $index * 0.15 . 's;"' . (!empty($i['animation_repeat']) ? ' data-animation-repeat="true"' : '');
}
$buttons .= '<div class="' . trim($animation) . '"' . $attr . '><a class="' . esc_attr($item_class) . '" href="' . $url . '"' . $target . '>' . $icon_left . wp_kses_post((string) $item['text']) . $icon_right . '</a></div>';
}
if ($buttons === '') return '';
return '<div class="widget-buttons mb20 pc-size-' . esc_attr($padding_pc) . ' m-size-' . esc_attr($padding_m) . '"><div class="widget-buttons-wrap flex hh align-' . esc_attr($align) . '" style="' . esc_attr($style) . '">' . $buttons . '</div></div>';
}
private static function render_layout_gap(array $i): string {
return '<div class="aksrt-widget-gap" aria-hidden="true" style="--aksrt-gap:' . (float) $i['pc_gap'] . 'px;--aksrt-gap-m:' . (float) $i['m_gap'] . 'px"></div>';
}
private static function render_tag_cloud(array $i): string {
$args = ['taxonomy' => (string) $i['taxonomy'], 'number' => (int) $i['number'], 'hide_empty' => true];
if ($i['orderby'] !== 'rand') {
$args['orderby'] = (string) $i['orderby'];
$args['order'] = 'DESC';
}
$terms = get_terms($args);
if (is_wp_error($terms) || !$terms) {
return RendererHelpers::empty_state(__('暂无标签', 'aksrt'));
}
if ($i['orderby'] === 'rand') {
shuffle($terms);
}
$html = '<div class="aksrt-widget-tag-cloud">';
foreach (array_slice($terms, 0, (int) $i['number']) as $term) {
$url = get_term_link($term);
if (!is_wp_error($url)) {
$html .= '<a href="' . esc_url($url) . '">' . esc_html($term->name) . (!empty($i['show_count']) ? '<small>' . (int) $term->count . '</small>' : '') . '</a>';
}
}
return $html . '</div>';
}
private static function render_recent_comments(array $i): string {
$comments = get_comments(['status' => 'approve', 'number' => (int) $i['count'], 'user__not_in' => RendererHelpers::ids((string) $i['exclude_users']), 'post__not_in' => RendererHelpers::ids((string) $i['exclude_posts'])]);
if (!$comments) {
return RendererHelpers::empty_state(__('暂无评论', 'aksrt'));
}
$html = '<ul class="aksrt-widget-comments">';
foreach ($comments as $comment) {
$html .= '<li><a class="aksrt-widget-comments__avatar" href="' . esc_url(get_comment_link($comment)) . '">' . (function_exists('aksrt_get_avatar_html') ? aksrt_get_avatar_html($comment, 48) : get_avatar($comment, 48)) . '</a><div><strong>' . esc_html(get_comment_author($comment)) . '</strong><p>' . esc_html(wp_trim_words(wp_strip_all_tags((string) $comment->comment_content), 18)) . '</p>' . (!empty($i['show_source']) ? '<a class="aksrt-widget-comments__source" href="' . esc_url(get_comment_link($comment)) . '">' . esc_html(get_the_title((int) $comment->comment_post_ID)) . '</a>' : '') . '</div></li>';
}
return $html . '</ul>';
}
private static function render_links(array $i): string {
$html = '<div class="aksrt-widget-links aksrt-widget-links--' . esc_attr((string) $i['style']) . '">';
foreach (array_slice((array) $i['links'], 0, (int) $i['limit']) as $item) {
$link = RendererHelpers::link((array) ($item['link'] ?? []));
if ($link['url']) {
$html .= '<a href="' . $link['url'] . '"' . RendererHelpers::link_attrs($link) . '><strong>' . esc_html((string) ($item['title'] ?? $link['text'])) . '</strong><small>' . esc_html((string) ($item['description'] ?? '')) . '</small></a>';
}
}
return $html . '</div>';
}
private static function render_notice(array $i): string {
$source = (string) ($i['source'] ?? '');
$lists = (array) ($i['img_ids'] ?? []);
$posts_query = false;
if ($source === 'posts' && class_exists(PostQuery::class)) {
$query_args = array_merge((array) ($i['posts_opts'] ?? []), ['count' => (int) ($i['count'] ?? 8), 'paginate' => '']);
$posts_query = PostQuery::build($query_args, 1);
$lists = [];
if ($posts_query && method_exists($posts_query, 'have_posts')) {
while ($posts_query->have_posts()) {
$posts_query->the_post();
$subtitle = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value(get_the_ID(), 'subtitle', '') : '';
$title = trim(wp_strip_all_tags(get_the_title())) . trim(wp_strip_all_tags((string) $subtitle));
if (!empty($i['desc_s'])) {
$description = class_exists('AKSRT\\Core\\PostMetaBox') ? \AKSRT\Core\PostMetaBox::get_meta_value(get_the_ID(), 'description', '') : '';
if (trim((string) $description) === '') $description = get_the_excerpt();
$title .= ': ' . wp_html_excerpt(wp_strip_all_tags((string) $description), 160, '...');
}
$lists[] = ['title' => $title, 'href' => get_permalink()];
}
wp_reset_postdata();
}
}
$msg_icon = ($posts_query && !empty($i['msg_icon'])) ? self::notice_icon((string) $i['msg_icon']) : '';
$slides = '';
$blank = !empty($i['blank']) ? ' target="_blank" rel="noopener noreferrer"' : '';
foreach ($lists as $notice) {
if (!is_array($notice) || trim((string) ($notice['title'] ?? '')) === '') continue;
$href = !empty($notice['href']) ? esc_url((string) $notice['href']) : 'javascript:void(0);';
$icon = !empty($notice['icon']) ? self::notice_icon((string) $notice['icon']) : '';
$title = wp_kses_post((string) ($notice['title'] ?? ''));
$slides .= '<div class="swiper-slide notice-slide"><a class="flex ac"' . $blank . ' href="' . $href . '">' . $icon . '<span class="ml6 text-ellipsis"><span class="">' . $title . '</span></span></a></div>';
}
$class = 'swiper-bulletin mb20 ' . sanitize_html_class((string) ($i['color'] ?? 'c-blue')) . (!empty($i['radius']) ? ' radius' : ' main-radius') . ($posts_query ? ' has-posts flex ac' : '');
$html = '<div class="new-swiper" data-interval="' . ((int) ($i['interval'] ?? 3) * 1000) . '" data-direction="vertical" data-loop="true" data-autoplay="1"><div class="swiper-wrapper">' . $slides . '</div></div>';
return '<div class="' . esc_attr($class) . '">' . $msg_icon . $html . '</div>';
}
private static function notice_icon(string $icon): string {
return '<span class="relative bulletin-icon flex jc shrink0">' . self::icon_markup($icon) . '</span>';
}
private static function icon_markup(string $icon): string {
$icon = trim($icon);
if ($icon === '') return '';
if (str_starts_with($icon, 'customsvg-')) {
return wp_kses(substr($icon, 10), [
'svg' => ['class' => true, 'viewbox' => true, 'viewBox' => true, 'width' => true, 'height' => true, 'fill' => true, 'xmlns' => true, 'aria-hidden' => true],
'use' => ['href' => true, 'xlink:href' => true],
'path' => ['d' => true, 'fill' => true, 'stroke' => true, 'stroke-width' => true],
]);
}
if (str_starts_with($icon, 'zibsvg-')) return '<svg class="icon" aria-hidden="true"><use xlink:href="#icon-' . esc_attr(substr($icon, 7)) . '"></use></svg>';
if (!str_contains($icon, 'fa ') && str_contains($icon, 'fa-')) $icon = 'fa ' . $icon;
return '<i class="' . esc_attr($icon) . '" aria-hidden="true"></i>';
}
}