Reputation: 67
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
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
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.
b) Step two Now you get the number of checkboxes corresponding to the number of seats:
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):
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):
On email notifications:
On Admin Order edit pages:
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