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 );
}
}
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.
// 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 =)
Related
I am trying to combine the two responses from [https://stackoverflow.com/questions/62943477/set-quantity-minimum-maximum-and-step-at-product-level-in-woocommerce ] and Decimal quantity step for specific product categories in WooCommerce but I can't figure out how to edit the first lot of code so that it allows decimal quantity steps.
// Displaying quantity setting fields on admin product pages
add_action( 'woocommerce_product_options_pricing', 'wc_qty_add_product_field' );
function wc_qty_add_product_field() {
global $product_object;
$values = $product_object->get_meta('_qty_args');
woocommerce_wp_text_input( array(
'id' => 'qty_step',
'type' => 'number',
'label' => __( 'Quantity step', 'woocommerce-quantity-step' ),
'placeholder' => '',
'desc_tip' => 'true',
'description' => __( 'Optional. Set quantity step (a number greater than 0)', 'woocommerce' ),
'custom_attributes' => array( 'step' => 'any', 'min' => '1'),
'value' => isset($values['qty_step']) && $values['qty_step'] > 1 ? (int) $values['qty_step'] : 1,
) );
echo '</div>';
}
// Save quantity setting fields values
add_action( 'woocommerce_admin_process_product_object', 'wc_save_product_quantity_settings' );
function wc_save_product_quantity_settings( $product ) {
if ( isset($_POST['qty_args']) ) {
$values = $product->get_meta('_qty_args');
'qty_step' => isset($_POST['qty_step']) && $_POST['qty_step'] > 1 ? (int) wc_clean($_POST['qty_step']) : 1,
) );
} else {
$product->update_meta_data( '_qty_args', array() );
}
}
// The quantity settings in action on front end
add_filter( 'woocommerce_quantity_input_args', 'filter_wc_quantity_input_args', 99, 2 );
function filter_wc_quantity_input_args( $args, $product ) {
if ( $product->is_type('variation') ) {
$parent_product = wc_get_product( $product->get_parent_id() );
$values = $parent_product->get_meta( '_qty_args' );
} else {
$values = $product->get_meta( '_qty_args' );
}
if ( ! empty( $values ) ) {
// Step value
if ( isset( $values['qty_step'] ) && $values['qty_step'] > 1 ) {
$args['step'] = $values['qty_step'];
}
}
return $args;
}
// Ajax add to cart, set "min quantity" as quantity on shop and archives pages
add_filter( 'woocommerce_loop_add_to_cart_args', 'filter_loop_add_to_cart_quantity_arg', 10, 2 );
function filter_loop_add_to_cart_quantity_arg( $args, $product ) {
$values = $product->get_meta( '_qty_args' );
if ( ! empty( $values ) ) {
// Min value
if ( isset( $values['qty_min'] ) && $values['qty_min'] > 1 ) {
$args['quantity'] = $values['qty_min'];
}
}
return $args;
}
I've tried editing the values to a decimal unit but it's not stepping up by that value and it's not saving the value.
In WooCommerce using the plugin Admin Custom Order Fields, I have a added a custom fields "Rebates Status" with 3 values "No Rebates", "Unpaid" and "Paid", on WooCommerce admin Orders list.
I have also displayed that on the view order screen just like the screenshot below:
Now I would like to bulk update the Rebates Status on selected orders, just as wooCommerce allow to do it for orders status bulk change.
Based on "Process custom bulk action on admin Orders list in Woocommerce" answer thread, I successfully added the 3 Rebates statuses on the bulk edit dropdown (as you can see on the first screenshot):
add_filter( 'bulk_actions-edit-shop_order', 'decrease_meals_orders_bulk_actions' );
function decrease_meals_orders_bulk_actions( $bulk_actions ) {
$bulk_actions['mr_norebates'] = 'Mark Transactions as No Rebates';
$bulk_actions['mr_unpaid'] = 'Mark Transactions as Unpaid';
$bulk_actions['mr_paid'] = 'Mark Transactions as Paid';
return $bulk_actions;
}
But no changes are applied when I try to bulk update the Rebates status for selected orders.
The meta key for Rebates Status is _wc_acof_2
Im stuck also and don't know how to solve the problem.
Any help is appreciated.
This is the complete, compact and optimized way to make it work for each of the 3 actions, to bulk update your custom "Rebate status" displaying a summary notice:
// Your settings in a function
function custom_admin_orders_bulk_actions( $labels = false ){
$domain = 'woocommerce';
return array(
'mr_norebates' => $labels ? __('No Rebates', $domain) : 'norebates',
'mr_unpaid' => $labels ? __('Unpaid', $domain) : 'unpaid',
'mr_paid' => $labels ? __('Paid', $domain) : 'paid',
);
}
// Display the custom actions on admin Orders bulk action dropdown
add_filter( 'bulk_actions-edit-shop_order', 'set_transactions_orders_bulk_actions' );
function set_transactions_orders_bulk_actions( $bulk_actions ) {
foreach( custom_admin_orders_bulk_actions(true) as $key => $label ) {
$bulk_actions[$key] = sprintf( __('Mark Transactions as %s', 'woocommerce'), $label );
}
return $bulk_actions;
}
// Process the bulk action from selected orders
add_filter( 'handle_bulk_actions-edit-shop_order', 'set_transactions_bulk_action_edit_shop_order', 10, 3 );
function set_transactions_bulk_action_edit_shop_order( $redirect_to, $action, $post_ids ) {
$actions = custom_admin_orders_bulk_actions();
if ( in_array( $action, array_keys($actions) ) ) {
$processed_ids = array(); // Initializing
foreach ( $post_ids as $post_id ) {
// Save the new value
update_post_meta( $post_id, '_wc_acof_2', $actions[$action] );
$processed_ids[] = $post_id; // Adding processed order IDs to an array
}
// Adding the right query vars to the returned URL
$redirect_to = add_query_arg( array(
'rebate_action' => $action,
'processed_count' => count( $processed_ids ),
'processed_ids' => implode( ',', $processed_ids ),
), $redirect_to );
}
return $redirect_to;
}
// Display the results notice from bulk action on orders
add_action( 'admin_notices', 'set_transactions_bulk_action_admin_notice' );
function set_transactions_bulk_action_admin_notice() {
global $pagenow;
if ( 'edit.php' === $pagenow && isset($_GET['post_type']) && 'shop_order' === $_GET['post_type']
&& isset($_GET['rebate_action']) && isset($_GET['processed_count']) && isset($_GET['processed_ids']) ) {
foreach( custom_admin_orders_bulk_actions(true) as $key => $label ) {
if ( $_GET['rebate_action'] === $key ) {
$count = intval( $_GET['processed_count'] );
printf( '<div class="notice notice-success fade is-dismissible"><p>' .
_n( '%s selected order updated to "%s" rebate status.',
'%s selected orders updated to "%s" rebate status.',
$count, 'woocommerce' )
. '</p></div>', $count, $label );
}
}
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
Based on: Process custom bulk action on admin Orders list in Woocommerce
actually I made it work with the help of your code, but its too long, I appreciate if you can make it simple...
add_filter( 'bulk_actions-edit-shop_order', 'decrease_meals_orders_bulk_actions' );
function decrease_meals_orders_bulk_actions( $bulk_actions ) {
$bulk_actions['mr_norebates'] = 'Mark Transactions as No Rebates';
$bulk_actions['mr_unpaid'] = 'Mark Transactions as Unpaid';
$bulk_actions['mr_paid'] = 'Mark Transactions as Paid';
return $bulk_actions;
}
// Process the bulk action from selected orders
add_filter( 'handle_bulk_actions-edit-shop_order', 'decrease_meals_bulk_action_edit_shop_order', 10, 3 );
function decrease_meals_bulk_action_edit_shop_order( $redirect_to, $action, $post_ids ) {
if ( $action === 'mr_norebates' ){
$processed_ids = array(); // Initializing
foreach ( $post_ids as $post_id ) {
// Get number of meals
$nb_meal = get_post_meta( $post_id, '_wc_acof_2', true );
// Save the decreased number of meals ($meals - 1)
update_post_meta( $post_id, '_wc_acof_2', $nb_meal = 'norebates' );
$processed_ids[] = $post_id; // Adding processed order IDs to an array
}
// Adding the right query vars to the returned URL
$redirect_to = add_query_arg( array(
'mr_norebates' => 'No Rebates',
'processed_count' => count( $processed_ids ),
'processed_ids' => implode( ',', $processed_ids ),
), $redirect_to );
}
elseif ( $action === 'mr_unpaid' ){
$processed_ids = array(); // Initializing
foreach ( $post_ids as $post_id ) {
// Get number of meals
$nb_meal = get_post_meta( $post_id, '_wc_acof_2', true );
// Save the decreased number of meals ($meals - 1)
update_post_meta( $post_id, '_wc_acof_2', $nb_meal = 'unpaid' );
$processed_ids[] = $post_id; // Adding processed order IDs to an array
}
// Adding the right query vars to the returned URL
$redirect_to = add_query_arg( array(
'mr_unpaid' => 'Unpaid',
'processed_count' => count( $processed_ids ),
'processed_ids' => implode( ',', $processed_ids ),
), $redirect_to );
}
elseif ( $action === 'mr_paid' ){
$processed_ids = array(); // Initializing
foreach ( $post_ids as $post_id ) {
// Get number of meals
$nb_meal = get_post_meta( $post_id, '_wc_acof_2', true );
// Save the decreased number of meals ($meals - 1)
update_post_meta( $post_id, '_wc_acof_2', $nb_meal = 'paid' );
$processed_ids[] = $post_id; // Adding processed order IDs to an array
}
// Adding the right query vars to the returned URL
$redirect_to = add_query_arg( array(
'mr_paid' => 'Paid',
'processed_count' => count( $processed_ids ),
'processed_ids' => implode( ',', $processed_ids ),
), $redirect_to );
}
return $redirect_to;
}
// Display the results notice from bulk action on orders
add_action( 'admin_notices', 'decrease_meals_bulk_action_admin_notice' );
function decrease_meals_bulk_action_admin_notice() {
if ( empty( $_REQUEST['mr_norebates'] ) ) return; // Exit
$count = intval( $_REQUEST['processed_count'] );
printf( '<div id="message" class="updated fade"><p>' .
_n( 'Selected %s transaction updated.',
'Selected %s transactions updated.',
$count,
'mr_norebates'
) . '</p></div>', $count );
I have this code which creates a drop-down on the product page. It saves the data chosen and it displays on the order. What I am need help with is displaying the value in the custom column.
Here's the code:
add_action( 'woocommerce_product_options_general_product_data', 'costcenter_management_group' );
function costcenter_management_group() {
global $post;
echo '<div class="options_group">';
woocommerce_wp_select( array(
'id' => '_cost_center',
'label' => __( 'Cost Center', 'woocommerce' ),
'options' => array(
'One' => __( 'Office One', 'woocommerce' ),
'Two' => __( 'Office Two', 'woocommerce' ),
)));
echo '</div>';
}
// save cost center settings
add_action( 'woocommerce_process_product_meta', 'costcenter_management_group_save' );
function costcenter_management_group_save( $post_id ){
if( isset( $_POST['_cost_center'] ) )
update_post_meta( $post_id, '_cost_center', esc_attr( $_POST['_cost_center'] ) );
}
// display on order
add_action('woocommerce_checkout_create_order_line_item', 'costcenter_management_group_display', 20, 4);
function costcenter_management_group_display($item, $cart_item_key, $values, $order) {
if ( $cost_center = $values['data']->get_meta('_cost_center') ) {
$item->update_meta_data( 'Cost Center', $cost_centre );
}}
// add cost center column on order view (WC admin)
add_filter('manage_edit-shop_order_columns', 'costcenter_management_group_column', 10, 1 );
function costcenter_management_group_column( $columns ) {
$actions_key = isset($columns['wc_actions']) ? 'wc_actions' : 'order_actions';
$order_actions = $columns[$actions_key];
unset($columns[$actions_key]);
$columns['cost_center'] = __("Cost Center", "woocommerce");
$columns[$actions_key] = $order_actions;
return $columns;
}
I know I can use echo but I don't know which value I'm supposed to use?
To display this custom order item metadata in your custom column use the following:
// Display data to custom column in admin orders list
add_action( 'manage_shop_order_posts_custom_column' , 'display_enclosed_invoice_order_column_data' );
function display_enclosed_invoice_order_column_data( $column ) {
global $the_order, $post;
if( $column == 'cost_center' ) {
$values = []; // Initializing
// Loop through order items
foreach ( $the_order->get_items() as $item ) {
if( $cost_centre = $item->get_meta( 'Cost Center' ) ) {
$values[] = $cost_centre;
}
}
// Display the value(s)
if( sizeof( $values ) > 0 ) {
echo implode( ', ', $values); // Convert the array to a coma separated string
}
}
}
Code goes on function.php file of your active child theme (or active theme). It should works.
In woocommerce I have added custom fields on checkout page based on cart count.
// Adding Custom Fields based on Cart Count
add_action( 'woocommerce_before_checkout_billing_form', 'srd_custom_einstiegswahl');
function srd_custom_einstiegswahl($checkout){
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$i = 1;
foreach($items as $item => $values) {
$_product = $values['data']->post;
$quantity = $values['quantity'];
$x = 1;
while ($x <= $quantity) {
// Add fields here
echo '<h6>Reiseteilnehmer '.$x . '</h6>';
woocommerce_form_field( 'attendee_surname_'.$x, array(
'type' => 'text',
'class' => array('checkout_vorname'),
'label' => __('Vorame'),
'placeholder' => __(''),
'required' => true
), $checkout->get_value( 'attendee_surname_'.$x ));
woocommerce_form_field( 'attendee_name_'.$x, array(
'type' => 'text',
'class' => array('checkout_nachname'),
'label' => __('Nachname'),
'placeholder' => __(''),
'required' => true
), $checkout->get_value( 'attendee_name_'.$x ));
echo '<select name=einstiegswahl'.$x .'>';
// Select field populated by Custom Product Meta
echo '<option value="" style="display:none"> Bitte wählen Sie Ihren Einstiegsort </option>';
// Loop through cart items
foreach ( WC()->cart->get_cart() as $cart_item ) {
// Get the custom field data
$einstiegsorte = get_post_meta( $cart_item[ 'product_id' ], '_einstiegsorte', true );
if( ! empty($einstiegsorte) ){
// if it's multiline we split it in an array
$select_field_items = explode( "\n", $einstiegsorte );
// If the array has more than one item
if( sizeof( $select_field_items ) > 1 ){
foreach( $select_field_items as $value )
echo '<option value="'. $value .'">' . $value . '</option>';
}
// If there is only one line
else {
// we clean it
$value = str_replace('\n', '', $einstiegsorte);
echo '<option value="'. $value .'">' . $value . '</option>';
}
}
}
echo '</select>'; $checkout->get_value( 'einstiegswahl'.$x );
$x++;
}
$i++;
}
}
// Process the checkout
add_action('woocommerce_checkout_process', 'srd_teilnehmer_fields_process');
function srd_teilnehmer_fields_process() {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$i = 1;
foreach($items as $item => $values) {
$_product = $values['data']->post;
$quantity = $values['quantity'];
$x = 1;
for($x = 1; $x <= $quantity; $x++ ) {
//while ($x <= $quantity) {
if (!$_POST['attendee_surname_'.$x] || !$_POST['attendee_name_'.$x] || !$_POST['einstiegswahl'.$x]) wc_add_notice( __( 'Bitte wählen Sie Ihren Einstiegsort', 'woocommerce' ), 'error' );
}
}
}
// Update the order meta with field value
add_action('woocommerce_checkout_update_order_meta', 'srd_teilnehmer_update_order_meta');
function srd_teilnehmer_update_order_meta( $order_id ) {
global $woocommerce;
$items = $woocommerce->cart->get_cart();
$i = 1;
foreach($items as $item => $values) {
$_product = $values['data']->post;
$quantity = $values['quantity'];
$x = 1;
for($x = 1; $x <= $quantity; $x++ ) {
if ( $_POST['attendee_name_'.$x] ) update_post_meta( $order_id, 'attendee_surname_'.$x , sanitize_text_field($_POST['attendee_name_'.$x]) );
if ($_POST['attendee_surname_'.$x]) update_post_meta( $order_id, 'attendee_name_'.$x, esc_attr($_POST['attendee_surname_'.$x]));
if ($_POST['einstiegswahl'.$x]) update_post_meta( $order_id, ' Teilnehmer Einstiegsort' .$x, esc_attr($_POST['einstiegswahl'.$x]));
}}}
All works fine and fields get validated and saved.
The problem: I am not able to get and display the values in admin Order edit pages.
Since I do not know at this point how many fields were created based on the amount ordered, I first need to get the a number of ordered items.
Here is that related code:
add_action( 'woocommerce_admin_order_data_after_billing_address', 'srd_teilnehmer_checkout_field_display_admin_order_meta', 10, 1 );
//add_action( 'woocommerce_email_order_meta', 'srd_teilnehmer_checkout_field_display_admin_order_meta', 10, 3 );
function srd_teilnehmer_checkout_field_display_admin_order_meta($order) {
$order = wc_get_order( $order_id );
$items = $item_data->get_quantity();
foreach($items as $item => $values) {
$order_quantity = $values['quantity'];
$x = 1;
while ($x <= $order_quantity) {
echo '<p><strong>'.__('Nachname'.$x).':</strong> ' . get_post_meta( $order->id, 'attendee_name_'.$x, true ) . '</p>';
}
}}
How can I get and display those custom field values in admin Order edit pages?
How to display that custom field values in email notifications?
Any help will be appreciated.
You are complicating a little bit things and there is some mistakes in your code.
It should be much better to display the attendees booking data as a custom meta box in admin shop orders edit pages (Here on the right column).
So I have completely revisited your code:
// Adding Custom Fields based on Cart Count
add_action( 'woocommerce_before_checkout_billing_form', 'srd_custom_einstiegswahl');
function srd_custom_einstiegswahl( $checkout ){
$count = 1;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
$options = array( '' => __("Bitte wählen Sie Ihren Einstiegsort") );
$einstiegsorte = get_post_meta( $cart_item[ 'product_id' ], '_einstiegsorte', true );
if( ! empty($einstiegsorte) ){
$option_items = explode( "\n", $einstiegsorte );
if( sizeof( $option_items ) > 1 ){
foreach( $option_items as $value )
$options[$value] = $value;
} else {
$value = str_replace('\n', '', $einstiegsorte);
$options[$value] = $value;
}
}
// Loop through cart item quantity
for($i = 1; $i <= $cart_item['quantity']; $i++ ) {
$j = $count.'_'.$i;
echo '<h6>Reiseteilnehmer '.$i . '</h6>';
woocommerce_form_field( '_teilnehmer_vorame_'.$j, array(
'type' => 'text',
'class' => array('checkout_vorname'),
'label' => __('Vorame'),
'required' => true,
), $checkout->get_value( '_teilnehmer_vorame_'.$j ));
woocommerce_form_field( '_teilnehmer_nachname_'.$j, array(
'type' => 'text',
'class' => array('checkout_nachname'),
'label' => __('Nachname'),
'required' => true,
), $checkout->get_value( '_teilnehmer_nachname_'.$j ));
woocommerce_form_field( '_teilnehmer_einstiegswahl_'.$j, array(
'type' => 'select',
'class' => array('checkout_einstiegswahl'),
'label' => __('Einstiegswahl'),
'required' => true,
'options' => $options,
), $checkout->get_value( '_teilnehmer_einstiegswahl_'.$j ));
}
$count++;
}
}
// Custom checkout fields validation
add_action('woocommerce_checkout_process', 'srd_teilnehmer_fields_process');
function srd_teilnehmer_fields_process() {
$count = 1;
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Loop through cart item quantity
for($i = 1; $i <= $cart_item['quantity']; $i++ ) {
$j = $count.'_'.$i;
if (!$_POST['_teilnehmer_vorame_'.$j] || !$_POST['_teilnehmer_nachname_'.$j] || !$_POST['_teilnehmer_einstiegswahl_'.$j])
wc_add_notice( __( 'Bitte wählen Sie Ihren Einstiegsort', 'woocommerce' ), 'error' );
}
$count++;
}
}
// Update the order meta data with checkout custom fields values
add_action('woocommerce_checkout_create_order', 'srd_teilnehmer_checkout_create_order', 20, 2 );
function srd_teilnehmer_checkout_create_order( $order, $data ) {
$count = 1;
// Loop through cart item quantity
foreach( WC()->cart->get_cart() as $cart_item ) {
// Loop through item quantity
for($i = 1; $i <= $cart_item['quantity']; $i++ ) {
$j = $count.'_'.$i;
if ( isset($_POST['_teilnehmer_vorame_'.$j]) )
$order->update_meta_data( '_teilnehmer_vorame_'.$j , sanitize_text_field($_POST['_teilnehmer_vorame_'.$j]) );
if ( isset($_POST['_teilnehmer_nachname_'.$j]) )
$order->update_meta_data( '_teilnehmer_nachname_'.$j, sanitize_text_field($_POST['_teilnehmer_nachname_'.$j]) );
if ( isset($_POST['_teilnehmer_einstiegswahl_'.$j]) )
$order->update_meta_data( '_teilnehmer_einstiegswahl_'.$j, sanitize_text_field($_POST['_teilnehmer_einstiegswahl_'.$j]) );
}
$count++;
}
}
// Adding Custom metabox in admin orders edit pages (on the right column)
add_action( 'add_meta_boxes', 'add_reiseteilnehmer_metabox' );
function add_reiseteilnehmer_metabox(){
add_meta_box(
'attendees',
__('Reiseteilnehmer'),
'reiseteilnehmer_inhalt',
'shop_order',
'side', // or 'normal'
'default' // or 'high'
);
}
// Adding the content for the custom metabox
function reiseteilnehmer_inhalt() {
$order = wc_get_order(get_the_id());
$count = 1;
$key_labels = array( 'vorame', 'nachname', 'einstiegswahl' );
// Loop through order items
foreach ( $order->get_items() as $item ){
echo '<h4 style="margin:1em 0 .5em;">Order item '.$count.'</h4>';
// Loop through item quantity
for($i = 1; $i <= $item->get_quantity(); $i++ ) {
echo '<div style="background-color:#eee;padding:2px;margin-bottom:.4em;">
<h4 style="margin:.5em 0;padding:2px;">Reiseteilnehmer '.$i.'</h4>
<table style="text-align:left;margin-bottom:.7em;" cellpadding="2"><tbody>';
$style = ' style="padding:2px 0;"';
// Loop through attendee fields
foreach( $key_labels as $key ){
$value = get_post_meta( $order->get_id(), '_teilnehmer_'.$key.'_'.$count.'_'.$i, true );
echo '<tr><th>'.ucfirst($key).':</th><td>'.$value.'</td></tr>';
}
echo '</tbody></table></div>';
}
$count++;
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
To display that in emails and in front end "Order Received" and My account "Order view" pages, you will have to ask a new question as it is just too broad to be answered in one answer.
I have a a custom field value for each product. This custom field is inserted with the code below :
<?php
// Insert a Custom Admin Field
add_action( 'woocommerce_product_options_general_product_data', 'woo_add_custom_general_fields' );
function woo_add_custom_general_fields() {
echo '<div class="options_group">';
woocommerce_wp_text_input( array(
'id' => 'days_manufacture',
'label' => __( 'Days for Manufacture', 'woocommerce' ),
'placeholder' => '',
'description' => __( 'Insert here', 'woocommerce' ),
'type' => 'number',
'custom_attributes' => array(
'step' => 'any',
'min' => '1'
),
) );
echo '</div>';
}
// Save the field
add_action( 'woocommerce_process_product_meta', 'woo_add_custom_general_fields_save' );
function woo_add_custom_general_fields_save( $post_id ){
$woocommerce_number_field = $_POST['days_manufacture'];
if( !empty( $woocommerce_number_field ) )
update_post_meta( $post_id, 'days_manufacture', esc_attr( $woocommerce_number_field ) );
}
// Store custom field
add_action( 'woocommerce_add_cart_item_data', 'save_days_field', 10, 2 );
function save_days_field( $cart_item_data, $product_id ) {
$special_item = get_post_meta( $product_id , 'days_manufacture',true );
if(!empty($special_item)) {
$cart_item_data[ 'days_manufacture' ] = $special_item;
// below statement make sure every add to cart action as unique line item
$cart_item_data['unique_key'] = md5( microtime().rand() );
WC()->session->set( 'days_manufacture', $special_item );
}
return $cart_item_data;
}
// Render meta on cart and checkout
add_filter( 'woocommerce_get_item_data', 'rendering_meta_field_on_cart_and_checkout', 10, 2 );
function rendering_meta_field_on_cart_and_checkout( $cart_data, $cart_item ) {
$custom_items = array();
// Woo 2.4.2 updates
if( !empty( $cart_data ) ) {
$custom_items = $cart_data;
}
if( isset( $cart_item['days_manufacture'] ) ) {
$custom_items[] = array( "name" => __( "Days", "woocommerce" ), "value" => $cart_item['days_manufacture'] );
}
return $custom_items;
} ?>
This code works perfectly.
Now I would like on Cart and checkout (before coupon notice) pages to display the highest value of this custom field (days_manufacture) on a custom message, when multiple items are in Cart, like in this screenshot.
How can I achieve this?
Thanks.
Here is a custom function that will display a message on cart and checkout (before coupon notice) pages with the highest number of days of manufacture…
Here is the code:
add_action('woocommerce_before_cart', 'days_of_manufacture');
add_action('woocommerce_before_checkout_form', 'days_of_manufacture', 5);
function days_of_manufacture() {
$day_txt = ' ' . __('day', 'your_theme_domain_slug' );
$days_txt = ' ' . __('days', 'your_theme_domain_slug' );
$text = __('Your Order will be produced in: ', 'your_theme_domain_slug' );
$max_days = 0;
foreach( WC()->cart->get_cart() as $cart_item )
if($cart_item['days_manufacture'] > $max_days)
$max_days = $cart_item['days_manufacture'];
if($max_days != 0) {
if ($max_days == 1)
$days_txt = $day_txt;
$output = $text . $max_days . $days_txt;
echo "<div class='woocommerce-info'>$output</div>";
}
}
This code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested and works.
Store the variable in the $_SESSION, then loop thru them and pick the highest, so you can use it later anywhere in your code