Display shipping cost on product page - WooCommerce

后端 未结 1 1868
轻奢々
轻奢々 2021-02-10 17:31

I\'m trying to make a custom page on Wordpress that display 2 subscription types in a form with 3 variations each (monthly, 6 month, 12 month). Each variation gets a radio butto

1条回答
  •  悲哀的现实
    2021-02-10 18:11

    This question is too broad. So I can answer partially as you should need to make some work yourself, and ask later more specific questions…

    Now the correct way to set shipping data on product page, is to use Ajax to update the data, as the action is made by the customer on client side (browser), avoiding 'post' and reload the page. But this should be your work...

    1) Customer location (for shipping Zones):

    You should need to get the customer location or shipping zone first.

    Then you will need to update the customer country in WC()->session and in WC()->customer objects. This can be done with the following:

    ## Get the geolocated customer country code *(if enabled)*:
    $country_code = WC()->customer->get_billing_country();
    // or
    // $country_code = WC()->customer->get_shipping_country();
    
    
    ## Set a new country code
    $new_country_code = 'FR';
    
    ## 1. WC_session: set customer billing and shipping country
    
    // Get the data
    $customer_session = WC()->session->get( 'customer' );
    // Change some data
    $customer_session['country'] = $new_country_code; // Billing
    $customer_session['shipping_country'] = $new_country_code; // Shipping
    // Set the changed data
    $customer_session = WC()->session->set( 'customer', $customer_session );
    
    ## 2. WC_Customer: set customer billing and shipping country
    
    WC()->customer->set_billing_country( $new_country_code );
    WC()->customer->set_shipping_country( $new_country_code );
    

    2) The shipping methods (by Shipping Zone, with costs):

    In Woocommerce the Shipping methods for a Shipping Zone are only available when customer add a product to cart…

    Based on this answer code: Display shipping methods to frontend as in the admin panel?
    we can make a custom array of the necessary data to be used to get the shipping methods by shipping Zones, with costs and everything needed.

    The code below is much more complete and include the shipping methods costs:

    // Initializing variable
    $zones = $data = $classes_keys = array();
    
    // Rest of the World zone
    $zone                                              = new \WC_Shipping_Zone(0);
    $zones[$zone->get_id()]                            = $zone->get_data();
    $zones[$zone->get_id()]['formatted_zone_location'] = $zone->get_formatted_location();
    $zones[$zone->get_id()]['shipping_methods']        = $zone->get_shipping_methods();
    
    // Merging shipping zones
    $shipping_zones = array_merge( $zones, WC_Shipping_Zones::get_zones() );
    
    // Shipping Classes
    $shipping           = new \WC_Shipping();
    $shipping_classes   = $shipping->get_shipping_classes();
    
    // The Shipping Classes for costs in "Flat rate" Shipping Method
    foreach($shipping_classes as $shipping_class) {
        //
        $key_class_cost = 'class_cost_'.$shipping_class->term_id;
    
        // The shipping classes
        $classes_keys[$shipping_class->term_id] = array(
            'term_id' => $shipping_class->term_id,
            'name' => $shipping_class->name,
            'slug' => $shipping_class->slug,
            'count' => $shipping_class->count,
            'key_cost' => $key_class_cost
        );
    }
    
    // For 'No class" cost
    $classes_keys[0] = array(
        'term_id' => '',
        'name' =>  'No shipping class',
        'slug' => 'no_class',
        'count' => '',
        'key_cost' => 'no_class_cost'
    );
    
    foreach ( $shipping_zones as $shipping_zone ) {
        $zone_id = $shipping_zone['id'];
        $zone_name = $zone_id == '0' ? __('Rest of the word', 'woocommerce') : $shipping_zone['zone_name'];
        $zone_locations = $shipping_zone['zone_locations']; // array
        $zone_location_name = $shipping_zone['formatted_zone_location'];
    
        // Set the data in an array:
        $data[$zone_id]= array(
            'zone_id'               => $zone_id,
            'zone_name'             => $zone_name,
            'zone_location_name'    => $zone_location_name,
            'zone_locations'        => $zone_locations,
            'shipping_methods'      => array()
        );
    
        foreach ( $shipping_zone['shipping_methods'] as $sm_obj ) {
            $method_id   = $sm_obj->id;
            $instance_id = $sm_obj->get_instance_id();
            $enabled = $sm_obj->is_enabled() ? true : 0;
            // Settings specific to each shipping method
            $instance_settings = $sm_obj->instance_settings;
            if( $enabled ){
                $data[$zone_id]['shipping_methods'][$instance_id] = array(
                    '$method_id'    => $sm_obj->id,
                    'instance_id'   => $instance_id,
                    'rate_id'       => $sm_obj->get_rate_id(),
                    'default_name'  => $sm_obj->get_method_title(),
                    'custom_name'   => $sm_obj->get_title(),
                );
    
                if( $method_id == 'free_shipping' ){
                    $data[$zone_id]['shipping_methods'][$instance_id]['requires'] = $instance_settings['requires'];
                    $data[$zone_id]['shipping_methods'][$instance_id]['min_amount'] = $instance_settings['min_amount'];
                }
                if( $method_id == 'flat_rate' || $method_id == 'local_pickup' ){
                    $data[$zone_id]['shipping_methods'][$instance_id]['tax_status'] = $instance_settings['tax_status'];
                    $data[$zone_id]['shipping_methods'][$instance_id]['cost'] = $sm_obj->cost;
                }
                if( $method_id == 'flat_rate' ){
                    $data[$zone_id]['shipping_methods'][$instance_id]['class_costs'] = $instance_settings['class_costs'];
                    $data[$zone_id]['shipping_methods'][$instance_id]['calculation_type'] = $instance_settings['type'];
                    $classes_keys[0]['cost'] = $instance_settings['no_class_cost'];
                    foreach( $instance_settings as $key => $setting )
                        if ( strpos( $key, 'class_cost_') !== false ){
                            $class_id = str_replace('class_cost_', '', $key );
                            $classes_keys[$class_id]['cost'] = $setting;
                        }
    
                    $data[$zone_id]['shipping_methods'][$instance_id]['classes_&_costs'] = $classes_keys;
                }
            }
        }
    }
    
    // Row output (for testing)
    echo '
    '; print_r($data); echo '
    ';

    custom shipping methods
    Now if you are using custom shipping methods (enabled sometimes by 3rd party shipping plugins) you will need to make some changes in the code…

    Costs and taxes calculation
    You should need to make the taxes calculations, as the costs are displayed just as they are set in shipping settings…


    3) Product page

    Customer location:
    You will need first to have a location selector (to define the Shipping Zone) or to set the location based on Woocommerce geolocation.

    Shipping Methods:
    Once the Shipping Zone is defined, you can get the corresponding Shipping Methods and rates (costs), displaying on this product page your radio buttons for Shipping methods.

    To get this, you should need to alter the single product pages:

    • Overriding the Woocommerce templates via your theme (and WC Subscriptions templates too)
    • Using the available filters and action hooks
    • Use Javascript, jQuery to alter prices and Ajax to update the customer data (WC_Session and WC_Customer).

    You should need to get/set/update the "chosen_shipping_methods" with the following code (Ajax).

    Get the Chosen Shipping method:

    $chosen_shipping = WC()->session->get('chosen_shipping_methods')[0];
    

    Set/Update the Chosen Shipping method (through Javascript/Ajax and admin-ajax.php):

    // HERE the new method ID
    $method_rate_id = array('free_shipping:10');
    
    // Set/Update the Chosen Shipping method
    WC()->session->set( 'chosen_shipping_methods', $method_rate_id );
    

    0 讨论(0)
提交回复
热议问题