Ronald
Ronald

Reputation: 41

How to get a list of shipping methods without a (filled)shopping cart

Is it possible to get a list of available shipping-methods based on
only a total amount and/or country code?

I quess it is possible by building my own SQL query, but I was wondering if it is also possible with the standard Woo-commerce functions.

I've tried it with the function:

$shipping_methods = WC()->shipping->get_shipping_methods(), 

but that gives me all shipping methods without filtering on country or cost. for example: local_pickup looks like

 [local_pickup] => WC_Shipping_Local_Pickup Object
    (
        [supports] => Array
            (
                [0] => shipping-zones
                [1] => instance-settings
                [2] => instance-settings-modal
            )

        [id] => local_pickup
        [method_title] => Afhalen
        [method_description] => Sta klanten toe bestellingen zelf op te halen. Standaard worden winkelgebaseerde belastingen toegepast wanneer gekozen is voor lokaal ophalen, onafhankelijk van het adres van de klant.
        [enabled] => yes
        [title] => 
        [rates] => Array
            (
            )

        [tax_status] => 
        [fee] => 
        [minimum_fee] => 
        [instance_id] => 0
        [instance_form_fields] => Array
            (
                [title] => Array
                    (
                        [title] => Titel
                        [type] => text
                        [description] => Dit bepaalt de titel die de gebruiker ziet tijdens het afrekenen.
                        [default] => Afhalen
                        [desc_tip] => 1
                    )

                [tax_status] => Array
                    (
                        [title] => Belastingstatus
                        [type] => select
                        [class] => wc-enhanced-select
                        [default] => taxable
                        [options] => Array
                            (
                                [taxable] => Belastbaar
                                [none] => Geen
                            )

                    )

                [cost] => Array
                    (
                        [title] => Kosten
                        [type] => text
                        [placeholder] => 0
                        [description] => Optionele kosten voor afhalen.
                        [default] => 
                        [desc_tip] => 1
                    )

            )

        [instance_settings] => Array
            (
            )

        [availability] => 
        [countries] => Array
            (
            )

        [plugin_id] => woocommerce_
        [errors] => Array
            (
            )

        [settings] => Array
            (
                [title] => 
                [tax_status] => 
                [cost] => 
            )

        [form_fields] => Array
            (
            )

        [data:protected] => Array
            (
            )

        [cost] => 
    )

Next I tried the following code, but I get no results at all.

print_r ( WC()->shipping->calculate_shipping( get_shipping_packages()));
die('ready');

function get_shipping_packages(){
    global $wpdb, $woocommerce;

    // Clear the Cart
    $woocommerce->cart->empty_cart(); 

   // Add an existing product to the cart, so $packages[0]['contents'] will not be empty... 
    $product_id = 26;
    WC()->cart->add_to_cart($product_id);

    $packages = array();
    $packages[0]['contents']                = WC()->cart->cart_contents;
    $packages[0]['contents_cost']           = 25;
    $packages[0]['destination']['country']  = 'NL';
    $packages[0]['destination']['state']    = null;
    $packages[0]['destination']['postcode'] = null;
    $packages[0]['destination']['city']     = null;
    $packages[0]['destination']['address']  = null;

    return ($packages);
}

Upvotes: 1

Views: 21661

Answers (4)

Timo
Timo

Reputation: 51

I improved Victor's answer a bit. print_r($class) inside foreach shows the rest of the options. I wanted to use a custom title instead of the method's title and needed to get free shipping also.

$zones = WC_Shipping_Zones::get_zones();
$methods = array_column( $zones, 'shipping_methods' );

foreach ( $methods[0] as $key => $class ) {

    // Method's ID and custom name
    $item = [
        "id" => $class->method_title,
        "name" => $class->title
    ];

    // Price with and without taxes
    if(isset($class->instance_settings["cost"]) && $class->instance_settings["cost"] > 0){
        $item["price_excl"] = number_format($class->instance_settings["cost"], 2, '.', '');
        $item["price_incl"] = number_format($class->instance_settings["cost"] / 100 * 24 + $class->instance_settings["cost"], 2, '.', '');
    }

    // If minimum amount is required
    if(isset($class->min_amount) && $class->min_amount > 0) $item["minimum"] = (float)$class->min_amount;

    $data[] = $item;
}

print_r($data);
die();

Upvotes: 2

Uriahs Victor
Uriahs Victor

Reputation: 1155

I was able to get a list of all the available shipping methods and create a new normalized array using the shipping method ID and name:

function prefix_get_available_shipping_methods(){

        if ( ! class_exists( 'WC_Shipping_Zones' ) ) {
            return array();
        }

        $zones = WC_Shipping_Zones::get_zones();

        if ( ! is_array( $zones ) ) {
            return array();
        }

        $shipping_methods = array_column( $zones, 'shipping_methods' );

        $flatten = array_merge( ...$shipping_methods );

        $normalized_shipping_methods = array();

        foreach ( $flatten as $key => $class ) {
            $normalized_shipping_methods[ $class->id ] = $class->method_title;
        }

        return $normalized_shipping_methods;

    }

Upvotes: 0

nfw
nfw

Reputation: 4192

I was able to get this done through the WC_Shipping_Zones class.

$zones = WC_Shipping_Zones::get_zones();
$methods = array_map(function($zone) {
    return $zone['shipping_methods'];
}, $zones);

Upvotes: 2

Ronald
Ronald

Reputation: 41

Finally I found a way to get the shipping methods.

Here is my solution, feedback is welcome..

function shipping() {

    global $woocommerce;

    $active_methods   = array();
    $values = array ('country' => 'NL',
                     'amount'  => 100);


    // Fake product number to get a filled card....
    $woocommerce->cart->add_to_cart('1');

    WC()->shipping->calculate_shipping(get_shipping_packages($values));
    $shipping_methods = WC()->shipping->packages;

    foreach ($shipping_methods[0]['rates'] as $id => $shipping_method) {
        $active_methods[] = array(  'id'        => $shipping_method->method_id,
                                    'type'      => $shipping_method->method_id,
                                    'provider'  => $shipping_method->method_id,
                                    'name'      => $shipping_method->label,
                                    'price'     => number_format($shipping_method->cost, 2, '.', ''));
    }
    return $active_methods;
}


function get_shipping_packages($value) {

    // Packages array for storing 'carts'
    $packages = array();
    $packages[0]['contents']                = WC()->cart->cart_contents;
    $packages[0]['contents_cost']           = $value['amount'];
    $packages[0]['applied_coupons']         = WC()->session->applied_coupon;
    $packages[0]['destination']['country']  = $value['countries'];
    $packages[0]['destination']['state']    = '';
    $packages[0]['destination']['postcode'] = '';
    $packages[0]['destination']['city']     = '';
    $packages[0]['destination']['address']  = '';
    $packages[0]['destination']['address_2']= '';


    return apply_filters('woocommerce_cart_shipping_packages', $packages);
}

Upvotes: 3

Related Questions