Sir_Nik
Sir_Nik

Reputation: 67

Collect checked Checkboxes and save values in Woocommerce order meta

I need kind of a seat reservation extension for woocommerce. Since most of the available plugins don't fit to well or don't work at all, i decided to try it myself.

Create the field (Product Meta) to store which seats are booked

add_action( 'woocommerce_product_data_panels', 'srd_seats' );
function srd_seats() {
    global $woocommerce, $post;

        ?><div id="srd_seating_data" class="panel woocommerce_options_panel"><?php
        woocommerce_wp_checkbox(
        array(
            'id'            => '_seat_1',
            'label'         => __('1', 'woocommerce' ),
            )
        );
            woocommerce_wp_checkbox(
        array(
            'id'            => '_seat_2',
            'label'         => __('2', 'woocommerce' ),
            )
        );
            woocommerce_wp_checkbox(
        array(
            'id'            => '_seat_3',
            'label'         => __('3', 'woocommerce' ),
            )
        );
            woocommerce_wp_checkbox(
        array(
            'id'            => '_seat_4',
            'label'         => __('4', 'woocommerce' ),
            )
        );
            woocommerce_wp_checkbox(
        array(
            'id'            => '_seat_5',
            'label'         => __('5', 'woocommerce' ),
            )
        );

Saving the data

 add_action( 'woocommerce_process_product_meta', 'srd_seatings_save' );
function srd_seatings_save( $post_id ){

    $woocommerce_checkbox = isset( $_POST['_seat_1'] ) ? 'yes' : 'no';
    update_post_meta( $post_id, '_seat_1', $woocommerce_checkbox );
    $woocommerce_checkbox = isset( $_POST['_seat_2'] ) ? 'yes' : 'no';
    update_post_meta( $post_id, '_seat_2', $woocommerce_checkbox );
    $woocommerce_checkbox = isset( $_POST['_seat_3'] ) ? 'yes' : 'no';
    update_post_meta( $post_id, '_seat_3', $woocommerce_checkbox );
    $woocommerce_checkbox = isset( $_POST['_seat_4'] ) ? 'yes' : 'no';
    update_post_meta( $post_id, '_seat_4', $woocommerce_checkbox );
    $woocommerce_checkbox = isset( $_POST['_seat_5'] ) ? 'yes' : 'no';
    update_post_meta( $post_id, '_seat_5', $woocommerce_checkbox );

Output as checkboxes on checkout Page Output all values as checkboxes: Booked seats get a special treatment and are disabled.

add_action( 'woocommerce_before_order_notes' , 'srd_seat_reservation');

function srd_seat_reservation($checkout){

    // Loop through cart item quantity
    foreach( WC()->cart->get_cart() as $cart_item ) {

        $seats = array( '_seat_1',
                        '_seat_2',
                        '_seat_3',
                        '_seat_4',
                        '_seat_5',
                            );

        foreach ($seats as $seat) {
        $seatnumber = preg_replace('/[^0-9.]+/', '', $seat);
        if ( get_post_meta( $cart_item[ 'product_id' ], $seat, true) == 'yes'){
            echo '<input type="checkbox" disabled="disabled" checked="checked">'.$seatnumber.'<br>';}
            else {
            echo '<input type="checkbox" name="checkboxseat[]" value="'.$seatnumber.'">'.$seatnumber.'<br>';
                        }
            }
    }
}

Validate the selected fields Customer needs to select exactly as many seats as there are items in cart.

    add_action('woocommerce_checkout_process', 'srd_seating_process');
function srd_seating_process() {
        $quantity = WC()->cart->get_cart_contents_count(); // Get cart quantity
        $checked_arr = count($_POST['checkboxseat']); // Get Number of checked Checkboxes

        if ($quantity > $checked_arr)
                wc_add_notice( __( 'Bitte wählen Sie für jeden Teilnehmer einen Sitzplatz.', 'woocommerce' ), 'error' );
        if ($quantity < $checked_arr)
                wc_add_notice( __( 'Sie haben zu viele Sitzplätze ausgewählt.', 'woocommerce' ), 'error' );
}

My problem The next step would be to save the value ($seatnumber) of all selected checkboxes to the order meta and to update the product meta. I am struggeling to collect the selected checkboxes and save the values. Please see below my attempt of achieving it. Any help is highly appreciated! =)

add_action('woocommerce_checkout_create_order', 'srd_seating_create_order', 20, 2 );
function srd_seating_create_order( $order, $data ) {


    foreach($_POST['checkboxseat'] as $check) {
                $order->update_meta_data( 'Sitzplatz' , $check );
        }
}

Upvotes: 1

Views: 2799

Answers (2)

Sir_Nik
Sir_Nik

Reputation: 67

// Update the order meta with the seats chosen
add_action('woocommerce_checkout_create_order', 'srd_seat_create_order', 20, 2);
function srd_seat_create_order( $order, $data ) {
    $checks = $_POST['checkboxseat'];

    foreach( WC()->cart->get_cart() as $cart_item ) {
        foreach ($checks as $check){
            $order->update_meta_data( '_sitzplatz'.$check , $check);
            update_post_meta( $cart_item[ 'product_id'], $check , 'yes' );
        }
    }}

UPDATE Now it works =)

Upvotes: 0

LoicTheAztec
LoicTheAztec

Reputation: 253784

I prefer to answer in this thread than in your last related question.

You say that your code works, but there is some mistakes and oversights, so here is the complete revisited code, that will really save the data to the order and display it everywhere:

1) On product backend (settings):

// Add a custom tab to product pages settings
add_filter( 'woocommerce_product_data_tabs', 'add_custom_product_tab_settings' , 99 , 1 );
function add_custom_product_tab_settings( $product_data_tabs ) {
    $product_data_tabs['seats'] = array(
        'label' => __( 'Seats', 'my_text_domain' ),
        'target' => 'seats_content',
    );
    return $product_data_tabs;
}

// The content of your custom product tab
add_action( 'woocommerce_product_data_panels', 'custom_product_tab_settings_content' );
function custom_product_tab_settings_content() {
    global $post;

    echo '<div id="seats_content" class="panel woocommerce_options_panel"><div class="options_group">';

    $seats_number = (int) get_post_meta( $post->ID, '_seats', true );

    $style1 = 'style="font-size:14px;font-weight:bold;"';
    $style2 = 'style="color:#E32636;"';
    $style3 = 'style="font-size:14px;font-style:italic;"';

    if( ! ( $seats_number > 0 ) ) {
        echo "<p $style1>" . sprintf( __('First, %s and %s (save)', 'woocommerce'),
        "<span $style2>" . __('define the number of seats', 'woocommerce') . "</span>",
        "<span $style2>" . __('Click on "Update"', 'woocommerce') . "</span>" ) . "</p>";
    }

    // Set the number of seats
    woocommerce_wp_text_input( array(
        'id'     => '_seats',
        'label'  => __('Number of seats'),
        'type'   => 'number',
        'value'  => ( $seats_number > 0 ? $seats_number : 0 ),
    ));

    echo '</div><div class="options_group">';

    if( $seats_number > 0 ) {
        // Loop through defined seats and display a checkbox for each
        for ( $i = 1; $i <= $seats_number; $i++) {
            woocommerce_wp_checkbox( array(
                'id'            => '_seat_'.$i,
                'label'         => $i,
            ));
        }
    } else {
        echo "<p $style3>" . __('No defined seats number yet', 'woocommerce') . '</p>';
    }
    echo '</div></div>';
}

// Saving the data from your custom tab fields settings
add_action( 'woocommerce_process_product_meta', 'save_custom_product_data' );
function save_custom_product_data( $post_id ){
    if( isset($_POST['_seats']) ){
        // Update the seats number
        update_post_meta( $post_id, '_seats', esc_attr($_POST['_seats']) );

        // Loop through seats
        for ( $i = 1; $i <= esc_attr($_POST['_seats']); $i++) {
            $value = isset( $_POST['_seat_'.$i] ) ? 'yes' : 'no';
            update_post_meta( $post_id, '_seat_'.$i, $value );
        }
    }
}

a) Step one: You will have to set first the number of seats for the product (when the value is zero, there is no checkboxes fields for the seats) and save.

enter image description here

b) Step two Now you get the number of checkboxes corresponding to the number of seats:

enter image description here


2) Front end - On checkout page (Display the available bookable seats fields):

add_action( 'woocommerce_before_order_notes' , 'checkout_seats_reservation');
function checkout_seats_reservation($checkout){
    $item_count = 0;

    echo '<h3 id="booking-seats">'.__("Book your purchased seats", "Woocommerce").'</h3>';

    // Loop through cart item quantity
    foreach( WC()->cart->get_cart() as $cart_item ) {
        $item_count++;
        $pid = $cart_item['product_id']; // The product Id

        echo '<div class="item-seats item-'.$item_count.' product-'.$pid.'">
        <p>Item '.$item_count.': "'. $cart_item['data']->get_name().'"
        <em>(Purchased seats: <strong>'.$cart_item['quantity'].'</strong>)<em><p>
        <ul style="list-style: none">';

        // Get the number of seats for the current item (product)
        $seats_number = get_post_meta( $pid, '_seats', true );

        for ( $i = 1; $i <= $seats_number; $i++) {
            if ( get_post_meta( $pid, '_seat_'.$i, true) === 'yes') {
                echo '<li><input type="checkbox" disabled="disabled" checked="checked"><label>'.$i.'</label></li>';
            } else {
                echo '<li><input type="checkbox" name="checkboxseat_'.$pid.'[]" value="'.$i.'"><label>'.$i.'</label></li>';
            }
        }
        echo '<ul></p></div>';
    }
}

// Checkout Fields validation
add_action('woocommerce_checkout_process', 'seats_checkout_fields_validation');
function seats_checkout_fields_validation() {
    $cart        = WC()->cart;
    $quantity    = $cart->get_cart_contents_count(); // Get cart quantity
    $seats_count = 0;
    $unavailable = false;

    // Loop through cart items
    foreach( $cart->get_cart() as $cart_item ){
        $pid = $cart_item['product_id']; // The product ID
        if( isset($_POST['checkboxseat_'.$pid]) ){
            $checkboxseat = (array) $_POST['checkboxseat_'.$pid];

            // Loop through selected
            foreach( $checkboxseat as $seat ) {
                // Check that selected seats are still available when order is submitted
                if ( get_post_meta( $pid, '_seat_'.$seat, true) === 'yes') {
                    $unavailable = true;
                    break;
                }
                $seats_count++;
            }
        }
    }

    if( $unavailable ) {
        wc_add_notice( __( 'Error: Some selected seats are not available anymore.', 'woocommerce' ), 'error' );
    } elseif ( $quantity > $seats_count ) {
        wc_add_notice( __( 'Bitte wählen Sie für jeden Teilnehmer einen Sitzplatz.', 'woocommerce' ), 'error' );
    } elseif ( $quantity < $seats_count ) {
        wc_add_notice( __( 'Sie haben zu viele Sitzplätze ausgewählt.', 'woocommerce' ), 'error' );
    }
}

On checkout page, where checkboxes appear (Here 2 items):

enter image description here


3) Save the submitted data to Order, Update related products and display the chosen seats everywhere:

// Update the order meta data with the chosen seats raw array data
add_action('woocommerce_checkout_create_order', 'save_seats_reservation_to_order_and_update_product', 10, 2);
function save_seats_reservation_to_order_and_update_product( $order, $data ) {
    $seats_arr   = array();
    // Loop through order items
    foreach( $order->get_items() as $item ) {
        $pid = $item->get_product_id();

        if( isset( $_POST['checkboxseat_'.$pid]) ) {
            $seats = (array) $_POST['checkboxseat_'.$pid];
            // Loop through submitted seats
            foreach ( $seats as $seat ){
                // Update seats data in the product
                update_post_meta( $pid, '_seat_'.$seat, 'yes' );
            }
            // Set and format our main array with the order item chosen seats
            $seats_arr[] = $seats;
        }
    }
    // Save selected seats multi-dimentional array data
    $order->update_meta_data( '_sitzplatz', $seats_arr );
}

// Save chosen seats to each order item as custom meta data and display order items chosen seats everywhere
add_action('woocommerce_checkout_create_order_line_item', 'save_order_item_seats_reservation', 10, 4 );
function save_order_item_seats_reservation( $item, $cart_item_key, $values, $order ) {
    // Get the chosen seats data from the order
    if( isset( $_POST['checkboxseat_'.$item->get_product_id()]) ) {
        $sitzplatz = $_POST['checkboxseat_'.$item->get_product_id()];
        $value     = implode( ', ', $sitzplatz );

        // Save selected item seats to each order item as custom meta data
        $item->update_meta_data( __('Sitzplatz'), $value );
    }
}

On Order received (thank you):

enter image description here

On email notifications:

enter image description here

On Admin Order edit pages:

enter image description here

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

You should need to restyle things a bit to make it nicer.

Upvotes: 1

Related Questions