[custom_product_carousel cat="your-category-slug" count="12"]
这是简码
add_shortcode('custom_product_carousel', function($atts){
$atts = shortcode_atts([
'cat' => '',
'count' => 30,
], $atts);
if(empty($atts['cat'])) return '';
$args = [
'post_type' => 'product',
'posts_per_page' => intval($atts['count']),
'post_status' => 'publish',
'ignore_sticky_posts' => 1,
'tax_query' => [[
'taxonomy' => 'product_cat',
'field' => 'slug',
'terms' => $atts['cat']
]]
];
$loop = new WP_Query($args);
if(!$loop->have_posts()) return '';
ob_start();
$list = [];
while($loop->have_posts()): $loop->the_post();
global $product;
$gallery = $product->get_gallery_image_ids();
$img1 = get_the_post_thumbnail_url(get_the_ID(),'large');
$img2 = isset($gallery[0]) ? wp_get_attachment_image_url($gallery[0], 'large') : $img1;
$list[] = [
'title' => get_the_title(),
'url' => get_permalink(),
'price' => $product->get_price_html(),
'img1' => $img1,
'img2' => $img2,
];
endwhile; wp_reset_postdata();
$count = count($list);
?>
<div class="cpc3-wrap">
<div class="cpc3-carousel-wrap">
<div class="cpc3-carousel">
<?php foreach($list as $i=>$item): ?>
<div class="cpc3-item" data-idx="<?php echo $i; ?>">
<a href="<?php echo esc_url($item['url']); ?>" class="cpc3-img-wrap">
<img src="<?php echo esc_url($item['img1']); ?>" class="cpc3-img img-1" alt="">
<img src="<?php echo esc_url($item['img2']); ?>" class="cpc3-img img-2" alt="">
</a>
<div class="cpc3-bottom-line"></div>
<div class="cpc3-meta">
<span class="cpc3-title"><?php echo esc_html($item['title']); ?></span>
<span class="cpc3-price"><?php echo wp_kses_post($item['price']); ?></span>
</div>
</div>
<?php endforeach; ?>
</div>
</div>
<button class="cpc3-arrow left cpc3-arrow-pc" aria-label="prev">
<svg fill="#000000" viewBox="0 0 24 24" id="left-circle-1" data-name="Flat Line" xmlns="http://www.w3.org/2000/svg" class="icon flat-line" width="44" height="44">
<circle cx="12" cy="12" r="9" style="fill: #F05B2D; stroke-width: 2;"></circle>
<polyline points="13 9 10 12 13 15" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline>
<circle cx="12" cy="12" r="9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></circle>
</svg>
</button>
<button class="cpc3-arrow right cpc3-arrow-pc" aria-label="next">
<svg fill="#000000" viewBox="0 0 24 24" id="right-circle" data-name="Flat Line" xmlns="http://www.w3.org/2000/svg" class="icon flat-line" width="44" height="44">
<circle cx="12" cy="12" r="9" style="fill: #F05B2D; stroke-width: 2;"></circle>
<polyline points="11 15 14 12 11 9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></polyline>
<circle cx="12" cy="12" r="9" style="fill: none; stroke: #fff; stroke-linecap: round; stroke-linejoin: round; stroke-width: 2;"></circle>
</svg>
</button>
<div class="cpc3-mobile-struct" style="display:none;">
<div class="cpc3-m-nav">
<button class="cpc3-m-arrow m-left" aria-label="prev">
<svg viewBox="0 0 1024 1024" class="icon" width="30" height="30" fill="#b5b5b5"><path d="M768 903.232l-50.432 56.768L256 512l461.568-448 50.432 56.768L364.928 512z"></path></svg>
</button>
<div class="cpc3-m-title"></div>
<button class="cpc3-m-arrow m-right" aria-label="next">
<svg viewBox="0 0 1024 1024" class="icon" width="30" height="30" fill="#b5b5b5"><path d="M256 120.768L306.432 64 768 512l-461.568 448L256 903.232 659.072 512z"></path></svg>
</button>
</div>
<div class="cpc3-m-price"></div>
<div class="cpc3-m-img-touch">
<div class="cpc3-m-img-wrap"></div>
</div>
<div class="cpc3-m-progress"></div>
</div>
</div>
<style>
@import url('https://fonts.googleapis.com/css2?family=Marcellus:wght@400&display=swap');
.cpc3-wrap { width:100%; position:relative; padding:0 0 24px 0;}
.cpc3-carousel-wrap { width:100%; overflow:hidden; position:relative; }
.cpc3-carousel {
display: flex;
flex-wrap: nowrap;
transition: transform .55s cubic-bezier(.5,.1,.1,1);
gap: 40px;
will-change:transform;
}
.cpc3-item {
flex: 0 0 calc((100% - 80px) / 3.5);
max-width: calc((100% - 80px) / 3.5);
box-sizing: border-box;
background: none;
position: relative;
min-width: 0;
display: flex;
flex-direction: column;
align-items: stretch;
}
.cpc3-img-wrap {
display: block;
width: 100%;
aspect-ratio: 1/1;
position: relative;
overflow: hidden;
background: #fff;
}
.cpc3-img {
width: 100%;
height: 100%;
aspect-ratio: 1/1;
object-fit: cover;
transition: opacity .42s;
position: absolute;
left: 0; top: 0;
}
.cpc3-img.img-1 { z-index:1; opacity:1; }
.cpc3-img.img-2 { z-index:2; opacity:0; }
.cpc3-img-wrap:hover .img-2 { opacity:1; }
.cpc3-img-wrap:hover .img-1 { opacity:0; }
.cpc3-bottom-line {
height: 1.5px;
width: 100%;
background: #e5decf;
}
.cpc3-meta {
display: flex;
justify-content: space-between;
align-items: flex-end;
font-family: 'Marcellus', serif;
font-size: 18px;
margin-top: 20px;
margin-bottom: 0;
width: 100%;
min-height: 24px;
}
.cpc3-title {
font-size: 18px;
color: #222;
font-family: 'Marcellus', serif;
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
max-width: 65%;
}
.cpc3-price {
font-size: 18px;
color: #222;
font-family: 'Marcellus', serif;
white-space: nowrap;
}
.cpc3-arrow,
.cpc3-arrow:focus,
.cpc3-arrow:active,
.cpc3-arrow:hover {
background: transparent !important;
border: none !important;
box-shadow: none !important;
outline: none !important;
}
.cpc3-arrow svg {
background: transparent !important;
box-shadow: none !important;
border: none !important;
outline: none !important;
}
.cpc3-arrow {
position: absolute;
top: 50%;
transform: translateY(-50%);
cursor: pointer;
padding: 0;
z-index: 8;
opacity: 0;
transition: .22s;
}
.cpc3-wrap:hover .cpc3-arrow { opacity:1;}
.cpc3-arrow.left, .cpc3-arrow.cpc3-arrow-pc.left { left: 0;}
.cpc3-arrow.right, .cpc3-arrow.cpc3-arrow-pc.right { right: 0;}
.cpc3-mobile-struct {display:none;}
@media (max-width:900px) {
.cpc3-item { flex: 0 0 100%; max-width:100%; }
.cpc3-carousel { gap:14px;}
}
@media (max-width:700px) {
.cpc3-carousel-wrap,
.cpc3-carousel,
.cpc3-meta,
.cpc3-bottom-line,
.cpc3-item,
.cpc3-img-wrap,
.cpc3-arrow.cpc3-arrow-pc { display: none !important; }
.cpc3-mobile-struct { display: block !important; }
.cpc3-m-nav {
display:flex;
justify-content:space-between;
align-items:center;
gap:8px;
margin-bottom:10px;
}
.cpc3-m-title {
flex:1;
font-size:17px;
color:#222;
font-family:'Marcellus',serif;
font-weight:400;
line-height:1.3;
display:-webkit-box;
-webkit-line-clamp:2;
-webkit-box-orient:vertical;
overflow:hidden;
text-overflow:ellipsis;
white-space:normal;
text-align:center;
}
.cpc3-m-arrow {
background:transparent !important;
border:none !important;
box-shadow:none !important;
outline:none !important;
padding:0 6px !important;
min-width:28px;
min-height:28px;
display:flex;
align-items:center;
justify-content:center;
transition:.2s;
user-select:none;
}
.cpc3-m-arrow:active,
.cpc3-m-arrow:focus { background:transparent !important; }
.cpc3-m-price {
text-align:center;
font-size:16px;
color:#222;
font-family:'Marcellus',serif;
margin-bottom:10px;
margin-top:2px;
}
.cpc3-m-img-touch {
width:100%;
overflow:hidden;
margin-bottom:18px;
position:relative;
}
.cpc3-m-img-wrap {
width:100%;
aspect-ratio:1/1;
background:#fff;
position:relative;
overflow:hidden;
}
.cpc3-m-img {
width:100%;
height:100%;
object-fit:cover;
aspect-ratio:1/1;
display:block;
}
.cpc3-m-progress {
margin:14px auto 0 auto;
display:flex;
justify-content:center;
align-items:center;
gap:7px;
}
.cpc3-m-progress-bar {
width:28px;
height:3.5px;
border-radius:2px;
background:#e5decf;
transition:.22s;
cursor:pointer;
}
.cpc3-m-progress-bar.active {
background:#F05B2D;
}
}
</style>
<script>
(function(){
var wrap = document.currentScript.parentElement,
carousel = wrap.querySelector('.cpc3-carousel'),
items = wrap ? wrap.querySelectorAll('.cpc3-item') : [],
btnL = wrap ? wrap.querySelector('.cpc3-arrow.left') : null,
btnR = wrap ? wrap.querySelector('.cpc3-arrow.right') : null;
var pcShow = 3.5, gap = 40, idx = 0, max = items.length, isMobile = false;
function setTransform() {
isMobile = window.innerWidth<=900;
var gapPx = isMobile ? 14 : gap;
var showNum = isMobile ? 1 : pcShow;
var offset = idx * (100 / showNum + gapPx * 100 / (showNum * wrap.offsetWidth));
if(carousel) carousel.style.transform = 'translateX(-' + offset + '%)';
if(btnL) btnL.style.display = (idx===0?'none':'');
if(btnR) btnR.style.display = (idx >= (max-showNum) ? 'none' : '');
}
function go(dir){
var showNum = window.innerWidth<=900 ? 1 : pcShow;
idx += dir;
if(idx<0) idx=0;
if(idx>max-showNum) idx=max-showNum;
setTransform();
}
if(btnL) btnL.onclick = function(){ go(-1);}
if(btnR) btnR.onclick = function(){ go(1);}
var sx, dx;
if(carousel){
carousel.addEventListener('touchstart',function(e){ sx = e.touches[0].clientX; dx=0; },{passive:true});
carousel.addEventListener('touchmove',function(e){ dx = e.touches[0].clientX-sx; },{passive:true});
carousel.addEventListener('touchend',function(){
if(Math.abs(dx)>40){
if(dx<0) go(1);
else go(-1);
}
});
}
window.addEventListener('resize',function(){ setTimeout(setTransform,120); });
setTimeout(setTransform,120);
// Mobile
var mStruct = wrap.querySelector('.cpc3-mobile-struct');
if(mStruct){
var list = <?php echo json_encode($list); ?>, midx = 0;
var titleBox = mStruct.querySelector('.cpc3-m-title'),
priceBox = mStruct.querySelector('.cpc3-m-price'),
imgBox = mStruct.querySelector('.cpc3-m-img-wrap'),
progressBox = mStruct.querySelector('.cpc3-m-progress'),
imgTouchBox = mStruct.querySelector('.cpc3-m-img-touch'),
leftBtn = mStruct.querySelector('.cpc3-m-arrow.m-left'),
rightBtn = mStruct.querySelector('.cpc3-m-arrow.m-right');
function renderMobile(){
var cur = list[midx];
titleBox.textContent = cur.title;
priceBox.innerHTML = cur.price;
imgBox.innerHTML = '<a href="'+cur.url+'"><img class="cpc3-m-img" src="'+cur.img1+'" alt=""></a>';
var p = '';
for(var i=0;i<list.length;i++){
p += '<div class="cpc3-m-progress-bar'+(i==midx?' active':'')+'" data-idx="'+i+'"></div>';
}
progressBox.innerHTML = p;
leftBtn.style.visibility = midx === 0 ? 'hidden' : 'visible';
rightBtn.style.visibility = midx === list.length-1 ? 'hidden' : 'visible';
}
// 进度条点击
mStruct.addEventListener('click', function(e){
var t = e.target;
if(t.classList.contains('cpc3-m-progress-bar')){
var i = parseInt(t.getAttribute('data-idx'));
if(!isNaN(i)) {
midx = i; renderMobile();
}
}
});
// 左右按钮
leftBtn.onclick = function(){ if(midx>0){midx--;renderMobile();} }
rightBtn.onclick = function(){ if(midx<list.length-1){midx++;renderMobile();} }
// 图片区域左右滑动
var touchX = 0, moveX = 0, dragging = false;
if(imgTouchBox){
imgTouchBox.addEventListener('touchstart',function(e){
if(e.touches.length===1){ touchX = e.touches[0].clientX; moveX=0; dragging=true; }
},{passive:true});
imgTouchBox.addEventListener('touchmove',function(e){
if(dragging){ moveX = e.touches[0].clientX - touchX; }
},{passive:true});
imgTouchBox.addEventListener('touchend',function(){
if(dragging && Math.abs(moveX)>40){
if(moveX<0 && midx<list.length-1){ midx++;renderMobile(); }
else if(moveX>0 && midx>0){ midx--;renderMobile(); }
}
dragging = false;
},{passive:true});
}
renderMobile();
}
})();
</script>
<?php
return ob_get_clean();
});