How can i change status button - php

I'm trying to make a button that changes my order status, but it can only appear on the view-quote page when the order status is at: ywraq-pending
I'm trying this code, but it shows up in all statuses:
function customer_order_confirm_args( $order_id ) {
return array(
'url' => wp_nonce_url( add_query_arg( 'complete_order', $order_id ) , 'wc_complete_order' ),
'name' => __( 'Aprovar Orçamento', 'woocommerce' )
);
}
// Add a custom action button to processing orders (My account > Orders)
add_filter( 'woocommerce_my_account_my_orders_actions', 'complete_action_button_my_accout_orders', 50, 2 );
function complete_action_button_my_accout_orders( $actions, $order ) {
if ( $order->has_status( 'ywraq-pending' ) ) {
$actions['order_confirmed'] = customer_order_confirm_args( $order->get_id() );
}
return $actions;
}
// Add a custom button to processing orders (My account > View order)
add_action( 'woocommerce_order_details_after_order_table', 'complete_action_button_my_accout_order_view' );
function complete_action_button_my_accout_order_view( $order ){
// Avoiding displaying buttons on email notification
if( is_wc_endpoint_url( 'view-quote' ) ) {
$data = customer_order_confirm_args( $order->get_id() );
echo '<div style="margin:16px 0 24px;">
<a class="button" href="'.$data['url'].'">'.$data['name'].'</a>
</div>';
}
}
// Change order status and display a message
add_action( 'template_redirect', 'action_complete_order_status' );
function action_complete_order_status( $query ) {
if ( ( is_wc_endpoint_url( 'orders' )
|| is_wc_endpoint_url( 'view-quote' ) )
&& isset( $_GET['complete_order'] )
&& $_GET['complete_order'] > 1
&& isset($_GET['_wpnonce'])
&& wp_verify_nonce($_GET['_wpnonce'], 'wc_complete_order') )
{
$order = wc_get_order( absint($_GET['complete_order']) );
if ( is_a($order, 'WC_Order') ) {
// Change order status to "ywraq-accepted"
$order->update_status( 'ywraq-accepted', __('Approvado pelo cliente', 'woocommerce') ) ;
// Add a notice (optional)
wc_add_notice( sprintf( __( 'Pedido #%s foi aprovado', 'woocommerce' ), $order->get_id() ) );
// Remove query args
wp_redirect( esc_url( remove_query_arg( array( 'complete_order', '_wpnonce' ) ) ) );
exit();
}
}
}
Can anybody help me?

If I understood your question clearly, you missed checking order status in the complete_action_button_my_accout_order_view function, so, you can achieve that with this code:
function customer_order_confirm_args( $order_id ) {
return array(
'url' => wp_nonce_url( add_query_arg( 'complete_order', $order_id ) , 'wc_complete_order' ),
'name' => __( 'Aprovar Orçamento', 'woocommerce' )
);
}
// Add a custom action button to processing orders (My account > Orders)
add_filter( 'woocommerce_my_account_my_orders_actions', 'complete_action_button_my_accout_orders', 50, 2 );
function complete_action_button_my_accout_orders( $actions, $order ) {
if ( $order->has_status( 'ywraq-pending' ) ) {
$actions['order_confirmed'] = customer_order_confirm_args( $order->get_id() );
}
return $actions;
}
// Add a custom button to processing orders (My account > View order)
add_action( 'woocommerce_order_details_after_order_table', 'complete_action_button_my_accout_order_view' );
function complete_action_button_my_accout_order_view( $order ){
// Avoiding displaying buttons on email notification && only for orders with ywraq-pending status
if( is_wc_endpoint_url( 'view-quote' )
&& $order->has_status( 'ywraq-pending' ) ) {
$data = customer_order_confirm_args( $order->get_id() );
echo '<div style="margin:16px 0 24px;"><a class="button" href="'.$data['url'].'">'.$data['name'].'</a></div>';
}
}
// Change order status and display a message
add_action( 'template_redirect', 'action_complete_order_status' );
function action_complete_order_status( $query ) {
if ( ( is_wc_endpoint_url( 'orders' )
|| is_wc_endpoint_url( 'view-quote' ) )
&& isset( $_GET['complete_order'] )
&& $_GET['complete_order'] > 1
&& isset($_GET['_wpnonce'])
&& wp_verify_nonce($_GET['_wpnonce'], 'wc_complete_order') )
{
$order = wc_get_order( absint($_GET['complete_order']) );
if ( is_a($order, 'WC_Order') ) {
// Change order status to "ywraq-accepted"
$order->update_status( 'ywraq-accepted', __('Approvado pelo cliente', 'woocommerce') ) ;
// Add a notice (optional)
wc_add_notice( sprintf( __( 'Pedido #%s foi aprovado', 'woocommerce' ), $order->get_id() ) );
// Remove query args
wp_redirect( esc_url( remove_query_arg( array( 'complete_order', '_wpnonce' ) ) ) );
exit();
}
}
}

Related

Custom add to cart button for certain product IDs if product appears in WooCommerce completed orders

My previous question has been answered and I want to expand the answer further
How can I add a custom url for a specific product (product is digital or physical type it's common I think)
Here is part of the example code I tried to write for a specific product:
// for the product ID 45 (for example)
if( $product->id == 45 ){
$add_to_cart_url = site_url('/custom-link/product-45/');
$button_text = __('View order now', 'woocommerce');
}
I don't know how to add/write this. Any advice?
Actually your question is simple and it is a matter of adding an if/else conditions. You can use in_array() to execute the if condition for 1 or more productIDs.
Note: Since WooCommerce 3 use $product->get_id() instead of $product->id
For WooCommerce shop and archives pages:
Replace
// When NOT empty
if ( ! empty( $order_id ) ) {
// Setting
$button_text_view_order = __( 'View order now', 'woocommerce' );
// Get view order url
$view_order_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
// New link + text
$sprintf = sprintf(
'%s',
esc_url( $view_order_url ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
esc_html( $button_text_view_order )
);
}
With
// When NOT empty
if ( ! empty( $order_id ) ) {
// Products IDs, several can be added, separated by a comma
$product_ids = array( 45 );
// Checks if a value exists in an array
if ( in_array( $product->get_id(), $product_ids ) ) {
// Button text
$button_text = __( 'For certain productIDs', 'woocommerce' );
// Button url
$button_url = site_url( '/custom-link/' );
} else {
// Button text - view order
$button_text = __( 'View order now', 'woocommerce' );
// Button url - get view order url
$button_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
}
// New link + text
$sprintf = sprintf(
'%s',
esc_url( $button_url ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
esc_html( $button_text )
);
}
For single product page:
Replace
// When NOT empty
if ( ! empty( $order_id ) ) {
// Remove default add to cart button and add a custom one
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
// Add action, priority 30 and pass data to add action function
add_action( 'woocommerce_single_product_summary', function() use ( $order_id ) {
// Setting
$button_text_view_order = __( 'View order now', 'woocommerce' );
// Get view order url
$view_order_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
echo '' . $button_text_view_order . '';
}, 30, 0 );
}
With
// When NOT empty
if ( ! empty( $order_id ) ) {
// Remove default add to cart button and add a custom one
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
// Products IDs, several can be added, separated by a comma
$product_ids = array( 30 );
// Checks if a value exists in an array
if ( in_array( $product->get_id(), $product_ids ) ) {
// Button text
$button_text = __( 'For certain productIDs', 'woocommerce' );
// Button url
$button_url = site_url( '/custom-link/' );
} else {
// Button text - view order
$button_text = __( 'View order now', 'woocommerce' );
// Button url - get view order url
$button_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
}
// Add action, priority 30 and pass data to add action function
add_action( 'woocommerce_single_product_summary', function() use ( $button_text, $button_url ) {
// New custom button, adjust classes if necessary (theme related)
echo '' . $button_text . '';
}, 30, 0 );
}
The full end result:
function get_order_id_by_product_id( $product_id ) {
global $wpdb;
// Get user ID
$user_id = get_current_user_id();
// Get order ID by product ID
$order_id = $wpdb->get_var( "
SELECT p.ID FROM {$wpdb->prefix}posts AS p
INNER JOIN {$wpdb->prefix}postmeta AS pm ON p.ID = pm.post_id
INNER JOIN {$wpdb->prefix}woocommerce_order_items AS woi ON p.ID = woi.order_id
INNER JOIN {$wpdb->prefix}woocommerce_order_itemmeta AS woim ON woi.order_item_id = woim.order_item_id
WHERE p.post_status IN ( 'wc-completed' )
AND pm.meta_key = '_customer_user'
AND pm.meta_value = '$user_id'
AND woim.meta_key IN ( '_product_id', '_variation_id' )
AND woim.meta_value = '$product_id'
LIMIT 1
" );
// Return
return $order_id;
}
// On WooCommerce shop and archives pages
function filter_woocommerce_loop_add_to_cart_link( $sprintf, $product, $args ) {
// Only for logged in users
if ( ! is_user_logged_in() ) return $sprintf;
// Only for single type products
if ( ! $product->is_type( 'simple' ) ) return $sprintf;
// Call fuction and get order ID
$order_id = get_order_id_by_product_id( $product->get_id() );
// When NOT empty
if ( ! empty( $order_id ) ) {
// Products IDs, several can be added, separated by a comma
$product_ids = array( 30 );
// Checks if a value exists in an array
if ( in_array( $product->get_id(), $product_ids ) ) {
// Button text
$button_text = __( 'For certain productIDs', 'woocommerce' );
// Button url
$button_url = site_url( '/custom-link/' );
} else {
// Button text - view order
$button_text = __( 'View order now', 'woocommerce' );
// Button url - get view order url
$button_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
}
// New link + text
$sprintf = sprintf(
'%s',
esc_url( $button_url ),
esc_attr( isset( $args['class'] ) ? $args['class'] : 'button' ),
esc_html( $button_text )
);
}
return $sprintf;
}
add_filter( 'woocommerce_loop_add_to_cart_link', 'filter_woocommerce_loop_add_to_cart_link', 10, 3 );
// On single product page, replacing the single add to cart product button by a custom button
function action_woocommerce_single_product_summary() {
global $product;
// Only for logged in users
if ( ! is_user_logged_in() ) return;
// Only for single type products
if ( ! $product->is_type( 'simple' ) ) return;
// Call fuction and get order ID
$order_id = get_order_id_by_product_id( $product->get_id() );
// When NOT empty
if ( ! empty( $order_id ) ) {
// Remove default add to cart button and add a custom one
remove_action( 'woocommerce_single_product_summary', 'woocommerce_template_single_add_to_cart', 30 );
// Products IDs, several can be added, separated by a comma
$product_ids = array( 30 );
// Checks if a value exists in an array
if ( in_array( $product->get_id(), $product_ids ) ) {
// Button text
$button_text = __( 'For certain productIDs', 'woocommerce' );
// Button url
$button_url = site_url( '/custom-link/' );
} else {
// Button text - view order
$button_text = __( 'View order now', 'woocommerce' );
// Button url - get view order url
$button_url = wc_get_endpoint_url( 'view-order', $order_id, wc_get_page_permalink( 'myaccount' ) );
}
// Add action, priority 30 and pass data to add action function
add_action( 'woocommerce_single_product_summary', function() use ( $button_text, $button_url ) {
// New custom button, adjust classes if necessary (theme related)
echo '' . $button_text . '';
}, 30, 0 );
}
}
add_action( 'woocommerce_single_product_summary', 'action_woocommerce_single_product_summary', 1 );

optimizing functions php file

for some extra needs i had to add some extra codes in fucnctions.php i notice slowing in my site i dont know if it has connection functions.php with jquery.js ,is there a anyway to optimize it ? its ok if i remove the entering space between the lines in fucntions.php id like to make as light as i can
/**
* Adding Custom GTIN Meta Field
* Save meta data to DB
*/
// add GTIN input field
add_action('woocommerce_product_options_inventory_product_data','woocom_simple_product_gtin_field', 10, 1 );
function woocom_simple_product_gtin_field(){
global $woocommerce, $post;
$product = new WC_Product(get_the_ID());
echo '<div id="gtin_attr" class="options_group">';
//add GTIN field for simple product
woocommerce_wp_text_input(
array(
'id' => '_gtin',
'label' => __( 'GTIN', 'textdomain' ),
'placeholder' => '01234567891231',
'desc_tip' => 'true',
'description' => __( 'Enter the Global Trade Item Number (UPC,EAN,ISBN)', 'textdomain' )
)
);
echo '</div>';
}
// save simple product GTIN
add_action('woocommerce_process_product_meta','woocom_simple_product_gtin_save');
function woocom_simple_product_gtin_save($post_id){
$gtin_post = $_POST['_gtin'];
// save the gtin
if(isset($gtin_post)){
update_post_meta($post_id,'_gtin', esc_attr($gtin_post));
}
// remove if GTIN meta is empty
$gtin_data = get_post_meta($post_id,'_gtin', true);
if (empty($gtin_data)){
delete_post_meta($post_id,'_gtin', '');
}
}
add_filter( 'rank_math/snippet/rich_snippet_product_entity', function( $entity ) {
global $post;
$entity['gtin8'] = get_post_meta( $post->ID,'_gtin', true );
return $entity;
});
/*
Tracking Info to WooCommerce order
Version: 0.4
$Id: tracking-info-to-wc-order.php 5168 2020-07-15 14:48:44Z damien $
*/
// Add the metabox to allow for manual entering (or editing) of tracking information.
add_action( 'cmb2_admin_init', 'dcwd_order_metabox' );
function dcwd_order_metabox() {
$cmb = new_cmb2_box( array(
'id' => 'order_tracking_info',
'title' => 'Tracking Information',
'object_types' => array( 'shop_order', ), // Post type
'context' => 'side',
'priority' => 'high',
'show_names' => true, // Show field names on the left
) );
$cmb->add_field( array(
'name' => 'Tracking number',
'id' => 'tracking_number',
'type' => 'text',
) );
$cmb->add_field( array(
'name' => 'Tracking URL',
'id' => 'tracking_url',
'type' => 'text_url',
'protocols' => array( 'http', 'https' ),
) );
}
// Examine the tracking url and return a provider name.
function dcwd_get_tracking_provider_from_url( $url ) {
if ( strpos( $url, 'usps.com' ) !== false ) {
return 'USPS';
}
if ( strpos( $url, 'fedex.com' ) !== false ) {
return 'FexEd';
}
if ( strpos( $url, 'ups.com' ) !== false ) {
return 'UPS';
}
// Add more as necessary.
// Unknown provider.
return null;
}
// If available, include the tracking information in the Completed Order email.
add_action( 'woocommerce_email_order_details', 'dcwd_add_tracking_info_to_order_completed_email', 5, 4 );
function dcwd_add_tracking_info_to_order_completed_email( $order, $sent_to_admin, $plain_text, $email ) {
/* // Only customers need to know about the tracking information.
if ( ! $sent_to_admin ) {
return;
}
*/
if ( 'customer_completed_order' == $email->id ) {
$order_id = $order->get_id();
$tracking_number = get_post_meta( $order_id, 'tracking_number', true );
$tracking_url = get_post_meta( $order_id, 'tracking_url', true );
// Quit if either tracking field is empty.
if ( empty( $tracking_number ) || empty( $tracking_url ) ) {
// Debugging code.
//error_log( sprintf( 'Order %d does not have both tracking number (%s) and url (%s)', $order_id, $tracking_number, $tracking_url ) );
//echo '<p>Ne pare rău, informațiile de urmărire nu sunt disponibile în acest moment.</p>';
return;
}
$tracking_provider = dcwd_get_tracking_provider_from_url( $tracking_url );
if ( $plain_text ) {
if ( ! empty( $tracking_provider ) ) {
printf( "\nComanda dumneavoastra a fost expediata. %s. Numărul de urmărire este %s și îl poți urmări la %s.\n", $tracking_provider, esc_html( $tracking_number ), esc_url( $tracking_url, array( 'http', 'https' ) ) );
}
else {
printf( "\nComanda dumneavoastra a fost expediata. Numărul de urmărire este %s și îl poți urmări la %s.\n", esc_html( $tracking_number ), esc_url( $tracking_url, array( 'http', 'https' ) ) );
}
}
else {
if ( ! empty( $tracking_provider ) ) {
printf( '<p>Your order has been shipped with <strong>%s</strong>. The tracking number is <strong>%s</strong>.</p>', $tracking_provider, esc_url( $tracking_url, array( 'http', 'https' ) ), esc_html( $tracking_number ) );
}
else {
printf( '<p>Comanda dumneavoastra a fost expediata. Numărul de urmărire este <strong>%s</strong>.</p>', esc_url( $tracking_url, array( 'http', 'https' ) ), esc_html( $tracking_number ) );
}
}
}
}
// Display tracking information in My Account area.
add_action( 'woocommerce_view_order', 'dcwd_add_tracking_info_to_view_order_page', 5 );
function dcwd_add_tracking_info_to_view_order_page( $order_id ) {
$tracking_number = get_post_meta( $order_id, 'tracking_number', true );
$tracking_url = get_post_meta( $order_id, 'tracking_url', true );
// Quit if either tracking field is empty.
if ( empty( $tracking_number ) || empty( $tracking_url ) ) {
// Debugging code.
error_log( sprintf( 'Order %d does not have both tracking number (%s) and url (%s)', $order_id, $tracking_number, $tracking_url ) );
echo '<p>Ne pare rău, informațiile de urmărire nu sunt disponibile în acest moment.</p>';
return;
}
$tracking_provider = dcwd_get_tracking_provider_from_url( $tracking_url );
if ( ! empty( $tracking_provider ) ) {
printf( '<p>Comanda dvs. a fost expediată cu <strong>%s</strong>. Numărul de urmărire este <strong>%s</strong>.</p>', $tracking_provider, esc_url( $tracking_url, array( 'http', 'https' ) ), esc_html( $tracking_number ) );
}
else {
printf( '<p>Comanda dumneavoastra a fost expediata. Numărul de urmărire este <strong>%s</strong>.</p>', esc_url( $tracking_url, array( 'http', 'https' ) ), esc_html( $tracking_number ) );
}
}
function add_file_types_to_uploads($file_types){
$new_filetypes = array();
$new_filetypes['svg'] = 'image/svg+xml';
$file_types = array_merge($file_types, $new_filetypes );
return $file_types;
}
add_filter('upload_mimes', 'add_file_types_to_uploads');
function flatsome_result_count_and_catalog_ordering_remover() {
remove_action( 'flatsome_category_title_alt', 'woocommerce_result_count', 20);
}
add_action('template_redirect','flatsome_result_count_and_catalog_ordering_remover');
add_filter( 'wc_add_to_cart_message_html', '__return_false' );
add_action( 'wp_print_scripts', 'de_script', 100 );
function de_script() {
wp_dequeue_script( 'wc-cart-fragments' );
return true;
}
/**
* #snippet Remove Additional Information Tab # WooCommerce Single Product Page
* #how-to Get CustomizeWoo.com FREE
* #author Rodolfo Melogli
* #testedwith WooCommerce 3.8
* #donate $9 https://businessbloomer.com/bloomer-armada/
*/
add_filter( 'woocommerce_product_tabs', 'bbloomer_remove_product_tabs', 9999 );
function bbloomer_remove_product_tabs( $tabs ) {
unset( $tabs['additional_information'] );
return $tabs;
}
/**
* Hide shipping rates when free shipping is available.
* Updated to support WooCommerce 2.6 Shipping Zones.
*
* #param array $rates Array of rates found for the package.
* #return array
*/
function my_hide_shipping_when_free_is_available( $rates ) {
$free = array();
foreach ( $rates as $rate_id => $rate ) {
if ( 'free_shipping' === $rate->method_id ) {
$free[ $rate_id ] = $rate;
break;
}
}
return ! empty( $free ) ? $free : $rates;
}
add_filter( 'woocommerce_package_rates', 'my_hide_shipping_when_free_is_available', 100 );
add_filter( 'woocommerce_default_address_fields', 'customise_postcode_fields' );
function customise_postcode_fields( $address_fields ) {
$address_fields['postcode']['required'] = false;
return $address_fields;
}
if ( function_exists( 'yith_affiliates_install' ) ) {
if ( ! function_exists( 'yith_wcaf_show_dashboard_links_call_back' ) ) {
function yith_wcaf_show_dashboard_links_call_back() {
return 'yes';
}
}
add_filter( 'yith_wcaf_show_dashboard_links', 'yith_wcaf_show_dashboard_links_call_back' );
}

Allow customer to change the order status in WooCommerce My account

Looking to create a custom order process that looks like this:
Customer adds item to cart
During Checkout Process customer uploads design to order
On Checkout payment is verified, but not captured
After design is finalized by the company, they upload the proof for customer review
the customer reviews proof on their dashboard, and clicks a button that processes the order and captures payment
I have figured out everything i need to make this happen except for how to allow the customer to change the status of their order in the dashboard. I do not need them to edit the order, just approve it for payment capture.
I think there should be an easy way to do this with custom PHP code in conjunction with a plugin like Woocommerce Status Control, but I can't seem to find a solution anywhere.
New improved answer: Allow customer to change order status in WooCommerce
You can use the following code that will:
Replace the button text "view" by "approve" on My account > Orders
Display a custom button to approve the order on My account > Order view (single order)
Display a custom success message once customer has approved an order
This will only happen on customer orders with a specific status. So you will have to define:
The order status that require an approval from customer.
The order status that reflect an approved order by the customer (on the 3 functions)
The button text for order approval
The text that will be displayed once customer has approved the order
The code:
// My account > Orders (list): Rename "view" action button text when order needs to be approved
add_filter( 'woocommerce_my_account_my_orders_actions', 'change_my_account_my_orders_view_text_button', 10, 2 );
function change_my_account_my_orders_view_text_button( $actions, $order ) {
$required_order_status = 'processing'; // Order status that requires to be approved
if( $order->has_status($required_order_status) ) {
$actions['view']['name'] = __("Approve", "woocommerce"); // Change button text
}
return $actions;
}
// My account > View Order: Add an approval button on the order
add_action( 'woocommerce_order_details_after_order_table', 'approve_order_button_process' );
function approve_order_button_process( $order ){
// Avoiding displaying buttons on email notification
if( ! ( is_wc_endpoint_url( 'view-order' ) || is_wc_endpoint_url( 'order-received' ) ) ) return;
$approved_button_text = __("Approve this order", "woocommerce");
$required_order_status = 'processing'; // Order status that requires to be approved
$approved_order_status = 'completed'; // Approved order status
// On submit change order status
if( isset($_POST["approve_order"]) && $_POST["approve_order"] == $approved_button_text
&& $order->has_status( $required_order_status ) ) {
$order->update_status( $approved_order_status ); // Change order status
}
// Display a form with a button for order approval
if( $order->has_status($required_order_status) ) {
echo '<form class="cart" method="post" enctype="multipart/form-data" style="margin-top:12px;">
<input type="submit" class="button" name="approve_order" value="Approve this order" />
</form>';
}
}
// My account > View Order: Add a custom notice when order is approved
add_action( 'woocommerce_order_details_before_order_table', 'approved_order_message' );
function approved_order_message( $order ){
// Avoiding displaying buttons on email notification
if( ! ( is_wc_endpoint_url( 'view-order' ) || is_wc_endpoint_url( 'order-received' ) ) ) return;
$approved_order_status = 'completed'; // Approved order status
if( $order->has_status( $approved_order_status ) ) {
wc_print_notice( __("This order is approved", "woocommerce"), 'success' ); // Message
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
On My account > Orders (list):
On My account > Order view (when an order required to be approved):
On My account > Order view (when customer has approved the order):
For order statuses, you can create custom order statuses with code or with plugins.
I know I might be a bit late. But here I am answering this question in case anyone still needs it.
The below code will add a Mark As Completed button in the My Account Order page action list. Please be informed that it checks if the order status is set to Delivered by the admin and then it shows the button to the customers.
I have developed a plugin for this as well and it's available on WordPress repository. You may check it out in case you need it. Order Approval by Customer for WooCommerce.
/*================================
Add Delivered Order Status
==================================*/
add_action( 'init', 'msoa_register_delivered_order_status' );
function msoa_register_delivered_order_status() {
register_post_status( 'wc-delivered', array(
'label' => 'Session Completed',
'public' => true,
'show_in_admin_status_list' => true,
'show_in_admin_all_list' => true,
'exclude_from_search' => false,
'label_count' => _n_noop( 'Delivered <span class="count">(%s)</span>', 'Delivered <span class="count">(%s)</span>' )
) );
}
add_filter( 'wc_order_statuses', 'msoa_add_delivered_status_to_order_statuses' );
function msoa_add_delivered_status_to_order_statuses( $order_statuses ) {
$new_order_statuses = array();
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-processing' === $key ) {
$new_order_statuses['wc-delivered'] = __( 'Delivered', 'order-approval' );
}
}
return $new_order_statuses;
}
add_filter( 'woocommerce_my_account_my_orders_actions', 'msoa_mark_as_received', 10, 2 );
function msoa_mark_as_received( $actions, $order ) {
$order_id = $order->id;
if ( ! is_object( $order ) ) {
$order_id = absint( $order );
$order = wc_get_order( $order_id );
}
// check if order status delivered and form not submitted
if ( ( $order->has_status( 'delivered' ) ) && ( !isset( $_POST['mark_as_received'] ) ) ) {
$check_received = ( $order->has_status( 'delivered' ) ) ? "true" : "false";
?>
<div class="ms-mark-as-received">
<form method="post">
<input type="hidden" name="mark_as_received" value="<?php echo esc_attr( $check_received ); ?>">
<input type="hidden" name="order_id" value="<?php echo esc_attr($order_id);?>">
<?php wp_nonce_field( 'so_38792085_nonce_action', '_so_38792085_nonce_field' ); ?>
<input class="int-button-small" type="submit" value="<?php echo esc_attr_e( 'Mark as Received', 'order-approval' ); ?>" data-toggle="tooltip" title="<?php echo esc_attr_e( 'Click to mark the order as complete if you have received the product', 'order-approval' ); ?>">
</form>
</div>
<?php
}
/*
//refresh page if form submitted
* fix status not updating
*/
if( isset( $_POST['mark_as_received'] ) ) {
echo "<meta http-equiv='refresh' content='0'>";
}
// not a "mark as received" form submission
if ( ! isset( $_POST['mark_as_received'] ) ){
return $actions;
}
// basic security check
if ( ! isset( $_POST['_so_38792085_nonce_field'] ) || ! wp_verify_nonce( $_POST['_so_38792085_nonce_field'], 'so_38792085_nonce_action' ) ) {
return $actions;
}
// make sure order id is submitted
if ( ! isset( $_POST['order_id'] ) ){
$order_id = intval( $_POST['order_id'] );
$order = wc_get_order( $order_id );
$order->update_status( "completed" );
return $actions;
}
if ( isset( $_POST['mark_as_received'] ) == true ) {
$order_id = intval( $_POST['order_id'] );
$order = wc_get_order( $order_id );
$order->update_status( "completed" );
}
$actions = array(
'pay' => array(
'url' => $order->get_checkout_payment_url(),
'name' => __( 'Pay', 'woocommerce' ),
),
'view' => array(
'url' => $order->get_view_order_url(),
'name' => __( 'View', 'woocommerce' ),
),
'cancel' => array(
'url' => $order->get_cancel_order_url( wc_get_page_permalink( 'myaccount' ) ),
'name' => __( 'Cancel', 'woocommerce' ),
),
);
if ( ! $order->needs_payment() ) {
unset( $actions['pay'] );
}
if ( ! in_array( $order->get_status(), apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ), $order ), true ) ) {
unset( $actions['cancel'] );
}
return $actions;
}

Custom action button in WooCommerce admin orders that send an email

I added a action button in the order page, the problem is no passing any data to the function.
add_filter( 'woocommerce_admin_order_actions', 'add_customer_second_payment_reminder_button', 100, 2 );
function add_customer_second_payment_reminder_button( $actions, $order ) {
if ( $order->has_status(array( 'partially-paid' ) )) {
$actions['email_reminder'] = array(
'url' => wp_nonce_url( admin_url('admin-ajax.php?action=customer_second_payment_reminder_button&order_id=' . $order->get_id() )),
'name' => __( 'Email Second Payment Reminder' , 'woocommerce-deposits' ),
'action' => 'email_reminder',
);
}
return $actions;
}
add_action( 'wp_ajax_customer_second_payment_reminder_button', 'customer_second_payment_reminder_button' );
function customer_second_payment_reminder_button( $order_id ) {
do_action( 'woocommerce_deposits_second_payment_reminder_email' , $order_id );
}
add_action( 'admin_head', 'add_customer_second_payment_reminder_button_css' );
function add_customer_second_payment_reminder_button_css() {
echo '<style>.wc-action-button-'.'email_reminder'.'::after { font-family: woocommerce !important; content: "\e030" !important; }</style>';
}
so always show a 0 when i use the button.
customer_second_payment_reminder_button function don't receive the ?order_id parameter from the url.
i put a var_dump($order_id); in the function and show string(0) "" 0
how i can pass the order id to the function?
There are some mistakes and some missing things in your code:
There are no function arguments with wp_ajax_{action} or wp_ajax_nopriv_{action} action hooks.
The order ID is sent via the URL, so you can catch it through $_GET variable
You have to secure your Ajax function and to embed a redirection at the end. If not you get a white page. Also never forget exit; at the end...
So your functional code will be:
add_filter( 'woocommerce_admin_order_actions', 'add_customer_second_payment_reminder_button', 100, 2 );
function add_customer_second_payment_reminder_button( $actions, $order ) {
if ( $order->has_status( array('partially-paid') ) ) {
$actions['email_reminder'] = array(
'url' => wp_nonce_url(
admin_url('admin-ajax.php?action=customer_second_payment_reminder&order_id=' . $order->get_id() ),
'customer-second-payment-reminder'
),
'name' => __( 'Email Second Payment Reminder', 'woocommerce-deposits' ),
'action' => 'email_reminder',
);
}
return $actions;
}
add_action( 'wp_ajax_customer_second_payment_reminder', 'get_customer_second_payment_reminder' );
function get_customer_second_payment_reminder() {
if ( current_user_can('edit_shop_orders') && check_admin_referer('customer-second-payment-reminder') &&
isset($_GET['order_id']) && get_post_type( absint( wp_unslash($_GET['order_id']) ) ) === 'shop_order' ) {
$order_id = absint( wp_unslash($_GET['order_id']) );
$order = wc_get_order($order_id);
if( is_a($order, 'WC_Order') ) {
do_action( 'woocommerce_deposits_second_payment_reminder_email', $order_id, $order );
update_post_meta( $order_id, '_reminder_button', 'OK' ); // For testing purpose (to be removed)
}
}
wp_safe_redirect( wp_get_referer() ? wp_get_referer() : admin_url( 'edit.php?post_type=shop_order' ) );
exit;
}
add_action( 'admin_head', 'customer_second_payment_reminder_button_css' );
function customer_second_payment_reminder_button_css() {
global $pagenow;
if( $pagenow === 'edit.php' && isset($_GET['post_type']) && $_GET['post_type'] === 'shop_order' ) {
echo '<style>.wc-action-button-'.'email_reminder'.'::after { font-family: woocommerce !important; content: "\e02d" !important; }</style>';
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.

Single product custom date fields not validated and saved in Woocommerce

I've added two customer date inputs to the single product page. I need them to be required and validated before adding to the cart, and would also like the dates to be shown on the cart/checkout page and in the order emails.
I found the snippets needed here, however it was only for one custom field so I adjusted to make it for two: https://www.kathyisawesome.com/add-a-custom-field-to-woocommerce-product/
The input fields show up fine, but once you hit the Add to Cart button it doesn't carry throughout the order.
Here is the code used in my functions.php file:
/*
* Display inputs on single product page
*/
function amp_custom_option_1(){
$value = isset( $_POST['_est_delivery'] ) ? sanitize_text_field( $_POST['_est_delivery'] ) : '';
printf( '<div id="dates"><div class="delivery"><label>%s</label><input name="_est_delivery" value="%s" type="date" required /></div>', __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' ), esc_attr( $value ) );
}
add_action( 'woocommerce_before_add_to_cart_form', 'amp_custom_option_1', 9 );
function amp_custom_option_2(){
$value = isset( $_POST['_est_pickup'] ) ? sanitize_text_field( $_POST['_est_pickup'] ) : '';
printf( '<div class="pickup"><label>%s</label><input name="_est_pickup" value="%s" type="date" required /></div></div>', __( 'Estimated Pickup Date:', 'amp-plugin-textdomain-2' ), esc_attr( $value ) );
}
add_action( 'woocommerce_before_add_to_cart_form', 'amp_custom_option_2', 9 );
/*
* Validate when adding to cart
*/
function amp_add_to_cart_validation_1($passed, $product_id, $qty){
if( isset( $_POST['_est_delivery'] ) && sanitize_text_field( $_POST['_est_delivery'] ) == '' ){
$product = wc_get_product( $product_id );
wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a delivery date.', 'amp-plugin-textdomain-1' ), $product->get_title() ), 'error' );
return false;
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation_1', 10, 3 );
function amp_add_to_cart_validation_2($passed, $product_id, $qty){
if( isset( $_POST['_est_pickup'] ) && sanitize_text_field( $_POST['_est_pickup'] ) == '' ){
$product = wc_get_product( $product_id );
wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a pickup date.', 'amp-plugin-textdomain-2' ), $product->get_title() ), 'error' );
return false;
}
return $passed;
}
add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation_2', 10, 3 );
/*
* Add custom data to the cart item
*/
function amp_add_cart_item_data_1( $cart_item, $product_id ){
if( isset( $_POST['_est_delivery'] ) ) {
$cart_item['est_delivery'] = sanitize_text_field( $_POST['_est_delivery'] );
}
return $cart_item;
}
add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data_1', 10, 2 );
function amp_add_cart_item_data_2( $cart_item, $product_id ){
if( isset( $_POST['_est_pickup'] ) ) {
$cart_item['est_pickup'] = sanitize_text_field( $_POST['_est_pickup'] );
}
return $cart_item;
}
add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data_2', 10, 2 );
/*
* Load cart data from session
*/
function amp_get_cart_item_from_session_1( $cart_item, $values ) {
if ( isset( $values['est_delivery'] ) ){
$cart_item['est_delivery'] = $values['est_delivery'];
}
return $cart_item;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'amp_get_cart_item_from_session_1', 20, 2 );
function amp_get_cart_item_from_session_2( $cart_item, $values ) {
if ( isset( $values['est_pickup'] ) ){
$cart_item['est_pickup'] = $values['est_pickup'];
}
return $cart_item;
}
add_filter( 'woocommerce_get_cart_item_from_session', 'amp_get_cart_item_from_session_2', 20, 2 );
/*
* Add meta to order item
*/
function amp_add_order_item_meta_1( $item_id, $values ) {
if ( ! empty( $values['est_delivery'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'est_delivery', $values['est_delivery'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'amp_add_order_item_meta_1', 10, 2 );
function amp_add_order_item_meta_2( $item_id, $values ) {
if ( ! empty( $values['est_pickup'] ) ) {
woocommerce_add_order_item_meta( $item_id, 'est_pickup', $values['est_pickup'] );
}
}
add_action( 'woocommerce_add_order_item_meta', 'amp_add_order_item_meta_2', 10, 2 );
/*
* Get item data to display in cart
*/
function amp_get_item_data_1( $other_data, $cart_item ) {
if ( isset( $cart_item['est_delivery'] ) ){
$other_data[] = array(
'name' => __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' ),
'value' => sanitize_text_field( $cart_item['est_delivery'] )
);
}
return $other_data;
}
add_filter( 'woocommerce_get_item_data', 'amp_get_item_data_1', 10, 2 );
function amp_get_item_data_2( $other_data, $cart_item ) {
if ( isset( $cart_item['est_pickup'] ) ){
$other_data[] = array(
'name' => __( 'Estimated Pickup Date', 'amp-plugin-textdomain-2' ),
'value' => sanitize_text_field( $cart_item['est_pickup'] )
);
}
return $other_data;
}
add_filter( 'woocommerce_get_item_data', 'amp_get_item_data_2', 10, 2 );
/*
* Show custom field in order overview
*/
function amp_order_item_product_1( $cart_item, $order_item ){
if( isset( $order_item['est_delivery'] ) ){
$cart_item_meta['est_delivery'] = $order_item['est_delivery'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_item_product', 'amp_order_item_product_1', 10, 2 );
function amp_order_item_product_2( $cart_item, $order_item ){
if( isset( $order_item['est_pickup'] ) ){
$cart_item_meta['est_pickup'] = $order_item['est_pickup'];
}
return $cart_item;
}
add_filter( 'woocommerce_order_item_product', 'amp_order_item_product_2', 10, 2 );
/*
* Add the field to order emails
*/
function amp_email_order_meta_fields_1( $fields ) {
$fields['est_delivery'] = __( 'Estimated Delivery Date:', 'amp-plugin-textdomain-1' );
return $fields;
}
add_filter('woocommerce_email_order_meta_fields', 'amp_email_order_meta_fields_1');
function amp_email_order_meta_fields_2( $fields ) {
$fields['est_delivery'] = __( 'Estimate Pickup Date:', 'amp-plugin-textdomain-2' );
return $fields;
}
add_filter('woocommerce_email_order_meta_fields', 'amp_email_order_meta_fields_2');
I'm not sure what is wrong with my code? Any help is appreciated.
There was some errors and mistakes. I have changed and removed some hooks, remove unnecessary code, merged functions, revisited all your code. As Your 2 dates fields are on single product pages, they will be related to cart items and order items (so order items meta data).
I have set your 2 date fields slugs and labels in the first function, inside an array. Then I call that function everywhere else and I use a foreach loop to process each field. This avoid repetitions, optimize and compact the code.
The code (commented):
// Utility function that contain the 2 field keys and labels pairs used on all other functions
function get_date_label_keys(){
$text_domain = 'woocommerce';
return array( 'est_delivery' => __( 'Estimated Delivery Date', $text_domain ),
'est_pickup' => __( 'Estimated Pickup Date', $text_domain ) );
}
// Display custom fields on single product page (hook replaced)
add_action( 'woocommerce_before_add_to_cart_button', 'amp_display_custom_fields', 20 );
function amp_display_custom_fields(){
echo '<div id="dates">';
// Loop through each custom field
foreach( get_date_label_keys() as $key => $label ){
$class = str_replace('est_', '', $key); // The class
$value = isset($_POST[$key]) ? sanitize_text_field($_POST[$key]) : ''; // Display the value
printf( '<div class="%s"><label>%s:</label> <input type="date" name="%s" value="%s" required /></div>', $class, $label, $key, $value );
}
echo '</div><br clear="all">';
}
// Add to cart fields validation (in case of need)
add_filter( 'woocommerce_add_to_cart_validation', 'amp_add_to_cart_validation', 20, 3 );
function amp_add_to_cart_validation( $passed, $product_id, $qty ){
// Loop through each custom field
foreach( get_date_label_keys() as $key => $label ){
if( isset( $_POST[$key] ) && empty( $_POST[$key] ) ){
wc_add_notice( sprintf( __( '%s cannot be added to the cart until you enter a delivery date.', $domain ), get_the_title() ), 'error' );
$passed = false;
}
}
return $passed;
}
// Add to cart items the custom data
add_filter( 'woocommerce_add_cart_item_data', 'amp_add_cart_item_data', 20, 2 );
function amp_add_cart_item_data( $cart_item, $product_id ){
// Loop through each custom field
foreach( get_date_label_keys() as $key => $label ){
if( isset( $_POST[$key] ) )
$cart_item['dates'][$key] = sanitize_text_field( $_POST[$key] );
}
return $cart_item;
}
// Display the dates in cart items on cart and checkout pages
add_filter( 'woocommerce_get_item_data', 'amp_get_item_data', 20, 2 );
function amp_get_item_data( $item_data, $cart_item = null ) {
// Loop through each custom field
foreach( get_date_label_keys() as $key => $label ){
if ( isset( $cart_item['dates'][$key] ) )
$item_data[] = array(
'name' => $label,
'value' => sanitize_text_field( $cart_item['dates'][$key] )
);
}
return $item_data;
}
// Add order item meta data and Display the data in order items (hook replaced)
add_action( 'woocommerce_checkout_create_order_line_item', 'amp_add_order_item_meta', 20, 4 );
function amp_add_order_item_meta( $item, $cart_item_key, $values, $order ) {
foreach( get_date_label_keys() as $key => $label ){
// Loop through each custom field
if ( ! empty( $values['dates'][$key] ) )
$item->update_meta_data( $label, $values['dates'][$key] );
}
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
On cart page (and checkout too):
Order received and order view pages (in admin order edit pages and email notifications too):

Categories