diff --git a/README.md b/README.md index 8e2b132..b6b928a 100644 --- a/README.md +++ b/README.md @@ -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 即使带有额外查询参数也能打开,但主题不再生成、读取、显示或传递服务名称。 ## 许可证 diff --git a/archive-case.php b/archive-case.php index b1dd267..dc6ddd2 100644 --- a/archive-case.php +++ b/archive-case.php @@ -48,7 +48,7 @@ get_header(); -
+
diff --git a/archive-service.php b/archive-service.php index 2fe6de6..680a2be 100644 --- a/archive-service.php +++ b/archive-service.php @@ -29,13 +29,10 @@ get_header();

-
+
-
- +

diff --git a/archive.php b/archive.php index a2ec4b2..716fb36 100644 --- a/archive.php +++ b/archive.php @@ -5,18 +5,64 @@ if ( ! defined( 'ABSPATH' ) ) { } get_header(); + +$is_news_archive = is_category() || is_tag() || is_date() || is_author(); ?> -
-
' ); ?> - -
- -
- + +
+
+ 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 ), + ), + ) + ); + ?> +
+

+

+ ', '
' ); ?> + + +
+ +
+
+ +
+ +
+

+

+ +
+
- - - - - + + +
+
' ); ?> + +
+ +
+ +
+ + + + + + diff --git a/assets/css/theme.css b/assets/css/theme.css index b0b58ef..274695a 100644 --- a/assets/css/theme.css +++ b/assets/css/theme.css @@ -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%; } diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/01.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/01.jpg new file mode 100644 index 0000000..37b57d8 Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/01.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/02.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/02.jpg new file mode 100644 index 0000000..133033e Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/02.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/03.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/03.jpg new file mode 100644 index 0000000..7092aa4 Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/03.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/04.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/04.jpg new file mode 100644 index 0000000..8298fed Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/04.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/05.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/05.jpg new file mode 100644 index 0000000..81ad9ca Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/05.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/06.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/06.jpg new file mode 100644 index 0000000..9f2b1a5 Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/06.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/07.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/07.jpg new file mode 100644 index 0000000..0724c10 Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/07.jpg differ diff --git a/assets/images/cases/byd-han-matte-blue-gold-floating-roof/08.jpg b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/08.jpg new file mode 100644 index 0000000..68208f6 Binary files /dev/null and b/assets/images/cases/byd-han-matte-blue-gold-floating-roof/08.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/01.jpg b/assets/images/cases/changan-uni-v-gt-silver/01.jpg new file mode 100644 index 0000000..a2c5d43 Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/01.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/02.jpg b/assets/images/cases/changan-uni-v-gt-silver/02.jpg new file mode 100644 index 0000000..7ae9409 Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/02.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/03.jpg b/assets/images/cases/changan-uni-v-gt-silver/03.jpg new file mode 100644 index 0000000..77959c5 Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/03.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/04.jpg b/assets/images/cases/changan-uni-v-gt-silver/04.jpg new file mode 100644 index 0000000..3ce5022 Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/04.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/05.jpg b/assets/images/cases/changan-uni-v-gt-silver/05.jpg new file mode 100644 index 0000000..205bc4d Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/05.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/06.jpg b/assets/images/cases/changan-uni-v-gt-silver/06.jpg new file mode 100644 index 0000000..399455d Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/06.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/07.jpg b/assets/images/cases/changan-uni-v-gt-silver/07.jpg new file mode 100644 index 0000000..1153d5b Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/07.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/08.jpg b/assets/images/cases/changan-uni-v-gt-silver/08.jpg new file mode 100644 index 0000000..192b317 Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/08.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/09.jpg b/assets/images/cases/changan-uni-v-gt-silver/09.jpg new file mode 100644 index 0000000..dab4ffb Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/09.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/10.jpg b/assets/images/cases/changan-uni-v-gt-silver/10.jpg new file mode 100644 index 0000000..0b067fa Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/10.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/11.jpg b/assets/images/cases/changan-uni-v-gt-silver/11.jpg new file mode 100644 index 0000000..0251c3a Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/11.jpg differ diff --git a/assets/images/cases/changan-uni-v-gt-silver/12.jpg b/assets/images/cases/changan-uni-v-gt-silver/12.jpg new file mode 100644 index 0000000..4aff59e Binary files /dev/null and b/assets/images/cases/changan-uni-v-gt-silver/12.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/01.jpg b/assets/images/cases/chery-arrizo-alexander-silver/01.jpg new file mode 100644 index 0000000..989592b Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/01.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/02.jpg b/assets/images/cases/chery-arrizo-alexander-silver/02.jpg new file mode 100644 index 0000000..2046312 Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/02.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/03.jpg b/assets/images/cases/chery-arrizo-alexander-silver/03.jpg new file mode 100644 index 0000000..5a32942 Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/03.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/04.jpg b/assets/images/cases/chery-arrizo-alexander-silver/04.jpg new file mode 100644 index 0000000..eddc3eb Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/04.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/05.jpg b/assets/images/cases/chery-arrizo-alexander-silver/05.jpg new file mode 100644 index 0000000..687ad45 Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/05.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/06.jpg b/assets/images/cases/chery-arrizo-alexander-silver/06.jpg new file mode 100644 index 0000000..1ea69ec Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/06.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/07.jpg b/assets/images/cases/chery-arrizo-alexander-silver/07.jpg new file mode 100644 index 0000000..0c8423b Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/07.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/08.jpg b/assets/images/cases/chery-arrizo-alexander-silver/08.jpg new file mode 100644 index 0000000..e02e93c Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/08.jpg differ diff --git a/assets/images/cases/chery-arrizo-alexander-silver/09.jpg b/assets/images/cases/chery-arrizo-alexander-silver/09.jpg new file mode 100644 index 0000000..1bb2157 Binary files /dev/null and b/assets/images/cases/chery-arrizo-alexander-silver/09.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/01.jpg b/assets/images/cases/ford-mondeo-alexander-silver/01.jpg new file mode 100644 index 0000000..28e725d Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/01.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/02.jpg b/assets/images/cases/ford-mondeo-alexander-silver/02.jpg new file mode 100644 index 0000000..a774522 Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/02.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/03.jpg b/assets/images/cases/ford-mondeo-alexander-silver/03.jpg new file mode 100644 index 0000000..bd3b20a Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/03.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/04.jpg b/assets/images/cases/ford-mondeo-alexander-silver/04.jpg new file mode 100644 index 0000000..e599c77 Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/04.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/05.jpg b/assets/images/cases/ford-mondeo-alexander-silver/05.jpg new file mode 100644 index 0000000..3af15ad Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/05.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/06.jpg b/assets/images/cases/ford-mondeo-alexander-silver/06.jpg new file mode 100644 index 0000000..8e490dd Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/06.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/07.jpg b/assets/images/cases/ford-mondeo-alexander-silver/07.jpg new file mode 100644 index 0000000..b36c491 Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/07.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/08.jpg b/assets/images/cases/ford-mondeo-alexander-silver/08.jpg new file mode 100644 index 0000000..c9b123e Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/08.jpg differ diff --git a/assets/images/cases/ford-mondeo-alexander-silver/09.jpg b/assets/images/cases/ford-mondeo-alexander-silver/09.jpg new file mode 100644 index 0000000..20b799b Binary files /dev/null and b/assets/images/cases/ford-mondeo-alexander-silver/09.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/01.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/01.jpg new file mode 100644 index 0000000..2dbd591 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/01.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/02.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/02.jpg new file mode 100644 index 0000000..1391246 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/02.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/03.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/03.jpg new file mode 100644 index 0000000..f7a5e95 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/03.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/04.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/04.jpg new file mode 100644 index 0000000..9bb7a99 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/04.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/05.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/05.jpg new file mode 100644 index 0000000..3f3c461 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/05.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/06.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/06.jpg new file mode 100644 index 0000000..0282148 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/06.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/07.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/07.jpg new file mode 100644 index 0000000..6831c1e Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/07.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/08.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/08.jpg new file mode 100644 index 0000000..a1efeb6 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/08.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/09.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/09.jpg new file mode 100644 index 0000000..c1a0caa Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/09.jpg differ diff --git a/assets/images/cases/porsche-718-liquid-metal-silver/10.jpg b/assets/images/cases/porsche-718-liquid-metal-silver/10.jpg new file mode 100644 index 0000000..78f8395 Binary files /dev/null and b/assets/images/cases/porsche-718-liquid-metal-silver/10.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/01.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/01.jpg new file mode 100644 index 0000000..d21f39b Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/01.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/02.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/02.jpg new file mode 100644 index 0000000..5dbf617 Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/02.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/03.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/03.jpg new file mode 100644 index 0000000..c487b84 Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/03.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/04.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/04.jpg new file mode 100644 index 0000000..e4b514f Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/04.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/05.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/05.jpg new file mode 100644 index 0000000..0b6d4e5 Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/05.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/06.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/06.jpg new file mode 100644 index 0000000..9336f69 Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/06.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/07.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/07.jpg new file mode 100644 index 0000000..5c79a8a Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/07.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/08.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/08.jpg new file mode 100644 index 0000000..98b8c00 Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/08.jpg differ diff --git a/assets/images/cases/tesla-model-3-highland-alexander-silver/09.jpg b/assets/images/cases/tesla-model-3-highland-alexander-silver/09.jpg new file mode 100644 index 0000000..63d00de Binary files /dev/null and b/assets/images/cases/tesla-model-3-highland-alexander-silver/09.jpg differ diff --git a/assets/images/consultation-studio-bg.jpg b/assets/images/consultation-studio-bg.jpg new file mode 100644 index 0000000..685bb19 Binary files /dev/null and b/assets/images/consultation-studio-bg.jpg differ diff --git a/assets/images/placeholder-news.svg b/assets/images/placeholder-news.svg new file mode 100644 index 0000000..7787f48 --- /dev/null +++ b/assets/images/placeholder-news.svg @@ -0,0 +1,9 @@ + + 新闻资讯图片占位 + 用于没有特色图片的新闻文章 + + + + + + diff --git a/assets/images/services/covers/kdx-dunjia-cover.jpg b/assets/images/services/covers/kdx-dunjia-cover.jpg new file mode 100644 index 0000000..3ada62d Binary files /dev/null and b/assets/images/services/covers/kdx-dunjia-cover.jpg differ diff --git a/assets/images/services/covers/kdx-dunjia-plus-cover.jpg b/assets/images/services/covers/kdx-dunjia-plus-cover.jpg new file mode 100644 index 0000000..e79c7e9 Binary files /dev/null and b/assets/images/services/covers/kdx-dunjia-plus-cover.jpg differ diff --git a/assets/images/services/covers/kdx-jinjia-pro-cover.jpg b/assets/images/services/covers/kdx-jinjia-pro-cover.jpg new file mode 100644 index 0000000..57441e8 Binary files /dev/null and b/assets/images/services/covers/kdx-jinjia-pro-cover.jpg differ diff --git a/assets/images/services/covers/kdx-kaijia-cover.jpg b/assets/images/services/covers/kdx-kaijia-cover.jpg new file mode 100644 index 0000000..5332875 Binary files /dev/null and b/assets/images/services/covers/kdx-kaijia-cover.jpg differ diff --git a/assets/images/services/covers/kdx-kaijia-plus-cover.jpg b/assets/images/services/covers/kdx-kaijia-plus-cover.jpg new file mode 100644 index 0000000..c892c12 Binary files /dev/null and b/assets/images/services/covers/kdx-kaijia-plus-cover.jpg differ diff --git a/assets/images/services/kdx-dunjia-plus.jpg b/assets/images/services/kdx-dunjia-plus.jpg new file mode 100644 index 0000000..133809f Binary files /dev/null and b/assets/images/services/kdx-dunjia-plus.jpg differ diff --git a/assets/images/services/kdx-dunjia.jpg b/assets/images/services/kdx-dunjia.jpg new file mode 100644 index 0000000..b5d5fdf Binary files /dev/null and b/assets/images/services/kdx-dunjia.jpg differ diff --git a/assets/images/services/kdx-jinjia-pro.jpg b/assets/images/services/kdx-jinjia-pro.jpg new file mode 100644 index 0000000..4b92fb1 Binary files /dev/null and b/assets/images/services/kdx-jinjia-pro.jpg differ diff --git a/assets/images/services/kdx-kaijia-plus.jpg b/assets/images/services/kdx-kaijia-plus.jpg new file mode 100644 index 0000000..cd56530 Binary files /dev/null and b/assets/images/services/kdx-kaijia-plus.jpg differ diff --git a/assets/images/services/kdx-kaijia.jpg b/assets/images/services/kdx-kaijia.jpg new file mode 100644 index 0000000..0a152e4 Binary files /dev/null and b/assets/images/services/kdx-kaijia.jpg differ diff --git a/assets/images/store/authorization.jpg b/assets/images/store/authorization.jpg index cfa3e55..d7b4f05 100644 Binary files a/assets/images/store/authorization.jpg and b/assets/images/store/authorization.jpg differ diff --git a/assets/images/store/award.jpg b/assets/images/store/award.jpg index 71c8fb8..e9dd622 100644 Binary files a/assets/images/store/award.jpg and b/assets/images/store/award.jpg differ diff --git a/assets/images/store/brand-event.jpg b/assets/images/store/brand-event.jpg index 9771638..49db5c8 100644 Binary files a/assets/images/store/brand-event.jpg and b/assets/images/store/brand-event.jpg differ diff --git a/assets/images/store/kdx-logo.jpg b/assets/images/store/kdx-logo.jpg index 8d850ab..ba320a1 100644 Binary files a/assets/images/store/kdx-logo.jpg and b/assets/images/store/kdx-logo.jpg differ diff --git a/assets/images/store/showroom-consultation.jpg b/assets/images/store/showroom-consultation.jpg index 7c2c4af..bba999c 100644 Binary files a/assets/images/store/showroom-consultation.jpg and b/assets/images/store/showroom-consultation.jpg differ diff --git a/assets/images/store/showroom-main.jpg b/assets/images/store/showroom-main.jpg index 3b7b21e..1834d9d 100644 Binary files a/assets/images/store/showroom-main.jpg and b/assets/images/store/showroom-main.jpg differ diff --git a/assets/images/store/storefront.jpg b/assets/images/store/storefront.jpg index bc8b725..e3331cc 100644 Binary files a/assets/images/store/storefront.jpg and b/assets/images/store/storefront.jpg differ diff --git a/assets/images/trust-workshop-bg.jpg b/assets/images/trust-workshop-bg.jpg new file mode 100644 index 0000000..f099579 Binary files /dev/null and b/assets/images/trust-workshop-bg.jpg differ diff --git a/assets/js/theme.js b/assets/js/theme.js index c44949a..d85424d 100644 --- a/assets/js/theme.js +++ b/assets/js/theme.js @@ -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(); } diff --git a/footer.php b/footer.php index 0d02c86..cbc534a 100644 --- a/footer.php +++ b/footer.php @@ -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', '' ); ?>
-

+

@@ -25,13 +32,17 @@ $fragrance_whatsapp = fragrance_trade_whatsapp_number();

-

+

+

+

+

diff --git a/functions.php b/functions.php index 30ff5f2..70f550c 100644 --- a/functions.php +++ b/functions.php @@ -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; } - diff --git a/home.php b/home.php new file mode 100644 index 0000000..46a6357 --- /dev/null +++ b/home.php @@ -0,0 +1,61 @@ + +
+
+ array( + array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ), + array( 'label' => $page_title, 'url' => null ), + ), + ) + ); + ?> +
+

+

+

+
+ + +
+ +
+
+ +
+ +
+

+

+ +
+ +
+
+ diff --git a/inc/case-seeds.php b/inc/case-seeds.php new file mode 100644 index 0000000..021893d --- /dev/null +++ b/inc/case-seeds.php @@ -0,0 +1,520 @@ + 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-V|GT 银改色膜', '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( + '
  • %1$s%2$s
  • %3$s%4$s
  • %5$s%6$s
  • %7$s%8$s
', + 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( + '
%3$s
', + $attachment_id, + esc_url( $full_url ), + $image + ); + } + + return sprintf( + '

%1$s

' . + '

%2$s

' . + '%3$s' . + '

%4$s

' . + '

%5$s

' . + '' . + '

%7$s

' . + '

%8$s

' . + '

%9$s

', + 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 ); + } + ?> +
+

+

+ + + +
+

+ +

+ +
    + +
  • + +
+ +
+ + +
+ + + +
+
+ $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' ); diff --git a/inc/cpt.php b/inc/cpt.php index 754cae7..62120ea 100644 --- a/inc/cpt.php +++ b/inc/cpt.php @@ -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; } diff --git a/inc/customizer.php b/inc/customizer.php index b0aa38e..7ef40ae 100644 --- a/inc/customizer.php +++ b/inc/customizer.php @@ -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' ), ); diff --git a/inc/defaults.php b/inc/defaults.php index ff572a5..8ec5132 100644 --- a/inc/defaults.php +++ b/inc/defaults.php @@ -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:00–22: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; diff --git a/inc/helpers.php b/inc/helpers.php index 2ceb528..2d3c8e6 100644 --- a/inc/helpers.php +++ b/inc/helpers.php @@ -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( + '%2$s', + 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( + '%2$s', + 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( '

%s %s %s

', 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( + '

%s %s %s

', + esc_html__( '主导航尚未包含新闻资讯', 'fragrance-trade' ), + esc_html__( '主题不会自动修改已分配的菜单,请将 WordPress 文章页添加到“主导航”。', 'fragrance-trade' ), esc_url( admin_url( 'nav-menus.php' ) ), esc_html__( '编辑菜单', 'fragrance-trade' ) ); diff --git a/inc/service-seeds.php b/inc/service-seeds.php new file mode 100644 index 0000000..b84f2f2 --- /dev/null +++ b/inc/service-seeds.php @@ -0,0 +1,385 @@ + 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( + '
  • %1$s:%2$s
  • ', + esc_html( $label ), + esc_html( $value ) + ); + } + + return sprintf( + '

    %1$s

    ' . + '

    %2$s

    ' . + '
      %3$s
    ' . + '

    %4$s

    ', + 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; +} diff --git a/languages/fragrance-trade.pot b/languages/fragrance-trade.pot index fb16635..c73f769 100644 --- a/languages/fragrance-trade.pot +++ b/languages/fragrance-trade.pot @@ -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 "" diff --git a/page-contact.php b/page-contact.php index 5b101b0..5a55309 100644 --- a/page-contact.php +++ b/page-contact.php @@ -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 ) + . '®ion=' . 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 );

    + +
    +

    +

    +
    + + +
    +

    +

    +
    + + +
    +

    +

    +
    +

    @@ -111,6 +156,12 @@ $map_title = sprintf( __( '%s门店地图', 'fragrance-trade' ), $store_name );

    + +
    +

    +

    +
    +

    @@ -135,8 +186,8 @@ $map_title = sprintf( __( '%s门店地图', 'fragrance-trade' ), $store_name );

    - -

    + +

    diff --git a/single-post.php b/single-post.php new file mode 100644 index 0000000..be4d340 --- /dev/null +++ b/single-post.php @@ -0,0 +1,87 @@ + +
    + +
    > + array( + array( 'label' => __( '首页', 'fragrance-trade' ), 'url' => home_url( '/' ) ), + array( 'label' => __( '新闻资讯', 'fragrance-trade' ), 'url' => fragrance_trade_news_url() ), + array( 'label' => get_the_title(), 'url' => null ), + ), + ) + ); + ?> +
    +
    + + + + + +
    +

    +
    + + +
    + 'img-fluid', 'decoding' => 'async' ) ); ?> +
    + + +
    + + '', + ) + ); + ?> +
    + + +
    + '' . esc_html__( '上一篇', 'fragrance-trade' ) . '%title', + 'next_text' => '' . esc_html__( '下一篇', 'fragrance-trade' ) . '%title', + 'in_same_term' => false, + 'taxonomy' => 'category', + 'screen_reader_text' => __( '新闻文章导航', 'fragrance-trade' ), + ) + ); + ?> +
    + + +
    +

    +

    + +
    +
    + +
    + diff --git a/style.css b/style.css index 17da95b..06adc4a 100644 --- a/style.css +++ b/style.css @@ -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 diff --git a/template-parts/content-news-card.php b/template-parts/content-news-card.php new file mode 100644 index 0000000..c404b30 --- /dev/null +++ b/template-parts/content-news-card.php @@ -0,0 +1,38 @@ + + diff --git a/template-parts/home/case-teaser.php b/template-parts/home/case-teaser.php index baf42f6..7f76c43 100644 --- a/template-parts/home/case-teaser.php +++ b/template-parts/home/case-teaser.php @@ -20,17 +20,53 @@ $case_query = new WP_Query(

    have_posts() ) : ?> -
    - have_posts() ) : $case_query->the_post(); ?> - - - 'img-fluid' ) ); ?> - - <?php the_title_attribute(); ?> - - - - +
    diff --git a/template-parts/home/credentials.php b/template-parts/home/credentials.php index 2f63fec..5ba79d1 100644 --- a/template-parts/home/credentials.php +++ b/template-parts/home/credentials.php @@ -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, diff --git a/template-parts/home/service-teaser.php b/template-parts/home/service-teaser.php index 1bf3a61..73992d6 100644 --- a/template-parts/home/service-teaser.php +++ b/template-parts/home/service-teaser.php @@ -22,28 +22,54 @@ if ( ! $service_query->have_posts() ) {

    -
    - 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'; - ?> - - +