__('AKSRT 商品列表组件:筛选、排序、AJAX 翻页。', 'aksrt')] ); } public function widget($args, $instance): void { $title = apply_filters('widget_title', $instance['title'] ?? ''); $per_page = max(1, min(50, (int) ($instance['per_page'] ?? 8))); $orderby = sanitize_key($instance['orderby'] ?? 'date'); $order = in_array(strtoupper($instance['order'] ?? ''), ['ASC', 'DESC'], true) ? strtoupper($instance['order']) : 'DESC'; $cat_ids = array_filter(array_map('intval', explode(',', (string) ($instance['cat_ids'] ?? '')))); $tag_ids = array_filter(array_map('intval', explode(',', (string) ($instance['tag_ids'] ?? '')))); $discount_ids = array_filter(array_map('intval', explode(',', (string) ($instance['discount_ids'] ?? '')))); $exclude_cat = !empty($instance['exclude_cat']); $style = sanitize_key($instance['style'] ?? 'default'); $paged = max(1, (int) ($_GET['aksrt_product_page'] ?? 1)); $query_args = [ 'post_type' => 'aksrt_product', 'post_status' => 'publish', 'posts_per_page' => $per_page, 'paged' => $paged, 'orderby' => $orderby === 'sales' ? 'meta_value_num' : $orderby, 'order' => $order, ]; if ($orderby === 'sales') { $query_args['meta_key'] = '_aksrt_sales'; } // Taxonomy filters $tax_query = []; if (!empty($cat_ids)) { $tax_query[] = [ 'taxonomy' => 'aksrt_product_cat', 'field' => 'term_id', 'terms' => $cat_ids, 'operator' => $exclude_cat ? 'NOT IN' : 'IN', ]; } if (!empty($tag_ids)) { $tax_query[] = [ 'taxonomy' => 'aksrt_product_tag', 'field' => 'term_id', 'terms' => $tag_ids, ]; } if (!empty($discount_ids)) { $tax_query[] = [ 'taxonomy' => 'shop_discount', 'field' => 'term_id', 'terms' => $discount_ids, ]; } if (!empty($tax_query)) { $query_args['tax_query'] = $tax_query; } $products = new WP_Query($query_args); echo $args['before_widget']; if ($title) { echo $args['before_title'] . esc_html($title) . $args['after_title']; } $style_class = 'aksrt-product-widget--' . $style; echo '
'; if ($products->have_posts()) { echo '
'; while ($products->have_posts()) { $products->the_post(); $pid = get_the_ID(); $card = class_exists('AKSRT_Shop') ? AKSRT_Shop::get_instance()->build_product_card_view($pid) : []; $price = (float) ($card['price'] ?? 0); $image = $card['image'] ?? ''; echo '
'; if ($image) { echo ''; echo '' . esc_attr(get_the_title($pid)) . ''; echo ''; } echo '
'; echo '' . esc_html(get_the_title($pid)) . ''; echo '
'; echo '¥' . esc_html(number_format_i18n($price, 2)) . ''; if (!empty($card['sales'])) { echo '' . esc_html($card['sales']) . __(' 已售', 'aksrt') . ''; } echo '
'; } echo '
'; // Pagination if ($products->max_num_pages > 1) { echo '
'; echo paginate_links([ 'base' => add_query_arg('aksrt_product_page', '%#%'), 'format' => '', 'current' => $paged, 'total' => $products->max_num_pages, 'prev_text' => '«', 'next_text' => '»', ]); echo '
'; } } else { echo '

' . esc_html__('暂无商品', 'aksrt') . '

'; } echo '
'; echo $args['after_widget']; wp_reset_postdata(); } public function form($instance): void { $defaults = [ 'title' => __('商品推荐', 'aksrt'), 'per_page' => 8, 'orderby' => 'date', 'order' => 'DESC', 'cat_ids' => '', 'tag_ids' => '', 'discount_ids' => '', 'exclude_cat' => false, 'style' => 'default', ]; $instance = wp_parse_args($instance, $defaults); ?>

sanitize_text_field($new_instance['title'] ?? ''), 'per_page' => max(1, min(50, (int) ($new_instance['per_page'] ?? 8))), 'orderby' => sanitize_key($new_instance['orderby'] ?? 'date'), 'order' => in_array(strtoupper($new_instance['order'] ?? ''), ['ASC', 'DESC'], true) ? strtoupper($new_instance['order']) : 'DESC', 'cat_ids' => sanitize_text_field($new_instance['cat_ids'] ?? ''), 'tag_ids' => sanitize_text_field($new_instance['tag_ids'] ?? ''), 'discount_ids' => sanitize_text_field($new_instance['discount_ids'] ?? ''), 'exclude_cat' => !empty($new_instance['exclude_cat']), 'style' => sanitize_key($new_instance['style'] ?? 'default'), ]; } } /** * Horizontal swiper product widget — equivalent to zibll `zib_shop_widget_ui_oneline_product_lists`. */ class AKSRT_Widget_Product_Oneline extends AKSRT_Widget_Product_List { public function __construct() { WP_Widget::__construct( 'aksrt_product_oneline', __('横滑商品', 'aksrt'), ['description' => __('AKSRT 单行横滑商品 Swiper 组件。', 'aksrt')] ); } public function widget($args, $instance): void { $instance['style'] = 'oneline'; parent::widget($args, $instance); } public function form($instance): void { $instance = wp_parse_args($instance, ['style' => 'oneline']); parent::form($instance); } } /** * Multi-tab product widget — equivalent to zibll `zib_shop_widget_ui_tab_product`. * Each tab has independent category/discount filter. */ class AKSRT_Widget_Product_Tab extends WP_Widget { public function __construct() { parent::__construct( 'aksrt_product_tab', __('多TAB商品', 'aksrt'), ['description' => __('AKSRT 多 TAB 商品列表组件(每 tab 独立筛选)。', 'aksrt')] ); } public function widget($args, $instance): void { $title = apply_filters('widget_title', $instance['title'] ?? ''); $tabs_raw = (string) ($instance['tabs'] ?? ''); $per_page = max(1, min(20, (int) ($instance['per_page'] ?? 8))); // Parse tabs: "Tab Name|cat_ids|discount_ids\n..." $tabs = []; foreach (array_filter(explode("\n", $tabs_raw)) as $line) { $parts = explode('|', trim($line)); if (count($parts) >= 1 && trim($parts[0]) !== '') { $tabs[] = [ 'label' => trim($parts[0]), 'cat_ids' => trim($parts[1] ?? ''), 'discount_ids' => trim($parts[2] ?? ''), ]; } } if (empty($tabs)) { return; } echo $args['before_widget']; if ($title) { echo $args['before_title'] . esc_html($title) . $args['after_title']; } echo '
'; // Tab headers echo '
'; foreach ($tabs as $i => $tab) { $active = $i === 0 ? ' is-active' : ''; echo ''; } echo '
'; // Tab panels foreach ($tabs as $i => $tab) { $hidden = $i > 0 ? ' style="display:none"' : ''; echo '
'; $query_args = [ 'post_type' => 'aksrt_product', 'post_status' => 'publish', 'posts_per_page' => $per_page, 'orderby' => 'date', 'order' => 'DESC', ]; $tax_query = []; $cat_ids = array_filter(array_map('intval', explode(',', $tab['cat_ids']))); $discount_ids = array_filter(array_map('intval', explode(',', $tab['discount_ids']))); if (!empty($cat_ids)) { $tax_query[] = ['taxonomy' => 'aksrt_product_cat', 'field' => 'term_id', 'terms' => $cat_ids]; } if (!empty($discount_ids)) { $tax_query[] = ['taxonomy' => 'shop_discount', 'field' => 'term_id', 'terms' => $discount_ids]; } if (!empty($tax_query)) { $query_args['tax_query'] = $tax_query; } $products = new WP_Query($query_args); if ($products->have_posts()) { echo '
'; while ($products->have_posts()) { $products->the_post(); $pid = get_the_ID(); $card = class_exists('AKSRT_Shop') ? AKSRT_Shop::get_instance()->build_product_card_view($pid) : []; $price = (float) ($card['price'] ?? 0); $image = $card['image'] ?? ''; echo '
'; if ($image) { echo ''; echo '' . esc_attr(get_the_title($pid)) . ''; echo ''; } echo '
'; echo '' . esc_html(get_the_title($pid)) . ''; echo '¥' . esc_html(number_format_i18n($price, 2)) . ''; echo '
'; } echo '
'; } else { echo '

' . esc_html__('暂无商品', 'aksrt') . '

'; } echo '
'; wp_reset_postdata(); } // Tab switching JS echo ''; echo '
'; echo $args['after_widget']; } public function form($instance): void { $defaults = [ 'title' => __('商品精选', 'aksrt'), 'tabs' => "热门推荐|\n最新上架|", 'per_page' => 8, ]; $instance = wp_parse_args($instance, $defaults); ?>

sanitize_text_field($new_instance['title'] ?? ''), 'tabs' => sanitize_textarea_field($new_instance['tabs'] ?? ''), 'per_page' => max(1, min(20, (int) ($new_instance['per_page'] ?? 8))), ]; } }