k-sync
Back to blog

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.

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

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

Key Liquid concepts for WooCommerce developers

Developer migration checklist

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 free

Related reading

Browse all migration guides