843 lines
33 KiB
PHP
843 lines
33 KiB
PHP
<?php
|
|
/**
|
|
* Homepage content widgets aligned to the fixed Zibll-like layout.
|
|
*
|
|
* @package AKSRT
|
|
*/
|
|
|
|
defined('ABSPATH') || exit;
|
|
|
|
if (!function_exists('aksrt_home_widget_allowed_layouts')) {
|
|
/**
|
|
* Allowed post-card layouts for homepage content widgets.
|
|
*
|
|
* @return array<string, string>
|
|
*/
|
|
function aksrt_home_widget_allowed_layouts(): array {
|
|
return [
|
|
'card' => __('卡片', 'aksrt'),
|
|
'list' => __('列表', 'aksrt'),
|
|
'grid-cms' => __('资源网格', 'aksrt'),
|
|
];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_post_types')) {
|
|
/**
|
|
* Post types used by homepage widgets.
|
|
*
|
|
* @return array<int, string>
|
|
*/
|
|
function aksrt_home_widget_post_types(): array {
|
|
$post_types = ['post'];
|
|
|
|
if (function_exists('aksrt_resource_post_types')) {
|
|
$post_types = array_unique(array_merge($post_types, aksrt_resource_post_types()));
|
|
}
|
|
|
|
return array_values(array_filter(array_map('sanitize_key', $post_types)));
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_available_categories')) {
|
|
/**
|
|
* Return categories for widget admin forms.
|
|
*
|
|
* @return array<int, WP_Term>
|
|
*/
|
|
function aksrt_home_widget_available_categories(): array {
|
|
$categories = get_categories([
|
|
'taxonomy' => 'category',
|
|
'hide_empty' => false,
|
|
'orderby' => 'name',
|
|
'order' => 'ASC',
|
|
]);
|
|
|
|
return is_array($categories) ? $categories : [];
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_fallback_category_ids')) {
|
|
/**
|
|
* Pick top categories as fallback when widget instance has no selection.
|
|
*
|
|
* @param int $limit Maximum category ids to return.
|
|
* @return array<int, int>
|
|
*/
|
|
function aksrt_home_widget_fallback_category_ids(int $limit = 1): array {
|
|
$limit = max(1, min(8, $limit));
|
|
$terms = get_terms([
|
|
'taxonomy' => 'category',
|
|
'orderby' => 'count',
|
|
'order' => 'DESC',
|
|
'number' => $limit,
|
|
'hide_empty' => true,
|
|
'fields' => 'ids',
|
|
]);
|
|
|
|
if (is_wp_error($terms) || !is_array($terms)) {
|
|
return [];
|
|
}
|
|
|
|
return array_values(array_filter(array_map('absint', $terms)));
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_normalize_category_ids')) {
|
|
/**
|
|
* Normalize selected category ids.
|
|
*
|
|
* @param mixed $raw_ids Raw ids from widget instance.
|
|
* @param int $limit Maximum ids to keep.
|
|
* @return array<int, int>
|
|
*/
|
|
function aksrt_home_widget_normalize_category_ids($raw_ids, int $limit = 4): array {
|
|
$ids = array_map('absint', (array) $raw_ids);
|
|
$ids = array_values(array_filter($ids, static fn($id) => $id > 0));
|
|
|
|
if ($limit > 0) {
|
|
$ids = array_slice($ids, 0, $limit);
|
|
}
|
|
|
|
return $ids;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_resolve_layout')) {
|
|
/**
|
|
* Sanitize requested widget post layout.
|
|
*
|
|
* @param mixed $layout Layout value.
|
|
* @param string $default Default layout.
|
|
* @return string
|
|
*/
|
|
function aksrt_home_widget_resolve_layout($layout, string $default = 'card'): string {
|
|
$allowed = array_keys(aksrt_home_widget_allowed_layouts());
|
|
$layout = is_string($layout) ? $layout : $default;
|
|
|
|
return in_array($layout, $allowed, true) ? $layout : $default;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_resolve_context')) {
|
|
/**
|
|
* Resolve widget area context from sidebar args.
|
|
*/
|
|
function aksrt_home_widget_resolve_context(array $args): string {
|
|
if (function_exists('aksrt_widget_get_area_context')) {
|
|
return aksrt_widget_get_area_context($args);
|
|
}
|
|
|
|
return 'homepage';
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_effective_layout')) {
|
|
/**
|
|
* Compact rich homepage widgets when placed into a sidebar area.
|
|
*/
|
|
function aksrt_home_widget_effective_layout(string $layout, string $context): string {
|
|
if ($context === 'sidebar' && $layout !== 'list') {
|
|
return 'list';
|
|
}
|
|
|
|
return $layout;
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_effective_columns')) {
|
|
/**
|
|
* Sidebar widgets should stay single-column.
|
|
*/
|
|
function aksrt_home_widget_effective_columns(int $columns, string $context): int {
|
|
if ($context === 'sidebar') {
|
|
return 1;
|
|
}
|
|
|
|
return max(1, min(4, $columns));
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_render_header')) {
|
|
/**
|
|
* Render a compact Zibll-like section header.
|
|
*
|
|
* @param string $title Section title.
|
|
* @param string $more_link Optional more link.
|
|
* @param string $more_text Optional more text.
|
|
* @return void
|
|
*/
|
|
function aksrt_home_widget_render_header(string $title, string $more_link = '', string $more_text = ''): void {
|
|
?>
|
|
<header class="aksrt-home-widget__header">
|
|
<h3 class="aksrt-home-widget__title"><?php echo esc_html($title); ?></h3>
|
|
<?php if ($more_link !== '') : ?>
|
|
<a class="aksrt-home-widget__more" href="<?php echo esc_url($more_link); ?>">
|
|
<?php echo esc_html($more_text !== '' ? $more_text : __('查看更多', 'aksrt')); ?>
|
|
</a>
|
|
<?php endif; ?>
|
|
</header>
|
|
<?php
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_render_post_grid')) {
|
|
/**
|
|
* Render posts for homepage widgets.
|
|
*
|
|
* Delegates to the unified shared renderer (aksrt_render_post_list).
|
|
*
|
|
* @param WP_Query $query Posts query.
|
|
* @param string $layout Card layout.
|
|
* @param int $columns Desktop columns.
|
|
* @param string $context Sidebar or homepage context.
|
|
* @return void
|
|
*/
|
|
function aksrt_home_widget_render_post_grid(WP_Query $query, string $layout = 'card', int $columns = 3, string $context = 'homepage'): void {
|
|
if (!$query->have_posts()) {
|
|
echo '<p class="widget-empty">' . esc_html__('暂无内容', 'aksrt') . '</p>';
|
|
wp_reset_postdata();
|
|
return;
|
|
}
|
|
|
|
if ($context === 'sidebar') {
|
|
$use_homepage_mini = function_exists('aksrt_is_fixed_homepage_request')
|
|
&& aksrt_is_fixed_homepage_request()
|
|
&& function_exists('aksrt_render_mini_list')
|
|
&& (!class_exists('AKSRT_Settings') || AKSRT_Settings::homepage_sidebar_mini_enabled());
|
|
|
|
if ($use_homepage_mini && function_exists('aksrt_render_mini_list')) {
|
|
echo '<div class="widget-tab-posts__list widget-tab-posts__list--mini aksrt-home-widget__sidebar-list">';
|
|
aksrt_render_mini_list($query, ['context' => 'sidebar', 'show_thumb' => true]);
|
|
echo '</div>';
|
|
return;
|
|
}
|
|
|
|
// Fallback: simple sidebar list
|
|
echo '<ul class="widget-tab-posts__list aksrt-home-widget__sidebar-list">';
|
|
while ($query->have_posts()) {
|
|
$query->the_post();
|
|
?>
|
|
<li class="widget-tab-posts__item">
|
|
<?php if (has_post_thumbnail()) : ?>
|
|
<a href="<?php the_permalink(); ?>" class="widget-tab-posts__thumb">
|
|
<?php the_post_thumbnail('thumbnail', ['loading' => 'lazy', 'class' => 'fit-cover']); ?>
|
|
</a>
|
|
<?php endif; ?>
|
|
<div class="widget-tab-posts__info">
|
|
<a href="<?php the_permalink(); ?>" class="widget-tab-posts__title"><?php the_title(); ?></a>
|
|
<span class="widget-tab-posts__meta">
|
|
<?php echo esc_html(human_time_diff(get_the_time('U'), current_time('timestamp')) . __('前', 'aksrt')); ?>
|
|
</span>
|
|
</div>
|
|
</li>
|
|
<?php
|
|
}
|
|
echo '</ul>';
|
|
wp_reset_postdata();
|
|
return;
|
|
}
|
|
|
|
// Homepage / content area: delegate to shared renderer
|
|
$layout = aksrt_home_widget_resolve_layout($layout, 'card');
|
|
$columns = max(1, min(4, $columns));
|
|
|
|
if (function_exists('aksrt_render_post_list')) {
|
|
aksrt_render_post_list($query, [
|
|
'mode' => $layout === 'grid-cms' ? 'grid-cms' : $layout,
|
|
'context' => 'widget',
|
|
'columns' => $columns,
|
|
], true);
|
|
} else {
|
|
// Fallback: use template part
|
|
$previous_layout = get_query_var('aksrt_post_card_layout', '');
|
|
$previous_scene = get_query_var('aksrt_post_card_scene', '');
|
|
|
|
set_query_var('aksrt_post_card_layout', $layout);
|
|
set_query_var('aksrt_post_card_scene', 'home');
|
|
|
|
$classes = [
|
|
'aksrt-home-widget__post-grid',
|
|
'aksrt-home-widget__post-grid--' . $layout,
|
|
'post-grid',
|
|
'post-grid--' . $layout,
|
|
];
|
|
|
|
printf(
|
|
'<div class="%1$s" style="--aksrt-widget-columns:%2$d;">',
|
|
esc_attr(implode(' ', $classes)),
|
|
(int) $columns
|
|
);
|
|
|
|
while ($query->have_posts()) {
|
|
$query->the_post();
|
|
get_template_part('templates/parts/content', 'post-card');
|
|
}
|
|
|
|
echo '</div>';
|
|
|
|
set_query_var('aksrt_post_card_layout', $previous_layout);
|
|
set_query_var('aksrt_post_card_scene', $previous_scene);
|
|
}
|
|
|
|
wp_reset_postdata();
|
|
}
|
|
}
|
|
|
|
if (!function_exists('aksrt_home_widget_get_lazyload_args')) {
|
|
/**
|
|
* Lazyload settings reused by category recommend widget.
|
|
*
|
|
* @return array{enabled: bool, placeholder_url: string}
|
|
*/
|
|
function aksrt_home_widget_get_lazyload_args(): array {
|
|
$config = class_exists('AKSRT_Settings')
|
|
? AKSRT_Settings::get_lazyload_config()
|
|
: ['enabled' => false, 'placeholder_url' => ''];
|
|
|
|
return [
|
|
'enabled' => ! empty($config['enabled']),
|
|
'placeholder_url' => ! empty($config['placeholder_url'])
|
|
? (string) $config['placeholder_url']
|
|
: get_template_directory_uri() . '/assets/img/placeholder.svg',
|
|
];
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Homepage category block widget.
|
|
*/
|
|
class AKSRT_Category_Block_Widget extends WP_Widget {
|
|
|
|
public function __construct() {
|
|
parent::__construct(
|
|
'aksrt_category_block',
|
|
esc_html__('AKSRT 分类块', 'aksrt'),
|
|
[
|
|
'classname' => 'widget_aksrt_category_block',
|
|
'description' => esc_html__('指定分类的最新内容区块,可挂载到首页内容挂载区。', 'aksrt'),
|
|
'customize_selective_refresh' => true,
|
|
]
|
|
);
|
|
}
|
|
|
|
public function widget($args, $instance): void {
|
|
$context = aksrt_home_widget_resolve_context($args);
|
|
$category_id = $this->resolve_category_id($instance);
|
|
$term = $category_id > 0 ? get_term($category_id, 'category') : null;
|
|
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
|
$title = $title !== '' ? $title : (($term && ! is_wp_error($term)) ? $term->name : __('精选分类', 'aksrt'));
|
|
$count = max(1, min(12, (int) ($instance['count'] ?? 6)));
|
|
$columns = aksrt_home_widget_effective_columns((int) ($instance['columns'] ?? 3), $context);
|
|
$layout = aksrt_home_widget_effective_layout(
|
|
aksrt_home_widget_resolve_layout($instance['layout'] ?? 'card', 'card'),
|
|
$context
|
|
);
|
|
$show_more = ! empty($instance['show_more']);
|
|
|
|
$query_args = [
|
|
'post_type' => aksrt_home_widget_post_types(),
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => $count,
|
|
'ignore_sticky_posts' => true,
|
|
'no_found_rows' => true,
|
|
];
|
|
|
|
if ($category_id > 0) {
|
|
$query_args['cat'] = $category_id;
|
|
}
|
|
|
|
$query = new WP_Query($query_args);
|
|
|
|
echo $args['before_widget'];
|
|
echo '<section class="aksrt-home-widget aksrt-home-widget--category-block">';
|
|
|
|
aksrt_home_widget_render_header(
|
|
(string) $title,
|
|
($show_more && $term && ! is_wp_error($term)) ? (string) get_category_link($category_id) : '',
|
|
__('查看分类', 'aksrt')
|
|
);
|
|
|
|
aksrt_home_widget_render_post_grid($query, $layout, $columns, $context);
|
|
|
|
echo '</section>';
|
|
echo $args['after_widget'];
|
|
}
|
|
|
|
public function form($instance): void {
|
|
$title = (string) ($instance['title'] ?? '');
|
|
$category_id = (int) ($instance['category_id'] ?? 0);
|
|
$count = (int) ($instance['count'] ?? 6);
|
|
$columns = (int) ($instance['columns'] ?? 3);
|
|
$layout = aksrt_home_widget_resolve_layout($instance['layout'] ?? 'card', 'card');
|
|
$show_more = ! empty($instance['show_more']);
|
|
$categories = aksrt_home_widget_available_categories();
|
|
?>
|
|
<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('category_id')); ?>"><?php esc_html_e('分类:', 'aksrt'); ?></label>
|
|
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('category_id')); ?>" name="<?php echo esc_attr($this->get_field_name('category_id')); ?>">
|
|
<option value="0"><?php esc_html_e('自动选择最热门分类', 'aksrt'); ?></option>
|
|
<?php foreach ($categories as $category) : ?>
|
|
<option value="<?php echo (int) $category->term_id; ?>" <?php selected($category_id, (int) $category->term_id); ?>>
|
|
<?php echo esc_html($category->name); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('count')); ?>"><?php esc_html_e('文章数量:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" 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="12" value="<?php echo (int) $count; ?>">
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('columns')); ?>"><?php esc_html_e('桌面列数:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('columns')); ?>" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" type="number" min="1" max="4" value="<?php echo (int) $columns; ?>">
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('layout')); ?>"><?php esc_html_e('布局:', 'aksrt'); ?></label>
|
|
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('layout')); ?>" name="<?php echo esc_attr($this->get_field_name('layout')); ?>">
|
|
<?php foreach (aksrt_home_widget_allowed_layouts() as $value => $label) : ?>
|
|
<option value="<?php echo esc_attr($value); ?>" <?php selected($layout, $value); ?>>
|
|
<?php echo esc_html($label); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_more); ?> id="<?php echo esc_attr($this->get_field_id('show_more')); ?>" name="<?php echo esc_attr($this->get_field_name('show_more')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_more')); ?>"><?php esc_html_e('显示分类链接', 'aksrt'); ?></label>
|
|
</p>
|
|
<?php if (function_exists('aksrt_widget_render_location_help')) { aksrt_widget_render_location_help('hybrid'); } ?>
|
|
<?php
|
|
}
|
|
|
|
public function update($new_instance, $old_instance): array {
|
|
return [
|
|
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
|
'category_id' => absint($new_instance['category_id'] ?? 0),
|
|
'count' => max(1, min(12, absint($new_instance['count'] ?? 6))),
|
|
'columns' => max(1, min(4, absint($new_instance['columns'] ?? 3))),
|
|
'layout' => aksrt_home_widget_resolve_layout($new_instance['layout'] ?? 'card', 'card'),
|
|
'show_more' => ! empty($new_instance['show_more']) ? 1 : 0,
|
|
];
|
|
}
|
|
|
|
private function resolve_category_id(array $instance): int {
|
|
$category_id = absint($instance['category_id'] ?? 0);
|
|
if ($category_id > 0) {
|
|
return $category_id;
|
|
}
|
|
|
|
$fallback = aksrt_home_widget_fallback_category_ids(1);
|
|
return $fallback[0] ?? 0;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Homepage category tabs widget.
|
|
*/
|
|
class AKSRT_Category_Tabs_Widget extends WP_Widget {
|
|
|
|
public function __construct() {
|
|
parent::__construct(
|
|
'aksrt_category_tabs',
|
|
esc_html__('AKSRT 分类 Tabs', 'aksrt'),
|
|
[
|
|
'classname' => 'widget_aksrt_category_tabs',
|
|
'description' => esc_html__('多分类切换内容流,可挂载到首页内容挂载区。', 'aksrt'),
|
|
'customize_selective_refresh' => true,
|
|
]
|
|
);
|
|
}
|
|
|
|
public function widget($args, $instance): void {
|
|
$context = aksrt_home_widget_resolve_context($args);
|
|
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
|
$title = $title !== '' ? $title : __('热门分类', 'aksrt');
|
|
$count = max(1, min(12, (int) ($instance['count'] ?? 6)));
|
|
$columns = aksrt_home_widget_effective_columns((int) ($instance['columns'] ?? 3), $context);
|
|
$layout = aksrt_home_widget_effective_layout(
|
|
aksrt_home_widget_resolve_layout($instance['layout'] ?? 'card', 'card'),
|
|
$context
|
|
);
|
|
$show_more = ! empty($instance['show_more']);
|
|
$tabs = $this->resolve_tabs($instance);
|
|
|
|
echo $args['before_widget'];
|
|
echo '<section class="aksrt-home-widget aksrt-home-widget--tabs widget-tab-posts">';
|
|
|
|
if (empty($tabs)) {
|
|
echo '<p class="widget-empty">' . esc_html__('暂无可用分类', 'aksrt') . '</p>';
|
|
echo '</section>';
|
|
echo $args['after_widget'];
|
|
return;
|
|
}
|
|
|
|
?>
|
|
<header class="aksrt-home-widget__header aksrt-home-widget__header--tabs">
|
|
<h3 class="aksrt-home-widget__title"><?php echo esc_html($title); ?></h3>
|
|
<ul class="widget-tab-posts__nav aksrt-home-widget__tab-nav" role="tablist">
|
|
<?php foreach ($tabs as $index => $tab) : ?>
|
|
<li role="presentation">
|
|
<button
|
|
type="button"
|
|
role="tab"
|
|
class="widget-tab-posts__tab<?php echo 0 === $index ? ' active' : ''; ?>"
|
|
data-tab="cat-<?php echo (int) $tab['id']; ?>"
|
|
aria-selected="<?php echo 0 === $index ? 'true' : 'false'; ?>"
|
|
>
|
|
<?php echo esc_html($tab['name']); ?>
|
|
</button>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
</header>
|
|
<?php
|
|
|
|
foreach ($tabs as $index => $tab) {
|
|
$query = new WP_Query([
|
|
'post_type' => aksrt_home_widget_post_types(),
|
|
'post_status' => 'publish',
|
|
'posts_per_page' => $count,
|
|
'ignore_sticky_posts' => true,
|
|
'no_found_rows' => true,
|
|
'cat' => (int) $tab['id'],
|
|
]);
|
|
?>
|
|
<div class="widget-tab-posts__panel<?php echo 0 === $index ? ' active' : ''; ?>" data-tab-panel="cat-<?php echo (int) $tab['id']; ?>" role="tabpanel"<?php echo 0 === $index ? '' : ' hidden'; ?>>
|
|
<?php aksrt_home_widget_render_post_grid($query, $layout, $columns, $context); ?>
|
|
<?php if ($show_more) : ?>
|
|
<div class="aksrt-home-widget__footer">
|
|
<a class="aksrt-home-widget__more" href="<?php echo esc_url($tab['link']); ?>">
|
|
<?php esc_html_e('查看更多', 'aksrt'); ?>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
<?php
|
|
}
|
|
|
|
echo '</section>';
|
|
echo $args['after_widget'];
|
|
}
|
|
|
|
public function form($instance): void {
|
|
$title = (string) ($instance['title'] ?? '');
|
|
$category_ids = aksrt_home_widget_normalize_category_ids($instance['category_ids'] ?? [], 6);
|
|
$count = (int) ($instance['count'] ?? 6);
|
|
$columns = (int) ($instance['columns'] ?? 3);
|
|
$layout = aksrt_home_widget_resolve_layout($instance['layout'] ?? 'card', 'card');
|
|
$show_more = ! empty($instance['show_more']);
|
|
$categories = aksrt_home_widget_available_categories();
|
|
?>
|
|
<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('category_ids')); ?>"><?php esc_html_e('分类(可多选):', 'aksrt'); ?></label>
|
|
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('category_ids')); ?>" name="<?php echo esc_attr($this->get_field_name('category_ids')); ?>[]" multiple size="6">
|
|
<?php foreach ($categories as $category) : ?>
|
|
<option value="<?php echo (int) $category->term_id; ?>" <?php selected(in_array((int) $category->term_id, $category_ids, true)); ?>>
|
|
<?php echo esc_html($category->name); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<small><?php esc_html_e('留空时自动选择热门分类。', 'aksrt'); ?></small>
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('count')); ?>"><?php esc_html_e('每个 Tab 的文章数量:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" 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="12" value="<?php echo (int) $count; ?>">
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('columns')); ?>"><?php esc_html_e('桌面列数:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('columns')); ?>" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" type="number" min="1" max="4" value="<?php echo (int) $columns; ?>">
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('layout')); ?>"><?php esc_html_e('布局:', 'aksrt'); ?></label>
|
|
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('layout')); ?>" name="<?php echo esc_attr($this->get_field_name('layout')); ?>">
|
|
<?php foreach (aksrt_home_widget_allowed_layouts() as $value => $label) : ?>
|
|
<option value="<?php echo esc_attr($value); ?>" <?php selected($layout, $value); ?>>
|
|
<?php echo esc_html($label); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_more); ?> id="<?php echo esc_attr($this->get_field_id('show_more')); ?>" name="<?php echo esc_attr($this->get_field_name('show_more')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_more')); ?>"><?php esc_html_e('显示“查看更多”链接', 'aksrt'); ?></label>
|
|
</p>
|
|
<?php if (function_exists('aksrt_widget_render_location_help')) { aksrt_widget_render_location_help('hybrid'); } ?>
|
|
<?php
|
|
}
|
|
|
|
public function update($new_instance, $old_instance): array {
|
|
return [
|
|
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
|
'category_ids' => aksrt_home_widget_normalize_category_ids($new_instance['category_ids'] ?? [], 6),
|
|
'count' => max(1, min(12, absint($new_instance['count'] ?? 6))),
|
|
'columns' => max(1, min(4, absint($new_instance['columns'] ?? 3))),
|
|
'layout' => aksrt_home_widget_resolve_layout($new_instance['layout'] ?? 'card', 'card'),
|
|
'show_more' => ! empty($new_instance['show_more']) ? 1 : 0,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Resolve configured category tabs.
|
|
*
|
|
* @param array $instance Widget instance.
|
|
* @return array<int, array{id:int,name:string,link:string}>
|
|
*/
|
|
private function resolve_tabs(array $instance): array {
|
|
$category_ids = aksrt_home_widget_normalize_category_ids($instance['category_ids'] ?? [], 6);
|
|
if (empty($category_ids)) {
|
|
$category_ids = aksrt_home_widget_fallback_category_ids(4);
|
|
}
|
|
|
|
$tabs = [];
|
|
foreach ($category_ids as $category_id) {
|
|
$term = get_term($category_id, 'category');
|
|
if (! $term || is_wp_error($term)) {
|
|
continue;
|
|
}
|
|
|
|
$tabs[] = [
|
|
'id' => (int) $category_id,
|
|
'name' => $term->name,
|
|
'link' => get_category_link($category_id),
|
|
];
|
|
}
|
|
|
|
return $tabs;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Homepage category recommend cards widget.
|
|
*/
|
|
class AKSRT_Category_Recommend_Widget extends WP_Widget {
|
|
|
|
public function __construct() {
|
|
parent::__construct(
|
|
'aksrt_category_recommend',
|
|
esc_html__('AKSRT 分类推荐卡片', 'aksrt'),
|
|
[
|
|
'classname' => 'widget_aksrt_category_recommend',
|
|
'description' => esc_html__('分类推荐卡片区块,可挂载到首页内容挂载区。', 'aksrt'),
|
|
'customize_selective_refresh' => true,
|
|
]
|
|
);
|
|
}
|
|
|
|
public function widget($args, $instance): void {
|
|
$title = apply_filters('widget_title', $instance['title'] ?? '', $instance, $this->id_base);
|
|
$title = $title !== '' ? $title : __('分类推荐', 'aksrt');
|
|
$category_ids = aksrt_home_widget_normalize_category_ids($instance['category_ids'] ?? [], 4);
|
|
$posts_per_cat = max(1, min(8, (int) ($instance['posts_per_category'] ?? 5)));
|
|
$columns = max(1, min(4, (int) ($instance['columns'] ?? 2)));
|
|
$show_views = ! empty($instance['show_views']);
|
|
$show_description = ! empty($instance['show_description']);
|
|
$show_dates = ! empty($instance['show_dates']);
|
|
$show_more = ! empty($instance['show_more']);
|
|
|
|
if (empty($category_ids)) {
|
|
$category_ids = aksrt_home_widget_fallback_category_ids(4);
|
|
}
|
|
|
|
$cards = $this->build_cards($category_ids, $posts_per_cat, $show_views, $show_description);
|
|
|
|
echo $args['before_widget'];
|
|
echo '<section class="aksrt-home-widget aksrt-home-widget--recommend">';
|
|
|
|
aksrt_home_widget_render_header($title);
|
|
|
|
if (empty($cards)) {
|
|
echo '<p class="widget-empty">' . esc_html__('暂无推荐分类', 'aksrt') . '</p>';
|
|
echo '</section>';
|
|
echo $args['after_widget'];
|
|
return;
|
|
}
|
|
|
|
$lazy = aksrt_home_widget_get_lazyload_args();
|
|
printf('<div class="aksrt-category-recommend__grid" style="--aksrt-recommend-columns:%d;">', (int) $columns);
|
|
|
|
foreach ($cards as $card) {
|
|
?>
|
|
<article class="aksrt-category-recommend__card">
|
|
<div class="aksrt-category-recommend__hero">
|
|
<a href="<?php echo esc_url($card['link']); ?>">
|
|
<?php if ($lazy['enabled']) : ?>
|
|
<span class="aksrt-skeleton"></span>
|
|
<img class="aksrt-category-recommend__cover aksrt-lazy" data-src="<?php echo esc_url($card['cover']); ?>" src="<?php echo esc_url($lazy['placeholder_url']); ?>" alt="<?php echo esc_attr($card['name']); ?>">
|
|
<?php else : ?>
|
|
<img class="aksrt-category-recommend__cover" src="<?php echo esc_url($card['cover']); ?>" alt="<?php echo esc_attr($card['name']); ?>">
|
|
<?php endif; ?>
|
|
</a>
|
|
<span class="aksrt-category-recommend__badge"><?php echo esc_html(sprintf(_n('%d 篇文章', '%d 篇文章', $card['count'], 'aksrt'), $card['count'])); ?></span>
|
|
<?php if ($show_views && $card['views'] > 0) : ?>
|
|
<span class="aksrt-category-recommend__views">
|
|
<i class="fas fa-eye" aria-hidden="true"></i>
|
|
<?php echo esc_html(function_exists('aksrt_format_number') ? aksrt_format_number($card['views']) : number_format_i18n($card['views'])); ?>
|
|
</span>
|
|
<?php endif; ?>
|
|
</div>
|
|
<div class="aksrt-category-recommend__body">
|
|
<div class="aksrt-category-recommend__meta">
|
|
<h4 class="aksrt-category-recommend__name">
|
|
<a href="<?php echo esc_url($card['link']); ?>"><?php echo esc_html($card['name']); ?></a>
|
|
</h4>
|
|
<?php if ($show_description && $card['description'] !== '') : ?>
|
|
<p class="aksrt-category-recommend__desc"><?php echo esc_html($card['description']); ?></p>
|
|
<?php endif; ?>
|
|
</div>
|
|
<ul class="aksrt-category-recommend__posts">
|
|
<?php foreach ($card['posts'] as $post_item) : ?>
|
|
<li class="aksrt-category-recommend__post">
|
|
<a class="aksrt-category-recommend__post-link" href="<?php echo esc_url($post_item['link']); ?>">
|
|
<?php echo esc_html($post_item['title']); ?>
|
|
</a>
|
|
<?php if ($show_dates && $post_item['date'] !== '') : ?>
|
|
<span class="aksrt-category-recommend__date"><?php echo esc_html($post_item['date']); ?></span>
|
|
<?php endif; ?>
|
|
</li>
|
|
<?php endforeach; ?>
|
|
</ul>
|
|
<?php if ($show_more) : ?>
|
|
<div class="aksrt-home-widget__footer">
|
|
<a class="aksrt-home-widget__more" href="<?php echo esc_url($card['link']); ?>">
|
|
<?php esc_html_e('查看更多', 'aksrt'); ?>
|
|
</a>
|
|
</div>
|
|
<?php endif; ?>
|
|
</div>
|
|
</article>
|
|
<?php
|
|
}
|
|
|
|
echo '</div>';
|
|
echo '</section>';
|
|
echo $args['after_widget'];
|
|
}
|
|
|
|
public function form($instance): void {
|
|
$title = (string) ($instance['title'] ?? __('分类推荐', 'aksrt'));
|
|
$category_ids = aksrt_home_widget_normalize_category_ids($instance['category_ids'] ?? [], 4);
|
|
$posts_per_cat = (int) ($instance['posts_per_category'] ?? 5);
|
|
$columns = (int) ($instance['columns'] ?? 2);
|
|
$show_views = ! empty($instance['show_views']);
|
|
$show_description = ! array_key_exists('show_description', $instance) || ! empty($instance['show_description']);
|
|
$show_dates = ! array_key_exists('show_dates', $instance) || ! empty($instance['show_dates']);
|
|
$show_more = ! array_key_exists('show_more', $instance) || ! empty($instance['show_more']);
|
|
$categories = aksrt_home_widget_available_categories();
|
|
?>
|
|
<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('category_ids')); ?>"><?php esc_html_e('分类(最多 4 个):', 'aksrt'); ?></label>
|
|
<select class="widefat" id="<?php echo esc_attr($this->get_field_id('category_ids')); ?>" name="<?php echo esc_attr($this->get_field_name('category_ids')); ?>[]" multiple size="6">
|
|
<?php foreach ($categories as $category) : ?>
|
|
<option value="<?php echo (int) $category->term_id; ?>" <?php selected(in_array((int) $category->term_id, $category_ids, true)); ?>>
|
|
<?php echo esc_html($category->name); ?>
|
|
</option>
|
|
<?php endforeach; ?>
|
|
</select>
|
|
<small><?php esc_html_e('留空时自动选择热门分类。', 'aksrt'); ?></small>
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('posts_per_category')); ?>"><?php esc_html_e('每个分类展示文章数:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('posts_per_category')); ?>" name="<?php echo esc_attr($this->get_field_name('posts_per_category')); ?>" type="number" min="1" max="8" value="<?php echo (int) $posts_per_cat; ?>">
|
|
</p>
|
|
<p>
|
|
<label for="<?php echo esc_attr($this->get_field_id('columns')); ?>"><?php esc_html_e('桌面列数:', 'aksrt'); ?></label>
|
|
<input class="tiny-text" id="<?php echo esc_attr($this->get_field_id('columns')); ?>" name="<?php echo esc_attr($this->get_field_name('columns')); ?>" type="number" min="1" max="4" value="<?php echo (int) $columns; ?>">
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_views); ?> id="<?php echo esc_attr($this->get_field_id('show_views')); ?>" name="<?php echo esc_attr($this->get_field_name('show_views')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_views')); ?>"><?php esc_html_e('显示分类总浏览量', 'aksrt'); ?></label>
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_description); ?> id="<?php echo esc_attr($this->get_field_id('show_description')); ?>" name="<?php echo esc_attr($this->get_field_name('show_description')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_description')); ?>"><?php esc_html_e('显示分类描述', 'aksrt'); ?></label>
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_dates); ?> id="<?php echo esc_attr($this->get_field_id('show_dates')); ?>" name="<?php echo esc_attr($this->get_field_name('show_dates')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_dates')); ?>"><?php esc_html_e('显示文章时间', 'aksrt'); ?></label>
|
|
</p>
|
|
<p>
|
|
<input class="checkbox" type="checkbox" <?php checked($show_more); ?> id="<?php echo esc_attr($this->get_field_id('show_more')); ?>" name="<?php echo esc_attr($this->get_field_name('show_more')); ?>" value="1">
|
|
<label for="<?php echo esc_attr($this->get_field_id('show_more')); ?>"><?php esc_html_e('显示“查看更多”链接', 'aksrt'); ?></label>
|
|
</p>
|
|
<?php if (function_exists('aksrt_widget_render_location_help')) { aksrt_widget_render_location_help('homepage'); } ?>
|
|
<?php
|
|
}
|
|
|
|
public function update($new_instance, $old_instance): array {
|
|
return [
|
|
'title' => sanitize_text_field($new_instance['title'] ?? ''),
|
|
'category_ids' => aksrt_home_widget_normalize_category_ids($new_instance['category_ids'] ?? [], 4),
|
|
'posts_per_category' => max(1, min(8, absint($new_instance['posts_per_category'] ?? 5))),
|
|
'columns' => max(1, min(4, absint($new_instance['columns'] ?? 2))),
|
|
'show_views' => ! empty($new_instance['show_views']) ? 1 : 0,
|
|
'show_description' => ! empty($new_instance['show_description']) ? 1 : 0,
|
|
'show_dates' => ! empty($new_instance['show_dates']) ? 1 : 0,
|
|
'show_more' => ! empty($new_instance['show_more']) ? 1 : 0,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* Build category recommend cards.
|
|
*
|
|
* @param array<int, int> $category_ids Category ids.
|
|
* @param int $posts_per_cat Post count per category.
|
|
* @param bool $show_views Whether to calculate views.
|
|
* @param bool $show_description Whether to fetch description.
|
|
* @return array<int, array<string, mixed>>
|
|
*/
|
|
private function build_cards(array $category_ids, int $posts_per_cat, bool $show_views, bool $show_description): array {
|
|
$cards = [];
|
|
|
|
foreach ($category_ids as $category_id) {
|
|
$term = get_term($category_id, 'category');
|
|
if (! $term || is_wp_error($term)) {
|
|
continue;
|
|
}
|
|
|
|
$posts = get_posts([
|
|
'post_type' => aksrt_home_widget_post_types(),
|
|
'cat' => $category_id,
|
|
'posts_per_page' => $posts_per_cat,
|
|
'post_status' => 'publish',
|
|
'orderby' => 'date',
|
|
'order' => 'DESC',
|
|
'no_found_rows' => true,
|
|
]);
|
|
|
|
$post_items = [];
|
|
foreach ($posts as $post) {
|
|
$post_items[] = [
|
|
'title' => get_the_title($post->ID),
|
|
'link' => get_permalink($post->ID),
|
|
'date' => function_exists('aksrt_time_ago') ? aksrt_time_ago($post->post_date) : get_the_date('Y-m-d', $post->ID),
|
|
];
|
|
}
|
|
|
|
$cards[] = [
|
|
'name' => $term->name,
|
|
'link' => get_category_link($category_id),
|
|
'cover' => class_exists('AKSRT_Settings') ? AKSRT_Settings::get_category_cover_url($category_id) : (get_template_directory_uri() . '/assets/img/placeholder.svg'),
|
|
'description' => $show_description && class_exists('AKSRT_Settings') ? AKSRT_Settings::get_category_recommend_desc($category_id) : ($show_description ? (string) $term->description : ''),
|
|
'count' => (int) $term->count,
|
|
'views' => $show_views && function_exists('aksrt_get_category_total_views') ? aksrt_get_category_total_views($category_id) : 0,
|
|
'posts' => $post_items,
|
|
];
|
|
}
|
|
|
|
return $cards;
|
|
}
|
|
}
|