id = 'afr';
$this->instance_id = absint( $instance_id );
$this->method_title = __( 'Advance Flat Rate', 'woocommerce-shipping-afr' );
$this->method_description = __( 'The AFR shipping extension allows you to manage shipping price per city and shipping classes.', 'woocommerce-shipping-afr' );
$this->supports = array('shipping-zones','instance-settings','settings',);
$this->enabled = isset( $this->settings['enabled'] ) ? $this->settings['enabled'] : 'yes';
$this->title = isset( $this->settings['title'] ) ? $this->settings['title'] : $this->method_title;
$this->weight_factor = ( ( $bool = $this->get_option( 'weight_factor' ) ) && $bool === 'yes' );
$my_wc_shipping = new WC_Shipping();
$this->shipping_class = $my_wc_shipping->get_shipping_classes();
$this->init();
}
/**
* get shipping classes.
*
* @access public
* @since 1.0.0
* @param
*/
public function get_def_shipping_classes() {
return $this->shipping_class;
}
/**
* init function.
*
* @access public
* @since 1.0.0
* @param
*/
private function init() {
// Load the settings.
$this->init_form_fields();
$this->set_settings();
add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) );
add_action( 'admin_enqueue_scripts', array( $this, 'load_admin_scripts' ) );
}
/**
* init_form_fields function.
*
* @access public
* @since 1.0.0
* @version 1.1.0
* @param
*/
public function init_form_fields() {
$this->instance_form_fields = include( dirname( __FILE__ ) . '/data/data-settings.php' );
$this->form_fields = array(
'debug' => array(
'title' => __( 'Debug Mode', 'woocommerce-shipping-afr' ),
'label' => __( 'Enable debug mode', 'woocommerce-shipping-afr' ),
'type' => 'checkbox',
'default' => 'no',
'description' => __( 'Enable debug mode to show debugging information on the cart/checkout.', 'woocommerce-shipping-afr' )
),
'weight_factor' => array(
'title' =>__( 'Weight Base Shipping', 'woocommerce-shipping-afr' ),
'label' => __( 'Enable weight base shipping', 'woocommerce-shipping-afr' ),
'type' => 'checkbox',
'default' => 'no',
'description' => __( 'Enable weight base shipping to manage flat rate shipping with respect to different weight .', 'woocommerce-shipping-afr' )
),
'weight_ranges' => array(
'type' => 'adv_weight_ranges'
),
);
}
/**
* Initialize settings
*
* @access public
* @since 1.0.0
* @version 1.0.1
* @param
*/
private function set_settings() {
$this->debug = ( ( $bool = $this->get_option( 'debug' ) ) && $bool === 'yes' );
$this->title = $this->get_option( 'title');
$this->table_rates = $this->get_option( 'table_rates', array( ));
$this->calculation_type = $this->get_option( 'calculation_type', 'per_item');
$this->weight_ranges = $this->get_option( 'weight_ranges', array( ));
if(!isset($this->table_rates['tr_city_name'][0]))
$this->table_rates['tr_city_name'][0]='Default';
if(!isset($this->table_rates['tr_no_class'][0]))
$this->table_rates['tr_no_class'][0]='';
if(!isset($this->table_rates['tr_enabled'][0]))
$this->table_rates['tr_enabled'][0]='on';
if($this->weight_factor):
foreach($this->weight_ranges['weight_class'] as $sclass):
if(!isset($this->table_rates['tr_class_'.$this->clean($sclass)][0]))
$this->table_rates['tr_class_'.$this->clean($sclass)][0]='';
endforeach;
else:
foreach($this->get_def_shipping_classes() as $sclass):
if(!isset($this->table_rates['tr_class_'.$sclass->slug][0]))
$this->table_rates['tr_class_'.$sclass->slug][0]='';
endforeach;
endif;
if(!isset($this->weight_ranges['weight_class'])):
$this->weight_ranges['weight_class'] = array('Small','Medium','Large');
$this->weight_ranges['min_weight'] = array(10,20,50);
$this->weight_ranges['max_weight'] = array(20,50,100);
endif;
}
/**
* Process settings on save
*
* @access public
* @since 1.0.0
* @param
*/
public function process_admin_options() {
parent::process_admin_options();
$this->set_settings();
}
/**
* Load admin scripts
*
* @access public
* @since 1.0.0
* @param
*/
public function load_admin_scripts() {
// May need this in future
}
/**
* Output a message or error
*
* @access public
* @since 1.0.0
* @param $message text and $type of message like notice, warning, error
*/
public function debug_messages( $message, $type = 'notice' ) {
if ( $this->debug || ( current_user_can( 'manage_options' ) && 'error' == $type ) ):
wc_add_notice( $message, $type );
endif;
}
/**
* generate_adv_weight_ranges_html function.
*
* @access public
* @since 1.1.0
*/
public function generate_adv_weight_ranges_html() {
$current_weight_unit = get_option('woocommerce_weight_unit');
ob_start();
include( 'views/html-weight-ranges.php' );
return ob_get_clean();
}
/**
* generate_adv_table_rates_html function.
*
* @access public
* @since 1.0.0
*/
public function generate_adv_table_rates_html() {
ob_start();
include( 'views/html-table-rates.php' );
return ob_get_clean();
}
/**
* validate_weight_ranges_field function.
*
* @access public
* @since 1.1.0
* @param mixed $key
*/
public function validate_adv_weight_ranges_field( $key ) {
$new_weight_ranges = array();
$new_weight_classes = isset( $_POST['weight_class'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['weight_class'] ) ) : array();
$new_min_weights = isset( $_POST['min_weight'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['min_weight'] ) ) : array();
$new_max_weights = isset( $_POST['max_weight'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['max_weight'] ) ) : array();
foreach ($new_weight_classes as $key => $value):
//Weight Class validation
$safe_class = $value;
if ( strlen( $safe_class ) > 32)
$safe_class = substr( $safe_class, 0, 32 );
$new_weight_ranges['weight_class'][] = $safe_class;
//Min Weight validation
$safe_min = floatval( $new_min_weights[$key] );
if ( ! $safe_min && $safe_min!='0')
$safe_min = '';
if ( strlen( $safe_min ) > 11 )
$safe_min = substr( $safe_min, 0, 11 );
$new_weight_ranges['min_weight'][] = $safe_min;
//Max Weight validation
$safe_max = floatval( $new_max_weights[$key] );
if ( ! $safe_max && $safe_max!='0' )
$safe_max = '';
if ( strlen( $safe_max ) > 11 )
$safe_max = substr( $safe_max, 0, 11 );
$new_weight_ranges['max_weight'][] = $safe_max;
endforeach;
return $new_weight_ranges;
}
/**
* validate_table_rates_field function.
*
* @access public
* @since 1.0.0
* @version 1.1.0
* @param mixed $key
*/
public function validate_adv_table_rates_field( $key ) {
$tr_city_names = isset( $_POST['tr_city_name'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['tr_city_name'] ) ) : array();
$tr_no_classes = isset( $_POST['tr_no_class'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['tr_no_class'] ) ) : array();
if($this->weight_factor):
foreach($this->weight_ranges['weight_class'] as $defclasses):
${'tr_classes_'.$this->clean($defclasses)} = isset( $_POST['tr_class_'.$this->clean($defclasses)] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['tr_class_'.$this->clean($defclasses)] ) ) : array();
endforeach;
else:
foreach($this->get_def_shipping_classes() as $defclasses):
${'tr_classes_'.$defclasses->slug} = isset( $_POST['tr_class_'.$defclasses->slug] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['tr_class_'.$defclasses->slug] ) ) : array();
endforeach;
endif;
$tr_enableds = isset( $_POST['tr_enabled'] ) ? array_map( 'sanitize_text_field', wp_unslash( $_POST['tr_enabled'] ) ) : array();
$new_city_rates = array();
foreach($tr_city_names as $key => $value):
//City Name validation
$safe_city = $value;
if ( strlen( $safe_city ) > 50)
$safe_city = substr( $safe_city, 0, 50 );
$new_city_rates['tr_city_name'][] = $safe_city;
//Default Shipping validation
$safe_default = floatval( $tr_no_classes[$key] );
if ( ! $safe_default && $safe_default!='0')
$safe_default = '';
if ( strlen( $safe_default ) > 11 )
$safe_default = substr( $safe_default, 0, 11 );
$new_city_rates['tr_no_class'][] = $safe_default;
if($this->weight_factor):
foreach($this->weight_ranges['weight_class'] as $defclasses):
//Shipping against weight class validation
$safe_sawc = floatval( ${'tr_classes_'.$this->clean($defclasses)}[$key] );
if ( ! $safe_sawc && $safe_sawc!='0')
$safe_sawc = '';
if ( strlen( $safe_sawc ) > 11 )
$safe_sawc = substr( $safe_sawc, 0, 11 );
$new_city_rates['tr_class_'.$this->clean($defclasses)][] = $safe_sawc;
endforeach;
else:
foreach($this->get_def_shipping_classes() as $defclasses):
//Shipping against shipping class validation
$safe_sawc = floatval( ${'tr_classes_'.$defclasses->slug}[$key] );
if ( ! $safe_sawc && $safe_sawc!='0')
$safe_sawc = '';
if ( strlen( $safe_sawc ) > 11 )
$safe_sawc = substr( $safe_sawc, 0, 11 );
$new_city_rates['tr_class_'.$defclasses->slug][] = $safe_sawc;
endforeach;
endif;
//Enabled validation
$safe_enabled = $tr_enableds[$key];
if ( strlen( $safe_enabled ) > 3)
$safe_enabled = substr( $safe_enabled, 0, 3 );
$new_city_rates['tr_enabled'][] = $safe_enabled;
endforeach;
return $new_city_rates;
}
/**
* is available function.
*
* @access public
* @since 1.0.0
* @param
*/
public function is_available( $package ) {
//if ( empty( $package['destination']['country']) || empty($package['destination']['city'] ) )
// return false;
return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', true, $package );
}
/**
* Calculate Shipping
*
* @access public
* @since 1.0.0
* @version 1.1.0
* @param $package product deatils, shipping details
* @return shipping price
*/
public function calculate_shipping( $package = array() ) {
// Find city index
$cityIndex=0;
foreach($this->table_rates['tr_city_name'] as $citykey => $cityname):
if( strtolower($cityname) == strtolower($package['destination']['city']) ):
if(isset($this->table_rates['tr_enabled'][$citykey]) && $this->table_rates['tr_enabled'][$citykey]=='on')
$cityIndex=$citykey;
break;
endif;
endforeach;
if($this->weight_factor)
$final_calculated_price = $this->weight_based($package,$cityIndex);
else
$final_calculated_price = $this->shipping_classes_based($package,$cityIndex);
$this->debug_messages( __( 'AFR debug mode is on - to hide these messages, turn debug mode off in the settings.', 'woocommerce-shipping-afr' ) );
if($final_calculated_price>0):
$mrate = array(
'id' => $this->id,
'label' => $this->title,
'cost' => $final_calculated_price
);
else:
$mrate = array(
'id' => $this->id,
'label' => __( 'Free Shipping', 'woocommerce-shipping-afr' ),
'cost' => 0.00
);
endif;
$this->add_rate( $mrate );
}
/**
* get weight class
*
* @access private
* @since 1.1.0
* @version 1.1.0
* @param weight
* @return user defined weight class index
*/
private function get_weight_class($weight)
{
$weight_class_index=-1;
if(!empty($weight) && $weight>0):
foreach($this->weight_ranges['weight_class'] as $key => $value):
if($this->weight_ranges['min_weight'][$key] <= $weight && $weight < $this->weight_ranges['max_weight'][$key]):
$weight_class_index=$key;
break;
endif;
endforeach;
endif;
return $weight_class_index;
}
/**
* Calculate Shipping wrt Weights and weight classes
*
* @access private
* @since 1.1.0
* @version 1.1.0
* @param Weight class index
* @return available price for given weight
*/
private function get_price_for_weight($weight_class_index,$cityIndex)
{
$available_price = 0;
if($weight_class_index>=0):
$weight_class = 'tr_class_'.$this->clean($this->weight_ranges['weight_class'][$weight_class_index]);
if(isset($this->table_rates[$weight_class][$cityIndex]) && $this->table_rates[$weight_class][$cityIndex]>-1)
$available_price = $this->table_rates[$weight_class][$cityIndex];
elseif(isset($this->table_rates['tr_no_class'][$cityIndex]) && $this->table_rates['tr_no_class'][$cityIndex]>-1)
$available_price = $this->table_rates['tr_no_class'][$cityIndex];
elseif(isset($this->table_rates[$weight_class][0]) && $this->table_rates[$weight_class][0]>-1)
$available_price = $this->table_rates[$weight_class][0];
elseif(isset($this->table_rates['tr_no_class'][0]) && $this->table_rates['tr_no_class'][0]>-1)
$available_price = $this->table_rates['tr_no_class'][0];;
else:
$weight_class = 'tr_no_class';
if(isset($this->table_rates[$weight_class][$cityIndex]) && $this->table_rates[$weight_class][$cityIndex]>-1)
$available_price = $this->table_rates[$weight_class][$cityIndex];
elseif(isset($this->table_rates[$weight_class][0]) && $this->table_rates[$weight_class][0]>-1)
$available_price = $this->table_rates[$weight_class][0];
endif;
return $available_price;
}
/**
* Weight Based Shipping wrt Weights and weight classes
*
* @access private
* @since 1.1.0
* @version 1.1.0
* @param package, city
* @return integer final shipping cost
*/
private function weight_based($package,$cityIndex) {
$total_weight=0;
$total_price=0;
$all_weight_class_found = array();
foreach ( $package['contents'] as $item_id => $values ):
$cart_item_sub_weight=0;
$cart_item_weight = $values['data']->get_weight();
if($cart_item_weight>0)
$cart_item_sub_weight = ($cart_item_weight * $values['quantity']);
$weight_class_index = $this->get_weight_class($cart_item_sub_weight);
if($this->calculation_type == 'per_order')
$total_weight += $cart_item_sub_weight;
else
$total_price += floatval($this->get_price_for_weight($weight_class_index,$cityIndex));
$all_weight_class_found[] = $cart_item_sub_weight;
endforeach;
if($this->calculation_type == 'per_order'):
$total_price = 0;
$weight_class_index = $this->get_weight_class($total_weight);
$total_price = floatval($this->get_price_for_weight($weight_class_index,$cityIndex));
endif;
$final_calculated_price=$total_price;
$this->debug_messages( __( 'Weights: '.implode(', ', $all_weight_class_found).'
Package Details: '.json_encode($package), 'woocommerce-shipping-afr' ) );
return $final_calculated_price;
}
/**
* Calculate Shipping wrt Shipping Classes
*
* @access private
* @since 1.1.0
* @version 1.1.0
* @param package, city
* @return integer final shipping cost
*/
private function shipping_classes_based($package,$cityIndex) {
$allClassPrice=0;
$minClassPrice=0;
$maxClassPrice=0;
$sclasses_index = 0;
$all_shipping_class_found = array();
foreach ( $package['contents'] as $item_id => $values ) :
$cart_item_shipping_class = $values['data']->get_shipping_class();
$all_shipping_class_found[] = $cart_item_shipping_class;
$priceForClass = 0;
if(!empty($cart_item_shipping_class)):
if( isset($this->table_rates['tr_class_'.$cart_item_shipping_class][$cityIndex]) && $this->table_rates['tr_class_'.$cart_item_shipping_class][$cityIndex]>-1)
$priceForClass = $this->table_rates['tr_class_'.$cart_item_shipping_class][$cityIndex];
else if(isset($this->table_rates['tr_no_class'][$cityIndex]) && $this->table_rates['tr_no_class'][$cityIndex]>-1)
$priceForClass = $this->table_rates['tr_no_class'][$cityIndex];
else if(isset($this->table_rates['tr_class_'.$cart_item_shipping_class][0]) && $this->table_rates['tr_class_'.$cart_item_shipping_class][0]>-1)
$priceForClass = $this->table_rates['tr_class_'.$cart_item_shipping_class][0];
else if(isset($this->table_rates['tr_no_class'][0]) && $this->table_rates['tr_no_class'][0]>-1)
$priceForClass = $this->table_rates['tr_no_class'][0];;
else:
if(isset($this->table_rates['tr_no_class'][$cityIndex]) && $this->table_rates['tr_no_class'][$cityIndex]>-1)
$priceForClass = $this->table_rates['tr_no_class'][$cityIndex];
else if(isset($this->table_rates['tr_no_class'][0]) && $this->table_rates['tr_no_class'][0]>-1)
$priceForClass = $this->table_rates['tr_no_class'][0];
endif;
$priceForClass = str_replace(" ", "", $priceForClass);
$priceForClassArr = explode("*", $priceForClass);
if(strtolower(@$priceForClassArr[1]) == '[qty]' && is_numeric($priceForClassArr[0]))
$priceForClass = $priceForClassArr[0] * $values['quantity'];
else if(is_numeric($priceForClassArr[0]))
$priceForClass = $priceForClassArr[0];
else
$priceForClass=0;
$allClassPrice += $priceForClass;
if($sclasses_index==0):
$minPriceClass=$priceForClass;
$maxPriceClass=$priceForClass;
else:
if($priceForClass<$minPriceClass)
$minPriceClass = $priceForClass;
if($priceForClass>$maxPriceClass)
$maxPriceClass = $priceForClass;
endif;
$sclasses_index++;
endforeach;
$final_calculated_price=0;
if($this->calculation_type == 'per_order_max')
$final_calculated_price=$maxPriceClass;
else if($this->calculation_type == 'per_order_min')
$final_calculated_price=$minPriceClass;
else
$final_calculated_price=$allClassPrice;
$this->debug_messages( __( 'Shipping Class: '.implode(', ', $all_shipping_class_found).'
'.json_encode($package), 'woocommerce-shipping-afr' ) );
return $final_calculated_price;
}
/**
* clean strings
*
* @access private
* @since 1.1.0
* @version 1.1.0
* @param $string
* @return clean string: without special characters
*/
private function clean($string) {
$string = esc_html($string);
$string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
$string = preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
return preg_replace('/-+/', '-', $string); // Replaces multiple hyphens with single one.
}
}