主题设置配置
主题设置允许商家通过主题编辑器自定义主题外观和功能,无需编写代码。本指南将详细介绍如何创建完善的主题设置系统。
设置文件结构
1. settings_schema.json 基础结构
[
{
"name": "theme_info",
"theme_name": "我的主题",
"theme_version": "1.0.0",
"theme_author": "开发者名称",
"theme_documentation_url": "https://docs.example.com",
"theme_support_url": "https://support.example.com"
},
{
"name": "全局颜色",
"settings": [
{
"type": "header",
"content": "主要颜色"
},
{
"type": "color",
"id": "color_primary",
"label": "主色调",
"default": "#1a1a1a",
"info": "用于按钮、链接等主要元素"
},
{
"type": "color",
"id": "color_secondary",
"label": "辅助色",
"default": "#666666",
"info": "用于辅助信息和装饰元素"
},
{
"type": "color",
"id": "color_accent",
"label": "强调色",
"default": "#ff6b6b",
"info": "用于促销、警告等需要突出的元素"
}
]
},
{
"name": "字体设置",
"settings": [
{
"type": "header",
"content": "标题字体"
},
{
"type": "font_picker",
"id": "font_heading",
"label": "标题字体",
"default": "assistant_n4"
},
{
"type": "range",
"id": "font_heading_scale",
"label": "标题字体缩放",
"min": 100,
"max": 150,
"step": 5,
"unit": "%",
"default": 120
},
{
"type": "header",
"content": "正文字体"
},
{
"type": "font_picker",
"id": "font_body",
"label": "正文字体",
"default": "assistant_n4"
},
{
"type": "range",
"id": "font_body_scale",
"label": "正文字体缩放",
"min": 80,
"max": 120,
"step": 5,
"unit": "%",
"default": 100
}
]
},
{
"name": "布局设置",
"settings": [
{
"type": "header",
"content": "页面宽度"
},
{
"type": "range",
"id": "page_width",
"label": "最大页面宽度",
"min": 1000,
"max": 1600,
"step": 50,
"unit": "px",
"default": 1200
},
{
"type": "checkbox",
"id": "enable_sticky_header",
"label": "启用粘性头部",
"default": true
},
{
"type": "select",
"id": "grid_gutter",
"label": "网格间距",
"options": [
{ "value": "small", "label": "小" },
{ "value": "medium", "label": "中" },
{ "value": "large", "label": "大" }
],
"default": "medium"
}
]
},
{
"name": "产品设置",
"settings": [
{
"type": "header",
"content": "产品卡片"
},
{
"type": "checkbox",
"id": "show_vendor",
"label": "显示品牌",
"default": false
},
{
"type": "checkbox",
"id": "show_secondary_image",
"label": "悬停显示第二张图片",
"default": true
},
{
"type": "select",
"id": "product_image_ratio",
"label": "产品图片比例",
"options": [
{ "value": "natural", "label": "自然" },
{ "value": "square", "label": "正方形" },
{ "value": "portrait", "label": "竖向" },
{ "value": "landscape", "label": "横向" }
],
"default": "natural"
},
{
"type": "header",
"content": "产品页面"
},
{
"type": "select",
"id": "product_gallery_layout",
"label": "图片画廊布局",
"options": [
{ "value": "stacked", "label": "堆叠" },
{ "value": "thumbnails_left", "label": "缩略图在左" },
{ "value": "thumbnails_bottom", "label": "缩略图在下" }
],
"default": "thumbnails_bottom"
},
{
"type": "checkbox",
"id": "enable_image_zoom",
"label": "启用图片放大",
"default": true
}
]
},
{
"name": "购物车设置",
"settings": [
{
"type": "header",
"content": "购物车行为"
},
{
"type": "select",
"id": "cart_type",
"label": "购物车类型",
"options": [
{ "value": "drawer", "label": "侧边抽屉" },
{ "value": "page", "label": "独立页面" },
{ "value": "popup", "label": "弹窗" }
],
"default": "drawer"
},
{
"type": "checkbox",
"id": "cart_notes_enable",
"label": "启用订单备注",
"default": true
},
{
"type": "range",
"id": "free_shipping_threshold",
"label": "免费配送门槛",
"min": 0,
"max": 1000,
"step": 50,
"unit": "¥",
"default": 200
}
]
},
{
"name": "社交媒体",
"settings": [
{
"type": "header",
"content": "社交媒体链接"
},
{
"type": "url",
"id": "social_facebook_link",
"label": "Facebook",
"info": "https://facebook.com/yourstore"
},
{
"type": "url",
"id": "social_twitter_link",
"label": "Twitter",
"info": "https://twitter.com/yourstore"
},
{
"type": "url",
"id": "social_instagram_link",
"label": "Instagram",
"info": "https://instagram.com/yourstore"
},
{
"type": "url",
"id": "social_youtube_link",
"label": "YouTube",
"info": "https://youtube.com/yourstore"
},
{
"type": "url",
"id": "social_weibo_link",
"label": "微博",
"info": "https://weibo.com/yourstore"
},
{
"type": "url",
"id": "social_wechat_qr",
"label": "微信二维码图片链接"
}
]
},
{
"name": "SEO 设置",
"settings": [
{
"type": "header",
"content": "搜索引擎优化"
},
{
"type": "image_picker",
"id": "favicon",
"label": "网站图标",
"info": "推荐 32x32px PNG 格式"
},
{
"type": "image_picker",
"id": "social_sharing_image",
"label": "社交分享图片",
"info": "推荐 1200x630px,用于 Facebook、Twitter 等社交媒体分享"
},
{
"type": "textarea",
"id": "social_sharing_description",
"label": "默认分享描述",
"info": "当页面没有特定描述时使用"
}
]
},
{
"name": "高级设置",
"settings": [
{
"type": "header",
"content": "分析和跟踪"
},
{
"type": "text",
"id": "google_analytics_id",
"label": "Google Analytics ID",
"info": "例如: G-XXXXXXXXXX"
},
{
"type": "text",
"id": "facebook_pixel_id",
"label": "Facebook Pixel ID"
},
{
"type": "header",
"content": "性能优化"
},
{
"type": "checkbox",
"id": "enable_lazyload",
"label": "启用图片懒加载",
"default": true
},
{
"type": "checkbox",
"id": "minify_css",
"label": "压缩 CSS",
"default": false,
"info": "可能影响主题编辑器预览"
},
{
"type": "header",
"content": "自定义代码"
},
{
"type": "textarea",
"id": "custom_css",
"label": "自定义 CSS",
"info": "在此添加自定义样式代码"
},
{
"type": "textarea",
"id": "custom_js",
"label": "自定义 JavaScript",
"info": "在此添加自定义脚本代码"
}
]
}
]
2. 设置在模板中的使用
<!-- layout/theme.liquid -->
<!DOCTYPE html>
<html lang="{{ shop.locale }}">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<!-- SEO 设置 -->
{% if settings.favicon %}
<link rel="icon" type="image/png" href="{{ settings.favicon | img_url: '32x32' }}">
{% endif %}
<!-- 社交分享 -->
<meta property="og:image" content="{{ settings.social_sharing_image | default: shop.brand.logo | img_url: '1200x630' }}">
<meta property="og:description" content="{{ page_description | default: settings.social_sharing_description | default: shop.description }}">
<!-- 字体设置 -->
<style>
{{ settings.font_heading | font_face: font_display: 'swap' }}
{{ settings.font_body | font_face: font_display: 'swap' }}
:root {
/* 颜色变量 */
--color-primary: {{ settings.color_primary }};
--color-secondary: {{ settings.color_secondary }};
--color-accent: {{ settings.color_accent }};
/* 字体变量 */
--font-heading-family: {{ settings.font_heading.family }}, {{ settings.font_heading.fallback_families }};
--font-body-family: {{ settings.font_body.family }}, {{ settings.font_body.fallback_families }};
--font-heading-scale: {{ settings.font_heading_scale }}%;
--font-body-scale: {{ settings.font_body_scale }}%;
/* 布局变量 */
--page-width: {{ settings.page_width }}px;
--grid-gutter: {% case settings.grid_gutter %}
{% when 'small' %}1rem
{% when 'large' %}3rem
{% else %}2rem
{% endcase %};
}
body {
font-family: var(--font-body-family);
font-size: calc(1rem * var(--font-body-scale) / 100);
}
h1, h2, h3, h4, h5, h6 {
font-family: var(--font-heading-family);
font-size: calc(1em * var(--font-heading-scale) / 100);
}
.container {
max-width: var(--page-width);
margin: 0 auto;
padding: 0 var(--grid-gutter);
}
</style>
<!-- 自定义 CSS -->
{% if settings.custom_css != blank %}
<style>{{ settings.custom_css }}</style>
{% endif %}
</head>
<body class="template-{{ template.name }}">
<!-- 粘性头部 -->
<header class="site-header {% if settings.enable_sticky_header %}site-header--sticky{% endif %}">
<!-- 头部内容 -->
</header>
<main class="main-content" role="main">
{{ content_for_layout }}
</main>
<footer class="site-footer">
<!-- 社交媒体链接 -->
{% if settings.social_facebook_link != blank or settings.social_twitter_link != blank or settings.social_instagram_link != blank %}
<div class="social-links">
{% if settings.social_facebook_link != blank %}
<a href="{{ settings.social_facebook_link }}" target="_blank" rel="noopener" aria-label="Facebook">
{% render 'icon-facebook' %}
</a>
{% endif %}
{% if settings.social_twitter_link != blank %}
<a href="{{ settings.social_twitter_link }}" target="_blank" rel="noopener" aria-label="Twitter">
{% render 'icon-twitter' %}
</a>
{% endif %}
{% if settings.social_instagram_link != blank %}
<a href="{{ settings.social_instagram_link }}" target="_blank" rel="noopener" aria-label="Instagram">
{% render 'icon-instagram' %}
</a>
{% endif %}
</div>
{% endif %}
</footer>
<!-- 分析代码 -->
{% if settings.google_analytics_id != blank %}
<!-- Google Analytics -->
<script async src="https://www.googletagmanager.com/gtag/js?id={{ settings.google_analytics_id }}"></script>
<script>
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', '{{ settings.google_analytics_id }}');
</script>
{% endif %}
{% if settings.facebook_pixel_id != blank %}
<!-- Facebook Pixel -->
<script>
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', '{{ settings.facebook_pixel_id }}');
fbq('track', 'PageView');
</script>
{% endif %}
<!-- 自定义 JavaScript -->
{% if settings.custom_js != blank %}
<script>{{ settings.custom_js }}</script>
{% endif %}
</body>
</html>
条件设置和依赖关系
1. 动态设置显示
{
"name": "头部设置",
"settings": [
{
"type": "select",
"id": "header_style",
"label": "头部样式",
"options": [
{ "value": "simple", "label": "简洁" },
{ "value": "centered", "label": "居中" },
{ "value": "drawer", "label": "抽屉式" }
],
"default": "simple"
},
{
"type": "checkbox",
"id": "show_search",
"label": "显示搜索框",
"default": true
},
{
"type": "select",
"id": "search_style",
"label": "搜索框样式",
"options": [
{ "value": "icon", "label": "图标" },
{ "value": "input", "label": "输入框" },
{ "value": "modal", "label": "模态框" }
],
"default": "icon",
"info": "需要启用搜索功能"
}
]
}
2. 在模板中处理条件逻辑
<!-- snippets/header-search.liquid -->
{% if settings.show_search %}
<div class="header-search header-search--{{ settings.search_style }}">
{% case settings.search_style %}
{% when 'icon' %}
<button type="button" class="search-toggle" data-search-open>
{% render 'icon-search' %}
</button>
{% when 'input' %}
<form action="{{ routes.search_url }}" method="get" class="search-form">
<input type="search"
name="q"
placeholder="搜索..."
class="search-input"
value="{{ search.terms | escape }}">
<button type="submit" class="search-submit">
{% render 'icon-search' %}
</button>
</form>
{% when 'modal' %}
<button type="button" class="search-modal-toggle" data-search-modal>
{% render 'icon-search' %}
<span>搜索</span>
</button>
{% endcase %}
</div>
{% endif %}
高级设置组合
1. 复杂产品设置
{
"name": "产品集合设置",
"settings": [
{
"type": "header",
"content": "集合页面"
},
{
"type": "range",
"id": "products_per_page",
"label": "每页产品数量",
"min": 12,
"max": 48,
"step": 12,
"default": 24
},
{
"type": "select",
"id": "collection_layout",
"label": "集合布局",
"options": [
{ "value": "grid", "label": "网格" },
{ "value": "list", "label": "列表" },
{ "value": "masonry", "label": "瀑布流" }
],
"default": "grid"
},
{
"type": "range",
"id": "grid_columns_desktop",
"label": "桌面端列数",
"min": 2,
"max": 6,
"step": 1,
"default": 4
},
{
"type": "range",
"id": "grid_columns_tablet",
"label": "平板端列数",
"min": 2,
"max": 4,
"step": 1,
"default": 3
},
{
"type": "range",
"id": "grid_columns_mobile",
"label": "移动端列数",
"min": 1,
"max": 2,
"step": 1,
"default": 2
},
{
"type": "header",
"content": "过滤器和排序"
},
{
"type": "checkbox",
"id": "enable_filtering",
"label": "启用过滤器",
"default": true
},
{
"type": "checkbox",
"id": "enable_sorting",
"label": "启用排序",
"default": true
},
{
"type": "checkbox",
"id": "enable_search_within_collection",
"label": "启用集合内搜索",
"default": false
}
]
}
2. 多语言设置支持
{
"name": "多语言内容",
"settings": [
{
"type": "header",
"content": "欢迎消息"
},
{
"type": "text",
"id": "welcome_message_zh",
"label": "欢迎消息 (中文)",
"default": "欢迎来到我们的商店!"
},
{
"type": "text",
"id": "welcome_message_en",
"label": "欢迎消息 (English)",
"default": "Welcome to our store!"
},
{
"type": "header",
"content": "按钮文字"
},
{
"type": "text",
"id": "button_add_to_cart_zh",
"label": "添加到购物车按钮 (中文)",
"default": "加入购物车"
},
{
"type": "text",
"id": "button_add_to_cart_en",
"label": "添加到购物车按钮 (English)",
"default": "Add to Cart"
}
]
}
3. 使用多语言设置
<!-- snippets/localized-text.liquid -->
{% comment %}
多语言文本组件
参数:
- key: 设置键名前缀 (必需)
- fallback: 备用文本 (可选)
{% endcomment %}
{% assign current_locale = request.locale.iso_code %}
{% assign setting_key = key | append: '_' | append: current_locale %}
{% assign localized_text = settings[setting_key] %}
{% if localized_text != blank %}
{{ localized_text }}
{% elsif fallback %}
{{ fallback }}
{% else %}
{{ settings[key | append: '_zh'] | default: settings[key | append: '_en'] }}
{% endif %}
<!-- 使用示例 -->
<h1 class="welcome-message">
{% render 'localized-text', key: 'welcome_message', fallback: '欢迎访问!' %}
</h1>
<button type="submit" class="btn btn--primary">
{% render 'localized-text', key: 'button_add_to_cart' %}
</button>
设置验证和错误处理
1. 前端验证
<!-- assets/theme-settings.js -->
<script>
class ThemeSettings {
constructor() {
this.init()
}
init() {
this.validateSettings()
this.setupDependencies()
}
validateSettings() {
// 验证必需的设置
const requiredSettings = [
'color_primary',
'font_heading',
'font_body'
]
requiredSettings.forEach(setting => {
if (!this.getSetting(setting)) {
console.warn(`主题设置缺失: ${setting}`)
}
})
// 验证颜色格式
const colorSettings = [
'color_primary',
'color_secondary',
'color_accent'
]
colorSettings.forEach(setting => {
const color = this.getSetting(setting)
if (color && !this.isValidColor(color)) {
console.warn(`无效的颜色值: ${setting} = ${color}`)
}
})
}
setupDependencies() {
// 根据设置调整其他元素
const headerStyle = this.getSetting('header_style')
if (headerStyle === 'drawer') {
document.body.classList.add('header-drawer-enabled')
}
// 动态加载功能
const enableLazyload = this.getSetting('enable_lazyload')
if (enableLazyload) {
this.loadLazyloadScript()
}
}
getSetting(key) {
return window.themeSettings?.[key]
}
isValidColor(color) {
const s = new Option().style
s.color = color
return s.color !== ''
}
loadLazyloadScript() {
if (!document.querySelector('[data-lazysizes]')) {
const script = document.createElement('script')
script.src = 'https://cdn.jsdelivr.net/npm/lazysizes@5/lazysizes.min.js'
script.dataset.lazysizes = 'true'
document.head.appendChild(script)
}
}
}
// 暴露设置到全局
window.themeSettings = {
color_primary: '{{ settings.color_primary }}',
color_secondary: '{{ settings.color_secondary }}',
color_accent: '{{ settings.color_accent }}',
font_heading: '{{ settings.font_heading.family }}',
font_body: '{{ settings.font_body.family }}',
header_style: '{{ settings.header_style }}',
enable_lazyload: {{ settings.enable_lazyload | json }},
// 添加其他需要在 JavaScript 中使用的设置
}
// 初始化主题设置
document.addEventListener('DOMContentLoaded', () => {
new ThemeSettings()
})
</script>
2. 设置备用值
<!-- snippets/safe-settings.liquid -->
{% comment %}
安全设置获取器,提供备用值和验证
{% endcomment %}
{% assign safe_color_primary = settings.color_primary | default: '#1a1a1a' %}
{% assign safe_color_secondary = settings.color_secondary | default: '#666666' %}
{% assign safe_color_accent = settings.color_accent | default: '#ff6b6b' %}
{% assign safe_page_width = settings.page_width | default: 1200 %}
{% if safe_page_width < 1000 %}
{% assign safe_page_width = 1000 %}
{% elsif safe_page_width > 1600 %}
{% assign safe_page_width = 1600 %}
{% endif %}
{% assign safe_grid_gutter = settings.grid_gutter | default: 'medium' %}
{% unless safe_grid_gutter == 'small' or safe_grid_gutter == 'medium' or safe_grid_gutter == 'large' %}
{% assign safe_grid_gutter = 'medium' %}
{% endunless %}
<!-- 在样式中使用安全值 -->
<style>
:root {
--color-primary: {{ safe_color_primary }};
--color-secondary: {{ safe_color_secondary }};
--color-accent: {{ safe_color_accent }};
--page-width: {{ safe_page_width }}px;
--grid-gutter: {% case safe_grid_gutter %}
{% when 'small' %}1rem
{% when 'large' %}3rem
{% else %}2rem
{% endcase %};
}
</style>
设置迁移和版本控制
1. 设置版本管理
{
"name": "theme_info",
"theme_name": "我的主题",
"theme_version": "2.1.0",
"theme_author": "开发者名称",
"theme_documentation_url": "https://docs.example.com",
"theme_support_url": "https://support.example.com",
"settings": [
{
"type": "text",
"id": "theme_version_check",
"label": "主题版本",
"default": "2.1.0",
"info": "用于版本检查和设置迁移"
}
]
}
2. 设置迁移脚本
<!-- assets/settings-migration.liquid -->
<script>
class SettingsMigration {
constructor() {
this.currentVersion = '{{ settings.theme_version_check | default: "1.0.0" }}'
this.targetVersion = '2.1.0'
if (this.needsMigration()) {
this.migrate()
}
}
needsMigration() {
return this.compareVersions(this.currentVersion, this.targetVersion) < 0
}
migrate() {
console.log(`迁移主题设置从 ${this.currentVersion} 到 ${this.targetVersion}`)
// v1.0.0 到 v2.0.0 的迁移
if (this.compareVersions(this.currentVersion, '2.0.0') < 0) {
this.migrateToV2()
}
// v2.0.0 到 v2.1.0 的迁移
if (this.compareVersions(this.currentVersion, '2.1.0') < 0) {
this.migrateToV21()
}
}
migrateToV2() {
// 重命名的设置
this.renameSetting('old_color_primary', 'color_primary')
this.renameSetting('old_font_size', 'font_body_scale')
// 删除废弃的设置
this.removeSetting('deprecated_option')
console.log('已迁移到 v2.0.0')
}
migrateToV21() {
// 新的默认值迁移
this.setDefaultIfEmpty('enable_lazyload', true)
this.setDefaultIfEmpty('cart_type', 'drawer')
console.log('已迁移到 v2.1.0')
}
compareVersions(v1, v2) {
const parts1 = v1.split('.').map(Number)
const parts2 = v2.split('.').map(Number)
for (let i = 0; i < Math.max(parts1.length, parts2.length); i++) {
const part1 = parts1[i] || 0
const part2 = parts2[i] || 0
if (part1 < part2) return -1
if (part1 > part2) return 1
}
return 0
}
renameSetting(oldKey, newKey) {
const oldValue = localStorage.getItem(`theme_setting_${oldKey}`)
if (oldValue) {
localStorage.setItem(`theme_setting_${newKey}`, oldValue)
localStorage.removeItem(`theme_setting_${oldKey}`)
}
}
removeSetting(key) {
localStorage.removeItem(`theme_setting_${key}`)
}
setDefaultIfEmpty(key, defaultValue) {
const currentValue = localStorage.getItem(`theme_setting_${key}`)
if (!currentValue) {
localStorage.setItem(`theme_setting_${key}`, JSON.stringify(defaultValue))
}
}
}
// 执行迁移
new SettingsMigration()
</script>
最佳实践总结
1. 设置组织原则
- 逻辑分组: 将相关设置归类到同一组
- 清晰命名: 使用描述性的标签和ID
- 提供帮助: 为复杂设置添加说明信息
- 合理默认值: 设置适当的默认值
- 渐进增强: 从基础设置开始,逐步添加高级选项
2. 性能考虑
- CSS变量: 使用CSS自定义属性管理动态样式
- 条件加载: 根据设置条件性加载资源
- 缓存友好: 避免频繁更改会影响缓存的设置
3. 用户体验
- 即时预览: 确保设置更改能立即在预览中体现
- 合理限制: 为数值设置适当的最小值和最大值
- 直观操作: 选择最适合的输入控件类型
通过完善的主题设置系统,您可以创建出既灵活又易用的 Shopify 主题!
下一步学习
掌握主题设置配置后,建议继续学习:
最后更新时间: