feat(shop): 商品详情/归档壳层 1:1 同家族卡片与内容流
商品详情接入 content-wrap 主站详情壳;相关推荐与分类/标签/用户主页商品统一 product-card;卖家入口对齐用户主页 product tab。 Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -463,3 +463,29 @@ html.dark .aksrt-product-page__content img {
|
|||||||
font-size: 13px;
|
font-size: 13px;
|
||||||
color: var(--color-ink-3);
|
color: var(--color-ink-3);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/* Product detail shell — align with single content stream */
|
||||||
|
.content-shell--product .content-wrap {
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
.content-shell--product .aksrt-product-page {
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
.aksrt-product-page__related {
|
||||||
|
margin-top: 28px;
|
||||||
|
padding-top: 8px;
|
||||||
|
}
|
||||||
|
.aksrt-product-page__related-title {
|
||||||
|
margin: 0 0 14px;
|
||||||
|
font-size: 18px;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--color-ink, #1f2937);
|
||||||
|
}
|
||||||
|
.aksrt-product-page__related-grid.aksrt-product-archive__grid {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
.aksrt-product-page__merchant-link {
|
||||||
|
display: inline-block;
|
||||||
|
margin-top: 4px;
|
||||||
|
}
|
||||||
|
|||||||
@@ -37,12 +37,15 @@ $author_id = (int) get_post_field('post_author', $product_id);
|
|||||||
$author = $author_id > 0 ? get_userdata($author_id) : null;
|
$author = $author_id > 0 ? get_userdata($author_id) : null;
|
||||||
?>
|
?>
|
||||||
|
|
||||||
<main id="main-content" class="site-main content-shell" tabindex="-1">
|
<main id="main-content" class="site-main content-shell content-shell--stream content-shell--product" tabindex="-1">
|
||||||
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
<?php if (function_exists('aksrt_breadcrumbs')) { aksrt_breadcrumbs(); } ?>
|
||||||
|
|
||||||
<?php if (!empty($product)) : ?>
|
<?php if (!empty($product)) : ?>
|
||||||
|
<div class="content-wrap container">
|
||||||
|
<div class="content-layout content-layout--no-sidebar">
|
||||||
|
<div class="content-layout__primary">
|
||||||
<div
|
<div
|
||||||
class="aksrt-product-page container"
|
class="aksrt-product-page"
|
||||||
data-aksrt-product-page
|
data-aksrt-product-page
|
||||||
data-product-id="<?php echo esc_attr((string) $product_id); ?>"
|
data-product-id="<?php echo esc_attr((string) $product_id); ?>"
|
||||||
data-options='<?php echo esc_attr(wp_json_encode($options, JSON_UNESCAPED_UNICODE)); ?>'
|
data-options='<?php echo esc_attr(wp_json_encode($options, JSON_UNESCAPED_UNICODE)); ?>'
|
||||||
@@ -236,12 +239,16 @@ $author = $author_id > 0 ? get_userdata($author_id) : null;
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<!-- Merchant info -->
|
<!-- Merchant info -->
|
||||||
<?php if ($author) : ?>
|
<?php if ($author) :
|
||||||
|
$store_url = function_exists('aksrt_get_user_home_url')
|
||||||
|
? add_query_arg('tab', 'product', aksrt_get_user_home_url($author_id))
|
||||||
|
: get_author_posts_url($author_id);
|
||||||
|
?>
|
||||||
<div class="aksrt-product-page__merchant">
|
<div class="aksrt-product-page__merchant">
|
||||||
<img src="<?php echo esc_url(function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($author_id) : get_avatar_url($author_id)); ?>" alt="" class="aksrt-product-page__merchant-avatar">
|
<img src="<?php echo esc_url(function_exists('aksrt_get_avatar_url') ? aksrt_get_avatar_url($author_id) : get_avatar_url($author_id)); ?>" alt="" class="aksrt-product-page__merchant-avatar">
|
||||||
<div>
|
<div>
|
||||||
<strong><?php echo esc_html($author->display_name); ?></strong>
|
<strong><?php echo esc_html($author->display_name); ?></strong>
|
||||||
<a href="<?php echo esc_url(get_author_posts_url($author_id)); ?>?tab=products" class="aksrt-product-page__merchant-link"><?php esc_html_e('进入店铺', 'aksrt'); ?></a>
|
<a href="<?php echo esc_url($store_url); ?>" class="aksrt-product-page__merchant-link"><?php esc_html_e('进入店铺', 'aksrt'); ?></a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -312,33 +319,44 @@ $author = $author_id > 0 ? get_userdata($author_id) : null;
|
|||||||
|
|
||||||
<!-- Related products -->
|
<!-- Related products -->
|
||||||
<?php
|
<?php
|
||||||
$related_query = new WP_Query([
|
$related_items = [];
|
||||||
'post_type' => 'aksrt_product',
|
if ($shop && method_exists($shop, 'build_product_card_view')) {
|
||||||
'posts_per_page' => 6,
|
$related_q = new WP_Query([
|
||||||
'post_status' => 'publish',
|
'post_type' => 'aksrt_product',
|
||||||
'post__not_in' => [$product_id],
|
'posts_per_page' => 6,
|
||||||
'tax_query' => !empty($product['categories']) ? [[
|
'post_status' => 'publish',
|
||||||
'taxonomy' => 'aksrt_product_cat',
|
'post__not_in' => [$product_id],
|
||||||
'field' => 'term_id',
|
'ignore_sticky_posts' => true,
|
||||||
'terms' => wp_list_pluck($product['categories'], 'term_id'),
|
'no_found_rows' => true,
|
||||||
]] : [],
|
'update_post_meta_cache' => false,
|
||||||
'orderby' => 'rand',
|
'update_post_term_cache' => false,
|
||||||
]);
|
'tax_query' => !empty($product['categories']) ? [[
|
||||||
|
'taxonomy' => 'aksrt_product_cat',
|
||||||
|
'field' => 'term_id',
|
||||||
|
'terms' => wp_list_pluck($product['categories'], 'term_id'),
|
||||||
|
]] : [],
|
||||||
|
'orderby' => 'rand',
|
||||||
|
]);
|
||||||
|
while ($related_q->have_posts()) {
|
||||||
|
$related_q->the_post();
|
||||||
|
$card = $shop->build_product_card_view((int) get_the_ID());
|
||||||
|
if (!empty($card['id'])) {
|
||||||
|
$related_items[] = $card;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
wp_reset_postdata();
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
<?php if ($related_query->have_posts()) : ?>
|
<?php if (!empty($related_items)) : ?>
|
||||||
<section class="aksrt-product-page__related">
|
<section class="aksrt-product-page__related">
|
||||||
<h2><?php esc_html_e('相关推荐', 'aksrt'); ?></h2>
|
<h2 class="aksrt-product-page__related-title"><?php esc_html_e('相关推荐', 'aksrt'); ?></h2>
|
||||||
<div class="aksrt-product-page__related-grid">
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--default aksrt-product-page__related-grid">
|
||||||
<?php while ($related_query->have_posts()) : $related_query->the_post(); ?>
|
<?php foreach ($related_items as $related_product) :
|
||||||
<a href="<?php echo esc_url(get_permalink()); ?>" class="aksrt-product-page__related-card">
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
<?php $thumb = $shop ? $shop->resolve_main_image(get_the_ID()) : get_the_post_thumbnail_url(get_the_ID(), 'medium'); ?>
|
'product' => $related_product,
|
||||||
<?php if ($thumb) : ?>
|
'show_sales' => ((int) ($related_product['sales'] ?? 0) > 0),
|
||||||
<img src="<?php echo esc_url($thumb); ?>" alt="<?php the_title_attribute(); ?>" loading="lazy">
|
]);
|
||||||
<?php endif; ?>
|
endforeach; ?>
|
||||||
<h3><?php the_title(); ?></h3>
|
|
||||||
<strong>¥<?php echo esc_html(number_format((float) get_post_meta(get_the_ID(), '_aksrt_price', true), 2)); ?></strong>
|
|
||||||
</a>
|
|
||||||
<?php endwhile; wp_reset_postdata(); ?>
|
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
@@ -397,6 +415,11 @@ $author = $author_id > 0 ? get_userdata($author_id) : null;
|
|||||||
</div>
|
</div>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
|
|
||||||
|
</div><!-- .aksrt-product-page -->
|
||||||
|
</div><!-- .content-layout__primary -->
|
||||||
|
</div><!-- .content-layout -->
|
||||||
|
</div><!-- .content-wrap -->
|
||||||
|
|
||||||
<!-- Mobile purchase tabbar -->
|
<!-- Mobile purchase tabbar -->
|
||||||
<div class="aksrt-product-page__mobile-bar" data-aksrt-mobile-purchase>
|
<div class="aksrt-product-page__mobile-bar" data-aksrt-mobile-purchase>
|
||||||
<button type="button" class="aksrt-product-page__mobile-btn" data-aksrt-toggle-fav="<?php echo esc_attr((string) $product_id); ?>">
|
<button type="button" class="aksrt-product-page__mobile-btn" data-aksrt-toggle-fav="<?php echo esc_attr((string) $product_id); ?>">
|
||||||
|
|||||||
@@ -0,0 +1,59 @@
|
|||||||
|
<?php
|
||||||
|
/**
|
||||||
|
* Shared product card (archive / related / storefront).
|
||||||
|
*
|
||||||
|
* Expected args:
|
||||||
|
* - product: array from AKSRT_Shop::build_product_card_view()
|
||||||
|
* - show_sales: bool (optional)
|
||||||
|
* - sales_cfg: array (optional; used when show_sales not provided)
|
||||||
|
*
|
||||||
|
* @package AKSRT
|
||||||
|
*/
|
||||||
|
|
||||||
|
defined('ABSPATH') || exit;
|
||||||
|
|
||||||
|
$args = is_array($args ?? null) ? $args : [];
|
||||||
|
$product = is_array($args['product'] ?? null) ? $args['product'] : [];
|
||||||
|
if (empty($product) || empty($product['id'])) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
$sales = (int) ($product['sales'] ?? 0);
|
||||||
|
if (array_key_exists('show_sales', $args)) {
|
||||||
|
$show_sales = !empty($args['show_sales']);
|
||||||
|
} else {
|
||||||
|
$sales_cfg = is_array($args['sales_cfg'] ?? null) ? $args['sales_cfg'] : [];
|
||||||
|
$mode = (string) ($sales_cfg['show'] ?? 'show');
|
||||||
|
$min_sales = max(0, (int) ($sales_cfg['show_min'] ?? 0));
|
||||||
|
$show_sales = ($mode === 'show' && $sales > 0) || ($mode === 'threshold' && $sales >= $min_sales);
|
||||||
|
}
|
||||||
|
|
||||||
|
$title = (string) ($product['title'] ?? '');
|
||||||
|
$permalink = (string) ($product['permalink'] ?? '#');
|
||||||
|
$image = (string) ($product['image'] ?? '');
|
||||||
|
$excerpt = (string) ($product['excerpt'] ?? '');
|
||||||
|
$price = (float) ($product['price'] ?? 0);
|
||||||
|
?>
|
||||||
|
<article class="aksrt-product-card">
|
||||||
|
<a href="<?php echo esc_url($permalink !== '' ? $permalink : '#'); ?>" class="aksrt-product-card__link">
|
||||||
|
<?php if ($image !== '') : ?>
|
||||||
|
<div class="aksrt-product-card__image">
|
||||||
|
<img src="<?php echo esc_url($image); ?>" alt="<?php echo esc_attr($title); ?>" loading="lazy">
|
||||||
|
</div>
|
||||||
|
<?php else : ?>
|
||||||
|
<div class="aksrt-product-card__image aksrt-product-card__image--placeholder"><i class="fas fa-image" aria-hidden="true"></i></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="aksrt-product-card__body">
|
||||||
|
<h3 class="aksrt-product-card__title"><?php echo esc_html($title); ?></h3>
|
||||||
|
<?php if ($excerpt !== '') : ?>
|
||||||
|
<p class="aksrt-product-card__excerpt"><?php echo esc_html(wp_trim_words($excerpt, 15)); ?></p>
|
||||||
|
<?php endif; ?>
|
||||||
|
<div class="aksrt-product-card__footer">
|
||||||
|
<span class="aksrt-product-card__price">¥<?php echo esc_html(number_format($price, 2)); ?></span>
|
||||||
|
<?php if ($show_sales) : ?>
|
||||||
|
<span class="aksrt-product-card__sales"><?php printf(esc_html__('已售 %d', 'aksrt'), $sales); ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</a>
|
||||||
|
</article>
|
||||||
@@ -145,32 +145,11 @@ extract($args, EXTR_SKIP); // phpcs:ignore WordPress.PHP.DontExtract.extract_ext
|
|||||||
?>
|
?>
|
||||||
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--default uh-product-grid">
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--default uh-product-grid">
|
||||||
<?php foreach ($product_items as $product) :
|
<?php foreach ($product_items as $product) :
|
||||||
$sales = (int) ($product['sales'] ?? 0);
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
?>
|
'product' => $product,
|
||||||
<article class="aksrt-product-card">
|
'show_sales' => ((int) ($product['sales'] ?? 0) > 0),
|
||||||
<a href="<?php echo esc_url((string) ($product['permalink'] ?? '#')); ?>" class="aksrt-product-card__link">
|
]);
|
||||||
<?php if (!empty($product['image'])) : ?>
|
endforeach; ?>
|
||||||
<div class="aksrt-product-card__image">
|
|
||||||
<img src="<?php echo esc_url((string) $product['image']); ?>" alt="<?php echo esc_attr((string) ($product['title'] ?? '')); ?>" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="aksrt-product-card__image aksrt-product-card__image--placeholder"><i class="fas fa-image"></i></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__body">
|
|
||||||
<h3 class="aksrt-product-card__title"><?php echo esc_html((string) ($product['title'] ?? '')); ?></h3>
|
|
||||||
<?php if (!empty($product['excerpt'])) : ?>
|
|
||||||
<p class="aksrt-product-card__excerpt"><?php echo esc_html(wp_trim_words((string) $product['excerpt'], 15)); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__footer">
|
|
||||||
<span class="aksrt-product-card__price">¥<?php echo esc_html(number_format((float) ($product['price'] ?? 0), 2)); ?></span>
|
|
||||||
<?php if ($sales > 0) : ?>
|
|
||||||
<span class="aksrt-product-card__sales"><?php printf(esc_html__('已售 %d', 'aksrt'), $sales); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
</div>
|
||||||
<?php if ($product_max_pages > 1 && function_exists('aksrt_render_profile_pagination')) : ?>
|
<?php if ($product_max_pages > 1 && function_exists('aksrt_render_profile_pagination')) : ?>
|
||||||
<?php aksrt_render_profile_pagination($product_max_pages, $product_page, 'product_page'); ?>
|
<?php aksrt_render_profile_pagination($product_max_pages, $product_page, 'product_page'); ?>
|
||||||
|
|||||||
@@ -80,35 +80,11 @@ $order_options = [
|
|||||||
<?php if (!empty($products)) : ?>
|
<?php if (!empty($products)) : ?>
|
||||||
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
||||||
<?php foreach ($products as $product) :
|
<?php foreach ($products as $product) :
|
||||||
$sales = (int) ($product['sales'] ?? 0);
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
$mode = (string) ($sales_cfg['show'] ?? 'show');
|
'product' => $product,
|
||||||
$min_sales = max(0, (int) ($sales_cfg['show_min'] ?? 0));
|
'sales_cfg' => $sales_cfg,
|
||||||
$show_sales = ($mode === 'show' && $sales > 0) || ($mode === 'threshold' && $sales >= $min_sales);
|
]);
|
||||||
?>
|
endforeach; ?>
|
||||||
<article class="aksrt-product-card">
|
|
||||||
<a href="<?php echo esc_url((string) ($product['permalink'] ?? '#')); ?>" class="aksrt-product-card__link">
|
|
||||||
<?php if (!empty($product['image'])) : ?>
|
|
||||||
<div class="aksrt-product-card__image">
|
|
||||||
<img src="<?php echo esc_url((string) $product['image']); ?>" alt="<?php echo esc_attr((string) ($product['title'] ?? '')); ?>" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="aksrt-product-card__image aksrt-product-card__image--placeholder"><i class="fas fa-image"></i></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__body">
|
|
||||||
<h3 class="aksrt-product-card__title"><?php echo esc_html((string) ($product['title'] ?? '')); ?></h3>
|
|
||||||
<?php if (!empty($product['excerpt'])) : ?>
|
|
||||||
<p class="aksrt-product-card__excerpt"><?php echo esc_html(wp_trim_words((string) $product['excerpt'], 15)); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__footer">
|
|
||||||
<span class="aksrt-product-card__price">¥<?php echo esc_html(number_format((float) ($product['price'] ?? 0), 2)); ?></span>
|
|
||||||
<?php if ($show_sales) : ?>
|
|
||||||
<span class="aksrt-product-card__sales"><?php printf(esc_html__('已售 %d', 'aksrt'), $sales); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($max_pages > 1) : ?>
|
<?php if ($max_pages > 1) : ?>
|
||||||
|
|||||||
@@ -80,35 +80,11 @@ $order_options = [
|
|||||||
<?php if (!empty($products)) : ?>
|
<?php if (!empty($products)) : ?>
|
||||||
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
<div class="aksrt-product-archive__grid aksrt-product-archive__grid--<?php echo esc_attr($style); ?>" id="aksrt-product-grid" data-aksrt-product-grid>
|
||||||
<?php foreach ($products as $product) :
|
<?php foreach ($products as $product) :
|
||||||
$sales = (int) ($product['sales'] ?? 0);
|
get_template_part('templates/parts/shop/product', 'card', [
|
||||||
$mode = (string) ($sales_cfg['show'] ?? 'show');
|
'product' => $product,
|
||||||
$min_sales = max(0, (int) ($sales_cfg['show_min'] ?? 0));
|
'sales_cfg' => $sales_cfg,
|
||||||
$show_sales = ($mode === 'show' && $sales > 0) || ($mode === 'threshold' && $sales >= $min_sales);
|
]);
|
||||||
?>
|
endforeach; ?>
|
||||||
<article class="aksrt-product-card">
|
|
||||||
<a href="<?php echo esc_url((string) ($product['permalink'] ?? '#')); ?>" class="aksrt-product-card__link">
|
|
||||||
<?php if (!empty($product['image'])) : ?>
|
|
||||||
<div class="aksrt-product-card__image">
|
|
||||||
<img src="<?php echo esc_url((string) $product['image']); ?>" alt="<?php echo esc_attr((string) ($product['title'] ?? '')); ?>" loading="lazy">
|
|
||||||
</div>
|
|
||||||
<?php else : ?>
|
|
||||||
<div class="aksrt-product-card__image aksrt-product-card__image--placeholder"><i class="fas fa-image"></i></div>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__body">
|
|
||||||
<h3 class="aksrt-product-card__title"><?php echo esc_html((string) ($product['title'] ?? '')); ?></h3>
|
|
||||||
<?php if (!empty($product['excerpt'])) : ?>
|
|
||||||
<p class="aksrt-product-card__excerpt"><?php echo esc_html(wp_trim_words((string) $product['excerpt'], 15)); ?></p>
|
|
||||||
<?php endif; ?>
|
|
||||||
<div class="aksrt-product-card__footer">
|
|
||||||
<span class="aksrt-product-card__price">¥<?php echo esc_html(number_format((float) ($product['price'] ?? 0), 2)); ?></span>
|
|
||||||
<?php if ($show_sales) : ?>
|
|
||||||
<span class="aksrt-product-card__sales"><?php printf(esc_html__('已售 %d', 'aksrt'), $sales); ?></span>
|
|
||||||
<?php endif; ?>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</a>
|
|
||||||
</article>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<?php if ($max_pages > 1) : ?>
|
<?php if ($max_pages > 1) : ?>
|
||||||
|
|||||||
Reference in New Issue
Block a user