Shopify - How to update product price on update - shopify

I have been trying to figure out the best way to add a free product to the cart in Shopify, but can't find what I am looking for in their documentation.
What I need to do is to add a product to the cart if the cart value is £10 or more. I have managed to get the product added, but how can I change the price to zero? Also, how can I ensure that if the user selects a higher quantity of the product, they do not get multiple free items and only get one free item? Hope that makes sense.
Here is what I have so far which works really well to add the product. But not change the price.
*EDIT: I realise if I can't change the price of an item then can I apply a fixed discount code at the cart page level?
**EDIT: Come to think of it, a discount code wouldn't work anyway because the user can easily remove the free product and still get the discount. Perhaps I need to either create some kind of hidden product that can not be searched for on the store, add that to the cart and disable the quantity selector.
There must be a way to do this because there are apps that can do it.
**I do not want to use an app
<script>
$(".cart__qty-input").blur(function() {
location.reload();
})(jQuery);
</script>
{% assign product = all_products['free-gift'] %}
{% unless cart.item_count == 0 or product.empty? or product.variants.first.available == false %}
{% if cart.total_price >= 1000 %}
{% assign variant_id = product.variants.first.id %}
<script>
(function($) {
var cartItems = {{ cart.items | json }},
qtyInTheCart = 0,
cartUpdates = {};
for (var i=0; i<cartItems.length; i++) {
if ( cartItems[i].id === {{ variant_id }} ) {
qtyInTheCart = cartItems[i].quantity;
break;
}
}
if ( ( cartItems.length === 1 ) && ( qtyInTheCart > 0 ) ) {
cartUpdates = { {{ variant_id }}: 0 }
}
else if ( ( cartItems.length >= 1 ) && ( qtyInTheCart !== 1 ) ) {
cartUpdates = { {{ variant_id }}: 1 }
}
else {
return;
}
var params = {
type: 'POST',
url: '/cart/update.js',
data: { updates: cartUpdates },
dataType: 'json',
success: function(stuff) {
window.location.href = '/cart';
}
};
$.ajax(params);
})(jQuery);
</script>
{% endif %}
{% endunless %}

You can achieve that by using standard Shopify functionality.
Create a collection that contains all product except the gift one.
Create an automatic discount using the following configuration:
Type: Buy X get Y
Customer spends: Minimum purchase amount
Amount: £10
Any items for: Specific collections
Search and add the collection you created in the 1st step
Customer gets:
Quantity: 1
Any items from: Specific products
Search and add the product you want to use as a gift (the one that doesn't belong to the collection created in the 1st step)
At a discounted value: Free
Set a maximum number of uses per order: enable it and set the value to 1
The above must suit your specification.
Then you can still use the scripts you've already created to automatically add/remove the gift product to the cart based on cart total (if that's necessary). If a customer will change the quantity of the gift product to 2 or more he will get it by the standard price specified in Shopify. Only one gift item will be discounted if the cart meets the criteria.

Related

Easy way to insert/remove attribute from specific products Woocommerce

i have an e-commerce with Woocommerce and i am searching an easy way to insert and remove existing attribute from specific products.
In particular i have many products with a specific brand (scott) and once a month i want to set attribute promozione = interesse zero for all scott products and after a week remove this attribute from this porducts.
How can i do this?
Thanks
yes you can run cron and get all products by get_posts or wp query and insert attribute like wp_insert_term( 'red', 'pa_colors' ); with conditions and then you can get products and remove product attribute as per condition
$product_attributes = get_post_meta( $product->id , '_product_attributes' );
$temp_product_attributes = [];
foreach($product_attributes as $product_attribute) {
foreach($product_attribute as $pt_k => $pt_v) {
if ($pt_k !== $attribute_name) {
$temp_product_attributes[$pt_k] = $pt_v;
}
}
}
update_post_meta( get_the_ID(), '_product_attributes', $temp_product_attributes);

Make a condition from array

I need your help, i tried many attempts without success, from my php controller i have following array :
$products = array(
'name' => 'shirt'
array(
'attribues' => array(
array("code" => "1", "label"=>"xs"),
array("code" => "2-", "label"=>"small"),
...
)
)
....
);
In product categories page, where i list all products i have following twig for an product item :
{% for product in products %}
<div>{{ product.name }}</div>
{% endfor %}
Here the aim it to able to filter by products attributes keys so i think something like this, the "product_tab" is a value from a tab where i click :
{% for product in products %}
<div v-if="[{{product.attributes|keys|join(',')}}].includes(selected_code)">{{ product.name }}</div>
{% endfor %}
The tab list :
<div data-tab="1" :click="show_products">xs</div>
<div data-tab="2-" :click="show_products">small</div>
// the vuejs part
const app = {
data() {
selected_code:"1"
},
methods:{
show_products:function(e){
this.selected_code = e.currentTarget.getAttribute("data-tab")
}
}
}
But i get error in console, vuejs as Uncaught SyntaxError: Unexpected token ',' and it brokes the page rendering. I know that the error is because of this line :
v-if="[{{product.attributes|keys|join('"','"')}}].includes(selected_code)"
But i don't know how to make this working, when i dump products.attributes|keys|join like below :
dump(product.attributes|keys|join('"','"'));
it outputs :
"["1-","18-total=0.5","81-"]"
You notice the double quotes around, I'm stumped and I can't find what to do to make this page work.

Shopify: How to check if there is > 1 collection in a cart

I am trying to prevent orders with more than one collection from being checked out. If there's more than one collection, i just want to disable the checkout button. I know the syntax is bad, but i want to do something like this.
{% for item in cart.collections %}
{% if item.collection.length > 1 %}
<button disabled>Cant checkout</button>
{% else %}
<button disabled>Can checkout</button>
{% endif %}
This is the current code for the button
<div class="cart__checkout-wrapper">
<button disabled id="button" type="submit" name="checkout" data-terms-required="{{ settings.cart_terms_conditions_enable }}" class="btn cart__checkout">
{{ 'cart.general.checkout' | t }}
</button>
{% if additional_checkout_buttons and settings.cart_additional_buttons %}
<div class="additional-checkout-buttons additional-checkout-buttons--vertical">{{ content_for_additional_checkout_buttons }}</div>
{% endif %}
</div>
{% endfor %}
Method 1
This simple check might work for what you need:
{% liquid
assign all_collections_in_cart = cart.items | map: 'product' | map: 'collections' | map: 'title' | uniq
assign collection_count = all_collections_in_cart.size
if collection_count > 1
assign can_checkout = false
else
assign can_checkout = true
endif
%}
What it does
First, we use a sequence of map filters to 'drill down' through the object structure. Items in the cart do not themselves belong to any specific collection(s), but each item is associated with both a variant and a product. From the product, we can then get all of the collections that it belongs to, which will be an array of collection objects. We can't do much with the objects themselves, so we drill down one layer further to get something that can be compared, such as title handle or id. At this point we now have an array of text entries (or numbers, if you swap to IDs), so we can apply the uniq filter to remove any duplicates.
Now that we have an array with no duplicates, we can check the size of the array to see if it is greater than one and set a variable appropriately.
Note that this will always return false if a single product belongs to more than one collection!
Method 2:
If instead you need to test that all products share a collection because products can belong to more than one at a time, we won't be able to take as many shortcuts. Instead, our code might look something like this:
{% liquid
assign can_checkout = true
if cart.items.size > 1
assign shared_collections = cart.items.first.product.collections | map: 'title'
for item in cart.items
if forloop.first
continue
endif
assign item_collections = item.product.collections | map: title
assign placeholder_array = ''
for coll in shared_collections
if item_collections contains coll
if placeholder_array.size > 0
assign placeholder_array = placeholder_array | append: ','
endif
assign placeholder_array = placeholder_array | append: coll
endif
endfor
assign shared_collections = placeholder_array | split: ','
if shared_collections.size == 0
assign can_checkout = false
break
endif
endfor
endif
%}
What it does
This second version will trigger if there are 2 or more items in the cart. If there are, we get all of the collection titles from the first item in the cart, then loop through all of the remaining items in the cart. At each step, we go through our list of shared collections to see how many are shared with the current item in the cart to make a new array. (Liquid does not let us make an array directly, so we have to build out a delimited string and then use the split filter afterwards)
If at any time we have an array with 0 shared entries, we set our can_checkout variable to false and use the break command to stop searching.
Addendum
For both of the above methods, things might get a little bit trickier if you have certain collections that don't count towards your collection rules. For example, if you have 'featured' or 'summer sale' collections, you will want to make sure that you aren't counting those in the collection comparisons (for example, by having an array of exceptions and removing those items from the array of collections that the item belongs to).

How to get the total of sales for each product, aggregation of foreignkey

I am working on a small django project. In my models.py I have a Product class like:
class Product(models.Model):
...
And I have a Sales class like:
class Sales(models.Model):
item = models.ForeignKey(Product)
quantity = models.IntegerField()
I want to display a list of all my products with the total of sales for each product...
I hope my question is clear.
Thanks
You can group by the product using values then aggregate to get the total price.
#assumption
class Product(models.Model):
price = models.DecimalField(...)
...
Sales.objects.values('item').annotate(total=Sum(F('quantity') * F('item__price')))
# provide more infomation if you want to loop in template
Sales.objects.values('item').annotate(
price_sum = Sum(F('quantity') * F('item__price')),
quantity_sum = Sum('quantity'),
product_name = F('item__name')
)
template
{% for sale in sales %}
{{ sale.product_name }}
{{ sale.quantity_sum }}
{{ sale.price_sum }}
{% endfor %}

How to group menu by Alphabet in shopify?

How to group menu by Alphabet in shopify?
I want to group dropdown menu like this.
I am new to shopify, I tried to group menu by trying to get the first letter using this code
{% assign first_letter = {{ link_primary.title | slice: 0 }} %}
but it is giving me following error
Liquid syntax error: Unexpected character { in "{{{{ link_primary.title | slice: 0 }} }}"
You don't actually need the {{ }} around the link title.
You can assign the first letter like:
{% assign first_letter = link_primary.title | slice: 0 %}
Then just check whether it's within a certain range, for example A-D, E-H etc.