Ajaxify header cart items count in Woocommerce - php

I'm creating a custom woocommerce integrated theme for wordpress.
I have a blob on the top that displays the total number of items in the cart, I want to update this blob using Jquery (w/o reloading the page) I was able to increase the number of items by getting the current number in the blob and increasing it by +1 for each click, the problem is the add to cart has an option to select the number of items you want to add to the cart. So if I select 3 items and click the button the blob only increases by one.
I can create a way to get the number of items being added from the front-end but I think it's unnecessary. I want to be able to get the total number from PHP sessions using jquery so that on every click of add item or remove item I'll get the current number dynamically from the server.
What I have done so far is to create a reloadCart.php file that echos the cart total, here's the code
<?php
require('../../../wp-blog-header.php');
global $woocommerce;
echo $woocommerce->cart->get_cart_contents_count();
?>
When I visit this page it echos the current item totals, but I cant get this data from jquery, it's been sometime since I last used AJAX also I have not worked on web projects for a very long time, but with what I remember, the AJAX call that I'm making is right.
I have tried using the get() and post() functions of jquery as well as the normal ajax() function, but nothing seems to work. Can someone please help?
$(".ajax_add_to_cart").click(function () {
/*$("#bag-total").html(function () {
var bagTotal = parseInt($(this).html());
return ++bagTotal;
});*/
alert('clicked');
$.get("<?php echo get_template_directory_uri(); ?>/reloadCart.php", function(data){
alert("Data: " + data);
});
});
The lines that are commented are the ones that I was using previously, to add the cart total by getting the current cart number from the front-end.
Any help would be appreciated. Thanks in advance!

You should not use any reload to update the cart content count… Instead you should use the dedicated woocommerce_add_to_cart_fragments action hook that is Ajax powered.
1) The HTML to be refreshed: So first in your theme's header.php file you should need to embed the cart count in a specific html tag with a defined unique ID (or a class), for example something like:
$items_count = WC()->cart->get_cart_contents_count();
?>
<div id="mini-cart-count"><?php echo $items_count ? $items_count : ' '; ?></div>
<?php
or:
$items_count = WC()->cart->get_cart_contents_count();
echo '<div id="mini-cart-count"><?php echo $items_count ? $items_count : ' '; ?></div>';
2) The code:
add_filter( 'woocommerce_add_to_cart_fragments', 'wc_refresh_mini_cart_count');
function wc_refresh_mini_cart_count($fragments){
ob_start();
$items_count = WC()->cart->get_cart_contents_count();
?>
<div id="mini-cart-count"><?php echo $items_count ? $items_count : ' '; ?></div>
<?php
$fragments['#mini-cart-count'] = ob_get_clean();
return $fragments;
}
if you use a class in your html Tag, you will replace ['#mini-cart-count'] by ['.mini-cart-count']. This hook is also used to refresh the mini-cart content.
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
Since few years global $woocommerce; + $woocommerce->cart is outdated and replaced by WC()->cart to access WooCommerce cart object.
If you need jQuery to force refresh that count, you can try wc_fragment_refresh or wc_fragments_refreshed delegated events, like:
$(document.body).trigger('wc_fragment_refresh');
or:
$(document.body).trigger('wc_fragments_refreshed');

For anyone who wants the proper ajax implementation, here is the way to go.
in functions.php
add_action('wp_ajax_cart_count_retriever', 'cart_count_retriever');
add_action('wp_ajax_nopriv_cart_count_retriever', 'cart_count_retriever');
function cart_count_retriever() {
global $wpdb;
echo WC()->cart->get_cart_contents_count();
wp_die();
}
in your script file (assuming you have enqued the script file and passed the ajax object into the script. you also need to put this block into a setInterval or in some other jquery action.
var data = {
'action': 'cart_count_retriever'
};
jQuery.post(ajax_object.ajax_url, data, function(response) {
alert('Got this from the server: ' + response);
});

In header.php or where you want to show count
<?php $items_count = WC()->cart->get_cart_contents_count();
echo $items_count; //use this function for print the value of cart items count
?>

I have not used woocommerce before but one pretty simple option when you say in your post:
When I visit this page it echos the current item totals, but I cant get this data from JQuery
...would be to use a user-sided JavaScript variable for the display, and then just call the PHP update methods for adding items to your cart using AJAX (which I do not show below because you have not provided that code).
<?php
//hardcoded value for $woocommerce->cart->get_cart_contents_count()
$woocommerce = 59;
?>
<button class="ajax_add_to_cart">Add to cart</button>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<script>
$(document).ready(function(){
//user sided variable for PHP value
var total = parseInt($(".totalCost").text());
$(".ajax_add_to_cart").click(function(){
total++; //add to cart
$(".totalCost").text(total); //update
});
});
</script>
<p class="totalCost">
<?php echo json_encode($woocommerce); ?>
</p>
You can copy and test this snippet on: http://phpfiddle.org/
Basically in the above code, I set the PHP value as a paragraph text on page load and then read that value into a JS variable to mess around with the data on the client side of the application and then I update the display text as needed.

function woocommerce_header_add_to_cart_fragment( $fragments ) {
$fragments['li.cart-open'] = '<li class="cart-open"><a href="javascript:void(0)" class="cart" title="Cart">
<svg xmlns="http://www.w3.org/2000/svg" width="96" height="96" viewBox="0 0 96 96" class="svg-large"><switch><g><path d="M68 24v-4C68 8.954 59.046 0 48 0S28 8.954 28 20v4H12v60c0 6.63 5.37 12 12 12h48c6.63 0 12-5.37 12-12V24H68zm-32-4c0-6.627 5.373-12 12-12s12 5.373 12 12v4H36v-4zm40 64c0 2.21-1.79 4-4 4H24c-2.21 0-4-1.79-4-4V32h56v52z"/></g></switch></svg>
<i>'.WC()->cart->get_cart_contents_count().'</i>
</a></li>';
return $fragments;
}

Related

Disable Add To Cart on Variation Change Using contains() function in jQuery

I need to Blur ( remove functionality ) of the Add to Cart button globally for product variations which are Out of stock so assume the jQuery contains() function is the best bet but can't get this code to work.
I've tried checking using the outOfStock but can't get it to work.
If the product contains the text Out of stock when the variation option is toggled, i need to prevent the add to cart button from working.
add_action('wp_footer', 'outofstock_product_variation_js');
function outofstock_product_variation_js() {
?>
<script type="text/javascript">
jQuery(function($) {
var addToCartButtonObj = $('.add-to-cart-button');
var outOfStock = $("p.stock.in-stock:contains('Out of stock')");
$('form.variations_form').on('show_variation', function(event, data) {
if ( ! data.is_in_stock ) {
addToCartButtonObj.hide();
} else if ( data.is_in_stock ) {
addToCartButtonObj.show();
}
})
});
</script>
<?php
}
Here's the HTML when the out of stock variation is selected
<div class="woocommerce-variation-availability"><p class="stock in-stock">Out of stock</p>
</div>
The behavior you explained is strange because WooCommerce by default assigns the disabled attribute to a add to cart button of a product that is out of stock.
It is also a bad practice to add <script> tags directly in a function passed to a hook in WordPress, as it can lead to various issues such as conflicts with other scripts, syntax errors, and security vulnerabilities.
That said, my advice is to add something like this vanilla JavaScript code using this plugin https://wordpress.org/plugins/insert-headers-and-footers/
<script>
window.onpageshow => {
const addToCart = document.querySelector('.outofstock button')
if (addToCart) {
addToCart.setAttribute('disabled', '')
}
}
</script>
WooCommerce provides the outofstock class which you can use to select the add to cart button. After that, you can simply use the setAttribute function to disable the button.

Wordpress Get value of hidden input field in functions.php

I have a hidden input field, which I want to fetch in my functions.php, but I keep getting NULL as a return value.
Here is my code:
add_filter('woocommerce_add_cart_item_data', 'add_custom_field_data_to_cart', 10, 2 );
function add_custom_field_data_to_cart($cart_item_data, $product_id, $variation_id) {
$cart_item_data['myHiddenInput'] = $_POST['myHiddenInput'];
return $cart_item_data;
}
Can someone maybe tell me why I get NULL ?
EDIT
The hidden input field is on my archive-products.php of my woocommerce-shop
<input type="hidden" name="myHiddenInput" value="">
The value gets set by using javascript
UPDATE
What I want to achive is, that I have an archive-products page where all my products are listed. Now, above my products I have a tab-menu with the next 5 days of the week. So I click the tab "Wednesday 19." the value of the hidden input gets the date of the active menu-tab:
<input type="hidden" name="chosenDate" value="2018-09-19">
Now I add a product to my cart. Then I click the menu-tab "Friday 21." - the value of the hidden filed gets updated -> I add a product to the cart.
Now when I go to my cart page - I want the products to have the dates listed when they will get delivered (the dates from the menu-tab when they were added)
as #LoicTheAztec Said
You can't pass anything custom from any archive page via ajax add to cart button as if you look to the source code of Ajax add to cart… There is no possible additional arguments or hooks. So you will need to build your own Ajax add to cart functionality, which is something huge and complicated. So your hooked function woocommerce_add_cart_item_data will have no effect
so the best logic is to use Javascript to achieve your goal and you can do it like the below solution:
First Lets add those value inside the add to cart button as an attribute instead of input tag.
for that we are going to us woocommerce_loop_add_to_cart_args hook as follow:
add_filter( 'woocommerce_loop_add_to_cart_args', 'change_item_price', 10, 2 );
function change_item_price( $args, $product ) {
$args['attributes'] = $args['attributes'] + [ 'data-chosen-date' => '2018-09-19' ];
return $args;
}
you can add as many attribute as you want and modify the value through your script and then store those value when the user click add to cart intro session storage and then in the cart page you can get those values and append them to cart table so for example:
add_action( 'wp_footer', 'script' );
function script() {
if ( is_shop() ) {?>
<script>
document.body.addEventListener('click', add_to_cart);
function add_to_cart(e) {
if (e.target.classList.contains('add_to_cart_button')) {
let val = e.target.getAttribute('data-chosen-date');
let product_id = e.target.getAttribute('data-product_id');
sessionStorage.setItem(product_id, val);
}
}
</script>
<?php
}
if ( is_cart() ) {
?>
<script>
var items = document.querySelectorAll("td");
items.forEach(function (item, index) {
if (item.classList.contains('product-remove')) {
var id = item.childNodes[1].getAttribute('data-product_id');
if (sessionStorage.getItem(id)) {
var textnode = document.createElement('p');
textnode.innerHTML = sessionStorage.getItem(id);
item.nextElementSibling.nextElementSibling.appendChild(textnode)
}
}
}); </script>
<?php
}
}
output :
The Date after the item link in the cart table has been retrieved from our storage session and each value we stored is maped with the product id as key in our storage session so we can have different value for each product.

Show WooCommerce cart count outside of Wordpress

I have a full website that I've built already. I have now installed Wordpress in a subdirectory (/shop) and I'm using WooCommerce to power the sale of products.
In the top menu bar while in the shop page I have a cart icon showing the number of products in the cart.
I would like that when the user clicks back into the non-Wordpress pages of the site to continue showing the number of items in the cart. Can someone point me in the right direction? I have tried to include the main class-woocommerce.php class but it's not working.
Here's what I have been using to test in my index.php file:
include 'shop/wp-content/plugins/woocommerce/includes/class-woocommerce.php';
global $woocommerce;
var_dump($woocommerce->cart);
EDIT:
I have now included wp-load.php instead of the class-woocommerce.php and when I dump the WooCommerce cart I can see it but it's completely empty, ie has 0 items even though I had items placed in the cart.
Update:
This could be done also setting a custom cookie or better using javascript session storage this way:
add_action('wp_footer', 'custom_cart_item_count_script');
function custom_cart_item_count_script(){
if( WC()->cart->is_empty() )
$cart_count = 0;
else
$cart_count = WC()->cart->get_cart_contents_count();
if(isset($cart_count)){
?>
<script type="text/javascript">
jQuery(function($){
var cartCount = <?php echo $cart_count; ?>,
csName = 'CARTCOUNT',
csStorage = sessionStorage.getItem(csName);
if(csStorage == null || csStorage == 'undefined'){
sessionStorage.setItem(csName, cartCount);
console.log(sessionStorage.getItem(csName));
}
});
</script>
<?php
}
}
This code goes in function.php file of your active child theme (or active theme).
Tested and works.
On your non Wordpress pages:
You will need to get this browser session storage value. so you will add something like the following in your non Wordpress pages:
?>
<script type="text/javascript">
jQuery(function($){
var caName = 'CARTCOUNT',
caStorage = sessionStorage.getItem(caName);
if(caStorage == null || caStorage == 'undefined')
$('span.cart-count').html('0');
else
$('span.cart-count').html(caStorage);
console.log('css-read: '+caStorage);
});
</script>
<p>Cart count: <span class="cart-count"></span></p>
<?php
Tested and works:

Creating Coupon counter click

I am trying to create a coupon click counter.
I received the default number of clicks using the code
<?php $couponusers = get_field('coupon_users'); ?>
And I displayed the default number of clicks using the code,
<p><?php echo $couponusers ?></p>
Now, I want to increase the value of ‘coupon_users’ whenever a click is made. Any suggestions on how to do this?
The page I need help with: https://deals.onlinerockershub.com/bluehost-web-hosting/
Add this action to your functions.php
function coupon_callback() {
//
// Add here cookie check
//
if(is_page('1')){ // ID of "Thank you for coupon click" page
update_field('coupon_users',$couponusers); // or similar
}
return;
}
add_filter( 'wp', 'coupon_callback' );

Hide php code if?

What I want to do is really simple but I'm obviously not great and very new to PHP. I'm using woocommerce for my store and a woocommerce add on called "woocommerce scheduler" to set a start and end time specific products are for sale each day.
The way the scheduling program works is you set start and end times with 24hr clock example 10am (10:00) to 8pm (20:00) the product can be purchased anytime from 8am-10pm after 10pm the plugin "hides" the add to cart button ans displays a custom message such as "Currently Unavailable" and you can't purchase the item.
I ran into 2 problems one of which is solved
I wanted the plugin to show the start time the product would become available with the unavailable message basically it would say "unavailable until 8am"
So the solution to that problem was a plugin called Advanced Custom Fields
and creating a custom field that I can set on the product page and then I can display by putting this php code if the feild is empty on another product page it isn't displayed <?php if( get_field('product_time') ): ?>
<p>Available at <?php the_field('product_time'); ?></p>
<?php endif; ?>
into my single product page template file.
I got that working just fine. Now my second issue that I can't solve.
I want to hide the code that shows the time when the unavailable message is hidden because the product is in the hours where it is available for purchase. So how would I go about this?
I found the bit of code that pulls the unavailable message but it is a js. file so I cant put the php I have into that file.
wdm_validate.js
jQuery(document).ready(function(){
jQuery('.cart').html('<p class = "wdm_message3">'+wdm_message.wdm_expiration_message+' </p>');
});
this is the bit in the php file for the scheduler plugin that calls that js file
woocommerce_scheduler.php
if($wdm_start_date <= $d && $d<=$wdm_end_date && $str_start_time <=
$curtime && $curtime <= $str_end_time) {
}else{
//echo "<style>.cart{display:none;}</style>";
//echo "hello";
//exit;
wp_enqueue_script('wdm_expiration_message',plugins_url('js/wdm_validate.js',__FILE__),
array('jquery'));
$data = array(
'wdm_expiration_message' => get_option( 'woocommerce_custom_product_expiration',true )
);
wp_localize_script('wdm_expiration_message','wdm_message',$data);
}
In your custom code just add class to <p> tag and perform following:-
<?php if( get_field('product_time') ): ?>
<p class='wdm_available'>Available at <?php the_field('product_time'); ?></p>
<script>
jQuery(document).ready(function(){
//checking wdm_message3 i.e. expiration message exist or not
if(!jQuery('.wdm_message3').is(':visible')){
jQuery('.wdm_available').hide();
}
});
</script>
<?php endif; ?>
adding this code to my price.php template page in woocommerce got me exactly what I needed. The time is hidden when the product is available and shows when the item is not available for sale letting my customer know what time they can purchase it.
<?php if( get_field('product_time') ): ?>
<p class='wdm_available'>Unavailable Until <?php the_field('product_time'); ?></p>
<script>
jQuery(document).ready(function(){
// set a timeout function to get around brief delay in scheduler script
setTimeout(function(){
//check if scheduler message is NOT visible
if(!jQuery('.wdm_message3').is(':visible')) {
// if not, hide custom availabilty time message
jQuery('.wdm_available').hide();
}
}, 0);
});
</script>
<?php endif; ?>
There's no way for me to know the format of your custom field, but you should be able to run a comparison against the current time. As an idea:
$current_time = time();
$sale_time = get_field('product_time');
if( $sale_time && $sale_time < $current_time ): ?>
<p class='wdm_available'>Unavailable Until <?php the_field('product_time'); ?></p>
<?php endif; ?>

Categories