March 11 Cart page
<?php
/*
Plugin Name: HloMart Cart
Description: HloMart Cart
Version: 1.0
Author: Bishal Thapa
*/
// hide the star rating for no rating
add_action('wp_head', function() {
$args = array(
'post_type' => 'product',
'posts_per_page' => -1,
'meta_query' => array(
array(
'key' => '_wc_review_count',
'value' => 0,
'compare' => '='
)
)
);
$query = new WP_Query($args);
if ($query->have_posts()) {
echo "<style>";
while ($query->have_posts()) {
$query->the_post();
$product_id = get_the_ID();
echo ".post-{$product_id} .star-rating { display: none !important; }";
}
echo "</style>";
}
wp_reset_postdata();
});
// If stock is limited and cart quantity more
add_action('woocommerce_before_checkout_process', 'adjust_cart_quantity_before_checkout');
function adjust_cart_quantity_before_checkout() {
// Get the cart object
$cart = WC()->cart->get_cart();
$updated = false; // Track if any changes were made
foreach ($cart as $cart_item_key => $cart_item) {
$product_id = $cart_item['product_id'];
$product = wc_get_product($product_id);
if ($product && $product->is_in_stock()) {
$stock_quantity = $product->get_stock_quantity(); // Get available stock
// If stock is limited and cart quantity exceeds stock
if (!is_null($stock_quantity) && $cart_item['quantity'] > $stock_quantity) {
WC()->cart->set_quantity($cart_item_key, $stock_quantity, true); // Set max available
$updated = true; // Mark changes
}
}
}
// Redirect to checkout after fixing cart quantity
if ($updated) {
wp_safe_redirect(wc_get_checkout_url());
exit;
}
}
// Add "Buy Now" button to the product page
add_action('woocommerce_after_add_to_cart_button', 'add_buy_now_button');
function add_buy_now_button() {
global $product;
// Check if product is in stock
if ( !$product->is_in_stock() ) {
echo '<button type="button" disabled class="button alt buy-now-button out-of-stock">Out of Stock</button>';
return;
}
// Add nonce for security
wp_nonce_field('buy_now_action', 'buy_now_nonce');
// Output the button markup
if ( $product->is_type('variable') ) {
echo '<button type="submit" name="buy_now" class="button alt buy-now-button">Buy Now</button>';
} else {
echo '<button type="submit" name="buy_now" value="1" class="button alt buy-now-button">Buy Now</button>';
}
}
// Handle "Buy Now" action and apply logic
add_action('template_redirect', 'handle_buy_now_redirect');
function handle_buy_now_redirect() {
if ( isset($_POST['buy_now']) && isset($_POST['add-to-cart']) ) {
// Verify nonce
if ( !isset($_POST['buy_now_nonce']) || !wp_verify_nonce($_POST['buy_now_nonce'], 'buy_now_action') ) {
return;
}
$product_id = intval($_POST['add-to-cart']);
$quantity = !empty($_POST['quantity']) ? intval($_POST['quantity']) : 1;
$cart = WC()->cart;
// Check if it's a variable product
if ( isset($_POST['variation_id']) && !empty($_POST['variation_id']) ) {
$variation_id = intval($_POST['variation_id']);
$variations = array();
// Collect selected variation attributes
foreach ( $_POST as $key => $value ) {
if ( strpos($key, 'attribute_') !== false ) {
$variations[$key] = wc_clean($value);
}
}
// Remove the exact same variation of the product from the cart
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] == $product_id && $cart_item['variation_id'] == $variation_id ) {
$cart->remove_cart_item($cart_item_key);
}
}
// Add the newly selected variation to the cart
$cart->add_to_cart($product_id, $quantity, $variation_id, $variations);
} else {
// For simple products, remove only if the exact same product exists
foreach ( $cart->get_cart() as $cart_item_key => $cart_item ) {
if ( $cart_item['product_id'] == $product_id ) {
$cart->remove_cart_item($cart_item_key);
}
}
$cart->add_to_cart($product_id, $quantity);
}
// Redirect to cart page
wp_safe_redirect( wc_get_cart_url() );
exit;
}
}
// For variable products, disable the Buy Now button if the selected variation is out of stock.
add_action('wp_footer', 'disable_buy_now_button_for_out_of_stock_variations');
function disable_buy_now_button_for_out_of_stock_variations() {
if ( is_product() ) { ?>
<script defer>
jQuery(document).ready(function($) {
var buyNowButton = $('.buy-now-button');
if ($('form.variations_form').length) {
buyNowButton.prop('disabled', true);
}
$('form.variations_form').on('found_variation', function(event, variation) {
buyNowButton.prop('disabled', !variation.is_in_stock);
});
$('form.variations_form').on('reset_data', function() {
buyNowButton.prop('disabled', true);
});
});
</script>
<?php }
}
/**
* Custom Cart Page, Removal, and Restoration
*
* Place this code in your theme's functions.php file or in a custom plugin.
*/
/**
* Enqueue inline CSS and JavaScript only on pages with the [custom_cart_page] shortcode.
*/
function custom_cart_page_enqueue_scripts() {
global $post;
if ( is_singular() && isset( $post->post_content ) && has_shortcode( $post->post_content, 'custom_cart_page' ) ) {
// Enqueue Custom CSS
wp_register_style( 'custom-cart-style', false );
wp_enqueue_style( 'custom-cart-style' );
$custom_css = "
/* Minified Custom Cart Page Styles */
.quantity-selector button{font-size:9px;padding:5px 10px;background-color:transparent;border:0px solid #cccc;}
.quantity-selector .quantity-input{width:70px;text-align:center;font-size:11px;padding:5px;border:0px solid #ccc;}
.remove-item{position:absolute;top:10%;left:5px;font-size:14px;color:red;background-color:#E8F2FF;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;cursor:pointer;z-index:10;}
.custom_cart_item{display:flex;justify-content:space-between;padding:2px 0;border-bottom:1px solid #ddd;align-items:center;position:relative;}
.product-info{display:flex;flex-direction:column;justify-content:center;width:100%;}
.product-name{font-weight:bold;font-size:13px;color:#333;}
.custom_cart_totals p{font-size:18px;font-weight:bold;margin-bottom:8px;color:red;text-align:center;}
.custom_cart_totals{width:100%;margin:35px auto 0 auto;background-color:#ffffff;padding:5px 10px;border-bottom:5px solid #e0e0e0;box-shadow:0 1px 5px rgba(0,0,0,0.1);z-index:1000;text-align:center;font-family:'Arial',sans-serif;font-size:14px;color:#333;line-height:1;border-radius:15px;box-sizing:border-box;}
.checkout-button.button.alt{display:inline-block;padding:15px 30px;font-size:16px;font-weight:600;text-transform:uppercase;text-align:center;color:#ffffff;background-color:#0073e6;border:none;border-radius:5px;box-shadow:0 4px 10px rgba(0,0,0,0.1);transition:all .3s ease;cursor:pointer;}
@media (min-width: 1024px){.custom_cart_totals{width:50%;margin:35px auto 0 auto;}}
";
wp_add_inline_style( 'custom-cart-style', $custom_css );
// Enqueue Custom JavaScript
wp_register_script( 'custom-cart-script', false, array( 'jquery' ), '1.0', true );
wp_enqueue_script( 'custom-cart-script' );
wp_localize_script( 'custom-cart-script', 'customCart', array(
'ajax_url' => admin_url( 'admin-ajax.php' ),
'nonce' => wp_create_nonce( 'custom_cart_nonce' )
) );
$custom_js = "
jQuery(document).ready(function($) {
var updateTimeout;
function updateSelectedTotal() {
var selectedTotal = 0;
$('.product-select:checked').each(function() {
var cartItemKey = $(this).data('cart_item_key');
var quantity = $(this).closest('.custom_cart_item').find('.quantity-input').val();
var priceText = $(this).closest('.custom_cart_item').find('.price').text();
var price = parseFloat(priceText.replace(/[^\d.-]/g, ''));
selectedTotal += price * quantity;
});
$('#selected-products-total').text(selectedTotal.toFixed(2));
}
$('.quantity-increment').on('click', function() {
var input = $(this).prev('.quantity-input');
var value = parseInt(input.val()) || 0;
input.val(value + 1);
scheduleUpdate(input);
});
$('.quantity-decrement').on('click', function() {
var input = $(this).next('.quantity-input');
var value = parseInt(input.val()) || 0;
if (value > 1) {
input.val(value - 1);
scheduleUpdate(input);
}
});
$('.quantity-input').on('input', function() {
var input = $(this);
clearTimeout(updateTimeout);
scheduleUpdate(input);
});
function scheduleUpdate(input) {
clearTimeout(updateTimeout);
updateTimeout = setTimeout(function() {
updateCart(input);
}, 600);
}
function updateCart(input) {
var key = input.data('cart_item_key');
var newQuantity = input.val();
if (newQuantity <= 0 || isNaN(newQuantity)) {
return;
}
$.ajax({
url: customCart.ajax_url,
method: 'POST',
data: {
action: 'update_cart_quantity',
cart_item_key: key,
quantity: newQuantity,
security: customCart.nonce
},
success: function(response) {
if (response.success) {
location.reload();
} else {
alert(response.data.message);
}
},
error: function() {
alert('Failed to update quantity. Please try again.');
}
});
}
$('#proceed-to-checkout').on('click', function(e) {
e.preventDefault();
var selectedItems = [];
$('.product-select:checked').each(function() {
selectedItems.push($(this).data('cart_item_key'));
});
if (selectedItems.length === 0) {
alert('Please select at least one item to proceed to checkout.');
return;
}
$.ajax({
url: customCart.ajax_url,
method: 'POST',
data: {
action: 'proceed_to_checkout',
selected_items: selectedItems,
security: customCart.nonce
},
success: function(response) {
if (response.success) {
window.location.href = '" . esc_url( wc_get_checkout_url() ) . "';
} else {
alert(response.data.message);
}
},
error: function() {
alert('Failed to proceed to checkout. Please try again.');
}
});
});
$('.remove-item').on('click', function() {
var key = $(this).data('cart_item_key');
$.ajax({
url: customCart.ajax_url,
method: 'POST',
data: {
action: 'remove_cart_item',
cart_item_key: key,
security: customCart.nonce
},
success: function(response) {
if (response.success) {
location.reload();
} else {
alert(response.data.message);
}
},
error: function() {
alert('Failed to remove item. Please try again.');
}
});
});
$('.product-select').on('change', function() {
updateSelectedTotal();
});
$('#select-all').on('change', function() {
var isChecked = $(this).prop('checked');
$('.product-select').prop('checked', isChecked);
updateSelectedTotal();
});
$('.product-select').on('change', function() {
var allSelected = $('.product-select').length === $('.product-select:checked').length;
$('#select-all').prop('checked', allSelected);
updateSelectedTotal();
});
updateSelectedTotal();
});
";
wp_add_inline_script( 'custom-cart-script', $custom_js );
}
}
add_action( 'wp_enqueue_scripts', 'custom_cart_page_enqueue_scripts' );
/**
* Custom Cart Page Shortcode with Optimized Image Loading
*/
function custom_cart_page_shortcode() {
if ( ! class_exists( 'WooCommerce' ) ) {
return '';
}
ob_start();
echo '<h2 style="text-align: center; font-size: 30px; font-weight: bold; color: #2c3e50; margin-bottom: 20px;">🛒 My Cart</h2>';
if ( WC()->cart->is_empty() ) {
echo '<p style="text-align: center; font-size: 20px; font-weight: bold; color: #2c3e50; padding: 15px; border: 1px solid #ddd; border-radius: 5px; background-color: #f8f9fa; display: inline-block;">🛒 Your cart is currently empty. Start shopping now!</p>';
echo '<div style="text-align: center; margin: 40px 0;">';
echo '<a href="' . esc_url( wc_get_page_permalink( 'shop' ) ) . '" class="button">🛍️ Return to Shop</a>';
echo '</div>';
echo '<div style="margin-top: 40px;">' . do_shortcode('[products limit="20" orderby="popularity"]') . '</div>';
echo '<div style="text-align: center; margin: 40px 0;">';
echo '<a href="' . esc_url( wc_get_page_permalink( 'shop' ) ) . '" class="button">🛍️ Return to Shop</a>';
echo '</div>';
} else {
echo '<label for="select-all">Select all</label>';
echo '<input type="checkbox" id="select-all" />';
echo '<form id="cart-selection-form">';
echo '<ul class="custom_cart_list product_list_widget">';
$selected_items = array();
$current_time = time();
$last_24_hours = $current_time - 86400;
$cart_items = array_reverse( WC()->cart->get_cart() );
foreach ( $cart_items as $cart_item_key => $cart_item ) {
$product = $cart_item['data'];
$product_name = sanitize_text_field( $product->get_name() );
$product_image = wp_get_attachment_image_src( $product->get_image_id(), 'woocommerce_thumbnail' )[0]; // Optimized image size
$price = floatval( $product->get_price() );
$quantity = intval( $cart_item['quantity'] );
if ( $product->get_stock_quantity() !== null && $quantity > $product->get_stock_quantity() ) {
$quantity = $product->get_stock_quantity();
WC()->cart->set_quantity( $cart_item_key, $quantity );
}
$total_price = $price * $quantity;
$timestamp = isset( $cart_item['timestamp'] ) ? $cart_item['timestamp'] : 0;
if ( $timestamp >= $last_24_hours ) {
$selected_items[] = $cart_item_key;
}
?>
<li class="custom_cart_item" data-cart_item_key="<?php echo esc_attr( $cart_item_key ); ?>">
<span class="remove-item" data-cart_item_key="<?php echo esc_attr( $cart_item_key ); ?>">Remove</span>
<div class="product-image-container">
<input type="checkbox" class="product-select" data-cart_item_key="<?php echo esc_attr( $cart_item_key ); ?>" <?php echo in_array( $cart_item_key, $selected_items ) ? 'checked' : ''; ?> /> Select
<a href="<?php echo esc_url( get_permalink( $product->get_id() ) ); ?>" class="product-link">
<img src="<?php echo esc_url( $product_image ); ?>"
alt="<?php echo esc_attr( $product_name ); ?>"
width="60" height="60"
loading="lazy"
style="width: 60px; height: 60px; object-fit: cover;" />
</a>
</div>
<div class="product-info">
<a href="<?php echo esc_url( get_permalink( $product->get_id() ) ); ?>" class="product-link">
<span class="product-name"><?php echo esc_html( $product_name ); ?></span>
<span class="stock-info" style="color: green; font-size: 12px;"> <?php echo esc_html( $product->get_stock_quantity() ); ?> In stock</span>
</a>
<div class="product-price" style="display: flex; align-items: center;">
<span class="price" style="color: red; margin-right: 20px;"><?php echo wc_price( $price ); ?></span>
<div class="quantity-selector" style="display: flex; align-items: left;">
<button type="button" class="quantity-decrement">➖</button>
<input type="text" class="quantity-input" data-cart_item_key="<?php echo esc_attr( $cart_item_key ); ?>" value="<?php echo esc_attr( $quantity ); ?>" />
<button type="button" class="quantity-increment">➕</button>
</div>
</div>
<div class="second-row" style="display: flex; align-items: center; margin-top: 10px;">
<span class="total-price" data-cart_item_key="<?php echo esc_attr( $cart_item_key ); ?>" style="color: red; font-weight: bold; font-size: 14px;">Total: <?php echo wc_price( $total_price ); ?></span>
</div>
</div>
</li>
<?php
}
echo '</ul>';
echo '<div class="custom_cart_totals">';
echo '<p style="color: #f08905; font-size: 10px; font-weight: 600; margin-top: 0; margin-bottom: 0; text-align: right;"><strong>Cart Total:</strong> ' . WC()->cart->get_total() . '</p>';
echo '<p><strong>Total:</strong> ' . get_woocommerce_currency_symbol() . '<span id="selected-products-total">0.00</span></p>';
echo '<button type="button" id="proceed-to-checkout" class="checkout-button button alt" style="background: #ff6110; color: white;">Proceed to Checkout 🚚</button>';
echo '</div>';
}
return ob_get_clean();
}
add_shortcode( 'custom_cart_page', 'custom_cart_page_shortcode' );
/**
* Adds a timestamp to cart item data when a product is added.
*/
function add_timestamp_to_cart_item( $cart_item_data, $product_id ) {
$cart_item_data['timestamp'] = time();
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'add_timestamp_to_cart_item', 10, 2 );
/**
* AJAX Endpoint: Remove Cart Item.
*/
function remove_cart_item() {
check_ajax_referer( 'custom_cart_nonce', 'security' );
if ( isset( $_POST['cart_item_key'] ) ) {
$cart_item_key = sanitize_text_field( $_POST['cart_item_key'] );
WC()->cart->remove_cart_item( $cart_item_key );
wp_send_json_success( array( 'cart_total' => WC()->cart->get_total() ) );
} else {
wp_send_json_error( array( 'message' => 'Invalid item key.' ) );
}
}
add_action( 'wp_ajax_remove_cart_item', 'remove_cart_item' );
add_action( 'wp_ajax_nopriv_remove_cart_item', 'remove_cart_item' );
/**
* AJAX Endpoint: Update Cart Quantity.
*/
function update_cart_quantity() {
check_ajax_referer( 'custom_cart_nonce', 'security' );
if ( isset( $_POST['cart_item_key'], $_POST['quantity'] ) ) {
$cart_item_key = sanitize_text_field( $_POST['cart_item_key'] );
$quantity = intval( $_POST['quantity'] );
if ( $quantity > 0 && WC()->cart->find_product_in_cart( $cart_item_key ) ) {
WC()->cart->set_quantity( $cart_item_key, $quantity );
wp_send_json_success( array( 'cart_total' => WC()->cart->get_total() ) );
} else {
wp_send_json_error( array( 'message' => 'Invalid quantity or cart item.' ) );
}
} else {
wp_send_json_error( array( 'message' => 'Missing parameters.' ) );
}
}
add_action( 'wp_ajax_update_cart_quantity', 'update_cart_quantity' );
add_action( 'wp_ajax_nopriv_update_cart_quantity', 'update_cart_quantity' );
/**
* AJAX Endpoint: Proceed to Checkout.
*
* This endpoint removes unselected items and stores them in the session.
*/
function proceed_to_checkout() {
check_ajax_referer( 'custom_cart_nonce', 'security' );
if ( isset( $_POST['selected_items'] ) ) {
$selected_items = array_map( 'sanitize_text_field', $_POST['selected_items'] );
$removed_items = array();
foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) {
if ( ! in_array( $cart_item_key, $selected_items ) ) {
$product = $cart_item['data'];
// Save full product data including variation details.
$removed_item = array(
'quantity' => intval( $cart_item['quantity'] ),
'sku' => $product->get_sku(),
'name' => $product->get_name(),
'price' => $product->get_price(),
'image' => wp_get_attachment_image_src( $product->get_image_id(), 'thumbnail' )[0] ?: 'path/to/fallback-image.jpg',
);
if ( $product->is_type( 'variation' ) ) {
$removed_item['product_id'] = $product->get_parent_id();
$removed_item['variation_id'] = $product->get_id();
$removed_item['variation'] = isset( $cart_item['variation'] ) ? $cart_item['variation'] : array();
} else {
$removed_item['product_id'] = $product->get_id();
$removed_item['variation_id'] = 0;
$removed_item['variation'] = array();
}
$removed_items[] = $removed_item;
WC()->cart->remove_cart_item( $cart_item_key );
}
}
WC()->session->set( 'removed_cart_items', $removed_items );
wp_send_json_success();
} else {
wp_send_json_error( array( 'message' => 'No items selected.' ) );
}
}
add_action( 'wp_ajax_proceed_to_checkout', 'proceed_to_checkout' );
add_action( 'wp_ajax_nopriv_proceed_to_checkout', 'proceed_to_checkout' );
/**
* Restore removed cart items when the cart page is visited.
*/
function restore_removed_items_to_cart() {
if ( is_cart() ) {
$removed_items = WC()->session->get( 'removed_cart_items', array() );
if ( ! empty( $removed_items ) ) {
foreach ( $removed_items as $item ) {
$product_id = $item['product_id'];
$quantity = intval( $item['quantity'] );
$variation_id = isset( $item['variation_id'] ) ? $item['variation_id'] : 0;
$variation = isset( $item['variation'] ) ? $item['variation'] : array();
if ( $variation_id ) {
WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variation );
} else {
WC()->cart->add_to_cart( $product_id, $quantity );
}
}
WC()->cart->calculate_totals();
WC()->session->set( 'removed_cart_items', array() );
}
}
}
add_action( 'template_redirect', 'restore_removed_items_to_cart' );