Search code examples
phpwoocommercewordpress-plugin-creation

On province change set shipping methods in checkout page of WooCommerce


I am trying to generate a dropdown list of available shipping methods based on the selected state by visitor, however, the page is never get updated, and the JSON response always has a 0 at the end of it which makes the parsing failed.

main.js of the plugin:

jQuery('#billing_state').on('change', function(event) {
    event.preventDefault();
    let dataVariable = {
        'action': 'yalidine_shippings_methods',
        'state': this.value 
    };
    jQuery.ajax({
        url: yalidine_shippings_methods.ajaxurl,
        type:'POST',
        data: dataVariable,
        success:function(response) {
            console.log('html shipping_fees: ', shipping_fees.html())
            console.log('html response: ', response)
            let options = ` <option value="pickup">Self pickup</option>
                            <option value="home">Home</option>`;
            try {
                let res = JSON.parse(response);
                for(let stopdesk in res.stop_desks) {
                    options += `<option value="${stopdesk}">${stopdesk}</option>`;
                }

                shipping_fees.html('<th>Shipping</th><td data-title="Shipping"><select id="shipping-method-list">' + options + '</select></td>');
                shipping_method = jQuery('#shipping-method-list');
            }
            catch(err) {

            }
        },
        error: function(err) {
            console.log('error: ', err)
        }
    });
});

yalidine_woocommerce.php plugin:

function yalidine_shippings_methods() {
    //file_put_contents('_POST.txt', json_encode($_POST) . '\r\n' . 'dd');
    $data = [];
    if(isset($_POST['action']) && $_POST['action'] == 'yalidine_shippings_methods') {
        $wilaya_id = explode('-', $_POST['state']);
        $wilaya_id = (int)$wilaya_id[1];

        $yalidine_options = get_option('WOO_YALIDINE_SETTINGS');
        $api_id = isset($yalidine_options['stopdesk']) ? key($yalidine_options['stopdesk']) : null;
        if($api_id !== null) {
            $api_token = $yalidine_options['stopdesk'][$api_id]['token'];
            $http_request = new CurlHttpRequest();
            $yalidine = new YalidineAPI($http_request);
            $yalidine->setApiKeys($api_id, $api_token);
            $response = $yalidine->getWilayaStopDesks($wilaya_id);
            $response2 = $yalidine->getWilayaDeliveryFees($wilaya_id);
            if(isset($response['total_data']) && $response['total_data'] > 0
                && isset($response2['total_data']) && $response2['total_data'] > 0) {
                foreach($response['data'] as $stopdesk) {
                    $data['stop_desks'][] = $stopdesk['name'];
                }

                $data['fee'] = ['home' => $response2['data'][0]['home_fee'], 'stop_desk' => $response2['data'][0]['desk_fee']];
            }
        }

    }

    echo json_encode($data);
}

add_action('wp_ajax_yalidine_shippings_methods', 'yalidine_shippings_methods' );
add_action('wp_ajax_yalidine_shippings_methods', 'yalidine_shippings_methods' );

enter image description here


Solution

  • What I was need is to extend the WC_Shipping_Method and create my own shipping method, A full tutorial about that can be found here, and a general skeleton(from the tutorial mentioned) of a shipping method would look like this:

    <?php
     
    /**
     * Plugin Name: TutsPlus Shipping
     * Plugin URI: http://code.tutsplus.com/tutorials/create-a-custom-shipping-method-for-woocommerce--cms-26098
     * Description: Custom Shipping Method for WooCommerce
     * Version: 1.0.0
     * Author: Igor Benić
     * Author URI: http://www.ibenic.com
     * License: GPL-3.0+
     * License URI: http://www.gnu.org/licenses/gpl-3.0.html
     * Domain Path: /lang
     * Text Domain: tutsplus
     */
     
    if ( ! defined( 'WPINC' ) ) {
     
        die;
     
    }
     
    /*
     * Check if WooCommerce is active
     */
    if ( in_array( 'woocommerce/woocommerce.php', apply_filters( 'active_plugins', get_option( 'active_plugins' ) ) ) ) {
     
        function tutsplus_shipping_method() {
            if ( ! class_exists( 'TutsPlus_Shipping_Method' ) ) {
                class TutsPlus_Shipping_Method extends WC_Shipping_Method {
                    /**
                     * Constructor for your shipping class
                     *
                     * @access public
                     * @return void
                     */
                    public function __construct() {
                        $this->id                 = 'tutsplus'; 
                        $this->method_title       = __( 'TutsPlus Shipping', 'tutsplus' );  
                        $this->method_description = __( 'Custom Shipping Method for TutsPlus', 'tutsplus' ); 
     
                        // Availability & Countries
                        $this->availability = 'including';
                        $this->countries = array(
                            'US', // Unites States of America
                            'CA', // Canada
                            'DE', // Germany
                            'GB', // United Kingdom
                            'IT',   // Italy
                            'ES', // Spain
                            'HR'  // Croatia
                            );
     
                        $this->init();
     
                        $this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
                        $this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : __( 'TutsPlus Shipping', 'tutsplus' );
                    }
     
                    /**
                     * Init your settings
                     *
                     * @access public
                     * @return void
                     */
                    function init() {
                        // Load the settings API
                        $this->init_form_fields(); 
                        $this->init_settings(); 
     
                        // Save settings in admin if you have any defined
                        add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
                    }
     
                    /**
                     * Define settings field for this shipping
                     * @return void 
                     */
                    function init_form_fields() { 
     
                        $this->form_fields = array(
     
                         'enabled' => array(
                              'title' => __( 'Enable', 'tutsplus' ),
                              'type' => 'checkbox',
                              'description' => __( 'Enable this shipping.', 'tutsplus' ),
                              'default' => 'yes'
                              ),
     
                         'title' => array(
                            'title' => __( 'Title', 'tutsplus' ),
                              'type' => 'text',
                              'description' => __( 'Title to be display on site', 'tutsplus' ),
                              'default' => __( 'TutsPlus Shipping', 'tutsplus' )
                              ),
     
                         'weight' => array(
                            'title' => __( 'Weight (kg)', 'tutsplus' ),
                              'type' => 'number',
                              'description' => __( 'Maximum allowed weight', 'tutsplus' ),
                              'default' => 100
                              ),
     
                         );
     
                    }
     
                    /**
                     * This function is used to calculate the shipping cost. Within this function we can check for weights, dimensions and other parameters.
                     *
                     * @access public
                     * @param mixed $package
                     * @return void
                     */
                    public function calculate_shipping( $package ) {
                        
                        $weight = 0;
                        $cost = 0;
                        $country = $package["destination"]["country"];
     
                        foreach ( $package['contents'] as $item_id => $values ) 
                        { 
                            $_product = $values['data']; 
                            $weight = $weight + $_product->get_weight() * $values['quantity']; 
                        }
     
                        $weight = wc_get_weight( $weight, 'kg' );
     
                        if( $weight <= 10 ) {
     
                            $cost = 0;
     
                        } elseif( $weight <= 30 ) {
     
                            $cost = 5;
     
                        } elseif( $weight <= 50 ) {
     
                            $cost = 10;
     
                        } else {
     
                            $cost = 20;
     
                        }
     
                        $countryZones = array(
                            'HR' => 0,
                            'US' => 3,
                            'GB' => 2,
                            'CA' => 3,
                            'ES' => 2,
                            'DE' => 1,
                            'IT' => 1
                            );
     
                        $zonePrices = array(
                            0 => 10,
                            1 => 30,
                            2 => 50,
                            3 => 70
                            );
     
                        $zoneFromCountry = $countryZones[ $country ];
                        $priceFromZone = $zonePrices[ $zoneFromCountry ];
     
                        $cost += $priceFromZone;
     
                        $rate = array(
                            'id' => $this->id,
                            'label' => $this->title,
                            'cost' => $cost
                        );
     
                        $this->add_rate( $rate );
                        
                    }
                }
            }
        }
     
        add_action( 'woocommerce_shipping_init', 'tutsplus_shipping_method' );
     
        function add_tutsplus_shipping_method( $methods ) {
            $methods[] = 'TutsPlus_Shipping_Method';
            return $methods;
        }
     
        add_filter( 'woocommerce_shipping_methods', 'add_tutsplus_shipping_method' );
     
        function tutsplus_validate_order( $posted )   {
     
            $packages = WC()->shipping->get_packages();
     
            $chosen_methods = WC()->session->get( 'chosen_shipping_methods' );
             
            if( is_array( $chosen_methods ) && in_array( 'tutsplus', $chosen_methods ) ) {
                 
                foreach ( $packages as $i => $package ) {
     
                    if ( $chosen_methods[ $i ] != "tutsplus" ) {
                                 
                        continue;
                                 
                    }
     
                    $TutsPlus_Shipping_Method = new TutsPlus_Shipping_Method();
                    $weightLimit = (int) $TutsPlus_Shipping_Method->settings['weight'];
                    $weight = 0;
     
                    foreach ( $package['contents'] as $item_id => $values ) 
                    { 
                        $_product = $values['data']; 
                        $weight = $weight + $_product->get_weight() * $values['quantity']; 
                    }
     
                    $weight = wc_get_weight( $weight, 'kg' );
                    
                    if( $weight > $weightLimit ) {
     
                            $message = sprintf( __( 'Sorry, %d kg exceeds the maximum weight of %d kg for %s', 'tutsplus' ), $weight, $weightLimit, $TutsPlus_Shipping_Method->title );
                                 
                            $messageType = "error";
     
                            if( ! wc_has_notice( $message, $messageType ) ) {
                             
                                wc_add_notice( $message, $messageType );
                          
                            }
                    }
                }       
            } 
        }
     
        add_action( 'woocommerce_review_order_before_cart_contents', 'tutsplus_validate_order' , 10 );
        add_action( 'woocommerce_after_checkout_validation', 'tutsplus_validate_order' , 10 );
    }