Token导航 LogoToken导航TokenDH.com
前端设计需要联网github未标认证来源可访问许可证需确认审计通过

shopify-theme-developmentShopify 主题开发

Agent Skill

shopify-theme-development 用于处理 GitHub 仓库、Issue、Pull Request 和代码协作信息,适合在 Codex、Claude、Cursor、Gemini CLI 中需要围绕仓库状态、代码变更或协作事项进行整理时使用。可结合来源仓库、安装命令和原始 README 继续核验具体用法。安装前建议确认权限范围、维护状态,以及是否会触发联网、命令执行或文件读写。

总安装

533

周安装

22

GitHub Stars

19

下载量

174
CodexClaudeCursorGemini CLI

安装说明

本站只整理中文说明和来源信息,不托管安装包,也不代用户安装。

GitHub

来源数

2

许可证

unknown

最后核验

2026-05-01

来源状态

来源可访问

安装方式

通过对话安装

复制提示词发给支持本地命令或 Skills 的 AI 助手,先确认命令和权限,再让它执行。

请帮我安装这个 Agent Skill:shopify-theme-development(Shopify 主题开发)
来源仓库:https://github.com/finsilabs/awesome-ecommerce-skills
仓库路径:skills/shopify-theme-development
安装命令:
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill shopify-theme-development
安装前请先检查当前环境是否支持对应 CLI,并向我确认将要执行的命令、安装目录、联网范围和文件读写权限;确认后再执行。

命令行安装

复制命令到本机终端执行。该命令会通过 npx skills 从第三方来源获取 Skill;本站只展示命令,不托管安装包,也不自动执行。

skills.shnpx skills
npx skills add https://github.com/finsilabs/awesome-ecommerce-skills --skill shopify-theme-development

简介

用于处理 Shopify 主题开发过程中的协作信息与变更追踪任务。

  • 适合在 Issue、Pull Request 或代码评审中整理主题相关讨论与修改点。
  • 通过 npx 命令安装,集成于支持技能扩展的 AI 编程工具链。
  • 使用时应注意主题文件的读写权限,避免误删关键配置文件。
  • shopify-theme-development 属于前端设计类 Skill,可作为该场景下的辅助能力补充。

SKILL.md

Shopify Theme Development

Overview

Build and customize Shopify themes using Liquid templating, JSON templates, sections and blocks for merchant-customizable layouts, and theme app extensions for app integrations. This skill covers the Shopify theme architecture (Online Store 2.0), the Shopify CLI development workflow, performance optimization with lazy loading and critical CSS, and patterns for building flexible sections that merchants can configure through the theme editor.

When to Use This Skill

  • When building a new Shopify theme from scratch or forking Dawn
  • When creating custom sections and blocks for the theme editor
  • When implementing product pages, collection grids, or cart functionality in Liquid
  • When optimizing a Shopify theme for Core Web Vitals and speed
  • When building theme app extensions to inject app content into themes

Core Instructions

  1. Set up the development environment with Shopify CLI # Install Shopify CLI npm install -g @shopify/cli @shopify/theme # Initialize a new theme (or clone Dawn) shopify theme init my-theme # Start development server with hot reload shopify theme dev --store=your-store.myshopify.com Theme directory structure (Online Store 2.0): my-theme/ ├── assets/ # CSS, JS, images ├── config/ # settings_schema.json, settings_data.json ├── layout/ # theme.liquid (main layout) ├── locales/ # Translation files ├── sections/ # Sections (reusable, merchant-configurable) ├── snippets/ # Partials (reusable Liquid fragments) └── templates/ # JSON templates referencing sections ├── product.json ├── collection.json └── index.json
  2. Create a JSON template with sections // templates/product.json {"sections": {"main": {"type": "main-product", "settings": {}}, "recommendations": {"type": "product-recommendations", "settings": {"heading": "You may also like", "products_to_show": 4}}, "reviews": {"type": "product-reviews", "settings": {}}}, "order": ["main", "recommendations", "reviews"]}
  3. Build a customizable product section with blocks {% comment %} sections/main-product.liquid {% endcomment %} <section class="product-section" data-section-id="{{section.id}}"> <div class="product-grid"> <div class="product-media"> {% for media in product.media %} {% case media.media_type %} {% when 'image' %} <div class="product-media-item {% if forloop.first %}active{% endif %}"> {{media | image_url: width: 800 | image_tag: loading: 'lazy', widths: '200,400,600,800,1000', sizes: '(min-width: 768px) 50vw, 100vw', class: 'product-image'}} </div> {% when 'video' %} <div class="product-media-item"> {{media | video_tag: autoplay: false, controls: true}} </div> {% endcase %} {% endfor %} </div> <div class="product-info"> {% for block in section.blocks %} {% case block.type %} {% when 'title' %} <h1 class="product-title" {{block.shopify_attributes}}> {{product.title}} </h1> {% when 'price' %} <div class="product-price" {{block.shopify_attributes}}> {% if product.compare_at_price > product.price %} <s class="price-compare">{{product.compare_at_price | money}}</s> {% endif %} <span class="price-current">{{product.price | money}}</span> {% if product.compare_at_price > product.price %} <span class="price-badge">Sale</span> {% endif %} </div> {% when 'variant_picker' %} <div class="variant-picker" {{block.shopify_attributes}}> {% for option in product.options_with_values %} <fieldset class="option-group"> <legend>{{option.name}}</legend> {% for value in option.values %} <label class="option-label"> <input type="radio" name="{{option.name}}" value="{{value}}" {% if option.selected_value == value %}checked{% endif %} > <span>{{value}}</span> </label> {% endfor %} </fieldset> {% endfor %} </div> {% when 'buy_buttons' %} <div class="buy-buttons" {{block.shopify_attributes}}> {% form 'product', product %} <input type="hidden" name="id" value="{{product.selected_or_first_available_variant.id}}"> <div class="quantity-selector"> <label for="quantity">Quantity</label> <input type="number" id="quantity" name="quantity" value="1" min="1"> </div> <button type="submit" class="btn btn-primary add-to-cart" {% unless product.selected_or_first_available_variant.available %}disabled{% endunless %} > {% if product.selected_or_first_available_variant.available %} Add to cart — {{product.selected_or_first_available_variant.price | money}} {% else %} Sold out {% endif %} </button> {% endform %} </div> {% when 'description' %} <div class="product-description" {{block.shopify_attributes}}> {{product.description}} </div> {% when 'custom_text' %} <div class="custom-text" {{block.shopify_attributes}}> {{block.settings.text}} </div> {% endcase %} {% endfor %} </div> </div> </section> {% schema %} {"name": "Product Page", "tag": "section", "class": "section-product", "blocks": [{"type": "title", "name": "Title", "limit": 1}, {"type": "price", "name": "Price", "limit": 1}, {"type": "variant_picker", "name": "Variant Picker", "limit": 1}, {"type": "buy_buttons", "name": "Buy Buttons", "limit": 1}, {"type": "description", "name": "Description", "limit": 1}, {"type": "custom_text", "name": "Custom Text", "settings": [{"type": "richtext", "id": "text", "label": "Text"}]}], "presets": [{"name": "Product Page", "blocks": [{"type": "title"}, {"type": "price"}, {"type": "variant_picker"}, {"type": "buy_buttons"}, {"type": "description"}]}]} {% endschema %}
  4. Implement AJAX cart with the Cart API // assets/cart.js class CartManager {async addItem(variantId, quantity = 1) {const response = await fetch('/cart/add.js', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({items: [{id: variantId, quantity}],}),}); if (!response.ok) {const error = await response.json(); throw new Error(error.description || 'Could not add to cart');} const data = await response.json(); this.updateCartUI(); return data;} async updateQuantity(lineKey, quantity) {const response = await fetch('/cart/change.js', {method: 'POST', headers: {'Content-Type': 'application/json'}, body: JSON.stringify({id: lineKey, quantity}),}); const cart = await response.json(); this.updateCartUI(cart); return cart;} async getCart() {const response = await fetch('/cart.js'); return response.json();} async updateCartUI(cart) {cart = cart || await this.getCart(); // Update cart count badge const badge = document.querySelector('[data-cart-count]'); if (badge) badge.textContent = cart.item_count; // Update cart drawer if open const drawer = document.querySelector('cart-drawer'); if (drawer) drawer.render(cart);}} window.cart = new CartManager();
  5. Optimize for performance {% comment %} layout/theme.liquid — Critical performance optimizations {% endcomment %} <!doctype html> <html lang="{{request.locale.iso_code}}"> <head> <meta charset="utf-8"> <meta name="viewport" content="width=device-width, initial-scale=1"> <!-- Preconnect to Shopify CDN --> <link rel="preconnect" href="https://cdn.shopify.com" crossorigin> <link rel="preconnect" href="https://fonts.shopifycdn.com" crossorigin> <!-- Preload critical assets --> {% if template.name == 'product' %} {% assign hero_image = product.featured_image %} {% if hero_image %} <link rel="preload" as="image" href="{{hero_image | image_url: width: 800}}" imagesrcset="{{hero_image | image_url: width: 400}} 400w, {{hero_image | image_url: width: 800}} 800w" imagesizes="(min-width: 768px) 50vw, 100vw" > {% endif %} {% endif %} <!-- Inline critical CSS --> <style> {{'critical.css' | asset_url | stylesheet_tag | split: '<link' | first}} </style> <!-- Defer non-critical CSS --> <link rel="stylesheet" href="{{'theme.css' | asset_url}}" media="print" onload="this.media='all'"> <noscript><link rel="stylesheet" href="{{'theme.css' | asset_url}}"></noscript> {{content_for_header}} </head> <body> {{content_for_layout}} <!-- Defer JavaScript --> <script src="{{'theme.js' | asset_url}}" defer></script> </body> </html>
  6. Create a theme app extension # Generate a theme app extension block shopify app generate extension --type theme_app_extension --name my-app-block {% comment %} extensions/my-app-block/blocks/product-badge.liquid {% endcomment %} <div class="app-product-badge" {{block.shopify_attributes}}> {% if block.settings.badge_text!= blank %} <span class="badge" style="background-color: {{block.settings.badge_color}}; color: {{block.settings.text_color}};" > {{block.settings.badge_text}} </span> {% endif %} </div> {% schema %} {"name": "Product Badge", "target": "section", "settings": [{"type": "text", "id": "badge_text", "label": "Badge text", "default": "New"}, {"type": "color", "id": "badge_color", "label": "Badge color", "default": "#FF0000"}, {"type": "color", "id": "text_color", "label": "Text color", "default": "#FFFFFF"}]} {% endschema %}

Examples

Collection grid with lazy-loaded images

{% comment %} sections/collection-grid.liquid {% endcomment %}
<section class="collection-grid">
  <h1>{{ collection.title }}</h1>

  <div class="product-grid" role="list">
    {% paginate collection.products by 24 %}
      {% for product in collection.products %}
        <div class="product-card" role="listitem">
          <a href="{{ product.url }}">
            {% if product.featured_image %}
              {{ product.featured_image | image_url: width: 400 | image_tag:
                loading: 'lazy',
                widths: '200,300,400',
                sizes: '(min-width: 1024px) 25vw, (min-width: 768px) 33vw, 50vw',
                class: 'product-card-image'
              }}
            {% endif %}
            <h2 class="product-card-title">{{ product.title }}</h2>
            <p class="product-card-price">{{ product.price | money }}</p>
          </a>
        </div>
      {% endfor %}

      {% if paginate.pages > 1 %}
        <nav class="pagination" aria-label="Pagination">
          {{ paginate | default_pagination: next: 'Next', previous: 'Previous' }}
        </nav>
      {% endif %}
    {% endpaginate %}
  </div>
</section>

Variant change with JavaScript

// assets/variant-selector.js
class VariantSelector extends HTMLElement {
  connectedCallback() {
    this.addEventListener('change', this.onVariantChange.bind(this));
    this.productData = JSON.parse(
      this.querySelector('[type="application/json"]').textContent
    );
  }

  onVariantChange() {
    const selectedOptions = [...this.querySelectorAll('input:checked')].map(
      input => input.value
    );

    const variant = this.productData.variants.find(v =>
      v.options.every((opt, i) => opt === selectedOptions[i])
    );

    if (!variant) return;

    // Update URL without reload
    const url = new URL(window.location);
    url.searchParams.set('variant', variant.id);
    window.history.replaceState({}, '', url);

    // Update price display
    const priceEl = document.querySelector('.price-current');
    if (priceEl) {
      priceEl.textContent = this.formatMoney(variant.price);
    }

    // Update add-to-cart button
    const addToCart = document.querySelector('.add-to-cart');
    const idInput = document.querySelector('input[name="id"]');
    if (addToCart && idInput) {
      idInput.value = variant.id;
      addToCart.disabled = !variant.available;
      addToCart.textContent = variant.available ? 'Add to cart' : 'Sold out';
    }
  }

  formatMoney(cents) {
    return '$' + (cents / 100).toFixed(2);
  }
}

customElements.define('variant-selector', VariantSelector);

Best Practices

  • Use Online Store 2.0 JSON templates — they enable merchants to add, remove, and reorder sections without editing code
  • Leverage the image_url and image_tag filters — they generate responsive srcset attributes automatically from Shopify's CDN
  • Always include {{block.shopify_attributes}} — this data attribute is required for the theme editor to identify and select blocks
  • Defer all JavaScript — use defer or type="module" on script tags; avoid render-blocking JS
  • Use Shopify's native Liquid filters| money, | image_url, | asset_url are optimized and handle edge cases; don't reinvent them
  • Provide section presets — presets define the default state when a merchant adds a section; without them, the section won't appear in "Add section"
  • Keep sections under 50KB of Liquid — large sections slow down the Liquid renderer; extract reusable code into snippets
  • Test on Shopify's staging theme — always preview changes on an unpublished theme before deploying to the live theme

Common Pitfalls

ProblemSolution
Section not appearing in "Add section" menuEnsure the section has a presets array in its {% schema %}; sections without presets are only available in JSON templates
Theme editor shows "Error rendering section"Check for Liquid syntax errors; use shopify theme check to lint your Liquid code
Images not loading on Shopify CDNUse image_url filter with explicit width parameter; the old img_url filter is deprecated
Cart count badge not updating after AJAX addFetch /cart.js after every cart mutation and update the badge; don't rely on the response from add.js alone
Slow Largest Contentful Paint (LCP)Preload the hero/product image in <head> using <link rel="preload" as="image">; inline critical CSS
Metafields not accessible in LiquidEnsure metafield definitions are created in Shopify admin; access via product.metafields.namespace.key

Related Skills

  • @product-page-design
  • @ecommerce-seo
  • @ecommerce-caching
  • @storefront-performance
  • @shopify-app-development

适合场景

01

用户想查找某类 Agent Skill 时

02

需要根据任务场景推荐可安装能力包时

03

需要对比不同来源的安装命令和来源信息时

能力概览

能力 1

按任务关键词查找相关 Skills

能力 2

展示可复制的安装命令

能力 3

保留来源站点、仓库和原始说明,方便继续核验

能力 4

展示第三方安全扫描或审计结果

安装后应在对应宿主中按原始 README 的触发条件使用;具体调用方式请以来源页面和 README 为准。

平台分布

Codex

35.57%
按下载量换算62

Claude

27.64%
按下载量换算48

Cursor

18.72%
按下载量换算33

Gemini CLI

8.37%
按下载量换算15

安全审计

Gen Agent Trust Hub

通过

Socket

通过

Snyk

通过

权限和风险

需要联网

该 Skill 可能需要联网访问来源站点、仓库或外部 API;具体网络访问范围需要结合源码和 README 复核。

安装前确认

本站仅展示第三方公开信息,不托管安装包,不提供自动安装或运行环境。安装前应自行审查源码、依赖和命令行为。当前只有一个来源,正式发布前建议补源仓库或其他目录站核验。

来源信息

继续浏览同类 Skills