feat: release news and store experience updates

This commit is contained in:
Codex
2026-07-26 11:09:11 +08:00
parent 2b37713791
commit c63bef311c
100 changed files with 2519 additions and 105 deletions
+44 -18
View File
@@ -1,27 +1,29 @@
# B2B Trade
B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题提供服务项目、施工案例、门店介绍、常见问题和联系方式;联系页只展示电话、邮箱、WhatsApp、营业时间与地图导航,不包含提交表单、邮件发送处理器或 SMTP 依赖。
B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题提供服务项目、施工案例、新闻资讯、门店介绍、常见问题和联系方式;联系页只展示门店对外信息、营业时间与地图导航,不包含提交表单、邮件发送处理器或 SMTP 依赖。
## 运行要求
- WordPress 6.8 或更高版本
- PHP 8.1 或更高版本
- 当前发布版:2.1.0
- 当前发布版:2.2.0
- 已针对 WordPress 7.0 系列配置回归环境
前端依赖仅包含主题内置的 Bootstrap 5.3.8 CSS 和 bundle JS。字体使用操作系统字体栈,不会向字体、脚本或样式 CDN 发起请求。
首页信任栏、首页咨询区、关于页资料区和联系行动区使用主题内置的汽车施工场景背景图;图片均随主题本地加载,不依赖外部图床。
## 页面与内容结构
首页固定显示 5 个板块:
1. 首屏定位与双按钮
2. 四项信任指标
3. 服务项目(最多 6 项)
4. 案例作品(最多 6 项)
3. 服务项目轮播(最多 6 项,桌面每屏 2 项)
4. 案例作品轮播(最多 6 项,桌面每屏 2 项)
5. 联系门店行动区
关于页承载门店介绍、信任指标、环境图片、外部视频链接和服务文档。FAQ 页复用 8 项手风琴内容;联系页按配置展示门店信息和地图卡片。
关于页承载门店介绍、信任指标、环境图片、外部视频链接和服务文档。FAQ 页复用 8 项手风琴内容;联系页按配置展示门店信息和地图卡片。新闻资讯使用 WordPress 原生文章和分类,列表页每页显示 9 篇,支持分类、标签、日期归档、搜索、RSS 和独立详情页。
主题注册:
@@ -30,13 +32,15 @@ B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题
- `case_type` 案例分类法
- `fragrance-capability` 图片尺寸(760 × 720,硬裁切)
服务图片的显示优先级为:
服务卡片图片的显示优先级为:
1. WordPress 特色图片
2. 旧站点的 `_service_image` URL
3. 主题内置的中性 SVG 占位图
1. 自定义横版封面 `_fragrance_service_cover_id`
2. 产品初始化数据中的主题横版封面
3. WordPress 特色图片
4. 旧站点的 `_service_image` URL
5. 主题内置的中性 SVG 占位图
列表和首页使用 `fragrance-capability`详情页使用 `large`
首页和列表优先使用 4:3 横版封面;服务详情页使用 `large` 尺寸的特色图片,可完整展示产品参数海报
## 首次激活
@@ -44,6 +48,8 @@ B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题
- 创建 7 个默认服务,并使用 `_fragrance_seed_key` 防止重复;
- 创建或复用 `home``about``faq``contact` 页面;
- 未配置文章页时创建或复用 `news` 页面,并将其设置为 WordPress 文章页;
- 已配置文章页时保留现有页面与 URL,不强制覆盖;
- 为约定页面补齐模板,但不修改已有正文;
- 不会自动发布或恢复用户已有的草稿、私密页或回收站页面;
- 将已发布的 `home` 设置为静态首页;
@@ -51,7 +57,24 @@ B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题
重复激活和重复执行初始化不会增加服务或页面数量。失败信息和未发布页面状态会在后台显示管理员通知。
未分配主导航时,主题输出:首页、服务项目、案例作品、关于门店、常见问题、联系我们。已分配菜单但少于两个菜单项时,后台同样会提醒
未分配主导航时,主题输出:首页、服务项目、案例作品、新闻资讯、关于门店、常见问题、联系我们。已分配菜单时,主题不会自动增加新闻入口;如果菜单缺少 WordPress 文章页,后台会提示管理员手动添加
## 新闻资讯
- 后台通过 WordPress“文章”发布新闻,不注册额外文章类型;
- 新站点的新闻列表默认位于 `/news/`,升级站点保留已有文章页地址;
- 列表卡片显示特色图片、分类、日期、标题和摘要,无图片时使用主题内置占位图;
- 分类、标签、日期和作者归档复用新闻卡片样式;
- 新闻详情包含上一篇、下一篇和联系门店行动区,不显示评论区;
- 主题不修改全站固定链接规则,也不会自动创建新闻分类或示例新闻。
## 服务与案例一键初始化
主题随包提供 5 个 KDX 隐形车衣产品服务、6 篇汽车改色案例和 62 张图片,但不会在主题激活时自动写入。管理员可进入“外观 → 初始化内容”,点击“一键初始化服务与案例”后将内容复制到当前站点的文章与媒体库。
导入器使用稳定的内容和图片标识防止重复;已有同名服务或案例会被保留且不会被覆盖。中途因写入失败留下的草稿可以再次执行导入以继续补齐,已发布内容不会重复生成。
首页的服务与案例区域使用原生响应式轮播,支持箭头、分页圆点、触摸滑动和 9 秒自动播放;鼠标悬停、键盘聚焦或触摸操作时会暂停,系统启用“减少动态效果”时自动播放关闭。
## 外观配置
@@ -64,13 +87,15 @@ B2B Trade 是一个面向汽车贴膜门店的 WordPress 经典主题。主题
- 常见问题
- 联系方式与社交链接
主题已预置康得新合肥新创贴膜中心的对外名称、主营品牌、授权级别、所在城市、门店联系人、电话、地址与营业时间。这些信息仍可在“联系方式与社交链接”板块中逐项修改。页脚 ICP 备案号及备案查询链接也在此配置;备案号留空时前台不会显示。
视频链接不会嵌入页面或打开弹窗;配置后会在新标签页直接打开,并带有 `noopener noreferrer`
地图卡片按以下顺序决定是否显示
地图与导航按以下顺序工作
1. 优先使用“地图导航链接”;
2. 没有显式链接但门店地址非空时,生成百度地图导航地址
3. 两项都为空时,隐藏地图卡片。
1. “地图导航链接”用于覆盖“打开地图导航”按钮的目标地址
2. 已配置有效的百度地图经纬度时,内嵌地图固定显示该坐标,并以门店名称和详细地址作为标注内容
3. 未配置坐标时,使用门店名称检索并将结果限制在所在城市;门店名称为空时回退使用门店地址,检索词也为空时隐藏地图卡片。
Hero 按钮的站内默认路径会通过 `home_url()` 解析,支持 WordPress 子目录安装与多站点路径。
@@ -79,10 +104,10 @@ Hero 按钮的站内默认路径会通过 `home_url()` 解析,支持 WordPress
1. 将主题目录复制到 WordPress 的 `wp-content/themes/`
2. 在“外观 → 主题”中激活 B2B Trade。
3. 在“外观 → 菜单”中创建并分配主导航;未分配时主题会显示默认导航。
4. 在“外观 → 自定义 → 门店首页”中填写真实门店信息。
5. 在服务项目和案例后台上传实际图片与内容。
4. 在“外观 → 自定义 → 门店首页”中核对并按需更新门店信息。
5. 在服务项目和案例后台上传实际图片与内容,并通过“文章”发布新闻资讯
发布前应在 WordPress 6.8 或更高版本、PHP 8.1 或更高版本环境中检查首页、列表详情、关于、FAQ、联系、搜索与 404 页面,并确认桌面和移动端没有资源 404、控制台错误或横向滚动。
发布前应在 WordPress 6.8 或更高版本、PHP 8.1 或更高版本环境中检查首页、服务、案例、新闻列表详情、新闻归档、关于、FAQ、联系、搜索与 404 页面,并确认桌面和移动端没有资源 404、控制台错误或横向滚动。
详细验收项见 `CODE_REVIEW_STANDARD.md`,清理范围与兼容策略见 `CODE_CLEANUP_PLAN.md`
@@ -92,6 +117,7 @@ Hero 按钮的站内默认路径会通过 `home_url()` 解析,支持 WordPress
- 保留 `store_map_url` 设置键。
- 保留 `_service_image` 只读回退,不自动改写或删除旧元数据。
- 旧的 `fragrance_trade_setup_done` 仅用于识别已有安装;新的流程以 `fragrance_trade_schema_version` 为准。
- schema 4 只在未配置有效文章页时创建 `/news/`,不会覆盖已有 `page_for_posts`
- 旧的联系页 URL 即使带有额外查询参数也能打开,但主题不再生成、读取、显示或传递服务名称。
## 许可证
+1 -1
View File
@@ -48,7 +48,7 @@ get_header();
<?php endif; ?>
<?php if ( have_posts() ) : ?>
<div class="case-grid">
<div class="case-grid case-grid-archive">
<?php while ( have_posts() ) : the_post(); ?>
<a class="case-card" href="<?php the_permalink(); ?>">
<?php if ( has_post_thumbnail() ) : ?>
+2 -5
View File
@@ -29,13 +29,10 @@ get_header();
<p><?php esc_html_e( '从车漆保护、外观改色到车窗隔热,按车型与使用需求查看可选项目。', 'fragrance-trade' ); ?></p>
</header>
<div class="pb-5">
<div class="capability-grid">
<div class="capability-grid capability-grid-archive">
<?php while ( have_posts() ) : the_post(); ?>
<?php
$image = get_post_meta( get_the_ID(), '_service_image', true );
?>
<article class="capability-card">
<div class="capability-image"><a href="<?php the_permalink(); ?>"><?php if ( has_post_thumbnail() ) : ?><?php the_post_thumbnail( 'fragrance-capability', array( 'class' => 'img-fluid', 'loading' => 'lazy', 'decoding' => 'async' ) ); ?><?php else : ?><img src="<?php echo esc_url( $image ? $image : fragrance_trade_asset_uri( 'images/products/placeholder-01.svg' ) ); ?>" alt="<?php the_title_attribute(); ?>" class="img-fluid" loading="lazy" decoding="async"><?php endif; ?></a></div>
<div class="capability-image"><a href="<?php the_permalink(); ?>"><?php echo fragrance_trade_service_card_image( get_the_ID() ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a></div>
<div class="capability-body">
<p class="capability-label"><?php esc_html_e( '贴膜服务', 'fragrance-trade' ); ?></p>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
+58 -12
View File
@@ -5,18 +5,64 @@ if ( ! defined( 'ABSPATH' ) ) {
}
get_header();
$is_news_archive = is_category() || is_tag() || is_date() || is_author();
?>
<main id="primary" class="site-main container py-5 fragrance-content-area">
<header class="page-header mb-5"><h1 class="page-title"><?php the_archive_title(); ?></h1><?php the_archive_description( '<div class="archive-description">', '</div>' ); ?></header>
<?php if ( have_posts() ) : ?>
<div class="row g-5">
<?php while ( have_posts() ) : the_post(); ?>
<div class="col-12"><?php get_template_part( 'template-parts/content', get_post_type() ); ?></div>
<?php endwhile; ?>
<?php if ( $is_news_archive ) : ?>
<main id="primary" class="site-main">
<div class="page-content container news-page news-archive">
<?php
get_template_part(
'template-parts/breadcrumb',
null,
array(
'items' => array(
array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ),
array( 'label' => __( '新闻资讯', 'fragrance-trade' ), 'url' => fragrance_trade_news_url() ),
array( 'label' => wp_strip_all_tags( get_the_archive_title() ), 'url' => null ),
),
)
);
?>
<header class="news-page-header">
<p class="section-eyebrow"><?php esc_html_e( '新闻归档', 'fragrance-trade' ); ?></p>
<h1><?php the_archive_title(); ?></h1>
<?php the_archive_description( '<div class="archive-description">', '</div>' ); ?>
</header>
<?php if ( have_posts() ) : ?>
<div class="news-grid">
<?php
while ( have_posts() ) :
the_post();
get_template_part( 'template-parts/content', 'news-card' );
endwhile;
?>
</div>
<div class="news-pagination">
<?php the_posts_pagination(); ?>
</div>
<?php else : ?>
<section class="news-empty">
<h2><?php esc_html_e( '此归档暂时没有新闻', 'fragrance-trade' ); ?></h2>
<p><?php esc_html_e( '可以返回新闻资讯页面浏览其他内容。', 'fragrance-trade' ); ?></p>
<a class="btn btn-b2b-primary" href="<?php echo esc_url( fragrance_trade_news_url() ); ?>"><?php esc_html_e( '返回新闻资讯', 'fragrance-trade' ); ?></a>
</section>
<?php endif; ?>
</div>
<?php the_posts_pagination(); ?>
<?php else : ?>
<?php get_template_part( 'template-parts/content', 'none' ); ?>
<?php endif; ?>
</main>
</main>
<?php else : ?>
<main id="primary" class="site-main container py-5 fragrance-content-area">
<header class="page-header mb-5"><h1 class="page-title"><?php the_archive_title(); ?></h1><?php the_archive_description( '<div class="archive-description">', '</div>' ); ?></header>
<?php if ( have_posts() ) : ?>
<div class="row g-5">
<?php while ( have_posts() ) : the_post(); ?>
<div class="col-12"><?php get_template_part( 'template-parts/content', get_post_type() ); ?></div>
<?php endwhile; ?>
</div>
<?php the_posts_pagination(); ?>
<?php else : ?>
<?php get_template_part( 'template-parts/content', 'none' ); ?>
<?php endif; ?>
</main>
<?php endif; ?>
<?php get_footer(); ?>
+547 -5
View File
@@ -416,7 +416,9 @@ img {
/* ---- Trust Strip ---- */
.trust-strip {
color: var(--b2b-surface);
background: var(--b2b-ink);
background:
linear-gradient(90deg, rgba(20, 20, 18, 0.9), rgba(20, 20, 18, 0.76)),
url("../images/trust-workshop-bg.jpg") 62% 55% / cover no-repeat;
}
.trust-metric {
@@ -460,6 +462,10 @@ img {
background: var(--b2b-line);
}
.capability-grid-archive {
background: transparent;
}
.capability-card {
display: grid;
min-width: 0;
@@ -474,7 +480,14 @@ img {
background: var(--b2b-mist);
}
.capability-image a {
display: block;
width: 100%;
height: 100%;
}
.capability-image img {
display: block;
width: 100%;
height: 100%;
object-fit: cover;
@@ -536,6 +549,139 @@ img {
align-self: flex-start;
}
/* ---- Homepage Carousels ---- */
.b2b-carousel {
--carousel-gap: 1px;
--carousel-items: 1;
}
.services-carousel {
--carousel-items: 2;
}
.cases-carousel {
--carousel-items: 2;
}
.b2b-carousel-viewport {
overflow-x: auto;
overflow-y: hidden;
overscroll-behavior-x: contain;
scroll-snap-type: x mandatory;
scrollbar-width: none;
-webkit-overflow-scrolling: touch;
}
.b2b-carousel-viewport::-webkit-scrollbar {
display: none;
}
.b2b-carousel .b2b-carousel-track {
display: grid;
width: auto;
grid-auto-flow: column;
grid-auto-columns: 100%;
grid-template-columns: none;
gap: var(--carousel-gap);
}
.services-carousel .b2b-carousel-track {
grid-auto-columns: calc(50% - 0.5px);
}
.cases-carousel .b2b-carousel-track {
grid-auto-columns: calc(50% - 0.5px);
}
.b2b-carousel-slide {
min-width: 0;
scroll-snap-align: start;
}
.b2b-carousel-controls {
display: none;
min-height: 44px;
margin-top: 1.5rem;
align-items: center;
justify-content: center;
gap: 1.25rem;
}
.b2b-carousel.is-ready .b2b-carousel-controls {
display: flex;
}
.b2b-carousel.is-ready.has-single-page .b2b-carousel-controls {
display: none;
}
.b2b-carousel-arrow,
.b2b-carousel-dot {
appearance: none;
color: var(--b2b-ink);
background: transparent;
border: 0;
border-radius: 0;
cursor: pointer;
}
.b2b-carousel-arrow {
display: inline-flex;
width: 44px;
height: 44px;
padding: 0;
align-items: center;
justify-content: center;
border: 1px solid var(--b2b-line);
font-size: 1.1rem;
line-height: 1;
transition:
color 180ms ease,
background-color 180ms ease,
border-color 180ms ease,
transform 180ms ease;
}
.b2b-carousel-arrow:hover {
color: var(--b2b-surface);
background: var(--b2b-ink);
border-color: var(--b2b-ink);
transform: translateY(-2px);
}
.b2b-carousel-arrow:active {
transform: translateY(0);
}
.b2b-carousel-arrow:focus-visible,
.b2b-carousel-dot:focus-visible {
outline: 2px solid var(--b2b-ink);
outline-offset: 3px;
}
.b2b-carousel-dots {
display: flex;
min-width: 64px;
align-items: center;
justify-content: center;
gap: 0.6rem;
}
.b2b-carousel-dot {
width: 7px;
height: 7px;
padding: 0;
background: var(--b2b-line);
transition:
width 220ms ease,
background-color 220ms ease;
}
.b2b-carousel-dot.is-active {
width: 24px;
background: var(--b2b-ink);
}
/* ---- Case Grid ---- */
.cases-section {
background: var(--b2b-mist);
@@ -548,6 +694,10 @@ img {
background: var(--b2b-line);
}
.case-grid-archive {
background: transparent;
}
.case-card {
position: relative;
display: block;
@@ -600,7 +750,9 @@ img {
/* ---- CTA Section ---- */
.cta-section {
background: var(--b2b-ink);
background:
linear-gradient(90deg, rgba(20, 20, 18, 0.88), rgba(20, 20, 18, 0.7)),
url("../images/consultation-studio-bg.jpg") center 58% / cover no-repeat;
color: var(--b2b-surface);
text-align: center;
padding: 5rem 0;
@@ -881,7 +1033,9 @@ img {
/* ---- Documents Section ---- */
.documents-section {
color: rgba(250, 250, 248, 0.65);
background: var(--b2b-ink);
background:
linear-gradient(90deg, rgba(20, 20, 18, 0.95), rgba(20, 20, 18, 0.86)),
url("../images/trust-workshop-bg.jpg") center 55% / cover no-repeat;
}
.documents-section h2,
@@ -902,7 +1056,7 @@ img {
min-width: 0;
padding: 1.75rem;
gap: 1rem;
background: var(--b2b-ink);
background: rgba(28, 28, 26, 0.88);
}
.document-grid article > span {
@@ -969,10 +1123,21 @@ img {
}
.footer-bottom {
align-items: center;
border-color: rgba(250, 250, 248, 0.08) !important;
font-size: 0.78rem;
}
.footer-icp {
text-align: center;
}
.footer-icp a {
text-decoration: underline;
text-decoration-color: rgba(250, 250, 248, 0.22);
text-underline-offset: 0.2em;
}
/* ---- WordPress Content Area ---- */
.fragrance-content-area {
min-height: 65vh;
@@ -1101,14 +1266,35 @@ textarea:focus-visible {
/* ---- About Page CTA ---- */
.about-cta {
padding: 5rem 0;
background: var(--b2b-mist);
color: var(--b2b-surface);
background:
linear-gradient(90deg, rgba(20, 20, 18, 0.88), rgba(20, 20, 18, 0.7)),
url("../images/consultation-studio-bg.jpg") center 58% / cover no-repeat;
text-align: center;
}
.about-cta h2 {
color: var(--b2b-surface);
font-size: clamp(1.8rem, 3vw, 2.4rem);
}
.about-cta .section-lead {
color: rgba(250, 250, 248, 0.74);
}
.about-cta .btn-b2b-primary {
color: var(--b2b-ink);
background: var(--b2b-surface);
border-color: var(--b2b-surface);
}
.about-cta .btn-b2b-primary:hover,
.about-cta .btn-b2b-primary:focus {
color: var(--b2b-ink);
background: var(--b2b-mist);
border-color: var(--b2b-mist);
}
/* ---- Contact Page ---- */
.contact-section {
padding-top: 0;
@@ -1289,6 +1475,319 @@ textarea:focus-visible {
color: var(--b2b-ink-soft);
}
/* ---- News ---- */
.news-page {
padding-bottom: clamp(5rem, 8vw, 8rem);
}
.news-page-header {
max-width: 760px;
padding: 1.5rem 0 clamp(3rem, 6vw, 5rem);
}
.news-page-header h1 {
margin-bottom: 1.25rem;
font-family: var(--b2b-font-display);
font-size: clamp(2.7rem, 5vw, 4.8rem);
font-weight: 300;
}
.news-page-header > p:last-child,
.news-page-header .archive-description {
color: var(--b2b-ink-soft);
font-size: 1.05rem;
line-height: 1.8;
}
.news-page-header .archive-description > :last-child {
margin-bottom: 0;
}
.news-grid {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: clamp(1.25rem, 2.5vw, 2rem);
}
.news-card {
display: flex;
min-width: 0;
height: 100%;
overflow: hidden;
background: var(--b2b-surface);
border: 1px solid var(--b2b-line);
flex-direction: column;
transition:
border-color 180ms ease,
transform 220ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.news-card:hover {
border-color: var(--b2b-ink-muted);
transform: translateY(-3px);
}
.news-card-media {
display: block;
aspect-ratio: 16 / 9;
overflow: hidden;
background: var(--b2b-mist);
}
.news-card-media img {
width: 100%;
height: 100%;
object-fit: cover;
transition: transform 650ms cubic-bezier(0.2, 0.7, 0.2, 1);
}
.news-card:hover .news-card-media img {
transform: scale(1.025);
}
.news-card-body {
display: flex;
padding: clamp(1.35rem, 2.5vw, 2rem);
flex: 1;
flex-direction: column;
}
.news-meta {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem 1rem;
margin-bottom: 1rem;
color: var(--b2b-ink-muted);
font-size: 0.74rem;
letter-spacing: 0.06em;
}
.news-categories a {
color: var(--b2b-ink);
font-weight: 600;
text-decoration: none;
}
.news-categories a:hover,
.news-categories a:focus {
opacity: 0.65;
}
.news-card h2 {
margin-bottom: 1rem;
font-family: var(--b2b-font-display);
font-size: clamp(1.45rem, 2vw, 1.9rem);
font-weight: 400;
line-height: 1.28;
}
.news-card h2 a {
color: var(--b2b-ink);
text-decoration: none;
}
.news-card-body > p {
margin-bottom: 1.5rem;
color: var(--b2b-ink-soft);
line-height: 1.75;
}
.news-card-body .text-link {
margin-top: auto;
align-self: flex-start;
}
.news-pagination {
margin-top: clamp(3rem, 6vw, 5rem);
}
.news-pagination .nav-links,
.news-single .page-links {
display: flex;
align-items: center;
flex-wrap: wrap;
gap: 0.5rem;
}
.news-pagination .page-numbers,
.news-single .post-page-numbers {
display: inline-flex;
min-width: 2.75rem;
min-height: 2.75rem;
align-items: center;
justify-content: center;
padding: 0.6rem 0.85rem;
color: var(--b2b-ink);
background: var(--b2b-surface);
border: 1px solid var(--b2b-line);
text-decoration: none;
}
.news-pagination .page-numbers.current,
.news-pagination .page-numbers:hover,
.news-pagination .page-numbers:focus,
.news-single .post-page-numbers.current,
.news-single .post-page-numbers:hover,
.news-single .post-page-numbers:focus {
color: var(--b2b-surface);
background: var(--b2b-ink);
border-color: var(--b2b-ink);
}
.news-empty {
padding: clamp(3rem, 7vw, 6rem);
background: var(--b2b-mist);
text-align: center;
}
.news-empty h2 {
margin-bottom: 1rem;
font-family: var(--b2b-font-display);
font-size: clamp(1.8rem, 3vw, 2.5rem);
font-weight: 400;
}
.news-empty p {
margin: 0 auto 2rem;
color: var(--b2b-ink-soft);
}
.news-single {
padding-bottom: clamp(5rem, 8vw, 8rem);
}
.news-single-header {
max-width: 940px;
margin: 2rem auto clamp(2.5rem, 5vw, 4.5rem);
text-align: center;
}
.news-single-header .news-meta {
justify-content: center;
}
.news-single-header h1 {
margin: 0;
font-family: var(--b2b-font-display);
font-size: clamp(2.5rem, 5vw, 4.8rem);
font-weight: 300;
line-height: 1.14;
}
.news-single-image {
max-width: 1120px;
margin: 0 auto clamp(3rem, 6vw, 5rem);
overflow: hidden;
background: var(--b2b-mist);
}
.news-single-image img {
display: block;
width: 100%;
height: auto;
}
.news-single-content {
max-width: 800px;
margin: 0 auto;
color: var(--b2b-ink);
font-size: 1.05rem;
line-height: 1.9;
}
.news-single-content > * {
max-width: 100%;
}
.news-single-content h2,
.news-single-content h3,
.news-single-content h4 {
margin-top: 2.25em;
margin-bottom: 0.75em;
font-family: var(--b2b-font-display);
font-weight: 400;
line-height: 1.3;
}
.news-single-content a {
color: var(--b2b-ink);
text-underline-offset: 0.18em;
}
.news-single-content img,
.news-single-content figure {
height: auto;
}
.news-single-content blockquote {
margin: 2rem 0;
padding: 0.25rem 0 0.25rem 1.5rem;
color: var(--b2b-ink-soft);
border-left: 3px solid var(--b2b-ink);
}
.news-single .page-links {
margin-top: 2.5rem;
}
.news-post-navigation {
max-width: 960px;
margin: clamp(4rem, 8vw, 7rem) auto 0;
padding-top: 2rem;
border-top: 1px solid var(--b2b-line);
}
.news-post-navigation .nav-links {
display: grid;
grid-template-columns: repeat(2, minmax(0, 1fr));
gap: 2rem;
}
.news-post-navigation .nav-next {
text-align: right;
}
.news-post-navigation a {
display: inline-flex;
color: var(--b2b-ink);
flex-direction: column;
text-decoration: none;
}
.news-post-navigation .nav-subtitle {
margin-bottom: 0.5rem;
color: var(--b2b-ink-muted);
font-size: 0.72rem;
letter-spacing: 0.1em;
}
.news-post-navigation .nav-title {
font-family: var(--b2b-font-display);
font-size: 1.25rem;
}
.news-single-cta {
max-width: 960px;
margin: clamp(3rem, 6vw, 5rem) auto 0;
padding: clamp(2rem, 5vw, 4rem);
background: var(--b2b-mist);
text-align: center;
}
.news-single-cta h2 {
margin-bottom: 1rem;
font-family: var(--b2b-font-display);
font-size: clamp(1.8rem, 3vw, 2.5rem);
font-weight: 400;
}
.news-single-cta p {
max-width: 650px;
margin: 0 auto 2rem;
color: var(--b2b-ink-soft);
}
/* ---- Reveal Motion ---- */
.motion-ready .reveal-item {
opacity: 0;
@@ -1395,6 +1894,7 @@ textarea:focus-visible {
.b2b-header .offcanvas .nav-item:nth-child(4) { transition-delay: 120ms; }
.b2b-header .offcanvas .nav-item:nth-child(5) { transition-delay: 160ms; }
.b2b-header .offcanvas .nav-item:nth-child(6) { transition-delay: 200ms; }
.b2b-header .offcanvas .nav-item:nth-child(7) { transition-delay: 240ms; }
.b2b-header .offcanvas.hiding .nav-item {
opacity: 0;
@@ -1442,6 +1942,14 @@ textarea:focus-visible {
/* LG down — 991px */
@media (max-width: 991px) {
.cases-carousel {
--carousel-items: 1;
}
.cases-carousel .b2b-carousel-track {
grid-auto-columns: 100%;
}
.b2b-section {
padding: 5rem 0;
}
@@ -1459,6 +1967,10 @@ textarea:focus-visible {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.news-grid {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
.factory-video-section {
padding-bottom: 5rem;
}
@@ -1533,6 +2045,19 @@ textarea:focus-visible {
grid-template-columns: 1fr;
}
.news-grid,
.news-post-navigation .nav-links {
grid-template-columns: 1fr;
}
.news-post-navigation .nav-next {
text-align: left;
}
.b2b-carousel-controls {
margin-top: 1.25rem;
}
.factory-gallery {
grid-template-rows: repeat(2, 160px);
}
@@ -1591,8 +2116,25 @@ textarea:focus-visible {
}
}
/* XS carousel — 575px */
@media (max-width: 575px) {
.services-carousel,
.cases-carousel {
--carousel-items: 1;
}
.b2b-carousel .b2b-carousel-track {
grid-auto-columns: 100%;
grid-template-columns: none;
}
}
/* SM down — 480px */
@media (max-width: 480px) {
.row.g-5 {
--bs-gutter-x: 1.5rem;
}
.b2b-hero .btn {
width: 100%;
}
Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 134 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 44 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 109 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 143 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 101 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 87 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 124 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 89 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 96 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 73 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 103 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 169 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 155 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 123 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 159 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 135 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 102 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 275 KiB

+9
View File
@@ -0,0 +1,9 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1200 675" role="img" aria-labelledby="title description">
<title id="title">新闻资讯图片占位</title>
<desc id="description">用于没有特色图片的新闻文章</desc>
<rect width="1200" height="675" fill="#ecece8"/>
<path d="M0 505 264 352l173 92 212-148 551 262v117H0Z" fill="#d6d6d0"/>
<circle cx="893" cy="185" r="66" fill="#fafaf8"/>
<path d="M406 220h388v18H406zm0 55h286v12H406zm0 42h342v12H406z" fill="#1c1c1a" opacity=".72"/>
<rect x="383" y="188" width="434" height="184" rx="2" fill="none" stroke="#1c1c1a" stroke-width="4" opacity=".3"/>
</svg>

After

Width:  |  Height:  |  Size: 635 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 144 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 165 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 129 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 277 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 127 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 326 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 239 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 301 KiB

After

Width:  |  Height:  |  Size: 172 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 276 KiB

After

Width:  |  Height:  |  Size: 153 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 232 KiB

After

Width:  |  Height:  |  Size: 132 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 318 KiB

After

Width:  |  Height:  |  Size: 179 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 296 KiB

After

Width:  |  Height:  |  Size: 166 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 504 KiB

After

Width:  |  Height:  |  Size: 278 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 264 KiB

+219 -1
View File
@@ -25,6 +25,217 @@
});
}
function initCarousels() {
var reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
document.querySelectorAll('[data-carousel]').forEach(function (carousel) {
var viewport = carousel.querySelector('.b2b-carousel-viewport');
var track = carousel.querySelector('.b2b-carousel-track');
var slides = Array.prototype.slice.call(carousel.querySelectorAll('.b2b-carousel-slide'));
var previousButton = carousel.querySelector('.b2b-carousel-prev');
var nextButton = carousel.querySelector('.b2b-carousel-next');
var dotsContainer = carousel.querySelector('.b2b-carousel-dots');
var autoplayDelay = parseInt(carousel.getAttribute('data-autoplay'), 10) || 9000;
var pageLabel = carousel.getAttribute('data-page-label') || 'Page %d';
var currentPage = 0;
var pageCount = 1;
var autoplayTimer = null;
var scrollTimer = null;
var resizeTimer = null;
var hoverPaused = false;
var focusPaused = false;
var pointerPaused = false;
if (!viewport || !track || !slides.length || !previousButton || !nextButton || !dotsContainer) {
return;
}
function getItemsPerPage() {
var value = parseInt(window.getComputedStyle(carousel).getPropertyValue('--carousel-items'), 10);
return Math.max(1, value || 1);
}
function updateDots() {
dotsContainer.querySelectorAll('.b2b-carousel-dot').forEach(function (dot, index) {
var active = index === currentPage;
dot.classList.toggle('is-active', active);
dot.setAttribute('aria-current', active ? 'true' : 'false');
});
}
function stopAutoplay() {
if (!autoplayTimer) return;
window.clearInterval(autoplayTimer);
autoplayTimer = null;
}
function goToPage(page, smooth) {
if (!pageCount) return;
currentPage = (page + pageCount) % pageCount;
var targetIndex = Math.min(currentPage * getItemsPerPage(), slides.length - 1);
var maximumScroll = Math.max(0, viewport.scrollWidth - viewport.clientWidth);
viewport.scrollTo({
left: Math.min(slides[targetIndex].offsetLeft, maximumScroll),
behavior: smooth && !reducedMotion ? 'smooth' : 'auto'
});
updateDots();
}
function startAutoplay() {
stopAutoplay();
if (
reducedMotion ||
hoverPaused ||
focusPaused ||
pointerPaused ||
pageCount < 2 ||
document.hidden
) {
return;
}
autoplayTimer = window.setInterval(function () {
goToPage(currentPage + 1, true);
}, Math.max(autoplayDelay, 7000));
}
function buildDots() {
var itemsPerPage = getItemsPerPage();
var nextPageCount = Math.ceil(slides.length / itemsPerPage);
var fragment = document.createDocumentFragment();
pageCount = Math.max(1, nextPageCount);
currentPage = Math.min(currentPage, pageCount - 1);
dotsContainer.textContent = '';
for (var index = 0; index < pageCount; index += 1) {
var dot = document.createElement('button');
dot.type = 'button';
dot.className = 'b2b-carousel-dot';
dot.setAttribute('aria-label', pageLabel.replace('%d', index + 1));
dot.dataset.page = index;
dot.addEventListener('click', function () {
goToPage(parseInt(this.dataset.page, 10), true);
startAutoplay();
});
fragment.appendChild(dot);
}
dotsContainer.appendChild(fragment);
carousel.classList.toggle('has-single-page', pageCount < 2);
updateDots();
goToPage(currentPage, false);
startAutoplay();
}
previousButton.addEventListener('click', function () {
goToPage(currentPage - 1, true);
startAutoplay();
});
nextButton.addEventListener('click', function () {
goToPage(currentPage + 1, true);
startAutoplay();
});
viewport.addEventListener(
'scroll',
function () {
window.clearTimeout(scrollTimer);
scrollTimer = window.setTimeout(function () {
var itemsPerPage = getItemsPerPage();
var maximumScroll = Math.max(0, viewport.scrollWidth - viewport.clientWidth);
var closestPage = 0;
var closestDistance = Number.POSITIVE_INFINITY;
for (var page = 0; page < pageCount; page += 1) {
var targetIndex = Math.min(page * itemsPerPage, slides.length - 1);
var targetPosition = Math.min(slides[targetIndex].offsetLeft, maximumScroll);
var distance = Math.abs(viewport.scrollLeft - targetPosition);
if (distance < closestDistance) {
closestDistance = distance;
closestPage = page;
}
}
currentPage = closestPage;
updateDots();
}, 100);
},
{ passive: true }
);
carousel.addEventListener('mouseenter', function () {
hoverPaused = true;
stopAutoplay();
});
carousel.addEventListener('mouseleave', function () {
hoverPaused = false;
startAutoplay();
});
carousel.addEventListener('focusin', function () {
focusPaused = true;
stopAutoplay();
});
carousel.addEventListener('focusout', function () {
window.setTimeout(function () {
if (carousel.contains(document.activeElement)) return;
focusPaused = false;
startAutoplay();
}, 0);
});
viewport.addEventListener(
'pointerdown',
function () {
pointerPaused = true;
stopAutoplay();
},
{ passive: true }
);
viewport.addEventListener(
'pointerup',
function () {
pointerPaused = false;
startAutoplay();
},
{ passive: true }
);
viewport.addEventListener(
'pointercancel',
function () {
pointerPaused = false;
startAutoplay();
},
{ passive: true }
);
window.addEventListener(
'resize',
function () {
window.clearTimeout(resizeTimer);
resizeTimer = window.setTimeout(buildDots, 160);
},
{ passive: true }
);
document.addEventListener('visibilitychange', function () {
if (document.hidden) {
stopAutoplay();
} else {
startAutoplay();
}
});
carousel.classList.add('is-ready');
buildDots();
});
}
function initRevealMotion() {
var reducedMotion = window.matchMedia('(prefers-reduced-motion: reduce)').matches;
var compactMotion = window.matchMedia('(max-width: 768px)').matches;
@@ -53,11 +264,12 @@
prepareGroup('.trust-strip .row', '.trust-metric', 60);
prepareGroup('.capability-grid', '.capability-card', 60);
prepareGroup('.case-grid', '.case-card', 60);
prepareGroup('.news-grid', '.news-card', 60);
prepareGroup('.factory-gallery', 'figure', 60);
prepareGroup('.credentials-grid', '.credential-card', 60);
prepareGroup('.document-grid', 'article', 60);
prepareGroup('.contact-detail-grid', '.contact-detail-card', 60);
prepareGroup('.service-content, .case-content', ':scope > *', 40);
prepareGroup('.service-content, .case-content, .news-single-content', ':scope > *', 40);
document.querySelectorAll(
[
@@ -70,6 +282,11 @@
'.contact-store-media',
'.contact-map-heading',
'.contact-map-panel',
'.news-page-header',
'.news-single-header',
'.news-single-image',
'.news-post-navigation',
'.news-single-cta',
'.cta-section .container',
'.about-cta .container',
'.page-header'
@@ -111,6 +328,7 @@
function initTheme() {
initStickyHeader();
initNavigation();
initCarousels();
initRevealMotion();
}
+24 -4
View File
@@ -9,14 +9,21 @@ $fragrance_social_links = array(
'youtube_url' => __( 'YouTube', 'fragrance-trade' ), 'linkedin_url' => __( 'LinkedIn', 'fragrance-trade' ),
'instagram_social_url' => __( 'Instagram', 'fragrance-trade' ),
);
$fragrance_email = fragrance_trade_inquiry_email();
$fragrance_whatsapp = fragrance_trade_whatsapp_number();
$fragrance_store_name = fragrance_trade_get_mod( 'b2b_hero_title' );
$fragrance_store_phone = fragrance_trade_get_mod( 'store_phone' );
$fragrance_phone_href = preg_replace( '/[^0-9+]/', '', $fragrance_store_phone );
$fragrance_store_address = fragrance_trade_get_mod( 'store_address' );
$fragrance_store_hours = fragrance_trade_get_mod( 'store_hours' );
$fragrance_contact_name = fragrance_trade_get_mod( 'store_contact_person' );
$fragrance_icp_number = fragrance_trade_get_mod( 'icp_number', '' );
$fragrance_icp_url = fragrance_trade_get_mod( 'icp_url', '' );
?>
<footer class="site-footer b2b-footer">
<div class="container py-5">
<div class="row g-5">
<div class="col-lg-5">
<h2 class="h3 text-white mb-3"><?php echo esc_html( get_bloginfo( 'name' ) ); ?></h2>
<h2 class="h3 text-white mb-3"><?php echo esc_html( $fragrance_store_name ); ?></h2>
<p class="footer-positioning"><?php echo esc_html( fragrance_trade_get_mod( 'footer_text' ) ); ?></p>
<p class="footer-kicker mb-0"><?php esc_html_e( '需求沟通 · 方案确认 · 施工交付', 'fragrance-trade' ); ?></p>
</div>
@@ -25,13 +32,17 @@ $fragrance_whatsapp = fragrance_trade_whatsapp_number();
<ul class="list-unstyled footer-links">
<li><a href="<?php echo esc_url( home_url( '/services/' ) ); ?>"><?php esc_html_e( '服务项目', 'fragrance-trade' ); ?></a></li>
<li><a href="<?php echo esc_url( home_url( '/cases/' ) ); ?>"><?php esc_html_e( '案例作品', 'fragrance-trade' ); ?></a></li>
<li><a href="<?php echo esc_url( fragrance_trade_news_url() ); ?>"><?php esc_html_e( '新闻资讯', 'fragrance-trade' ); ?></a></li>
<li><a href="<?php echo esc_url( home_url( '/about/' ) ); ?>"><?php esc_html_e( '关于门店', 'fragrance-trade' ); ?></a></li>
<li><a href="<?php echo esc_url( home_url( '/contact/' ) ); ?>"><?php esc_html_e( '联系我们', 'fragrance-trade' ); ?></a></li>
</ul>
</div>
<div class="col-sm-6 col-lg-4">
<h2 class="h6 text-uppercase text-white mb-3"><?php esc_html_e( '联系门店', 'fragrance-trade' ); ?></h2>
<p><a href="mailto:<?php echo esc_attr( antispambot( $fragrance_email ) ); ?>"><?php echo esc_html( antispambot( $fragrance_email ) ); ?></a></p>
<?php if ( $fragrance_contact_name ) : ?><p><?php echo esc_html( sprintf( __( '联系人:%s', 'fragrance-trade' ), $fragrance_contact_name ) ); ?></p><?php endif; ?>
<?php if ( $fragrance_store_phone ) : ?><p><a href="tel:<?php echo esc_attr( $fragrance_phone_href ); ?>"><?php echo esc_html( $fragrance_store_phone ); ?></a></p><?php endif; ?>
<?php if ( $fragrance_store_address ) : ?><p><?php echo esc_html( $fragrance_store_address ); ?></p><?php endif; ?>
<?php if ( $fragrance_store_hours ) : ?><p><?php echo esc_html( sprintf( __( '营业时间:%s', 'fragrance-trade' ), $fragrance_store_hours ) ); ?></p><?php endif; ?>
<?php if ( $fragrance_whatsapp ) : ?><p><a href="<?php echo esc_url( fragrance_trade_get_inquiry_url() ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( '通过 WhatsApp 联系我们', 'fragrance-trade' ); ?></a></p><?php endif; ?>
<ul class="list-unstyled d-flex flex-wrap gap-3 footer-social mb-0">
<?php foreach ( $fragrance_social_links as $setting => $label ) : $url = fragrance_trade_get_mod( $setting, '' ); if ( $url ) : ?>
@@ -41,7 +52,16 @@ $fragrance_whatsapp = fragrance_trade_whatsapp_number();
</div>
</div>
<div class="footer-bottom d-flex flex-wrap justify-content-between gap-2 pt-4 mt-4 border-top">
<p class="mb-0">&copy; <?php echo esc_html( wp_date( 'Y' ) ); ?> <?php echo esc_html( get_bloginfo( 'name' ) ); ?></p>
<p class="mb-0">&copy; <?php echo esc_html( wp_date( 'Y' ) ); ?> <?php echo esc_html( $fragrance_store_name ); ?></p>
<?php if ( $fragrance_icp_number ) : ?>
<p class="footer-icp mb-0">
<?php if ( $fragrance_icp_url ) : ?>
<a href="<?php echo esc_url( $fragrance_icp_url ); ?>" target="_blank" rel="noopener noreferrer"><?php echo esc_html( $fragrance_icp_number ); ?></a>
<?php else : ?>
<?php echo esc_html( $fragrance_icp_number ); ?>
<?php endif; ?>
</p>
<?php endif; ?>
<p class="mb-0"><?php esc_html_e( '项目、价格、工期与质保以门店最终确认为准。', 'fragrance-trade' ); ?></p>
</div>
</div>
+2 -1
View File
@@ -14,10 +14,11 @@ $fragrance_trade_modules = array(
'setup.php',
'helpers.php',
'cpt.php',
'service-seeds.php',
'case-seeds.php',
'customizer.php',
);
foreach ( $fragrance_trade_modules as $fragrance_trade_module ) {
require_once get_template_directory() . '/inc/' . $fragrance_trade_module;
}
+61
View File
@@ -0,0 +1,61 @@
<?php
/**
* WordPress posts page: news index.
*
* @package Fragrance_Trade
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$posts_page_id = absint( get_option( 'page_for_posts', 0 ) );
$page_title = $posts_page_id ? get_the_title( $posts_page_id ) : __( '新闻资讯', 'fragrance-trade' );
if ( ! $page_title ) {
$page_title = __( '新闻资讯', 'fragrance-trade' );
}
get_header();
?>
<main id="primary" class="site-main">
<div class="page-content container news-page">
<?php
get_template_part(
'template-parts/breadcrumb',
null,
array(
'items' => array(
array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ),
array( 'label' => $page_title, 'url' => null ),
),
)
);
?>
<header class="news-page-header">
<p class="section-eyebrow"><?php esc_html_e( '门店动态与用车知识', 'fragrance-trade' ); ?></p>
<h1><?php echo esc_html( $page_title ); ?></h1>
<p><?php esc_html_e( '了解门店活动、产品信息、施工知识与汽车膜日常护理建议。', 'fragrance-trade' ); ?></p>
</header>
<?php if ( have_posts() ) : ?>
<div class="news-grid">
<?php
while ( have_posts() ) :
the_post();
get_template_part( 'template-parts/content', 'news-card' );
endwhile;
?>
</div>
<div class="news-pagination">
<?php the_posts_pagination(); ?>
</div>
<?php else : ?>
<section class="news-empty">
<h2><?php esc_html_e( '新闻内容正在整理中', 'fragrance-trade' ); ?></h2>
<p><?php esc_html_e( '门店动态、产品知识和施工说明将在这里陆续发布。', 'fragrance-trade' ); ?></p>
<a class="btn btn-b2b-primary" href="<?php echo esc_url( home_url( '/contact/' ) ); ?>"><?php esc_html_e( '联系门店', 'fragrance-trade' ); ?></a>
</section>
<?php endif; ?>
</div>
</main>
<?php get_footer(); ?>
+520
View File
@@ -0,0 +1,520 @@
<?php
/**
* Optional one-click importer for the bundled case portfolio.
*
* @package Fragrance_Trade
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** Return the case records available to the optional importer. */
function fragrance_trade_case_seeds() {
return array(
'ford-mondeo-alexander-silver' => array(
'title' => __( '福特蒙迪欧|亚历山大银改色膜', 'fragrance-trade' ),
'slug' => 'ford-mondeo-alexander-silver',
'vehicle' => __( '福特蒙迪欧', 'fragrance-trade' ),
'project' => __( '整车改色膜', 'fragrance-trade' ),
'color' => __( '亚历山大银', 'fragrance-trade' ),
'direction' => __( '哑光金属银、黑银对比', 'fragrance-trade' ),
'excerpt' => __( '福特蒙迪欧亚历山大银整车改色,哑光金属银质感搭配黑色车顶与饰件,呈现克制、利落的黑银对比效果。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为福特蒙迪欧,车主选择亚历山大银整车改色。银灰色膜面带有细腻的哑光金属质感,与黑色车顶、后视镜、窗框及前后灯组形成清晰的黑银对比。', 'fragrance-trade' ),
'effect' => __( '亚历山大银弱化了高亮反射,让蒙迪欧的车身折线在室内灯光和自然光下都更容易被看见。大面积银色保持干净、克制,黑色车顶与饰件则进一步压低视觉重心,让整车轮廓显得更修长。', 'fragrance-trade' ),
'details' => __( '施工重点检查了隐藏式门把手、后视镜底座、尾灯边缘、尾翼和车身折角等位置。完成后从正面、侧面和车尾分别复查膜面平整度、拼接位置与边角收口,确保整体颜色连续、车身线条清晰。', 'fragrance-trade' ),
'image_count' => 9,
'featured_index' => 0,
),
'porsche-718-liquid-metal-silver' => array(
'title' => __( '保时捷 718|液态金属银改色膜', 'fragrance-trade' ),
'slug' => 'porsche-718-liquid-metal-silver',
'vehicle' => __( '保时捷 718', 'fragrance-trade' ),
'project' => __( '整车改色膜', 'fragrance-trade' ),
'color' => __( '液态金属银', 'fragrance-trade' ),
'direction' => __( '亮面金属银灰、红色软顶对比', 'fragrance-trade' ),
'excerpt' => __( '保时捷 718 液态金属银整车改色,以亮面金属银灰强化跑车曲面,并保留红色软顶形成鲜明层次。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为保时捷 718,选择液态金属银整车改色。银灰色膜面带有明亮、流动的金属反射,与红色软顶和黑色灯组形成鲜明但克制的颜色层次。', 'fragrance-trade' ),
'effect' => __( '液态金属银会随着光线角度呈现由浅银到深灰的变化,能够突出 718 前翼子板、车门和后轮拱的连续曲面。红色软顶保留原有视觉焦点,让整车兼具精致感与运动感。', 'fragrance-trade' ),
'details' => __( '施工重点检查前后保险杠曲面、进气口边缘、门把手、后视镜底座、尾翼与软顶交界等位置。交付前分别在正面、侧面和车尾复查膜面连续性与边角收口。', 'fragrance-trade' ),
'image_count' => 10,
'featured_index' => 0,
),
'tesla-model-3-highland-alexander-silver' => array(
'title' => __( '特斯拉焕新版 Model 3|亚历山大银改色膜', 'fragrance-trade' ),
'slug' => 'tesla-model-3-highland-alexander-silver',
'vehicle' => __( '特斯拉焕新版 Model 3', 'fragrance-trade' ),
'project' => __( '整车改色膜', 'fragrance-trade' ),
'color' => __( '亚历山大银', 'fragrance-trade' ),
'direction' => __( '哑光金属银、黑色玻璃与轮毂对比', 'fragrance-trade' ),
'excerpt' => __( '特斯拉焕新版 Model 3 亚历山大银整车改色,以细腻哑光金属质感呈现更简洁的黑银对比。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为特斯拉焕新版 Model 3,选择亚历山大银整车改色。低反光的银色膜面与黑色玻璃、门把手、饰件和轮毂组合,延续车辆简洁、科技感明确的外观语言。', 'fragrance-trade' ),
'effect' => __( '亚历山大银降低了车身大面积高光反射,让焕新版 Model 3 的前脸、肩线与溜背轮廓显得更干净。不同光线下,膜面会在冷银与浅灰之间变化,整体观感克制而利落。', 'fragrance-trade' ),
'details' => __( '施工重点覆盖无框车门边缘、隐藏式门把手、后视镜底座、前后灯组与保险杠曲面。完成后检查各覆盖面颜色一致性,并确认门把手和车门开合区域收口平整。', 'fragrance-trade' ),
'image_count' => 9,
'featured_index' => 0,
),
'byd-han-matte-blue-gold-floating-roof' => array(
'title' => __( '比亚迪汉|远峰蓝魅金哑面+悬浮顶', 'fragrance-trade' ),
'slug' => 'byd-han-matte-blue-gold-floating-roof',
'vehicle' => __( '比亚迪汉', 'fragrance-trade' ),
'project' => __( '整车哑面改色膜+悬浮顶', 'fragrance-trade' ),
'color' => __( '远峰蓝魅金(哑面)', 'fragrance-trade' ),
'direction' => __( '低饱和蓝金变色、哑面质感、黑色悬浮顶', 'fragrance-trade' ),
'excerpt' => __( '比亚迪汉远峰蓝魅金哑面整车改色,并搭配黑色悬浮顶,在不同光线下呈现低饱和蓝金变化。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为比亚迪汉,选择远峰蓝魅金哑面改色,并搭配黑色悬浮顶。膜面在银灰基调中带有轻微蓝金变化,车顶与窗框的黑色区域则让车身形成清晰的上下分层。', 'fragrance-trade' ),
'effect' => __( '哑面效果降低了直接反射,远峰蓝魅金在不同角度和灯光下呈现偏冷银、浅蓝与柔和金色变化。黑色悬浮顶进一步拉长侧面视觉比例,让比亚迪汉的车身姿态更低、更完整。', 'fragrance-trade' ),
'details' => __( '施工重点处理悬浮顶边界、A/B/C 柱、后视镜、门把手、尾灯和车身腰线等位置。交付前复查黑色车顶与车身改色膜的边界是否连续,并确认哑面膜无明显压痕或高光点。', 'fragrance-trade' ),
'image_count' => 8,
'featured_index' => 4,
),
'chery-arrizo-alexander-silver' => array(
'title' => __( '奇瑞艾瑞泽|亚历山大银改色膜', 'fragrance-trade' ),
'slug' => 'chery-arrizo-alexander-silver',
'vehicle' => __( '奇瑞艾瑞泽', 'fragrance-trade' ),
'project' => __( '整车改色膜', 'fragrance-trade' ),
'color' => __( '亚历山大银', 'fragrance-trade' ),
'direction' => __( '哑光金属银、黑色格栅与灯组对比', 'fragrance-trade' ),
'excerpt' => __( '奇瑞艾瑞泽亚历山大银整车改色,以细腻哑光金属银突出车身折线与前脸黑色细节。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为奇瑞艾瑞泽,选择亚历山大银整车改色。银色哑光膜面弱化反射,同时保留金属颗粒感,与黑色进气格栅、灯组和车窗区域形成简洁对比。', 'fragrance-trade' ),
'effect' => __( '亚历山大银让艾瑞泽的前脸折线、车门腰线和车尾层次更容易被看见。整体颜色接近低饱和银灰,不会掩盖原有造型,适合希望外观焕新但仍保持稳重观感的方案。', 'fragrance-trade' ),
'details' => __( '施工重点检查前脸饰条、后视镜、门把手、车顶鲨鱼鳍、尾灯边缘与保险杠转角。交付前从不同光线方向复查膜面色差、平整度和细节收口。', 'fragrance-trade' ),
'image_count' => 9,
'featured_index' => 0,
),
'changan-uni-v-gt-silver' => array(
'title' => __( '长安 UNI-VGT 银改色膜', 'fragrance-trade' ),
'slug' => 'changan-uni-v-gt-silver',
'vehicle' => __( '长安 UNI-V', 'fragrance-trade' ),
'project' => __( '整车改色膜', 'fragrance-trade' ),
'color' => __( 'GT 银', 'fragrance-trade' ),
'direction' => __( '亮面金属银、黑色车顶与运动套件对比', 'fragrance-trade' ),
'excerpt' => __( '长安 UNI-V GT 银整车改色,利用亮面金属银与黑色车顶、尾翼和运动饰件强化低趴姿态。', 'fragrance-trade' ),
'intro' => __( '本次施工车型为长安 UNI-V,选择 GT 银整车改色。亮面银色膜面能够清晰表现车身折线,与黑色车顶、后视镜、窗框和运动套件形成更直接的银黑对比。', 'fragrance-trade' ),
'effect' => __( 'GT 银在室内灯光下呈现干净的金属高光,能够强化 UNI-V 的溜背线条、宽体感和低趴姿态。黑色车顶与尾翼保留原有运动气质,使整体效果更利落。', 'fragrance-trade' ),
'details' => __( '施工重点处理无边框车门区域、隐藏式门把手、后视镜底座、前后保险杠折角、尾灯与升降尾翼周边。车辆交付前同时检查外观覆盖面与开合部件的边缘收口。', 'fragrance-trade' ),
'image_count' => 12,
'featured_index' => 3,
),
);
}
/** Find a case previously created by this importer. */
function fragrance_trade_find_seeded_case( $seed_key ) {
$ids = get_posts(
array(
'post_type' => 'case',
'post_status' => fragrance_trade_seed_post_statuses(),
'posts_per_page' => 1,
'fields' => 'ids',
'meta_key' => '_fragrance_case_seed_key',
'meta_value' => $seed_key,
'no_found_rows' => true,
)
);
return $ids ? (int) $ids[0] : 0;
}
/** Find a case with the conventional seed slug without changing it. */
function fragrance_trade_find_case_seed_slug( $slug ) {
$posts = get_posts(
array(
'post_type' => 'case',
'post_status' => fragrance_trade_seed_post_statuses(),
'name' => $slug,
'posts_per_page' => 1,
'no_found_rows' => true,
)
);
return $posts ? (int) $posts[0]->ID : 0;
}
/** Find one media item already copied for a seed image. */
function fragrance_trade_find_case_seed_attachment( $image_key ) {
$ids = get_posts(
array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'posts_per_page' => 1,
'fields' => 'ids',
'meta_key' => '_fragrance_case_seed_image',
'meta_value' => $image_key,
'no_found_rows' => true,
)
);
return $ids ? (int) $ids[0] : 0;
}
/**
* Copy one bundled seed image into the WordPress media library.
*
* @param int $case_id Parent case post ID.
* @param string $seed_key Stable case seed key.
* @param array $seed Seed record.
* @param int $index Zero-based image index.
* @return int|WP_Error
*/
function fragrance_trade_import_case_seed_image( $case_id, $seed_key, $seed, $index ) {
$image_key = $seed_key . ':' . $index;
$existing = fragrance_trade_find_case_seed_attachment( $image_key );
if ( $existing ) {
if ( (int) wp_get_post_parent_id( $existing ) !== (int) $case_id ) {
wp_update_post(
array(
'ID' => $existing,
'post_parent' => $case_id,
)
);
}
return $existing;
}
$number = $index + 1;
$source_file = sprintf(
'%1$s/assets/images/cases/%2$s/%3$02d.jpg',
get_template_directory(),
$seed['slug'],
$number
);
if ( ! is_readable( $source_file ) ) {
return new WP_Error(
'fragrance_case_seed_image_missing',
sprintf(
/* translators: 1: case title, 2: image number. */
__( '案例“%1$s”的第 %2$d 张初始化图片不存在。', 'fragrance-trade' ),
$seed['title'],
$number
)
);
}
$image_bytes = file_get_contents( $source_file );
if ( false === $image_bytes ) {
return new WP_Error(
'fragrance_case_seed_image_unreadable',
sprintf(
/* translators: 1: case title, 2: image number. */
__( '无法读取案例“%1$s”的第 %2$d 张初始化图片。', 'fragrance-trade' ),
$seed['title'],
$number
)
);
}
$filename = sprintf( '%1$s-%2$02d.jpg', $seed['slug'], $number );
$upload = wp_upload_bits( $filename, null, $image_bytes );
unset( $image_bytes );
if ( ! empty( $upload['error'] ) ) {
return new WP_Error( 'fragrance_case_seed_upload_failed', $upload['error'] );
}
$attachment_id = wp_insert_attachment(
array(
'post_mime_type' => 'image/jpeg',
'post_title' => sprintf(
/* translators: 1: vehicle name, 2: color name, 3: image number. */
__( '%1$s %2$s施工实拍图 %3$d', 'fragrance-trade' ),
$seed['vehicle'],
$seed['color'],
$number
),
'post_status' => 'inherit',
),
$upload['file'],
$case_id,
true
);
if ( is_wp_error( $attachment_id ) ) {
wp_delete_file( $upload['file'] );
return $attachment_id;
}
require_once ABSPATH . 'wp-admin/includes/image.php';
$metadata = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
if ( $metadata ) {
wp_update_attachment_metadata( $attachment_id, $metadata );
}
update_post_meta( $attachment_id, '_fragrance_case_seed_image', $image_key );
update_post_meta(
$attachment_id,
'_wp_attachment_image_alt',
sprintf(
/* translators: 1: vehicle name, 2: color name, 3: image number. */
__( '%1$s%2$s施工实拍图 %3$d', 'fragrance-trade' ),
$seed['vehicle'],
$seed['color'],
$number
)
);
return (int) $attachment_id;
}
/** Build the block-editor content for an imported case. */
function fragrance_trade_build_case_seed_content( $seed, $attachment_ids ) {
$list = sprintf(
'<ul class="wp-block-list"><li><strong>%1$s</strong>%2$s</li><li><strong>%3$s</strong>%4$s</li><li><strong>%5$s</strong>%6$s</li><li><strong>%7$s</strong>%8$s</li></ul>',
esc_html__( '车型:', 'fragrance-trade' ),
esc_html( $seed['vehicle'] ),
esc_html__( '施工项目:', 'fragrance-trade' ),
esc_html( $seed['project'] ),
esc_html__( '颜色:', 'fragrance-trade' ),
esc_html( $seed['color'] ),
esc_html__( '外观方向:', 'fragrance-trade' ),
esc_html( $seed['direction'] )
);
$gallery = '';
foreach ( $attachment_ids as $attachment_id ) {
$full_url = wp_get_attachment_url( $attachment_id );
$image = wp_get_attachment_image( $attachment_id, 'large' );
if ( ! $full_url || ! $image ) {
continue;
}
$gallery .= sprintf(
'<!-- wp:image {"id":%1$d,"sizeSlug":"large","linkDestination":"media"} --><figure class="wp-block-image size-large"><a href="%2$s">%3$s</a></figure><!-- /wp:image -->',
$attachment_id,
esc_url( $full_url ),
$image
);
}
return sprintf(
'<!-- wp:paragraph --><p>%1$s</p><!-- /wp:paragraph -->' .
'<!-- wp:heading --><h2 class="wp-block-heading">%2$s</h2><!-- /wp:heading -->' .
'<!-- wp:list -->%3$s<!-- /wp:list -->' .
'<!-- wp:heading --><h2 class="wp-block-heading">%4$s</h2><!-- /wp:heading -->' .
'<!-- wp:paragraph --><p>%5$s</p><!-- /wp:paragraph -->' .
'<!-- wp:gallery {"linkTo":"media","sizeSlug":"large"} --><figure class="wp-block-gallery has-nested-images columns-2 is-cropped">%6$s</figure><!-- /wp:gallery -->' .
'<!-- wp:heading --><h2 class="wp-block-heading">%7$s</h2><!-- /wp:heading -->' .
'<!-- wp:paragraph --><p>%8$s</p><!-- /wp:paragraph -->' .
'<!-- wp:paragraph --><p><em>%9$s</em></p><!-- /wp:paragraph -->',
esc_html( $seed['intro'] ),
esc_html__( '项目概览', 'fragrance-trade' ),
$list,
esc_html__( '整体效果', 'fragrance-trade' ),
esc_html( $seed['effect'] ),
$gallery,
esc_html__( '细节与收口', 'fragrance-trade' ),
esc_html( $seed['details'] ),
esc_html__( '提示:实际颜色会受到环境光线、屏幕显示和拍摄设备影响,到店选色请以实物色卡与门店样板为准。', 'fragrance-trade' )
);
}
/**
* Import every bundled case without duplicating or overwriting existing work.
*
* @return array{created:int,existing:int,errors:string[]}
*/
function fragrance_trade_import_case_seeds() {
$result = array(
'created' => 0,
'existing' => 0,
'errors' => array(),
);
$term_name = __( '改色膜', 'fragrance-trade' );
$term = term_exists( $term_name, 'case_type' );
if ( ! $term ) {
$term = wp_insert_term( $term_name, 'case_type' );
}
if ( is_wp_error( $term ) ) {
$result['errors'][] = $term->get_error_message();
return $result;
}
$term_id = (int) ( is_array( $term ) ? $term['term_id'] : $term );
foreach ( fragrance_trade_case_seeds() as $seed_key => $seed ) {
$case_id = fragrance_trade_find_seeded_case( $seed_key );
if ( $case_id && 'publish' === get_post_status( $case_id ) ) {
++$result['existing'];
continue;
}
if (
$case_id
&& (
'draft' !== get_post_status( $case_id )
|| 'importing' !== get_post_meta( $case_id, '_fragrance_case_seed_state', true )
)
) {
++$result['existing'];
continue;
}
if ( ! $case_id ) {
$slug_match = fragrance_trade_find_case_seed_slug( $seed['slug'] );
if ( $slug_match ) {
++$result['existing'];
continue;
}
$case_id = wp_insert_post(
array(
'post_type' => 'case',
'post_name' => $seed['slug'],
'post_title' => $seed['title'],
'post_excerpt' => $seed['excerpt'],
'post_status' => 'draft',
),
true
);
if ( is_wp_error( $case_id ) ) {
$result['errors'][] = sprintf(
/* translators: 1: case title, 2: error message. */
__( '无法创建案例“%1$s”:%2$s', 'fragrance-trade' ),
$seed['title'],
$case_id->get_error_message()
);
continue;
}
update_post_meta( $case_id, '_fragrance_case_seed_key', $seed_key );
update_post_meta( $case_id, '_fragrance_case_seed_state', 'importing' );
}
$attachment_ids = array();
$case_errors = array();
for ( $index = 0; $index < $seed['image_count']; ++$index ) {
$attachment_id = fragrance_trade_import_case_seed_image( $case_id, $seed_key, $seed, $index );
if ( is_wp_error( $attachment_id ) ) {
$case_errors[] = $attachment_id->get_error_message();
continue;
}
$attachment_ids[] = $attachment_id;
}
if ( $case_errors || count( $attachment_ids ) !== (int) $seed['image_count'] ) {
$result['errors'] = array_merge( $result['errors'], $case_errors );
continue;
}
$terms_set = wp_set_object_terms( $case_id, array( $term_id ), 'case_type', false );
if ( is_wp_error( $terms_set ) ) {
$result['errors'][] = $terms_set->get_error_message();
continue;
}
set_post_thumbnail( $case_id, $attachment_ids[ $seed['featured_index'] ] );
$updated = wp_update_post(
array(
'ID' => $case_id,
'post_title' => $seed['title'],
'post_name' => $seed['slug'],
'post_excerpt' => $seed['excerpt'],
'post_content' => fragrance_trade_build_case_seed_content( $seed, $attachment_ids ),
'post_status' => 'publish',
),
true
);
if ( is_wp_error( $updated ) ) {
$result['errors'][] = sprintf(
/* translators: 1: case title, 2: error message. */
__( '无法发布案例“%1$s”:%2$s', 'fragrance-trade' ),
$seed['title'],
$updated->get_error_message()
);
continue;
}
delete_post_meta( $case_id, '_fragrance_case_seed_state' );
++$result['created'];
}
$result['errors'] = array_values( array_unique( $result['errors'] ) );
return $result;
}
/** Add the bundled-content importer below Appearance for administrators. */
function fragrance_trade_register_case_seed_page() {
add_theme_page(
__( '初始化内容', 'fragrance-trade' ),
__( '初始化内容', 'fragrance-trade' ),
'edit_theme_options',
'fragrance-case-import',
'fragrance_trade_render_case_seed_page'
);
}
add_action( 'admin_menu', 'fragrance_trade_register_case_seed_page' );
/** Render the one-click service and case importer. */
function fragrance_trade_render_case_seed_page() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
return;
}
$transient_key = 'fragrance_trade_case_import_result_' . get_current_user_id();
$result = get_transient( $transient_key );
if ( false !== $result ) {
delete_transient( $transient_key );
}
?>
<div class="wrap">
<h1><?php esc_html_e( '初始化服务与案例', 'fragrance-trade' ); ?></h1>
<p><?php esc_html_e( '将主题内置的 5 个产品服务、6 篇汽车改色案例和 62 张图片复制到当前 WordPress 站点。已有同名内容不会被覆盖,重复执行不会产生重复内容。', 'fragrance-trade' ); ?></p>
<?php if ( is_array( $result ) ) : ?>
<?php $notice_class = empty( $result['errors'] ) ? 'notice-success' : 'notice-warning'; ?>
<div class="notice <?php echo esc_attr( $notice_class ); ?> is-dismissible">
<p>
<?php
printf(
/* translators: 1: created service count, 2: existing service count, 3: created case count, 4: existing case count. */
esc_html__( '初始化完成:服务新增 %1$d 个、已有 %2$d 个;案例新增 %3$d 篇、已有 %4$d 篇。', 'fragrance-trade' ),
(int) $result['services']['created'],
(int) $result['services']['existing'],
(int) $result['cases']['created'],
(int) $result['cases']['existing']
);
?>
</p>
<?php if ( ! empty( $result['errors'] ) ) : ?>
<ul>
<?php foreach ( $result['errors'] as $error ) : ?>
<li><?php echo esc_html( $error ); ?></li>
<?php endforeach; ?>
</ul>
<?php endif; ?>
</div>
<?php endif; ?>
<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>">
<input type="hidden" name="action" value="fragrance_trade_import_case_seeds">
<?php wp_nonce_field( 'fragrance_trade_import_case_seeds' ); ?>
<?php submit_button( __( '一键初始化服务与案例', 'fragrance-trade' ), 'primary', 'submit', false ); ?>
</form>
</div>
<?php
}
/** Handle the bundled-content importer form submission. */
function fragrance_trade_handle_case_seed_import() {
if ( ! current_user_can( 'edit_theme_options' ) ) {
wp_die( esc_html__( '您没有权限初始化案例。', 'fragrance-trade' ) );
}
check_admin_referer( 'fragrance_trade_import_case_seeds' );
$services = fragrance_trade_import_product_service_seeds();
$cases = fragrance_trade_import_case_seeds();
$result = array(
'services' => $services,
'cases' => $cases,
'errors' => array_values( array_unique( array_merge( $services['errors'], $cases['errors'] ) ) ),
);
set_transient(
'fragrance_trade_case_import_result_' . get_current_user_id(),
$result,
5 * MINUTE_IN_SECONDS
);
wp_safe_redirect( admin_url( 'themes.php?page=fragrance-case-import' ) );
exit;
}
add_action( 'admin_post_fragrance_trade_import_case_seeds', 'fragrance_trade_handle_case_seed_import' );
+67 -2
View File
@@ -345,9 +345,63 @@ function fragrance_trade_create_required_pages( &$errors ) {
return $result;
}
/**
* Preserve an existing posts page or create the conventional news page.
*
* @param string[] $errors Setup errors collected by the caller.
* @return array{id:int,changed:bool}
*/
function fragrance_trade_ensure_news_page( &$errors ) {
$result = array( 'id' => 0, 'changed' => false );
$current_page_id = absint( get_option( 'page_for_posts', 0 ) );
$current_page = $current_page_id ? get_post( $current_page_id ) : null;
if ( $current_page && 'page' === $current_page->post_type ) {
$result['id'] = $current_page_id;
return $result;
}
$news_page = fragrance_trade_find_required_page( 'news' );
if ( ! $news_page ) {
$news_page_id = wp_insert_post(
array(
'post_type' => 'page',
'post_name' => 'news',
'post_title' => __( '新闻资讯', 'fragrance-trade' ),
'post_status' => 'publish',
),
true
);
if ( is_wp_error( $news_page_id ) ) {
$errors[] = sprintf(
/* translators: %s: error message. */
__( '无法创建新闻资讯页面:%s', 'fragrance-trade' ),
$news_page_id->get_error_message()
);
return $result;
}
$news_page = get_post( $news_page_id );
$result['changed'] = true;
}
$news_page_id = (int) $news_page->ID;
if ( $current_page_id !== $news_page_id ) {
update_option( 'page_for_posts', $news_page_id );
if ( $news_page_id !== absint( get_option( 'page_for_posts', 0 ) ) ) {
$errors[] = __( '无法将新闻资讯页面设置为 WordPress 文章页。', 'fragrance-trade' );
return $result;
}
$result['changed'] = true;
}
$result['id'] = $news_page_id;
return $result;
}
/** Versioned and retryable site setup. */
function fragrance_trade_maybe_setup_site() {
$target_version = 3;
$target_version = 4;
if ( (int) get_option( 'fragrance_trade_schema_version', 0 ) >= $target_version ) {
return;
}
@@ -356,12 +410,13 @@ function fragrance_trade_maybe_setup_site() {
$seed_changed = fragrance_trade_create_seed_services( $errors );
$copy_changed = fragrance_trade_migrate_seed_service_copy( $errors );
$page_result = fragrance_trade_create_required_pages( $errors );
$news_result = fragrance_trade_ensure_news_page( $errors );
if ( ! empty( $page_result['pages']['home'] ) ) {
update_option( 'page_on_front', $page_result['pages']['home'] );
update_option( 'show_on_front', 'page' );
}
if ( $seed_changed || $copy_changed || $page_result['changed'] ) {
if ( $seed_changed || $copy_changed || $page_result['changed'] || $news_result['changed'] ) {
flush_rewrite_rules();
}
@@ -412,6 +467,16 @@ function fragrance_trade_page_status_notice() {
$unpublished[] = $page->post_title;
}
}
$posts_page_id = absint( get_option( 'page_for_posts', 0 ) );
$posts_page = $posts_page_id ? get_post( $posts_page_id ) : null;
if (
$posts_page
&& 'page' === $posts_page->post_type
&& 'publish' !== $posts_page->post_status
&& ! in_array( $posts_page->post_title, $unpublished, true )
) {
$unpublished[] = $posts_page->post_title;
}
if ( ! $unpublished ) {
return;
}
+8
View File
@@ -92,10 +92,18 @@ function fragrance_trade_customize_register( $wp_customize ) {
array( 'youtube_url', 'fragrance_contact_social', __( 'YouTube 链接', 'fragrance-trade' ), 'url' ),
array( 'linkedin_url', 'fragrance_contact_social', __( 'LinkedIn 链接', 'fragrance-trade' ), 'url' ),
array( 'instagram_social_url', 'fragrance_contact_social', __( 'Instagram 链接', 'fragrance-trade' ), 'url' ),
array( 'store_brand', 'fragrance_contact_social', __( '主营品牌', 'fragrance-trade' ), 'text' ),
array( 'store_authorization', 'fragrance_contact_social', __( '授权级别', 'fragrance-trade' ), 'text' ),
array( 'store_city', 'fragrance_contact_social', __( '所在城市', 'fragrance-trade' ), 'text' ),
array( 'store_contact_person', 'fragrance_contact_social', __( '门店联系人', 'fragrance-trade' ), 'text' ),
array( 'store_address', 'fragrance_contact_social', __( '门店地址', 'fragrance-trade' ), 'textarea' ),
array( 'store_phone', 'fragrance_contact_social', __( '联系电话', 'fragrance-trade' ), 'text' ),
array( 'store_hours', 'fragrance_contact_social', __( '营业时间', 'fragrance-trade' ), 'text' ),
array( 'store_map_url', 'fragrance_contact_social', __( '地图导航链接', 'fragrance-trade' ), 'url' ),
array( 'store_map_lat', 'fragrance_contact_social', __( '百度地图纬度', 'fragrance-trade' ), 'text' ),
array( 'store_map_lng', 'fragrance_contact_social', __( '百度地图经度', 'fragrance-trade' ), 'text' ),
array( 'icp_number', 'fragrance_contact_social', __( 'ICP备案号', 'fragrance-trade' ), 'text' ),
array( 'icp_url', 'fragrance_contact_social', __( 'ICP备案查询链接', 'fragrance-trade' ), 'url' ),
array( 'footer_text', 'fragrance_contact_social', __( '页脚定位文案', 'fragrance-trade' ), 'text' ),
);
+14 -6
View File
@@ -18,8 +18,8 @@ function fragrance_trade_defaults() {
$defaults = array(
'b2b_hero_eyebrow' => __( '需求沟通 · 方案确认 · 施工交付', 'fragrance-trade' ),
'b2b_hero_title' => __( 'xxx店铺名字', 'fragrance-trade' ),
'b2b_hero_text' => __( 'xxx地址', 'fragrance-trade' ),
'b2b_hero_title' => __( '康得新合肥新创贴膜中心(官方授权店)', 'fragrance-trade' ),
'b2b_hero_text' => __( '康得新 KDX 官方授权至尊服务店,位于合肥市瑶海区铜陵北路高架桥出口与铜陵北路辅路交叉口东北140米。', 'fragrance-trade' ),
'b2b_hero_primary_label' => __( '联系门店', 'fragrance-trade' ),
'b2b_hero_primary_url' => '/contact/',
'b2b_hero_secondary_label' => __( '了解服务项目', 'fragrance-trade' ),
@@ -85,11 +85,19 @@ function fragrance_trade_defaults() {
'youtube_url' => '',
'linkedin_url' => '',
'instagram_social_url' => '',
'store_address' => '',
'store_phone' => __( 'xxx电话', 'fragrance-trade' ),
'store_hours' => '',
'store_brand' => __( '康得新 KDX', 'fragrance-trade' ),
'store_authorization' => __( '官方授权至尊服务店', 'fragrance-trade' ),
'store_city' => __( '合肥市', 'fragrance-trade' ),
'store_contact_person' => __( '贾文浩', 'fragrance-trade' ),
'store_address' => __( '合肥市瑶海区铜陵北路高架桥出口与铜陵北路辅路交叉口东北140米', 'fragrance-trade' ),
'store_phone' => '18655174646',
'store_hours' => __( '09:0022:30', 'fragrance-trade' ),
'store_map_url' => '',
'footer_text' => __( '专注汽车贴膜方案沟通、施工交付与日常护理说明。', 'fragrance-trade' ),
'store_map_lat' => '31.907786',
'store_map_lng' => '117.336666',
'icp_number' => '',
'icp_url' => 'https://beian.miit.gov.cn/',
'footer_text' => __( '康得新 KDX 官方授权至尊服务店,提供隐形车衣、改色膜与汽车隔热膜服务。', 'fragrance-trade' ),
);
return $defaults;
+121 -1
View File
@@ -32,6 +32,74 @@ function fragrance_trade_image_uri( $setting, $fallback_filename ) {
return $image ? $image : fragrance_trade_asset_uri( 'images/' . $fallback_filename );
}
/**
* Return the horizontal image used by service cards and carousels.
*
* Product seeds use a dedicated landscape cover while their featured image
* remains the complete parameter poster shown on the service detail page.
*
* @param int $post_id Service post ID.
* @param string $fallback_filename Asset path below assets/images/.
* @return string
*/
function fragrance_trade_service_card_image( $post_id, $fallback_filename = 'products/placeholder-01.svg' ) {
$post_id = absint( $post_id );
$image_attr = array(
'class' => 'img-fluid',
'loading' => 'lazy',
'decoding' => 'async',
);
$cover_id = absint( get_post_meta( $post_id, '_fragrance_service_cover_id', true ) );
if ( $cover_id ) {
$image = wp_get_attachment_image( $cover_id, 'large', false, $image_attr );
if ( $image ) {
return $image;
}
}
$cover_file = (string) get_post_meta( $post_id, '_fragrance_service_cover_file', true );
if ( ! $cover_file && function_exists( 'fragrance_trade_product_service_seeds' ) ) {
$seeds = fragrance_trade_product_service_seeds();
$seed_key = (string) get_post_meta( $post_id, '_fragrance_product_seed_key', true );
if ( $seed_key && isset( $seeds[ $seed_key ]['cover'] ) ) {
$cover_file = $seeds[ $seed_key ]['cover'];
} else {
$post_slug = (string) get_post_field( 'post_name', $post_id );
foreach ( $seeds as $seed ) {
if ( $post_slug === $seed['slug'] && ! empty( $seed['cover'] ) ) {
$cover_file = $seed['cover'];
break;
}
}
}
}
if (
$cover_file
&& preg_match( '#^[a-zA-Z0-9/_-]+\.(?:jpe?g|png|webp)$#', $cover_file )
&& is_readable( get_template_directory() . '/assets/images/services/' . $cover_file )
) {
return sprintf(
'<img src="%1$s" alt="%2$s" class="img-fluid" width="1448" height="1086" loading="lazy" decoding="async">',
esc_url( fragrance_trade_asset_uri( 'images/services/' . $cover_file ) ),
esc_attr( get_the_title( $post_id ) )
);
}
if ( has_post_thumbnail( $post_id ) ) {
return (string) get_the_post_thumbnail( $post_id, 'fragrance-capability', $image_attr );
}
$legacy_image = get_post_meta( $post_id, '_service_image', true );
return sprintf(
'<img src="%1$s" alt="%2$s" class="img-fluid" loading="lazy" decoding="async">',
esc_url( $legacy_image ? $legacy_image : fragrance_trade_asset_uri( 'images/' . ltrim( $fallback_filename, '/' ) ) ),
esc_attr( get_the_title( $post_id ) )
);
}
function fragrance_trade_show_section( $setting ) {
return (bool) fragrance_trade_get_mod( $setting, true );
}
@@ -56,11 +124,36 @@ function fragrance_trade_get_inquiry_url( $project = '' ) {
return 'mailto:' . antispambot( fragrance_trade_inquiry_email() ) . '?subject=' . rawurlencode( __( '汽车贴膜服务咨询', 'fragrance-trade' ) ) . '&body=' . rawurlencode( $message );
}
/** Return the configured WordPress posts-page URL with a stable fresh-site fallback. */
function fragrance_trade_news_url() {
$posts_page_id = absint( get_option( 'page_for_posts', 0 ) );
$posts_page = $posts_page_id ? get_post( $posts_page_id ) : null;
if ( $posts_page && 'page' === $posts_page->post_type ) {
$url = get_permalink( $posts_page_id );
if ( $url ) {
return $url;
}
}
return home_url( '/news/' );
}
/** Keep news grids aligned without changing the site's global reading option. */
function fragrance_trade_news_posts_per_page( $query ) {
if ( is_admin() || ! $query->is_main_query() || $query->is_feed() ) {
return;
}
if ( $query->is_home() || $query->is_category() || $query->is_tag() || $query->is_date() || $query->is_author() ) {
$query->set( 'posts_per_page', 9 );
}
}
add_action( 'pre_get_posts', 'fragrance_trade_news_posts_per_page' );
function fragrance_trade_primary_menu_fallback() {
$links = array(
array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ),
array( 'label' => __( '服务项目', 'fragrance-trade' ), 'url' => get_post_type_archive_link( 'service' ) ?: home_url( '/services/' ) ),
array( 'label' => __( '案例作品', 'fragrance-trade' ), 'url' => get_post_type_archive_link( 'case' ) ?: home_url( '/cases/' ) ),
array( 'label' => __( '新闻资讯', 'fragrance-trade' ), 'url' => fragrance_trade_news_url() ),
array( 'label' => __( '关于门店', 'fragrance-trade' ), 'url' => home_url( '/about/' ) ),
array( 'label' => __( '常见问题', 'fragrance-trade' ), 'url' => home_url( '/faq/' ) ),
array( 'label' => __( '联系我们', 'fragrance-trade' ), 'url' => home_url( '/contact/' ) ),
@@ -102,7 +195,34 @@ add_action(
printf(
'<div class="notice notice-warning is-dismissible"><p><strong>%s</strong> %s <a href="%s">%s</a></p></div>',
esc_html__( '主导航菜单项过少', 'fragrance-trade' ),
esc_html__( '手机端和桌面端导航目前只显示一个菜单项。请前往后台添加:首页、服务项目、案例作品、关于门店、常见问题、联系我们。', 'fragrance-trade' ),
esc_html__( '手机端和桌面端导航目前只显示一个菜单项。请前往后台添加:首页、服务项目、案例作品、新闻资讯、关于门店、常见问题、联系我们。', 'fragrance-trade' ),
esc_url( admin_url( 'nav-menus.php' ) ),
esc_html__( '编辑菜单', 'fragrance-trade' )
);
}
$news_page_id = absint( get_option( 'page_for_posts', 0 ) );
$news_page = $news_page_id ? get_post( $news_page_id ) : null;
if ( ! $news_page || 'publish' !== $news_page->post_status ) {
return;
}
$news_url = untrailingslashit( fragrance_trade_news_url() );
$has_news_link = false;
foreach ( (array) $items as $item ) {
if (
( 'page' === $item->object && $news_page_id === (int) $item->object_id )
|| $news_url === untrailingslashit( $item->url )
) {
$has_news_link = true;
break;
}
}
if ( ! $has_news_link ) {
printf(
'<div class="notice notice-warning is-dismissible"><p><strong>%s</strong> %s <a href="%s">%s</a></p></div>',
esc_html__( '主导航尚未包含新闻资讯', 'fragrance-trade' ),
esc_html__( '主题不会自动修改已分配的菜单,请将 WordPress 文章页添加到“主导航”。', 'fragrance-trade' ),
esc_url( admin_url( 'nav-menus.php' ) ),
esc_html__( '编辑菜单', 'fragrance-trade' )
);
+385
View File
@@ -0,0 +1,385 @@
<?php
/**
* Optional one-click importer for the bundled KDX service products.
*
* @package Fragrance_Trade
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
/** Return every post status that may contain an existing optional seed. */
function fragrance_trade_seed_post_statuses() {
return array( 'publish', 'pending', 'draft', 'auto-draft', 'future', 'private', 'inherit', 'trash' );
}
/** Return the product service records available to the optional importer. */
function fragrance_trade_product_service_seeds() {
return array(
'kdx-dunjia' => array(
'title' => __( 'KDX 盾甲隐形车衣', 'fragrance-trade' ),
'slug' => 'kdx-dunjia-paint-protection-film',
'image' => 'kdx-dunjia.jpg',
'cover' => 'covers/kdx-dunjia-cover.jpg',
'excerpt' => __( '7.5mil 厚度 · 7 年质保 · 光泽度 150', 'fragrance-trade' ),
'summary' => __( '盾甲是一款兼顾车漆保护、亮面效果与日常养护的隐形车衣产品,适合关注基础防护与光泽表现的用车场景。', 'fragrance-trade' ),
'specs' => array(
__( '产品厚度', 'fragrance-trade' ) => '7.5mil',
__( '质保年限', 'fragrance-trade' ) => __( '7 年', 'fragrance-trade' ),
__( '光泽度', 'fragrance-trade' ) => '150',
__( '拉伸强度', 'fragrance-trade' ) => '18MPa',
__( '断裂伸长率', 'fragrance-trade' ) => '380%',
__( '耐有机溶剂性', 'fragrance-trade' ) => __( '通过', 'fragrance-trade' ),
__( '水接触角', 'fragrance-trade' ) => '102°',
__( '耐粘污性', 'fragrance-trade' ) => __( '良好', 'fragrance-trade' ),
__( '热修复', 'fragrance-trade' ) => __( '60 秒', 'fragrance-trade' ),
),
),
'kdx-kaijia-plus' => array(
'title' => __( 'KDX 铠甲 Plus 隐形车衣', 'fragrance-trade' ),
'slug' => 'kdx-kaijia-plus-paint-protection-film',
'image' => 'kdx-kaijia-plus.jpg',
'cover' => 'covers/kdx-kaijia-plus-cover.jpg',
'excerpt' => __( '8.5mil 厚度 · 8 年质保 · 断裂伸长率 460%', 'fragrance-trade' ),
'summary' => __( '铠甲 Plus 采用更高的标称厚度和断裂伸长率,适合希望进一步提升车漆覆盖防护与膜面韧性的用车需求。', 'fragrance-trade' ),
'specs' => array(
__( '产品厚度', 'fragrance-trade' ) => '8.5mil',
__( '质保年限', 'fragrance-trade' ) => __( '8 年', 'fragrance-trade' ),
__( '光泽度', 'fragrance-trade' ) => '150',
__( '拉伸强度', 'fragrance-trade' ) => '23MPa',
__( '断裂伸长率', 'fragrance-trade' ) => '460%',
__( '耐有机溶剂性', 'fragrance-trade' ) => __( '通过', 'fragrance-trade' ),
__( '水接触角', 'fragrance-trade' ) => '73°',
__( '耐粘污性', 'fragrance-trade' ) => __( '良好', 'fragrance-trade' ),
__( '热修复', 'fragrance-trade' ) => __( '60 秒', 'fragrance-trade' ),
),
),
'kdx-kaijia' => array(
'title' => __( 'KDX 铠甲隐形车衣', 'fragrance-trade' ),
'slug' => 'kdx-kaijia-paint-protection-film',
'image' => 'kdx-kaijia.jpg',
'cover' => 'covers/kdx-kaijia-cover.jpg',
'excerpt' => __( '7.5mil 厚度 · 7 年质保 · 拉伸强度 25MPa', 'fragrance-trade' ),
'summary' => __( '铠甲隐形车衣侧重膜面韧性、亮面效果与基础耐粘污表现,并提供雾度、可见光透射比和剥离力等补充参数。', 'fragrance-trade' ),
'specs' => array(
__( '产品厚度', 'fragrance-trade' ) => '7.5mil',
__( '质保年限', 'fragrance-trade' ) => __( '7 年', 'fragrance-trade' ),
__( '光泽度', 'fragrance-trade' ) => '150',
__( '拉伸强度', 'fragrance-trade' ) => '25MPa',
__( '断裂伸长率', 'fragrance-trade' ) => '430%',
__( '耐有机溶剂性', 'fragrance-trade' ) => __( '通过', 'fragrance-trade' ),
__( '水接触角', 'fragrance-trade' ) => '73°',
__( '耐粘污性', 'fragrance-trade' ) => __( '三星', 'fragrance-trade' ),
__( '热修复', 'fragrance-trade' ) => __( '60 秒', 'fragrance-trade' ),
__( '雾度', 'fragrance-trade' ) => '0.3%',
__( '可见光透射比', 'fragrance-trade' ) => '90%',
__( '180°剥离力(30 分钟)', 'fragrance-trade' ) => '1400gf/inch',
__( '180°剥离力(2 小时)', 'fragrance-trade' ) => '1800gf/inch',
__( '涂层断裂伸长率', 'fragrance-trade' ) => '160%',
),
),
'kdx-dunjia-plus' => array(
'title' => __( 'KDX 盾甲 Plus 隐形车衣', 'fragrance-trade' ),
'slug' => 'kdx-dunjia-plus-paint-protection-film',
'image' => 'kdx-dunjia-plus.jpg',
'cover' => 'covers/kdx-dunjia-plus-cover.jpg',
'excerpt' => __( '8.5mil 厚度 · 8 年质保 · 水接触角 102°', 'fragrance-trade' ),
'summary' => __( '盾甲 Plus 在盾甲产品方向上提升标称厚度与质保年限,兼顾膜面亮度、水接触角和日常车漆保护需求。', 'fragrance-trade' ),
'specs' => array(
__( '产品厚度', 'fragrance-trade' ) => '8.5mil',
__( '质保年限', 'fragrance-trade' ) => __( '8 年', 'fragrance-trade' ),
__( '光泽度', 'fragrance-trade' ) => '150',
__( '拉伸强度', 'fragrance-trade' ) => '21MPa',
__( '断裂伸长率', 'fragrance-trade' ) => '400%',
__( '耐有机溶剂性', 'fragrance-trade' ) => __( '通过', 'fragrance-trade' ),
__( '水接触角', 'fragrance-trade' ) => '102°',
__( '耐粘污性', 'fragrance-trade' ) => __( '良好', 'fragrance-trade' ),
__( '热修复', 'fragrance-trade' ) => __( '60 秒', 'fragrance-trade' ),
),
),
'kdx-jinjia-pro' => array(
'title' => __( 'KDX 金甲 PRO 隐形车衣', 'fragrance-trade' ),
'slug' => 'kdx-jinjia-pro-paint-protection-film',
'image' => 'kdx-jinjia-pro.jpg',
'cover' => 'covers/kdx-jinjia-pro-cover.jpg',
'excerpt' => __( '7.5mil 厚度 · 8 年质保 · 光泽度 153', 'fragrance-trade' ),
'summary' => __( '金甲 PRO 侧重高光泽、耐粘污表现与较长质保周期,适合关注亮面质感和日常清洁便利性的车漆保护方案。', 'fragrance-trade' ),
'specs' => array(
__( '产品厚度', 'fragrance-trade' ) => '7.5mil',
__( '质保年限', 'fragrance-trade' ) => __( '8 年', 'fragrance-trade' ),
__( '光泽度', 'fragrance-trade' ) => '153',
__( '拉伸强度', 'fragrance-trade' ) => '18MPa',
__( '断裂伸长率', 'fragrance-trade' ) => '350%',
__( '耐有机溶剂性', 'fragrance-trade' ) => __( '通过', 'fragrance-trade' ),
__( '水接触角', 'fragrance-trade' ) => '95°',
__( '耐粘污性', 'fragrance-trade' ) => __( '优秀', 'fragrance-trade' ),
__( '热修复', 'fragrance-trade' ) => __( '90 秒', 'fragrance-trade' ),
),
),
);
}
/** Find a product service previously created by this importer. */
function fragrance_trade_find_product_service_seed( $seed_key ) {
$ids = get_posts(
array(
'post_type' => 'service',
'post_status' => fragrance_trade_seed_post_statuses(),
'posts_per_page' => 1,
'fields' => 'ids',
'meta_key' => '_fragrance_product_seed_key',
'meta_value' => $seed_key,
'no_found_rows' => true,
)
);
return $ids ? (int) $ids[0] : 0;
}
/** Find a service with the conventional product slug. */
function fragrance_trade_find_product_service_slug( $slug ) {
$posts = get_posts(
array(
'post_type' => 'service',
'post_status' => fragrance_trade_seed_post_statuses(),
'name' => $slug,
'posts_per_page' => 1,
'no_found_rows' => true,
)
);
return $posts ? (int) $posts[0]->ID : 0;
}
/** Find a bundled product image already copied into the media library. */
function fragrance_trade_find_product_service_attachment( $seed_key ) {
$ids = get_posts(
array(
'post_type' => 'attachment',
'post_status' => 'inherit',
'posts_per_page' => 1,
'fields' => 'ids',
'meta_key' => '_fragrance_product_seed_image',
'meta_value' => $seed_key,
'no_found_rows' => true,
)
);
return $ids ? (int) $ids[0] : 0;
}
/**
* Copy one bundled service image into the WordPress media library.
*
* @param int $service_id Parent service post ID.
* @param string $seed_key Stable service seed key.
* @param array $seed Service seed record.
* @return int|WP_Error
*/
function fragrance_trade_import_product_service_image( $service_id, $seed_key, $seed ) {
$existing = fragrance_trade_find_product_service_attachment( $seed_key );
if ( $existing ) {
if ( (int) wp_get_post_parent_id( $existing ) !== (int) $service_id ) {
wp_update_post(
array(
'ID' => $existing,
'post_parent' => $service_id,
)
);
}
return $existing;
}
$source_file = get_template_directory() . '/assets/images/services/' . $seed['image'];
if ( ! is_readable( $source_file ) ) {
return new WP_Error(
'fragrance_product_seed_image_missing',
sprintf(
/* translators: %s: service title. */
__( '服务“%s”的初始化图片不存在。', 'fragrance-trade' ),
$seed['title']
)
);
}
$image_bytes = file_get_contents( $source_file );
if ( false === $image_bytes ) {
return new WP_Error(
'fragrance_product_seed_image_unreadable',
sprintf(
/* translators: %s: service title. */
__( '无法读取服务“%s”的初始化图片。', 'fragrance-trade' ),
$seed['title']
)
);
}
$upload = wp_upload_bits( $seed['image'], null, $image_bytes );
unset( $image_bytes );
if ( ! empty( $upload['error'] ) ) {
return new WP_Error( 'fragrance_product_seed_upload_failed', $upload['error'] );
}
$attachment_id = wp_insert_attachment(
array(
'post_mime_type' => 'image/jpeg',
'post_title' => sprintf(
/* translators: %s: service title. */
__( '%s产品参数图', 'fragrance-trade' ),
$seed['title']
),
'post_status' => 'inherit',
),
$upload['file'],
$service_id,
true
);
if ( is_wp_error( $attachment_id ) ) {
wp_delete_file( $upload['file'] );
return $attachment_id;
}
require_once ABSPATH . 'wp-admin/includes/image.php';
$metadata = wp_generate_attachment_metadata( $attachment_id, $upload['file'] );
if ( $metadata ) {
wp_update_attachment_metadata( $attachment_id, $metadata );
}
update_post_meta( $attachment_id, '_fragrance_product_seed_image', $seed_key );
update_post_meta(
$attachment_id,
'_wp_attachment_image_alt',
sprintf(
/* translators: %s: service title. */
__( '%s产品参数与车型示意图', 'fragrance-trade' ),
$seed['title']
)
);
return (int) $attachment_id;
}
/** Build block-editor content for a product service. */
function fragrance_trade_build_product_service_content( $seed ) {
$items = '';
foreach ( $seed['specs'] as $label => $value ) {
$items .= sprintf(
'<li><strong>%1$s</strong>%2$s</li>',
esc_html( $label ),
esc_html( $value )
);
}
return sprintf(
'<!-- wp:paragraph --><p>%1$s</p><!-- /wp:paragraph -->' .
'<!-- wp:heading --><h2 class="wp-block-heading">%2$s</h2><!-- /wp:heading -->' .
'<!-- wp:list --><ul class="wp-block-list">%3$s</ul><!-- /wp:list -->' .
'<!-- wp:paragraph --><p><em>%4$s</em></p><!-- /wp:paragraph -->',
esc_html( $seed['summary'] ),
esc_html__( '产品参数', 'fragrance-trade' ),
$items,
esc_html__( '以上参数根据所提供的产品资料整理。实际产品版本、施工范围、价格、质保条件与交付标准请以门店最终确认及正式质保文件为准。', 'fragrance-trade' )
);
}
/**
* Import every bundled product service without overwriting existing content.
*
* @return array{created:int,existing:int,errors:string[]}
*/
function fragrance_trade_import_product_service_seeds() {
$result = array(
'created' => 0,
'existing' => 0,
'errors' => array(),
);
foreach ( fragrance_trade_product_service_seeds() as $seed_key => $seed ) {
$service_id = fragrance_trade_find_product_service_seed( $seed_key );
if ( $service_id && 'publish' === get_post_status( $service_id ) ) {
update_post_meta( $service_id, '_fragrance_service_cover_file', $seed['cover'] );
++$result['existing'];
continue;
}
if (
$service_id
&& (
'draft' !== get_post_status( $service_id )
|| 'importing' !== get_post_meta( $service_id, '_fragrance_product_seed_state', true )
)
) {
update_post_meta( $service_id, '_fragrance_service_cover_file', $seed['cover'] );
++$result['existing'];
continue;
}
if ( ! $service_id ) {
if ( fragrance_trade_find_product_service_slug( $seed['slug'] ) ) {
++$result['existing'];
continue;
}
$service_id = wp_insert_post(
array(
'post_type' => 'service',
'post_name' => $seed['slug'],
'post_title' => $seed['title'],
'post_excerpt' => $seed['excerpt'],
'post_status' => 'draft',
),
true
);
if ( is_wp_error( $service_id ) ) {
$result['errors'][] = sprintf(
/* translators: 1: service title, 2: error message. */
__( '无法创建服务“%1$s”:%2$s', 'fragrance-trade' ),
$seed['title'],
$service_id->get_error_message()
);
continue;
}
update_post_meta( $service_id, '_fragrance_product_seed_key', $seed_key );
update_post_meta( $service_id, '_fragrance_product_seed_state', 'importing' );
update_post_meta( $service_id, '_fragrance_service_cover_file', $seed['cover'] );
}
$attachment_id = fragrance_trade_import_product_service_image( $service_id, $seed_key, $seed );
if ( is_wp_error( $attachment_id ) ) {
$result['errors'][] = $attachment_id->get_error_message();
continue;
}
set_post_thumbnail( $service_id, $attachment_id );
$updated = wp_update_post(
array(
'ID' => $service_id,
'post_title' => $seed['title'],
'post_name' => $seed['slug'],
'post_excerpt' => $seed['excerpt'],
'post_content' => fragrance_trade_build_product_service_content( $seed ),
'post_status' => 'publish',
),
true
);
if ( is_wp_error( $updated ) ) {
$result['errors'][] = sprintf(
/* translators: 1: service title, 2: error message. */
__( '无法发布服务“%1$s”:%2$s', 'fragrance-trade' ),
$seed['title'],
$updated->get_error_message()
);
continue;
}
delete_post_meta( $service_id, '_fragrance_product_seed_state' );
update_post_meta( $service_id, '_fragrance_service_cover_file', $seed['cover'] );
++$result['created'];
}
$result['errors'] = array_values( array_unique( $result['errors'] ) );
return $result;
}
+141 -3
View File
@@ -2,9 +2,9 @@
# This file is distributed under the GNU General Public License v2 or later.
msgid ""
msgstr ""
"Project-Id-Version: B2B Trade 2.1.0\n"
"Project-Id-Version: B2B Trade 2.2.0\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2026-07-24 14:19+0000\n"
"POT-Creation-Date: 2026-07-26 00:00+0000\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
@@ -335,7 +335,7 @@ msgid "想先了解适合哪种贴膜方案?"
msgstr ""
#: inc/helpers.php:105
msgid "手机端和桌面端导航目前只显示一个菜单项。请前往后台添加:首页、服务项目、案例作品、关于门店、常见问题、联系我们。"
msgid "手机端和桌面端导航目前只显示一个菜单项。请前往后台添加:首页、服务项目、案例作品、新闻资讯、关于门店、常见问题、联系我们。"
msgstr ""
#: header.php:32
@@ -968,3 +968,141 @@ msgstr ""
#: inc/defaults.php
msgid "xxx电话"
msgstr ""
#: template-parts/home/case-teaser.php:66
msgid "下一组案例"
msgstr ""
#: template-parts/home/service-teaser.php:70
msgid "下一组服务项目"
msgstr ""
#: template-parts/home/case-teaser.php:62
msgid "上一组案例"
msgstr ""
#: template-parts/home/service-teaser.php:66
msgid "上一组服务项目"
msgstr ""
#: template-parts/home/case-teaser.php:61
msgid "案例作品轮播控制"
msgstr ""
#: template-parts/home/service-teaser.php:65
msgid "服务项目轮播控制"
msgstr ""
#: template-parts/home/case-teaser.php:27
#: template-parts/home/service-teaser.php:29
#, php-format
msgid "转到第 %d 组"
msgstr ""
#: footer.php home.php archive.php single-post.php inc/cpt.php inc/helpers.php
msgid "新闻资讯"
msgstr ""
#. translators: %s: error message.
#: inc/cpt.php
#, php-format
msgid "无法创建新闻资讯页面:%s"
msgstr ""
#: inc/cpt.php
msgid "无法将新闻资讯页面设置为 WordPress 文章页。"
msgstr ""
#: inc/helpers.php
msgid "主导航尚未包含新闻资讯"
msgstr ""
#: inc/helpers.php
msgid "主题不会自动修改已分配的菜单,请将 WordPress 文章页添加到“主导航”。"
msgstr ""
#: home.php
msgid "门店动态与用车知识"
msgstr ""
#: home.php
msgid "了解门店活动、产品信息、施工知识与汽车膜日常护理建议。"
msgstr ""
#: home.php
msgid "新闻内容正在整理中"
msgstr ""
#: home.php
msgid "门店动态、产品知识和施工说明将在这里陆续发布。"
msgstr ""
#: template-parts/content-news-card.php
msgid "阅读全文"
msgstr ""
#. translators: %s: news article title.
#: template-parts/content-news-card.php
#, php-format
msgid "阅读%s"
msgstr ""
#: archive.php
msgid "新闻归档"
msgstr ""
#: archive.php
msgid "此归档暂时没有新闻"
msgstr ""
#: archive.php
msgid "可以返回新闻资讯页面浏览其他内容。"
msgstr ""
#: archive.php
msgid "返回新闻资讯"
msgstr ""
#: single-post.php
msgid "文章分页"
msgstr ""
#: single-post.php
msgid "上一篇"
msgstr ""
#: single-post.php
msgid "下一篇"
msgstr ""
#: single-post.php
msgid "新闻文章导航"
msgstr ""
#: single-post.php
msgid "需要了解适合车辆的贴膜方案?"
msgstr ""
#: single-post.php
msgid "提供车型、使用场景和关注的问题,门店会结合实际情况说明可选项目。"
msgstr ""
#: single-post.php
msgid "咨询贴膜方案"
msgstr ""
#: inc/customizer.php
msgid "ICP备案号"
msgstr ""
#: inc/customizer.php
msgid "ICP备案查询链接"
msgstr ""
#: inc/customizer.php
msgid "百度地图纬度"
msgstr ""
#: inc/customizer.php
msgid "百度地图经度"
msgstr ""
+58 -7
View File
@@ -13,9 +13,15 @@ if ( ! defined( 'ABSPATH' ) ) {
get_header();
$store_name = fragrance_trade_get_mod( 'b2b_hero_title' );
$store_address = fragrance_trade_get_mod( 'store_address', '' );
$store_brand = fragrance_trade_get_mod( 'store_brand' );
$authorization = fragrance_trade_get_mod( 'store_authorization' );
$store_city = fragrance_trade_get_mod( 'store_city' );
$contact_name = fragrance_trade_get_mod( 'store_contact_person' );
$store_address = fragrance_trade_get_mod( 'store_address' );
$store_phone = fragrance_trade_get_mod( 'store_phone' );
$store_hours = fragrance_trade_get_mod( 'store_hours', '' );
$store_hours = fragrance_trade_get_mod( 'store_hours' );
$store_map_lat = fragrance_trade_get_mod( 'store_map_lat' );
$store_map_lng = fragrance_trade_get_mod( 'store_map_lng' );
$store_image = fragrance_trade_image_uri( 'b2b_factory_image_1', 'store/storefront.jpg' );
$phone_href = preg_replace( '/[^0-9+]/', '', $store_phone );
$has_phone = strlen( preg_replace( '/[^0-9]/', '', $phone_href ) ) >= 5;
@@ -26,10 +32,31 @@ if ( ! $store_address ) {
$map_nav_url = fragrance_trade_get_mod( 'store_map_url', '' );
$baidu_map_url = '';
if ( $store_address ) {
$baidu_map_url = 'https://api.map.baidu.com/geocoder?address='
. rawurlencode( $store_address )
$map_search_term = $store_name ? $store_name : $store_address;
$has_map_coordinates = is_numeric( $store_map_lat )
&& is_numeric( $store_map_lng )
&& (float) $store_map_lat >= -90
&& (float) $store_map_lat <= 90
&& (float) $store_map_lng >= -180
&& (float) $store_map_lng <= 180;
if ( $has_map_coordinates ) {
$baidu_map_url = 'https://api.map.baidu.com/marker?location='
. rawurlencode( $store_map_lat . ',' . $store_map_lng )
. '&title=' . rawurlencode( $store_name )
. '&content=' . rawurlencode( $store_address )
. '&output=html&src=webapp';
} elseif ( $map_search_term ) {
if ( $store_city ) {
$baidu_map_url = 'https://api.map.baidu.com/place/search?query='
. rawurlencode( $map_search_term )
. '&region=' . rawurlencode( $store_city )
. '&city_limit=true&output=html&src=webapp';
} else {
$baidu_map_url = 'https://api.map.baidu.com/geocoder?address='
. rawurlencode( $map_search_term )
. '&output=html&src=webapp';
}
}
if ( ! $map_nav_url ) {
$map_nav_url = $baidu_map_url;
@@ -97,6 +124,24 @@ $map_title = sprintf( __( '%s门店地图', 'fragrance-trade' ), $store_name );
<p class="contact-detail-label"><?php esc_html_e( '门店名称', 'fragrance-trade' ); ?></p>
<h3><?php echo esc_html( $store_name ); ?></h3>
</article>
<?php if ( $store_brand ) : ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '主营品牌', 'fragrance-trade' ); ?></p>
<h3><?php echo esc_html( $store_brand ); ?></h3>
</article>
<?php endif; ?>
<?php if ( $authorization ) : ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '授权级别', 'fragrance-trade' ); ?></p>
<h3><?php echo esc_html( $authorization ); ?></h3>
</article>
<?php endif; ?>
<?php if ( $contact_name ) : ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '门店联系人', 'fragrance-trade' ); ?></p>
<h3><?php echo esc_html( $contact_name ); ?></h3>
</article>
<?php endif; ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '联系电话', 'fragrance-trade' ); ?></p>
<?php if ( $store_phone ) : ?>
@@ -111,6 +156,12 @@ $map_title = sprintf( __( '%s门店地图', 'fragrance-trade' ), $store_name );
<p class="contact-detail-empty"><?php esc_html_e( '请在后台填写联系电话', 'fragrance-trade' ); ?></p>
<?php endif; ?>
</article>
<?php if ( $store_city ) : ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '所在城市', 'fragrance-trade' ); ?></p>
<h3><?php echo esc_html( $store_city ); ?></h3>
</article>
<?php endif; ?>
<article class="contact-detail-card">
<p class="contact-detail-label"><?php esc_html_e( '门店地址', 'fragrance-trade' ); ?></p>
<?php if ( $store_address ) : ?>
@@ -135,8 +186,8 @@ $map_title = sprintf( __( '%s门店地图', 'fragrance-trade' ), $store_name );
<div>
<p class="section-eyebrow"><?php esc_html_e( '地图与导航', 'fragrance-trade' ); ?></p>
<h2 id="contact-map-title"><?php esc_html_e( '找到门店', 'fragrance-trade' ); ?></h2>
<?php if ( $store_address ) : ?>
<p><?php echo esc_html( $store_address ); ?></p>
<?php if ( $store_city ) : ?>
<p><?php echo esc_html( $store_city ); ?></p>
<?php endif; ?>
</div>
<?php if ( $map_nav_url ) : ?>
+87
View File
@@ -0,0 +1,87 @@
<?php
/**
* Single news article template.
*
* @package Fragrance_Trade
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
get_header();
?>
<main id="primary" class="site-main">
<?php while ( have_posts() ) : the_post(); ?>
<article <?php post_class( 'page-content container news-single' ); ?>>
<?php
get_template_part(
'template-parts/breadcrumb',
null,
array(
'items' => array(
array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ),
array( 'label' => __( '新闻资讯', 'fragrance-trade' ), 'url' => fragrance_trade_news_url() ),
array( 'label' => get_the_title(), 'url' => null ),
),
)
);
?>
<header class="news-single-header">
<div class="news-meta">
<?php $categories = get_the_category_list( ' · ' ); ?>
<?php if ( $categories ) : ?>
<span class="news-categories"><?php echo wp_kses_post( $categories ); ?></span>
<?php endif; ?>
<time datetime="<?php echo esc_attr( get_the_date( DATE_W3C ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
</div>
<h1><?php the_title(); ?></h1>
</header>
<?php if ( has_post_thumbnail() ) : ?>
<figure class="news-single-image">
<?php the_post_thumbnail( 'large', array( 'class' => 'img-fluid', 'decoding' => 'async' ) ); ?>
</figure>
<?php endif; ?>
<div class="news-single-content">
<?php the_content(); ?>
<?php
wp_link_pages(
array(
'before' => '<nav class="page-links" aria-label="' . esc_attr__( '文章分页', 'fragrance-trade' ) . '">',
'after' => '</nav>',
)
);
?>
</div>
<?php
$previous_post = get_previous_post();
$next_post = get_next_post();
if ( $previous_post || $next_post ) :
?>
<div class="news-post-navigation">
<?php
the_post_navigation(
array(
'prev_text' => '<span class="nav-subtitle">' . esc_html__( '上一篇', 'fragrance-trade' ) . '</span><span class="nav-title">%title</span>',
'next_text' => '<span class="nav-subtitle">' . esc_html__( '下一篇', 'fragrance-trade' ) . '</span><span class="nav-title">%title</span>',
'in_same_term' => false,
'taxonomy' => 'category',
'screen_reader_text' => __( '新闻文章导航', 'fragrance-trade' ),
)
);
?>
</div>
<?php endif; ?>
<section class="news-single-cta">
<h2><?php esc_html_e( '需要了解适合车辆的贴膜方案?', 'fragrance-trade' ); ?></h2>
<p><?php esc_html_e( '提供车型、使用场景和关注的问题,门店会结合实际情况说明可选项目。', 'fragrance-trade' ); ?></p>
<a class="btn btn-b2b-primary" href="<?php echo esc_url( home_url( '/contact/' ) ); ?>"><?php esc_html_e( '咨询贴膜方案', 'fragrance-trade' ); ?></a>
</section>
</article>
<?php endwhile; ?>
</main>
<?php get_footer(); ?>
+2 -2
View File
@@ -2,8 +2,8 @@
Theme Name: B2B Trade
Theme URI: http://git.xgouo.cn/zhs123/car-t-t
Author: B2B Trade
Description: 专业汽车贴膜门店主题,支持服务项目、案例作品集、门店信息和直接联系,适配移动端。
Version: 2.1.0
Description: 专业汽车贴膜门店主题,支持服务项目、案例作品集、新闻资讯、门店信息和直接联系,适配移动端。
Version: 2.2.0
Requires at least: 6.8
Tested up to: 7.0
Requires PHP: 8.1
+38
View File
@@ -0,0 +1,38 @@
<?php
/**
* News card used by the posts page and native post archives.
*
* @package Fragrance_Trade
*/
if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$categories = get_the_category_list( ' · ' );
$media_label = sprintf(
/* translators: %s: news article title. */
__( '阅读%s', 'fragrance-trade' ),
get_the_title()
);
?>
<article id="post-<?php the_ID(); ?>" <?php post_class( 'news-card' ); ?>>
<a class="news-card-media" href="<?php the_permalink(); ?>" aria-label="<?php echo esc_attr( $media_label ); ?>">
<?php if ( has_post_thumbnail() ) : ?>
<?php the_post_thumbnail( 'medium_large', array( 'class' => 'img-fluid', 'loading' => 'lazy', 'decoding' => 'async' ) ); ?>
<?php else : ?>
<img src="<?php echo esc_url( fragrance_trade_asset_uri( 'images/placeholder-news.svg' ) ); ?>" alt="" width="1200" height="675" loading="lazy" decoding="async">
<?php endif; ?>
</a>
<div class="news-card-body">
<div class="news-meta">
<?php if ( $categories ) : ?>
<span class="news-categories"><?php echo wp_kses_post( $categories ); ?></span>
<?php endif; ?>
<time datetime="<?php echo esc_attr( get_the_date( DATE_W3C ) ); ?>"><?php echo esc_html( get_the_date() ); ?></time>
</div>
<h2><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h2>
<p><?php echo esc_html( wp_trim_words( get_the_excerpt(), 28 ) ); ?></p>
<a class="text-link" href="<?php the_permalink(); ?>"><?php esc_html_e( '阅读全文', 'fragrance-trade' ); ?></a>
</div>
</article>
+47 -11
View File
@@ -20,17 +20,53 @@ $case_query = new WP_Query(
<h2><?php esc_html_e( '从案例了解不同项目的实际效果', 'fragrance-trade' ); ?></h2>
</div>
<?php if ( $case_query->have_posts() ) : ?>
<div class="case-grid mt-5">
<?php while ( $case_query->have_posts() ) : $case_query->the_post(); ?>
<a class="case-card" href="<?php the_permalink(); ?>">
<?php if ( has_post_thumbnail() ) : ?>
<?php the_post_thumbnail( 'medium', array( 'class' => 'img-fluid' ) ); ?>
<?php else : ?>
<img src="<?php echo esc_url( fragrance_trade_asset_uri( 'images/products/placeholder-01.svg' ) ); ?>" alt="<?php the_title_attribute(); ?>" class="img-fluid">
<?php endif; ?>
<span class="case-card-title"><?php the_title(); ?></span>
</a>
<?php endwhile; wp_reset_postdata(); ?>
<div
class="b2b-carousel cases-carousel mt-5"
data-carousel
data-autoplay="9000"
data-page-label="<?php esc_attr_e( '转到第 %d 组', 'fragrance-trade' ); ?>"
role="region"
aria-roledescription="carousel"
aria-label="<?php esc_attr_e( '案例作品', 'fragrance-trade' ); ?>"
>
<div class="b2b-carousel-viewport">
<div class="case-grid b2b-carousel-track">
<?php
$count = 1;
$total_items = $case_query->post_count;
while ( $case_query->have_posts() ) :
$case_query->the_post();
?>
<a
class="case-card b2b-carousel-slide"
href="<?php the_permalink(); ?>"
role="group"
aria-roledescription="slide"
aria-label="<?php echo esc_attr( sprintf( '%1$d / %2$d', $count, $total_items ) ); ?>"
>
<?php if ( has_post_thumbnail() ) : ?>
<?php the_post_thumbnail( 'large', array( 'class' => 'img-fluid', 'loading' => 'lazy', 'decoding' => 'async' ) ); ?>
<?php else : ?>
<img src="<?php echo esc_url( fragrance_trade_asset_uri( 'images/products/placeholder-01.svg' ) ); ?>" alt="<?php the_title_attribute(); ?>" class="img-fluid" loading="lazy" decoding="async">
<?php endif; ?>
<span class="case-card-title"><?php the_title(); ?></span>
</a>
<?php
$count++;
endwhile;
wp_reset_postdata();
?>
</div>
</div>
<div class="b2b-carousel-controls" aria-label="<?php esc_attr_e( '案例作品轮播控制', 'fragrance-trade' ); ?>">
<button type="button" class="b2b-carousel-arrow b2b-carousel-prev" aria-label="<?php esc_attr_e( '上一组案例', 'fragrance-trade' ); ?>">
<span aria-hidden="true">←</span>
</button>
<div class="b2b-carousel-dots"></div>
<button type="button" class="b2b-carousel-arrow b2b-carousel-next" aria-label="<?php esc_attr_e( '下一组案例', 'fragrance-trade' ); ?>">
<span aria-hidden="true">→</span>
</button>
</div>
</div>
<div class="text-center mt-5">
<a href="<?php echo esc_url( home_url( '/cases/' ) ); ?>" class="btn btn-b2b-primary"><?php esc_html_e( '查看全部案例', 'fragrance-trade' ); ?></a>
+16 -4
View File
@@ -9,11 +9,18 @@ if ( ! defined( 'ABSPATH' ) ) {
exit;
}
$store_brand = fragrance_trade_get_mod( 'store_brand', __( '康得新 KDX', 'fragrance-trade' ) );
$authorization = fragrance_trade_get_mod( 'store_authorization', __( '官方授权至尊服务店', 'fragrance-trade' ) );
$credentials = array(
array(
'image' => 'store/kdx-logo.jpg',
'title' => __( 'KDX 品牌服务', 'fragrance-trade' ),
'description' => __( '门店展示的 KDX 品牌标识与产品服务体系。', 'fragrance-trade' ),
'title' => $store_brand,
'description' => sprintf(
/* translators: %s: store's primary brand. */
__( '门店主营 %s 汽车膜产品与施工服务。', 'fragrance-trade' ),
$store_brand
),
'alt' => __( 'KDX 品牌标识', 'fragrance-trade' ),
'width' => 1600,
'height' => 1472,
@@ -21,8 +28,13 @@ $credentials = array(
),
array(
'image' => 'store/authorization.jpg',
'title' => __( '授权服务资质', 'fragrance-trade' ),
'description' => __( 'KDX 汽车膜授权服务店证书,具体有效期以证书原件为准。', 'fragrance-trade' ),
'title' => $authorization,
'description' => sprintf(
/* translators: 1: brand, 2: authorization level. */
__( '%1$s %2$s,具体授权范围与有效期以证书原件为准。', 'fragrance-trade' ),
$store_brand,
$authorization
),
'alt' => __( 'KDX 汽车膜授权服务店证书', 'fragrance-trade' ),
'width' => 1600,
'height' => 1199,
+48 -22
View File
@@ -22,28 +22,54 @@ if ( ! $service_query->have_posts() ) {
<p class="section-eyebrow"><?php esc_html_e( '服务项目', 'fragrance-trade' ); ?></p>
<h2><?php esc_html_e( '按车型与需求选择贴膜方案', 'fragrance-trade' ); ?></h2>
</div>
<div class="capability-grid mt-5">
<?php
$count = 1;
while ( $service_query->have_posts() ) :
$service_query->the_post();
$image = get_post_meta( get_the_ID(), '_service_image', true );
$fallback = 'images/products/placeholder-0' . ( $count < 10 ? $count : 1 ) . '.svg';
?>
<article class="capability-card">
<div class="capability-image"><a href="<?php the_permalink(); ?>"><?php if ( has_post_thumbnail() ) : ?><?php the_post_thumbnail( 'fragrance-capability', array( 'class' => 'img-fluid', 'loading' => 'lazy', 'decoding' => 'async' ) ); ?><?php else : ?><img src="<?php echo esc_url( $image ? $image : fragrance_trade_asset_uri( $fallback ) ); ?>" alt="<?php the_title_attribute(); ?>" class="img-fluid" loading="lazy" decoding="async"><?php endif; ?></a></div>
<div class="capability-body">
<p class="capability-label"><?php esc_html_e( '贴膜服务', 'fragrance-trade' ); ?></p>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p><?php echo esc_html( get_the_excerpt() ); ?></p>
<a href="<?php echo esc_url( home_url( '/contact/' ) ); ?>" class="btn btn-b2b-outline"><?php esc_html_e( '联系门店', 'fragrance-trade' ); ?></a>
</div>
</article>
<?php
$count++;
endwhile;
wp_reset_postdata();
?>
<div
class="b2b-carousel services-carousel mt-5"
data-carousel
data-autoplay="9000"
data-page-label="<?php esc_attr_e( '转到第 %d 组', 'fragrance-trade' ); ?>"
role="region"
aria-roledescription="carousel"
aria-label="<?php esc_attr_e( '服务项目', 'fragrance-trade' ); ?>"
>
<div class="b2b-carousel-viewport">
<div class="capability-grid b2b-carousel-track">
<?php
$count = 1;
$total_items = $service_query->post_count;
while ( $service_query->have_posts() ) :
$service_query->the_post();
$fallback = 'products/placeholder-0' . ( $count < 10 ? $count : 1 ) . '.svg';
?>
<article
class="capability-card b2b-carousel-slide"
role="group"
aria-roledescription="slide"
aria-label="<?php echo esc_attr( sprintf( '%1$d / %2$d', $count, $total_items ) ); ?>"
>
<div class="capability-image"><a href="<?php the_permalink(); ?>"><?php echo fragrance_trade_service_card_image( get_the_ID(), $fallback ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped ?></a></div>
<div class="capability-body">
<p class="capability-label"><?php esc_html_e( '贴膜服务', 'fragrance-trade' ); ?></p>
<h3><a href="<?php the_permalink(); ?>"><?php the_title(); ?></a></h3>
<p><?php echo esc_html( get_the_excerpt() ); ?></p>
<a href="<?php echo esc_url( home_url( '/contact/' ) ); ?>" class="btn btn-b2b-outline"><?php esc_html_e( '联系门店', 'fragrance-trade' ); ?></a>
</div>
</article>
<?php
$count++;
endwhile;
wp_reset_postdata();
?>
</div>
</div>
<div class="b2b-carousel-controls" aria-label="<?php esc_attr_e( '服务项目轮播控制', 'fragrance-trade' ); ?>">
<button type="button" class="b2b-carousel-arrow b2b-carousel-prev" aria-label="<?php esc_attr_e( '上一组服务项目', 'fragrance-trade' ); ?>">
<span aria-hidden="true">←</span>
</button>
<div class="b2b-carousel-dots"></div>
<button type="button" class="b2b-carousel-arrow b2b-carousel-next" aria-label="<?php esc_attr_e( '下一组服务项目', 'fragrance-trade' ); ?>">
<span aria-hidden="true">→</span>
</button>
</div>
</div>
<div class="text-center mt-5">
<a href="<?php echo esc_url( home_url( '/services/' ) ); ?>" class="btn btn-b2b-primary"><?php esc_html_e( '查看全部服务项目', 'fragrance-trade' ); ?></a>