szenario / craft-shopify-variants
Pick individual Shopify product variants in Craft, as a field or a link type.
Package info
github.com/szenario-fordesigners/craft-shopify-variants
Type:craft-plugin
pkg:composer/szenario/craft-shopify-variants
Requires
- php: >=8.2
- craftcms/cms: ^5.10.0
- craftcms/shopify: ^8.0
Requires (Dev)
- craftcms/ecs: dev-main
- craftcms/phpstan: dev-main
Suggests
None
Provides
None
Conflicts
None
Replaces
None
README
Shopify Variants
Made possible by
The team behind the magic
Simon Wesp Thomas Bendl Erich Bendl
Lets Craft editors pick individual Shopify product variants, not just products. Builds on the synced catalog from craftcms/shopify.
Two things ship in the box:
- Shopify Variants field: an ordered, optionally capped list of variants.
- Shopify variant link type: a single variant, for Craft's native Link field.
Requirements
- Craft CMS 5.10+
- PHP 8.2+
craftcms/shopify8.0+
Both the field type and the link type only appear while the Shopify plugin is installed and enabled.
The field
Add a Shopify Variants field, drop it in a field layout, and editors get a search box over the synced catalog with results grouped by product.
| Setting | Default | Notes |
|---|---|---|
maxVariants |
blank | Most variants an editor may select. Blank means no limit. Enforced server-side as well as in the picker. |
Search matches product title, variant title, and SKU. Shopify joins a variant's option values into its title ("Black / S"), so searching an option value works too.
Value
Persisted as JSON: [{"productGid": "...", "variantGid": "..."}, ...].
In Twig the field returns a SelectedVariantCollection. Each item is a SelectedVariant:
productGid,variantGid: the stored GIDs, always present.product,variant: the resolved Shopify models, ornullif that variant is gone from the sync.isResolved(): true only when both resolved.label: product and variant title combined, with Shopify'sDefault Titleplaceholder suppressed.image:{url, alt}, ornull. Falls back to the product image, since Shopify carries no variant image on single-variant products. Prefer this overvariant.image, which is null for those.
A variant can disappear from Shopify after it was picked, so always guard on product and variant:
{% for selection in entry.featuredVariants %}
{% if selection.isResolved() %}
{% set product = selection.product %}
{% set variant = selection.variant %}
{% set image = selection.image %}
{% if image %}<img src="{{ image.url }}" alt="{{ image.alt }}">{% endif %}
<a href="{{ product.url }}?variant={{ variant.shopifyId }}">
{{ selection.label }} {{ variant.price }}
</a>
{% endif %}
{% endfor %}
Stale selections are deliberately kept rather than silently dropped: the picker flags them so an editor can fix the entry.
The link type
Enable Shopify variant on any Link field. The stored value is a compound productGid|variantGid string, and it renders as a storefront deep link: <product url>?variant=<numeric variant id>.
It renders as an empty string when the product has no URL, so give Shopify products a URI format in the Shopify plugin's settings if you need the link to resolve.
The search endpoint
The picker fetches a page at a time from shopify-variants/variants/search rather than rendering the whole catalog into the page.
| Param | Default | Notes |
|---|---|---|
search |
'' |
product title, variant title, SKU |
page |
0 |
zero-indexed, paginated by product |
limit |
20 |
products per page, clamped to 100 |
Returns {groups, total, hasMore}. Control Panel requests from a logged-in user only; no extra permission, since this is the same catalog data an editor already needs to fill in the field.
Checking an install
php craft shopify-variants/check
Asserts that the catalog searches, paginates, and round-trips: pick an option, resolve it back, and get the same product and variant. Worth running after any craftcms/shopify upgrade. Shopify 8 moved the full GID off Variant::$shopifyId (now numeric) onto Variant::$shopifyGid, and that class of change fails silently: the picker keeps working while every stored selection resolves as missing.
Development
composer check-cs
composer phpstan