Skip to content

Instantly share code, notes, and snippets.

@Archie22is
Created July 1, 2025 12:58
Show Gist options
  • Save Archie22is/5cc50dc8165676b09eadafbd656dc902 to your computer and use it in GitHub Desktop.
Save Archie22is/5cc50dc8165676b09eadafbd656dc902 to your computer and use it in GitHub Desktop.
Handles frontend checkout, validation, and basic saving
/**
* 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