Shopify How to add meta fields to product in liquid - shopify

I am trying to figure out How to add meta fields to product in liquid
I have a product that has a list of meta fields (scents) how do I add the selected meta field to the product. I don’t want the scents to be variants.
Example on a candle product page user selects strawberry scent how does this get added to cart as candle strawberry scent?
I added meta-field list in settings.
This I what I have so far it renders the meta-fields.
{% if product.metafields.custom.scents != blank %}
<div class="product_scents">
{% for p in product.metafields.custom.scents.value %}
<div class="">{{ p }}</div>
{% endfor %}
</div>
{% endif %}
Thanks for having a look!

After further research this is how I solved my problem I loop over the meta fields and the selected meta field gets added to the cart as a line item of the product.
{% if product.metafields.custom.scents != blank %}
<div class="tw-flex tw-flex-col tw-py-12 tw-space-y-4">
<p>Select Your scent</p>
{% for p in product.metafields.custom.scents.value %}
<p class="line-item-property__field">
<input type="radio" name="properties[Scent]" value="{{ p }}"> <span>{{ p }}</span><br>
</p>
{% endfor %}
</div>
{% endif %}

Related

Shopify: Product grid - how overwrite a Product STOCK-OUT msg, with "Coming Soon" if it's in a ComingSoon collection

Our existing theme displays a 'Stock Out' banner over the product image if there is no stock.
We want to change this banner to "Coming Soon" if the Product is in a ComingSoon Collection.
The theme's 'product-grid-item.liquid file contains:
<a href="{{ product.url | within: current_collection }}" class="product-grid-item">
<div class="product-grid-image">
<div class="product-grid-image--centered">
{% if sold_out %}
<div class="badge badge--sold-out"><span class="badge-label">{{ 'products.product.sold_out' | t }}</span></div>
{% endif %}
...
Which I changed to:
<!-- added ###For Test ### -->
{% assign found_collection = false %}
{% for collection in product.collections %}
{% if collection.handle contains 'Coming Soon' %}
{% assign found_collection = true %}
{% break %}
{% endif %}
{% endfor %}
{% if found_collection %}
<div class="badge badge--sold-out"><span class="badge-label">Coming Soon</span></div>
{% else %}
<div class="badge badge--sold-out"><span class="badge-label">{{ 'products.product.sold_out' | t }}</span></div> <!-- this is the original line of code -->
{% endif %}
<!-- end of added code -->
But is doesn't work, all 'no-stock' products display with the banner "Stock out"
Nb The actual Title of the ComingSoon collection is "Coming Soon ..." - so the contains statement should work?
We could change the code to look for a Tag, but admin maintaining a tag would be more work.
Most likely this is because 'Coming Soon' is not the correct handle. A handle is part of your URL that can be found under Collection SEO inside the admin panel
e.g. store.myshopify.com/collections/my-collection -> my-collection is the handle

Can I Add Discount Code To Metafield And Include In Add To Cart Button to auto apply to checkout page?

I have created a new product metafield: product.metafields.my_fields.discount_code
In my product-template.liquid, there is this section:
<button class="btn cv_addtocart{% if section.settings.enable_payment_button %} btn--secondary{% else %} btn--primary{% endif %}" type="button" name="add" data-add-to-cart {% unless current_variant.available %}disabled="disabled"{% endunless %}>
<span data-add-to-cart-text>
{% if current_variant.available %}
{{ 'products.product.add_to_cart' | t }}
{% else %}
{{ 'products.product.sold_out' | t }}
{% endif %}
</span>
</button>
{% if section.settings.enable_payment_button %}
{{ form | payment_button }}
{% endif %}
</div>
</div>
I am trying to pass the value of a metafield for a product into the add to cart button. In this case, I want the discount code which is entered into the product metafield to be included.
So am hoping to do something like this:
{% if section.settings.enable_payment_button %}
{{ form | payment_button | discountCode = product.metafields.my_fields.discount_code }}
{% endif %}
Basically, I am trying to automatically apply a normal discount to a product at checkout. I have seen the various shareable links that append the discount code to the url, but this does not suit my needs. Instead, I would like to retrieve the discount code (DISCOUNT20) from a metafield for that product on the checkout page and apply the coupon code there.
Any thoughts? I have been stuck on this for a long time
So I have figured out a more reliable route:
I located my cart template liquid file and searched for a form
<form action="/cart" method="post" >
Directly below this line I inserted this
{%- for item in cart.items -%}
{%- if item.product.metafields.my_fields.discount_code.value != blank -%}
<input type="hidden" name="discount" value="{{item.product.metafields.my_fields.discount_code.value}}" >
{%- endif -%}
{%- endfor -%}
In my case, value = an interpolated value being retrieved from a product metafield for the product in the cart.
FYI - you need to create a metafield in settings, then create a discount code, copy the discount code, go to your product that you want the discount code to apply to, access the product and scroll down to metafields, paste the discount code in the product's discount(if you named your metafield "discount", you might have named it something else) metafield.
Hence, as the form will be submitted with a name="discount" and value="discount_code", the checkout page will evaluate to true for discount and use the appropriate values. However this is only possible with the for loop.
For such a simple fix, I am surprised it was so hard to figure out. Hope this helps you!
** Some extra reading if you want: https://wearetmbr.com/shopify-auto-fill-discount-code-on-checkout-page/ **

How to avoid calling content when two tags are partially the same in Shopify

I am currently trying to display content based on product tags that are assigned to products in Shopify.
This is working ok, but my problem is that I have two tags that contain partially the same tag name, so I am getting both sets of content appearing on the front end.
One tag shows a field that is required "r-[tag-name]" and the other shows the same field but it is not required "[tag-name]".
Obviously I know this is due to the fact that I am using 'contains' so the logic is true for both when either tag is applied, but I have tried using '==' (equals) but it when I do, nothing appears at all :/
What I would like to know is, what do I need to change so that the statement is only true if a tag exists that is exactly the same as the if statement.
I am new to Liquid so any help would be greatly appreciated!
<!--Convert the tags into a string by joining them with COMMA-->
{% assign productTags = product.tags | join: ', ' %}
<!--Now Check for the desired tag name-->
{% if productTags contains 'r-custom-name-one' %}
<p class="line-item-property__field">
<label for="name-one">Name One:</label>
<input class="required" id="name-one" type="text" name="properties[Name One]">
</p>
{% endif %}
{% if productTags contains 'custom-name-one' %}
<p class="line-item-property__field">
<label for="name-one">Name One:</label>
<input id="name-one" type="text" name="properties[Name One]">
</p>
{% endif %}
I need to change so that the statement is only true if a tag exists that is exactly the same as the if statement
This should do it:
{% for tag in product.tags %}
{% if tag == 'r-custom-name-one' %}
<p class="line-item-property__field">
<label for="name-one">Name One:</label>
<input class="required" id="name-one" type="text" name="properties[Name One]">
</p>
{% break %}
{% endif %}
{% if tag == 'custom-name-one' %}
<p class="line-item-property__field">
<label for="name-one">Name One:</label>
<input id="name-one" type="text" name="properties[Name One]">
</p>
{% break %}
{% endif %}
{% endfor %}
I added {% break %} which will
Causes the loop to stop iterating when it encounters the break tag.
I assumed that once the tag is found, you don't need need to continue looping through the rest of the tags!

Display Items in Collection that Do Not Exist In Shopping Cart Shopify

I'm trying to iterate over items in the shopping cart and generate an upsell div with products NOT in the cart. Below is the code I have so far, but I run into issues when adding two items to cart running the loop twice generating the html twice. Any ideas on how to resolve it? I'm stumped.
{% for item in cart.items %} // iterates over items in cart
{% if item.product.id == 4456879040188 %} // checks if product id matches in item in cart
<div class="upsell-pop" style="text-align:center; width: 100%;">
<h4>Frequently bought together</h4>
{% for prod in collections.upsell.products %} // iterates products in collection upsell
{% unless prod.handle contains "product-name" %} // shows only prods that do not contain url handle
<div>
<span class="upsell-title">{{ prod.title }}</span>
<span class="upsell-price">{{ prod.metafields["meta"]["promo"] }} {{ prod.price | money }}</span>
<img src="{{ prod.featured_image | img_url: '200x' }}" />
<a class="btn-product" href="{{prod.url}}">View Product</a>
</div>
{% endunless %}
{% endfor %}
</div>
{% endif %}
{% endfor %}
Another thought is to somehow check to see if product is NOT in cart items inside to replace the existing "unless" statement, but not sure how to code it.
{% unless cart.items exist then %} // I know this is not correct syntax
<div>
<span class="upsell-title">{{ prod.title }}</span>
<span class="upsell-price">{{ prod.metafields["meta"]["promo"] }} {{ prod.price | money }}</span>
<img src="{{ prod.featured_image | img_url: '200x' }}" />
<a class="btn-product" href="{{prod.url}}">View Product</a>
</div>
{% endunless %}
On my mind, there are two steps here.
First, capture your cart content to get string to compare to when you loop through your upsell collection. This could be something like that:
{%- capture cart_items -%}
{% for item in cart.items %}
{{ item.product.handle }}{% unless forloop.last %} , {% endunless %}
{% endfor %}
{%- endcapture -%}
Then loop through your collection while checking your string does not contain the handle of the current product at each iteration:
{% for product in collections['upsell'].products %}
{% unless cart_items contains product.handle %}
{{ product.title }}
{% endunless %}
{% endfor %}
Remarks:
Snippet 1 => In line_item (here called item because it's shorter to write) object you may access product object attributes: item.product.product_attr_needed
Snippet 2 => To access directly a collection object using its handle you must use collections + square brackets containing collection handle + attribute. Here 'upsell' is the handle of your upsell collection.
Not tested but this should work.
HTH

Assigning a collection to a custom created collection page in Shopify?

I am using a free Venture theme on Shopify and i am trying to make a custom collection page.
I found a solution in stackoverflow but it was able to help someplace.
How to add collection.liquid to an existing page?
The summery of the solution is:
Copy everything that's in collection.liquid and paste it into a new snippet (let's say you call it collection-copy.liquid).
Then, in the page you want to add the collections page to, just add {% include 'collection-copy' %}
This solution worked well but there is one more issue for me. In the custom created page it says "Sorry, there are no products in this collection" In the customization of the same page there is a "collection" section. But in the "collection" section there is no option to choose a collection. There is only "Enable tag filtering" and "Enable sorting" check boxes.
Webpage: https://mottomfreedom.com/pages/less-is-more
Do you have any idea of assigning a collection with this custom created snippet?
{% paginate collections[settings.frontpage_collection].products by 20 %}
<div class="page-width">
<header class="grid medium-up--grid--table section-header small--text-center">
<div class="grid__item medium-up--one-half section-header__item">
<h1 class="section-header__title">
{{ collection.title }}
{% if current_tags %}
– {% assign title_tags = current_tags | join: ', ' %}
{{ title_tags }}
{% endif %}
</h1>
{% if collection.description != blank %}
<div class="section-header__subtext rte">
{{ collection.description }}
</div>
{% endif %}
</div>
<div class="grid__item medium-up--one-half medium-up--text-right section-header__item">
{% section 'collection-filters' %}
</div>
</header>
<div class="grid grid--no-gutters grid--uniform">
{% for product in collection.products %}
<div class="grid__item small--one- medium-up--one-third">
{% include 'product-card', product: product %}
</div>
{% else %}
{% comment %}
Add default products to help with onboarding for collections/all only.
The onboarding styles and products are only loaded if the
store has no products.
{% endcomment %}
{% if shop.products_count == 0 %}
<div class="grid__item">
<div class="grid grid--no-gutters grid--uniform">
{% assign collection_index = 1 %}
{% for i in (1..10) %}
{% case i %}
{% when 7 %}
{% assign collection_index = 1 %}
{% when 8 %}
{% assign collection_index = 2 %}
{% when 9 %}
{% assign collection_index = 3 %}
{% when 10 %}
{% assign collection_index = 4 %}
{% endcase %}
<div class="grid__item small--one-half medium-up--one-fifth">
<a href="/admin/products" class="product-card">
<div class="product-card__image-container">
<div class="product-card__image-wrapper">
<div class="product-card__image">
{% capture current %}{% cycle 1, 2, 3, 4, 5, 6 %}{% endcapture %}
{{ 'product-' | append: current | placeholder_svg_tag: 'placeholder-svg' }}
</div>
</div>
</div>
<div class="product-card__info">
<div class="product-card__name">{{ 'homepage.onboarding.product_title' | t }}</div>
<div class="product-card__price">
$19.99
</div>
</div>
<div class="product-card__overlay">
{% assign view_string_length = 'products.product.view' | t | size %}
<span class="btn product-card__overlay-btn {% if view_string_length > 8 %} btn--narrow{% endif %}">{{ 'products.product.view' | t }}</span>
</div>
</a>
</div>
{% assign collection_index = collection_index | plus: 1 %}
{% endfor %}
</div>
</div>
{% else %}
{% comment %}
If collection exists but is empty, display message
{% endcomment %}
<div class="grid__item small--text-center">
<p>{{ 'collections.general.no_matches' | t }}</p>
</div>
{% endif %}
{% endfor %}
</div>
{% if paginate.pages > 1 %}
<div class="pagination">
{{ paginate | default_pagination | replace: '« Previous', '←' | replace: 'Next »', '→' }}
</div>
{% endif %}
</div>
{% endpaginate %}
You are right about giving some time before accepting an answer :)) The solution worked but forced me to create 1 page and 4 liquid files per collection. And at the end, i figured out that some sections like "collection.list" doesn't directs to the page which i have created. I think you were talking about this at the beginning of the answer :)
After that, i found a much better solution. Just creating a new section.liquid file and placing it in "collection.liquid" with an "if" statement solved my problem.
{% if collection.handle == 'less-is-more' %}
{% section 'custom-featured-products-LESSisMORE' %}
{% endif %}
But in any way, i'm grateful for your interest. Thank you very much Dave.
It looks like there's nothing defining the collection variable anywhere.
I would suggest changing the beginning of your code snippet from:
{% paginate collections[settings.frontpage_collection].products by 20 %}
To:
{% assign collection = collections[settings.frontpage_collection] %}
{% paginate collection.products by 20 %}
There is an implicit collections variable whenever you're on a page that includes /collections/[something] in the URL, but when you're on a URL that's /page/[something], you have an implicit page variable in Liquid instead.
Note: if the collection set in your theme's value for settings.frontpage_collection isn't the one you want, you can possibly:
a. Change the value using the 'Customize' link beside your theme (most easily found on the /admin/themes page), useful if you're not going to use that setting for anything else;
b. Hard-code a collection handle, eg: collections['i-am-sure-this-will-never-change'], but hard-coded strings are ugly and should generally be avoided;
c. Create your own theme setting by adding an entry to config/settings_schema.json - see https://help.shopify.com/en/themes/development/theme-editor/settings-schema if you're still getting up to speed with custom theme settings; or
d. If all your content is in a section, you can use section settings (similar to theme settings) to make a variable that's tied specifically to just that block of code.
If you need to make these special pages for multiple collections, and each of these pages is largely reusing the same code, you can make your life easier by moving the common code to a snippet and passing variables to it from your page template. To do so:
Create a file in the 'snippets' folder of your theme. (For this example, let's say the file is called collection-in-page.liquid. We will be passing a collection into this snippet, so you can remove the assign statement.
In your page-specific template, figure out what the collection handle is going to be
a. This might be hard-coded, or it might be something you could look up by using metafields or tags on the page. Examples:
{% assign collection_handle = 'hardcoded-handle' %}, {% assign collection_handle = page.metafields.related_items.collection %}
In your page template, include the snippet you created. I find it helps to explicitly pass any variables I want to use, like so:
{% include 'collection-in-page', collection: collections[collection_handle] %}
Hope this helps!