woocommerce order list action button on click - wordpress

I am trying to add a custom button in woocommerce order list that will send an email to the customer (the button will only show next to orders that have status 'processing' and a custom field 'deltime' is not empty). So I got the button to show but the email is send every time that I am in woocommerce/orders or during refresh instead sending only when the button is clicked. I must have understood something wrong about action hooks...any ideas?
here is the code used in functions.php :
// Add your custom order status action button (for orders with "processing" status)
add_filter( 'woocommerce_admin_order_actions', 'add_custom_email_button', 100, 2 );
function add_custom_email_button( $actions, $order ) {
// Display the button for all orders that have a 'processing' status
// Get Order ID (compatibility all WC versions)
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
global $wpdb;
$deltime = $wpdb->get_var( "SELECT meta_value FROM wp_postmeta WHERE post_id = $order_id AND meta_key = 'is_gift' " );
if ( $order->has_status( array( 'processing' ) ) && (!empty($deltime)) ) {
$mailer = WC()->mailer();
$mails = $mailer->get_emails();
if ( ! empty( $mails ) ) {
foreach ( $mails as $mail ) {
if ( $mail->id == 'customer_processing_order' ) {
$mail->trigger( $order_id );
}
}
}
// Set the action button
$actions['partial'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=add_custom_email_button&order_id=' . $order_id )),
'name' => __( 'Αποστολή Email', 'woocommerce' ),
'action' => "view partial", // keep "view" class for a clean button CSS
);
}
return $actions;
}
// Set Here the WooCommerce icon for your action button
add_action( 'admin_head', 'add_custom_email_button_css' );
function add_custom_email_button_css() {
echo '<style>.view.partial::after { font-family: woocommerce; content: "\1F4E7" !important; }</style>';
}
button image

The way you have it defined now, the button definition and action are in the same function, so when the button is created, its action is also performed.
You have to split the button definition and the action in two different functions:
add_filter( 'woocommerce_admin_order_actions', 'add_custom_email_button', 100, 2 );
function add_custom_email_button( $actions, $order ) {
if ( $order->status == "processing" ) {
$order_id = method_exists( $order, 'get_id' ) ? $order->get_id() : $order->id;
global $wpdb;
$deltime = $wpdb->get_var( "SELECT meta_value FROM wp_postmeta WHERE post_id = $order_id AND meta_key = 'is_gift' " );
if ( !empty( $deltime ) ) {
// Set the action button
$actions['partial'] = array(
'url' => wp_nonce_url( admin_url( 'admin-ajax.php?action=click_custom_email_button&order_id=' . $order_id )),
'name' => __( 'Αποστολή Email', 'woocommerce' ),
'action' => "view partial", // keep "view" class for a clean button CSS
);
}
}
return $actions;
}
add_action( 'wp_ajax_click_custom_email_button', 'click_custom_email_button' );
function click_custom_email_button( $order_id ) {
$mailer = WC()->mailer();
$mails = $mailer->get_emails();
if ( ! empty( $mails ) ) {
foreach ( $mails as $mail ) {
if ( $mail->id == 'customer_processing_order' ) {
$mail->trigger( $order_id );
}
}
}
}

Related

WooCommerce Shortcode For "Order Again" Customer's Last Order

I'm fairly new with this, but I am learning. I am trying to create a shortcode which can be inserted anywhere on the site, allowing the customer to order their previous order again.
In other words, I need to enable the customer to "order again" their last order. Main problem is, when I try this, the site goes blank (white screen).
Any ideas what's wrong here?
add_shortcode( 'order_again', 'matt_order_again' );
function matt_order_again( $order ) {
if ( is_user_logged_in() ) {
$user_id = get_current_user_id();
$customer = new WC_Customer( $user_id );
$last_order = $customer->get_last_order();
if ( $last_order->has_status( 'completed' ) ) {
$actions['order-again'] = array(
'url' => wp_nonce_url( add_query_arg( 'order_again', $order->get_id(), wc_get_cart_url() ), 'woocommerce-order_again' ),
'name' => __( 'Order again', 'woocommerce' ),
);
}
return $actions;
}
}
I have tried adding the global variable for WC.
try this :
add_shortcode( 'order_again', 'matt_order_again' );
function matt_order_again( $order ) {
if ( is_user_logged_in() ) {
$user_id = get_current_user_id();
$customer = new WC_Customer( $user_id );
$last_order = $customer->get_last_order();
if ( $last_order->has_status( 'completed' ) ) {
$actions['order-again'] = array(
'url' => wp_nonce_url( add_query_arg( 'order_again', $last_order->get_id(), wc_get_cart_url() ), 'woocommerce-order_again' ),
'name' => __( 'Order again', 'woocommerce' ),
);
}
return $actions;
}
}
Or if you want to return a button with url for order again using shorcode use this code (edited).
add_shortcode('order_again', 'matt_order_again');
function matt_order_again($order)
{
if (is_user_logged_in()) {
global $woocommerce;
ob_start();
$user_id = get_current_user_id();
$customer = new WC_Customer($user_id);
$last_order = $customer->get_last_order();
if(!$last_order){
return;
}
if ($last_order->has_status('completed')) {
$url = wp_nonce_url(add_query_arg('order_again', $last_order->get_id(), wc_get_cart_url()), 'woocommerce-order_again');
echo '' . __('Order Again', 'woocomerce') . '';
}
$contents = ob_get_contents();
ob_end_clean();
return $contents;
}
}

Update WooCommerce order status if product custom field is set

I need to automatically set a certain order status (different than processing) when getting a new order.
This is achieved by this function:
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) { return; }
$order = wc_get_order( $order_id );
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
This totally works. Now I only need this to happen when a product has a customization.
The way to customize a product is filling an input field before adding to cart. The input is attached to the item data:
// Add custom cart item data
add_filter( 'woocommerce_add_cart_item_data', 'add_custom_cart_item_data', 10, 2 );
function add_custom_cart_item_data( $cart_item_data, $product_id ){
if( isset($_POST['custom_text']) ) {
$cart_item_data['custom_text'] = sanitize_text_field( $_POST['custom_text'] );
$cart_item_data['unique_key'] = md5( microtime().rand() ); // Make each item unique
}
return $cart_item_data;
}
Then the custom text is retrieved and displayed in cart and in the order data using this:
// Display custom cart item data on cart and checkout
add_filter( 'woocommerce_get_item_data', 'display_custom_cart_item_data', 10, 2 );
function display_custom_cart_item_data( $cart_item_data, $cart_item ) {
if ( !empty( $cart_item['custom_text'] ) ){
$cart_item_data[] = array(
'name' => __('Customization', 'woocommerce'),
'value' => $cart_item['custom_text'] // Already sanitized field
);
}
return $cart_item_data;
}
// Save and display custom item data everywhere on orders and email notifications
add_action( 'woocommerce_checkout_create_order_line_item', 'add_product_custom_field_as_order_item_meta', 10, 4 );
function add_product_custom_field_as_order_item_meta( $item, $cart_item_key, $values, $order ) {
if ( isset($values['custom_text']) ) {
$item->update_meta_data('Add on', $values['custom_text'] );
}
}
I'm trying using the if ( isset($values['custom_text']) ) part as a trigger of the function to change the order status only if the product add on is set and other similar methods (like if ( !empty( $cart_item['custom_text'] ) ) but I'm not sure this is the way to go:
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) {return;}
$order = wc_get_order( $order_id );
if ( isset($values['custom_text']) ) {
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
}
This above does nothing. Am I anywhere near it with this approach?
EDIT: I tried this too
add_action('woocommerce_thankyou','change_order_status');
function change_order_status( $order_id ) {
if ( ! $order_id ) {return;}
$order = wc_get_order( $order_id );
foreach ( $order->get_items() as $item_id => $item ) {
$allmeta = $item->get_meta_data();
if ( isset($values['custom_text']) ) {
if( 'processing'== $order->get_status() ) {
$order->update_status( 'wc-custom-status' );
}
}
}
}
Your code contains some unnecessary steps as well as some shortcomings
For example, the woocommerce_add_cart_item_data hook contains 3 arguments versus 2
So you get:
// Add custom cart item data
function filter_add_cart_item_data( $cart_item_data, $product_id, $variation_id ) {
// Isset and NOT empty
if ( isset ( $_POST[ 'custom_text' ] ) && ! empty ( $_POST[ 'custom_text' ] ) ) {
$cart_item_data['custom_text'] = sanitize_text_field( $_POST['custom_text'] );
}
return $cart_item_data;
}
add_filter( 'woocommerce_add_cart_item_data', 'filter_add_cart_item_data', 10, 3 );
// Display custom cart item data on cart and checkout
function filter_woocommerce_get_item_data( $cart_data, $cart_item = null ) {
if ( isset ( $cart_item['custom_text'] ) ) {
$cart_data[] = array(
'name' => __( 'Customization', 'woocommerce' ),
'value' => $cart_item['custom_text']
);
}
return $cart_data;
}
add_filter( 'woocommerce_get_item_data', 'filter_woocommerce_get_item_data', 10, 2 );
// Add the information as meta data so that it can be seen as part of the order
// Save and display custom item data everywhere on orders and email notifications
function action_woocommerce_checkout_create_order_line_item( $item, $cart_item_key, $values, $order ) {
if ( isset ( $values['custom_text'] ) ) {
$item->update_meta_data( 'custom_text', $values['custom_text'] );
}
}
add_action( 'woocommerce_checkout_create_order_line_item', 'action_woocommerce_checkout_create_order_line_item', 10, 4 );
// On thankyou page
function action_woocommerce_thankyou( $order_id ) {
// Get $order object
$order = wc_get_order( $order_id );
// Is a WC_Order
if ( is_a( $order, 'WC_Order' ) ) {
// Only when the current order status is 'processing'
if ( $order->get_status() == 'processing' ) {
// Loop trough
foreach ( $order->get_items() as $item ) {
// Get meta
$value = $item->get_meta( 'custom_text' );
// NOT empty
if ( ! empty ( $value ) ) {
// Update status (change to desired status)
$order->update_status( 'cancelled' );
// Stop loop
break;
}
}
}
}
}
add_action( 'woocommerce_thankyou', 'action_woocommerce_thankyou', 10, 1 );
Currently it is just checking if the value exists, to compare it effectively
Change
// NOT empty
if ( ! empty ( $value ) ) {
// Update status
$order->update_status( 'cancelled' );
// Stop loop
break;
}
To
// Compare
if ( $value == 'some value' ) ) {
// Update status
$order->update_status( 'cancelled' );
// Stop loop
break;
}

Add custom select field with validation to WooCommerce checkout page if certain products are in cart

I wish to add a custom select field with validation to the WooCommerce checkout page if certain products are in cart.
With my current code I retrieve the value of my custom WooCommerce form field. However, it display "array" at the order page.
I have an select field which have an option of 1 and 0. Upon selection of the select field, i want it to display either 1 or 0 at the order page but im unable to do so.
Please guide me on what should i do with my current codes:
//AMBASSADOR CUSTOM CHECKOUT FIELDS, CONTENT add marketplace for sameday TEST
add_action( 'woocommerce_after_checkout_billing_form', 'aym_custom_checkout_field' );
function aym_custom_checkout_field( $checkout ) {
//Check if Product in Cart
$prod_in_cart_17563 = aym_is_conditional_product_in_cart_17563( 212 );
if ( $prod_in_cart_17563 === true ) {
$domain = 'wocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order' ),
'required' => true,
'options' => array(
'Y' => __('1'),
'N' => __('0')
),'default' => $default),
$checkout->get_value( '_my_field_name' ) );
}
}
//AMBSSADOR BUNDLE add marketplace for same day pa rt 2
function aym_is_conditional_product_in_cart_17563( $product_id ) {
//Check to see if user has product in cart
global $woocommerce;
//flag no product in cart
$prod_in_cart_17563 = false;
foreach ( $woocommerce->cart->get_cart() as $cart_item_key => $values ) {
$_product = $values['data'];
if ( $_product->id === $product_id ) {
//product is in cart!
$prod_in_cart_17563 = true;
}
}
return $prod_in_cart_17563;
}
//process orders in order page
// Custom checkout fields validation
add_action( 'woocommerce_checkout_process', 'custom_checkout_field_process' );
function custom_checkout_field_process() {
if ( isset($_POST['_my_field_name']) && empty($_POST['_my_field_name']) )
wc_add_notice( __( 'Please fill in "My 1st new field".' ), 'error' );
}
// Save custom checkout fields the data to the order
add_action( 'woocommerce_checkout_create_order', 'custom_checkout_field_update_meta', 10, 2 );
function custom_checkout_field_update_meta( $order, $data ){
if( isset($_POST['_my_field_name']) && ! empty($_POST['_my_field_name']) )
$order->update_meta_data( '_my_field_name', sanitize_text_field( $_POST['_my_field_name'] ) );
}
/**
* Update the order meta with field value
**/
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 ($_POST['_my_field_name']) update_post_meta( $order_id, 'My Field', esc_attr($_POST['_my_field_name']));
}
// View fields in Edit Order Page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'display_custom_fields_value_admin_order', 10, 1 );
function display_custom_fields_value_admin_order( $order ){
// Display the delivery option
if( $delivery_option = $order->get_meta('_my_field_name') )
echo '<p><strong>'.__('Delivery type').':</strong> ' . $delivery_option . '</p>';
}
// 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 ) {
if( $selectoption = $order->get_meta('_my_field_name') ) {
//$value = wc_get_hearaboutus_options()[$selectoptions];
$meta= get_post_meta( $post->ID, $selectoption, true );
$myvalues = unserialize( $meta );
echo '<p><strong>'.__('Market_Place').':</strong> ' . $myvalues . '</p>';
}
}
I have partly rewritten / modified your code with some (extra) features
The ability to check for multiple product IDs in the shopping cart
The custom field is only added if a certain product id is in the shopping cart
The possibility to check out if the custom field is not present (product ID is NOT in cart)
No possibility to checkout as long as the value 'Y' is not selected from the custom select menu (Product ID is IN cart)
Explanation via comment tags added in the code
// Add custom 'select' field after checkout billing form (if product ID is in cart)
function action_woocommerce_after_checkout_billing_form( $checkout ) {
// Check if Product in Cart
// Multiple product IDs can be entered, separated by a comma
$product_in_cart = is_product_in_cart( array( 212, 30, 815 ) );
// True
if ( $product_in_cart ) {
$domain = 'woocommerce';
$default = 'Y';
woocommerce_form_field( '_my_field_name', array(
'type' => 'select',
'class' => array( 'form-row-wide' ),
'label' => __( 'Market Place - Please Select Y to complete this order', $domain ),
'required' => true,
'options' => array(
'Y' => __( 'Y', $domain ),
'N' => __( 'N', $domain ),
),
'default' => $default,
), $checkout->get_value( '_my_field_name' ) );
}
}
add_action( 'woocommerce_after_checkout_billing_form', 'action_woocommerce_after_checkout_billing_form', 10, 1 );
// Function to check if a certain product ID is in cart
function is_product_in_cart( $targeted_ids ) {
// Flag no product in cart
$flag = false;
// WC Cart NOT null
if ( ! is_null( WC()->cart ) ) {
// Loop through cart items
foreach( WC()->cart->get_cart() as $cart_item ) {
// Check cart item for defined product Ids
if ( in_array( $cart_item['product_id'], $targeted_ids ) ) {
// Product is in cart
$flag = true;
// Break loop
break;
}
}
}
return $flag;
}
// Custom checkout 'select' field validation
function action_woocommerce_checkout_process() {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$domain = 'woocommerce';
$my_field_name = $_POST['_my_field_name'];
// Empty
if ( empty ( $my_field_name ) ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
// NOT empty but value is 'N'
if ( ! empty ( $my_field_name ) && $my_field_name == 'N' ) {
wc_add_notice( __( 'Please Select Y to complete this order', $domain ), 'error' );
}
}
}
add_action( 'woocommerce_checkout_process', 'action_woocommerce_checkout_process', 10, 0 );
// Save custom checkout 'select' field
function action_woocommerce_checkout_create_order( $order, $data ) {
// Isset
if ( isset( $_POST['_my_field_name'] ) ) {
$my_field_name = $_POST['_my_field_name'];
// NOT empty & equal to 'Y'
if ( ! empty( $my_field_name ) && $my_field_name == 'Y' ) {
$order->update_meta_data( '_my_field_name', sanitize_text_field( $my_field_name ) );
}
}
}
add_action( 'woocommerce_checkout_create_order', 'action_woocommerce_checkout_create_order', 10, 2 );
// Display the custom 'select' field value on admin order pages after billing adress
function action_woocommerce_admin_order_data_after_billing_address( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_admin_order_data_after_billing_address', 'action_woocommerce_admin_order_data_after_billing_address', 10, 1 );
// Display the custom 'select' field value on 'order received' and 'order view' pages (frontend)
function action_woocommerce_order_details_after_order_table( $order ) {
$domain = 'woocommerce';
// Get meta
$my_field_name = $order->get_meta( '_my_field_name' );
// NOT empty
if ( ! empty ( $my_field_name ) ) {
echo '<p><strong>' . __( 'Delivery type', $domain ) . ':</strong> ' . $order->get_meta( '_my_field_name' ) . '</p>';
}
}
add_action( 'woocommerce_order_details_after_order_table', 'action_woocommerce_order_details_after_order_table', 10, 1 );

Hide / Change WooCommerce admin notice

Hi WooCommerce ninjas!
I'm developing WooCommerce plugin and every time when I submit form (Save Changes button) on top shows update notice with 'Your settings have been saved.'. How I can hide or change this notice, I'm use woocommerce_show_admin_notice filter but don't work in my plugin class. Below is part of code from my plugin. Any ideas for hook who will be usefull?
Great thanks!
<?php
class name_of_plugin extends WC_Payment_Gateway {
public $error = '';
// Setup our Gateway's id, description and other values
function __construct() {
$this->id = "name_of_plugin";
$this->method_title = __( "Name", 'domain' );
$this->method_description = __( "Gateway Plug-in for WooCommerce", 'domain' );
$this->title = __( "TFS VPOS", 'domain' );
$this->icon = null;
$this->has_fields = false;
$this->init_settings();
$this->init_form_fields();
$this->title = $this->get_option( 'title' );
$this->testurl = 'https://example.com/payment/api';
$this->liveurl = 'https://example.com/payment/api';
// Save settings
if ( is_admin()) {
add_action( 'woocommerce_update_options_payment_gateways_' . $this->id, array( $this, 'process_admin_options' ) );
}
// Disable Admin Notice
add_filter( 'woocommerce_show_admin_notice', array( $this, 'shapeSpace_custom_admin_notice' ), 10, 2 );
// add the filter
add_filter( 'woocommerce_add_error', array( $this, 'filter_woocommerce_add_notice_type' ), 10, 1 );
} // End __construct()
// display custom admin notice
public function filter_woocommerce_add_notice_type($true, $notice ) {
// magic happen here...
return $true;
}
I can't see any proper hook that can be used to remove this.
But these 2 seems to work.
My first thought is to reload the page so the settings text will be gone at the time. Something like this.
add_action( 'woocommerce_sections_checkout', 'woocommerce_sections_checkout' );
function woocommerce_sections_checkout() {
if ( isset( $_GET['section'] ) && isset( $_REQUEST['_wpnonce'] ) && ( $_GET['section'] === 'paypal' )
&& wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-settings' ) ) {
WC_Admin_Settings::add_message( __( 'Your settings have been saved!', 'woocommerce' ) );
wp_safe_redirect( wp_get_raw_referer() );
exit();
}
}
Then my second option is if you wanted to change the text, we can use the filter gettext.
add_filter( 'gettext', 'woocommerce_save_settings_text', 20, 3 );
function woocommerce_save_settings_text( $translated_text, $text, $domain ) {
if ( ( $domain == 'woocommerce' ) && isset( $_GET['section'] ) && ( $_GET['section'] === 'paypal' ) ) {
switch ( $translated_text ) {
case 'Your settings have been saved.' :
$translated_text = __( 'Your awesome settings have been saved.', 'woocommerce' );
break;
}
}
return $translated_text;
}
Please do note that this code is just an example and will work for paypal settings. Change everything that is needed.

Changes in item meta_data on payment_completed

I want change add/change a meta_data in order item after complete a payment
is somethink like add a custom field with random number.
How I can make that ?
I dont found how
public function process_payment( $order_id ) {
global $woocommerce;
$order = new WC_Order( $order_id );
// Mark as on-hold (we're awaiting the cheque)
if ( 'yes' == $this->debug ) {
$this->log->add( 'Compra', "IPN Response Loggin test" );
}
$order->get_items();
if ( sizeof( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $item ) {
if ( ! $item['qty'] ) {
continue;
}
// Any information about function to edit meta data in item ?
}
}
$order->payment_complete();
// Reduce stock levels
$order->reduce_order_stock();
// Remove cart
$woocommerce->cart->empty_cart();
// Return thankyou redirect
return array(
'result' => 'success',
'redirect' => $this->get_return_url( $order )
);
}
Use wc_update_order_item_meta for this purpose.
Try this
if ( sizeof( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $id => $item ) {
if ( ! $item['qty'] ) {
continue;
}
// Any information about function to edit meta data in item ?
wc_update_order_item_meta( $id, 'your meta key', 'new value' );
}
}
If you look at the payment_complete() method in the Order abstract class you will see the woocommerce_payment_complete action hook. If you want to run something when the payment is completed, then you would attach your function to this hook. Without really understanding what you are doing, the following will simply add a random number (not necessarily unique) to each item in the order.
add_action( 'woocommerce_payment_complete', 'so_27852832_item_data' );
function so_27852832_item_data( $order_id ){
$order = new WC_Order( $order_id );
if ( sizeof( $order->get_items() ) > 0 ) {
foreach ( $order->get_items() as $id => $item ) {
wc_update_order_item_meta( $id, '_random_number', rand() );
}
}
}

Resources