Reputation: 121
In My WooCommerce website I am using this plugin WooCommerce Order Cancel for Customers which allow customers to cancel their order based on payment type and on a time delay. But the cancel button only appears on the "woocommerce_order_details_after_order_table
".
I would like this cancel button to appear in the "My account" > "Orders list" near the "View" button:
I have tried to edit the plugin and adding this code: add_filter('woocommerce_my_account_my_orders_actions', array($this, 'order_cancel_button'), 10, 2);
But it doesn't work: the View button is gone and the Cancel button is not displayed.
Here is the whole code:
<?php
/**
* Plugin Name: WooCommerce Order Cancel For Customers
* Plugin URI: https://wpmanageninja.com/plugins/order-cancel-for-customers-woocommerce
* Description: A tiny plugin that will enable customers to cancel woocommerce order within a certain amount of time.
* Version: 1.0
* Author: Techjewel
* Author URI: https://wpmanageninja.com
* Requires at least: 4.4
* Tested up to: 4.8
*
* Text Domain: wco
*
*/
// If this file is called directly, abort.
if ( ! defined( 'WPINC' ) ) {
die;
}
require_once plugin_dir_path( __FILE__ ) . 'libs/class-wco-woo-settings.php';
if ( ! class_exists( 'WCOCancelOrder' ) ) :
class WCOCancelOrder {
/**
* Eligible Order statuses for cancel
* @type array
*/
private $eligibleCancelStatuses;
/**
* New Order Status for Woocommerce Order, It must have wc prefix
* @type string
*/
private $custom_order_status_name = 'wc-customer-cancel';
/**
* Declare all the action and filter hooks
*
*/
public function init_plugin() {
add_filter("plugin_action_links_".plugin_basename(__FILE__), array($this, 'wco_plugin_settings_link') );
$cancelOrderStatus = get_option('wc_wco_settings_activate');
if($cancelOrderStatus != 'yes') {
return;
}
$eligible_order_statuses = get_option('wc_wco_settings_eligible_statuses', array());
$this->eligibleCancelStatuses = apply_filters(
'wco_eligible_cancel_order_statuses', $eligible_order_statuses
);
$this->register_custom_order_status();
add_filter('wc_order_statuses', array($this,'custom_wc_order_statuses'));
add_action('admin_head', array($this, 'cancel_order_font_icon'));
add_action('woocommerce_order_details_after_order_table', array($this, 'order_cancel_button'), 10, 1);
add_filter('woocommerce_my_account_my_orders_actions', array($this, 'order_cancel_button'), 10, 2);
add_action('wp', array($this, 'process_cancel_order'));
add_action('wco_after_order_cancel_action', array($this, 'send_email_notification_to_shop_admin'), 10, 2);
add_filter('wco_notification_email_subject', array($this, 'parse_text_with_order_fields'), 10, 2);
add_filter('wco_notification_email_body', array($this, 'parse_text_with_order_fields'), 10, 2);
}
public function wco_plugin_settings_link($links) {
$settings_link = '<a href="admin.php?page=wc-settings&tab=wco_settings">'.__('Settings', 'wco').'</a>';
array_unshift($links, $settings_link);
return $links;
}
/**
* Register New order status for Woocommerce
*
* @uses register_post_status()
*/
public function register_custom_order_status()
{
register_post_status( $this->custom_order_status_name, array(
'label' => __('Cancelled By Customer', 'wco'),
'public' => true,
'show_in_admin_status_list' => true,
'show_in_admin_all_list' => true,
'exclude_from_search' => false,
'label_count' => _n_noop( 'Cancelled By Customer <span class="count">(%s)</span>', 'Cancelled By Customers <span class="count">(%s)</span>' )
) );
}
/**
* Append newly registered order-status in woocommerce status lists
*
* @param array $order_statuses
* @return array $new_order_statuses
*/
public function custom_wc_order_statuses($order_statuses)
{
$new_order_statuses = array();
foreach ( $order_statuses as $key => $status ) {
$new_order_statuses[ $key ] = $status;
if ( 'wc-cancelled' === $key ) {
$new_order_statuses[$this->custom_order_status_name] = __('Cancelled By Customer', 'wco');
}
}
return $new_order_statuses;
}
/**
* Add order cancel button
*
* @uses $this->can_customer_cancel_order($order)
* @param $order
*/
public function order_cancel_button($order) {
$can_cancel = apply_filters('wco_can_customer_cancel_order', $this->can_customer_cancel_order($order), $order);
if($can_cancel) {
$cancel_url = $this->get_cancel_url($order->get_id());
do_action('wco_before_cancel_button_wrapper', $order);
?>
<div class="ico_cancel_order_wrapper">
<p><i><?php _e('', 'wco'); ?></i> <a class="button" href="<?php echo $cancel_url; ?>"><?php _e('CANCEL ORDER', 'wco');?></a></p>
</div>
<?php
do_action('wco_after_cancel_button_wrapper', $order);
}
}
public function get_cancel_url($order_id) {
$urlData = build_query(array(
'wco_order_cancel_id' => $order_id,
'_nonce' => wp_create_nonce('wco_customer_cancel_order_' . $order_id),
'action' => 'process_cancel_order'
));
return site_url().'?'.$urlData;
}
/**
* Process Cancel Order once user request to cancel
*/
public function process_cancel_order() {
if(isset($_REQUEST['wco_order_cancel_id'])) {
$order_id = $_REQUEST['wco_order_cancel_id'];
if(!wp_verify_nonce($_REQUEST['_nonce'], 'wco_customer_cancel_order_'.$order_id)) {
wp_die('Security Error, Please try again!', 'wco');
}
$order = wc_get_order($order_id);
if($this->can_customer_cancel_order($order)) {
$redirectUrl = esc_url( wc_get_endpoint_url( get_option( 'woocommerce_myaccount_orders_endpoint', 'orders' ), '', wc_get_page_permalink( 'myaccount' ) ));
$redirectUrl = apply_filters('wco_after_cancel_redirect_url', $redirectUrl , $order_id);
// cancel the order now
$order_status_change_message = __('Customer wants to cancel the order and want to get refund.', 'wco');
$order_status_change_message = apply_filters('wco_after_order_cancel_note', $order_status_change_message, $order_id);
$success_message = get_option('wc_wco_settings_cancel_success_message', __('Your order has been submitted as "Cancelled by Customer"!', 'wco'));
$success_message = apply_filters('wco_after_order_cancel_message', $success_message, $order_id);
if(!wc_has_notice($success_message)) {
wc_add_notice($success_message, 'success');
}
$order = new WC_Order($order_id);
$order->update_status($this->custom_order_status_name, $order_status_change_message);
do_action('wco_after_order_cancel_action', $order, get_current_user_id());
wp_redirect($redirectUrl);
die();
} else {
wp_die('Sorry! You can not cancel this order now!', 'wco');
}
}
}
/**
* Determine if customer can cancel a selected order
*
* @param $order
*
* @return bool
*/
private function can_customer_cancel_order($order)
{
$cancelOrderStatus = get_option('wc_wco_settings_activate');
if($cancelOrderStatus != 'yes') {
return false;
}
$cancelTimeValidityMinutes = apply_filters('wco_cancel_validity_minutes', get_option('wc_wco_settings_cancel_order_threshold_time', 0), $order);
$cancelTimeValidity = $cancelTimeValidityMinutes * 60; // in seconds
$customer_id = $order->get_customer_id();
$user_ID = get_current_user_id();
$order_timestamp_diff = strtotime(current_time('mysql')) - strtotime($order->get_date_created());
if ($cancelTimeValidity > $order_timestamp_diff && $customer_id == $user_ID && in_array($order->get_status(), $this->eligibleCancelStatuses) ) {
return true;
}
return false;
}
/**
* CSS for Cancel Order Icon
*/
public function cancel_order_font_icon()
{
echo '<style>
mark.customer-cancel:after{
font-family:WooCommerce;
speak:none;
font-weight:400;
font-variant:normal;
text-transform:none;
line-height:1;
-webkit-font-smoothing:antialiased;
margin:0;
text-indent:0;
position:absolute;
top:0;
left:0;
width:100%;
height:100%;
text-align:center;
}
mark.customer-cancel:after{
content:"\e012";
color:#ff0000;
}
</style>';
}
/**
* Send email notification to admin once the customer cancel an order
*
* @param $order
* @param $user_id
*/
public function send_email_notification_to_shop_admin($order, $user_id) {
$email_to = apply_filters('wco_notification_email', get_option('wc_wco_settings_shop_owner_email'), $order);
echo $email_to;
if(!$email_to)
return;
$email_subject = apply_filters('wco_notification_email_subject', get_option('wc_wco_settings_notification_email_subject'), $order);
$email_body = apply_filters('wco_notification_email_body', get_option('wc_wco_settings_notification_email_body'), $order);
$email_headers = array(
'Content-Type: text/html; charset=UTF-8'
);
$email_headers = apply_filters('wco_notification_email_headers', $email_headers, $order);
$mail_result = wp_mail($email_to, $email_subject, $email_body, $email_headers);
do_action('wco_after_cancel_notification_email_sent_action', $mail_result, $order);
}
/**
* Parse text with order shortcodes for email
* @param $text
* @param $order
*
* @return mixed
*/
public function parse_text_with_order_fields($text, $order) {
$replace_fields = array(
'%%order_id%%' => $order->get_id(),
'%%customer_name%%' => $order->get_billing_first_name().' '.$order->get_billing_last_name(),
'%%order_admin_url%%' => get_edit_post_link($order->get_id())
);
apply_filters('wco_parse_email_replace_fields', $replace_fields, $order);
$replaces = array_keys($replace_fields);
$replacesWith = array_values($replace_fields);
$parsed_text = str_replace($replaces, $replacesWith, $text);
return $parsed_text;
}
}
endif;
/**
* Boot this plugin
*/
function wco_boot_plugin() {
$cancelOrderClass = new WCOCancelOrder();
$cancelOrderClass->init_plugin();
if(is_admin()) {
WCO_Woo_Settings::init();
}
}
add_action('init', 'wco_boot_plugin');
How can I make the "Cancel" button appear in My account > Orders list, in the action column?
Upvotes: 4
Views: 17586
Reputation: 253978
New Update May 2018: Conditional Cancel Button on my account orders list in Woocommerce
Old Update regarding your comment: The cancel button is available 3 days (from creation date) and solved a bug issue when the cancel button is pressed (made on January 2018)
Without editing or using this plugin, you can make enable the cancel button in My Account > Order list in the action column, using this little snippet of code where you will set:
Here is that code:
add_filter( 'woocommerce_valid_order_statuses_for_cancel', 'custom_valid_order_statuses_for_cancel', 10, 2 );
function custom_valid_order_statuses_for_cancel( $statuses, $order ){
// Set HERE the order statuses where you want the cancel button to appear
$custom_statuses = array( 'completed', 'pending', 'processing', 'on-hold', 'failed' );
// Set HERE the delay (in days)
$duration = 3; // 3 days
// UPDATE: Get the order ID and the WC_Order object
if( isset($_GET['order_id']))
$order = wc_get_order( absint( $_GET['order_id'] ) );
$delay = $duration*24*60*60; // (duration in seconds)
$date_created_time = strtotime($order->get_date_created()); // Creation date time stamp
$date_modified_time = strtotime($order->get_date_modified()); // Modified date time stamp
$now = strtotime("now"); // Now time stamp
// Using Creation date time stamp
if ( ( $date_created_time + $delay ) >= $now ) return $custom_statuses;
else return $statuses;
}
Code goes in function.php file of your active child theme (or theme) or also in any plugin file.
This code is tested on Woocommerce 3+ and works. You will get something like:
Note: The default order statuses returned in this function are 'pending'
and 'failed'
You can also use the
WC_Order
object argument in the function to set some custom conditions.See this related thread: How to get WooCommerce order details
Upvotes: 12
Reputation: 11
By default woocommerce show cancel order button for the order when its status is Pending or Failed only
But I made this plugin so you can show Order cancellation request button for order that are even under Processing state
https://wordpress.org/plugins/cancel-order-request-woocommerce/
You can set which order status to have "Cancellation request button" Order status on which the cancel request buton will be shown
Once you have set this user will have "cancel request" button on his My account order list, using those button user can send cancellation request with reason for cancellation Cancel request button shown on My account page of customer
Order cancellation reason in popup
Upvotes: 0