Wheel and Tire product variants on the search results and in the Verify Fitment widget
If a store has wheels and tires with variants, it is possible to display the variants as products in the search results after selecting a vehicle and check the variants for the selected vehicle.
1. Connect the WheelTireVariantsPlugin
and add the wheel_tire_hierarchy_type
field
Plugins: - WheelTireUpsizeDownsizePluginFields: wheel_tire_hierarchy_type: Faceted: true Scope: Internal Visibility: Hide
2. Override the ConvertVariant
method
protected override void ConvertVariant(Item item, Item varItem, ProductVariant variant, Product product, int varNumber, ref bool skip){ base.ConvertVariant(item, varItem, variant, product, varNumber, ref skip);
// call this again, the variant image is removed in ShopifyFitmentSearchItemConverter.ConvertVariant ImageGraphQL variantImage = variant.Image ?? product.Images.FirstOrDefault()?.Image; if (variantImage is not null) { AddImages(varItem, [variantImage]); }
varItem.Add("stock", FieldValues.All); if (varItem.Get<bool>("available")) { varItem.Add("stock", FieldValues.Available); } else { varItem["out_of_stock"] = true; }
varItem["inventory_quantity"] = variant.InventoryQuantity;
if (product.TracksInventory is true && variant.InventoryQuantity is > 0 and not 9999) { varItem.Add("stock", FieldValues.InStockOnly); }}
3. Create Wheel and Tire variants (please, follow the comments)
Wheel variants
protected override void AddWheels(Item item, Product product, IList<Item> productVariants){ if (product.HasOnlyDefaultVariant) { item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Universal;
// Add wheel attributes here } else { AddWheelVariants(item, productVariants); }
if (Store.Schema.Sources.ContainsKey(WheelTireFitmentHelper.SourceName)) { item["Fitment"] = FitmentFieldValues.VehicleSpecific; }}
private void AddWheelVariants(Item item, IList<Item> productVariants){ // Add needed fields as collections to item item["wheel_diameter"] = new HashSet<string>();
List<Item> processedVariants = [];
foreach (Item variant in productVariants) { Item processedVariant = new(variant) { [WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Variant, // Add all needed item fields to the variant item ["title"] = $"{item.Get("title")} {variant.Get("title")}", ["vendor"] = item["vendor"], ["vendor_url"] = item["vendor_url"], ["published_at"] = item["published_at"], ["collection_ids"] = item["collection_ids"], ["category"] = item["category"], ["YMMText"] = item["YMMText"], [FitmentHelper.FitmentType] = new List<FitmentTypes>() { FitmentTypes.Wheel } };
// Add all variant attributes to the item string diameter = "17"; variant.Add("wheel_diameter", diameter); item.Add("wheel_diameter", diameter);
processedVariants.Add(processedVariant); }
if (processedVariants.Count > 0) { item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Product; item["product_variants"] = processedVariants; } else { item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Universal; }}
Tire variants
protected override void AddTires(Item item, Product product, IList<Item> productVariants){ if (product.HasOnlyDefaultVariant) { base.AddTires(item, product, productVariants);
item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Universal; } else { AddTireVariants(item, productVariants); }}
private void AddTireVariants(Item item, IList<Item> productVariants){ // Add needed fields as collections to item item["tire_width"] = new HashSet<string>();
List<Item> processedVariants = [];
foreach (Item variant in productVariants) { Item processedVariant = new(variant) { [WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Variant, // Add all needed item fields to the variant item ["title"] = $"{item.Get("title")} ({variant.Get("title")})", ["vendor"] = item["vendor"], ["handle"] = item["handle"], ["published_at"] = item["published_at"], ["collection_ids"] = item["collection_ids"], ["category"] = item["category"], ["YMMText"] = item["YMMText"], ["Fitment"] = item["Fitment"], [FitmentHelper.FitmentType] = new List<FitmentTypes>() { FitmentTypes.Tire } };
// Add all variant attributes to the item string width = "30"; variant.Add("tire_width", width); item.Add("tire_width", width);
processedVariants.Add(processedVariant); }
if (processedVariants.Count > 0) { item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Product; item["product_variants"] = processedVariants; } else { item[WheelTireVariantsPlugin.HierarchyField] = WheelTireVariantsPlugin.HierarchyType.Universal; }}
4. Override the GetProducts
method to add variants to the index
public override async IAsyncEnumerable<IEnumerable<Item>> GetProducts(){ await foreach (IEnumerable<Item> batch in base.GetProducts()) { List<Item> products = [];
foreach (Item item in batch) { if (item.ContainsKey("product_variants")) { products.AddRange((List<Item>)item["product_variants"]); item.Remove("product_variants"); }
products.Add(item); }
yield return products; }}
5. Use variant IDs for the Verify Fitment widget
Override the getItemId
function
const getItemId = () => { // check if the product has variants // e.g. 'body.page-type-product variant-selects' if (window.document.querySelector('PRODUCT OPTIONS SELECTOR')) { const queryString = window.location.search; const urlParams = new URLSearchParams(queryString); const variantId = urlParams.get('variant');
if (variantId) { return variantId; }
const shopifyAnalytics = window.ShopifyAnalytics; if (shopifyAnalytics && shopifyAnalytics.meta.product.variants.length > 0) { return shopifyAnalytics.meta.product.variants[0].id; } }
const shopifyAnalytics = window.ShopifyAnalytics; if (shopifyAnalytics) { return `${shopifyAnalytics.meta.product.id}`; }
console.warn('window.ShopifyAnalytics not found'); return '';};
export default { ... product: { ..., getItemId, }, ...};
Update the Verify Fitment widget on a variant selection
const InitFunc = () => { // e.g. 'body.page-type-product variant-selects input' const productOptions = window.document.querySelectorAll('OPTION INPUTS SELECTOR');
productOptions?.forEach((element) => { element.addEventListener('change', () => { setTimeout(() => { window.Convermax.updateVerifyFitmentWidget(getItemId()); }, 300); }); });};
export default { ... InitFunc, ...};