phpwoocommerceordersemail-notificationswoocommerce-checkout-fields

Attendees Custom Checkout Fields per Cart item Quantity in WooCommerce


I found this code that does exactly what I need it to, except it doesn't add the information to the email, or the order details.

So for context, we are selling tickets and want to collect information for each ticket holder.

//Custom WooCommerce Checkout Fields based on Quantity
    add_action( 'woocommerce_before_order_notes', 'person_details' );

    function person_details($checkout) {
        global $woocommerce;
    $count = $woocommerce->cart->cart_contents_count;
    $i = 1;
       for($k=2; $k<= $count; $k++) {
        $i++;
           print ('<h3>Please enter details of attendee '.$i.'</h3>');
        woocommerce_form_field( 'cstm_full_name'.$i, array(
            'type'          => 'text',
            'class'         => array('my-field-class form-row-wide'),
            'label'         => __('Full name'),
            'placeholder'   => __('Enter full name'),
            ),
            $checkout->get_value( 'cstm_full_name'.$i ));
        echo '<div class="clear"></div>';
        woocommerce_form_field( 'cstm_phone'.$i, array(
            'type'          => 'text',
            'class'         => array('my-field-class form-row-first'),
            'label'         => __('Phone'),
            'placeholder'   => __('Enter phone number'),
            ),
            $checkout->get_value( 'cstm_phone'.$i ));
        woocommerce_form_field( 'cstm_email'.$i, array(
            'type'          => 'email',
            'class'         => array('my-field-class form-row-last'),
            'label'         => __('Email address'),
            'placeholder'   => __('Enter email address'),
            ),
            $checkout->get_value( 'cstm_email'.$i ));
        echo '<div class="clear"></div>';
        woocommerce_form_field( 'cstm_address'.$i, array(
            'type'          => 'textarea',
            'class'         => array('my-field-class form-row-wide'),
            'label'         => __('Full address'),
            'placeholder'   => __('Enter full address'),
            ),
            $checkout->get_value( 'cstm_address'.$i ));
    }
    }

    /**
     * Save value of fields
     */
 
    add_action('woocommerce_checkout_update_order_meta',     'customise_checkout_field_update_order_meta');
 
    function customise_checkout_field_update_order_meta($order_id) {
    global $woocommerce;
    $count = $woocommerce->cart->cart_contents_count;
    $i = 1;
       for($k=2; $k<= $count; $k++) {
        $i++;
    if (!empty($_POST['cstm_full_name'.$i])) {
        update_post_meta($order_id, 'Name of Attendee'.$i, sanitize_text_field($_POST['cstm_full_name'.$i]));
    }
    if (!empty($_POST['cstm_phone'.$i])) {
        update_post_meta($order_id, 'Phone of Attendee'.$i, sanitize_text_field($_POST['cstm_phone'.$i]));
    }
    if (!empty($_POST['cstm_email'.$i])) {
        update_post_meta($order_id, 'Email of Attendee'.$i, sanitize_text_field($_POST['cstm_email'.$i]));
    }
    if (!empty($_POST['cstm_address'.$i])) {
        update_post_meta($order_id, 'Address of Attendee'.$i,               sanitize_text_field($_POST['cstm_address'.$i]));
        }
    }
    }

    /**
     * Add fields to order emails
     **/
    add_filter('woocommerce_email_order_meta_keys', 'my_custom_checkout_field_order_meta_keys');
    function my_custom_checkout_field_order_meta_keys( $keys ) {
    $i = 1;
    for($k=2; $k<= 50; $k++) {
    $i++;
    $keys[] = 'Name of Attendee'.$i;
    $keys[] = 'Phone of Attendee'.$i;
    $keys[] = 'Email of Attendee'.$i;
    $keys[] = 'Email of Participant '.$i;
    $keys[] = 'Address of Attendee'.$i;
    }   
    return $keys;
    }

I think some of this might be depreciated but my attempts at bringing it up to snuff have all failed.


Solution

  • I have revised the code, simplifying. I have added the necessary code to display attendees on admin orders, customer orders and email notifications.

    // Custom WooCommerce Checkout Fields based on Quantity
    add_action( 'woocommerce_before_order_notes', 'attendees_checkout_fields' );
    function attendees_checkout_fields( $checkout ) {
        echo '<h3>'.__('Attendees details').'</h3>';
    
        for($i = 1; $i <= WC()->cart->get_cart_contents_count(); $i++) {
            printf( '<h4>%s %d</h4>', __('Please enter details of the attendees'), $i );
    
            woocommerce_form_field( 'cstm_full_name'.$i, array(
                'type'          => 'text',
                'class'         => array('my-field-class form-row-wide'),
                'label'         => __('Full name'),
                'placeholder'   => __('Enter full name'),
            ), $checkout->get_value( 'cstm_full_name'.$i ));
    
            echo '<div class="clear"></div>';
    
            woocommerce_form_field( 'cstm_phone'.$i, array(
                'type'          => 'text',
                'class'         => array('my-field-class form-row-first'),
                'label'         => __('Phone'),
                'placeholder'   => __('Enter phone number'),
            ), $checkout->get_value( 'cstm_phone'.$i ));
    
            woocommerce_form_field( 'cstm_email'.$i, array(
                'type'          => 'email',
                'class'         => array('my-field-class form-row-last'),
                'label'         => __('Email address'),
                'placeholder'   => __('Enter email address'),
            ), $checkout->get_value( 'cstm_email'.$i ));
    
            echo '<div class="clear"></div>';
    
            woocommerce_form_field( 'cstm_address'.$i, array(
                'type'          => 'textarea',
                'class'         => array('my-field-class form-row-wide'),
                'label'         => __('Full address'),
                'placeholder'   => __('Enter full address'),
            ), $checkout->get_value( 'cstm_address'.$i ));
        }
    }
    
    // Utility function
    function attendee_fields_keys_labels() {
        return array(
            'cstm_full_name' => __('Name'),
            'cstm_phone'     => __('Phone'),
            'cstm_email'     => __('Email'),
            'cstm_address'   => __('Address'),
        );
    }
    
    // Save value of fields
    add_action('woocommerce_checkout_create_order', 'save_custom_checkout_fields_data');
    function save_custom_checkout_fields_data($order) {
        $count = WC()->cart->get_cart_contents_count();
        $order->update_meta_data('items_count', $count );
    
        for($i = 1; $i <= WC()->cart->get_cart_contents_count(); $i++) {
            foreach( attendee_fields_keys_labels() as $field_key => $field_label ) {
                if ( isset($_POST[$field_key.$i]) && !empty($_POST[$field_key.$i]) ) {
                    if( $field_key !== 'cstm_address' ) {
                        $order->update_meta_data($field_key.$i, sanitize_text_field($_POST[$field_key.$i]) );
                    } else {
                        $order->update_meta_data($field_key.$i, sanitize_textarea_field($_POST[$field_key.$i]) );
                    }
                }
            }
        }
    }
    
    // Display attendees on email notifications
    add_action('woocommerce_email_order_details', 'action_after_email_order_details', 25, 4 );
    function action_after_email_order_details( $order, $sent_to_admin, $plain_text, $email )
    {
        $count = $order->get_meta('items_count');
    
        if ( ! $count ) return;
    
        // The HTML Structure
        $html_output = '<h2>' . __('Attendees details') . '</h2>
        <div class="discount-info">';
    
        // Loop though the data array to set the fields
        for($i = 1; $i <= $count; $i++) {
            $html_output .= '<table cellspacing="0" cellpadding="6">
            <thead><tr><th colspan="2"><h4>' . __('Attendee') . ' ' . $i . '</h4></th></tr></thead>
            <tbody>';
    
            foreach( attendee_fields_keys_labels() as $field_key => $field_label ) {
                if( $meta_value = $order->get_meta($field_key.$i) ){
                    $html_output .= '<tr>
                        <th>' . $field_label . '</th>
                        <td>' . $meta_value . '</td>
                    </tr>';
                }
            }
            $html_output .= '</tbody></table>';
        }
        $html_output .= '</div><br>'; // HTML (end)
    
        // The CSS styling
        $styles = '<style>
            .discount-info table{width: 100%; font-family: \'Helvetica Neue\', Helvetica, Roboto, Arial, sans-serif;
                color: #737373; border: 1px solid #e4e4e4; margin-bottom:8px;}
            .discount-info table th, table.tracking-info td{text-align: left; border-top-width: 4px;
                color: #737373; border: 1px solid #e4e4e4; padding: 12px; width:58%;}
            .discount-info table td{text-align: left; border-top-width: 4px; color: #737373; border: 1px solid #e4e4e4; padding: 12px;}
        </style>';
    
        // The Output CSS + HTML
        echo $styles . $html_output;
    }
    
    // Display attendees on Customer orders
    add_action( 'woocommerce_view_order', 'woocommerce_order_attendees_table', 15 );
    add_action( 'woocommerce_thankyou', 'woocommerce_order_attendees_table', 15 );
    function woocommerce_order_attendees_table( $order_id ) {
        $order = wc_get_order($order_id);
        $count = $order->get_meta('items_count');
    
        if ( ! $count ) return;
    
        echo '<section class="woocommerce-attendees">
        <h2 class="woocommerce-attendees__title">' . esc_html__( 'Attendees', 'woocommerce' ) . '</h2>
        <table class="woocommerce-table woocommerce-table--attendees shop_table attendees">
        <tbody>';
        // Loop though the data array to set the fields
        for($i = 1; $i <= $count; $i++) {
            echo '<tr><th colspan="4">
                <h4>' . __('Attendee') . ' ' . $i . '</h4>
            </th></tr><tr>';
            
            foreach( attendee_fields_keys_labels() as $field_key => $field_label ) {
                echo '<th>'. $field_label .'</th>';
            }
            echo '</tr><tr>';
    
            foreach( attendee_fields_keys_labels() as $field_key => $field_label ) {
                if( $meta_value = $order->get_meta($field_key.$i) ){
                    echo '<td>'. $meta_value .'</td>';
                }
            }
            echo '</tr>';
        }
        echo '</tbody></table></section>';
    }
    
    // Display attendees on Admin Order edit pages: Custom metabox (right column)
    add_action( 'add_meta_boxes', 'add_attendees_metabox' );
    function add_attendees_metabox(){
        add_meta_box(
            'attendees',
            __('Attendees'),
            'attendees_metabox_content',
            'shop_order',
            'side', // or 'normal'
            'default' // or 'high'
        );
    }
    
    // Adding the content for the custom metabox
    function attendees_metabox_content() {
        $order = wc_get_order(get_the_id());
        $count = $order->get_meta('items_count');
    
        if ( ! $count ) return;
    
        for($i = 1; $i <= $order->get_meta('items_count'); $i++) {
            echo '<div style="background-color:#eee;padding:2px;margin-bottom:.4em;">
            <h4 style="margin:.5em 0;padding:2px;">Attendee '.$i.'</h4>
            <table style="text-align:left;margin-bottom:.7em;" cellpadding="2"><tbody>';
            
            foreach( attendee_fields_keys_labels() as $field_key => $field_label ) {
                if( $meta_value = $order->get_meta($field_key.$i) ){
                    echo '<tr><th valign="top">'.$field_label.':</th><td>'.$meta_value.'</td></tr>';
                }
            }
            echo '</tbody></table></div>';
        }
    }
    

    Code goes on functions.php file of your child theme (or in a plugin). Tested and works.

    Customer orders:

    enter image description here

    Email notifications:

    enter image description here

    Admin Orders

    enter image description here