instance_id = absint( $instance_id ); $this->id = $this->identifier . '_' . mb_strtolower( $this->carrier ); $this->ext = mb_strtolower( $this->carrier ); $this->title = $this->return_method_title(); $this->method_title = $this->title; $this->name_ext = $this->title; //get settings from WC_Shipping_Method $this->init_settings(); //set default settings used by all shipping methods $this->set_default_settings(); //initialize form fields for admin $this->initialize_form_fields(); //set hooks $this->set_hooks(); //initilize method type $this->initialize(); } /** * Set hooks used by all WooCommerce shipping methods * * @since 3.0.0 */ final public function set_hooks() { //update options add_action( 'woocommerce_update_options_shipping_' . $this->id, array( $this, 'process_admin_options' ) ); //Woocommerce Multilingual overrides (change some titles) if ( \MakeCommerce\i18n::using_language_plugins() ) { add_filter( 'woocommerce_package_rates', array( $this, 'override_label_translation' ), 50 ); add_filter( 'woocommerce_order_get_items', array( $this, 'override_shipping_title_translation' ), 50, 2 ); } //check if a parcelmachine has been chosen in checkout add_action( 'woocommerce_checkout_process', array( $this, 'check_checkout_fields' ) ); add_action( 'woocommerce_after_checkout_validation', array( $this, 'check_checkout_fields' ) ); } /** * Add check for parcelmachine selectbox * Checks if something is chosen * * @since 3.0.4 */ public function check_checkout_fields() { //those checks are needed, otherwise the notification will be added more than once static $added1 = false; static $added2 = false; $shipping_method = !empty( $_POST['shipping_method'] ) ? $_POST['shipping_method'] : false; if ( !empty( $shipping_method[0] ) ) { $shipping_method_ext = explode( ':', $shipping_method[0] ); } if ( !$added1 && $shipping_method_ext[0] === $this->id && empty( $_POST[$shipping_method_ext[0]] ) && $this->type == "apt" ) { wc_add_notice( __( 'Parcel machine is a required field.', 'wc_makecommerce_domain' ), 'error' ); $added1 = true; } $shipping_phone_number = null; if ( isset( $_POST['ship_to_different_address'] ) && isset( $_POST['shipping_phone'] ) ) { $_POST['shipping_phone'] = $this->sanitize_phone_number( $_POST['shipping_phone'] ); $shipping_phone_number = $_POST['shipping_phone']; } else { $_POST['billing_phone'] = $this->sanitize_phone_number( $_POST['billing_phone'] ); $shipping_phone_number = $_POST['billing_phone']; } if ( $shipping_phone_number !== null ) { if ( !$added2 && $shipping_method_ext[0] === $this->id && !$this->valid_phone_number( $shipping_phone_number ) ) { wc_add_notice( $this->phone_number_validation_error(), 'error' ); $added2 = true; } } } /** * Sanitize phone number * * @since 3.0.4 */ public function sanitize_phone_number( $phone_number ) { $phone_number = filter_var ( $phone_number, FILTER_SANITIZE_NUMBER_INT ); $phone_number = trim( $phone_number, '-' ); //convert first 2 zeros to + if needed if ( substr( $phone_number, 0, 2 ) == "00" ) { $phone_number = '+' . substr( $phone_number, 2 ); } return $phone_number; } /** * Check if provided phonenumber is valid * * @since 3.0.4 */ public function valid_phone_number( $phone_number ) { //could be that all that we need to check is international format if ( $this->international_number_format ) { return $this->check_international_number( $phone_number ); } //allow all numbers if validation is not defined if ( !isset( $this->valid_phonenumber_country_codes ) ) { return true; } //remove + signs $phone_number = trim( $phone_number, '+' ); //check if it contains country code foreach ( $this->valid_phonenumber_country_codes as $country_code=>$valid_numbers ) { //country code matched if ( substr( $phone_number, 0, strlen( $country_code ) ) == $country_code ) { return $this->check_number( substr( $phone_number, strlen( $country_code ) ), $valid_numbers ); } } //country code didn't match, there is nothing we can do but check if its valid in any of the provided countries foreach ( $this->valid_phonenumber_country_codes as $country_code=>$valid_numbers ) { if ( $this->check_number( $phone_number, $valid_numbers ) === true ) { return true; } } return false; } /** * Check if phone number is international format * * This function could be improved. Either by using https://github.com/google/libphonenumber or creating our own library * * @since 3.0.4 */ public function check_international_number( $number ) { //https://en.wikipedia.org/wiki/E.164 (Solomon islands has 8) $min = 8; $max = 15; //without going into any more detail we are just going to check if the number starts with a + and has a minimum amount of numbers and a maximum if ( substr( $number, 0, strlen( '+' ) ) && strlen( $number ) >= ( $min + 1 ) && strlen( $number ) <= ( $max + 1 ) ) { return true; } return false; } /** * Check if number is valid according to an array * * @since 3.0.4 */ public function check_number( $number, $valid_numbers ) { foreach ( $valid_numbers as $start_digits=>$lenghts ) { foreach ( $lenghts as $lenght ) { if ( substr( $number, 0, strlen( $start_digits ) ) == $start_digits && strlen( $number ) == $lenght ) { return true; } } } return false; } /** * Label translation override for WPML (woocommerce_package_rates) * * @since 3.0.0 */ public function override_label_translation( $rates ) { $id_instance = $this->id . ':' . $this->instance_id; if ( array_key_exists( $id_instance, $rates ) ) { $rates[$id_instance]->label = $this->title; } return $rates; } /** * Title translation override for WPML (woocommerce_order_get_items) * * @since 3.0.0 */ public function override_shipping_title_translation( $items, $order ) { foreach ( $items as $key => $item ) { if ( $item['type'] == 'shipping' ) { foreach ( $item['item_meta_array'] as $meta ) { if ( $meta->key === 'method_id' ) { $tmp = explode( ':', $meta->value ); if ( $tmp[0] == $this->id ) { $items[$key]['name'] = $this->title; } } } } } return $items; } /** * Sets default settings used by all shipping methods * * @since 3.0.0 */ final public function set_default_settings() { $this->enable = !empty( $this->settings['active'] ) ? $this->settings['active'] : null; $this->availability = 'specific'; $this->order_country = 'unknown'; $this->maximum_weight = !empty( $this->settings['maximum_weight']) ? ( double )$this->settings['maximum_weight'] : 0; $this->free_shipping_min_amount = !empty( $this->settings['free_shipping_min_amount'] ) ? $this->settings['free_shipping_min_amount'] : 0; $this->countries = !empty( $this->settings['countries'] ) ? $this->settings['countries'] : array(); //Overrides title if its set in settings already $this->override_title(); } /** * Check if the shipping method is available (automatically called by parent \WC_Shipping_Method) * * @since 3.0.0 */ public function is_available( $package ) { //check if cart weight exceeds max weight if ( WC()->cart->cart_contents_weight > $this->maximum_weight ) { return false; } $is_available = $this->enable === 'yes'; if ( !$is_available || !\MakeCommerce::is_api_set() ) { return false; } $this->order_country = $package['destination']['country']; return apply_filters( 'woocommerce_shipping_' . $this->id . '_is_available', $is_available, $package ); } /** * Calculate price for shipping * * @since 3.0.0 */ public function calculate_shipping( $package = array() ) { $price = isset( $this->instance_settings['price'] ) ? $this->instance_settings['price'] : ( isset( $this->settings['price_'.$package['destination']['country']] ) ? $this->settings['price_'.$package['destination']['country']] : 0 ); $rate = array( 'id' => $this->get_rate_id(), 'label' => $this->title, 'cost' => $price, 'package' => $package, 'calc_tax' => 'per_order', ); //check shippingclasses $rate = $this->calculate_shipping_class_price( $rate, $package ); //check all free shipping options: $free_shipping_min_amount = $this->instance_settings['free_shipping_min_amount']; if ( $free_shipping_min_amount && $package['contents_cost'] >= $free_shipping_min_amount ) { $rate["cost"] = 0; } //check only for parcelmachines if ( $this->type == "apt" ) { $free_shipping = true; foreach ( $package['contents'] as $line ) { $free_shipping = get_post_meta( $line['product_id'], '_no_shipping_cost', true ) === 'yes' ? $free_shipping : false; } if ( $free_shipping ) { $rate["cost"] = 0; } } //check if there is a free shipping coupon (if it's free then allow free shipping) if ( isset( $package['applied_coupons'] ) && $this->instance_settings["allow_free_shipping_coupons"] === "yes" ) { foreach ( $package['applied_coupons'] as $coupon_code ) { $coupon = new \WC_Coupon( $coupon_code ); if ( $coupon->get_free_shipping() === true ) { $rate["cost"] = 0; break; } } } $this->add_rate( $rate ); } /** * This function overrides shipping method title * if you have set language specific titles in admin. * * @since 3.0.0 */ final public function override_title() { $language_code = \MakeCommerce\i18n::get_two_char_locale(); //default (no language) if ( !empty( $this->settings['method_name'] ) ) { $this->title = $this->settings['method_name']; } //if method name setting has been set with current language code if ( !empty( $this->settings['method_name_' . $language_code] ) ) { $this->title = $this->settings['method_name_' . $language_code]; } } /** * Initializes basic fields used by all shipping methods. * * @since 3.0.0 */ public function initialize_form_fields() { //Initialize instance form fields first $this->initialize_instance_form_fields(); //Initialize basic form fields $this->initialize_basic_form_fields(); //Initialize method specific form fields $this->initialize_method_type_form_fields(); //Initialize return address fields $this->initalize_return_addres_form_fields(); } /** * Initializes basic shared form fields * Used by all shipping methods * * @since 3.0.0 */ final public function initialize_basic_form_fields() { $this->form_fields = array(); $this->form_fields['logo'] = array( 'type' => 'title', 'description' => \MakeCommerce::get_logo_html() ); $this->form_fields['generic'] = array( 'type' => 'title', 'title' => __( 'Generic and pricing options', 'wc_makecommerce_domain' ), ); $this->form_fields['active'] = array( 'title' => __( 'Enable', 'wc_makecommerce_domain' ), 'type' => 'checkbox', 'label' => __( 'enabled', 'wc_makecommerce_domain' ), 'default' => 'no', ); $this->form_fields['maximum_weight'] = array( 'title' => sprintf( __( 'Maximum weight allowed for shipping (%s)', 'wc_makecommerce_domain' ), get_option( 'woocommerce_weight_unit' ) ), 'type' => 'text', 'default' => $this->default_max_weight ); $this->form_fields['look_and_feel'] = array( 'type' => 'title', 'title' => '