File "class.shipping-method.php"

Full Path: /home/siazco/grocery.siazco.se/wp-content/plugins/woocommerce-table-rate-shipping/inc/class.shipping-method.php
File size: 20.53 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/*
 * Table Rate Shipping Method Extender Class
 */

if ( ! defined( 'ABSPATH' ) )
	exit;

// Check if WooCommerce is active
if ( class_exists( 'WooCommerce' ) ) {

	if ( ! class_exists('WC_Shipping_Method')) return;

	if ( class_exists( 'BE_Table_Rate_Method' ) ) return;

	class BE_Table_Rate_Method extends WC_Shipping_Method {

		/*
		 * Table Rates from Database
		 */
		protected $options_save_name;
		
		/*
		 * Table Rates from Database
		 */
		protected $m_conds_save_name;

		/*
		 * BE_Table_Rate_Calculate class.
		 */
		protected $calcClass;

		/*
		 * Default Table Selected
		 */
		public $default;

		/*
		 * Settings Variables
		 */
		public $condition;
		public $user_limitation;
		public $user_limit_roles;
		public $user_modification;
		public $user_mod_users;
		public $user_mod_roles;
		public $includetax;
		public $volumetric_number;
		public $volumetric_operand;
		public $volumetric_exclude;
		public $include_coupons;
		public $single_class;
		public $round_weight;
		public $hide_method;

		/**
		 * Cloning is forbidden. Will deactivate prior 'instances' users are running
		 *
		 * @since 4.0
		 */
		public function __clone() {
			_doing_it_wrong( __FUNCTION__, esc_html__( 'Cloning this class could cause catastrophic disasters!', 'be-table-ship' ), '4.0' );
		}

		/**
		 * Unserializing instances of this class is forbidden.
		 *
		 * @since 4.0
		 */
		public function __wakeup() {
			_doing_it_wrong( __FUNCTION__, esc_html__( 'Unserializing is forbidden!', 'be-table-ship' ), '4.0' );
		}

		/**
		 * __construct function.
		 *
		 * @access public
		 * @return void
		 */
		function __construct( $instance_id = 0 ) {
			global $betrs_shipping;

			$this->id 					= 'betrs_shipping';
			$this->instance_id 			= absint( $instance_id );
	 		$this->method_title 		= esc_html__( 'Table Rate', 'be-table-ship' );
	 		$this->method_description 	= esc_html__( 'Charge varying rates based on user defined conditions', 'be-table-ship' );
			$this->supports 			= array( 'shipping-zones', 'instance-settings' );
			$this->options_save_name	= $this->id . '_options-' . $this->instance_id;
			$this->m_conds_save_name	= $this->id . '_method_conds-' . $this->instance_id;
			$this->default 				= "";

			// Initialize settings
			$this->init();
			$betrs_shipping->method_conditions->set_save_name( $this->get_method_conditions_save_name() );

			// additional hooks for post-calculations settings
			add_filter( 'betrs_shipping_rate_description', array( $this, 'shortcode_free_counter' ), 10, 5 );
			add_filter( 'woocommerce_shipping_chosen_method', array( $this, 'select_default_rate' ), 10, 2 );
			add_filter( 'woocommerce_package_rates', array( $this, 'hide_shipping_when_free_is_available' ), 100 );
			add_filter( 'betrs_calculated_table_rate_options', array( $this, 'hide_other_options' ), 100, 1 );
			add_filter( 'woocommerce_shipping_' . $this->id . '_instance_settings_values', array( $this, 'update_management_permissions' ), 10, 2 );

		}


		/**
		* init function.
		* initialize variables to be used
		*
		* @access public
		* @return void
		*/
		function init() {
			// Load the form fields.
			$this->instance_form_fields = include( 'instance-settings-fields.php' );
			$this->instance_form_fields = apply_filters( 'woocommerce_shipping_instance_form_fields_' . $this->id, $this->instance_form_fields );

			// Define user set variables
			$this->title 				= $this->get_instance_option( 'title' );
			$this->tax_status 			= $this->get_instance_option( 'tax_status' );
			$this->condition 			= $this->get_instance_option( 'condition' );
			$this->user_limitation 		= $this->get_instance_option( 'user_limitation' );
			$this->user_limit_roles 	= $this->get_instance_option( 'user_limitation_roles' );
			$this->user_modification 	= $this->get_instance_option( 'user_modification' );
			$this->user_mod_users 		= $this->get_instance_option( 'user_modification_users' );
			$this->user_mod_roles 		= $this->get_instance_option( 'user_modification_roles' );
			$this->volumetric_number 	= $this->get_instance_option( 'volumetric_number' );
			$this->volumetric_operand 	= $this->get_instance_option( 'volumetric_operand' );
			$this->volumetric_exclude 	= $this->get_instance_option( 'volumetric_exclude' );
			$this->includetax	 		= $this->get_instance_option( 'includetax' );
			$this->include_coupons 		= $this->get_instance_option( 'include_coupons' );
			$this->single_class 		= $this->get_instance_option( 'single_class' );
			$this->round_weight 		= $this->get_instance_option( 'round_weight' );
			$this->hide_method 			= $this->get_instance_option( 'hide_method' );

			do_action( 'betrs_shipping_initialize_settings' );
		}


		/**
		 * Get settings fields for instances of this shipping method (within zones).
		 *
		 * @access public
		 * @return array
		 */
		public function get_instance_form_fields() {

			$fields = ( is_array( $this->instance_form_fields ) ) ? $this->alter_options_array( $this->instance_form_fields ) : array();

			return $fields;
		}


		/**
		 * Initialize settings for instances.
		 *
		 * @access public
		 * @return array
		 */
		public function init_instance_settings() {
			$this->instance_settings = get_option( $this->get_instance_option_key(), null );

			// If there are no settings defined, use defaults.
			if ( ! is_array( $this->instance_settings ) ) {
				$form_fields             = $this->get_instance_form_fields();
				$this->instance_settings = array_merge( array_fill_keys( array_keys( $form_fields ), '' ), wp_list_pluck( $form_fields, 'default' ) );
			}
		}


		/**
		* condense multidimensional array into one array of options
		*
		* @access public
		* @return array
		*/
		function alter_options_array( $instance_form_fields ) {

			$copy = array();
			foreach( $instance_form_fields as $kg => $group )
				if( isset( $group[ 'settings' ] ) ) {
					foreach( $group[ 'settings' ] as $ko => $option )
						$copy[ $ko ] = $option;
				} else {
					$copy[ $kg ] = $group;
				}

			// add empty 'table_rates' field for saving purposes
			$copy[ 'table_rates' ] = array(
				'title' 		=> esc_html__( 'Table of Rates', 'be-table-ship' ),
				'type' 			=> 'table_rates',
				'default' 		=> array(),
				'description' 	=> '',
				);

			return apply_filters('betrs_shipping_altered_form_fields_' . $this->id, $copy );
		}


		/**
		 * Admin Panel Options
		 *
		 * @access public
		 * @return void
		 */
		public function admin_options() {
			global $wp_filter;

			$this->init();

			$section_counter = 1;
			$settings_exceptions = apply_filters( 'betrs_shipping_settings_fields_exceptions', array(), $this->instance_form_fields );
			$settings_sections = apply_filters( 'betrs_shipping_settings_fields_sections', array() );
?>
<div id="BETRS-method-options">
	<a href="#" class="expand">Expand All</a> | 
	<a href="#" class="collapse">Collapse All</a>
</div>
<?php
			if( is_array( $this->instance_form_fields ) ) :
				// sort by priority number
				$priority = $other_fields = array();
				foreach( $this->instance_form_fields as $key => $instance_fields )
					$priority[ $key ] = ( isset( $instance_fields[ 'priority' ] ) ) ? absint( $instance_fields[ 'priority' ] ) : 30;
				array_multisort( $priority, SORT_ASC, SORT_NUMERIC, $this->instance_form_fields );

				foreach( $this->instance_form_fields as $key => $instance_fields ) :

					if( isset( $instance_fields ) && is_array( $instance_fields ) ) :

						// only process Table Rate made sections
						if( isset( $instance_fields['settings'] ) ) {
							$this->generate_settings_section( $key, $instance_fields, $section_counter );
							$section_counter++;
						} elseif( array_key_exists( $key, $settings_exceptions ) ) {
							// nothing to do right now
						} else {
							$other_fields[ $key ] = $instance_fields;
						}

					endif;

				endforeach;

			endif;

			// Setup section of third party add-ins
			if( is_array( $settings_sections ) && ! empty( $settings_sections ) ) {

				foreach( $settings_sections as $section_key => $section_args ) {
					
					// validate required arguments
					if( ! isset( $section_args['title'] ) || ! isset( $section_args['settings'] ) || ! is_array( $section_args['settings'] ) ) continue;

					// sanitize user input data
					$new_title = sanitize_text_field( $section_args['title'] );
					
					// add new section
					$new_section = array(
						'title'		=> $new_title,
						'settings'	=> apply_filters( 'betrs_shipping_settings_exceptions_' . sanitize_title( $section_key ) . '_settings_fields', $section_args['settings'] )
						);

					$this->generate_settings_section( sanitize_title( $section_key ), $new_section, $section_counter++ );
				}
			}

			// Setup section of third party add-ins
			if( ! empty( $other_fields ) ) {
				$other_section = array(
					'title'		=> esc_html__( 'Settings from Other Plugins', 'be-table-ship' ),
					'settings'	=> $other_fields
					);
				$this->generate_settings_section( 'other_plugins', $other_section, $section_counter++ );
			}

			// Setup table of rates section
			$table_rate_section = array(
				'title'		=> esc_html__( 'Table of Rates', 'be-table-ship' ),
				'callback'	=> array( $this, 'section_table_rates' ),
				);
			$this->generate_settings_section( 'table_rates', $table_rate_section, $section_counter++ );
		}



		/**
		 * Section for Admin Panel Options
		 *
		 * @access public
		 * @return void
		 */
		public function generate_settings_section( $key, $admin_section, $section_counter = 1 ) {
?>
<div id="<?php echo sanitize_text_field( $key ); ?>" class="betrs_settings_section">

<?php if( isset( $admin_section[ 'title' ] ) ) : ?>
	<h3><span class="counter"><?php echo absint( $section_counter ); ?></span>
		<span><?php echo sanitize_text_field( $admin_section[ 'title' ] ); ?></span>
		</h3>
<?php endif; ?>

	<div class="betrs_settings_inner">

<?php
		if( isset( $admin_section[ 'description' ] ) && ! empty( $admin_section[ 'description' ] ) ) {
			echo '<p>' . sanitize_text_field( $admin_section[ 'description' ] ) . '</p>';
		}

		// generate custom settings sections
		if( isset( $admin_section[ 'callback' ] ) ) { // Call user function for custom option blocks
			if( is_callable( $admin_section[ 'callback' ] ) )
				call_user_func( $admin_section[ 'callback' ] );

		} elseif( isset( $admin_section[ 'settings' ] ) && is_array( $admin_section[ 'settings' ] ) ) { 
			// generate regular box for predefined sections
?>
		<table class="form-table">
			<?php $this->generate_settings_html( $admin_section[ 'settings' ] ); ?>
		</table>
<?php
		}
?>
		<p class="next-link"><a href="#" class="button">Next</a></p>
	</div>
</div>
<?php
		}



		/**
		 * Section for Admin Panel Options
		 *
		 * @access public
		 * @return void
		 */
		public function section_other() {
			global $betrs_shipping;

			$betrs_shipping->table_rates->set_saved_table_rates( get_option( $this->get_options_save_name() ) );
			$betrs_shipping->table_rates->display();
		}



		/**
		 * Section for Admin Panel Options
		 *
		 * @access public
		 * @return void
		 */
		public function section_table_rates() {
			global $betrs_shipping;

			$betrs_shipping->table_rates->set_saved_table_rates( get_option( $this->get_options_save_name() ) );
			$betrs_shipping->table_rates->display();
		}


		/**
		 * Process settings for table of rates
		 *
		 * @access public
		 * @return void
		 */
		public function validate_table_rates_field( $key, $data ) {
			global $betrs_shipping;
			
			$betrs_shipping->table_rates->process_table_rates( $this->get_options_save_name() );
		}


		/**
		 * Process settings for method conditions
		 *
		 * @access public
		 * @return void
		 */
		public function validate_method_conditions_field( $key, $data ) {
			global $betrs_shipping;
			
			$betrs_shipping->method_conditions->process_method_conditions( $this->get_method_conditions_save_name() );
		}


		/**
		 * calculate_shipping function.
		 *
		 * @access public
		 * @param array $package (default: array())
		 * @return void
		 */
		function calculate_shipping( $package = array() ) {
			// do not calculate if user permissions are set and not qualified
			if( ! $this->user_restrictions_qualified() ) return;

			// check for other external requirements
			$results = apply_filters( 'betrs_custom_restrictions', array( true ), $package, $this );
			if( ! in_array( true, (array) $results ) || in_array( false, (array) $results ) ) return;

			// setup necessary class for calculations
			$table_rates = get_option( $this->get_options_save_name() );
			$this->calcClass = new BE_Table_Rate_Calculate( $this, $table_rates );

			// get qualified shipping rates
			$rates = $this->calcClass->calculate_shipping( $package );
			$rates = apply_filters( 'betrs_calculated_table_rate_options', $rates );
			
			// send shipping rates to WooCommerce
			if( is_array( $rates ) && count( $rates ) > 0 ) {
				// cycle through rates to send and alter post-add settings
				foreach( $rates as $key => $rate ) {
					// process meta data
					$meta_data = array();

					if( ! empty( $rate['description'] ) ) {
						$rate_description = array();
						$rate_description['scalar'] = apply_filters( 'betrs_shipping_rate_description', $rate['description'], $key, $this->instance_id, $rate['row_id'], $rate['contents_cost'] );
						$meta_data['description'] = (object) $rate_description;
					}

					$this->add_rate( array(
						'id'        => $rate['id'],
						'label'     => apply_filters( 'betrs_shipping_rate_label', $rate['label'], $key, $this->instance_id ),
						'cost'      => $rate['cost'],
						'meta_data' => apply_filters( 'betrs_shipping_rate_meta', $meta_data, $rate ),
						'package'   => $package,
						));

					if( $rate['default'] == 'on' )
						$this->default = $rate['id'];

				}

			}

		}


	    /**
	     * determine if current user qualifies for this method.
	     *
	     * @access public
	     * @param null
	     * @return bool
	     */
	    function user_restrictions_qualified() {

			switch( $this->user_limitation ) {
				case 'specific-roles':
					if( empty( $this->user_limit_roles ) || ! is_array( $this->user_limit_roles ) )
						return false;

					// retrieve user's roles if logged in
					if( is_user_logged_in() ) {
						$current_user = wp_get_current_user();
						$current_user_data = get_userdata( $current_user->ID );
						$current_user_roles = $current_user_data->roles;
					} else {
						$current_user_roles = array( "guest" );
					}

					// determine if user's role is accepted
					foreach( $this->user_limit_roles as $role ) {
						if( in_array( $role, $current_user_roles ) )
							return true;
					}
					break;

				case 'everyone':
					return true;
					break;
				default:
					return (bool) apply_filters( 'betrs_user_restrictions_condition', true, $this->user_limitation );
					break;
			}

			return false;
		}


	    /**
	     * assign permissions to users/roles selected.
	     *
	     * @access public
	     * @param array $instance_settings, array $method
	     * @return bool
	     */
	    function update_management_permissions( $instance_settings, $method ) {
	    	$post_data = $method->get_post_data();
	    	if( ! is_array( $post_data ) || empty( $post_data ) ) return $instance_settings;

	    	switch( sanitize_title( $post_data['woocommerce_betrs_shipping_user_modification'] ) ) {
	    		case 'specific-users':
	    			$selected_users = $post_data['woocommerce_betrs_shipping_user_modification_users'];
	    			if( is_array( $selected_users ) && ! empty( $selected_users ) ) {
		    			foreach( $selected_users as $user_id ) {
					    	$user = new WP_User( (int) $user_id );
							$user->add_cap( 'betrs_manage_shipping' );
		    			}
		    		}
	    			break;
	    		case 'specific-roles':
	    			$selected_roles = $post_data['woocommerce_betrs_shipping_user_modification_roles'];
	    			if( is_array( $selected_roles ) && ! empty( $selected_roles ) ) {
		    			foreach( $selected_roles as $role_id ) {
					    	$role = get_role( sanitize_title( $role_id ) );
							$role->add_cap( 'betrs_manage_shipping' );
		    			}
		    		}
	    			break;
	    		default:
	    			break;
	    	}

			return $instance_settings;
	    	
	    }


	    /**
	     * alter the default rate if one is chosen in settings.
	     *
	     * @access public
	     * @param mixed $package
	     * @return bool
	     */
	    function select_default_rate( $chosen_method, $_available_methods ) {

			//Select the 'Default' method from WooCommerce settings
			if( array_key_exists( $this->default, $_available_methods ) ) {

				return $this->default;
		    }

			return $chosen_method;
	    }


	    /**
		 * Hide shipping rates when free shipping is available.
		 * Updated to support WooCommerce 2.6 Shipping Zones.
		 *
	     * @access public
		 * @param array $rates Array of rates found for the package.
		 * @return array
		 */
		function hide_shipping_when_free_is_available( $rates ) {
			if( $this->hide_method !== 'yes' ) return $rates;

			// determine if free shipping is available
			$free_shipping = false;
			foreach ( $rates as $rate_id => $rate ) {
				if ( 'free_shipping' === $rate->method_id ) {
					$free_shipping = true;
					break;
				}
			}
			// if available, remove all options from this method
			if( $free_shipping ) {
				foreach ( $rates as $rate_id => $rate ) {
					if ( $this->id === $rate->method_id && strpos( $rate_id, $this->id . ':' . $this->instance_id . '-') !== false ) {
						unset( $rates[ $rate_id ] );
					}
				}
			}

			return $rates;
		}


	    /**
		 * Hide shipping rates when one has option enabled.
		 *
	     * @access public
		 * @param array $rates Array of rates found for the package.
		 * @return array
		 */
		function hide_other_options( $rates ) {
			$hide_key = false;

			// return if no rates have been added
			if( ! isset( $rates ) || empty( $rates ) )
				return $rates;

			// cycle through available rates
			foreach( $rates as $key => $rate ) {
				if( $rate['hide_ops'] === 'on' ) {
					$hide_key = $key;
				}
			}

			if( $hide_key ) {
				return array( $hide_key => $rates[ $hide_key ] );
			}

			return $rates;
		}


	    /**
		 * Return formatted price for remainder until free shipping is qualified
		 *
	     * @access public
		 * @param array $atts Array of shortcode parameters.
		 * @return string
		 */
		function shortcode_free_counter( $description, $key, $instance_id, $row_id, $contents_cost  ) {
			global $betrs_shipping;

			$remainder = 0;
			$qualifier = '{free-shipping@';

			// sanitize and convert currencies
			$contents_cost = floatval( $contents_cost );
			$description = wp_kses( $description, $betrs_shipping->allowedtags );

			// return if description does not contain shortcode
			if( ! strstr( $description, $qualifier ) )
				return $description;

			// determine the free shipping amount
			if( 0 < $contents_cost ) {
				$price_string = substr( $description, strpos( $description, $qualifier ) + strlen( $qualifier ) );
				$free_ship_price = floatval( substr( $price_string, 0, strpos( $price_string, '}' ) ) );
				$free_ship_price = floatval( apply_filters( 'betrs_condition_tertiary_subtotal', $free_ship_price ) );
			    $remainder = $free_ship_price - $contents_cost;

			}
	
		    // reformat description to include price
		    $description = preg_replace('#\\' . $qualifier . '[^\]]+\}#', wc_price( $remainder ), $description);

			return $description;
		}


	    /**
		 * Allow 3rd party to retrieve shipping calculations class
		 *
	     * @access protected
		 * @param void
		 * @return string
		 */
		public function get_class_calculate_shipping() {

			return $this->calcClass;
		}


	    /**
		 * Allow 3rd party to override the options key to allow managing of multiple sets of options (e.g. multi-currency support)
		 *
	     * @access protected
		 * @param void
		 * @return string
		 */
		public function get_options_save_name() {

			return apply_filters('betrs_instance_options_save_name', $this->options_save_name, $this);
		}


	    /**
		 * Allow 3rd party to override the options key to allow managing of multiple sets of options
		 *
	     * @access protected
		 * @param void
		 * @return string
		 */
		public function get_method_conditions_save_name() {

			return apply_filters('betrs_instance_method_conditions_save_name', $this->m_conds_save_name, $this);
		}

	}

}

?>