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.
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
| Concept | WooCommerce | Shopify |
|---|---|---|
| Template language | PHP | Liquid (Ruby-based) |
| Template overrides | Copy to child-theme/woocommerce/ | Edit theme files directly (or use theme app extension) |
| Action hooks | add_action('woocommerce_before_add_to_cart_button', ...) | No hook system — edit Liquid files directly |
| Filter hooks | add_filter('woocommerce_product_title', ...) | No filter system — logic in Liquid or app embed |
| Dynamic sections | PHP partial + AJAX | Liquid sections + Section Rendering API |
| Theme settings | WordPress customizer | Shopify Theme Editor (settings_schema.json) |
| Metafields in templates | get_post_meta() in PHP | product.metafields.namespace.key in Liquid |
| Conditional logic | PHP if/else/foreach | Liquid if/unless/for |
| SCSS/CSS | Child theme style.css | assets/theme.css or inline CSS in sections |
| JavaScript | wp_enqueue_script() in functions.php | assets/*.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:
- Create
assets/custom.cssin the theme - Reference in
layout/theme.liquid:{{ 'custom.css' | asset_url | stylesheet_tag }} - For section-specific CSS: write CSS directly inside the section file's
<style>tag (Shopify scopes it to the section) - CSS variables: define in
assets/base.css(Dawn) or inline in theme.liquid's<style>block based onsettings.*
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
- Use Shopify CLI:
shopify theme dev --store yourstore.myshopify.comfor local development with live preview - Pull theme to local:
shopify theme pull - Push changes:
shopify theme push - Work in an unpublished duplicate theme to avoid breaking the live store
- Never edit the published theme directly in production — always use a development theme
- Dawn source code: GitHub at Shopify/dawn — reference for patterns
Developer migration checklist
- Map WooCommerce PHP template overrides to Liquid section/snippet equivalents
- Convert PHP logic (conditionals, loops) to Liquid syntax
- Move custom CSS from child theme style.css to assets/custom.css
- Move wp_enqueue_script JS to assets/*.js with defer loading in theme.liquid
- Add custom theme settings for merchant-editable values (colors, text) in settings_schema.json
- Display metafields in templates using product.metafields.namespace.key
- Test all Liquid templates with edge cases: sold out products, products without images, empty metafields
- Use Shopify CLI for local development workflow
- Review Dawn source code for standard implementation patterns before writing custom code
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 freeRelated reading
Migrating a luggage and travel accessories store from WooCommerce to Shopify (2026)
How to migrate a luggage, travel bags, or travel accessories WooCommerce store to Shopify — luggage specifications, airline compliance, TSA lock, warranty and durability claims, and luggage retail Shopify setup.
Migrating a motorcycle accessories store from WooCommerce to Shopify (2026)
How to migrate a motorcycle accessories, biker gear, or motorbike parts WooCommerce store to Shopify — helmet safety standards, CE-rated protective clothing, type approval for parts, fitment compatibility, and motorcycle retail Shopify setup.