skip to Main Content

I have a custom shipping method and I want it to display its description (shipping instructions) on Thank you page and in email sent to customer. Just as payment gateways do. I am hooking to woocommerce_thankyou hook in my shipping method init() function. It works, but … it works like eight times. Those hooked functions are firing multiple times. My shipping method looks like this:

<?php
class WC_Shipping_XY extends WC_Shipping_Method {

    function __construct( $instance_id = 0 ) {
        
        $this->id = 'my-shipping';
        // etc etc
        
        $this->init();
    }
    

    function init() {

        $this->init_form_fields();
        // etc
        
        add_action( 'woocommerce_thankyou', array( $this, 'woocommerce_thankyou' ), 5, 1 ); 
    }
    
    
    function woocommerce_thankyou( $order_id ) {
        
        $order = wc_get_order( $order_id );
        
        if( $order->has_shipping_method('my-shipping') ) {
            
            echo wpautop( wptexturize( $this->description ) );
            
        }
    }   
        
}

Shipping method description is duplicated many times on Thank you page. I don’t know why. Is shipping method constructor called more than once? (Obviously it is …)

2

Answers


  1. Chosen as BEST ANSWER

    Well, I finally found out this behaviour is "by design", someone asked the same question on WooCommerce Github (issue).

    Shipping methods/instances are not singletons and can be init/loaded/constructed multiple times depending on whats going on.

    It's not possible to hook any function inside shipping method class - if so, it will result in multiple function calls. Period.


  2. I think this is how it should be done.

    • You create your custom shipping method.
    if (in_array('woocommerce/woocommerce.php', apply_filters('active_plugins', get_option('active_plugins')))) {
    
        function your_shipping_method_init()
        {
            if (!class_exists('WC_Your_Shipping_Method')) {
                class WC_Your_Shipping_Method extends WC_Shipping_Method
                {
    
                    public $description = null;
    
    
                    /**
                     * Constructor for your shipping class
                     *
                     * @access public
                     * @return void
                     */
                    public function __construct()
                    {
                        $this->id                 = 'your_shipping_method'; // Id for your shipping method. Should be uunique.
                        $this->method_title       = __('Your Shipping Method');  // Title shown in admin
                        $this->method_description = __('Description of your shipping method'); // Description shown in admin
    
                        $this->enabled            = "yes"; // This can be added as an setting but for this example its forced enabled
                        $this->title              = "My Shipping Method"; // This can be added as an setting but for this example its forced.
    
                        $this->description = __('Some other description'); // Description shown in admin
    
                        $this->init();
                    }
    
                    /**
                     * Init your settings
                     *
                     * @access public
                     * @return void
                     */
                    function init()
                    {
                        // Load the settings API
                        $this->init_form_fields(); // This is part of the settings API. Override the method to add your own settings
                        $this->init_settings(); // This is part of the settings API. Loads settings you previously init.
    
                        // Save settings in admin if you have any defined
                        add_action('woocommerce_update_options_shipping_' . $this->id, array($this, 'process_admin_options'));
                    }
    
                    /**
                     * calculate_shipping function.
                     *
                     * @access public
                     * @param mixed $package
                     * @return void
                     */
                    public function calculate_shipping($package = array())
                    {
                        $rate = array(
                            'label' => $this->title,
                            'cost' => '10.99',
                            'calc_tax' => 'per_item'
                        );
    
                        // Register the rate
                        $this->add_rate($rate);
                    }
                }
            }
        }
    
        add_action('woocommerce_shipping_init', 'your_shipping_method_init');
    
        function add_your_shipping_method($methods)
        {
            $methods['your_shipping_method'] = 'WC_Your_Shipping_Method';
            return $methods;
        }
    
        add_filter('woocommerce_shipping_methods', 'add_your_shipping_method');
    }
    

    Please see that it has a description class variable inside of it, which is different from method_description used by WooCommerce.

    • Use the thankyou hook outside your class like this to get that description.
    add_action('woocommerce_thankyou', 'woocommerce_thankyou', 5, 1);
    
    
    function woocommerce_thankyou($order_id)
    {
        $order = wc_get_order($order_id);
    
        if ($order->has_shipping_method('your_shipping_method')) {
            $shipping = new WC_Your_Shipping_Method();
            $description = $shipping->description;
            echo wpautop(wptexturize($description));
        }
    }
    

    I have tested this code and it works.

    Screenshot below. You can see Some other description on the thank you page.

    enter image description here

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search