Send some product data at publish time in Woocommerce - php

I am trying to develop a plugin for Woocommerce which it sends new published product's information to a Telegram channel. I need to get the price and image of product when it is published. but my code returns empty.
my code :
add_action('transition_post_status', 'btb_send_telegram_post', 10, 3);
function btb_send_telegram_post( $new_status, $old_status, $post ) {
if(
$old_status != 'publish'
&& $new_status == 'publish'
&& !empty($post->ID)
&& in_array( $post->post_type,array( 'product'))
) {
// product is new published.
$product = wc_get_product ( $post->ID );
$message = $product->get_short_description()."\r\n";
$message .= "price : ". $product->get_price()."\r\n";
$message .= " regular price : ". $product->get_regular_price() ."\r\n";
$message .= "sale price : ". $product->get_sale_price()."\r\n";
btb_send_message($message);
}
I think it is because the changing status of product to publish occurs before it completely saved in database. because when I save a draft before publish it returns correct prices. for that matter I need to do one of these two approaches:
Save product as a draft by my code before publish .
Use another action which it triggers after product meta is saved completely.
And now I don't have any idea how to do both of above approaches.
any advice will be appreciated.
Thank you.

Update 2 (the product data is not anymore empty)
You could try this custom function hooked in save_post action hook:
// Only on WooCommerce Product edit pages (Admin)
add_action( 'save_post', 'send_telegram_post', 50, 3 );
function send_telegram_post( $post_id, $post, $update ) {
if ( $post->post_type != 'product') return; // Only products
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE )
return $post_id; // Exit if it's an autosave
if ( $post->post_status != 'publish' )
return $post_id; // Exit if not 'publish' post status
if ( ! current_user_can( 'edit_product', $post_id ) )
return $post_id; // Exit if user is not allowed
// Check if product message has already been sent (avoiding repetition)
$message_sent = get_post_meta( $post_id, '_message_sent', true );
if( ! empty($message_sent) )
return $post_id; // Exit if message has already been sent
## ------------ MESSAGE ------------ ##
// Get active price or "price" (we check if sale price exits)
$price = empty( $_POST['_sale_price'] ) ? $_POST['_regular_price'] : $_POST['_sale_price'];
$message = '';
$rn = "\r\n";
// Title
if( ! empty( $_POST['post_title'] ) )
$message .= 'Title : ' . $_POST['post_title'] . $rn;
// Short description
if( ! empty( $_POST['excerpt'] ) )
$message .= 'Description : ' . $_POST['excerpt'] . $rn;
// Active price
if( ! empty( $price ) )
$message .= 'Price : ' . $price . "\r\n";
// Regular price
if( ! empty( $_POST['_regular_price'] ) )
$message .= 'Regular price : ' . $_POST['_regular_price'] . $rn;
// Sale price
if( ! empty( $_POST['_sale_price'] ) )
$message .= 'Sale price : ' . $_POST['_sale_price'] . $rn;
// Send message custom function
btb_send_message( $message );
// Just for testing (uncomment below to enable):
// update_post_meta( $post_id, '_message_content', $message ); // Message in database
// add custom meta field to mark this product as "message sent"
update_post_meta( $post_id, '_message_sent', '1' );
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.

Related

WooCommerce customized email only for processing and completed orders

I am using a plugin to send custom referral codes in the email orders but now I found that every order email has the code inserted.
function gens_raf_customer_email( $order, $sent_to_admin, $plain_text ) {
$user_id = ( version_compare( WC_VERSION, '2.7', '<' ) ) ? $order->customer_user : $order->get_customer_id();
if( ! empty( $user_id ) && ( get_user_meta($user_id, "gens_referral_id", true) ) != '' ){
$code = get_user_meta($user_id, "gens_referral_id", true);
} else {
$code = ( version_compare( WC_VERSION, '2.7', '<' ) ) ? $order->billing_email : $order->get_billing_email();
}
if( $plain_text ){
_e('Your referral code is: ','gens-raf') . $code;
} else {
echo '<p style="text-align:center;margin-top:10px;">Your referral code is: ' .get_home_url() .'?raf='. $code . '</p>';
}
}
add_action('woocommerce_email_customer_details', 'gens_raf_customer_email', 30, 3 );
I was messing around with
if ( $email->id == 'customer_completed_order' )
But gave me error from the php code builder. The main issue is to send that email only to completed and/or processing orders instead of refunded, cancelled and so on.
Thank you!
You're getting the error because you didn't add the fourth $email argument available to the woocommerce_email_customer_details hook.
The content will only be displayed in the Completed order and
Processing order templates.
Try this:
add_action('woocommerce_email_customer_details', 'gens_raf_customer_email', 30, 4 );
function gens_raf_customer_email( $order, $sent_to_admin, $plain_text, $email ) {
if ( $email->id == 'customer_completed_order' || $email->id == 'customer_processing_order' ) {
$user_id = ( version_compare( WC_VERSION, '2.7', '<' ) ) ? $order->customer_user : $order->get_customer_id();
if( ! empty( $user_id ) && ( get_user_meta($user_id, "gens_referral_id", true) ) != '' ){
$code = get_user_meta($user_id, "gens_referral_id", true);
} else {
$code = ( version_compare( WC_VERSION, '2.7', '<' ) ) ? $order->billing_email : $order->get_billing_email();
}
if( $plain_text ){
_e('Your referral code is: ','gens-raf') . $code;
} else {
echo '<p style="text-align:center;margin-top:10px;">Your referral code is: ' .get_home_url() .'?raf='. $code . '</p>';
}
}
}
The code has been tested and works.
The variable $email is the 4th missing argument from your hooked function, that you need to target specific email notifications.
Use instead (for woocommerce 3 and above):
add_action('woocommerce_email_customer_details', 'gens_raf_customer_email', 100, 4 );
function gens_raf_customer_email( $order, $sent_to_admin, $plain_text, $email ) {
// Target specific notifications: Customer processing and completed orders
if ( in_array( $email->id, ['customer_processing_order', 'customer_completed_order'] ) ) {
$gens_raf = get_user_meta( $order->get_user_id(), "gens_referral_id", true );
$code = empty( $gens_raf ) ? $order->get_billing_email() : $gens_raf;
if( $plain_text ){
printf( __('Your referral code is: %s', 'gens-raf'), $code );
} else {
$output = sprintf( __("Your referral code is: %s", "gens-raf"), get_home_url() .'?raf='. $code );
echo '<p style="text-align:center;margin-top:10px;">' . $output . '</p>';
}
}
}
Code goes in functions.php file of the active child theme (or active theme). It should works.

Hide a custom action button on click displaying a text in WooCommerce admin orders list

I am creating woocommerce plugin to send order details via WhatsApp. Here is my plugin code
add_filter( 'manage_edit-shop_order_columns', 'dvs_whatsapp_msg_list_column' );
function dvs_whatsapp_msg_list_column( $columns ) {
$columns['dvs_show_whatsapp'] = 'WhatsApp';
return $columns;
}
add_action( 'manage_shop_order_posts_custom_column', 'dvs_whatsapp_msg_list_column_content' );
function dvs_whatsapp_msg_list_column_content( $column ) {
global $post;
if ( 'dvs_show_whatsapp' === $column ) {
$order = wc_get_order( $post->ID );
$firstname = $order->get_billing_first_name();
$lastname = $order->get_billing_last_name();
$phone = $order->get_billing_phone();
$ordernum = $order->get_order_number();
$total = $order->get_total();
$payment = $order->get_payment_method_title();
$country = $order->get_billing_country();
$calling_code = WC()->countries->get_country_calling_code($country);
$whatsappnum = $calling_code.$phone;
$msg = 'Hello ' .$firstname. ' ' .$lastname. ', your order #' .$ordernum. ' has been received. The order amount is ' .$total. '. Your payment method is ' .$payment. '. Please contact us if you have any question regarding your order. Thank you.';
echo 'Send WhatsApp';
}
}
This is output
I want when shop manager or admin click the Send Whatsapp link then it will hide the link and show Message sent so shop manager or admin can know the details of this msg is already sent.
Please help.
Javascript is not the way to achieve this. You will use the following instead to hide the link and display "Message sent" once an external link has been clicked:
add_filter( 'manage_edit-shop_order_columns', 'dvs_whatsapp_msg_list_column' );
function dvs_whatsapp_msg_list_column( $columns ) {
$columns['whatsapp'] = __('WhatsApp', 'woocommerce');
return $columns;
}
add_action( 'manage_shop_order_posts_custom_column', 'dvs_whatsapp_msg_list_column_content' );
function dvs_whatsapp_msg_list_column_content( $column ) {
if ( 'whatsapp' === $column ) {
global $the_order;
if( ! $the_order->get_meta('_wapp_sent') ) {
echo '' . __("Send WhatsApp") . '';
}
else {
echo __("Message sent", "woocommerce");
}
}
}
add_action( 'admin_init', 'dvs_redirect_whatsapp_send' );
function dvs_redirect_whatsapp_send() {
global $pagenow;
# Check current admin page.
if ( $pagenow == 'edit.php' && isset($_GET['post_type']) && $_GET['post_type'] == 'shop_order'
&& isset($_GET['send']) && $_GET['send'] == 'dvs_whatsapp' && isset($_GET['order_id']) && $_GET['order_id'] > 0 ) {
$order = wc_get_order( $_GET['order_id'] );
$msg = sprintf( __("Hello %s %s, your order #%s has been received. The order amount is %s. Your payment method is %s. %s", "woocommerce"),
$order->get_billing_first_name(),
$order->get_billing_last_name(),
$order->get_order_number(),
$order->get_total(),
$order->get_payment_method_title(),
__("Please contact us if you have any question regarding your order. Thank you.", "woocommerce")
);
$whatsapp_num = WC()->countries->get_country_calling_code( $order->get_billing_country() ) . $order->get_billing_phone();
update_post_meta( $_GET['order_id'], '_wapp_sent', 'true' ); // Mark order as WhatsApp message sent
wp_redirect( 'https://wa.me/' . $whatsappnum . '?text=' . urlencode($msg) ); // Redirect to WhatsApp sending service
exit;
}
}
Code goes in functions.php file of your active child theme (or active theme). Tested and works.
I believe this should do the trick:
jQuery to insert on your page
jQuery('.dvs-whatsapp-btn').click(function(){
jQuery('<span class="link-clicked">Link clicked!</span>').insertAfter('.dvs-whatsapp-btn');
jQuery('.dvs-whatsapp-btn').hide();
});

Save WooCommerce custom Session Variables as order meta data

I'm trying to store custom session variables in database. Then, show them inside new order email and order details in WooCommerce Admin.
I have custom variables inside session:
add_action( 'init', 'oturum_degiskeni_olustur' );
function oturum_degiskeni_olustur () {
// Early initialize customer session
if ( isset(WC()->session) && ! WC()->session->has_session() ) {
WC()->session->set_customer_session_cookie( true );
}
if ( isset( $_GET['konumu'] ) || isset( $_GET['masa_no'] ) ) {
$konum = isset( $_GET['konumu'] ) ? esc_attr( $_GET['konumu'] ) : '';
$masa = isset( $_GET['masa_no'] ) ? esc_attr( $_GET['masa_no'] ) : '';
// Set the session data
WC()->session->set( 'custom_data', array( 'konum' => $konum, 'masa' => $masa ) );
}
}
Firstly, I added custom variables to database with this code;
// Storing session variables for using them in order notifications
add_action( 'woocommerce_checkout_create_order', 'oturum_degiskeni_kaydet' );
function oturum_degiskeni_kaydet( $order, $data ) {
if ( $_POST['konumu'] ) update_meta_data( $order_id, '_konum', esc_attr( $_POST['konumu'] ) );
if ( $_POST['masa_no'] ) update_meta_data( $order_id, '_masa', esc_attr( $_POST['masa_no'] ) );
}
Second, I added this variable's data to a new order email for admin.
// Show this session variables in new order email for admin
add_action( 'woocommerce_email_after_order_table', 'konumu_emaile_ekle', 20, 4 );
function konumu_emaile_ekle( $order, $sent_to_admin, $plain_text, $email ) {
if ( get_post_meta( $order->get_id(), '_konum', true ) ) echo '<p><strong>Konum :</strong> ' . get_post_meta( $order->get_id(), '_konum', true ) . '</p>';
if ( get_post_meta( $order->get_id(), '_masa', true ) ) echo '<p><strong>Masa Numarası :</strong> ' . get_post_meta( $order->get_id(), '_masa', true ) . '</p>';
}
Last part of the code is shown session variables data in WooCommerce order page;
// Show session variable in woocommerce order page
add_action( 'woocommerce_admin_order_data_after_billing_address', 'konumu_admine_ekle', 10, 1 );
function konumu_admine_ekle( $order ) {
$order_id = $order->get_id();
if ( get_post_meta( $order_id, '_konum', true ) ) echo '<p><strong>Konum :</strong> ' . get_post_meta( $order_id, '_konum', true ) . '</p>';
if ( get_post_meta( $order_id, '_masa', true ) ) echo '<p><strong>Masa Numarası :</strong> ' . get_post_meta( $order_id, '_masa', true ) . '</p>';
}
But, it does not work. When customer made an order, it gave an error "We were unable to process your order, please try again."
Updated: There are some mistakes in your code when you are trying to save your custom data from session as order meta data and display it on emails and admin order pages…
Your first function is correct (oturum_degiskeni_olustur)…
Assuming that data is passed through URL like: website.com/?konumu=newyork&masa_no=12
Here is the revisited code:
// Unchanged
add_action( 'init', 'oturum_degiskeni_olustur' );
function oturum_degiskeni_olustur () {
// Early initialize customer session
if ( isset(WC()->session) && ! WC()->session->has_session() ) {
WC()->session->set_customer_session_cookie( true );
}
if ( isset( $_GET['konumu'] ) || isset( $_GET['masa_no'] ) ) {
$konum = isset( $_GET['konumu'] ) ? esc_attr( $_GET['konumu'] ) : '';
$masa = isset( $_GET['masa_no'] ) ? esc_attr( $_GET['masa_no'] ) : '';
// Set the session data
WC()->session->set( 'custom_data', array( 'konum' => $konum, 'masa' => $masa ) );
}
}
// Save custom session data as order meta data
add_action( 'woocommerce_checkout_create_order', 'oturum_degiskeni_kaydet' );
function oturum_degiskeni_kaydet( $order ) {
$data = WC()->session->get( 'custom_data' ); // Get custom data from session
if ( isset($data['konum']) ) {
$order->update_meta_data( '_konum', $data['konum'] );
}
if ( isset($data['masa']) ) {
$order->update_meta_data( '_masa', $data['masa'] );
}
WC()->session->__unset( 'custom_data' ); // Remove session variable
}
// Show this session variables in new order email for admin and in woocommerce order page
add_action( 'woocommerce_email_after_order_table', 'konumu_emaile_admine_ekle', 20 );
add_action( 'woocommerce_admin_order_data_after_billing_address', 'konumu_emaile_admine_ekle' );
function konumu_emaile_admine_ekle( $order ) {
if ( $konum = $order->get_meta( '_konum' ) )
echo '<p><strong>Masa Numarası :</strong> ' . $konum . '</p>';
if ( $masa = $order->get_meta( '_masa' ) )
echo '<p><strong>Konum :</strong> ' . $masa . '</p>';
}
Code goes in functions.php file of your active child theme (or active theme). Tested and Works.
On the email notification before customer details:
On admin order edit page (under billing phone):
Tested on WooCommerce 4.2+ under storefront theme

Dispatch received orders woocommerce to dealers sending email notifications

I have a list of emails (dealers) and I need when I receive order in wp-admin i open this order and send this order to a dealer (commercial , user...). Every dealer have an email and mark this order in custom field that he have been send to this dealer.
In my woocommerce orders page I need to open a order and do something like this:
Order 001 --- > send to Email1#exemple.com = Order 001 - Sent to Email1#exemple.com
Order 002 ----> send to Email2#exemple.com = Order 002 - Sent to Email2#exemple.com
Order 003 --- > send to Email1#exemple.com = Order 003 - Sent to Email1#exemple.com
I don't know where to start.
Does anyone have an idea or some code to achieve something like this?
Thanks
Here is a complete answer that will feet your needs. You will have to set in the 2nd function the array of the emails and names from your dealer list.
This code will display in backend Order edit pages a custom metabox with a selector, were you will set a dealer and you will click on "Save Order"…
A New Order notification email will be sent just once to that dealer email address.
Here is the code:
//Adding Meta container admin shop_order pages
add_action( 'add_meta_boxes', 'my_custom_order_meta_box' );
if ( ! function_exists( 'my_custom_order_meta_box' ) )
{
function my_custom_order_meta_box()
{
global $woocommerce, $order, $post;
add_meta_box( 'dealer_dispatch', __('Dealer Dispatch','woocommerce'), 'add_order_custom_fields_for_packaging', 'shop_order', 'side', 'core' );
}
}
//adding Meta field in the meta container admin shop_order pages
if ( ! function_exists( 'add_order_custom_fields_for_packaging' ) )
{
function add_order_custom_fields_for_packaging()
{
global $woocommerce, $order, $post;
// Define HERE your array of values <== <== <== <== <== <== <== <==
$option_values = array(
'default' => __('no selection', 'woocommerce'),
'dealer1#email.com' => 'Dealer 1 Name',
'dealer2#email.com' => 'Dealer 2 Name',
'dealer3#email.com' => 'Dealer 3 Name',
);
// Get the values from the custom-fields (if they exist)
$meta_field_data = get_post_meta( $post->ID, '_dealer_dispatch', true );
$dealer_email_sent = get_post_meta( $post->ID, '_dealer_email_sent', true );
echo '<input type="hidden" name="my-custom-order_meta-box-nonce" value="'. wp_create_nonce() .'">
<label for="dealer_dispatch">'.__('Select a dealer', 'woocommerce').'</label><br>
<select name="dealer_dispatch">';
foreach( $option_values as $option_key => $option_value ){
if ( $meta_field_data == $option_key || 'default' == $option_key )
$selected = ' selected';
else
$selected = '';
echo '<option value="'.$option_key.'"'.$selected.'>'. $option_value.'</option>';
}
echo '</select><br>';
// if an email has been sent to the dealer we display a message
if( ! empty($dealer_email_sent) )
echo '<p style="color:green; font-weight:bold;">'.__('Email sent to: ', 'woocommerce').$dealer_email_sent.'</p>';
}
}
//Save the data of the Meta field
add_action( 'save_post', 'add_my_custom_field_for_order_meta_box', 20, 1 );
if ( ! function_exists( 'add_my_custom_field_for_order_meta_box' ) )
{
function add_my_custom_field_for_order_meta_box( $post_id ) {
## Verify and securing data. ##
// Check if our nonce is set.
if ( ! isset( $_POST[ 'my-custom-order_meta-box-nonce' ] ) ) {
return $post_id;
}
$nonce = $_REQUEST[ 'my-custom-order_meta-box-nonce' ];
//Verify that the nonce is valid.
if ( ! wp_verify_nonce( $nonce ) ) {
return $post_id;
}
// Continuing only if form is submited.
if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
return $post_id;
}
// Check and set the user's permissions.
if ( 'page' == $_POST[ 'post_type' ] ) {
if ( ! current_user_can( 'edit_page', $post_id ) ) {
return $post_id;
}
} else {
if ( ! current_user_can( 'edit_post', $post_id ) ) {
return $post_id;
}
}
// -- -- IT IS SECURED NOW -- --
// Sanitize input and update order meta data custom field.
$dealer_dispatch = $_POST[ 'dealer_dispatch' ];
// Saving the selected value
if( 'default' != $dealer_dispatch )
update_post_meta( $post_id, '_dealer_dispatch', sanitize_text_field( $dealer_dispatch ) );
# SEND CUSTOM EMAIL ONLY ONCE #
$dealer_dispatch_val = get_post_meta( $post_id, '_dealer_dispatch', true );
$dealer_email_sent = get_post_meta( $post_id, '_dealer_email_sent', true );
if( empty($dealer_email_sent) && !empty($dealer_dispatch_val) ){
$email_notifications = WC()->mailer()->get_emails();
$email_notifications['WC_Email_New_Order']->recipient = $dealer_dispatch;
$email_notifications['WC_Email_New_Order']->trigger( $post_id );
// Creating a custom meta data for this order to avoid sending this email 2 times
update_post_meta( $post_id, '_dealer_email_sent', $dealer_dispatch_val );
}
}
}
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.

Presumably simple PHP if/else statement not working

I seem to be having trouble with another piece of what seems to be super basic PHP, but it just won't work for me.
My client (real estate website) needs to be able to have properties with no price to be either “price upon request” OR “auction”. Currently, leaving the price field blank only allows for one.
I tried changing the following code:
$listing_price_labels = array(
‘sold’ => __( ‘Sold’, ‘wpsight’ ),
‘rented’ => __( ‘Rented’, ‘wpsight’ ),
‘request’ => __( ‘Price on request’, ‘wpsight’ ),
‘auction’ => __( ‘Auction’, ‘wpsight’ ), ***– Added this line***
);
And where this code is found…
if( is_admin() )
$listing_price .= ‘<br />’ . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['request'] . ‘</span><!– .listing-price-on-request –>’;
} elseif( $listing_price = ‘auction’ ) {
// When price field contains ‘auction’ (case sensitive)
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['auction'] . ‘</span><!– .listing-price-on-request –>’;
}
function wpsight_get_price( $post_id = '' ) {
// Get post ID from $post_id
if( empty( $post_id ) )
$post_id = get_the_ID();
// If still empty, return false
if( empty( $post_id ) )
return false;
// Set listing price labels
$listing_price_labels = array(
'sold' => __( 'Sold', 'wpsight' ),
'rented' => __( 'Rented', 'wpsight' ),
'request' => __( 'Price on request', 'wpsight' ),
'auction' => __( 'Auction', 'wpsight' ),
);
$listing_price_labels = apply_filters( 'wpsight_get_price_labels', $listing_price_labels );
// Get listing price
$listing_price = wpsight_get_price_value();
// Get custom fields
$custom_fields = get_post_custom( $post_id );
$listing_status = isset( $custom_fields['_price_status'][0] ) ? $custom_fields['_price_status'][0] : false;
$listing_availability = isset( $custom_fields['_price_sold_rented'][0] ) ? $custom_fields['_price_sold_rented'][0] : false;
// Create price output
if( ! empty( $listing_availability ) ) {
// When listing is not available
$sold_rented = ( $listing_status == 'sale' ) ? $listing_price_labels['sold'] : $listing_price_labels['rented'];
// Display sold/rented bold red in admin
$style = is_admin() ? ' style="color:red;font-weight:bold"' : false;
$listing_price = '<span class="listing-price-sold-rented"' . $style . '>' . $sold_rented . '</span><!-- .listing-price-sold-rented -->';
if( is_admin() )
$listing_price .= '<br />' . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = '<span class="listing-price-on-request">' . $listing_price_labels['request'] . '</span><!-- .listing-price-on-request -->';
} elseif( $listing_price == "auction" ) {
// When price field contains 'auction' (case sensitive)
$listing_price = '<span class="listing-price-on-request">' . $listing_price_labels['auction'] . '</span><!-- .listing-price-on-request -->';
}
return apply_filters( 'wpsight_listing_price', $listing_price );
}
I’m sure my syntax must just be wrong, because with that code in place it makes any property with anything at all written into the price field display “auction”.
Can anyone see what I've done wrong?
try:
if( is_admin() ){
$listing_price .= ‘<br />’ . wpsight_get_price_value();
} elseif( empty( $listing_price ) ) {
// When no price available Price on request
$listing_price = ‘<span class=”listing-price-on-request”>’ . $listing_price_labels['request'] . ‘</span><!– .listing-price-on-request –>’;
}
btw its not recommended to use if( is_admin() ) since its only applicable on 1 line.

Categories