WooCommerce PHP templates vs Shopify liquid: a developer's migration guide (2026)
How WooCommerce PHP templates, hooks, and filters translate to Shopify Liquid — template hierarchy comparison, filter/action equivalents, product loops, custom fields, and building custom sections.
WooCommerce developers fluent in WordPress PHP, hooks, filters, and template overrides need to learn a new mental model for Shopify. Liquid is a simpler templating language than PHP, but the architectural concepts differ significantly. This guide maps WooCommerce PHP patterns to Shopify Liquid equivalents for developers performing migrations.
Template hierarchy comparison
WooCommerce template structure
woocommerce/
├── templates/
│ ├── single-product.php ← product page
│ ├── archive-product.php ← collection/shop page
│ ├── cart/cart.php ← cart page
│ ├── checkout/form-checkout.php
│ └── content-product.php ← product card in loops
WooCommerce templates are overridden by copying to yourtheme/woocommerce/. WordPress's template hierarchy determines which template loads.
Shopify template structure
templates/
├── product.liquid (or product.json) ← product page
├── collection.liquid ← collection page
├── cart.liquid ← cart page
├── index.liquid ← homepage
└── page.liquid ← static pages
sections/
├── product-form.liquid ← product form section
├── collection-product-grid.liquid ← product grid section
└── custom-section.liquid ← your custom sections
snippets/
├── product-card.liquid ← product card partial
└── price.liquid ← price rendering snippet
Shopify Online Store 2.0 uses JSON templates that define which sections load on a page. This enables theme editor customization.
PHP vs Liquid syntax comparison
Variables
// WooCommerce PHP
$product->get_title();
$product->get_price();
$product->get_sku();
// Shopify Liquid
{{ product.title }}
{{ product.price | money }}
{{ product.selected_or_first_available_variant.sku }}
Loops
// WooCommerce PHP
foreach ($products as $product) {
wc_get_template_part('content', 'product');
}
// Shopify Liquid
{% for product in collection.products %}
{{ product.title }}
{% endfor %}
Conditionals
// WooCommerce PHP
if ($product->is_on_sale()) {
echo 'On Sale!';
}
// Shopify Liquid
{% if product.compare_at_price > product.price %}
On Sale!
{% endif %}
Filters (Liquid) vs Functions (PHP)
// WooCommerce PHP
wc_price($product->get_price());
strtoupper($text);
date('Y-m-d', $timestamp);
// Shopify Liquid
{{ product.price | money }}
{{ text | upcase }}
{{ article.created_at | date: "%Y-%m-%d" }}
WordPress hooks vs Shopify sections
WooCommerce hooks
WooCommerce's hook system (actions and filters) allows injecting content into templates:
// WooCommerce: add content before product summary
add_action('woocommerce_before_single_product_summary', 'my_function');
function my_function() {
echo '<div class="custom">Custom content</div>';
}
// WooCommerce: modify product price
add_filter('woocommerce_get_price_html', 'my_price_filter', 10, 2);
Shopify equivalent: sections and snippets
In Shopify, there's no hook system. Content is injected by editing templates and sections directly:
// Shopify product.json: add a custom section to product template
{
"sections": {
"product-info": { "type": "product-form" },
"custom-badge": { "type": "custom-badge-section" } ← add custom section here
},
"order": ["product-info", "custom-badge"]
}
Or: edit the section Liquid file directly to add content in specific positions.
Custom fields: ACF vs Shopify metafields
WooCommerce ACF in PHP
// Reading ACF field in WooCommerce template
$custom_value = get_field('material', get_the_ID());
echo esc_html($custom_value);
// Or with post meta
$value = get_post_meta(get_the_ID(), '_custom_field_key', true);
Shopify metafields in Liquid
// Reading metafield in Shopify Liquid
{{ product.metafields.product_info.material }}
// With fallback
{{ product.metafields.product_info.material | default: 'Not specified' }}
// Accessing a list metafield
{% for item in product.metafields.product_info.materials.value %}
{{ item }}
{% endfor %}
Product loops: WooCommerce vs Shopify
WooCommerce product query loop
// WooCommerce: get products and loop
$args = array(
'post_type' => 'product',
'posts_per_page' => 12,
'tax_query' => array(
array('taxonomy' => 'product_cat', 'field' => 'slug', 'terms' => 'sale')
)
);
$products = new WP_Query($args);
while ($products->have_posts()) {
$products->the_post();
wc_get_template_part('content', 'product');
}
Shopify collection product loop
// Shopify Liquid: loop products in a collection
{% for product in collection.products %}
{{ product.title }}
{{ product.price | money }}
{% if product.available %}
<a href="{{ product.url }}">Add to Cart</a>
{% endif %}
{% endfor %}
// With pagination
{% paginate collection.products by 24 %}
{% for product in collection.products %}
...
{% endfor %}
{{ paginate | default_pagination }}
{% endpaginate %}
Custom section development (equivalent to WooCommerce widget areas)
Creating a custom Shopify section (equivalent to a WooCommerce widget area or custom hook):
// sections/custom-badge.liquid
{% schema %}
{
"name": "Custom Badge",
"settings": [
{
"type": "text",
"id": "badge_text",
"label": "Badge text",
"default": "New!"
},
{
"type": "color",
"id": "badge_color",
"label": "Badge color",
"default": "#3a8c9c"
}
],
"presets": [
{
"name": "Custom Badge"
}
]
}
{% endschema %}
<div class="custom-badge" style="background: {{ section.settings.badge_color }}">
{{ section.settings.badge_text }}
</div>
WooCommerce filter plugins vs Shopify search/filter
WooCommerce layered navigation filter (PHP)
WooCommerce's layered nav uses widget areas and custom taxonomy queries. WOOF and FacetWP provide advanced filtering with custom PHP queries.
Shopify native filtering
Shopify's Search & Discovery app adds faceted filtering using collection filters configured in the admin. No custom PHP required — filters are applied via URL parameters and Liquid.
// Liquid: render active filters
{% for filter in collection.filters %}
{% for filter_value in filter.values %}
{% if filter_value.active %}
{{ filter_value.label }} ×
{% endif %}
{% endfor %}
{% endfor %}
Shopify CLI for theme development
The Shopify CLI replaces WP-CLI and local WordPress development:
// WooCommerce: local development
# wp server, LocalWP, WAMP, Docker
// Shopify: local theme development
npm install -g @shopify/cli @shopify/theme
shopify theme dev --store your-store.myshopify.com
# Live reload with file watching, direct to development store
shopify theme dev: live development with hot reloadshopify theme push: push theme files to storeshopify theme pull: pull theme files from store- Git workflow: commit theme files, use
shopify theme pushfor deployment
Key Liquid concepts for WooCommerce developers
- No database queries: Liquid has no direct database access. All data comes from Shopify's pre-built objects (product, collection, customer, cart).
- No custom PHP functions: Can't add custom PHP business logic. Move complex logic to Shopify Flow or a Shopify app (serverless functions).
- Section schema: Every section has a
{% schema %}block defining its settings — this is how theme editor customization works. - Metafield types matter: Shopify metafields are strongly typed. Accessing a list metafield requires
.valuein Liquid (e.g.,product.metafields.ns.key.valuefor list types). - No WP_Query equivalent: Can't query arbitrary products in Liquid. Use collections, featured product sections, or the Storefront API (JavaScript) for dynamic product queries.
- AJAX vs Section Rendering API: Shopify's Section Rendering API replaces WordPress AJAX for dynamic section updates (cart drawer, product picker, etc.).
Developer migration checklist
- Audit all WooCommerce template overrides: list each template file being overridden and what customization it performs
- Map each override to Shopify equivalent: section edit, snippet, or metafield rendering
- List all WooCommerce actions/filters: which hooks inject content? Reimplement in Liquid sections.
- Export all ACF fields: map to Shopify metafield definitions
- Set up Shopify CLI for local theme development
- Learn Liquid basics: filters, loops, conditionals, section schema syntax
- Build custom sections for any injected content that was PHP hook-based
- Test Section Rendering API for any AJAX-based UI (cart drawer, variant switching, product quick view)
- Use Shopify Flow for any business logic previously in custom WooCommerce PHP (auto-tag, auto-email, status updates)
Liquid is easier than PHP for most tasks — it's intentionally constrained (no database access, no arbitrary PHP execution) which means less risk of developer errors. The transition requires a mindset shift: stop thinking "how do I write PHP to do this" and start thinking "how does Shopify expose this data already, and how do I render it". Most WooCommerce customizations can be replicated with the data Shopify provides — the cases that can't are edge cases requiring a Shopify app (server-side logic) rather than template code.
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.