I'm attempting to use the 'woocommerce_order_shipping_to_display' filter to show 'Free' in the WooCommerce email table when no shipping charges will be incurred. In the image, I'm trying to get 'Flat Rate' to display as 'Free'. My PHP is moderate, and I can't get my code quite there. Does anyone see what I could be missing?
My function breaks the actual email so I can't see if it's working or not. When the function is in place, and I resend a processing email, instead of resending, it opens in the same browser window without anything below the main email body table data (screenshot).
/* return custom text on email when shipping is free */
add_filter( 'woocommerce_order_shipping_to_display', 'filter_email_shipping_text', 10, 2 );
function filter_email_shipping_text( $shipping, $this ) {
global $woocommerce;
if ( $this->get_shipping_method() ) {
$shipping = __( 'Free', 'woocommerce' );
}
return $shipping;
}
Shipping Email
Broken Post Attempt
UPDATED
I've scavenged for a few similar cases, and I've rewritten the function below. This still doesn't work, but I think I needed to initialise the WC_Order class to tell the function which order to reference. Can anyone help me finish it off?
/* return custom text on email when shipping is free */
add_filter( 'woocommerce_order_shipping_to_display', 'filter_email_shipping_text', 10 );
function filter_email_shipping_text( $shipping ) {
global $wcdn;
$order = new WC_Order($wcdn->print->order_id);
if ( $order->get_shipping_method() || $order->order_shipping = 0 ) {
$shipping = sprintf(__( 'Free', 'woocommerce' ));
}
return $shipping;
}
CONCLUSION
I was able to fix my function and it now works how intended. This is the working function and filter in case anyone need to replicate.
/* return custom text on email when shipping is free */
add_filter( 'woocommerce_order_shipping_to_display', 'filter_email_shipping_text', 10, 2 );
function filter_email_shipping_text( $shipping, $order_id ) {
global $woocommerce, $post;
$order = new WC_Order( $order_id );
if ( $order->order_shipping == 0 ) {
$shipping = sprintf(__( 'Free!', 'woocommerce' ));
}
return $shipping;
}
Related
I am having some really hard times trying to make it work.
I've had an idea in back of my head to:
be able to assign single user to a coupon code through an extra field in general coupon tab, which is listing unassigned users to coupon codes
I dont want to use third party extensions, custom-fields, etc. I was hoping I'll be able to do it through meta data but I failed. Not sure how to get it done properly.
add two extra columns on orders page and display both coupon code and user assigned to it.
After some time reading docs and xDebugging in phpstorm I have also failed to get it done.
function order_sellers_and_coupons_columns_values($column)
{
global $post, $the_order;
if ($column == 'order_coupon_code') {
$coupons = $the_order->get_used_coupons(); // not sure how to get coupon object by the coupon code
echo (count($coupons)) ? $coupons[0] : '';
}
}
// even though I see the order objects have an items and coupon lines property,
// which is an object, i can't get access to it
$the_order->items["coupon_lines"]
I am not asking for ready-to-go solution, but to show me the way how to get it done.
Thanks in advance for any kind of help.
In WooCommerce admin single coupon pages, we add an extra field for the seller (dealer):
// Add a custom field to Admin coupon settings pages
add_action( 'woocommerce_coupon_options', 'add_coupon_text_field', 10 );
function add_coupon_text_field() {
woocommerce_wp_text_input( array(
'id' => 'seller_id',
'label' => __( 'Assing a seller (dealer)', 'woocommerce' ),
'placeholder' => '',
'description' => __( 'Assign a seller / dealer to a coupon', 'woocommerce' ),
'desc_tip' => true,
) );
}
// Save the custom field value from Admin coupon settings pages
add_action( 'woocommerce_coupon_options_save', 'save_coupon_text_field', 10, 2 );
function save_coupon_text_field( $post_id, $coupon ) {
if( isset( $_POST['seller_id'] ) ) {
$coupon->update_meta_data( 'seller_id', sanitize_text_field( $_POST['seller_id'] ) );
$coupon->save();
}
}
Then using the following you will add to admin orders list the coupon code (when it's used in the order) with the seller / dealer name:
// Adding a new column to admin orders list
add_filter( 'manage_edit-shop_order_columns', 'custom_shop_order_column' );
function custom_shop_order_column($columns)
{
$reordered_columns = array();
// Inserting columns to a specific location
foreach( $columns as $key => $column){
$reordered_columns[$key] = $column;
if( $key == 'order_status' ){
// Inserting after "Status" column
$reordered_columns['coupons'] = __( 'Coupon','theme_domain');
}
}
return $reordered_columns;
}
// Adding used coupon codes
add_action( 'manage_shop_order_posts_custom_column' , 'custom_orders_list_column_content', 10, 2 );
function custom_orders_list_column_content( $column, $post_id )
{
global $the_order;
if ( $column == 'coupons' ) {
$coupons = (array) $the_order->get_used_coupons();
$dealers = [];
foreach( $coupons as $coupon_code ) {
$coupon = new WC_Coupon( $coupon_code );
$dealers[] = $coupon->get_meta('seller_id');
}
if( count($coupons) > 0 )
echo implode( ', ', $coupons );
if( count($dealers) > 0 )
echo '<br><small>(' . implode( ', ', $dealers ) . ')</small>';
}
}
All code goes in functions.php file of your active child theme (or active theme). Tested and works.
On Admin coupon single pages:
On Admin edit orders list:
I'm adding a custom fees to WC with WC()->cart->add_fee() method.
My problem is that I'd like to add metadata to that fee item too. Preferably same time I'm adding the actual fee.
Apparently the WC_Order_Item_Fee Object is generated in the order creation only, so there seems to be no way to add FeeItem-specific metadata to custom fees.
Of course I could save this meta to session, but because add_fee doesn't return any identifier I have no idea which custom fee is actually which.
Any ideas how to solve this issue?
This is the code I use to add Fees:
add_filter('woocommerce_cart_calculate_fees', function (){
foreach( FeeChecker::getFees() as $fee )
{
$cart->add_fee("Added fee: ". $fee, 10 , true, $tax_class);
}
}
Note: In your code the $cart argument is missing from the hooked function and it's an action hook, but not a filter hook.
The WC_Cart method add_fee() doesn't allow to add custom meta data, so you will need to add it before on add_to_cart event or in WC_Session.
You can add custom meta data to WC_Order_Item_Fee when order is submitted using the following code example (using WC_Session to set and get the custom meta data in here):
// Add a custom cart fee
add_action( 'woocommerce_cart_calculate_fees', 'adding_cart_fees', 10, 1 );
function adding_cart_fees( $cart ){
$cart->add_fee(__("Added fee"), 10, true, '');
}
// Set Fee custom meta data in WC_Session
add_action( 'woocommerce_calculate_totals', 'calculate_totals_for_fees_meta_data', 10, 1 );
function calculate_totals_for_fees_meta_data( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
$fees_meta = WC()->session->get('fees_meta');
$update = false;
// Loop through applied fees
foreach( $cart->get_fees() as $fee_key => $fee ) {
// Set the fee in the fee custom meta data array
if( ! isset($fees_meta[$fee_key]) ){
$fees_meta[$fee_key] = 'some value';
$update = true;
}
}
// If any fee meta data doesn't exist yet, we update the WC_Session custom meta data array
if ( $update ) {
WC()->session->set('fees_meta', $fees_meta);
}
}
// Save fee custom meta data to WC_Order_Item_Fee.
add_action( 'woocommerce_checkout_create_order_fee_item', 'save_custom_met_data_to_fee_order_items', 10, 4 );
function save_custom_met_data_to_fee_order_items( $item, $fee_key, $fee, $order ) {
// Get fee meta data from WC_Session
$fees_meta = WC()->session->get('fees_meta');
// If fee custom meta data exist, save it to fee order item
if ( isset($fees_meta[$fee_key]) ) {
$item->update_meta_data( 'custom_key', $fees_meta[$fee_key] );
}
}
// Remove Fee meta data from WC_Session.
add_action( 'woocommerce_checkout_create_order', 'remove_fee_custom_met_data_from_wc_session', 10, 2 );
function remove_fee_custom_met_data_from_wc_session( $order, $data ) {
$fees_meta = WC()->session->__unset('fees_meta');
}
Code goes in function.php file of your active child theme (or active theme). Tested and works.
The custom meta data is saved to WC_Order_Item_Fee and you can get it using something like:
// Get an instance of the WC_Order Object (if needed)
$order = wc_get_order( $order_id );
// loop through fee order items
foreach ( $order->get_items('fee') as $fee_key => $item ) {
// Get the fee custom meta data
$fee_custom_meta = $item->get_meta('custom_key');
if ( $fee_custom_meta ) {
// Display the custom meta data value
echo '<p>' . $fee_custom_meta . '</p>';
}
}
A somewhat hacky way is to use the ID field of the fee item to link to data stored somewhere else.
$args = array(
'id' => $data_id,
'name' => $name,
'amount' => (float) $amount,
'taxable' => false,
'tax_class' => '',
);
$cart->fees_api()->add_fee( $args );
Later you can use the hook woocommerce_checkout_create_order_fee_item to fetch the data and populate the order item fee. In my case:
add_action( 'woocommerce_checkout_create_order_fee_item', array( $this, 'create_order_fee_item' ), 20, 4 );
public function create_order_fee_item( $item, $fee_key, $fee, $order ) {
$item->add_meta_data( 'product_id', $fee_key, true );
}
It seems I overlooked WC_Cart->fees_api
In there I have method that actually returns the created Fee so I know the exact Fee in woocommerce_checkout_create_order_fee_item action
Edit: This code was originally mostly done by LoicTheAztec. I edited it to fit my particular use case and posted it as solution. Unfortunatelly he deleted his post which could have been beneficial to others.
// Add cod fee
add_action('woocommerce_cart_calculate_fees', function ( $cart ){
if ( is_admin() && ! defined( 'DOING_AJAX' ) )
return;
//Make sure it's the right payment method
if( WC()->session->chosen_payment_method == "cod"){
$tax_class = '';
$amount = 5;
$session_data = [];
foreach( $cart->get_shipping_packages() as $package)
{
$fee = $cart->fees_api()->add_fee(
array(
'name' => "Additional cost: ".$package['custom_data'],
'amount' => (float) $amount,
'taxable' => true,
'tax_class' => $tax_class,
)
);
$session_data [ $fee->id ] = $package['custom_data'];
}
WC()->session->set('COD_fee_meta', $session_data);
}
}, 10, 2);
// Save fee custom meta data to WC_Order_Item_Fee.
add_action( 'woocommerce_checkout_create_order_fee_item', function ( $item, $fee_key, $fee, $order ) {
// Get fee meta data from WC_Session
$fees_meta = WC()->session->get('COD_fee_meta');
// If fee custom meta data exist, save it to fee order item
if ( isset($fees_meta[$fee_key]) ) {
$item->update_meta_data( '_custom_data', $fees_meta[$fee_key] );
}
}, 10, 4 );
// Remove Fee meta data from WC_Session.
add_action( 'woocommerce_checkout_create_order', function ( $order, $data ) {
WC()->session->__unset('COD_fee_meta');
}, 10, 2 );
I've created a new page in WordPress and set a custom made template as template for the new page.
In my template I'm doing some stuff like show a HTML content. After all worked fine I've decided to add a do_action in my custom template to sent an email via WooCommerce email client/class.
So I've set up a new email class and build a custom trigger in this class which triggers the email sending:
// Triggers for this email.
add_action( 'trigger_rated_email', array( $this, 'trigger' ), 10, 10 );
/**
* Trigger the sending of this email.
*
* #param int $order_id The order ID.
* #param WC_Order|false $order Order object.
*/
public function trigger( $order_id, $order = false ) {
$this->setup_locale();
if ( $order_id && ! is_a( $order, 'WC_Order' ) ) {
$order = wc_get_order( $order_id );
}
if ( is_a( $order, 'WC_Order' ) ) {
$developer_id = get_post_meta( $order_id, 'developer_id', true );
$developer = get_userdata( $developer_id );
$this->object = $order;
$this->recipient = $developer->user_email;
$this->placeholders['{order_date}'] = wc_format_datetime( $this->object->get_date_created() );
$this->placeholders['{order_number}'] = $this->object->get_order_number();
}
if ( $this->is_enabled() && $this->get_recipient() ) {
$this->send( $this->get_recipient(), $this->get_subject(), $this->get_content(), $this->get_headers(), $this->get_attachments() );
}
$this->restore_locale();
}
This add_action triggers the trigger() method in the email class which sends the email. To trigger the sending I've done this in my custom template PHP file:
do_action( 'trigger_rated_email', $order_id );
After saving it I've uploaded it to my server and called the page but there is no email sent to my email account.
So I've did a lot of checks to clarify if there is a problem in my email class:
Triggered the email from an other page (not custom template) -> email gets sent
Checked if there is an error in my debug.log -> no error
So what is the problem? I think there must be a problem in the custom template so my first thoughts are that the do_action is not called correctly because it don't knows the add_action from my class.
After a lot of hours and a help from a good friend we've found the problem. The point is that when you want to sent email from a non WooCommerce page you need to initialize the WooCommerce mailer first.
So for all who wants to sent emails from a non WooCommerce page do this here:
WC()->mailer();
do_action( 'trigger_your_custom_email', $order_id );
In your custom WooCommerce email class do this here:
add_action( 'trigger_your_custom_email', array( $this, 'trigger' ), 10, 10 );
I'm trying to add a message to the order-received (Thank You) page, only if the order is using Free Shipping. The message can either replace the standard "Thank you..." message, or can be in addition to.
Here is the code I'm working with. It's based off of the answer here: Customize Order received page based on shipping method in WooCommerce
//add message to order received if outside delivery area
add_filter( 'woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 20, 2 );
function woo_change_order_received_text( $thankyou_text, $order ) {
if ( is_wc_endpoint_url( 'order-received' ) ) {
global $wp;
$order_id = absint( $wp->query_vars['order-received'] );
$order_key = isset( $_GET['key'] ) ? wc_clean( $_GET['key'] ) : '';
$method_title_names = array();
if( in_array( 'Free shipping', $method_title_names ) ) {
return sprintf( __("%s <div class=\"outside-delivery-checkout\"><b>PLEASE NOTE:</b><br />Your shipping destination is outside of our normal delivery area. Our team will call you to calculate an additional fuel surcharge.</div>", "woocommerce"),
$thankyou_text
);
}
}
return $thankyou_text;
}
I can't get it to work correctly, and not sure what's wrong. Any help is greatly appreciated.
You need simply the following (where "Free shipping" is the name of your free shipping method):
add_filter( 'woocommerce_thankyou_order_received_text', 'woo_change_order_received_text', 20, 2 );
function woo_change_order_received_text( $text, $order ) {
if( $order->get_shipping_method() == 'Free shipping' ) {
$text .= ' <div class=\"outside-delivery-checkout\"><strong>'. __("PLEASE NOTE", "woocommerce") . ':</strong><br />'.__("Your shipping destination is outside of our normal delivery area. Our team will call you to calculate an additional fuel surcharge.", "woocommerce") . '</div>';
}
return $text;
}
Similar: Code goes in function.php file of your active child theme (or active theme). Tested and works.
Customize Order received page based on shipping method in WooCommerce
I need to add custom args to PayPal paying link.
The PHP function looks like this:
$paypal_args = apply_filters( 'woocommerce_paypal_args', $paypal_args );
add_filter( 'woocommerce_paypal_args' , 'change_paypal_args' );
function change_paypal_args( $paypal_args ) {
global $wp;
global $woocommerce;
$order = wc_get_order( $order_id );
$paypal_args['invoice'] = 'spi432';
$paypal_args['txn_type'] = 'cart';
$paypal_args['payment_date'] = $order->order_date;
return $paypal_args;
}
I added txn_type and invoice as arguments to the link. But payment_date is not shown.
What may be the problem? Also, how can I display email of the customer?
If you enabled WP_DEBUG you would probably see that $order_id is undefined, and therefore $order is not an order object, so $order->order_date is likely a fatal error. Try passing the order as the second parameter instead.
add_filter( 'woocommerce_paypal_args' , 'so_42424283_change_paypal_args', 10, 2 );
function so_42424283_change_paypal_args( $paypal_args, $order ) {
$paypal_args['invoice'] = 'spi432';
$paypal_args['txn_type'] = 'cart';
// WC 2.6+
$paypal_args['payment_date'] = $order->order_date;
// WC 2.7
//$paypal_args['payment_date'] = $order->get_date_created();
return $paypal_args;
}