I have some problems trying to add/get custom item data when a re-order is made.
First let me explain a little bit: I am using WooCommerce as a invoice maker mostly, so one of the custom changes I had to make was to add custom percentage discount field in each product (that you can edit in cart page too), so my problem is when a re-order is made, cart items are there but the percentage discount does not affect anymore the prices, and if I try to change the percentage value, all prices are 0 (product price and product total).
Here is the code that I'm using:
// Add a custom field before single add to cart
add_action('woocommerce_before_add_to_cart_button', 'custom_product_price_field', 5);
function custom_product_price_field()
{
echo '<div class="custom-text text">
<p>Descuento %:</p>
<input type="text" id="custom_price" name="custom_price" value="" placeholder="e.g. 10" title="Custom Text" class="custom_price text_custom text">
</div>';
}
// Get custom field value, calculate new item price, save it as custom cart item data
add_filter('woocommerce_add_cart_item_data', 'add_custom_field_data', 20, 3);
function add_custom_field_data($cart_item_data, $product_id, $variation_id)
{
$product_id = $variation_id > 0 ? $variation_id : $product_id;
if (!isset($_POST['custom_price'])) {
return $cart_item_data;
}
$custom_price = (float) sanitize_text_field($_POST['custom_price']);
if ($custom_price > 40) {
wc_add_notice(__('El descuento debe ser menor a 40%'), 'error');
return $cart_item_data;
}
$product = wc_get_product($product_id); // The WC_Product Object
$price = (float) $product->get_price();
$cart_item_data['base_price'] = $price;
$cart_item_data['new_price'] = $price * (100 - $custom_price) / 100;
if($custom_price > 0 || !empty($custom_price))
$cart_item_data['percentage'] = $custom_price . "%";
return $cart_item_data;
}
// Set the new calculated cart item price
add_action('woocommerce_before_calculate_totals', 'extra_price_add_custom_price', 20, 1);
function extra_price_add_custom_price($cart)
{
if (is_admin() && !defined('DOING_AJAX')) {
return;
}
if (did_action('woocommerce_before_calculate_totals') >= 2) {
return;
}
foreach ($cart->get_cart() as $cart_item) {
if (isset($cart_item['new_price'])) {
$cart_item['data']->set_price((float) $cart_item['new_price']);
}
}
}
// Display cart item custom price details
add_filter('woocommerce_cart_item_price', 'display_cart_items_custom_price_details', 20, 3);
function display_cart_items_custom_price_details($product_price, $cart_item, $cart_item_key)
{
if (isset($cart_item['base_price'])) {
$product = $cart_item['data'];
$product_price = wc_price(wc_get_price_to_display($product, array('price' => $cart_item['base_price'])));
}
return $product_price;
}
// Add order item meta.
add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 3);
function add_order_item_meta($item_id, $cart_item, $cart_item_key)
{
if (isset($cart_item['percentage'])) {
wc_add_order_item_meta($item_id, 'percentage', $cart_item['percentage']);
}
}
This part is for edit the percentage discount in cart page:
//Custom Script Register
function discount_update_cart_scripts()
{
wp_register_script('discount-cart-script', get_stylesheet_directory_uri() . '/js/discount-cart.js', array('jquery'), time(), true);
wp_localize_script('discount-cart-script', 'discount_vars', array('ajaxurl' => admin_url('admin-ajax.php')));
wp_enqueue_script('discount-cart-script');
}
add_action('wp_enqueue_scripts', 'discount_update_cart_scripts');
//Update Discount percentage in cart item
function discount_update_cart_item()
{
if (!isset($_POST['wpnonce']) || !wp_verify_nonce($_POST['wpnonce'], 'woocommerce-cart')) {
wp_send_json(array('status' => 'error', 'message' => 'wp nonce error'));
exit;
}
$cart = WC()->cart->cart_contents;
$cart_id = $_POST['cart_id'];
$percentage = $_POST['percentage'];
if ($percentage > 40) {
wc_add_notice(__('El descuento debe ser menor a 40%'), 'notice');
wp_send_json(array('status' => 'error', 'message' => 'percentage error'));
exit;
}
wc_clear_notices();
$cart_item = $cart[$cart_id];
$cart_item['new_price'] = $cart_item['base_price'] * (100 - $percentage) / 100;
$cart_item['percentage'] = $percentage . "%";
WC()->cart->cart_contents[$cart_id] = $cart_item;
WC()->cart->set_session();
wp_send_json(array('status' => 'success'));
exit;
}
add_action('wp_ajax_discount_update_cart_item', 'discount_update_cart_item');
This is javascript code:
(function ($) {
function updateDiscountMeta(cart_id) {
$.ajax({
type: 'POST',
url: discount_vars.ajaxurl,
data: {
action: 'discount_update_cart_item',
wpnonce: $('#woocommerce-cart-nonce').val(),
percentage: $('#discount_cart_' + cart_id).val(),
cart_id: cart_id
},
success: function (response) {}
})
}
$('.discount-cart-item').on('change keyup paste', function () {
var cart_id = $(this).data('cart-id');
updateDiscountMeta(cart_id);
});
$( document.body ).on( 'updated_cart_totals', function(){
$('.discount-cart-item').on('change keyup paste', function () {
var cart_id = $(this).data('cart-id');
updateDiscountMeta(cart_id);
});
});
})(jQuery);
This is for the re-order part (where I am stuck):
add_filter( 'woocommerce_order_again_cart_item_data', 'order_again_custom', 10, 3 );
function order_again_custom($cart_item_meta, $product, $order){
//Create an array of all the missing custom field keys that needs to be added in cart item.
$customfields = [
'Titulo1',
'percentage',
'custom_price',
'price',
'new_price',
];
global $woocommerce;
remove_all_filters( 'woocommerce_add_to_cart_validation' );
if ( ! array_key_exists( 'item_meta', $cart_item_meta ) || ! is_array( $cart_item_meta['item_meta'] ) )
foreach ( $customfields as $key ){
if(!empty($product[$key])){
$cart_item_meta[$key] = $product[$key];
}
}
return $cart_item_meta;
}
function cs_add_order_again_to_my_orders_actions( $actions, $order ) {
if ( $order->has_status( 'completed' ) ) {
$actions['order-again'] = array(
'url' => wp_nonce_url( add_query_arg( 'order_again', $order->get_id() ) , 'woocommerce-order_again' ),
'name' => __( 'Order Again', 'woocommerce' )
);
}
return $actions;
}
add_filter( 'woocommerce_my_account_my_orders_actions', 'cs_add_order_again_to_my_orders_actions', 50, 2 );
code for cart page
<?php
/**
* Cart Page
*
* This template can be overridden by copying it to yourtheme/woocommerce/cart/cart.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce/Templates
* #version 3.8.0
*/
defined( 'ABSPATH' ) || exit;
do_action( 'woocommerce_before_cart' ); ?>
<form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
<?php do_action( 'woocommerce_before_cart_table' ); ?>
<table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents" cellspacing="0">
<thead>
<tr>
<th class="product-remove"> </th>
<th class="product-thumbnail"> </th>
<th class="product-name"><?php esc_html_e( 'Product', 'woocommerce' ); ?></th>
<th class="product-price"><?php esc_html_e( 'Price', 'woocommerce' ); ?></th>
<th class="product-quantity"><?php esc_html_e( 'Quantity', 'woocommerce' ); ?></th>
<th class="product-quantity"><?php esc_html_e( 'Descuento', 'woocommerce' ); ?></th>
<th class="product-subtotal"><?php esc_html_e( 'Total', 'woocommerce' ); ?></th>
</tr>
</thead>
<tbody>
<?php do_action( 'woocommerce_before_cart_contents' ); ?>
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
?>
<tr class="woocommerce-cart-form__cart-item <?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
<td class="product-remove">
<?php
echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'woocommerce_cart_item_remove_link',
sprintf(
'×',
esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
esc_html__( 'Remove this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
),
$cart_item_key
);
?>
</td>
<td class="product-thumbnail">
<?php
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
if ( ! $product_permalink ) {
echo $thumbnail; // PHPCS: XSS ok.
} else {
printf( '%s', esc_url( $product_permalink ), $thumbnail ); // PHPCS: XSS ok.
}
?>
</td>
<td class="product-name" data-title="<?php esc_attr_e( 'Product', 'woocommerce' ); ?>">
<?php
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}
do_action( 'woocommerce_after_cart_item_name', $cart_item, $cart_item_key );
// Meta data.
echo wc_get_formatted_cart_item_data( $cart_item ); // PHPCS: XSS ok.
// Backorder notification.
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_backorder_notification', '<p class="backorder_notification">' . esc_html__( 'Available on backorder', 'woocommerce' ) . '</p>', $product_id ) );
}
?>
</td>
<td class="product-price" data-title="<?php esc_attr_e( 'Price', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
?>
</td>
<td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
<?php
if ( $_product->is_sold_individually() ) {
$product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
} else {
$product_quantity = woocommerce_quantity_input(
array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->get_max_purchase_quantity(),
'min_value' => '0',
'product_name' => $_product->get_name(),
),
$_product,
false
);
}
echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
?>
</td>
<td class="product-quantity" data-title="<?php esc_attr_e( 'Discount', 'woocommerce' ); ?>">
<!--label for="discount"><?php esc_html_e( 'Discount:', 'woocommerce' ); ?></label> <input type="text" name="discount" class="input-text" id="discount_code" value="" placeholder="<?php esc_attr_e( 'dscto', 'woocommerce' ); ?>" /-->
<span>Dscto %:</span>
<input class="discount-cart-item" type="text" id="discount_cart_<?php echo $cart_item_key; ?>" class="input-text text" data-cart-id="<?php echo $cart_item_key; ?>" value="<?php echo ( isset( $cart_item[ 'percentage' ] ) ) ? substr($cart_item['percentage'], 0, -1) : ''; ?>" title="<?php esc_attr_e( 'Descuento', 'woocommerce' ); ?>" size="4" placeholder="e.g. 10">
</td>
<td class="product-subtotal" data-title="<?php esc_attr_e( 'Total', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
?>
</td>
</tr>
<?php
}
}
?>
<?php do_action( 'woocommerce_cart_contents' ); ?>
<tr>
<td colspan="6" class="actions">
<?php if ( wc_coupons_enabled() ) { ?>
<div class="coupon">
<label for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>" /> <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?></button>
<?php do_action( 'woocommerce_cart_coupon' ); ?>
</div>
<?php } ?>
<button type="submit" class="button" name="update_cart" value="<?php esc_attr_e( 'Update cart', 'woocommerce' ); ?>"><?php esc_html_e( 'Update cart', 'woocommerce' ); ?></button>
<?php do_action( 'woocommerce_cart_actions' ); ?>
<?php wp_nonce_field( 'woocommerce-cart', 'woocommerce-cart-nonce' ); ?>
</td>
</tr>
<?php do_action( 'woocommerce_after_cart_contents' ); ?>
</tbody>
</table>
<?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>
<?php do_action( 'woocommerce_before_cart_collaterals' ); ?>
<div class="cart-collaterals">
<?php
/**
* Cart collaterals hook.
*
* #hooked woocommerce_cross_sell_display
* #hooked woocommerce_cart_totals - 10
*/
do_action( 'woocommerce_cart_collaterals' );
?>
</div>
<?php do_action( 'woocommerce_after_cart' ); ?>
What I am doing wrong? Any idea?
You are not saving all the required cart item data as custom order item meta, so when using "Order again", some custom cart item data is missing ad your price calculations doesn't get applied.
Also woocommerce_add_order_item_meta hook is deprecated since WooCommerce 3.
Note: With your provided code, I am not able to change the percentage in cart page, so maybe something is missing.
You will need to remove/replace in your code the following functions:
// Add order item meta.
add_action('woocommerce_add_order_item_meta', 'add_order_item_meta', 10, 3);
function add_order_item_meta($item_id, $cart_item, $cart_item_key)
{
if (isset($cart_item['percentage'])) {
wc_add_order_item_meta($item_id, 'percentage', $cart_item['percentage']);
}
}
and this one too:
add_filter( 'woocommerce_order_again_cart_item_data', 'order_again_custom', 10, 3 );
function order_again_custom($cart_item_meta, $product, $order){
//Create an array of all the missing custom field keys that needs to be added in cart item.
$customfields = [
'Titulo1',
'percentage',
'custom_price',
'price',
'new_price',
];
global $woocommerce;
remove_all_filters( 'woocommerce_add_to_cart_validation' );
if ( ! array_key_exists( 'item_meta', $cart_item_meta ) || ! is_array( $cart_item_meta['item_meta'] ) )
foreach ( $customfields as $key ){
if(!empty($product[$key])){
$cart_item_meta[$key] = $product[$key];
}
}
return $cart_item_meta;
}
by the following ones:
// Save custom cart item data as custom order item meta data
add_action( 'woocommerce_checkout_create_order_line_item', 'add_order_item_meta', 10, 4 );
function add_order_item_meta( $item, $cart_item_key, $values, $order ) {
// Save and display the "Percentage" (optional - if needed)
if (isset($values['percentage'])) {
$item->update_meta_data( 'Percentage', $values['percentage'] );
}
// Save All custom cart item data as a hidden data array (important)
if (isset($values['percentage']) && isset($values['base_price']) && isset($values['new_price']) ) {
$custom_data = array(
'percentage' => $values['percentage'],
'base_price' => $values['base_price'],
'new_price' => $values['new_price'],
);
$item->update_meta_data( '_custom_data', $custom_data ); // save
}
}
// Add custom order item meta as custom cart item meta
add_filter( 'woocommerce_order_again_cart_item_data', 'custom_cart_item_data_for_order_again', 10, 3 );
function custom_cart_item_data_for_order_again( $cart_item_meta, $item, $order ) {
// Get the hidden order item data
$custom_data = (array) $item->get_meta( '_custom_data' );
if( ! empty($custom_data) ) {
$cart_item_meta = array_merge( $cart_item_meta, $custom_data );
}
return $cart_item_meta;
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
Related
I developing my own WooCommerce theme. I want to realize cart in popup in which all changes will show without reloading.
I already make adding to cart without reloading, but I don't know how to realize my idea about remove items. Now when I remove some item the page is reloading, but I want to remove items and save changes without page refresh.
Tell me, please, how to do it?
My php-code:
(function popup_cart_template() is default code from cart.php customized for my template)
//ajax adding items
add_filter( 'woocommerce_add_to_cart_fragments', 'cart_popup_fragment', 30, 1 );
function cart_popup_fragment( $fragments ) {
global $woocommerce;
ob_start();
popup_cart_template();
$fragments['.cart__table'] = ob_get_clean();
return $fragments;
}
//cart template function
function popup_cart_template() {
wc_get_template( 'cart/cart-popup.php' );
}
//cart-popup.php content
<table class="cart__table" cellspacing="0">
<thead>
<tr>
<td></td>
<td></td>
<td class="cart__header_quantity"><?php esc_html_e( 'QTY', 'woocommerce' ); ?></td>
<td class="cart__header_cost"><?php esc_html_e( 'Cost', 'woocommerce' ); ?></td>
</tr>
</thead>
<tbody class="cart__items">
<?php do_action( 'woocommerce_before_cart_contents' ); ?>
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
?>
<tr class="cart__item woocommerce-cart-form__cart-item <?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
<td class="cart__item_image product-thumbnail">
<?php
echo apply_filters('woocommerce_cart_item_remove_link',
sprintf('<a href="%s" class="cart__item-remove remove" aria-label="%s" data-product_id="%s" data-product_sku="%s">
X
</a>',
esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
esc_html__( 'Remove this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
),
$cart_item_key
);
<!-- and other code...:) -->
My html-code:
<section class="cart__layout popup" id="cart">
<div class="cart__body">
<div class="cart__content popup__content">
<?php do_action( 'woocommerce_before_cart_table' ); ?>
<div class="popup-close close-popup">
<img src="assets/img/popup/close-icon.png" alt="close-icon" class="popup-close__icon">
</div>
<h1 class="cart__title">
CART
</h1>
<?php popup_cart_template(); ?>
</div>
</div>
</section>
We created an additional page on our webshop for some kind of 'quotation'. On that page we'd like to load the cart. The contents of the 'quotation' is basically the same as the cart content.
We tried copying all of the WooCommerce code from the template file cart.php.
Everything is showing correctly, except for the prices. Our quotation cart is showing the basic prices that are set up in the WooCommerce back-end.
But here's our problem: When adding a product to the cart, there are additional price settings which we custom coded by using some hooks, like cart item data that's being added.
All of our custom code works perfectly fine when opening the regular WooCommerce cart, but when showing that exact Cart on another page, prices are 'reset' to the regular starting prices.
The reason we copied the code from the cart.php template file is the ability to change the structure with additional css/html.
Here you can find the shortcode & complete function of our 'quotation' cart:
<?php function toon_winkelmand_offerte() {
do_action( 'woocommerce_before_cart_table' );?>
<form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
<?php do_action( 'woocommerce_before_cart_table' ); ?>
<div class="offerte_wrapper">
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
?>
<div class="offerte_item">
<?php
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
$product_qty = $cart_item['quantity'];
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
?>
<div class="product-thumbnail">
<?php
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
if ( ! $product_permalink ) {
echo $thumbnail; // PHPCS: XSS ok.
} else {
printf( '%s', esc_url( $product_permalink ), $thumbnail ); // PHPCS: XSS ok.
}
?>
</div>
<div class="product-name" data-title="<?php esc_attr_e( 'Product', 'woocommerce' ); ?>">
<?php
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
?>
<span class="offerte_qty"><?php echo ' x ';
echo $product_qty;
?>
</span>
<?php
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
?>
<span class="offerte_qty"><?php echo ' x ';
echo $product_qty;
?>
</span>
<?php
}
do_action( 'woocommerce_after_cart_item_name', $cart_item, $cart_item_key );
echo wc_get_formatted_cart_item_data( $cart_item );
?>
<div class="product_prijs">
<?php
echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
?>
<span class="prijs_per_stuk"><?php echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key );
echo ' ';
printf(esc_html__('per stuk', 'astra-child'));
// print_r($_product);
?>
</span>
</div>
</div>
<div class="product-remove">
<?php
echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'woocommerce_cart_item_remove_link',
sprintf(
'<img src="https://kreatixlabs.be/rivanco/wp-content/uploads/2021/08/trash.png">',
esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
esc_html__( 'Remove this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
),
$cart_item_key
);
?>
</div>
<?php
}
?>
</div>
<?php
}
?>
</div>
</form>
<?php
}
add_shortcode('toon_winkelmand_offerte', 'toon_winkelmand_offerte');?>
add_action( 'wp_footer', 'bbloomer_split_cart_by_az', 9999 );
function bbloomer_split_cart_by_az(){
if ( ! is_cart() ) return;
if ( WC()->cart->is_empty() ) return;
$i = 0;
$split = array();
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$cart_item_title = $cart_item['data']->get_title();
$first_letter = substr( $cart_item_title, 0, 1 );
if ( 0 == $i || ( 0 < $i && ! in_array( $first_letter, $split ) ) ) {
if($cart_item['quantity'] == 2) {
$split[$i] = 'custom message'
}
}
$i++;
}
?>
<script type="text/javascript">
jQuery(document).ready(function($){
var indx = $('.woocommerce-cart-form__contents tbody tr').length;
var rows = <?php echo json_encode($split); ?>;
$.each(rows,function(key,value){
var newRow = $('<tr><td colspan="6">'+value+'</td></tr>');
newRow.insertBefore($('.woocommerce-cart-form__contents tbody tr.woocommerce-cart-form__cart-item:nth('+key+')'));
});
});
</script>
<?php
}
See screenshot
https://businessbloomer.com/woocommerce-split-cart-table-az-headings/ - I have used this hook,
This is showing alphabet something, but my message dynamically changed when qty changes made.
when the total cart page is refreshed message is showing properly, if u adding one qty of any product then WordPress default ajax will load to update total and etc. After that, my message is not showing. I am thinking to add any hook that will trigger after ajax loaded the new qty and cart total so that jquery will add the new tr td with my message any suggestions?
Copy this code to your active theme folder /woocommerce/cart.php. Template overriding is the best option for this.
<?php
/**
* Cart Page
*
* This template can be overridden by copying it to yourtheme/woocommerce/cart/cart.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #package WooCommerce/Templates
* #version 3.8.0
*/
defined( 'ABSPATH' ) || exit;
do_action( 'woocommerce_before_cart' ); ?>
<form class="woocommerce-cart-form" action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
<?php do_action( 'woocommerce_before_cart_table' ); ?>
<table class="shop_table shop_table_responsive cart woocommerce-cart-form__contents" cellspacing="0">
<thead>
<tr>
<th class="product-remove"> </th>
<th class="product-thumbnail"> </th>
<th class="product-name"><?php esc_html_e( 'Product', 'woocommerce' ); ?></th>
<th class="product-price"><?php esc_html_e( 'Price', 'woocommerce' ); ?></th>
<th class="product-quantity"><?php esc_html_e( 'Quantity', 'woocommerce' ); ?></th>
<th class="product-subtotal"><?php esc_html_e( 'Subtotal', 'woocommerce' ); ?></th>
</tr>
</thead>
<tbody>
<?php do_action( 'woocommerce_before_cart_contents' ); ?>
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
?>
<?php if($cart_item['quantity'] == 2): ?>
<tr><td colspan="6">custom message</td></tr>
<?php endif; ?>
<tr class="woocommerce-cart-form__cart-item <?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
<td class="product-remove">
<?php
echo apply_filters( // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
'woocommerce_cart_item_remove_link',
sprintf(
'×',
esc_url( wc_get_cart_remove_url( $cart_item_key ) ),
esc_html__( 'Remove this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
),
$cart_item_key
);
?>
</td>
<td class="product-thumbnail">
<?php
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
if ( ! $product_permalink ) {
echo $thumbnail; // PHPCS: XSS ok.
} else {
printf( '%s', esc_url( $product_permalink ), $thumbnail ); // PHPCS: XSS ok.
}
?>
</td>
<td class="product-name" data-title="<?php esc_attr_e( 'Product', 'woocommerce' ); ?>">
<?php
if ( ! $product_permalink ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', $_product->get_name(), $cart_item, $cart_item_key ) . ' ' );
} else {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_name() ), $cart_item, $cart_item_key ) );
}
do_action( 'woocommerce_after_cart_item_name', $cart_item, $cart_item_key );
// Meta data.
echo wc_get_formatted_cart_item_data( $cart_item ); // PHPCS: XSS ok.
// Backorder notification.
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
echo wp_kses_post( apply_filters( 'woocommerce_cart_item_backorder_notification', '<p class="backorder_notification">' . esc_html__( 'Available on backorder', 'woocommerce' ) . '</p>', $product_id ) );
}
?>
</td>
<td class="product-price" data-title="<?php esc_attr_e( 'Price', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
?>
</td>
<td class="product-quantity" data-title="<?php esc_attr_e( 'Quantity', 'woocommerce' ); ?>">
<?php
if ( $_product->is_sold_individually() ) {
$product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
} else {
$product_quantity = woocommerce_quantity_input(
array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->get_max_purchase_quantity(),
'min_value' => '0',
'product_name' => $_product->get_name(),
),
$_product,
false
);
}
echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item ); // PHPCS: XSS ok.
?>
</td>
<td class="product-subtotal" data-title="<?php esc_attr_e( 'Subtotal', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key ); // PHPCS: XSS ok.
?>
</td>
</tr>
<?php
}
}
?>
<?php do_action( 'woocommerce_cart_contents' ); ?>
<tr>
<td colspan="6" class="actions">
<?php if ( wc_coupons_enabled() ) { ?>
<div class="coupon">
<label for="coupon_code"><?php esc_html_e( 'Coupon:', 'woocommerce' ); ?></label> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>" /> <button type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?>"><?php esc_attr_e( 'Apply coupon', 'woocommerce' ); ?></button>
<?php do_action( 'woocommerce_cart_coupon' ); ?>
</div>
<?php } ?>
<button type="submit" class="button" name="update_cart" value="<?php esc_attr_e( 'Update cart', 'woocommerce' ); ?>"><?php esc_html_e( 'Update cart', 'woocommerce' ); ?></button>
<?php do_action( 'woocommerce_cart_actions' ); ?>
<?php wp_nonce_field( 'woocommerce-cart', 'woocommerce-cart-nonce' ); ?>
</td>
</tr>
<?php do_action( 'woocommerce_after_cart_contents' ); ?>
</tbody>
</table>
<?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>
<?php do_action( 'woocommerce_before_cart_collaterals' ); ?>
<div class="cart-collaterals">
<?php
/**
* Cart collaterals hook.
*
* #hooked woocommerce_cross_sell_display
* #hooked woocommerce_cart_totals - 10
*/
do_action( 'woocommerce_cart_collaterals' );
?>
</div>
<?php do_action( 'woocommerce_after_cart' ); ?>
I am trying to display the count of the items in the cart at the bottom or top of the Woocommerce cart widget. It seems that by default behaviour the cart widget does not do this when in the sidebar.
I have researched SO and found the following answer, but it has a slightly different goal of adding individual subtotals. I have tried modifying it, by passing in WC()->cart->get_cart_contents_count() instead of WC()->cart->get_cart() to see if I can get the cart item count, but it's not displaying...any suggestions?
Example of what I am trying to do:
Code I have modified from the approved answer:
<?php
/**
* Mini-cart
*
* Contains the markup for the mini-cart, used by the cart widget
*
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.1.0
*/
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly
?>
<?php do_action( 'woocommerce_before_mini_cart' ); ?>
<ul class="cart_list product_list_widget <?php echo $args['list_class']; ?>">
<?php if ( WC()->cart->get_cart_contents_count() ) > 0 ) : ?>
<?php
foreach ( WC()->cart->get_cart_contents_count() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_widget_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_name = apply_filters( 'woocommerce_cart_item_name', $_product->get_title(), $cart_item, $cart_item_key );
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
$product_price = apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key );
echo "<p>".$product_price."</p>";
?>
<li>
<?php if ( ! $_product->is_visible() ) { ?>
<?php echo str_replace( array( 'http:', 'https:' ), '', $thumbnail ) . $product_name; ?>
<?php } else { ?>
<a href="<?php echo get_permalink( $product_id ); ?>">
<?php echo str_replace( array( 'http:', 'https:' ), '', $thumbnail ) . $product_name; ?>
</a>
<?php } ?>
<?php echo WC()->cart->get_item_data( $cart_item ); ?>
<?php $new_product_price_array = explode ( get_woocommerce_currency_symbol(), $product_price);
$new_product_price = number_format((float)$new_product_price_array[1] * $cart_item['quantity'], 2, '.', '');
?>
<?php echo apply_filters( 'woocommerce_widget_cart_item_quantity', '<span class="quantity">' . sprintf( '%s × %s=%s%s', $cart_item['quantity'], $product_price,get_woocommerce_currency_symbol(), $new_product_price ) . '</span>', $cart_item, $cart_item_key ); ?>
</li>
<?php
}
}
?>
<?php else : ?>
<li class="empty"><?php _e( 'No products in the cart.', 'woocommerce' ); ?></li>
<?php endif; ?>
</ul><!-- end product list -->
<?php if ( WC()->cart->get_cart_contents_count() ) > 0 ) : ?>
<p class="total"><strong><?php _e( 'Subtotal', 'woocommerce' ); ?>:</strong> <?php echo WC()->cart->get_cart_subtotal(); ?></p>
<?php do_action( 'woocommerce_widget_shopping_cart_before_buttons' ); ?>
<p class="buttons">
<?php _e( 'View Cart', 'woocommerce' ); ?>
<?php _e( 'Checkout', 'woocommerce' ); ?>
</p>
<?php endif; ?>
<?php do_action( 'woocommerce_after_mini_cart' ); ?>
If you want to display the cart item count in the mini cart widget you can use hooks:
1) On top before minicart content:
add_action( 'woocommerce_before_mini_cart', 'minicart_count_after_content' );
function minicart_count_after_content() {
$items_count = WC()->cart->get_cart_contents_count();
$text_label = _n( 'Item', 'Items', $items_count, 'woocommerce' );
?>
<p class="total item-count"><strong><?php echo $text_label; ?>:</strong> <?php echo $items_count; ?></p>
<?php
}
2) On the bottom before the buttons:
add_action( 'woocommerce_widget_shopping_cart_before_buttons', 'minicart_count_before_content' );
function minicart_count_before_content() {
$items_count = WC()->cart->get_cart_contents_count();
$text_label = _n( 'Item', 'Items', $items_count, 'woocommerce' );
?>
<p class="total item-count"><strong><?php echo $text_label; ?>:</strong> <?php echo $items_count; ?></p>
<?php
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
WC()->cart->get_cart_contents_count(); will give you the total items count including quantities.
If you want to get the number of items in cart you will use instead:
$items_count = sizeof( WC()->cart->get_cart() );
You aren't echoing WC()->cart->get_cart_contents_count() anywhere, so no, it won't display.
Wherever in the code you need to display the count, you'll need to use
echo WC()->cart->get_cart_contents_count();
In WooCommerce, my products are listed in category page with details as well as "Add to Cart" button. When user clicked on the button page refreshed and on the top success message with view cart button appeared.
when a user does it for multiple times(add more than one items):
If the user is logged in the cart page listed all the items with calculation.
but if the user is not logged in, the user only see the last item listed in cart page.
I need to list the cart added products for not logged in user..Can anyone have the solution for this...
Here is my loop/add-to-cart.php code:
echo apply_filters( 'woocommerce_loop_add_to_cart_link',
sprintf( '%s',
esc_url( $product->add_to_cart_url() ),
esc_attr( $product->id ),
esc_attr( $product->get_sku() ),
esc_attr( isset( $quantity ) ? $quantity : 1 ),
$product->is_purchasable() && $product->is_in_stock() ? 'add_to_cart_button' : '',
esc_attr( $product->product_type ),
esc_html( $product->add_to_cart_text() )
),
$product );
Updated and checked the code (2)
Cart count works and cart page displays only last cart item for non logged users
1) When you are not logged in, only last cart item is displayed.
2) When you are logged in, all cart items are displayed.
This is possible editing the woocommerce cart.php template.
You will need first to copy to your active child theme (or theme) folder, the WooCommerce templates folder located in your woocommerce plugin folder (if not done yet) and rename that newly added folder woocommerce. See this related documentation.
Once done, you will open edit cart/cart.php file and replace the code by the following:
<?php
/**
* Cart Page
*
* This template can be overridden by copying it to yourtheme/woocommerce/cart/cart.php.
*
* HOWEVER, on occasion WooCommerce will need to update template files and you
* (the theme developer) will need to copy the new files to your theme to
* maintain compatibility. We try to do this as little as possible, but it does
* happen. When this occurs the version of the template file will be bumped and
* the readme will list any important changes.
*
* #see https://docs.woocommerce.com/document/template-structure/
* #author WooThemes
* #package WooCommerce/Templates
* #version 2.3.8
*/
if ( ! defined( 'ABSPATH' ) ) {
exit; // Exit if accessed directly
}
wc_print_notices();
do_action( 'woocommerce_before_cart' ); ?>
<form action="<?php echo esc_url( wc_get_cart_url() ); ?>" method="post">
<?php do_action( 'woocommerce_before_cart_table' );
// Cart count
$the_cart = WC()->cart->get_cart_contents_count();
// initialising counter for the loop (out of it)
$count = 0;
// CHECKING JUST THE CART COUNT - TO BE REMOVED
echo '<p style="font-style:italic; color: grey; margin:10px;">(Debug Info only - Cart count: <strong>'. WC()->cart->get_cart_contents_count() . '</strong> item(s))</p>';
?>
<table class="shop_table shop_table_responsive cart" cellspacing="0">
<thead>
<tr>
<th class="product-remove"> </th>
<th class="product-thumbnail"> </th>
<th class="product-name"><?php _e( 'Product', 'woocommerce' ); ?></th>
<th class="product-price"><?php _e( 'Price', 'woocommerce' ); ?></th>
<th class="product-quantity"><?php _e( 'Quantity', 'woocommerce' ); ?></th>
<th class="product-subtotal"><?php _e( 'Total', 'woocommerce' ); ?></th>
</tr>
</thead>
<tbody>
<?php do_action( 'woocommerce_before_cart_contents' ); ?>
<?php
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
$_product = apply_filters( 'woocommerce_cart_item_product', $cart_item['data'], $cart_item, $cart_item_key );
$product_id = apply_filters( 'woocommerce_cart_item_product_id', $cart_item['product_id'], $cart_item, $cart_item_key );
if( is_user_logged_in() || ( !is_user_logged_in() && $count == $cart_count) ):
// adding 1 to counter
$count++;
if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 && apply_filters( 'woocommerce_cart_item_visible', true, $cart_item, $cart_item_key ) ) {
$product_permalink = apply_filters( 'woocommerce_cart_item_permalink', $_product->is_visible() ? $_product->get_permalink( $cart_item ) : '', $cart_item, $cart_item_key );
?>
<tr class="<?php echo esc_attr( apply_filters( 'woocommerce_cart_item_class', 'cart_item', $cart_item, $cart_item_key ) ); ?>">
<td class="product-remove">
<?php
echo apply_filters( 'woocommerce_cart_item_remove_link', sprintf(
'×',
esc_url( WC()->cart->get_remove_url( $cart_item_key ) ),
__( 'Remove this item', 'woocommerce' ),
esc_attr( $product_id ),
esc_attr( $_product->get_sku() )
), $cart_item_key );
?>
</td>
<td class="product-thumbnail">
<?php
$thumbnail = apply_filters( 'woocommerce_cart_item_thumbnail', $_product->get_image(), $cart_item, $cart_item_key );
if ( ! $product_permalink ) {
echo $thumbnail;
} else {
printf( '%s', esc_url( $product_permalink ), $thumbnail );
}
?>
</td>
<td class="product-name" data-title="<?php _e( 'Product', 'woocommerce' ); ?>">
<?php
if ( ! $product_permalink ) {
echo apply_filters( 'woocommerce_cart_item_name', $_product->get_title(), $cart_item, $cart_item_key ) . ' ';
} else {
echo apply_filters( 'woocommerce_cart_item_name', sprintf( '%s', esc_url( $product_permalink ), $_product->get_title() ), $cart_item, $cart_item_key );
}
// Meta data
echo WC()->cart->get_item_data( $cart_item );
// Backorder notification
if ( $_product->backorders_require_notification() && $_product->is_on_backorder( $cart_item['quantity'] ) ) {
echo '<p class="backorder_notification">' . esc_html__( 'Available on backorder', 'woocommerce' ) . '</p>';
}
?>
</td>
<td class="product-price" data-title="<?php _e( 'Price', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_price', WC()->cart->get_product_price( $_product ), $cart_item, $cart_item_key );
?>
</td>
<td class="product-quantity" data-title="<?php _e( 'Quantity', 'woocommerce' ); ?>">
<?php
if ( $_product->is_sold_individually() ) {
$product_quantity = sprintf( '1 <input type="hidden" name="cart[%s][qty]" value="1" />', $cart_item_key );
} else {
$product_quantity = woocommerce_quantity_input( array(
'input_name' => "cart[{$cart_item_key}][qty]",
'input_value' => $cart_item['quantity'],
'max_value' => $_product->backorders_allowed() ? '' : $_product->get_stock_quantity(),
'min_value' => '0'
), $_product, false );
}
echo apply_filters( 'woocommerce_cart_item_quantity', $product_quantity, $cart_item_key, $cart_item );
?>
</td>
<td class="product-subtotal" data-title="<?php _e( 'Total', 'woocommerce' ); ?>">
<?php
echo apply_filters( 'woocommerce_cart_item_subtotal', WC()->cart->get_product_subtotal( $_product, $cart_item['quantity'] ), $cart_item, $cart_item_key );
?>
</td>
</tr>
<?php
}
endif;
}
do_action( 'woocommerce_cart_contents' );
?>
<tr>
<td colspan="6" class="actions">
<?php if ( wc_coupons_enabled() ) { ?>
<div class="coupon">
<label for="coupon_code"><?php _e( 'Coupon:', 'woocommerce' ); ?></label> <input type="text" name="coupon_code" class="input-text" id="coupon_code" value="" placeholder="<?php esc_attr_e( 'Coupon code', 'woocommerce' ); ?>" /> <input type="submit" class="button" name="apply_coupon" value="<?php esc_attr_e( 'Apply Coupon', 'woocommerce' ); ?>" />
<?php do_action( 'woocommerce_cart_coupon' ); ?>
</div>
<?php } ?>
<input type="submit" class="button" name="update_cart" value="<?php esc_attr_e( 'Update Cart', 'woocommerce' ); ?>" />
<?php do_action( 'woocommerce_cart_actions' ); ?>
<?php wp_nonce_field( 'woocommerce-cart' ); ?>
</td>
</tr>
<?php do_action( 'woocommerce_after_cart_contents' ); ?>
</tbody>
</table>
<?php do_action( 'woocommerce_after_cart_table' ); ?>
</form>
<div class="cart-collaterals">
<?php do_action( 'woocommerce_cart_collaterals' ); ?>
</div>
<?php do_action( 'woocommerce_after_cart' ); ?>
Then save.
As you will see on line 31 to 38 (outside the cat foreach loop), I have added some code to get the total cart items count and initialized a counter to zero. Also I have temporarily displayed the cart count (You can remove this line as it's only for testing).
I have add a conditional if statement that is going to do what you are expecting:
if( is_user_logged_in() || ( !is_user_logged_in() && $count == $cart_count) ):
Just after this condition I increment the $count variable (which is in the condition).
This is tested and works perfectly now…