Summary
The README's "add products to the cart" example posts variant.id to the cart/add endpoint:
<form action="{{ craft.shopify.store.getUrl('cart/add') }}" method="post">
<select name="id">
{% for variant in product.getVariants() %}
<option value="{{ variant.id }}">{{ variant.title }}</option>
{% endfor %}
</select>
{{ hiddenInput('qty', 1) }}
<button>Add to Cart</button>
</form>
In v7, variant.id is the Craft element/row ID, not a Shopify identifier. Submitting this form sends e.g. id=7271 to the store, and Shopify responds:
Cart Error: Cannot find variant
Root cause
In v7 a variant is a craft\shopify\models\Variant (@since 7.0.0), where:
public ?int $id = null; // Craft row/element ID, e.g. 7271
public ?string $shopifyId = null; // Shopify GID, e.g. gid://shopify/ProductVariant/55602221973830
So variant.id is never a Shopify identifier. The Shopify ID is on variant.shopifyId, but it's a GID (gid://shopify/ProductVariant/<numeric>), whereas the cart/add endpoint expects the bare numeric variant ID. The plugin itself strips this prefix elsewhere — see src/fieldlayoutelements/VariantsField.php:
str_replace('gid://shopify/ProductVariant/', '', $variant->shopifyId)
This confirms shopifyId is a GID and there is no first-class numeric accessor on Variant.
Product vs. Variant inconsistency (related)
Products and variants are stored differently, and expose shopifyId differently:
|
Storage |
Numeric ID exposed? |
GID exposed? |
| Product |
shopify_products table |
✅ shopifyId (numeric) |
✅ shopifyGid |
| Variant |
shopify_data (type = ProductVariant) |
❌ none |
✅ shopifyId (the GID) |
So product.shopifyId is a clean numeric, but variant.shopifyId is a GID — same property name, different shape — and variants have no numeric equivalent.
Suggested fixes (either/both)
-
Docs: update the README cart/add example to use the numeric portion of the variant's Shopify ID:
<option value="{{ variant.shopifyId|split('/')|last }}">{{ variant.title }}</option>
-
API (preferred): make Variant consistent with the Product element — expose a numeric shopifyId (and a shopifyGid for the GID) — so consumers don't have to string-split a GID for a documented, common workflow.
Environment
craftcms/shopify 7.1.2
- Craft CMS 5.10.x
- PHP 8.3
Summary
The README's "add products to the cart" example posts
variant.idto thecart/addendpoint:In v7,
variant.idis the Craft element/row ID, not a Shopify identifier. Submitting this form sends e.g.id=7271to the store, and Shopify responds:Root cause
In v7 a variant is a
craft\shopify\models\Variant(@since 7.0.0), where:So
variant.idis never a Shopify identifier. The Shopify ID is onvariant.shopifyId, but it's a GID (gid://shopify/ProductVariant/<numeric>), whereas thecart/addendpoint expects the bare numeric variant ID. The plugin itself strips this prefix elsewhere — seesrc/fieldlayoutelements/VariantsField.php:This confirms
shopifyIdis a GID and there is no first-class numeric accessor onVariant.Product vs. Variant inconsistency (related)
Products and variants are stored differently, and expose
shopifyIddifferently:shopify_productstableshopifyId(numeric)shopifyGidshopify_data(type = ProductVariant)shopifyId(the GID)So
product.shopifyIdis a clean numeric, butvariant.shopifyIdis a GID — same property name, different shape — and variants have no numeric equivalent.Suggested fixes (either/both)
Docs: update the README
cart/addexample to use the numeric portion of the variant's Shopify ID:API (preferred): make
Variantconsistent with theProductelement — expose a numericshopifyId(and ashopifyGidfor the GID) — so consumers don't have to string-split a GID for a documented, common workflow.Environment
craftcms/shopify7.1.2