k-sync
Back to blog

Shopify theme customization for WooCommerce developers (2026)

How WooCommerce developers customize Shopify themes — Liquid syntax, theme sections, settings schema, Dawn architecture, overriding theme defaults, and porting WooCommerce template customizations to Shopify.

·By k-sync
6 min read · 1,182 words

WooCommerce developers customizing storefronts used PHP template overrides, hooks, and filters — replacing woocommerce/templates/ files in the child theme and hooking into woocommerce_before_add_to_cart_button and similar action hooks. Shopify's equivalent is the Liquid template system with a completely different architecture. This guide maps WooCommerce developer patterns to their Shopify Liquid equivalents.

WooCommerce template system vs Shopify Liquid

ConceptWooCommerceShopify
Template languagePHPLiquid (Ruby-based)
Template overridesCopy to child-theme/woocommerce/Edit theme files directly (or use theme app extension)
Action hooksadd_action('woocommerce_before_add_to_cart_button', ...)No hook system — edit Liquid files directly
Filter hooksadd_filter('woocommerce_product_title', ...)No filter system — logic in Liquid or app embed
Dynamic sectionsPHP partial + AJAXLiquid sections + Section Rendering API
Theme settingsWordPress customizerShopify Theme Editor (settings_schema.json)
Metafields in templatesget_post_meta() in PHPproduct.metafields.namespace.key in Liquid
Conditional logicPHP if/else/foreachLiquid if/unless/for
SCSS/CSSChild theme style.cssassets/theme.css or inline CSS in sections
JavaScriptwp_enqueue_script() in functions.phpassets/*.js referenced in layout/theme.liquid or section files

Liquid syntax basics

Variables and output

{{ product.title }}
{{ product.price | money }}
{{ product.description }}
{{ product.metafields.sizing.fit_notes }}

Control flow

{% if product.available %}
  <button>Add to cart</button>
{% else %}
  <p>Sold out</p>
{% endif %}

{% for variant in product.variants %}
  <option value="{{ variant.id }}">{{ variant.title }} — {{ variant.price | money }}</option>
{% endfor %}

{% unless product.tags contains 'sale' %}
  <!-- not on sale -->
{% endunless %}

Filters (equivalent to WordPress/WooCommerce filters but built-in)

{{ product.price | money }}                    {# £29.99 #}
{{ product.title | upcase }}                   {# PRODUCT TITLE #}
{{ 'image.jpg' | asset_url | img_tag }}        {# <img src="cdn.shopify.com/..." #}
{{ product.description | strip_html | truncate: 150 }}
{{ collection.products | sort: 'title' }}

Dawn theme architecture

Dawn is Shopify's reference theme (free, open source). Understanding its structure maps to WooCommerce child theme structure:

dawn/
├── assets/              ← CSS, JS, fonts, images (all served as-is from CDN)
├── config/
│   ├── settings_schema.json   ← Theme Editor controls (like WordPress customizer)
│   └── settings_data.json     ← Saved theme setting values
├── layout/
│   ├── theme.liquid     ← Global layout (like WP header.php + footer.php + wp_head())
│   └── password.liquid  ← Pre-launch password page layout
├── locales/             ← i18n translation strings
├── sections/            ← Reusable, configurable page sections (draggable in editor)
├── snippets/            ← Reusable Liquid partials (like WP template-parts)
└── templates/           ← Page templates
    ├── product.json     ← Product page template (references sections)
    ├── collection.json  ← Collection page template
    ├── index.json       ← Home page template
    ├── cart.json
    ├── page.json
    └── page.about.json  ← Custom template for specific pages

Sections and blocks

Sections are the core building block of Shopify themes — merchant-editable, draggable regions. Each section has a {% schema %} block that defines its settings:

{%- comment -%} sections/product-badges.liquid {%- endcomment -%}

<div class="product-badges">
  {% if section.settings.show_sale_badge and product.compare_at_price > product.price %}
    <span class="badge badge--sale">{{ section.settings.sale_text }}</span>
  {% endif %}
  {% if section.settings.show_new_badge and product.tags contains 'new' %}
    <span class="badge badge--new">New</span>
  {% endif %}
{% for block in section.blocks %}
  {% if block.type == 'custom_badge' %}
    <span class="badge" style="background: {{ block.settings.color }}">{{ block.settings.text }}</span>
  {% endif %}
{% endfor %}
</div>

{% schema %}
{
  "name": "Product Badges",
  "settings": [
    { "type": "checkbox", "id": "show_sale_badge", "label": "Show sale badge", "default": true },
    { "type": "checkbox", "id": "show_new_badge", "label": "Show new badge", "default": false },
    { "type": "text", "id": "sale_text", "label": "Sale badge text", "default": "Sale" }
  ],
  "blocks": [
    {
      "type": "custom_badge",
      "name": "Custom Badge",
      "settings": [
        { "type": "text", "id": "text", "label": "Badge text" },
        { "type": "color", "id": "color", "label": "Badge colour", "default": "#c0392b" }
      ]
    }
  ]
}
{% endschema %}

Snippets (replaces WooCommerce template partials)

Snippets are reusable Liquid partials — the equivalent of WooCommerce template parts and wc_get_template_part():

{%- comment -%} snippets/product-card.liquid {%- endcomment -%}
{%- assign product = product_card_product -%}

<div class="product-card">
  <a href="{{ product.url }}">
    {{ product.featured_media | image_url: width: 600 | image_tag: class: 'product-card__image', loading: 'lazy', alt: product.featured_media.alt }}
  </a>
  <div class="product-card__info">
    <h3>{{ product.title }}</h3>
    <span class="product-card__price">{{ product.price | money }}</span>
  </div>
</div>

{%- comment -%} Usage in a section: {%- endcomment -%}
{% render 'product-card', product_card_product: product %}

Theme settings (settings_schema.json)

Theme settings define global controls visible in the Theme Editor — equivalent to WordPress customizer settings:

// config/settings_schema.json (excerpt)
[
  {
    "name": "Brand",
    "settings": [
      { "type": "color", "id": "accent_color", "label": "Accent colour", "default": "#3a8c9c" },
      { "type": "font_picker", "id": "heading_font", "label": "Heading font", "default": "helvetica_n4" },
      { "type": "checkbox", "id": "show_announcement_bar", "label": "Show announcement bar", "default": false },
      { "type": "text", "id": "announcement_text", "label": "Announcement text" }
    ]
  }
]

Access in Liquid: {{ settings.accent_color }}, {{ settings.announcement_text }}

Adding custom CSS

WooCommerce developers added CSS in child theme style.css or via WordPress customizer custom CSS. Shopify equivalent:

Adding custom JavaScript

{%- comment -%} In layout/theme.liquid, before </body> {%- endcomment -%}
<script src="{{ 'custom.js' | asset_url }}" defer="defer"></script>

{%- comment -%} In a section, event listeners scoped to section {%- endcomment -%}
<script>
document.addEventListener('DOMContentLoaded', function() {
  var section = document.getElementById('shopify-section-{{ section.id }}');
  // section-scoped JavaScript
});
</script>

Displaying metafields in templates

WooCommerce used get_post_meta($product_id, 'custom_field', true) in PHP templates. Shopify Liquid:

{% comment %} In snippets/product-metafields.liquid {% endcomment %}
{% if product.metafields.sizing.fit_notes != blank %}
  <div class="fit-notes">
    <h3>Fit guide</h3>
    <p>{{ product.metafields.sizing.fit_notes }}</p>
  </div>
{% endif %}

{% if product.metafields.bike.frame_material != blank %}
  <dl class="bike-specs">
    <dt>Frame</dt>
    <dd>{{ product.metafields.bike.frame_material }}</dd>
    <dt>Weight</dt>
    <dd>{{ product.metafields.bike.weight_kg }}kg</dd>
  </dl>
{% endif %}

Theme development workflow

Developer migration checklist

The biggest mindset shift from WooCommerce to Shopify theme development is moving from hooks to direct edits. WooCommerce encouraged never editing plugin templates — use hooks to inject code around them. Shopify has no hook system; you edit Liquid files directly. This is simultaneously simpler (you see exactly what renders) and more fragile (theme updates can overwrite edits). The mitigation is Shopify's theme versioning: always work in a development theme, commit changes to version control, and review diffs before applying theme updates to ensure your customizations survive.

Migrate your store with k-sync

Connect your WooCommerce store, validate your products, and push to Shopify in minutes. Free for up to 50 products.

Get started free

Related reading

Browse all migration guides