Rhob Gatchalian
Rhob Gatchalian

Reputation: 121

Add Cancel button on My account Orders list using Woo Cancel for Customers Plugin

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: enter image description here

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

Answers (2)

LoicTheAztec
LoicTheAztec

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:

  • The order statuses: where you want the "Cancel" button to appear
  • The duration (in days) from the order creation date.

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:

enter image description here

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

rajesh singh
rajesh singh

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

Related Questions