Dynamic checkout custom fields per persons and items in Woocommerce bookings

折月煮酒 提交于 2021-02-18 17:55:44

问题


For a bookings website I'm trying to create a function which makes it possible to add an attendee list, based on the amount of persons. I've already got the code for a single booking, thanks to LoicTheAztec. That part is working fine.

I also need the same functionality for multiple bookings. How can I achieve this?

Here is the code:

//* Add a new checkout field
add_filter( 'woocommerce_checkout_fields', 'ppp_filter_checkout_fields' );
function ppp_filter_checkout_fields($fields){
    $fields['extra_fields'] = array(
    'participant_details' => array(
        'type' => 'participant_details',
        'required'      => false,
        'label' => __( 'Participant Details' )
        ),
    );

    // Add a "persons" hidden input field
    foreach( WC()->cart->get_cart() as $cart_item ) {
        $persons = $cart_item['booking']['_persons'][0];
    }
    echo '<input type="hidden" name="persons" value="' . $persons . '">';

    return $fields;
}

//* Add the field to the checkout
add_filter( 'woocommerce_form_field_participant_details', 'ppp_filter_checkout_field_group', 10, 4 );
function ppp_filter_checkout_field_group( $field, $key, $args, $value ){
    $op_cart_count = WC()->cart->get_cart_contents_count();

    $items = WC()->cart->get_cart();

    foreach($items as $item) {
        $person = $item['booking']['_persons'][0];
    }

    if ($person > 1) {

        $html = '';

        $html .= "<h3>Deelnemers</h3>";

        for ( $i = 1; $i < $person; $i++) {
            $counter = $i + 1;

            $html .= "Deelnemer ". $counter . "<br>";

            $html .= woocommerce_form_field( "participant_details[$i][full_name]", array(
                "type" => "text",
                "return" => true,
                "value" => "",
                "required"      => true,
                "label" => __( "Naam" )
                )
            );
            $html .= woocommerce_form_field( "participant_details[$i][email_address]", array(
                "type" => "email",
                "return" => true,
                "value" => "",
                "required"      => true,
                "label" => __( "Emailadres" )
                )
            );

        }
        return $html;
    }
}

//* display the extra field on the checkout form
add_action( 'woocommerce_checkout_after_customer_details' ,'ppp_extra_checkout_fields' );
function ppp_extra_checkout_fields(){

    $checkout = WC()->checkout();

    foreach ( $checkout->checkout_fields['extra_fields'] as $key => $field ) :

        woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );

    endforeach;
}

//* Validate custom checkout fields
add_action( 'woocommerce_after_checkout_validation', 'ppp_checkout_field_participant_details_validation', 20, 2 );
function ppp_checkout_field_participant_details_validation( $data, $errors ){
    if ( isset( $_POST['persons'] ) && $_POST['persons'] > 1 ){

        for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons'] ); $i++, $j++ ) {
            if ( empty( $_POST['participant_details'][$i]['full_name'] ) )
                $errors->add( 'participant_'.$i.'_full_name',  __( "Please fill in the participant $j full name" ), 'error' );

            if ( empty( $_POST['participant_details'][$i]['email_address'] ) )
                $errors->add( 'participant_'.$i.'_email_address',  __( "Please fill in the participant $j email address" ), 'error' );
        }
    }
}


//* Sanitize our custom field
function ppp_custom_process_checkout_field_participant_details( $posted ){

    $clean = array();

    foreach( $posted as $participant ){
        $details = ppp_custom_checkout_clean_participant_details( $participant );

        if( ! empty( $details ) ){
            $clean[] = $details;
        }
    }

    return $clean;
}
add_filter( 'woocommerce_process_checkout_participant_details_field', 'ppp_custom_process_checkout_field_participant_details' );

//*
function ppp_custom_checkout_clean_participant_details( $participant = array() ){
    $details = array();
    if( isset( $participant["full_name"] ) ){
        $details['full_name'] = sanitize_text_field( $participant["full_name"] );
    }
    if( isset( $participant["email_address"] ) ){
        $details['email_address'] = sanitize_text_field( $participant["email_address"] );
    }
    return $details;
}


//* Update_post_meta
add_action( 'woocommerce_checkout_update_order_meta', 'ppp_custom_checkout_field_update_order_meta', 10, 2 );
function ppp_custom_checkout_field_update_order_meta( $order_id, $posted ){

    if( ! empty( $posted["participant_details"] ) ){
        update_post_meta( $order_id, "_participant_details", $posted["participant_details"] );
    } else {
        delete_post_meta( $order_id, "_participant_details" );
    }

}
add_action( 'woocommerce_checkout_update_order_meta', 'ppp_custom_checkout_field_update_order_meta', 10, 2 );

回答1:


You missed an additional loop (the cart items loop) … I have revisited completely your code make it work for multiple item (different items).

So the fields are now dynamically generated by items and by persons on each item:

// Conditional function: Check if at least there is more than one person in cart items
function ppp_check_persons(){
    $enabled    = array();

    foreach( WC()->cart->get_cart() as $cart_item) {
        if( isset($cart_item['booking']['_persons'][0])
        && $cart_item['booking']['_persons'][0] > 1 )
        {
            $enabled = true;
            break;
        }
    }
    return $enabled;
}

// Add a new checkout field
add_filter( 'woocommerce_checkout_fields', 'ppp_filter_checkout_fields' );
function ppp_filter_checkout_fields($fields){

    $fields['extra_fields'] = array( 'participant' => array(
        'type' => 'participant',
        'required'      => false,
        'label' => __( 'Participant Details' )
    ) );

    $cart_items = WC()->cart->get_cart();
    $count      = 1;

    echo '<input type="hidden" name="items_count" value="' . sizeof($cart_items) . '">';

    if( ! ppp_check_persons() ) return $fields; // Exit (not enough persons)

    // Add "persons" hidden input fields for each cart_item
    foreach( WC()->cart->get_cart() as $cart_item ) {
        $persons = $cart_item['booking']['_persons'][0];
        echo '<input type="hidden" name="persons_'.$count.'" value="' . $persons . '">';
        $count++;
    }

    return $fields;
}

// Add the field to the checkout
add_filter( 'woocommerce_form_field_participant', 'ppp_filter_checkout_field_group', 10, 4 );
function ppp_filter_checkout_field_group( $field, $key, $args, $value ){
    if( ! ppp_check_persons() ) return $fields; // Exit (not enough persons)

    ob_start();

    echo "<h3>Deelnemers</h3>";

    $cart_items = WC()->cart->get_cart();
    $nb_items   = sizeof($cart_items);
    $count      = 1;

    // Loop through cart items;
    foreach( $cart_items as $cart_item) {
        $persons = $cart_item['booking']['_persons'][0];

        if ( $persons > 1  && $persons != 1 ) {
            echo '<h4 style="font-size:135%;">Item'.$count.'</h4>';

            for ( $i = 1, $j = 2; $i < $persons; $i++, $j++)
            {
                echo '<span style="margin-bottom:12px;display:inline-block;font-size:112%;">' . __("Deelnemer") . ' ' . $j . '</span>';

                echo woocommerce_form_field( "participant[$count][$j][fname]", array(
                    "type" => "text",
                    "return" => true,
                    "value" => "",
                    "required"      => true,
                    "label" => __( "Naam" )
                ) );

                echo woocommerce_form_field( "participant[$count][$j][email]", array(
                    "type" => "email",
                    "return" => true,
                    "value" => "",
                    "required"      => true,
                    "label" => __( "Emailadres" )
                ) );

            }
            echo '<br>';
        }
        $count++;
    }
    return ob_get_clean();
}

// display the extra field on the checkout form
add_action( 'woocommerce_checkout_after_customer_details' ,'ppp_extra_checkout_fields' );
function ppp_extra_checkout_fields(){
    $checkout = WC()->checkout();

    foreach ( $checkout->checkout_fields['extra_fields'] as $key => $field )
    {
        woocommerce_form_field( $key, $field, $checkout->get_value( $key ) );
    }
}

// Validate custom checkout fields
add_action( 'woocommerce_after_checkout_validation', 'ppp_checkout_field_participant_details_validation', 20, 2 );
function ppp_checkout_field_participant_details_validation( $data, $errors ){
    if ( !( isset($_POST['items_count']) && ! empty($_POST['items_count']) ) ) return; // Exit

    for ( $h = 1; $h <= esc_attr( $_POST['items_count'] ); $h++ )
    {
        if ( isset( $_POST['persons_'.$h] ) && $_POST['persons_'.$h] > 1 )
        {
            for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons_'.$h] ); $i++, $j++ )
            {
                if ( isset( $data['participant'][$h][$j]['fname'] ) && empty( $data['participant'][$h][$j]['fname'] ) )
                    $errors->add( 'participant_'.$h.'_'.$j.'_fname',  __( "Please fill in the participant $j full name (Item $h)" ), 'error' );

                if ( isset( $data['participant'][$h][$j]['email'] ) && empty( $data['participant'][$h][$j]['email'] ) )
                    $errors->add( 'participant_'.$h.'_'.$j.'_email',  __( "Please fill in the participant $j email address (Item $h)" ), 'error' );
            }
        }
    }
}


// Save custom fields values in the order as meta data
add_action( 'woocommerce_checkout_create_order', 'ppp_custom_fields_checkout_create_order', 20, 2 );
function ppp_custom_fields_checkout_create_order( $order, $data ){
    if ( !( isset($_POST['items_count']) && ! empty($_POST['items_count']) ) ) return; // Exit

    // Save number of different items in cart
    $order->update_meta_data( '_items_count', esc_attr( $_POST['items_count'] ) );

    for ( $h = 1; $h <= esc_attr( $_POST['items_count'] ); $h++ )
    {
        if ( isset( $_POST['persons_'.$h] ) && $_POST['persons_'.$h] > 1 )
        {
            // Save number of persons for each item in cart
            $order->update_meta_data( '_item_'.$h.'_persons', esc_attr( $_POST['persons_'.$h] ) );

            for ( $i = 1, $j = 2; $i < esc_attr( $_POST['persons_'.$h] ); $i++, $j++ )
            {
                // Save number of persons for each item in cart
                if ( isset( $data['participant'][$h][$j]['fname'] ) ){
                    $full_name = sanitize_text_field( $data['participant'][$h][$j]['fname'] );
                    $order->update_meta_data( '_participant_'.$h.'_'.$j.'_fname', $full_name );
                }

                if ( isset( $data['participant'][$h][$j]['email'] ) ){
                    $email_address = sanitize_text_field( $data['participant'][$h][$j]['email'] );
                    $order->update_meta_data( '_participant_'.$h.'_'.$j.'_email', $email_address );
                }
            }
        }
    }
}

Code goes in function.php file of your active child theme (or active theme). Tested and works.

Displaying the data in orders front-end and backend and/or email notifications is just too broad for this answer that handle everything else. To display theis data in admin order edit pages, below customers details, is not a good idea and should be done in a custom metabox instead.



来源:https://stackoverflow.com/questions/50525386/dynamic-checkout-custom-fields-per-persons-and-items-in-woocommerce-bookings

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!