Woocommerce - Adding Custom Fields to Checkout & Custom Dashboard Tab - woocommerce

I have an Multistep Checkout and for that reason i have created a new custom step called "Card-Data", where i want the customer to fill the inputs. This inputs should also appear on a Tab in My Account. I already created a new custom tab for My Account Dashboard.
Can you tell me please, how i can create Custom Fields in the checkout process and and make them visible in the Custom Dashboard Tab. The customer should has the possibility to change data entries on his own through the dashboard.
Many Thanks

// i use multistep checkout wizzard plugin. here i create a step, where user
enters the card data
add_action('woocommerce_multistep_checkout_before', 'add_visica_step');
function add_visica_step() {
$contents = '<h1>Visica Daten</h1>';
$contents .= '<div class="visica-step"> Please Enter something </div>';
echo $contents;
}
add_filter ( 'woocommerce_account_menu_items', 'one_more_link' );
function one_more_link( $menu_links ){
$new = array( 'carddata' => 'Card Data' );
$menu_links = array_slice( $menu_links, 0, 1, true )
+ $new
+ array_slice( $menu_links, 1, NULL, true );
return $menu_links;
}
/*
* Step 2. Register Permalink Endpoint
*/
add_action( 'init', 'add_endpoint' );
function add_endpoint() {
// WP_Rewrite is my Achilles' heel, so please do not ask me for detailed
explanation
add_rewrite_endpoint( 'visicadata', EP_PAGES );
}
/*
* Step 3. Content for the new page in My Account, woocommerce_account_{ENDPOINT
NAME}_endpoint
*/
add_action( 'woocommerce_account_visicadata_endpoint',
'my_account_endpoint_content' );
function my_account_endpoint_content() {
echo 'Here I want do display custom fields from checkout';
}
add_filter( 'woocommerce_checkout_fields' ,
'woocommerce_checkout_field_editor' );
// Our hooked in function - $fields is passed via the filter!
function woocommerce_checkout_field_editor( $fields ) {
$fields['shipping']['shipping_field_value'] = array(
'label' => __('Field Value', 'woocommerce'),
'placeholder' => _x('Field Value', 'placeholder', 'woocommerce'),
'required' => true
);
return $fields;
}
// Display Field on Order Page, but i would like to display it on custom tab
add_action( 'woocommerce_admin_order_data_after_shipping_address',
'edit_woocommerce_checkout_page', 10, 1 );
function edit_woocommerce_checkout_page($order){
global $post_id;
$order = new WC_Order( $post_id );
echo '<p><strong>'.__('Field Value').':</strong> ' . get_post_meta($order->get_id(), '_shipping_field_value', true ) . '</p>';

Related

Create a custom field on WooCommerce checkout if product category equals x

so I'm looking to create/show a couple of custom fields on the checkout page of my WooCommerce page as long as a product with a certain category is in the cart. The values of these fields are only necessary for me to access in the order on the backend afterwards, and does not need to be added to the order e-mail confirmation to the customer.
Any pointers? If it helps things, I'm using ACF on my website.
Thanks in advance!
You need to do the following:
Detect if the existing products in cart is in your category
Add the fields on checkout if it matches your condition.
Validate and save the data
Display it on the backend.
This is already outlined on the docs, and you might want to read it:
https://woocommerce.com/document/tutorial-customising-checkout-fields-using-actions-and-filters/#adding-a-custom-special-field
Here is an example function to detect if the cart contains a certain product within a defined category
// functions.php
function cat_in_cart( $cat_slug ) {
$cat_in_cart = false;
$cart = WC()->cart->get_cart();
if ( !$cart ) {
return $cat_in_cart;
}
foreach( $cart as $cart_item_key => $cart_item ) {
if ( has_term( $cat_slug, 'product_cat', $cart_item['product_id'] )) {
$cat_in_cart = true;
break;
}
}
return $cat_in_cart;
}
To add a field on checkout (Link to docs):
// functions.php
/**
* Add the field to the checkout
*/
add_action( 'woocommerce_after_order_notes', 'my_custom_checkout_field' );
function my_custom_checkout_field( $checkout ) {
if ( cat_in_cart( 'your_category_slug' ) ) {
echo '<div id="my_custom_checkout_field"><h2>' . __('My Field') . '</h2>';
woocommerce_form_field( 'my_field_name', array(
'type' => 'text',
'class' => array('my-field-class form-row-wide'),
'label' => __('Fill in this field'),
'placeholder' => __('Enter something'),
), $checkout->get_value( 'my_field_name' ));
echo '</div>';
}
}
After that, save the field on checkout:
add_action('woocommerce_checkout_process', 'my_custom_checkout_field_process');
function my_custom_checkout_field_process() {
// Check if set, if its not set add an error.
if ( ! $_POST['my_field_name'] )
wc_add_notice( __( 'Please enter something into this new shiny field.' ), 'error' );
}
add_action( 'woocommerce_checkout_update_order_meta', 'my_custom_checkout_field_update_order_meta' );
function my_custom_checkout_field_update_order_meta( $order_id ) {
if ( ! empty( $_POST['my_field_name'] ) ) {
update_post_meta( $order_id, 'My Field', sanitize_text_field( $_POST['my_field_name'] ) );
}
}
Lastly, display it on the dashboard:
/**
* Display field value on the order edit page
*/
add_action( 'woocommerce_admin_order_data_after_billing_address', 'my_custom_checkout_field_display_admin_order_meta', 10, 1 );
function my_custom_checkout_field_display_admin_order_meta($order){
echo '<p><strong>'.__('My Field').':</strong> ' . get_post_meta( $order->id, 'My Field', true ) . '</p>';
}

How to add sub-menu in My Account WooCommerce?

I would like to ask some help.
add_filter ( 'woocommerce_account_menu_items', 'misha_one_more_link' );
function misha_one_more_link( $menu_links ){
// we will hook "anyuniquetext123" later
$new = array( 'anyuniquetext123' => 'Gift for you' );
// or in case you need 2 links
// $new = array( 'link1' => 'Link 1', 'link2' => 'Link 2' );
// array_slice() is good when you want to add an element between the other ones
$menu_links = array_slice( $menu_links, 0, 1, true )
+ $new
+ array_slice( $menu_links, 1, NULL, true );
return $menu_links;
}
add_filter( 'woocommerce_get_endpoint_url', 'misha_hook_endpoint', 10, 4 );
function misha_hook_endpoint( $url, $endpoint, $value, $permalink ){
if( $endpoint === 'anyuniquetext123' ) {
// ok, here is the place for your custom URL, it could be external
$url = site_url();
}
return $url;
}
I am using this code to add custom menu on My Account page of WooCommerce:
This worked pretty well but it only adds menu link. I would like to add submenus under Gift for You for example is "For Her" or "For Him".
The only solution I found is to override the file plugins/woocommerce/templates/myaccount/navigation.php and do whatever you want inside ;)

WooCommerce 4.0 custom checkout & ACF field value on email, admin order, and thank you page

I'm having a hard time printing my custom field value to the email notifications, order admin and thank you page. I've browsed through StackOverflow, tried every single answer I found but unfortunately not working and I couldn't figure out the problem:
I am trying to pass the value of the additional checkout field, it only prints the strong label with a blank value, and in the emails nothing shows, here is my code so far:
//new pickup location checkout field
add_action( 'woocommerce_before_order_notes', 'pickup_location_custom_checkout_field' );
function pickup_location_custom_checkout_field( $checkout ) {
echo '<div><h3>' . __('Pick-up location') . '</h3>';
woocommerce_form_field( 'pick_up_location', array(
'type' => 'text',
'class' => array('notes'),
'label' => __('<span style="color:red">[IMPORTANT]</span> Where should we meet you?'),
'placeholder' => __('Please enter your accomodation name or the nearest pick-up point if not accessible by car'),
'required' => true,
), $checkout->get_value( 'pick_up_location' ));
echo '</div>';
}
// Save the pickup location data to the order meta
add_action( 'woocommerce_checkout_create_order', 'pickup_location_checkout_field_update_order_meta' );
function pickup_location_checkout_field_update_order_meta( $order_id ) {
if (!empty($_POST['pick_up_location'])) {
update_post_meta( $order_id, 'Pick-up location', sanitize_text_field( $_POST['pick_up_location']));
}
}
// Display 'pickup location' on the order edit page (backend)
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'pickup_location_checkout_field_order_page', 10, 1 );
function pickup_location_checkout_field_order_page($order){
global $post_id;
$order = new WC_Order( $post_id );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
// Display 'pickup location' in "Order received" and "Order view" pages (frontend)
add_action( 'woocommerce_order_details_after_order_table', 'display_client_pickup_data_in_orders', 10 );
function display_client_pickup_data_in_orders( $order ) {
global $post_id;
$order = new WC_Order( $post_id );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
}
// Display 'pickup location data' in Email notifications
add_filter( 'woocommerce_email_order_meta_fields', 'display_client_pickup_data_in_emails', 10, 3 );
function display_client_pickup_data_in_emails( $fields, $sent_to_admin, $order ) {
$fields['Pickup Location'] = array(
'label' => __( 'Pickup Location' ),
'value' => get_post_meta( $order->get_id(), 'pick_up_location', true ),
);
return $fields;
}
No matter what I try, the code only prints the label without any value from the checkout form.
I know this question has been asked many times, but I tried every single answer for over 6 days without any luck. I also need to mention that I am using Woocommerce Bookings in this project.
Thanks for your help
[Update:] Saving and displaying ACF field in the cart, admin order, customer order, checkout, and emails.
Thanks to #7uc1f3r for the detailed explanation, his answer helped me to display the ACF field in a similar way, it is also based on This answer from #LoicTheAztec.
Displaying custom field on the product page above ATC:
// Displaying Pick-up time custom field value in single product page
add_action( 'woocommerce_before_add_to_cart_button', 'add_pickup_time_custom_field', 0 );
function add_pickup_time_custom_field() {
global $product;
//(compatibility with WC +3)
$product_id = method_exists( $product, 'get_id' ) ? $product->get_id() : $product->id;
echo "<div class='pickup-time-atc'>";
echo "<span>Pick-up time: </span>";
echo get_field( 'pick_up_time', $product_id );
echo "</div>";
return true;
}
Displaying custom field value in single product page
Saving Pick-up time custom field into cart and session
// Saving Pick-up time custom field into cart and session
add_filter( 'woocommerce_add_cart_item_data', 'save_pickup_time_custom_field', 10, 2 );
function save_pickup_time_custom_field( $cart_item_data, $product_id ) {
$custom_field_value = get_field( 'pick_up_time', $product_id, true );
if( !empty( $custom_field_value ) )
{
$cart_item_data['pick_up_time'] = $custom_field_value;
}
return $cart_item_data;
}
Render Pick-up time custom field meta on cart and checkout
// Render Pick-up time meta on cart and checkout
add_filter( 'woocommerce_get_item_data', 'render_pickuptime_meta_on_cart_and_checkout', 10, 2 );
function render_pickuptime_meta_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['pick_up_time'] ) ) {
$custom_items[] = array( "name" => "Pickup time", "value" => $cart_item['pick_up_time'] );
}
return $custom_items;
}
Render custom field meta on cart and checkout
Add custom field meta to order admin details
// Add pickup time custom field meta to order admin
add_action( 'woocommerce_checkout_create_order_line_item', 'pickuptime_checkout_create_order_line_item', 10, 4 );
function pickuptime_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if( isset( $values['pick_up_time'] ) ) {
$item->add_meta_data(
__( 'Pickup time' ),
$values['pick_up_time'],
true
);
}
}
Add custom field meta to order admin details
Add pickup time custom field meta to emails
// Add pickup time custom field meta to emails
add_filter( 'woocommerce_order_item_name', 'pickuptime_order_item_emails', 10, 2 );
function pickuptime_order_item_emails( $product_name, $item ) {
if( isset( $item['pick_up_time'] ) ) {
$product_name .= sprintf(
'<ul"><li>%s: %s</li></ul>',
__( '<span style="color:red !important">Pickup time</span>' ),
esc_html( $item['pick_up_time'] )
);
}
return $product_name;
}
Add pickup time custom field meta to emails
Please comment if you see any errors or ways to improve,
Thanks.
Woocommerce 4.0.0 and Wordpress 5.3.2
Go through your code step by step
update_post_meta( $order_id, 'Pick-up location', sanitize_text_field( $_POST['pick_up_location']));
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . get_post_meta($order->get_id(), '_pick_up_location', true ) . '</p>';
'value' => get_post_meta( $order->get_id(), 'pick_up_location', true ),
You use Pick-up location, _pick_up_location & pick_up_location as meta_key
while this should be 3x the same value.
You also miss a closing tag by pickup_location_checkout_field_order_page function.
You also use wrong parameters with some hooks, etc..
Try this instead
//new pickup location checkout field
add_action( 'woocommerce_before_order_notes', 'pickup_location_custom_checkout_field' );
function pickup_location_custom_checkout_field( $checkout ) {
echo '<div><h3>' . __('Pick-up location') . '</h3>';
woocommerce_form_field( 'pick_up_location', array(
'type' => 'text',
'class' => array('notes'),
'label' => __('<span style="color:red">[IMPORTANT]</span> Where should we meet you?'),
'placeholder' => __('Please enter your accomodation name or the nearest pick-up point if not accessible by car'),
'required' => true,
), $checkout->get_value( 'pick_up_location' ));
echo '</div>';
}
// Save the pickup location data to the order meta
add_action( 'woocommerce_checkout_create_order', 'pickup_location_checkout_field_update_order_meta', 10, 2 );
function pickup_location_checkout_field_update_order_meta( $order, $data ) {
if ( !empty( $_POST['pick_up_location']) ) {
$order->update_meta_data( '_pick_up_location', sanitize_text_field( $_POST['pick_up_location'] ) ); // Order meta data
}
}
// Display 'pickup location' on the order edit page (backend)
add_action( 'woocommerce_admin_order_data_after_shipping_address', 'pickup_location_checkout_field_order_page', 10, 1 );
function pickup_location_checkout_field_order_page( $order ) {
$pick_up_location = $order->get_meta( '_pick_up_location' );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . $pick_up_location . '</p>';
}
// Display 'pickup location' in "Order received" and "Order view" pages (frontend)
add_action( 'woocommerce_order_details_after_order_table', 'display_client_pickup_data_in_orders', 10 );
function display_client_pickup_data_in_orders( $order ) {
$pick_up_location = $order->get_meta( '_pick_up_location' );
echo '<p><strong style="color:red">'.__('Pickup Location').':</strong> ' . $pick_up_location . '</p>';
}
// Display 'pickup location data' in Email notifications
add_filter( 'woocommerce_email_order_meta_fields', 'display_client_pickup_data_in_emails', 10, 3 );
function display_client_pickup_data_in_emails( $fields, $sent_to_admin, $order ) {
$fields['Pickup Location'] = array(
'label' => __( 'Pickup Location' ),
'value' => $order->get_meta( '_pick_up_location' ),
);
return $fields;
}

Change title "Additional Information" in woocommerce

I want to change the title from the checkout page. But I just can change the label and the placeholder.
// Hook in
add_filter( 'woocommerce_checkout_fields' , 'custom_override_checkout_fields' );
// Our hooked in function - $fields is passed via the filter!
function custom_override_checkout_fields( $fields ) {
$fields['order']['order_comments']['placeholder'] = 'Please type your PO number here and we will add it to the invoice.';
$fields['order']['order_comments']['label'] = '';
return $fields;
}
https://docs.woocommerce.com/document/editing-product-data-tabs/#
/**
* Rename product data tabs
*/
add_filter( 'woocommerce_product_tabs', 'woo_rename_tabs', 98 );
function woo_rename_tabs( $tabs ) {
$tabs['description']['title'] = __( 'More Information' ); // Rename the description tab
$tabs['reviews']['title'] = __( 'Ratings' ); // Rename the reviews tab
$tabs['additional_information']['title'] = __( 'Product Data' ); // Rename the additional information tab
return $tabs;
}
As it stands there is not hook to change the section title. But here's the hack if you are desperate enough to make the modification.
Locate your template folder
Create a folder named 'checkout'
Locate the file form-shipping.php in the Woocommerce plugin foler under templates/checkout/
Copy file in step 3 to the folder created in step 2
Now you have superpowers over the checkout form
Edit this line:
<h3><?php _e( 'Additional Information', 'woocommerce' ); ?></h3>
This solution worked for me:
function ajg_relabel_additional_information_tab(){
return __( 'Specification', 'text-domain' );
}
add_filter('woocommerce_product_additional_information_heading', 'ajg_relabel_additional_information_tab');
function th_wc_order_review_strings( $translated_text, $text, $domain ) {
if(is_checkout()){
switch ($translated_text) {
case 'Billing details' :
$translated_text = __( 'Billing Info', 'woocommerce' );
break;
case 'Additional information':
$translated_text = __('New Field Name', 'woocommerce');
break;
case 'Your order':
$translated_text = __('My Order', 'woocommerce');
break;
case 'Product':
$translated_text = __('Your Product', 'woocommerce');
break;
}
}
return $translated_text;
}
add_filter( 'gettext', 'th_wc_order_review_strings', 20, 3 );
The documentation of Woocommerce is not complety...
https://docs.woocommerce.com/document/editing-product-data-tabs/
You would check condition about the callback before add or replace some value in array, otherwise the tab will display with nothing inside.
/**
* Filter product data tabs
*/
function filter_product_tabs( $tabs ) {
global $product;
if ( isset($tabs['description']['callback']) ) {
$tabs['description']['title'] = __( 'More Information' ); // Rename the description tab
$tabs['description']['priority'] = 5; // Description
}
if ( isset($tabs['additional_information']['callback']) ) {
$tabs['additional_information']['title'] = __( 'Product Data' ); // Rename the additional information tab
$tabs['additional_information']['priority'] = 10; // Additional information
}
if ( isset($tabs['reviews']['callback']) ) {
$tabs['reviews']['title'] = __( 'Review' ) . ' (' . $product->get_review_count() . ') '; // Rename the reviews tab
$tabs['reviews']['priority'] = 15; // Reviews
}
return $tabs;
}
add_filter( 'woocommerce_product_tabs', 'filter_product_tabs', 98 );
Why ? because the developper Woocommerce will check the content of array in the tab template
(version 3.8.0) (WC
/**
* Filter tabs and allow third parties to add their own.
*
* Each tab is an array containing title, callback and priority.
*
* #see woocommerce_default_product_tabs()
*/
$product_tabs = apply_filters( 'woocommerce_product_tabs', array() );
if ( ! empty( $product_tabs ) ) :
....
This worked for me if anyone is still after this change
//Shipping Weight custom tab name
add_filter( 'woocommerce_product_tabs', 'woo_rename_tabs', 98 );
function woo_rename_tabs( $tabs ) {
$tabs['additional_information']['title'] = __( 'Additional Information' ); // Rename the Additional Information text
return $tabs;
}

wordpress moving publish metabox

I'm working on a plugin and I'm trying to:
1- move the publish metabox from side to the bottom of the page in the normal section.
2- force 1 column layout for the plugin custom post type edit page.
3- remove the screen options tab for the custom post type.
I'm using the next code block but it dont work:
function sds_do_meta_boxes() {
remove_meta_box( 'submitdiv', 'sliding_panel', 'side' );
add_meta_box( 'submitdiv', __( 'Publish' ), 'post_submit_meta_box', 'sliding_panel', 'normal', 'core' );
}
add_action('do_meta_boxes', 'sds_do_meta_boxes');
function SDS_init() { //The current user is already authenticated by this time
add_filter( 'screen_layout_columns', 'so_screen_layout_columns' );
add_filter( 'get_user_option_screen_layout_dashboard', 'so_screen_layout_dashboard' );
add_filter( 'screen_options_show_screen', 'SDS_remove_screen_options_tab');
}
add_action( 'init', 'SDS_init' );
function so_screen_layout_columns( $columns ) {
$columns['dashboard'] = 1;
return $columns;
}
function so_screen_layout_dashboard() {
return 1;
}
function SDS_remove_screen_options_tab() {
return false;
}
So, the 'publish' metabox is removed but it is not re-added. Also, the 1 column layout filters don't work. I need help:)
Changing the $priority parameter from core to high and setting priority of add_action to 0 should do the trick. I would also suggest using the dynamic add_meta_boxes_{$post_type} hook:
add_action( 'add_meta_boxes_sliding_panel', 'sds_do_meta_boxes', 0, 1 );
function sds_do_meta_boxes( $post )
{
remove_meta_box( 'submitdiv', 'sliding_panel', 'side' );
add_meta_box( 'submitdiv', __( 'Publish' ), 'post_submit_meta_box', 'sliding_panel', 'normal', 'high', null );
}

Resources