$data Collected post data. * @param array $cfg Renderer config. * @return string */ function aksrt_renderer_list(array $data, array $cfg): string { $classes = ['posts-item', 'list', 'ajax-item', 'flex', 'posts-item--' . ($cfg['card_style'] ?: 'standard')]; if ($cfg['style'] !== '' && $cfg['style'] !== 'default') { $classes[] = $cfg['style']; } if ($cfg['style'] === 'style2') { $classes[] = 'xx'; } if (!empty($data['is_mult_thumb'])) { $classes[] = 'mult-thumb'; } if ($cfg['context'] === 'home') { $classes[] = 'posts-item--home-list'; } if (empty($data['has_img'])) { $classes[] = 'no-thumb'; } if (($cfg['list_show_type'] ?? 'separate') === 'no_margin') { $classes[] = 'no-margin'; $classes[] = 'no_margin'; } $thumb = aksrt_renderer_thumb($data, $cfg); $mult = aksrt_renderer_mult_thumb($data); if (!empty($data['is_mult_thumb'])) { // Zibll's multi-image mode replaces the primary graphic; both must // never be emitted for the same list item. $thumb = ''; } if ($cfg['card_style'] === 'text' || ($cfg['card_style'] === 'thumb_if_has' && empty($data['has_img']))) { $thumb = ''; $mult = ''; $classes[] = 'no-thumb'; $classes[] = 'posts-item--text'; } $title_markup = aksrt_renderer_title_markup($data, $cfg); $excerpt_markup = aksrt_renderer_excerpt_markup($data, $cfg); $badges = aksrt_renderer_badges($data, $cfg); $meta = aksrt_renderer_meta($data, $cfg); $target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : ''; $heading_cls = !empty($cfg['heading_bold']) ? 'item-heading item-heading--bold' : 'item-heading'; $title_html = '

' . $title_markup . '

'; $excerpt_html = $cfg['show_excerpt'] && $excerpt_markup !== '' ? '

' . $excerpt_markup . '

' : ''; $html = '
'; if ($cfg['style'] === 'style2') { $html .= $title_html; $html .= '
'; $html .= $thumb; $html .= '
'; $html .= $mult ?: $excerpt_html; $html .= $badges; $html .= $meta; $html .= '
'; } else { $html .= $thumb; $html .= '
'; $html .= $title_html; $html .= $mult ?: $excerpt_html; $html .= '
' . $badges . $meta . '
'; $html .= '
'; } $html .= '
'; return $html; } } if (!function_exists('aksrt_renderer_card')) { /** * Render a vertical card or CMS resource card. * * @param array $data Collected post data. * @param array $cfg Renderer config. * @return string */ function aksrt_renderer_card(array $data, array $cfg): string { $classes = ['posts-item', 'card', 'ajax-item', 'posts-item--' . ($cfg['card_style'] ?: 'standard')]; if ($cfg['style'] !== '' && $cfg['style'] !== 'default') { $classes[] = $cfg['style']; } if ($cfg['context'] === 'home') { $classes[] = 'posts-item--home'; } if ($cfg['mode'] === 'grid-cms') { $classes[] = 'posts-item--cms'; } if (!empty($data['is_mult_thumb'])) { $classes[] = 'mult-thumb'; } if (empty($data['has_img'])) { $classes[] = 'no-thumb'; } $thumb = aksrt_renderer_thumb($data, $cfg); $badges = aksrt_renderer_badges($data, $cfg); $resource_strip = aksrt_renderer_resource_strip($data); $meta = aksrt_renderer_meta($data, $cfg); $title_markup = aksrt_renderer_title_markup($data, $cfg); $html = '
'; $html .= $thumb; $html .= '
'; $target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : ''; $heading_cls = !empty($cfg['heading_bold']) ? 'item-heading item-heading--bold' : 'item-heading'; $html .= '

' . $title_markup . '

'; $html .= $badges; if ($cfg['mode'] === 'grid-cms') { $html .= $resource_strip; } $html .= $meta; $html .= '
'; return $html; } } if (!function_exists('aksrt_renderer_mini')) { /** * Render a compact mini card. * * @param array $data Collected post data. * @param array $cfg Renderer config. * @return string */ function aksrt_renderer_mini(array $data, array $cfg): string { $classes = ['posts-mini']; if (!empty($cfg['extra_class'])) { $classes[] = $cfg['extra_class']; } if (empty($data['has_img'])) { $classes[] = 'posts-mini--no-thumb'; } $number_html = ''; if ($cfg['show_number'] && $cfg['number_offset'] > 0) { $badge_colors = ['c-red', 'c-yellow', 'c-orange', 'c-blue', 'c-green']; $index = $cfg['number_offset'] - 1; $color = $badge_colors[$index] ?? ''; $number_html = '' . (int) $cfg['number_offset'] . ''; } $thumb_html = ''; $target_attr = !empty($cfg['target_blank']) ? ' target="_blank"' : ''; if ($cfg['show_thumb'] && !empty($data['has_img'])) { $fit_class = !empty($cfg['thumb_fit']) && $cfg['thumb_fit'] === 'contain' ? 'fit-contain' : 'fit-cover'; $thumb_attr = aksrt_get_lazy_attr('lazy_posts_thumb', (string) $data['img_url'], $fit_class); $thumb_img = ''; $thumb_html = '' . $thumb_img . ''; } $heading_class = 'item-heading' . (!empty($cfg['heading_bold']) ? ' item-heading--bold' : '') . (!empty($data['has_img']) ? ' text-ellipsis-2' : ' text-ellipsis'); $title_html = '

' . $number_html . '' . aksrt_renderer_title_markup($data, $cfg) . '

'; $html = '
'; $html .= $thumb_html; $html .= '
'; $html .= $title_html; $html .= aksrt_renderer_meta($data, $cfg); $html .= '
'; return $html; } } if (!function_exists('aksrt_render_post')) { /** * Render one post item inside a loop. * * @param array $config Renderer config overrides. * @return string */ function aksrt_render_post(array $config = []): string { $cfg = aksrt_renderer_config($config); $data = aksrt_renderer_collect_post_data($cfg); if (empty($data)) { return ''; } switch ($cfg['mode']) { case 'card': case 'grid-cms': return aksrt_renderer_card($data, $cfg); case 'mini': return aksrt_renderer_mini($data, $cfg); case 'list': default: return aksrt_renderer_list($data, $cfg); } } } if (!function_exists('aksrt_render_post_list')) { /** * Render a query loop with the unified renderer. * * @param WP_Query|null $query Posts query. Falls back to global loop. * @param array $config Renderer config overrides. * @param bool $echo Whether to echo output. * @return string */ function aksrt_render_post_list(?WP_Query $query = null, array $config = [], bool $echo = true): string { $cfg = aksrt_renderer_config($config); $wrapper_classes = ['posts-row', 'ajaxpager']; if ($cfg['context'] === 'home') { $wrapper_classes[] = 'aksrt-homepage__posts'; $wrapper_classes[] = 'post-grid'; $wrapper_classes[] = 'post-grid--home'; } elseif ($cfg['mode'] !== 'mini') { $wrapper_classes[] = 'post-grid'; $wrapper_classes[] = 'post-grid--' . $cfg['mode']; } if (!empty($config['wrapper_class']) && is_string($config['wrapper_class'])) { foreach (preg_split('/\s+/', trim($config['wrapper_class'])) as $extra_class) { $extra_class = sanitize_html_class($extra_class); if ($extra_class !== '') { $wrapper_classes[] = $extra_class; } } } $wrapper_attr = 'class="' . esc_attr(implode(' ', array_unique($wrapper_classes))) . '"'; if ($cfg['columns'] > 1) { $wrapper_attr .= ' style="--aksrt-widget-columns:' . (int) $cfg['columns'] . '"'; } $data_view = in_array($cfg['mode'], ['card', 'grid-cms'], true) ? 'card' : $cfg['mode']; // Homepage panel already provides .posts-row.ajaxpager — allow callers to skip nesting. $skip_wrapper = !empty($config['skip_wrapper']); $html = ''; if ($query instanceof WP_Query) { if (!$query->have_posts()) { $html = '

' . esc_html__('暂无文章', 'aksrt') . '

'; } else { if (!$skip_wrapper) { $html .= '
'; } $number = $cfg['number_offset']; while ($query->have_posts()) { $query->the_post(); if ($cfg['mode'] === 'mini' && $cfg['show_number']) { $number++; $config['number_offset'] = $number; $cfg = aksrt_renderer_config($config); } $html .= aksrt_render_post($cfg); } if (!$skip_wrapper) { $html .= '
'; } } wp_reset_postdata(); } else { if (!have_posts()) { $html = '

' . esc_html__('暂无文章', 'aksrt') . '

'; } else { if (!$skip_wrapper) { $html .= '
'; } while (have_posts()) { the_post(); $html .= aksrt_render_post($cfg); } if (!$skip_wrapper) { $html .= '
'; } } } if ($echo) { echo $html; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped return ''; } return $html; } } if (!function_exists('aksrt_render_mini_list')) { /** * Convenience wrapper for mini lists. * * @param WP_Query $query Posts query. * @param array $config Renderer config overrides. * @param bool $echo Whether to echo output. * @return string */ function aksrt_render_mini_list(WP_Query $query, array $config = [], bool $echo = true): string { $config['mode'] = 'mini'; return aksrt_render_post_list($query, $config, $echo); } } if (!function_exists('aksrt_render_placeholder')) { /** * Render skeleton placeholders for loading states. * * @param string $mode list|card|mini. * @param int $count Number of placeholders. * @return string */ function aksrt_render_placeholder(string $mode = 'list', int $count = 3): string { $count = max(1, min(12, $count)); $html = ''; if ($mode === 'card') { $item = '
' . '

' . '

' . '
'; $html = str_repeat($item, $count); } elseif ($mode === 'mini') { $item = '
' . '
' . '
'; $html = str_repeat($item, $count); } else { $item = '
' . '

' . '

' . '
'; $html = str_repeat($item, $count); } return $html; } }