Created
July 1, 2025 12:58
-
-
Save Archie22is/5cc50dc8165676b09eadafbd656dc902 to your computer and use it in GitHub Desktop.
Handles frontend checkout, validation, and basic saving
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /** | |
| * WooCommerce Attendee System - SCRIPT 1: CORE FUNCTIONALITY | |
| * Handles frontend checkout, validation, and basic saving | |
| * Add this first to your functions.php | |
| */ | |
| // Check if WooCommerce is active | |
| if (!in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) { | |
| return; | |
| } | |
| // 1. ENFORCE MAXIMUM QUANTITY LIMIT OF 5 PER PRODUCT | |
| add_filter('woocommerce_add_to_cart_validation', 'enforce_max_quantity_limit', 10, 3); | |
| function enforce_max_quantity_limit($passed, $product_id, $quantity) { | |
| if (!WC() || !WC()->cart) { | |
| return $passed; | |
| } | |
| $cart_quantity = 0; | |
| foreach (WC()->cart->get_cart() as $cart_item) { | |
| if ($cart_item['product_id'] == $product_id) { | |
| $cart_quantity += $cart_item['quantity']; | |
| } | |
| } | |
| $total_quantity = $cart_quantity + $quantity; | |
| $max_quantity = 5; | |
| if ($total_quantity > $max_quantity) { | |
| $product = wc_get_product($product_id); | |
| if (!$product) { | |
| return false; | |
| } | |
| $remaining = $max_quantity - $cart_quantity; | |
| if ($remaining <= 0) { | |
| wc_add_notice(sprintf( | |
| 'You already have the maximum quantity (%d) of "%s" in your cart.', | |
| $max_quantity, | |
| $product->get_name() | |
| ), 'error'); | |
| } else { | |
| wc_add_notice(sprintf( | |
| 'Maximum quantity allowed is %d. You can only add %d more "%s" to your cart.', | |
| $max_quantity, | |
| $remaining, | |
| $product->get_name() | |
| ), 'error'); | |
| } | |
| return false; | |
| } | |
| return $passed; | |
| } | |
| // 2. ENFORCE MAX QUANTITY ON CART UPDATE | |
| add_filter('woocommerce_update_cart_validation', 'enforce_max_quantity_on_cart_update', 10, 4); | |
| function enforce_max_quantity_on_cart_update($passed, $cart_item_key, $values, $quantity) { | |
| $max_quantity = 5; | |
| if ($quantity > $max_quantity) { | |
| $product = wc_get_product($values['product_id']); | |
| if ($product) { | |
| wc_add_notice(sprintf( | |
| 'Maximum quantity allowed is %d for "%s".', | |
| $max_quantity, | |
| $product->get_name() | |
| ), 'error'); | |
| } | |
| return false; | |
| } | |
| return $passed; | |
| } | |
| // 3. ADD ATTENDEE FIELDS TO CHECKOUT | |
| add_action('woocommerce_checkout_after_customer_details', 'add_item_specific_attendee_fields'); | |
| function add_item_specific_attendee_fields($checkout = null) { | |
| if (!WC() || !WC()->cart) { | |
| return; | |
| } | |
| $cart_items = WC()->cart->get_cart(); | |
| if (empty($cart_items)) { | |
| return; | |
| } | |
| echo '<div id="attendee_information">'; | |
| echo '<h3>' . esc_html__('Attendee Information', 'woocommerce') . '</h3>'; | |
| echo '<p>' . esc_html__('Please assign each item to a specific person:', 'woocommerce') . '</p>'; | |
| foreach ($cart_items as $cart_item_key => $cart_item) { | |
| $product = $cart_item['data']; | |
| if (!$product) { | |
| continue; | |
| } | |
| $product_name = $product->get_name(); | |
| $quantity = $cart_item['quantity']; | |
| echo '<div class="product-attendee-section" style="margin: 20px 0; padding: 15px; border: 2px solid #00bcd4; border-radius: 8px; background: #f8fdff;">'; | |
| echo '<h4 style="margin: 0 0 15px 0; color: #00bcd4; font-size: 18px;">' . esc_html($product_name) . '</h4>'; | |
| for ($i = 1; $i <= $quantity; $i++) { | |
| echo '<div class="individual-item-group" style="border: 1px solid #ddd; padding: 15px; margin: 10px 0; background: white; border-radius: 4px;">'; | |
| echo '<h5 style="color: #555; margin: 0 0 10px 0;">' . esc_html($product_name) . ' #' . $i . '</h5>'; | |
| $field_prefix = 'item_' . sanitize_key($cart_item_key) . '_' . $i; | |
| $name_value = isset($_POST[$field_prefix . '_name']) ? sanitize_text_field($_POST[$field_prefix . '_name']) : ''; | |
| $email_value = isset($_POST[$field_prefix . '_email']) ? sanitize_email($_POST[$field_prefix . '_email']) : ''; | |
| $phone_value = isset($_POST[$field_prefix . '_phone']) ? sanitize_text_field($_POST[$field_prefix . '_phone']) : ''; | |
| woocommerce_form_field($field_prefix . '_name', array( | |
| 'type' => 'text', | |
| 'class' => array('form-row-wide'), | |
| 'label' => __('Full Name *', 'woocommerce'), | |
| 'required' => true, | |
| ), $name_value); | |
| woocommerce_form_field($field_prefix . '_email', array( | |
| 'type' => 'email', | |
| 'class' => array('form-row-wide'), | |
| 'label' => __('Email Address *', 'woocommerce'), | |
| 'required' => true, | |
| ), $email_value); | |
| woocommerce_form_field($field_prefix . '_phone', array( | |
| 'type' => 'tel', | |
| 'class' => array('form-row-wide'), | |
| 'label' => __('Phone Number *', 'woocommerce'), | |
| 'required' => true, | |
| ), $phone_value); | |
| echo '</div>'; | |
| } | |
| echo '</div>'; | |
| } | |
| echo '</div>'; | |
| } | |
| // 4. VALIDATE ATTENDEE INFORMATION | |
| add_action('woocommerce_checkout_process', 'validate_item_specific_attendee_information'); | |
| function validate_item_specific_attendee_information() { | |
| if (!WC() || !WC()->cart) { | |
| return; | |
| } | |
| $cart_items = WC()->cart->get_cart(); | |
| foreach ($cart_items as $cart_item_key => $cart_item) { | |
| $product = $cart_item['data']; | |
| if (!$product) { | |
| continue; | |
| } | |
| $product_name = $product->get_name(); | |
| $quantity = $cart_item['quantity']; | |
| for ($i = 1; $i <= $quantity; $i++) { | |
| $field_prefix = 'item_' . sanitize_key($cart_item_key) . '_' . $i; | |
| if (empty($_POST[$field_prefix . '_name'])) { | |
| wc_add_notice(sprintf(__('Please enter the name for %s #%d', 'woocommerce'), $product_name, $i), 'error'); | |
| } | |
| if (empty($_POST[$field_prefix . '_email'])) { | |
| wc_add_notice(sprintf(__('Please enter the email for %s #%d', 'woocommerce'), $product_name, $i), 'error'); | |
| } elseif (!is_email($_POST[$field_prefix . '_email'])) { | |
| wc_add_notice(sprintf(__('Please enter a valid email for %s #%d', 'woocommerce'), $product_name, $i), 'error'); | |
| } | |
| if (empty($_POST[$field_prefix . '_phone'])) { | |
| wc_add_notice(sprintf(__('Please enter the phone number for %s #%d', 'woocommerce'), $product_name, $i), 'error'); | |
| } | |
| } | |
| } | |
| } | |
| // 5. SAVE ATTENDEE INFORMATION TO ORDER | |
| add_action('woocommerce_checkout_update_order_meta', 'save_item_specific_attendee_information'); | |
| function save_item_specific_attendee_information($order_id) { | |
| if (!WC() || !WC()->cart) { | |
| return; | |
| } | |
| $cart_items = WC()->cart->get_cart(); | |
| $all_attendees = array(); | |
| foreach ($cart_items as $cart_item_key => $cart_item) { | |
| $product = $cart_item['data']; | |
| if (!$product) { | |
| continue; | |
| } | |
| $product_id = $cart_item['product_id']; | |
| $product_name = $product->get_name(); | |
| $quantity = $cart_item['quantity']; | |
| for ($i = 1; $i <= $quantity; $i++) { | |
| $field_prefix = 'item_' . sanitize_key($cart_item_key) . '_' . $i; | |
| if (!empty($_POST[$field_prefix . '_name'])) { | |
| $all_attendees[] = array( | |
| 'product_id' => $product_id, | |
| 'product_name' => $product_name, | |
| 'item_number' => $i, | |
| 'cart_item_key' => $cart_item_key, | |
| 'name' => sanitize_text_field($_POST[$field_prefix . '_name']), | |
| 'email' => sanitize_email($_POST[$field_prefix . '_email']), | |
| 'phone' => sanitize_text_field($_POST[$field_prefix . '_phone']) | |
| ); | |
| } | |
| } | |
| } | |
| if (!empty($all_attendees)) { | |
| $order = wc_get_order($order_id); | |
| if ($order) { | |
| $order->update_meta_data('_item_attendee_information', $all_attendees); | |
| $order->update_meta_data('_attendee_information', $all_attendees); // Backward compatibility | |
| $order->save(); | |
| } | |
| } | |
| } | |
| // 6. HELPER FUNCTION TO GET ORDER ATTENDEE INFO (HPOS COMPATIBLE) | |
| function get_order_attendee_info($order_id) { | |
| $order = wc_get_order($order_id); | |
| if (!$order) { | |
| return false; | |
| } | |
| $attendees = $order->get_meta('_item_attendee_information', true); | |
| if (!$attendees) { | |
| $attendees = $order->get_meta('_attendee_information', true); | |
| } | |
| return $attendees; | |
| } | |
| // 7. BASIC ADMIN DISPLAY (Simple version) | |
| add_action('woocommerce_admin_order_data_after_billing_address', 'display_basic_attendee_info'); | |
| function display_basic_attendee_info($order) { | |
| if (!$order) { | |
| return; | |
| } | |
| $attendees = get_order_attendee_info($order->get_id()); | |
| if ($attendees && is_array($attendees)) { | |
| echo '<div class="order_data_column">'; | |
| echo '<h3>' . esc_html__('Attendee Information', 'woocommerce') . '</h3>'; | |
| foreach ($attendees as $attendee) { | |
| $product_name = isset($attendee['product_name']) ? $attendee['product_name'] : __('Unknown Product', 'woocommerce'); | |
| $item_number = isset($attendee['item_number']) ? $attendee['item_number'] : '?'; | |
| echo '<div style="margin-bottom: 10px; padding: 10px; border: 1px solid #ddd; background: #f9f9f9;">'; | |
| echo '<strong>' . esc_html($product_name) . ' #' . esc_html($item_number) . ':</strong><br>'; | |
| echo __('Name:', 'woocommerce') . ' ' . esc_html($attendee['name'] ?? 'N/A') . '<br>'; | |
| echo __('Email:', 'woocommerce') . ' ' . esc_html($attendee['email'] ?? 'N/A') . '<br>'; | |
| echo __('Phone:', 'woocommerce') . ' ' . esc_html($attendee['phone'] ?? 'N/A') . '<br>'; | |
| echo '</div>'; | |
| } | |
| echo '</div>'; | |
| } | |
| } | |
| // 8. CSS FOR CHECKOUT STYLING | |
| add_action('wp_head', 'item_attendee_form_styles'); | |
| function item_attendee_form_styles() { | |
| if (is_checkout()) { | |
| ?> | |
| <style> | |
| #woocommerce-additional-fields { | |
| display: none !important; | |
| } | |
| #attendee_information { | |
| display: block; | |
| margin: 20px 0; | |
| padding: 20px; | |
| border: 2px solid #00bcd4; | |
| border-radius: 8px; | |
| background-color: #f8fdff; | |
| } | |
| #attendee_information h3 { | |
| margin: 0 0 15px; | |
| color: #00bcd4; | |
| font-size: 24px; | |
| } | |
| .product-attendee-section { | |
| animation: fadeIn 0.3s ease-in; | |
| } | |
| .individual-item-group { | |
| background-color: white; | |
| border-radius: 4px; | |
| transition: box-shadow 0.2s ease; | |
| } | |
| .individual-item-group:hover { | |
| box-shadow: 0 2px 8px rgba(0,188,212,0.1); | |
| } | |
| .individual-item-group h5 { | |
| font-weight: 600; | |
| border-bottom: 1px solid #eee; | |
| padding-bottom: 8px; | |
| } | |
| .individual-item-group p { | |
| margin: 10px 0 0 0 !important; | |
| } | |
| @keyframes fadeIn { | |
| from { opacity: 0; transform: translateY(10px); } | |
| to { opacity: 1; transform: translateY(0); } | |
| } | |
| </style> | |
| <?php | |
| } | |
| } | |
| // 9. REQUEST INVOICE PAYMENT METHOD | |
| add_filter('woocommerce_payment_gateways', 'add_request_invoice_gateway'); | |
| function add_request_invoice_gateway($gateways) { | |
| $gateways[] = 'WC_Gateway_Request_Invoice'; | |
| return $gateways; | |
| } | |
| add_action('plugins_loaded', 'init_request_invoice_gateway_class'); | |
| function init_request_invoice_gateway_class() { | |
| if (!class_exists('WC_Payment_Gateway')) { | |
| return; | |
| } | |
| class WC_Gateway_Request_Invoice extends WC_Payment_Gateway { | |
| public function __construct() { | |
| $this->id = 'request_invoice'; | |
| $this->icon = ''; | |
| $this->has_fields = false; | |
| $this->method_title = __('Request Invoice', 'woocommerce'); | |
| $this->method_description = __('Allow customers to request an invoice for manual payment.', 'woocommerce'); | |
| $this->init_form_fields(); | |
| $this->init_settings(); | |
| $this->title = $this->get_option('title'); | |
| $this->description = $this->get_option('description'); | |
| $this->enabled = $this->get_option('enabled'); | |
| add_action('woocommerce_update_options_payment_gateways_' . $this->id, array($this, 'process_admin_options')); | |
| } | |
| public function init_form_fields() { | |
| $this->form_fields = array( | |
| 'enabled' => array( | |
| 'title' => __('Enable/Disable', 'woocommerce'), | |
| 'type' => 'checkbox', | |
| 'label' => __('Enable Request Invoice', 'woocommerce'), | |
| 'default' => 'yes' | |
| ), | |
| 'title' => array( | |
| 'title' => __('Title', 'woocommerce'), | |
| 'type' => 'text', | |
| 'description' => __('This controls the title which the user sees during checkout.', 'woocommerce'), | |
| 'default' => __('Request Invoice', 'woocommerce'), | |
| 'desc_tip' => true, | |
| ), | |
| 'description' => array( | |
| 'title' => __('Description', 'woocommerce'), | |
| 'type' => 'textarea', | |
| 'description' => __('Payment method description that the customer will see on your checkout.', 'woocommerce'), | |
| 'default' => __('Select this option to receive a formal invoice for your records or internal processing. No payment is required now — we'll send you an official invoice with payment details shortly after you place your order.', 'woocommerce'), | |
| ), | |
| ); | |
| } | |
| public function process_payment($order_id) { | |
| $order = wc_get_order($order_id); | |
| if (!$order) { | |
| return array( | |
| 'result' => 'fail', | |
| 'messages' => __('Order not found.', 'woocommerce') | |
| ); | |
| } | |
| $order->update_status('pending', __('Awaiting invoice payment', 'woocommerce')); | |
| $order->add_order_note(__('Customer requested invoice. Manual payment required.', 'woocommerce')); | |
| $this->send_invoice_notifications($order); | |
| wc_reduce_stock_levels($order_id); | |
| if (WC()->cart) { | |
| WC()->cart->empty_cart(); | |
| } | |
| return array( | |
| 'result' => 'success', | |
| 'redirect' => $this->get_return_url($order) | |
| ); | |
| } | |
| private function send_invoice_notifications($order) { | |
| $admin_email = get_option('admin_email'); | |
| $invoice_email = '[email protected]'; | |
| $subject = sprintf(__('Invoice Request - Order #%s', 'woocommerce'), $order->get_order_number()); | |
| $message = __("New invoice request received!\n\n", 'woocommerce'); | |
| $message .= __("Order #: ", 'woocommerce') . $order->get_order_number() . "\n"; | |
| $message .= __("Date: ", 'woocommerce') . $order->get_date_created()->format('Y-m-d H:i:s') . "\n"; | |
| $message .= __("Customer: ", 'woocommerce') . $order->get_billing_first_name() . " " . $order->get_billing_last_name() . "\n"; | |
| $message .= __("Email: ", 'woocommerce') . $order->get_billing_email() . "\n"; | |
| $message .= __("Total: ", 'woocommerce') . $order->get_formatted_order_total() . "\n\n"; | |
| $message .= __("Items:\n", 'woocommerce'); | |
| foreach ($order->get_items() as $item) { | |
| $message .= "- " . $item->get_name() . " (" . __("Qty: ", 'woocommerce') . $item->get_quantity() . ")\n"; | |
| } | |
| $attendees = get_order_attendee_info($order->get_id()); | |
| if ($attendees && is_array($attendees)) { | |
| $message .= "\n" . __("Item Assignments:\n", 'woocommerce'); | |
| foreach ($attendees as $attendee) { | |
| $prod_name = isset($attendee['product_name']) ? $attendee['product_name'] : __('Unknown', 'woocommerce'); | |
| $item_num = isset($attendee['item_number']) ? $attendee['item_number'] : '?'; | |
| $message .= "- " . $prod_name . " #" . $item_num . ": " . $attendee['name'] . " (" . $attendee['email'] . ") - " . $attendee['phone'] . "\n"; | |
| } | |
| } | |
| $message .= "\n" . __("View order: ", 'woocommerce') . admin_url('post.php?post=' . $order->get_id() . '&action=edit'); | |
| wp_mail($admin_email, $subject, $message); | |
| if ($invoice_email !== $admin_email) { | |
| wp_mail($invoice_email, $subject, $message); | |
| } | |
| } | |
| } | |
| } | |
| // 10. DISABLE ORDER NOTES FIELD | |
| add_filter('woocommerce_enable_order_notes_field', '__return_false'); | |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment