$user_id > 0, 'billing' => [ 'first_name' => '', 'last_name' => '', 'email' => '', 'phone' => '', 'address_1' => '', 'city' => '', 'postcode' => '', 'country' => '', 'state' => '', ] ]; if ($user_id) { $customer = new \WC_Customer($user_id); if ($customer) { $data['billing'] = [ 'first_name' => $customer->get_billing_first_name(), 'last_name' => $customer->get_billing_last_name(), 'email' => $customer->get_billing_email() ?: $customer->get_email(), 'phone' => $customer->get_billing_phone(), 'address_1' => $customer->get_billing_address_1(), 'city' => $customer->get_billing_city(), 'postcode' => $customer->get_billing_postcode(), 'country' => $customer->get_billing_country(), 'state' => $customer->get_billing_state(), ]; } } // Get WooCommerce base country/state list to populate dynamic selectors if needed $countries = new \WC_Countries(); $data['allowed_countries'] = $countries->get_shipping_countries(); // Get enabled payment gateways dynamically $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); $gateways_data = []; if (!empty($available_gateways)) { foreach ($available_gateways as $gateway) { $gateways_data[] = [ 'id' => $gateway->id, 'title' => $gateway->get_title(), 'description' => $gateway->get_description() ?: '', ]; } } if (empty($gateways_data)) { $gateways_data[] = [ 'id' => 'stripe', 'title' => 'Credit Card', 'description' => 'Pay securely with your credit card.' ]; $gateways_data[] = [ 'id' => 'cod', 'title' => 'Cash on Delivery', 'description' => 'Pay with cash upon delivery.' ]; } $data['payment_gateways'] = $gateways_data; wp_send_json_success($data); } public function calculate_shipping_rates() { check_ajax_referer('shoponix_chat_nonce', 'nonce'); $country = isset($_POST['country']) ? sanitize_text_field(wp_unslash($_POST['country'])) : ''; $state = isset($_POST['state']) ? sanitize_text_field(wp_unslash($_POST['state'])) : ''; $city = isset($_POST['city']) ? sanitize_text_field(wp_unslash($_POST['city'])) : ''; $postcode = isset($_POST['postcode']) ? sanitize_text_field(wp_unslash($_POST['postcode'])) : ''; $address = isset($_POST['address_1']) ? sanitize_text_field(wp_unslash($_POST['address_1'])) : ''; if (empty($country) || empty($postcode)) { wp_send_json_error(['message' => 'Please provide country and postcode.']); } // Set customer shipping & billing location WC()->customer->set_billing_location($country, $state, $postcode, $city); WC()->customer->set_shipping_location($country, $state, $postcode, $city); WC()->customer->set_billing_address_1($address); WC()->customer->set_shipping_address_1($address); WC()->customer->save(); // recalculate shipping WC()->shipping->reset_shipping(); WC()->cart->calculate_shipping(); WC()->cart->calculate_totals(); $packages = WC()->shipping->get_packages(); $methods = []; if (!empty($packages)) { foreach ($packages as $i => $package) { if (isset($package['rates'])) { foreach ($package['rates'] as $rate_id => $rate) { $methods[] = [ 'id' => $rate_id, 'label' => $rate->get_label(), 'cost' => wc_price($rate->get_cost()), 'raw_cost' => $rate->get_cost() ]; } } } } wp_send_json_success([ 'methods' => $methods, 'totals' => [ 'subtotal' => wc_price(WC()->cart->get_subtotal()), 'discount' => wc_price(WC()->cart->get_discount_total()), 'shipping' => wc_price(WC()->cart->get_shipping_total()), 'tax' => wc_price(WC()->cart->get_cart_contents_tax()), 'total' => WC()->cart->get_total() ] ]); } public function save_checkout_details() { check_ajax_referer('shoponix_chat_nonce', 'nonce'); // phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized $billing_raw = isset($_POST['billing']) ? wp_unslash($_POST['billing']) : []; $billing = map_deep($billing_raw, 'sanitize_text_field'); if (empty($billing)) { wp_send_json_error(['message' => 'Billing details are empty.']); } // Save fields in WC Session WC()->session->set('shoponix_billing_details', $billing); // Natively update customer object WC()->customer->set_billing_first_name(sanitize_text_field($billing['first_name'] ?? '')); WC()->customer->set_billing_last_name(sanitize_text_field($billing['last_name'] ?? '')); WC()->customer->set_billing_email(sanitize_email($billing['email'] ?? '')); WC()->customer->set_billing_phone(sanitize_text_field($billing['phone'] ?? '')); WC()->customer->set_billing_address_1(sanitize_text_field($billing['address_1'] ?? '')); WC()->customer->set_billing_city(sanitize_text_field($billing['city'] ?? '')); WC()->customer->set_billing_postcode(sanitize_text_field($billing['postcode'] ?? '')); WC()->customer->set_billing_country(sanitize_text_field($billing['country'] ?? '')); WC()->customer->set_billing_state(sanitize_text_field($billing['state'] ?? '')); // Defaults shipping to billing WC()->customer->set_shipping_first_name(sanitize_text_field($billing['first_name'] ?? '')); WC()->customer->set_shipping_last_name(sanitize_text_field($billing['last_name'] ?? '')); WC()->customer->set_shipping_address_1(sanitize_text_field($billing['address_1'] ?? '')); WC()->customer->set_shipping_city(sanitize_text_field($billing['city'] ?? '')); WC()->customer->set_shipping_postcode(sanitize_text_field($billing['postcode'] ?? '')); WC()->customer->set_shipping_country(sanitize_text_field($billing['country'] ?? '')); WC()->customer->set_shipping_state(sanitize_text_field($billing['state'] ?? '')); WC()->customer->save(); // Selected shipping method key $shipping_method = isset($_POST['shipping_method']) ? sanitize_text_field(wp_unslash($_POST['shipping_method'])) : ''; if ($shipping_method) { WC()->session->set('chosen_shipping_methods', [$shipping_method]); } WC()->cart->calculate_totals(); wp_send_json_success([ 'message' => 'Details validated and saved successfully!', 'totals' => [ 'subtotal' => wc_price(WC()->cart->get_subtotal()), 'discount' => wc_price(WC()->cart->get_discount_total()), 'shipping' => wc_price(WC()->cart->get_shipping_total()), 'tax' => wc_price(WC()->cart->get_cart_contents_tax()), 'total' => WC()->cart->get_total() ] ]); } public function process_payment() { check_ajax_referer('shoponix_chat_nonce', 'nonce'); if (WC()->cart->is_empty()) { wp_send_json_error(['message' => 'Your cart is empty. Please add items to proceed.']); } $payment_method = isset($_POST['payment_method']) ? sanitize_text_field(wp_unslash($_POST['payment_method'])) : 'cod'; $billing = WC()->session->get('shoponix_billing_details'); if (empty($billing)) { $billing = [ 'first_name' => WC()->customer->get_billing_first_name(), 'last_name' => WC()->customer->get_billing_last_name(), 'email' => WC()->customer->get_billing_email(), 'phone' => WC()->customer->get_billing_phone(), 'address_1' => WC()->customer->get_billing_address_1(), 'city' => WC()->customer->get_billing_city(), 'postcode' => WC()->customer->get_billing_postcode(), 'country' => WC()->customer->get_billing_country(), 'state' => WC()->customer->get_billing_state(), ]; } try { $order = wc_create_order(); foreach (WC()->cart->get_cart() as $cart_item_key => $values) { $product_id = $values['product_id']; $quantity = $values['quantity']; $variation_id = $values['variation_id']; $variation = $values['variation']; if ($variation_id > 0) { $order->add_product(wc_get_product($variation_id), $quantity, [ 'variation' => $variation ]); } else { $order->add_product(wc_get_product($product_id), $quantity); } } $order->set_billing_first_name($billing['first_name']); $order->set_billing_last_name($billing['last_name']); $order->set_billing_email($billing['email']); $order->set_billing_phone($billing['phone']); $order->set_billing_address_1($billing['address_1']); $order->set_billing_city($billing['city']); $order->set_billing_postcode($billing['postcode']); $order->set_billing_country($billing['country']); $order->set_billing_state($billing['state']); $order->set_shipping_first_name($billing['first_name']); $order->set_shipping_last_name($billing['last_name']); $order->set_shipping_address_1($billing['address_1']); $order->set_shipping_city($billing['city']); $order->set_shipping_postcode($billing['postcode']); $order->set_shipping_country($billing['country']); $order->set_shipping_state($billing['state']); foreach (WC()->cart->get_applied_coupons() as $coupon_code) { $order->apply_coupon($coupon_code); } $chosen_shipping = WC()->session->get('chosen_shipping_methods'); if (!empty($chosen_shipping)) { $packages = WC()->shipping->get_packages(); foreach ($packages as $i => $package) { if (isset($package['rates'])) { foreach ($package['rates'] as $rate_id => $rate) { if (in_array($rate_id, $chosen_shipping)) { $item = new \WC_Order_Item_Shipping(); $item->set_method_id($rate->get_method_id()); $item->set_method_title($rate->get_label()); $item->set_total($rate->get_cost()); $order->add_item($item); break 2; } } } } } if ($payment_method === 'stripe') { $order->set_payment_method('stripe'); $order->set_payment_method_title('Stripe Credit Card'); $order->payment_complete(); } else { $order->set_payment_method('cod'); $order->set_payment_method_title('Cash on Delivery (COD)'); $order->update_status('processing', 'Placed conversationally inside AI widget.'); } $order->calculate_totals(); $order->save(); WC()->cart->empty_cart(); WC()->session->set('shoponix_billing_details', null); WC()->session->set('chosen_shipping_methods', null); wp_send_json_success([ 'order_id' => $order->get_id(), 'order_number' => $order->get_order_number(), 'total' => wc_price($order->get_total()), 'payment_method' => $payment_method === 'stripe' ? 'Credit Card' : 'Cash on Delivery' ]); } catch (\Exception $e) { wp_send_json_error(['message' => 'Could not process order: ' . $e->getMessage()]); } } public function track_order() { check_ajax_referer('shoponix_chat_nonce', 'nonce'); $order_id = isset($_POST['order_id']) ? sanitize_text_field(wp_unslash($_POST['order_id'])) : ''; $contact = isset($_POST['contact']) ? sanitize_text_field(wp_unslash($_POST['contact'])) : ''; // Strip hash symbols if user entered it (e.g. #1234 -> 1234) $order_id = ltrim($order_id, '#'); $order_id = intval($order_id); if (!$order_id && empty($contact)) { wp_send_json_error(['message' => 'Please enter EITHER an Order ID OR Billing Email/Phone.']); } $order = null; // Case 1: Only Billing Email/Phone contact is provided -> Query the latest order associated with it if (!$order_id && !empty($contact)) { $query_args = [ 'limit' => 1, 'orderby' => 'date', 'order' => 'DESC', ]; if (is_email($contact)) { $query_args['billing_email'] = sanitize_email($contact); } else { $query_args['billing_phone'] = sanitize_text_field($contact); } $orders = wc_get_orders($query_args); if (!empty($orders)) { $order = reset($orders); $order_id = $order->get_id(); } else { wp_send_json_error(['message' => 'No orders found matching this Contact details.']); } } else { // Case 2: Order ID is provided -> Retrieve the order $order = wc_get_order($order_id); if (!$order) { wp_send_json_error(['message' => 'Order not found. Please double-check your Order ID.']); } // Case 3: Both are provided -> Perform security check verification if (!empty($contact)) { $billing_email = strtolower(trim($order->get_billing_email())); $billing_phone = preg_replace('/[^0-9]/', '', $order->get_billing_phone()); $input_contact = strtolower(trim($contact)); $input_phone_digits = preg_replace('/[^0-9]/', '', $contact); $email_match = ($billing_email === $input_contact); $phone_match = (!empty($billing_phone) && !empty($input_phone_digits) && (strpos($billing_phone, $input_phone_digits) !== false || strpos($input_phone_digits, $billing_phone) !== false)); if (!$email_match && !$phone_match) { wp_send_json_error(['message' => 'Security Verification Failed. The email or phone number does not match this Order.']); } } } if (!$order) { $order = wc_get_order($order_id); } // Get visual progress step mapping based on order status $status = $order->get_status(); $status_label = wc_get_order_status_name($status); $steps = [ 'pending' => 1, 'on-hold' => 1, 'processing' => 2, 'completed' => 4, 'refunded' => 0, // Special states 'cancelled' => 0, 'failed' => 0 ]; $current_step = isset($steps[$status]) ? $steps[$status] : 2; // default to processing if unknown $items = []; foreach ($order->get_items() as $item) { $items[] = $item->get_name() . ' (x' . $item->get_quantity() . ')'; } wp_send_json_success([ 'order_id' => $order->get_id(), 'status' => $status, 'status_label' => $status_label, 'current_step' => $current_step, // 1: Received, 2: Processing, 3: Shipped (virtual status or mapping), 4: Delivered 'date_created' => $order->get_date_created()->date('M d, Y'), 'total' => wp_strip_all_tags($order->get_formatted_order_total()), 'shipping_method'=> $order->get_shipping_method() ?: 'Standard Delivery', 'items' => $items, 'billing_name' => $order->get_billing_first_name() . ' ' . $order->get_billing_last_name(), 'shipping_addr' => $order->get_shipping_address_1() . ', ' . $order->get_shipping_city() ]); } }