WooCommerce – Custom discount based on Pickup/Delivery not working properly

1 week ago 5
ARTICLE AD BOX

enter image description here

Hi everyone,

I’m working on a WooCommerce website, and I’ve added custom functionality in the checkout page.

What I’m trying to do:

If the user selects Pickup, they should get a discounted price.

If the user selects Delivery, it should show the normal price.

I’ve already written the code, and the functionality is working, but I’m facing a problem:

Even when the user selects Pickup, the discount works correctly. But when the user switches to Delivery, the discount still applies, and the amount keeps being reduced, even though it should return to the normal price.

Basically, no matter what option I click (Pickup or Delivery), the discount is always being subtracted.

Has anyone faced this issue before? Can someone please guide me on how to fix this?

Any help would be appreciated 🙏

If anyone would like to check my code, kindly DM me.

<

/** * Plugin Name: WooCommerce Pickup Category Discount * Description: Gives discount on selected categories when Pickup is chosen. Shows in emails. * Version: 2.8 * Author: Dev * License: GPL v2 or later * Text Domain: wpd-pickup-discount */ // Prevent direct access if ( ! defined( 'ABSPATH' ) ) { exit; } // ============================== // REGISTER SETTINGS // ============================== add_action( 'admin_init', 'wpd_register_settings' ); function wpd_register_settings() { register_setting( 'wpd_settings_group', 'wpd_categories', [ 'type' => 'array', 'sanitize_callback' => 'wpd_sanitize_categories', 'default' => [], ] ); register_setting( 'wpd_settings_group', 'wpd_discount', [ 'type' => 'float', 'sanitize_callback' => 'wpd_sanitize_discount', 'default' => 4.0, ] ); register_setting( 'wpd_settings_group', 'wpd_label', [ 'type' => 'string', 'sanitize_callback' => 'sanitize_text_field', 'default' => 'Pickup Discount', ] ); // Optional settings register_setting( 'wpd_settings_group', 'wpd_max_discount', [ 'type' => 'float', 'sanitize_callback' => 'wpd_sanitize_discount', 'default' => 0, ] ); register_setting( 'wpd_settings_group', 'wpd_debug_mode', [ 'type' => 'boolean', 'sanitize_callback' => 'absint', 'default' => 0, ] ); // New: Show discount notice in cart register_setting( 'wpd_settings_group', 'wpd_show_cart_notice', [ 'type' => 'boolean', 'sanitize_callback' => 'absint', 'default' => 1, ] ); } // ============================== // SANITIZATION FUNCTIONS // ============================== function wpd_sanitize_categories( $input ) { if ( ! is_array( $input ) ) { return []; } return array_map( 'absint', $input ); } function wpd_sanitize_discount( $input ) { $float = floatval( $input ); return max( 0, $float ); // Ensure non-negative } // ============================== // SETTINGS PAGE // ============================== add_action( 'admin_menu', 'wpd_settings_page' ); function wpd_settings_page() { add_submenu_page( 'woocommerce', __( 'Pickup Discount Settings', 'wpd-pickup-discount' ), __( 'Pickup Discount', 'wpd-pickup-discount' ), 'manage_options', 'wpd-discount', 'wpd_settings_html' ); } function wpd_settings_html() { // Capability check if ( ! current_user_can( 'manage_options' ) ) { wp_die( __( 'You do not have sufficient permissions to access this page.', 'wpd-pickup-discount' ) ); } // Nonce for security wp_nonce_field( 'wpd_settings_action', 'wpd_settings_nonce' ); ?> <div class="wrap"> <h1><?php _e( 'Pickup Category Discount Settings', 'wpd-pickup-discount' ); ?></h1> <div class="notice notice-info"> <p> <strong><?php _e( 'How it works:', 'wpd-pickup-discount' ); ?></strong> <?php _e( 'When customers select "Local Pickup" shipping method, products from the selected categories will receive the specified discount per item. Discount shows in cart totals and order emails.', 'wpd-pickup-discount' ); ?> </p> </div> <form method="post" action="options.php"> <?php settings_fields( 'wpd_settings_group' ); ?> <table class="form-table"> <!-- CATEGORY SELECT --> <tr> <th scope="row"> <label for="wpd_categories"><?php _e( 'Select Categories', 'wpd-pickup-discount' ); ?></label> </th> <td> <?php $saved_cats = (array) get_option( 'wpd_categories', [] ); $categories = get_terms( [ 'taxonomy' => 'product_cat', 'hide_empty' => false, 'orderby' => 'name', 'order' => 'ASC', ] ); if ( ! empty( $categories ) && ! is_wp_error( $categories ) ) : ?> <select name="wpd_categories[]" id="wpd_categories" multiple style="width:300px; min-height:200px;"> <?php foreach ( $categories as $cat ) : ?> <option value="<?php echo esc_attr( $cat->term_id ); ?>" <?php selected( in_array( $cat->term_id, $saved_cats, true ) ); ?>> <?php echo esc_html( $cat->name ); ?> </option> <?php endforeach; ?> </select> <p class="description"> <?php _e( 'Hold CTRL (Windows) or CMD (Mac) to choose multiple categories.', 'wpd-pickup-discount' ); ?> </p> <?php else : ?> <p><?php _e( 'No product categories found.', 'wpd-pickup-discount' ); ?></p> <?php endif; ?> </td> </tr> <!-- DISCOUNT AMOUNT --> <tr> <th scope="row"> <label for="wpd_discount"><?php _e( 'Discount Amount (CHF)', 'wpd-pickup-discount' ); ?></label> </th> <td> <input type="number" name="wpd_discount" id="wpd_discount" value="<?php echo esc_attr( get_option( 'wpd_discount', 4 ) ); ?>" min="0" step="0.01" required> <p class="description"> <?php _e( 'Discount amount per item in selected categories.', 'wpd-pickup-discount' ); ?> </p> </td> </tr> <!-- MAXIMUM DISCOUNT --> <tr> <th scope="row"> <label for="wpd_max_discount"><?php _e( 'Maximum Total Discount (CHF)', 'wpd-pickup-discount' ); ?></label> </th> <td> <input type="number" name="wpd_max_discount" id="wpd_max_discount" value="<?php echo esc_attr( get_option( 'wpd_max_discount', 0 ) ); ?>" min="0" step="0.01"> <p class="description"> <?php _e( 'Set to 0 for unlimited discount. Maximum discount that can be applied to the entire cart.', 'wpd-pickup-discount' ); ?> </p> </td> </tr> <!-- DISCOUNT LABEL --> <tr> <th scope="row"> <label for="wpd_label"><?php _e( 'Discount Label', 'wpd-pickup-discount' ); ?></label> </th> <td> <input type="text" name="wpd_label" id="wpd_label" value="<?php echo esc_attr( get_option( 'wpd_label', 'Pickup Discount' ) ); ?>" style="width:300px;" required> <p class="description"> <?php _e( 'This text will appear in the cart/checkout summary and emails.', 'wpd-pickup-discount' ); ?> </p> </td> </tr> <!-- SHOW CART NOTICE --> <tr> <th scope="row"> <label for="wpd_show_cart_notice"><?php _e( 'Show Discount Notice in Cart', 'wpd-pickup-discount' ); ?></label> </th> <td> <label> <input type="checkbox" name="wpd_show_cart_notice" id="wpd_show_cart_notice" value="1" <?php checked( get_option( 'wpd_show_cart_notice' ), 1 ); ?>> <?php _e( 'Display a notice in cart when discount is applied.', 'wpd-pickup-discount' ); ?> </label> </td> </tr> <!-- DEBUG MODE --> <tr> <th scope="row"> <label for="wpd_debug_mode"><?php _e( 'Debug Mode', 'wpd-pickup-discount' ); ?></label> </th> <td> <label> <input type="checkbox" name="wpd_debug_mode" id="wpd_debug_mode" value="1" <?php checked( get_option( 'wpd_debug_mode' ), 1 ); ?>> <?php _e( 'Enable debug logging', 'wpd-pickup-discount' ); ?> </label> <p class="description"> <?php _e( 'Log discount calculations to error log for troubleshooting.', 'wpd-pickup-discount' ); ?> </p> </td> </tr> </table> <?php submit_button( __( 'Save Settings', 'wpd-pickup-discount' ) ); ?> </form> </div> <?php } // ============================== // SETTINGS LINK IN PLUGINS PAGE // ============================== add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), 'wpd_add_settings_link' ); function wpd_add_settings_link( $links ) { $settings_link = sprintf( '<a href="%s">%s</a>', esc_url( admin_url( 'admin.php?page=wpd-discount' ) ), __( 'Settings', 'wpd-pickup-discount' ) ); array_unshift( $links, $settings_link ); return $links; } // ============================== // DETECT IF PICKUP IS SELECTED (IMPROVED VERSION) // ============================== function wpd_is_pickup_selected() { $debug_mode = get_option( 'wpd_debug_mode', 0 ); // METHOD 1: Check if cart/checkout exists if ( ! isset( WC()->session ) || is_null( WC()->session ) ) { if ( $debug_mode ) { error_log( 'WPD Debug: WC session not available' ); } return false; } // METHOD 2: Check chosen shipping methods $chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); if ( empty( $chosen_methods ) || ! is_array( $chosen_methods ) ) { if ( $debug_mode ) { error_log( 'WPD Debug: No shipping methods chosen' ); } return false; } $method = $chosen_methods[0] ?? ''; if ( $debug_mode ) { error_log( 'WPD Debug: Checking shipping method: ' . $method ); error_log( 'WPD Debug: All chosen methods: ' . print_r( $chosen_methods, true ) ); } // STRICTER PICKUP DETECTION - EXACT MATCHES ONLY $is_pickup = false; // Check for exact pickup method IDs $pickup_identifiers = [ 'local_pickup', 'local_pickup:', // With instance ID 'pickup', 'pickup:', // With instance ID 'abholung', 'abholung:', // With instance ID 'selbstabholung', 'selbstabholung:', // With instance ID 'pickup_at_store', 'pickup_at_store:' // With instance ID ]; foreach ( $pickup_identifiers as $identifier ) { if ( strpos( $method, $identifier ) === 0 ) { // Check if method starts with identifier $is_pickup = true; break; } } // Also check if method contains "pickup" (case-insensitive) if ( ! $is_pickup && stripos( $method, 'pickup' ) !== false ) { $is_pickup = true; } // Exclude delivery methods if ( stripos( $method, 'delivery' ) !== false || stripos( $method, 'versand' ) !== false || stripos( $method, 'shipping' ) !== false || stripos( $method, 'flat_rate' ) !== false || stripos( $method, 'free_shipping' ) !== false ) { $is_pickup = false; } if ( $debug_mode ) { error_log( 'WPD Debug: Final pickup determination - ' . ( $is_pickup ? 'YES' : 'NO' ) ); } return $is_pickup; } // ============================== // ADDITIONAL DEBUGGING FUNCTION // ============================== add_action( 'wp_footer', 'wpd_display_shipping_debug' ); function wpd_display_shipping_debug() { // Only show if debug mode is on and user is admin if ( ! get_option( 'wpd_debug_mode', 0 ) || ! current_user_can( 'manage_options' ) ) { return; } if ( ! function_exists( 'WC' ) || ! isset( WC()->session ) ) { return; } $chosen_methods = WC()->session->get( 'chosen_shipping_methods' ); $is_pickup = wpd_is_pickup_selected(); ?> <div style="position:fixed; bottom:10px; right:10px; background:#f0f0f0; padding:10px; border:1px solid #ccc; z-index:9999; font-size:12px; max-width:300px;"> <strong>WPD Debug Info (Admin Only):</strong><br> Shipping Method: <?php echo esc_html( print_r( $chosen_methods, true ) ); ?><br> Is Pickup: <?php echo $is_pickup ? 'YES' : 'NO'; ?><br> Session Discount: <?php echo WC()->session->get( 'wpd_discount_amount', 0 ); ?> </div> <?php } // ============================== // MAIN DISCOUNT LOGIC (ONLY ONE FUNCTION) // ============================== add_action( 'woocommerce_cart_calculate_fees', 'wpd_apply_pickup_discount', 20, 1 ); function wpd_apply_pickup_discount( $cart ) { // Prevent execution in admin (unless doing AJAX) if ( is_admin() && ! defined( 'DOING_AJAX' ) ) { return; } // Don't run during certain AJAX calls if ( defined( 'DOING_AJAX' ) && isset( $_REQUEST['action'] ) ) { $action = sanitize_text_field( $_REQUEST['action'] ); $allowed_actions = array( 'woocommerce_update_shipping_method', 'woocommerce_update_order_review', 'update_order_review', 'wc_blocks_checkout_update_shipping_method' ); if ( ! in_array( $action, $allowed_actions ) ) { return; } } if ( $cart->is_empty() ) { return; } // Get settings $cats = (array) get_option( 'wpd_categories', [] ); $discount = floatval( get_option( 'wpd_discount', 4 ) ); $max_discount = floatval( get_option( 'wpd_max_discount', 0 ) ); $label = get_option( 'wpd_label', 'Pickup Discount' ); $debug_mode = get_option( 'wpd_debug_mode', 0 ); $show_notice = get_option( 'wpd_show_cart_notice', 1 ); // Check if pickup is selected - USING STRICT DETECTION $is_pickup = wpd_is_pickup_selected(); if ( $debug_mode ) { error_log( 'WPD Debug: Is pickup selected? ' . ( $is_pickup ? 'YES' : 'NO' ) ); error_log( 'WPD Debug: Selected categories: ' . print_r( $cats, true ) ); error_log( 'WPD Debug: Discount per item: ' . $discount ); } // STRICT CHECK: Only apply if pickup is selected if ( ! $is_pickup ) { // Remove any existing discount with our label $fees = $cart->get_fees(); foreach ( $fees as $fee_key => $fee ) { if ( $fee->name === $label ) { $cart->remove_fee( $fee_key ); if ( $debug_mode ) { error_log( 'WPD Debug: Removed discount fee (not pickup)' ); } } } // Clear session data WC()->session->__unset( 'wpd_discount_amount' ); WC()->session->__unset( 'wpd_discount_applied' ); WC()->session->__unset( 'wpd_notice_shown' ); WC()->session->__unset( 'wpd_discounted_items' ); if ( $debug_mode ) { error_log( 'WPD Debug: No pickup selected - clearing all session data' ); } return; // EXIT EARLY - NO DISCOUNT FOR NON-PICKUP } // If no categories selected, no discount if ( empty( $cats ) ) { if ( $debug_mode ) { error_log( 'WPD Debug: No categories selected for discount' ); } return; } // Calculate discount for each item $total_discount = 0; $discounted_items = []; foreach ( $cart->get_cart() as $item_key => $item ) { $product_id = $item['product_id']; $quantity = $item['quantity']; $product = $item['data']; // Check if product is in selected categories if ( has_term( $cats, 'product_cat', $product_id ) ) { $item_discount = $discount * $quantity; $total_discount += $item_discount; $discounted_items[] = [ 'product_id' => $product_id, 'name' => $product->get_name(), 'quantity' => $quantity, 'discount' => $item_discount ]; if ( $debug_mode ) { error_log( sprintf( 'WPD Debug: Product "%s" (ID %d) qualifies for discount. Quantity: %d, Added: %f CHF', $product->get_name(), $product_id, $quantity, $item_discount ) ); } } } // Apply maximum discount limit if set if ( $max_discount > 0 && $total_discount > $max_discount ) { if ( $debug_mode ) { error_log( sprintf( 'WPD Debug: Discount capped from %f CHF to %f CHF', $total_discount, $max_discount ) ); } $total_discount = $max_discount; } // Store discount amount in session for emails if ( $total_discount > 0 ) { // First, remove any existing discount with the same label to avoid duplicates $fees = $cart->get_fees(); foreach ( $fees as $fee_key => $fee ) { if ( $fee->name === $label ) { $cart->remove_fee( $fee_key ); if ( $debug_mode ) { error_log( 'WPD Debug: Removed duplicate fee with label: ' . $label ); } } } // Apply discount $cart->add_fee( $label, -$total_discount, false ); WC()->session->set( 'wpd_discount_amount', $total_discount ); WC()->session->set( 'wpd_discount_applied', true ); WC()->session->set( 'wpd_discounted_items', $discounted_items ); if ( $debug_mode ) { error_log( sprintf( 'WPD Debug: Applied discount of %f CHF with label: %s', $total_discount, $label ) ); error_log( 'WPD Debug: Discounted items: ' . print_r( $discounted_items, true ) ); } // Frontend notice if enabled (only show once per session to avoid duplicates) if ( $show_notice && ! is_admin() && ! WC()->session->get( 'wpd_notice_shown' ) ) { wc_add_notice( sprintf( __( '%s: -%s CHF applied for pickup!', 'wpd-pickup-discount' ), $label, wc_price( $total_discount ) ), 'success' ); WC()->session->set( 'wpd_notice_shown', true ); if ( $debug_mode ) { error_log( 'WPD Debug: Displayed notice in cart' ); } } } else { // No discount to apply WC()->session->__unset( 'wpd_discount_amount' ); WC()->session->__unset( 'wpd_discount_applied' ); WC()->session->__unset( 'wpd_discounted_items' ); if ( $debug_mode ) { error_log( 'WPD Debug: No discount applied (total discount was 0 or no qualifying items)' ); } } } // ============================== // Clear notice flag when cart is updated // ============================== add_action( 'woocommerce_update_cart_action_cart_updated', 'wpd_clear_notice_flag' ); add_action( 'woocommerce_checkout_update_order_review', 'wpd_clear_notice_flag' ); function wpd_clear_notice_flag() { WC()->session->__unset( 'wpd_notice_shown' ); if ( get_option( 'wpd_debug_mode', 0 ) ) { error_log( 'WPD Debug: Cleared notice flag' ); } } // ============================== // Recalculate fees when shipping is changed // ============================== add_action( 'woocommerce_checkout_update_order_review', 'wpd_update_shipping_method', 10, 1 ); function wpd_update_shipping_method( $post_data ) { // Parse the posted data parse_str( $post_data, $posted ); $debug_mode = get_option( 'wpd_debug_mode', 0 ); if ( isset( $posted['shipping_method'] ) ) { WC()->session->set( 'chosen_shipping_methods', (array) $posted['shipping_method'] ); if ( $debug_mode ) { error_log( 'WPD Debug: Updated shipping methods in session: ' . print_r( (array) $posted['shipping_method'], true ) ); } } } // ============================== // EMAIL INTEGRATION: Add discount to order emails // ============================== add_action( 'woocommerce_email_order_meta', 'wpd_add_discount_to_emails', 20, 3 ); function wpd_add_discount_to_emails( $order, $sent_to_admin, $plain_text ) { // Get discount from order meta $discount_amount = $order->get_meta( '_wpd_discount_amount', true ); if ( $discount_amount > 0 ) { $label = $order->get_meta( '_wpd_discount_label', true ); if ( empty( $label ) ) { $label = get_option( 'wpd_label', 'Pickup Discount' ); } if ( $plain_text ) { echo sprintf( __( '%s: -%s', 'wpd-pickup-discount' ), $label, wc_price( $discount_amount ) ) . "\n"; } else { echo '<p><strong>' . $label . ':</strong> ' . wc_price( -$discount_amount ) . '</p>'; } } } // ============================== // Save discount to order meta for emails // ============================== add_action( 'woocommerce_checkout_create_order', 'wpd_save_discount_to_order', 10, 1 ); function wpd_save_discount_to_order( $order ) { $discount_amount = WC()->session->get( 'wpd_discount_amount', 0 ); if ( $discount_amount > 0 ) { $order->update_meta_data( '_wpd_discount_amount', $discount_amount ); $label = get_option( 'wpd_label', 'Pickup Discount' ); $order->update_meta_data( '_wpd_discount_label', $label ); if ( get_option( 'wpd_debug_mode', 0 ) ) { error_log( 'WPD Debug: Saved discount to order meta - Amount: ' . $discount_amount . ', Label: ' . $label ); } } } // ============================== // Display discount in order details (frontend) // ============================== add_action( 'woocommerce_order_details_after_order_table', 'wpd_display_discount_in_order_details', 10, 1 ); function wpd_display_discount_in_order_details( $order ) { $discount_amount = $order->get_meta( '_wpd_discount_amount', true ); if ( $discount_amount > 0 ) { $label = $order->get_meta( '_wpd_discount_label', true ); if ( empty( $label ) ) { $label = get_option( 'wpd_label', 'Pickup Discount' ); } echo '<tr class="wpd-pickup-discount">'; echo '<th>' . esc_html( $label ) . '</th>'; echo '<td>' . wc_price( -$discount_amount ) . '</td>'; echo '</tr>'; } } // ============================== // LOAD TEXT DOMAIN (FOR TRANSLATIONS) // ============================== add_action( 'plugins_loaded', 'wpd_load_textdomain' ); function wpd_load_textdomain() { load_plugin_textdomain( 'wpd-pickup-discount', false, dirname( plugin_basename( __FILE__ ) ) . '/languages/' ); } // ============================== // CLEANUP ON DEACTIVATION // ============================== register_deactivation_hook( __FILE__, 'wpd_deactivation_cleanup' ); function wpd_deactivation_cleanup() { // Clear session data if ( isset( WC()->session ) ) { WC()->session->__unset( 'wpd_discount_amount' ); WC()->session->__unset( 'wpd_discount_applied' ); WC()->session->__unset( 'wpd_notice_shown' ); WC()->session->__unset( 'wpd_discounted_items' ); } }

>

Read Entire Article