Search code examples
phpwordpresswoocommercecustom-fieldsemail-notifications

Display multiple grouped custom fields in WooCommerce email notifications


I have created some custom checkout fields based on whether a customer buys 1 or 2 items. The fields are called: 'Voorletters', 'Roepnaam', 'Achternaam' and 'Geboortedatum'. The code works since the data shows up in our Wordpress backend below the respective orders, but we want to include it in our e-mails as well. Ideally we would want to include this in the order completed mail that the customer receives after a successful payment, but also to the confirmation mail that the admin receives upon a new order.

Based on Add multiple custom checkout fields grouped in two columns on WooCommerce answer code, here it's what I have:

// Utility function: Get specific product total cart item quantity
function get_specific_cart_item_quantity() {
    $targeted_id = 5027; // <== Product ID to check for.
    $item_qty    = 0; // Initializing

    // Loop through cart items
    foreach ( WC()->cart->get_cart() as $item ) {
        if ( $item['product_id'] == $targeted_id ) {
            $item_qty += $item['quantity'];
        }
    }
    return $item_qty;
}

// Add custom checkout fields
add_action('woocommerce_checkout_before_customer_details', 'add_custom_checkout_fields');
function add_custom_checkout_fields() {
    $item_qty = get_specific_cart_item_quantity();
    
    if ( $item_qty ) {
        $domain  = 'woocommerce';

        echo '<div id="custom_checkout_fields">
            <h3>' . __('<b>Persoonsgegevens BHV</b>', $domain) . '</h3>
            <p>' . __('Vul a.u.b. de persoonsgegevens van de BHV kandidaten in hieronder.', $domain) . '</p>
            <div class="custom-fields-container">';
        
        $qty1 = $item_qty % 2 == 0 ? $item_qty / 2 : ( $item_qty == 1 ? 1 : ($item_qty + 1) / 2 );
        $qty2 = $item_qty == 1 ? 1 : 2;

        // Multi-loop to display custom fields based on quantity in 2 columns
        for ( $k = 1; $k <= $qty1; $k++ ) {
            $qty2 = $item_qty % 2 != 0 && $k == $qty1 ? 1 : 2;

            // 2nd Loop (letters)
            foreach ( array('Voorletters', 'Roepnaam', 'Achternaam', 'Geboortedatum') as $letter ) {
                $key = strtolower($letter);

                // 3rd Loop (Columns)
                for ( $h = 1; $h <= $qty2; $h++ ) {
                    $class = $item_qty > 1 ? (($h % 2 == 0) ? 'last' : 'first' ) : 'wide';
                    $class = $item_qty % 2 != 0 && $k == $qty1 ? 'wide' : $class;

                    $index = $item_qty == 1 ? 1 : 2;
                    $index = in_array($class, ['first', 'wide']) ? ($k*2)-1 : $k*2;

                    $field = "custom_field_{$key}{$index}";
                    $label = sprintf('%s %d %s', __('Kandidaat', $domain), $index, $letter);
                
                    woocommerce_form_field( $field, array(
                        'type'          => 'text',
                        'label'         => $label,
                        'placeholder'   => '',
                        'class'         => array('custom-field form-row-'.$class),
                        'required'      => true, // or false
                    ), WC()->checkout->get_value( $field ) );
                }
            }
        }
        echo '</div></div>';
    }
}

// Validate custom fields
add_action( 'woocommerce_after_checkout_validation', 'validate_custom_checkout_fields', 10, 2 );
function validate_custom_checkout_fields( $data, $errors ) {
    if ( did_action('woocommerce_checkout_process') >= 2 ) return;

    $item_qty = get_specific_cart_item_quantity();

    if ( $item_qty ) {
        $domain   = 'woocommerce';
        $break    = false;

        // 1st Loop (Letters)
        foreach ( array('Voorletters', 'Roepnaam', 'Achternaam', 'Geboortedatum') as $letter ) {
            $key   = strtolower($letter);

            // 2nd Loop (Numbers)
            for ( $i = 1; $i <= $item_qty; $i++ ) {
                $field = "custom_field_{$key}{$i}";
                
                if ( isset($_POST[$field]) && empty($_POST[$field]) ) {
                    $errors->add( 'validation', __('Vul a.u.b. de verplichte velden in.', $domain), 'error' );
                    $break = true;
                    break;
                }
            }
            if ( $break ) break;
        }
    }
}

// Save custom field data as custom order meta data
add_action( 'woocommerce_checkout_create_order', 'save_custom_checkout_fields', 10, 2 );
function save_custom_checkout_fields( $order, $data ) {
    $item_qty = get_specific_cart_item_quantity();

    if ( $item_qty ) {
        // 1st Loop (Letters)
        foreach ( array('Voorletters', 'Roepnaam', 'Achternaam', 'Geboortedatum') as $letter ) {
            $key   = strtolower($letter);

            // 2nd Loop (Numbers)
            for ( $i = 1; $i <= $item_qty; $i++ ) {
                $field = "custom_field_{$key}{$i}";
                
                if ( isset($_POST[$field]) && ! empty($_POST[$field]) ) {
                    $order->update_meta_data( $field, sanitize_text_field($_POST[$field]) );
                }
            }
        }
    }
}

Solution

  • I have revisited lightly all your code. The following will display your custom fields data in Admin "New order" and "Customer completed order" email notifications:

    // Utility function: Get specific product total cart item quantity
    function get_specific_cart_item_quantity() {
        $targeted_id = 5027; // <== Product ID to check for.
        $item_qty    = 0; // Initializing
    
        // Loop through cart items
        foreach ( WC()->cart->get_cart() as $item ) {
            if ( $item['product_id'] == $targeted_id ) {
                $item_qty += $item['quantity'];
            }
        }
        return $item_qty;
    }
    
    // Utility function: Get participant fields labels
    function get_candidate_fields_labels() {
        return array('Voorletters', 'Roepnaam', 'Achternaam', 'Geboortedatum');
    }
    
    // Add custom checkout fields
    add_action('woocommerce_checkout_before_customer_details', 'add_custom_checkout_fields');
    function add_custom_checkout_fields() {
        $item_qty = get_specific_cart_item_quantity();
        
        if ( $item_qty ) {
            $domain  = 'woocommerce';
    
            echo '<div id="custom_checkout_fields">
                <h3>' . __('<b>Persoonsgegevens BHV</b>', $domain) . '</h3>
                <p>' . __('Vul a.u.b. de persoonsgegevens van de BHV kandidaten in hieronder.', $domain) . '</p>
                <div class="custom-fields-container">';
            
            $qty1 = $item_qty % 2 == 0 ? $item_qty / 2 : ( $item_qty == 1 ? 1 : ($item_qty + 1) / 2 );
            $qty2 = $item_qty == 1 ? 1 : 2;
    
            // Multi-loop to display custom fields based on quantity in 2 columns
            for ( $k = 1; $k <= $qty1; $k++ ) {
                $qty2 = $item_qty % 2 != 0 && $k == $qty1 ? 1 : 2;
    
                // 2nd Loop (letters)
                foreach ( get_candidate_fields_labels() as $letter ) {
                    $key = strtolower($letter);
    
                    // 3rd Loop (Columns)
                    for ( $h = 1; $h <= $qty2; $h++ ) {
                        $class = $item_qty > 1 ? (($h % 2 == 0) ? 'last' : 'first' ) : 'wide';
                        $class = $item_qty % 2 != 0 && $k == $qty1 ? 'wide' : $class;
    
                        $index = $item_qty == 1 ? 1 : 2;
                        $index = in_array($class, ['first', 'wide']) ? ($k*2)-1 : $k*2;
    
                        $field = "custom_field_{$key}{$index}";
                        $label = sprintf('%s %d %s', __('Kandidaat', $domain), $index, $letter);
                    
                        woocommerce_form_field( $field, array(
                            'type'          => 'text',
                            'label'         => $label,
                            'placeholder'   => '',
                            'class'         => array('custom-field form-row-'.$class),
                            'required'      => true, // or false
                        ), WC()->checkout->get_value( $field ) );
                    }
                }
            }
            echo '</div></div>';
        }
    }
    
    // Validate custom fields
    add_action( 'woocommerce_after_checkout_validation', 'validate_custom_checkout_fields', 10, 2 );
    function validate_custom_checkout_fields( $data, $errors ) {
        if ( did_action('woocommerce_after_checkout_validation') >= 2 ) return;
    
        $item_qty = get_specific_cart_item_quantity();
    
        if ( $item_qty ) {
            $domain   = 'woocommerce';
            $break    = false;
    
            // 1st Loop (Letters)
            foreach ( get_candidate_fields_labels() as $label ) {
                $key   = strtolower($label);
    
                // 2nd Loop (Numbers)
                for ( $i = 1; $i <= $item_qty; $i++ ) {
                    $field = "custom_field_{$key}{$i}";
                    
                    if ( isset($_POST[$field]) && empty($_POST[$field]) ) {
                        $errors->add( 'validation', __('Vul a.u.b. de verplichte velden in.', $domain), 'error' );
                        $break = true;
                        break;
                    }
                }
                if ( $break ) break;
            }
        }
    }
    
    // Save custom field data as custom order meta data
    add_action( 'woocommerce_checkout_create_order', 'save_custom_checkout_fields', 10, 2 );
    function save_custom_checkout_fields( $order, $data ) {
        $item_qty = get_specific_cart_item_quantity();
    
        if ( $item_qty ) {
            // 1st Loop (Letters)
            foreach ( get_candidate_fields_labels() as $label ) {
                $key   = strtolower($label);
    
                // 2nd Loop (Numbers)
                for ( $i = 1; $i <= $item_qty; $i++ ) {
                    $field = "custom_field_{$key}{$i}";
                    
                    if ( isset($_POST[$field]) && ! empty($_POST[$field]) ) {
                        $order->update_meta_data( $field, sanitize_text_field($_POST[$field]) );
                    }
                }
            }
            $order->update_meta_data( 'participants', $item_qty ); // Add the number of participants
        }
    }
    
    // Display custom fields data on email notifications
    add_action( 'woocommerce_email_order_details', 'display_on_email_notifications', 20, 4 );
    function display_on_email_notifications( $order, $sent_to_admin, $plain_text, $email ) {
        $item_qty = $order->get_meta('participants');
    
        // Targeting "New order" and "Customer completed order" email notifications
        if ( $item_qty > 0 && in_array($email->id, ['new_order','customer_completed_order']) ) {
            $domain  = 'woocommerce';
    
            echo '<style>
            .personal-info table{width: 100%; font-family: \'Helvetica Neue\', Helvetica, Roboto, Arial, sans-serif;
                color: #737373; border: 1px solid #e4e4e4; margin-bottom:8px;}
            .personal-info table th, .personal-info table td{text-align: left; border-top-width: 4px; color: #737373; 
                border: 1px solid #e4e4e4; padding: 12px; width:'.($item_qty == 1 ? '100%' : '50%').';}
            .personal-info table td h4{font-size:92%; margin-block-start: 0; margin-block-end: 1em;}
            .personal-info table td p{font-size:84%; line-height:20px; margin:0 !important;}
            </style>';
    
            echo '<div class="personal-info">
                <h3>' . __('<b>Persoonsgegevens BHV</b>', $domain) . '</h3>
                <p>' . __('Vul a.u.b. de persoonsgegevens van de BHV kandidaten in hieronder.', $domain) . '</p>
                <table cellspacing="0" cellpadding="6"><tbody>
                <tr>';
            
            for ( $i = 1; $i <= $item_qty; $i++ ) {
                echo '<td>';
                printf('<h4>%s %d</h4><p>', __('Kandidaat', $domain), $i);
                // 2nd Loop (letters)
                foreach ( get_candidate_fields_labels() as $label ) {
                    $key   = strtolower($label);
                    $field = "custom_field_{$key}{$i}";
                    printf('<strong>%s:</strong> %s<br>', $label, $order->get_meta($field));
                }
                echo '</p></td>';
                echo $i % 2 == 0 && $i < $item_qty ? '</tr><tr>' : '';
                echo $item_qty % 2 != 0 && $i == $item_qty ? '<td><h4>&nbsp;</h4><p>&nbsp;</p></td>' : '';
            }
            echo '</tr></tbody></table></div><br>';
        }
    }
    

    The participant(s) custom fields data will be displayed in 2 columns, a bit like in checkout.

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