JezK
Edit File: advaxe-checkout.php
<?php /** * Plugin Name: Advaxe Mobile App Cart & Checkout * Description: Fully customizes Cart and Checkout with App UI. Features: Field Editor, AJAX Cart/Checkout Updates, Dynamic Color Options. * Version: 12.6 * Author: Advaxe */ if ( ! defined( 'ABSPATH' ) ) exit; // ============================================================================= // PART 1: ADMIN SETTINGS (FIELD EDITOR WITH DRAG & DROP & COLOR PICKER) // ============================================================================= add_action('admin_menu', 'advx_register_admin_page'); function advx_register_admin_page() { add_menu_page( 'Checkout Editor', 'Advaxe Checkout', 'manage_options', 'advx-checkout-editor', 'advx_render_settings_page', 'dashicons-cart', 50 ); } // Load Scripts for Drag & Drop add_action('admin_enqueue_scripts', 'advx_admin_scripts'); function advx_admin_scripts($hook) { if ($hook != 'toplevel_page_advx-checkout-editor') return; wp_enqueue_script('jquery-ui-sortable'); wp_enqueue_style( 'wp-color-picker' ); wp_enqueue_script( 'wp-color-picker' ); } function advx_render_settings_page() { // Save Settings if ( isset($_POST['advx_save_fields']) && check_admin_referer('advx_save_fields_nonce') ) { // Save Color Setting if ( isset($_POST['advx_ui_color']) ) { update_option('advx_ui_primary_color', sanitize_hex_color($_POST['advx_ui_color'])); } // Save Field Settings $data = array(); if ( ! empty($_POST['fields']) ) { foreach ($_POST['fields'] as $key => $values) { $data[$key] = array( 'label' => sanitize_text_field($values['label']), 'placeholder' => sanitize_text_field($values['placeholder']), 'required' => isset($values['required']) ? 1 : 0, 'enabled' => isset($values['enabled']) ? 1 : 0, 'minlength' => intval($values['minlength']), 'maxlength' => intval($values['maxlength']) ); } update_option('advx_checkout_fields_settings', $data); } echo '<div class="notice notice-success is-dismissible"><p>Settings, Color & Field Order Saved Successfully!</p></div>'; } $all_fields_default = array( 'billing_first_name' => 'First Name', 'billing_last_name' => 'Last Name', 'billing_company' => 'Company Name', 'billing_country' => 'Country / Region', 'billing_address_1' => 'Street Address', 'billing_address_2' => 'Apartment/Unit', 'billing_city' => 'City', 'billing_state' => 'State/District', 'billing_postcode' => 'Postcode/ZIP', 'billing_phone' => 'Phone', 'billing_email' => 'Email Address' ); $saved_settings = get_option('advx_checkout_fields_settings', array()); $primary_color = get_option('advx_ui_primary_color', '#008060'); $render_list = array(); if( !empty($saved_settings) ) { foreach($saved_settings as $key => $val) { if( array_key_exists($key, $all_fields_default) ) { $render_list[$key] = $all_fields_default[$key]; } } } foreach($all_fields_default as $key => $label) { if( !array_key_exists($key, $render_list) ) { $render_list[$key] = $label; } } ?> <div class="wrap"> <h1>Advaxe Checkout Settings</h1> <form method="post"> <?php wp_nonce_field('advx_save_fields_nonce'); ?> <!-- Color Picker Section --> <div style="background:#fff; padding:20px; border-left:4px solid <?php echo esc_attr($primary_color); ?>; margin:20px 0; box-shadow:0 1px 3px rgba(0,0,0,.05); border-radius:4px;"> <h3 style="margin-top: 0;">App UI Color</h3> <label for="advx_ui_color" style="font-weight:600; font-size:14px; margin-right:15px; display:inline-block; vertical-align:middle;">Primary Color:</label> <input type="color" id="advx_ui_color" name="advx_ui_color" value="<?php echo esc_attr($primary_color); ?>" style="vertical-align:middle; cursor:pointer; width: 50px; height: 35px; border: 1px solid #ccc; padding: 2px;"> <p class="description">This color will be applied to buttons, links, icons, and highlights throughout the cart and checkout process.</p> </div> <!-- Fields Editor Section --> <p>Drag and drop rows using the <span class="dashicons dashicons-menu"></span> icon to reorder fields.</p> <table class="wp-list-table widefat fixed striped"> <thead> <tr> <th style="width: 30px;"></th> <th>Field ID</th> <th style="width: 50px;">Show</th> <th style="width: 50px;">Req</th> <th>Label</th> <th>Placeholder</th> <th style="width: 70px;">Min Digits</th> <th style="width: 70px;">Max Digits</th> </tr> </thead> <tbody id="advx-sortable-rows"> <?php foreach ($render_list as $key => $name) : $val = isset($saved_settings[$key]) ? $saved_settings[$key] : array(); $is_enabled = isset($val['enabled']) ? $val['enabled'] : 1; $is_required = isset($val['required']) ? $val['required'] : 1; $label = isset($val['label']) ? $val['label'] : $name; $placeholder = isset($val['placeholder']) ? $val['placeholder'] : ''; $minlength = isset($val['minlength']) && $val['minlength'] > 0 ? $val['minlength'] : ''; $maxlength = isset($val['maxlength']) && $val['maxlength'] > 0 ? $val['maxlength'] : ''; ?> <tr class="ui-state-default"> <td style="cursor: move; color:#888;"><span class="dashicons dashicons-menu"></span></td> <td><strong><?php echo $key; ?></strong></td> <td><input type="checkbox" name="fields[<?php echo $key; ?>][enabled]" value="1" <?php checked($is_enabled, 1); ?>></td> <td><input type="checkbox" name="fields[<?php echo $key; ?>][required]" value="1" <?php checked($is_required, 1); ?>></td> <td><input type="text" name="fields[<?php echo $key; ?>][label]" value="<?php echo esc_attr($label); ?>" style="width:100%"></td> <td><input type="text" name="fields[<?php echo $key; ?>][placeholder]" value="<?php echo esc_attr($placeholder); ?>" style="width:100%"></td> <td><input type="number" name="fields[<?php echo $key; ?>][minlength]" value="<?php echo esc_attr($minlength); ?>" style="width:60px;"></td> <td><input type="number" name="fields[<?php echo $key; ?>][maxlength]" value="<?php echo esc_attr($maxlength); ?>" style="width:60px;"></td> </tr> <?php endforeach; ?> </tbody> </table> <br> <input type="submit" name="advx_save_fields" class="button button-primary" value="Save Changes"> </form> </div> <script> jQuery(document).ready(function($) { $("#advx-sortable-rows").sortable({ placeholder: "ui-state-highlight", axis: "y", containment: "parent", handle: ".dashicons-menu", cursor: "move" }); }); </script> <style>.ui-state-highlight { height: 50px; background: #f0f0f1; border: 1px dashed #ccc; }</style> <?php } // ============================================================================= // FIX: APPLY SETTINGS TO CHECKOUT (FIXED "PLEASE ENTER ADDRESS" ERROR) // ============================================================================= add_filter( 'woocommerce_default_address_fields', 'advx_apply_settings_to_default_fields', 9999 ); function advx_apply_settings_to_default_fields( $fields ) { $settings = get_option('advx_checkout_fields_settings'); if ( empty($settings) ) return $fields; foreach ( $settings as $key => $val ) { $field_id = str_replace('billing_', '', $key); if ( array_key_exists($field_id, $fields) ) { if ( isset($val['enabled']) && $val['enabled'] == 0 ) { unset($fields[$field_id]); } elseif ( isset($val['required']) ) { $fields[$field_id]['required'] = ($val['required'] == 1); } } } return $fields; } add_filter( 'woocommerce_checkout_fields' , 'advx_apply_custom_checkout_fields', 9999 ); function advx_apply_custom_checkout_fields( $fields ) { $settings = get_option('advx_checkout_fields_settings'); if ( empty($settings) ) return $fields; $new_billing_fields = array(); $priority_counter = 10; foreach ( $settings as $key => $val ) { if ( isset($fields['billing'][$key]) ) { if ( isset($val['enabled']) && $val['enabled'] == 0 ) { unset($fields['billing'][$key]); continue; } $field_data = $fields['billing'][$key]; if ( ! empty($val['label']) ) $field_data['label'] = $val['label']; if ( ! empty($val['placeholder']) ) $field_data['placeholder'] = $val['placeholder']; if ( isset($val['required']) && $val['required'] == 1 ) { $field_data['required'] = true; } else { $field_data['required'] = false; } if ( ! isset($field_data['custom_attributes']) ) $field_data['custom_attributes'] = array(); if ( ! empty($val['minlength']) && intval($val['minlength']) > 0 ) $field_data['custom_attributes']['minlength'] = intval($val['minlength']); if ( ! empty($val['maxlength']) && intval($val['maxlength']) > 0 ) $field_data['custom_attributes']['maxlength'] = intval($val['maxlength']); $field_data['priority'] = $priority_counter; $priority_counter += 10; $new_billing_fields[$key] = $field_data; } } foreach($fields['billing'] as $key => $field_data) { if( !array_key_exists($key, $new_billing_fields) ) { if ( array_key_exists($key, $settings) && isset($settings[$key]['enabled']) && $settings[$key]['enabled'] == 0 ) { continue; } $field_data['priority'] = $priority_counter; $new_billing_fields[$key] = $field_data; $priority_counter += 10; } } $fields['billing'] = $new_billing_fields; return $fields; } // ============================================================================= // 0. HELPER FUNCTIONS TO RENDER LISTS (FOR AJAX & INITIAL) // ============================================================================= function advx_get_items_html_cart_mode() { ob_start(); ?> <div class="advx-card"> <h4>Your Cart</h4> <?php if( WC()->cart->is_empty() ): ?> <p>Your cart is currently empty.</p> <?php else: ?> <?php foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { $_product = $cart_item['data']; if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 ) { $max_qty = $_product->get_max_purchase_quantity(); ?> <div class="advx-item"> <a href="#" class="advx-remove-btn" data-cart-key="<?php echo $cart_item_key; ?>">×</a> <div class="advx-thumb"><?php echo $_product->get_image(); ?></div> <div class="advx-details"> <div class="advx-title"><?php echo $_product->get_name(); ?></div> <div class="advx-meta"><?php echo wc_get_formatted_cart_item_data( $cart_item ); ?></div> <div class="advx-price"><?php echo WC()->cart->get_product_price( $_product ); ?></div> </div> <div class="advx-qty"> <button class="advx-qty-btn minus" type="button">-</button> <input type="number" class="qty" data-cart-key="<?php echo $cart_item_key; ?>" value="<?php echo $cart_item['quantity']; ?>" max="<?php echo ($max_qty > 0) ? $max_qty : -1; ?>" readonly /> <button class="advx-qty-btn plus" type="button">+</button> </div> </div> <?php } } ?> <?php endif; ?> </div> <?php return ob_get_clean(); } function advx_get_totals_html_cart_mode() { ob_start(); ?> <div class="advx-card"> <h4>Order Summary</h4> <table class="shop_table"> <tr class="cart-subtotal"> <th>Subtotal</th> <td data-title="Subtotal" style="text-align:right; font-weight:bold; color:var(--advx-primary);"> <?php wc_cart_totals_subtotal_html(); ?> </td> </tr> </table> <p style="font-size:12px; color:#666; margin-top:10px; margin-bottom:0;"> Shipping, taxes, and discounts calculated at checkout. </p> </div> <a href="<?php echo esc_url( wc_get_checkout_url() ); ?>" class="advx-btn-main">Proceed to Checkout</a> <?php return ob_get_clean(); } function advx_get_items_html_checkout_mode() { ob_start(); ?> <div class="advx-card"> <div style="display:flex; justify-content:space-between; align-items:center; border-bottom:1px solid #eee; padding-bottom:10px; margin-bottom:15px;"> <h4 style="border:none; margin:0; padding:0;">Order Items</h4> <a href="<?php echo wc_get_cart_url(); ?>" style="font-size:12px; color:var(--advx-primary); text-decoration:none; font-weight:600;">Edit</a> </div> <?php foreach ( WC()->cart->get_cart() as $cart_item_key => $cart_item ) { $_product = $cart_item['data']; if ( $_product && $_product->exists() && $cart_item['quantity'] > 0 ) { $max_qty = $_product->get_max_purchase_quantity(); ?> <div class="advx-item"> <a href="#" class="advx-remove-btn" data-cart-key="<?php echo $cart_item_key; ?>">×</a> <div class="advx-thumb"><?php echo $_product->get_image(); ?></div> <div class="advx-details"> <div class="advx-title"><?php echo $_product->get_name(); ?></div> <div class="advx-meta"><?php echo wc_get_formatted_cart_item_data( $cart_item ); ?></div> <div class="advx-price"><?php echo WC()->cart->get_product_price( $_product ); ?></div> </div> <div class="advx-qty compact"> <button class="advx-qty-btn minus" type="button">-</button> <input type="number" class="qty" data-cart-key="<?php echo $cart_item_key; ?>" value="<?php echo $cart_item['quantity']; ?>" min="1" max="<?php echo ($max_qty > 0) ? $max_qty : -1; ?>" readonly /> <button class="advx-qty-btn plus" type="button">+</button> </div> </div> <?php } } ?> </div> <?php return ob_get_clean(); } // ============================================================================= // 1. AJAX HANDLER (CORE LOGIC) // ============================================================================= add_action('wp_ajax_advx_update_qty', 'advx_update_qty'); add_action('wp_ajax_nopriv_advx_update_qty', 'advx_update_qty'); function advx_update_qty() { if ( ! isset($_POST['cart_key']) || ! isset($_POST['qty']) ) { wp_send_json_error('Missing data'); } $cart_item_key = sanitize_text_field($_POST['cart_key']); $quantity = intval($_POST['qty']); $context = isset($_POST['context']) ? sanitize_text_field($_POST['context']) : 'cart'; $cart = WC()->cart; if( $cart_item = $cart->get_cart_item( $cart_item_key ) ) { if ( $quantity > 0 ) { $cart->set_quantity( $cart_item_key, $quantity, true ); } else { $cart->remove_cart_item( $cart_item_key ); } $cart->calculate_totals(); $response = array(); if ( $context === 'checkout' ) { $response['items_html'] = advx_get_items_html_checkout_mode(); } else { $response['items_html'] = advx_get_items_html_cart_mode(); $response['totals_html'] = advx_get_totals_html_cart_mode(); } wp_send_json_success($response); } else { wp_send_json_error('Item not found'); } } // ============================================================================= // 2. ASSETS & STYLES // ============================================================================= add_action('wp_head', 'advx_app_ui_assets'); function advx_app_ui_assets() { if ( ! is_cart() && ! is_checkout() && ! is_page() ) return; $ajax_url = admin_url( 'admin-ajax.php' ); $wc_ajax_url = WC_AJAX::get_endpoint( '%%endpoint%%' ); $apply_coupon_nonce = wp_create_nonce( 'apply-coupon' ); // Fetch the customized color or fallback to default $primary_color = get_option('advx_ui_primary_color', '#008060'); // Convert Hex to RGB for rgba background variants $hex = str_replace('#', '', $primary_color); $r = hexdec(strlen($hex) == 3 ? substr($hex,0,1).substr($hex,0,1) : substr($hex,0,2)); $g = hexdec(strlen($hex) == 3 ? substr($hex,1,1).substr($hex,1,1) : substr($hex,2,2)); $b = hexdec(strlen($hex) == 3 ? substr($hex,2,1).substr($hex,2,1) : substr($hex,4,2)); ?> <style> /* --- 0. DYNAMIC CSS VARIABLES --- */ :root { --advx-primary: <?php echo esc_attr($primary_color); ?>; --advx-light: rgba(<?php echo "$r, $g, $b"; ?>, 0.12); } /* --- 1. GENERAL CONTAINER --- */ html, body { overflow-x: hidden; overflow-y: auto !important; height: auto !important; } #advx-app-ui { font-family: 'Segoe UI', Roboto, Helvetica, Arial, sans-serif; background: #F3F5F7; padding: 15px; max-width: 500px; margin: 0 auto; color: #111; min-height: 100vh; } #advx-app-ui *, #advx-app-ui *::before, #advx-app-ui *::after { box-sizing: border-box; } /* --- 2. FIX: NOTICES AS POPUPS --- */ #advx-app-ui .woocommerce-notices-wrapper { position: fixed; top: 20px; right: 20px; width: auto; max-width: 350px; z-index: 999999; display: flex; flex-direction: column; gap: 10px; pointer-events: none; /* Let clicks pass through wrapper */ } @media (max-width: 480px) { #advx-app-ui .woocommerce-notices-wrapper { top: 15px; right: 15px; left: 15px; max-width: none; } } #advx-app-ui .woocommerce-error, #advx-app-ui .woocommerce-message, #advx-app-ui .woocommerce-info { pointer-events: auto; /* Catch clicks on notice */ margin: 0; border-radius: 8px; font-size: 14px; list-style: none; padding: 15px; background: #fff; border-left: 4px solid var(--advx-primary); box-shadow: 0 4px 15px rgba(0,0,0,0.15); display: flex !important; flex-wrap: wrap; gap: 5px; width: 100%; align-items: center; font-weight: 500; animation: advxPopupSlideIn 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards; } #advx-app-ui .woocommerce-error { border-color: #D32F2F; color: #D32F2F; } #advx-app-ui .woocommerce-error li { margin: 0; padding: 0; width: 100%; } @keyframes advxPopupSlideIn { 0% { transform: translateX(120%); opacity: 0; } 100% { transform: translateX(0); opacity: 1; } } @keyframes advxPopupFadeOut { 0% { transform: translateX(0); opacity: 1; } 100% { transform: translateX(120%); opacity: 0; } } .advx-popup-hide { animation: advxPopupFadeOut 0.4s cubic-bezier(0.25, 0.8, 0.25, 1) forwards !important; } /* --- TABLET & DESKTOP LAYOUT (768px+) --- */ @media(min-width: 768px) { #advx-app-ui { max-width: 1140px; border-radius: 20px; margin: 30px auto; padding: 40px; min-height: auto; } .advx-checkout-layout { display: flex; gap: 30px; align-items: flex-start; width: 100%; } .advx-col-left { flex: 1.8; } .advx-col-right { flex: 1.2; position: sticky; top: 20px; } } /* --- 3. CARDS --- */ .advx-card { background: #ffffff; border-radius: 12px; padding: 20px; margin-bottom: 15px; box-shadow: 0 2px 10px rgba(0,0,0,0.03); border: 1px solid #fff; } .advx-card h4 { margin-top: 0; margin-bottom: 15px; font-size: 16px; font-weight: 700; color: #333; border-bottom: 1px solid #eee; padding-bottom: 10px; } /* --- 4. INPUTS --- */ #advx-app-ui input[type="text"], #advx-app-ui input[type="email"], #advx-app-ui input[type="tel"], #advx-app-ui input[type="password"], #advx-app-ui select, #advx-app-ui textarea { width: 100%; padding: 12px 15px; border: 1px solid #E0E0E0; border-radius: 8px; font-size: 14px; background: #fff; color: #333; outline: none; height: 48px; margin: 0; box-shadow: none; } #advx-app-ui .form-row { margin-bottom: 12px; width: 100%; padding: 0; display: block; } #advx-app-ui label { font-size: 13px; color: #555; margin-bottom: 5px; display: block; font-weight: 600; line-height: 1.5; } #advx-app-ui .select2-container .select2-selection--single { height: 48px; border: 1px solid #E0E0E0; border-radius: 8px; display: flex; align-items: center; } /* --- 5. COUPON DESIGN --- */ .advx-coupon-wrapper { display: flex; align-items: center; background: #FFFFFF; border: 1px solid #D1D5DB; border-radius: 10px; padding: 5px; position: relative; flex-wrap: nowrap; } .advx-coupon-wrapper input[type="text"] { border: none !important; background: transparent !important; box-shadow: none !important; padding: 10px 15px !important; flex-grow: 1; font-size: 14px; color: #333; height: 40px !important; min-width: 0; } .advx-coupon-wrapper button { background: var(--advx-primary); color: #fff; border: none; border-radius: 8px; padding: 0 20px; font-weight: 600; font-size: 14px; cursor: pointer; flex-shrink: 0; transition: all 0.2s; height: 40px; width: auto !important; } .advx-coupon-wrapper button:hover { filter: brightness(0.85); } /* Applied Coupon Active State */ .advx-coupon-wrapper.has-coupon { background: var(--advx-light); border-color: var(--advx-primary); } .advx-coupon-wrapper.has-coupon input[type="text"] { color: var(--advx-primary); font-weight: 700; } .advx-coupon-wrapper.has-coupon button { background: var(--advx-primary); opacity: 0.7; cursor: default; } /* --- 6. PRODUCT ITEMS --- */ .advx-item { display: flex; gap: 15px; padding-bottom: 15px; border-bottom: 1px solid #eee; margin-bottom: 15px; align-items: center; position: relative; } .advx-item:last-child { border-bottom: none; margin-bottom: 0; padding-bottom: 0; } .advx-remove-btn { position: absolute; top: -5px; right: 0; width: 20px; height: 20px; color: #999; font-size: 18px; line-height: 20px; text-align: center; cursor: pointer; z-index: 10; font-weight: bold; text-decoration: none; } .advx-remove-btn:hover { color: #d32f2f; } .advx-thumb { width: 65px; height: 65px; border-radius: 10px; overflow: hidden; background: #eee; flex-shrink: 0; } .advx-thumb img { width: 100%; height: 100%; object-fit: cover; margin: 0; } .advx-details { flex: 1; padding-right: 15px; } .advx-title { font-size: 14px; font-weight: 700; margin: 0 0 4px; color: #222; line-height: 1.3; } .advx-meta { font-size: 12px; color: #888; margin-bottom: 4px; } .advx-price { font-size: 15px; font-weight: 800; color: var(--advx-primary); } .advx-qty { display: flex; align-items: center; background: #F3F4F6; border-radius: 6px; padding: 2px; width: max-content; } .advx-qty-btn { width: 30px; height: 30px; background: #fff; border: none; border-radius: 4px; cursor: pointer; color: #333; display: flex; align-items: center; justify-content: center; font-weight: bold; font-size: 18px; line-height: 1; } .advx-qty input { width: 35px; background: transparent; border: none; text-align: center; font-weight: bold; font-size: 14px; padding: 0; height: auto; margin: 0; box-shadow: none !important; pointer-events: none; } .advx-qty.compact { transform: scale(0.9); transform-origin: right center; } /* --- 7. TOTALS TABLE & SHIPPING --- */ #advx-app-ui table.shop_table, #advx-app-ui .woocommerce-checkout-review-order-table { width: 100%; border-collapse: collapse; margin-bottom: 0; border: none; } #advx-app-ui table.shop_table th, #advx-app-ui table.shop_table td { text-align: right; padding: 10px 0; color: #111; font-weight: 600; font-size: 14px; vertical-align: top; border-top: none; } #advx-app-ui table.shop_table th { text-align: left; color: #666; font-weight: 500; width: 50%; } #advx-app-ui table.shop_table tr { border-bottom: 1px dashed #eee; } #advx-app-ui table.shop_table tr:last-child { border-bottom: none; } #advx-app-ui .order-total th, #advx-app-ui .order-total td { font-size: 18px; color: var(--advx-primary); font-weight: 800; border-top: 1px solid #ddd; padding-top: 15px; border-bottom: none; } #advx-app-ui .woocommerce-checkout-review-order-table .cart_item { display: none; } #advx-app-ui .woocommerce-checkout-review-order-table thead { display: none; } #advx-app-ui .wc-proceed-to-checkout { display: none !important; } /* ==================================================================== */ /* FIX: 100% WIDTH FOR SHIPPING SECTION (EXTREME FORCE) */ /* ==================================================================== */ #advx-app-ui table.shop_table tr.woocommerce-shipping-totals { display: flex !important; flex-direction: column !important; width: 100% !important; border-bottom: 1px dashed #eee !important; padding-bottom: 15px !important; margin-top: 10px !important; } #advx-app-ui table.shop_table tr.woocommerce-shipping-totals th { display: block !important; width: 100% !important; text-align: left !important; padding: 0 0 10px 0 !important; border: none !important; font-size: 16px !important; color: #333 !important; } #advx-app-ui table.shop_table tr.woocommerce-shipping-totals td { display: block !important; width: 200% !important; text-align: left !important; padding: 0 !important; } #advx-app-ui ul#shipping_method { list-style: none !important; padding: 0 !important; margin: 0 !important; width: 100% !important; display: block !important; } #advx-app-ui ul#shipping_method li { margin-bottom: 10px !important; width: 100% !important; display: block !important; } #advx-app-ui ul#shipping_method li label { display: flex !important; align-items: center !important; justify-content: flex-start !important; width: 100% !important; padding: 15px !important; background: #FFFFFF !important; border: 1px solid #ddd !important; border-radius: 10px !important; cursor: pointer !important; font-size: 14px !important; font-weight: 600 !important; box-sizing: border-box !important; color: #333 !important; } #advx-app-ui ul#shipping_method li label span.amount { margin-left: auto !important; } /* ==================================================================== */ /* --- 8. PAYMENT & SPECIFIC PAYMENT BOXES --- */ #advx-app-ui #payment { background: transparent; border-radius: 0; padding: 0; display: block !important; margin-top: 10px; width: 100% !important; box-sizing: border-box; } #advx-app-ui .woocommerce-checkout-payment { display: block !important; width: 100% !important; box-sizing: border-box; } /* USER CUSTOM PAYMENT METHODS CONTAINER */ #advx-app-ui #add_payment_method #payment ul.payment_methods, #advx-app-ui .woocommerce-cart #payment ul.payment_methods, #advx-app-ui .woocommerce-checkout #payment ul.payment_methods, #advx-app-ui ul.wc_payment_methods { text-align: left; padding: 0em !important; border-bottom: 1px solid rgba(104, 87, 125, .14) !important; margin: 0; list-style: none outside; width: 100% !important; display: block !important; box-sizing: border-box; } #advx-app-ui ul.wc_payment_methods li, #advx-app-ui ul.payment_methods li { margin-bottom: 10px !important; position: relative; background: #fff; border: 1px solid #ddd; border-radius: 10px; overflow: hidden; width: 100% !important; box-sizing: border-box; display: block !important; } #advx-app-ui ul.wc_payment_methods li label, #advx-app-ui ul.payment_methods li label { display: flex; align-items: center; width: 100% !important; padding: 15px; cursor: pointer; font-size: 14px; font-weight: 600; color: #333; margin: 0; box-sizing: border-box; } #advx-app-ui input[type="radio"] { position: absolute; opacity: 0; z-index: -1; } #advx-app-ui ul#shipping_method li label::before, #advx-app-ui ul.wc_payment_methods li label::before, #advx-app-ui ul.payment_methods li label::before { content: ''; width: 18px; height: 18px; border: 2px solid #888; border-radius: 50%; margin-right: 12px !important; display: inline-block; flex-shrink: 0; } #advx-app-ui input[type="radio"]:checked + label { background-color: var(--advx-light) !important; border-color: var(--advx-primary) !important; color: var(--advx-primary) !important; } #advx-app-ui input[type="radio"]:checked + label::before { border-color: var(--advx-primary) !important; background-color: var(--advx-primary) !important; box-shadow: inset 0 0 0 3px var(--advx-light) !important; } /* USER CUSTOM PAYMENT BOXES */ #advx-app-ui #add_payment_method #payment div.payment_box, #advx-app-ui .woocommerce-cart #payment div.payment_box, #advx-app-ui .woocommerce-checkout #payment div.payment_box, #advx-app-ui #payment div.payment_box { position: relative; box-sizing: border-box; width: 100% !important; padding: 1em !important; margin: 0em 0 !important; font-size: .92em !important; border-radius: 2px !important; line-height: 1.5 !important; background-color: #f8ffff !important; color: #515151 !important; display: none; } #advx-app-ui input[type="radio"]:checked ~ .payment_box { display: block !important; } #advx-app-ui #place_order { display: block !important; width: 100% !important; background: var(--advx-primary); color: #fff; font-size: 16px; font-weight: 700; text-align: center; padding: 16px; border-radius: 10px; border: none; cursor: pointer; text-decoration: none; margin-top: 20px; line-height: 1.2; opacity: 1 !important; visibility: visible !important; box-sizing: border-box; transition: all 0.2s; } #advx-app-ui #place_order:hover { filter: brightness(0.85); } /* --- 9. THANK YOU PAGE --- */ .advx-thankyou-box { text-align: center; padding: 30px 20px; } .advx-success-icon { width: 80px; height: 80px; background: var(--advx-light); color: var(--advx-primary); border-radius: 50%; display: flex; align-items: center; justify-content: center; margin: 0 auto 20px; font-size: 40px; } .advx-thankyou-msg { font-size: 24px; font-weight: 700; color: var(--advx-primary); margin-bottom: 10px; } .advx-order-number { font-size: 16px; color: #555; margin-bottom: 25px; } .advx-btn-main { display: block; width: 100%; background: var(--advx-primary); color: #fff; font-size: 16px; font-weight: 700; text-align: center; padding: 16px; border-radius: 10px; border: none; cursor: pointer; text-decoration: none; margin-top: 15px; transition: all 0.2s; } .advx-btn-main:hover { filter: brightness(0.85); } /* FIX: THANK YOU PAGE ORDER DETAILS ALIGNMENT & COLORS */ #advx-app-ui table.order_details { width: 100%; border-collapse: collapse; } #advx-app-ui table.order_details thead th { text-align: left; border-bottom: 2px solid #eee; } #advx-app-ui table.order_details thead th:last-child { text-align: right; } #advx-app-ui table.order_details tbody td { text-align: left; vertical-align: middle; padding: 12px 0; border-bottom: 1px dashed #eee; } #advx-app-ui table.order_details tbody td.woocommerce-table__product-total { text-align: right; } #advx-app-ui table.order_details tfoot th { text-align: left; width: 50%; padding: 12px 0; } #advx-app-ui table.order_details tfoot td { text-align: right; padding: 12px 0; } #advx-app-ui table.order_details td.woocommerce-table__product-name a { color: var(--advx-primary) !important; text-decoration: none !important; font-weight: 600; } #advx-app-ui table.order_details td.woocommerce-table__product-name a:hover { filter: brightness(0.85); } .blockUI.blockOverlay { background: rgba(255,255,255,0.8) !important; border-radius: 12px; z-index: 9999 !important; } </style> <script> var advx_ajax_url = "<?php echo esc_url($ajax_url); ?>"; var advx_wc_ajax_url = "<?php echo esc_url($wc_ajax_url); ?>"; var advx_apply_coupon_nonce = "<?php echo esc_js($apply_coupon_nonce); ?>"; jQuery(document).ready(function($){ function init_advx_popups() { $('#advx-app-ui .woocommerce-error, #advx-app-ui .woocommerce-message, #advx-app-ui .woocommerce-info').each(function() { var $notice = $(this); if(!$notice.hasClass('advx-initialized')) { $notice.addClass('advx-initialized'); setTimeout(function() { $notice.addClass('advx-popup-hide'); setTimeout(function(){ $notice.remove(); }, 400); }, 5000); } }); } init_advx_popups(); var is_checkout = $('form.checkout').length > 0; var request_running = false; function advx_trigger_update(cart_key, new_qty) { if(request_running) return; request_running = true; var $target = $('#advx-app-ui'); if( $.fn.block ) { $target.block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } }); } var context = is_checkout ? 'checkout' : 'cart'; $.ajax({ type: 'POST', url: advx_ajax_url, data: { action: 'advx_update_qty', cart_key: cart_key, qty: new_qty, context: context }, success: function(res) { if(res.success) { if( context === 'checkout' ) { $('#advx-checkout-items-wrapper').html(res.data.items_html); $('body').trigger('update_checkout'); } else { $('#advx-cart-items-wrapper').html(res.data.items_html); $('#advx-cart-totals-wrapper').html(res.data.totals_html); if( $.fn.unblock ) { $target.unblock(); } request_running = false; } } else { request_running = false; if( $.fn.unblock ) { $target.unblock(); } } }, error: function() { request_running = false; if( $.fn.unblock ) { $target.unblock(); } } }); } $(document).on('click', '.advx-qty-btn', function(e){ e.preventDefault(); var $btn = $(this); var $input = $btn.siblings('input.qty'); var cart_key = $input.data('cart-key'); var val = parseInt($input.val()); var max = parseFloat($input.attr('max')); if( isNaN(max) || max < 0 ) max = 999999; var newVal = val; if($btn.hasClass('plus')) { if(val < max) newVal = val + 1; } else { if(val > 1) newVal = val - 1; } if(newVal !== val) { $input.val(newVal); advx_trigger_update(cart_key, newVal); } }); $(document).on('click', '.advx-remove-btn', function(e){ e.preventDefault(); if(!confirm('Remove this item?')) return; var cart_key = $(this).data('cart-key'); advx_trigger_update(cart_key, 0); }); $(document.body).on('updated_checkout applied_coupon', function(){ if( $.fn.unblock ) { $('#advx-app-ui').unblock(); } request_running = false; init_advx_popups(); }); $(document).on('click', '#advx_apply_coupon_btn', function(e){ e.preventDefault(); var $btn = $(this); var code = $('#advx_coupon_code').val(); if( !code ) return; $btn.prop('disabled', true).text('...'); if( $.fn.block ) { $('#advx-app-ui').block({ message: null, overlayCSS: { background: '#fff', opacity: 0.6 } }); } var data = { security: advx_apply_coupon_nonce, coupon_code: code }; var ajax_url = advx_wc_ajax_url.toString().replace( '%%endpoint%%', 'apply_coupon' ); $.ajax({ type: 'POST', url: ajax_url, data: data, success: function( code ) { $('.woocommerce-error, .woocommerce-message').remove(); if ( code ) { if ( $('.woocommerce-notices-wrapper').length ) { $('.woocommerce-notices-wrapper').html( code ); init_advx_popups(); } else { $('#advx-app-ui').prepend( code ); init_advx_popups(); } // Check if coupon was successfully applied if ( code.indexOf('woocommerce-message') !== -1 ) { $('.advx-coupon-wrapper').addClass('has-coupon'); $('#advx_coupon_code').prop('readonly', true); $btn.prop('disabled', true).text('Applied'); } else { // If error, reset so user can try again $btn.prop('disabled', false).text('Apply'); $('#advx_coupon_code').val(''); } if(is_checkout) { $('body').trigger('update_checkout'); } else { location.reload(); } } else { $btn.prop('disabled', false).text('Apply'); if( $.fn.unblock ) { $('#advx-app-ui').unblock(); } } }, error: function() { $btn.prop('disabled', false).text('Apply'); if( $.fn.unblock ) { $('#advx-app-ui').unblock(); } } }); }); // Reset the coupon box when a coupon is removed (checkout and cart events) $(document.body).on('removed_coupon removed_coupon_in_checkout', function(){ $('.advx-coupon-wrapper').removeClass('has-coupon'); $('#advx_coupon_code').prop('readonly', false).val(''); $('#advx_apply_coupon_btn').prop('disabled', false).text('Apply'); }); // Fallback: Also clear it specifically if the direct WooCommerce remove link is clicked $(document.body).on('click', '.woocommerce-remove-coupon', function(){ $('.advx-coupon-wrapper').removeClass('has-coupon'); $('#advx_coupon_code').prop('readonly', false).val(''); $('#advx_apply_coupon_btn').prop('disabled', false).text('Apply'); }); if( $('#payment').length ) { $('#payment').show(); } $(document.body).on('checkout_error', function(){ $('html, body').animate({ scrollTop: $("#advx-app-ui").offset().top - 20 }, 500); init_advx_popups(); }); $(document).on('click', '.wc_payment_methods li', function() { $(this).find('input[type="radio"]').prop('checked', true).trigger('change'); }); }); </script> <?php } // ============================================================================= // 3. SHORTCODE: [advaxe_cart] // ============================================================================= add_shortcode('advaxe_cart', 'advx_render_cart_app'); function advx_render_cart_app() { if ( ! class_exists( 'WooCommerce' ) ) return; WC()->cart->calculate_totals(); if ( WC()->cart->is_empty() ) { return '<div id="advx-app-ui"><div class="advx-card" style="text-align:center; padding:60px 20px;"> <h3 style="margin:0 0 10px;">Cart is Empty</h3> <p style="color:#888; margin-bottom:20px;">Add items to start checkout</p> <a href="'.wc_get_page_permalink('shop').'" class="advx-btn-main">Go Shopping</a></div></div>'; } ob_start(); ?> <div id="advx-app-ui"> <div class="woocommerce-notices-wrapper"><?php wc_print_notices(); ?></div> <div class="advx-checkout-layout"> <div class="advx-col-left" id="advx-cart-items-wrapper"> <?php echo advx_get_items_html_cart_mode(); ?> </div> <div class="advx-col-right" id="advx-cart-totals-wrapper"> <?php echo advx_get_totals_html_cart_mode(); ?> </div> </div> </div> <?php return ob_get_clean(); } // ============================================================================= // 3. SHORTCODE: [advaxe_checkout] // ============================================================================= add_shortcode('advaxe_checkout', 'advx_render_checkout_app'); function advx_render_checkout_app() { if ( ! class_exists( 'WooCommerce' ) ) return; // --- THANK YOU PAGE --- global $wp; if ( is_wc_endpoint_url( 'order-received' ) ) { $order_id = isset( $wp->query_vars['order-received'] ) ? intval( $wp->query_vars['order-received'] ) : 0; $order = wc_get_order( $order_id ); if ( ! $order ) return; ob_start(); ?> <div id="advx-app-ui"> <div class="advx-card advx-thankyou-box"> <div class="advx-success-icon">✓</div> <div class="advx-thankyou-msg">Order Placed!</div> <div class="advx-order-number">Order #<?php echo $order->get_order_number(); ?></div> <p>Thank you. Your order has been received.</p> <a href="<?php echo wc_get_page_permalink('shop'); ?>" class="advx-btn-main">Continue Shopping</a> </div> <div class="advx-card"> <h4>Order Details</h4> <table class="shop_table"> <tr><th style="width: 50%; text-align: left;">Date:</th><td style="text-align: right;"><?php echo wc_format_datetime( $order->get_date_created() ); ?></td></tr> <tr><th style="width: 50%; text-align: left;">Total:</th><td style="text-align: right;"><?php echo $order->get_formatted_order_total(); ?></td></tr> <tr><th style="width: 50%; text-align: left;">Payment:</th><td style="text-align: right;"><?php echo $order->get_payment_method_title(); ?></td></tr> </table> </div> <div class="advx-card"> <?php do_action( 'woocommerce_thankyou', $order->get_id() ); ?> </div> </div> <?php return ob_get_clean(); } // --- CHECKOUT PAGE --- if ( WC()->cart->is_empty() ) { wp_redirect( wc_get_page_permalink( 'shop' ) ); exit; } ob_start(); ?> <div id="advx-app-ui"> <div class="woocommerce-notices-wrapper"><?php wc_print_notices(); ?></div> <form name="checkout" method="post" class="checkout woocommerce-checkout" action="<?php echo esc_url( wc_get_checkout_url() ); ?>" enctype="multipart/form-data"> <div class="advx-checkout-layout"> <div class="advx-col-left"> <div class="advx-card"> <h4>Billing Details</h4> <div class="woocommerce-billing-fields__field-wrapper"> <?php $checkout = WC()->checkout(); $fields = $checkout->get_checkout_fields( 'billing' ); foreach ( $fields as $key => $field ) { woocommerce_form_field( $key, $field, $checkout->get_value( $key ) ); } ?> </div> </div> <?php if ( WC()->cart->needs_shipping_address() === true ) : ?> <div class="advx-card"> <h4 id="ship-to-different-address"> <label class="woocommerce-form__label woocommerce-form__label-for-checkbox checkbox"> <input id="ship-to-different-address-checkbox" class="woocommerce-form__input woocommerce-form__input-checkbox input-checkbox" <?php checked( apply_filters( 'woocommerce_ship_to_different_address_checked', 'shipping' === get_option( 'woocommerce_ship_to_destination' ) ? 1 : 0 ), 1 ); ?> type="checkbox" name="ship_to_different_address" value="1" /> <span>Ship to different address?</span> </label> </h4> <div class="shipping_address"> <div class="woocommerce-shipping-fields__field-wrapper"> <?php $fields = $checkout->get_checkout_fields( 'shipping' ); foreach ( $fields as $key => $field ) { woocommerce_form_field( $key, $field, $checkout->get_value( $key ) ); } ?> </div> </div> </div> <?php endif; ?> <div id="advx-checkout-items-wrapper"> <?php echo advx_get_items_html_checkout_mode(); ?> </div> </div> <div class="advx-col-right"> <?php if ( wc_coupons_enabled() ) { $applied_coupons = WC()->cart->get_applied_coupons(); $has_coupon = !empty($applied_coupons); $coupon_code = $has_coupon ? $applied_coupons[0] : ''; ?> <div class="advx-card"> <h4>Discount Code</h4> <div class="advx-coupon-wrapper <?php echo $has_coupon ? 'has-coupon' : ''; ?>"> <input type="text" id="advx_coupon_code" class="input-text" placeholder="Enter coupon code" value="<?php echo esc_attr($coupon_code); ?>" <?php echo $has_coupon ? 'readonly' : ''; ?> /> <button type="button" id="advx_apply_coupon_btn" class="button" <?php echo $has_coupon ? 'disabled' : ''; ?>><?php echo $has_coupon ? 'Applied' : 'Apply'; ?></button> </div> </div> <?php } ?> <div class="advx-card"> <h4>Payment & Total</h4> <div id="order_review" class="woocommerce-checkout-review-order"> <?php remove_action( 'woocommerce_checkout_order_review', 'woocommerce_checkout_payment', 20 ); woocommerce_order_review(); woocommerce_checkout_payment(); ?> </div> </div> </div> </div> </form> </div> <?php return ob_get_clean(); } // ============================================================================= // 4. CHANGE ORDER DETAILS HEADING TO "FULL ORDER DETAILS" (USING GETTEXT FILTER) // ============================================================================= add_filter( 'gettext', 'advx_change_order_details_text', 99, 3 ); function advx_change_order_details_text( $translated_text, $text, $domain ) { if ( is_wc_endpoint_url( 'order-received' ) && $domain === 'woocommerce' ) { if ( $text === 'Order details' || $text === 'Order Details' ) { return 'Full Order Details'; } } return $translated_text; }