File "class-location-zones.php"

Full Path: /home/romayxjt/public_html/wp-content/plugins/orderable/inc/modules/location/zones/class-location-zones.php
File size: 7.36 KB
MIME-type: text/x-php
Charset: utf-8

<?php
/**
 * Module: Location (Zones).
 *
 * @since   1.18.0
 * @package Orderable/Classes
 */

defined( 'ABSPATH' ) || exit;

/**
 * Orderable_Location_Zones class.
 */
class Orderable_Location_Zones {
	/**
	 * Init.
	 */
	public static function run() {
		add_filter( 'woocommerce_package_rates', array( __CLASS__, 'modify_package_rates' ), 20, 2 );
		add_filter( 'woocommerce_no_shipping_available_html', array( __CLASS__, 'no_shipping_available_html' ) );
	}

	/**
	 * Modify the package rates for a matching zone.
	 *
	 * @param array $rates   Package rates.
	 * @param array $package Package of cart items.
	 * @return array
	 */
	public static function modify_package_rates( $rates, $package ) {
		$selected_location = Orderable_Location::get_selected_location();
		$zone_id           = self::get_zone_id_matching_package( $package );

		// Set shipping zone ID here so we can capture it later.
		WC()->session->set( 'orderable_chosen_zone_id', $zone_id );

		if ( ! $selected_location || ! $selected_location->has_services() ) {
			return $rates;
		}

		$pickup_rates   = array();
		$delivery_rates = array();

		foreach ( $rates as $rate_id => $rate ) {
			// If is a delivery rate.
			if ( false === strpos( $rate_id, 'pickup' ) ) {
				$delivery_rates[ $rate_id ] = $rate;

				if ( ! $selected_location->is_service_enabled( 'delivery' ) || ! $selected_location->has_service_dates( 'delivery' ) ) {
					unset( $rates[ $rate_id ] );
				}
			} else {
				$pickup_rates[ $rate_id ] = $rate;

				if ( ! $selected_location->is_service_enabled( 'pickup' ) || ! $selected_location->has_service_dates( 'pickup' ) ) {
					unset( $rates[ $rate_id ] );
				}
			}
		}

		// Add delivery rates if none exist. Use matched zone ID so time slot lookup is correct.
		// Don't add delivery method to "Locations not covered by your other zones" (Zone 0).
		if ( $zone_id > 0 && $selected_location->is_service_enabled( 'delivery' ) && $selected_location->has_service_dates( 'delivery' ) && empty( $delivery_rates ) ) {
			$zone_fee = 0;

			if ( $selected_location->has_zone( $zone_id ) ) {
				$zone     = new WC_Shipping_Zone( $zone_id );
				$zone_fee = floatval( $zone->get_meta( 'delivery_fee' ) );

				if ( 0 > $zone_fee ) {
					$zone_fee = 0;
				}
			}

			$rates[ 'orderable_delivery:' . $zone_id ] = new WC_Shipping_Rate(
				'orderable_delivery:' . $zone_id,
				__( 'Delivery', 'orderable' ),
				$zone_fee,
				array(),
				'orderable_delivery',
				$zone_id
			);
		}

		// Add pickup rates if none exist. Use matched zone ID so time slot lookup is correct.
		if ( $selected_location->is_service_enabled( 'pickup' ) && empty( $pickup_rates ) && $selected_location->has_service_dates( 'pickup' ) ) {
			$rates[ 'orderable_pickup:' . $zone_id ] = new WC_Shipping_Rate(
				'orderable_pickup:' . $zone_id,
				__( 'Pickup', 'orderable' ),
				0,
				array(),
				'orderable_pickup',
				$zone_id
			);
		}

		return $rates;
	}

	/**
	 * Get zone id which matches package.
	 *
	 * @param array $package Shipping package.
	 *
	 * @return int
	 */
	public static function get_zone_id_matching_package( $package ) {
		$zone = WC_Shipping_Zones::get_zone_matching_package( $package );

		return $zone ? $zone->get_id() : 0;
	}

	/**
	 * Get the method ID for a given instance ID.
	 *
	 * @param int $instance_id Instance ID.
	 * @return string|bool
	 */
	public static function get_method_id( $instance_id ) {
		global $wpdb;

		$result = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT
					method_id
				FROM
					{$wpdb->prefix}woocommerce_shipping_zone_methods
				WHERE
					instance_id = %d",
				$instance_id
			)
		);

		return empty( $result ) ? false : $result . ':' . $instance_id;
	}

	/**
	 * Get zones.
	 *
	 * @param int $time_slot_id Time slot ID.
	 * @return array
	 */
	public static function get_zones( $time_slot_id = null ) {
		$cache_key = 'orderable_zones';

		if ( $time_slot_id ) {
			$cache_key .= '_time_slot_' . $time_slot_id;
		}

		$matching_zones = wp_cache_get( $cache_key );

		if ( false !== $matching_zones ) {
			return $matching_zones;
		}

		$zones = WC_Shipping_Zones::get_zones();

		if ( empty( $zones ) ) {
			return array();
		}

		$matching_zones = array();

		foreach ( $zones as $key => $zone ) {
			$matching_zones[ $key ] = self::enrich_zone_data( $zone );
		}

		// If $time_slot_id is set, filter out zones that don't have the time slot.
		if ( $time_slot_id ) {
			foreach ( $matching_zones as $key => $matching_zone ) {
				if ( empty( $matching_zone['time_slots'] ) || ! in_array( $time_slot_id, $matching_zone['time_slots'], true ) ) {
					unset( $matching_zones[ $key ] );
				}
			}
		}

		wp_cache_set( $cache_key, $matching_zones );

		return $matching_zones;
	}

	/**
	 * Enrich zone data with locations and meta.
	 *
	 * @param array $zone Zone data.
	 * @return array
	 */
	public static function enrich_zone_data( $zone ) {
		$zone_instance = new WC_Shipping_Zone( $zone['zone_id'] );

		// Add locations to the zone.
		$locations      = array();
		$zone_locations = $zone_instance->get_zone_locations();

		if ( $zone_locations ) {
			foreach ( $zone_locations as $location ) {
				if ( 'postcode' === $location->type ) {
					$locations[] = $location->code;
				}
			}
		}

		$zone['zone_postcodes'] = join( ',', $locations );

		// Add fee data to the zone.
		$zone['zone_fee']   = floatval( $zone_instance->get_meta( 'delivery_fee' ) );
		$zone['time_slots'] = self::get_time_slots_for_zone( $zone['zone_id'] );

		return $zone;
	}

	/**
	 * Get time slots for a given zone.
	 *
	 * @param int $zone_id Zone ID.
	 *
	 * @return array
	 */
	public static function get_time_slots_for_zone( $zone_id ) {
		$cache_key  = 'orderable_time_slots_for_zone_' . $zone_id;
		$time_slots = wp_cache_get( $cache_key );

		if ( false !== $time_slots ) {
			return apply_filters( 'orderable_get_time_slots_for_zone', $time_slots, $zone_id );
		}

		global $wpdb;

		$zone_id = absint( $zone_id );

		$time_slots_lookup = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT
                time_slot_id
            FROM
                {$wpdb->prefix}orderable_location_delivery_zones_lookup
            WHERE
                zone_id = %d",
				$zone_id
			),
			ARRAY_A
		);

		if ( empty( $time_slots_lookup ) ) {
			$time_slots_lookup = array();
		}

		$time_slots = array_map( 'absint', wp_list_pluck( $time_slots_lookup, 'time_slot_id' ) );
		wp_cache_set( $cache_key, $time_slots );

		return apply_filters( 'orderable_get_time_slots_for_zone', $time_slots, $zone_id );
	}

	/**
	 * Get the selected shipping zone ID.
	 *
	 * If this function returns `0`, then the zone ID matched
	 * is the "Rest of the world" zone (created by WooCommerce)
	 *
	 * @return int|false
	 */
	public static function get_selected_shipping_zone_id() {
		return ! empty( WC()->session ) ? WC()->session->get( 'orderable_chosen_zone_id', false ) : false;
	}

	/**
	 * Shows when no shipping options are available.
	 *
	 * @param string $html Text string about no shipping options.
	 *
	 * @return string
	 */
	public static function no_shipping_available_html( $html ) {
		$location        = Orderable_Location::get_selected_location();
		$services        = $location->get_services();
		$services_string = implode( '/', $services );

		// Translators: %s is the service types (delivery/pickup).
		return sprintf( __( 'Sorry, there are no %s options available. Please ensure that your address has been entered correctly, or contact us if you need any help.', 'orderable' ), $services_string );
	}
}