357 lines
11 KiB
PHP
357 lines
11 KiB
PHP
<?php
|
|
|
|
/**
|
|
* Replaces saved package data with WooCommerce Shipping's if it is active.
|
|
*
|
|
* Redirects reads of and writes to wc_connect_options[packages] to wcshipping_options[packages].
|
|
*
|
|
* @since x.x.x
|
|
*/
|
|
class WC_Connect_Compatibility_WCShipping_Packages {
|
|
|
|
/**
|
|
* Number WCShipping uses to indicate data migration from WCS&T has completed.
|
|
*
|
|
* @var int
|
|
*/
|
|
const WCSHIP_DATA_MIGRATION_COMPLETED = 14;
|
|
|
|
/**
|
|
* Mapping of WCShipping keys => WCS&T keys.
|
|
*
|
|
* @var array
|
|
*/
|
|
const WCSHIPPING_TO_WCSERVICES_KEY_MAP = array(
|
|
'boxWeight' => 'box_weight',
|
|
'dimensions' => 'inner_dimensions',
|
|
'maxWeight' => 'max_weight',
|
|
);
|
|
|
|
/**
|
|
* Keys that are allowed in packages mapped to the WCS&T package data format.
|
|
*
|
|
* Other keys will be removed.
|
|
*
|
|
* @var array
|
|
*/
|
|
const KEYS_USED_BY_WCSERVICES = array(
|
|
'box_weight',
|
|
'inner_dimensions',
|
|
'is_letter',
|
|
'is_user_defined',
|
|
'max_weight',
|
|
'name',
|
|
);
|
|
|
|
/**
|
|
* Keys that are allowed in packages mapped to the WCShipping package data format.
|
|
*
|
|
* Other keys will be removed.
|
|
*
|
|
* @var array
|
|
*/
|
|
const KEYS_USED_BY_WCSHIPPING = array(
|
|
'boxWeight',
|
|
'dimensions',
|
|
'id',
|
|
'is_user_defined',
|
|
'maxWeight',
|
|
'name',
|
|
'type',
|
|
);
|
|
|
|
/**
|
|
* Registers all, some, or no hooks based on store configuration.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function maybe_enable() {
|
|
// Don't do anything if WooCommerce Shipping is not active.
|
|
if ( ! WC_Connect_Loader::is_wc_shipping_activated() ) {
|
|
return;
|
|
}
|
|
|
|
self::register_rest_controller_hooks();
|
|
|
|
$is_migration_to_wcshipping_completed = self::WCSHIP_DATA_MIGRATION_COMPLETED === (int) get_option( 'wcshipping_migration_state' );
|
|
if ( $is_migration_to_wcshipping_completed ) {
|
|
self::register_option_overwriting_hooks();
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Enqueue REST controller registration after WCS&T has finished initializing its other controllers.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function register_rest_controller_hooks() {
|
|
add_action( 'wcservices_rest_api_init', array( self::class, 'register_wcshipping_compatibility_rest_controller' ) );
|
|
}
|
|
|
|
/**
|
|
* Registers hooks intercepting reads/writes to "wc_connect_options".
|
|
*
|
|
* This is done to replace the keys "packages" and "predefined_packages" with values from WCShipping's options
|
|
* after doing some mapping.
|
|
*
|
|
* @return void
|
|
*/
|
|
public static function register_option_overwriting_hooks() {
|
|
// Intercept reads of "wc_connect_options[packages]" and "wc_connect_options[predefined_packages]".
|
|
add_filter( 'option_wc_connect_options', array( self::class, 'intercept_packages_read' ) );
|
|
add_filter( 'option_wc_connect_options', array( self::class, 'intercept_predefined_packages_read' ) );
|
|
|
|
// Intercept updates to "wc_connect_options[packages]" and "wc_connect_options[predefined_packages]".
|
|
add_action( 'pre_update_option_wc_connect_options', array( self::class, 'intercept_packages_update' ), 10, 2 );
|
|
add_action( 'pre_update_option_wc_connect_options', array( self::class, 'intercept_predefined_packages_update' ), 10, 2 );
|
|
}
|
|
|
|
/**
|
|
* Replaces `wc_connect_options[packages]` with mapped values from `wcshipping_options[packages]`.
|
|
*
|
|
* Leaves the rest of `wc_connect_options` intact.
|
|
*
|
|
* @param mixed $wc_connect_options "wc_connect_options" value from the WP options table.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function intercept_packages_read( $wc_connect_options ) {
|
|
$wcshipping_options = get_option( 'wcshipping_options' );
|
|
|
|
if ( is_array( $wcshipping_options ) && isset( $wcshipping_options['packages'] ) ) {
|
|
$wc_connect_options['packages'] = self::map_packages_to_wcservices_format( $wcshipping_options['packages'] );
|
|
}
|
|
|
|
return $wc_connect_options;
|
|
}
|
|
|
|
/**
|
|
* Replaces `wc_connect_options[predefined_packages]` with values from `wcshipping_options[predefined_packages]`.
|
|
*
|
|
* Leaves the rest of `wc_connect_options` intact.
|
|
*
|
|
* @param mixed $wc_connect_options "wc_connect_options" value from the WP options table.
|
|
*
|
|
* @return mixed
|
|
*/
|
|
public static function intercept_predefined_packages_read( $wc_connect_options ) {
|
|
$wcshipping_options = get_option( 'wcshipping_options' );
|
|
|
|
if ( is_array( $wcshipping_options ) && isset( $wcshipping_options['predefined_packages'] ) ) {
|
|
$wc_connect_options['predefined_packages'] = $wcshipping_options['predefined_packages'];
|
|
}
|
|
|
|
return $wc_connect_options;
|
|
}
|
|
|
|
/**
|
|
* Saves the mapped value of `wc_connect_options[packages]` to `wcshipping_options[packages]`.
|
|
*
|
|
* Reverts `wc_connect_options[packages]` to old value so that only the packages
|
|
* in `wcshipping_options` get updated.
|
|
*
|
|
* Leaves the rest of `wcshipping_options` intact.
|
|
*
|
|
* @param mixed $value New value for "wc_connect_options" to extract packages from.
|
|
* @param mixed $old_value Old value of "wc_connect_options".
|
|
*
|
|
* @return array `$value` with the `packages` field reverted to current DB value to prevent updating.
|
|
*/
|
|
public static function intercept_packages_update( $value, $old_value ) {
|
|
$wcshipping_options = get_option( 'wcshipping_options' );
|
|
|
|
if ( ! empty( $value['packages'] ) ) {
|
|
$wcshipping_options['packages'] = self::map_packages_to_wcshipping_format( $value['packages'] );
|
|
} else {
|
|
$wcshipping_options['packages'] = array();
|
|
}
|
|
|
|
update_option( 'wcshipping_options', $wcshipping_options );
|
|
|
|
/*
|
|
* Prevent update of WCS&T's packages so that only `wcshipping_options` get updated.
|
|
*/
|
|
$value['packages'] = $old_value['packages'];
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Saves the mapped value of `wc_connect_options[predefined_packages]` to `wcshipping_options[predefined_packages]`.
|
|
*
|
|
* Reverts `wc_connect_options[predefined_packages]` to old value so that only the predefined packages
|
|
* in `wcshipping_options` get updated.
|
|
*
|
|
* Leaves the rest of `wcshipping_options` intact.
|
|
*
|
|
* @param mixed $value New value for "wc_connect_options" to extract predefined packages from.
|
|
* @param mixed $old_value Old value of "wc_connect_options".
|
|
*
|
|
* @return array `$value` with the `predefined_packages` field reverted to current DB value to prevent updating.
|
|
*/
|
|
public static function intercept_predefined_packages_update( $value, $old_value ) {
|
|
$wcshipping_options = get_option( 'wcshipping_options' );
|
|
|
|
if ( ! empty( $value['predefined_packages'] ) ) {
|
|
$wcshipping_options['predefined_packages'] = $value['predefined_packages'];
|
|
} else {
|
|
$wcshipping_options['predefined_packages'] = array();
|
|
}
|
|
|
|
update_option( 'wcshipping_options', $wcshipping_options );
|
|
|
|
/*
|
|
* Prevent update of WCS&T's predefined packages so that only `wcshipping_options` get updated.
|
|
*/
|
|
$value['predefined_packages'] = $old_value['predefined_packages'];
|
|
|
|
return $value;
|
|
}
|
|
|
|
/**
|
|
* Register a REST controller that reads "wc_connect_options".
|
|
*
|
|
* We do this because if WCShipping is active, it registers its own controller under /wc/v1/connect/packages
|
|
* that accesses "wcshipping_options". For the purpose of the WCS&T settings page, we still want the page
|
|
* accessing `wc_connect_options` that we'll possibly overwrite with the option read/write-intercepting filters
|
|
* if migration of options from WCS&T to WCShipping has been completed.
|
|
*
|
|
* This is so that we can always modify the value of "wc_connect_options" but leave the value of
|
|
* "wcshipping_options" intact.
|
|
*
|
|
* If migration has been completed, the controller will overwrite the value of "wc_connect_options[packages]" with
|
|
* WCShipping's packages.
|
|
*
|
|
* If migration hasn't been completed, it will return the value of "wc_connect_options[packages]" with no changes.
|
|
*
|
|
* @see self::register_option_overwriting_hooks
|
|
*
|
|
* @param WC_Connect_Loader $loader WCS&T's main class.
|
|
*/
|
|
public static function register_wcshipping_compatibility_rest_controller( WC_Connect_Loader $loader ) {
|
|
require_once __DIR__ . '/class-wc-rest-connect-wcshipping-compatibility-packages-controller.php';
|
|
$rest_wcshipping_package_compatibility_controller = new WC_REST_Connect_WCShipping_Compatibility_Packages_Controller(
|
|
$loader->get_api_client(),
|
|
$loader->get_service_settings_store(),
|
|
$loader->get_logger(),
|
|
$loader->get_service_schemas_store()
|
|
);
|
|
$rest_wcshipping_package_compatibility_controller->register_routes();
|
|
}
|
|
|
|
/**
|
|
* Maps package data from WCShipping's to WCS&T's format.
|
|
*
|
|
* @param array $custom_packages The custom packages to map from WCShipping's to WCS&T's format.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function map_packages_to_wcservices_format( $custom_packages ) {
|
|
$old_custom_packages = $custom_packages;
|
|
|
|
foreach ( $custom_packages as &$package ) {
|
|
$package = self::rename_keys( $package, self::WCSHIPPING_TO_WCSERVICES_KEY_MAP );
|
|
$package = self::map_type_to_is_letter( $package );
|
|
$package = self::unset_unused_keys( $package, self::KEYS_USED_BY_WCSERVICES );
|
|
}
|
|
|
|
return apply_filters(
|
|
'wcservices_map_packages_to_wcservices_format',
|
|
$custom_packages,
|
|
$old_custom_packages
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Maps package data from WCS&T's to WCShipping's format.
|
|
*
|
|
* @param array $custom_packages The custom packages to map from WCS&T's to WCShipping's format.
|
|
*
|
|
* @return array
|
|
*/
|
|
public static function map_packages_to_wcshipping_format( $custom_packages ) {
|
|
$old_custom_packages = $custom_packages;
|
|
|
|
foreach ( $custom_packages as &$package ) {
|
|
$package = self::rename_keys( $package, array_flip( self::WCSHIPPING_TO_WCSERVICES_KEY_MAP ) );
|
|
$package = self::map_is_letter_to_type( $package );
|
|
$package = self::unset_unused_keys( $package, self::KEYS_USED_BY_WCSHIPPING );
|
|
}
|
|
|
|
return apply_filters(
|
|
'wcservices_map_packages_to_wcshipping_format',
|
|
$custom_packages,
|
|
$old_custom_packages
|
|
);
|
|
}
|
|
|
|
/**
|
|
* Renames keys according to provided key map then unsets the original keys.
|
|
*
|
|
* @param array $package Package data.
|
|
* @param array $key_map Mapping to follow.
|
|
*
|
|
* @return array
|
|
*/
|
|
private static function rename_keys( $package, $key_map ) {
|
|
foreach ( $key_map as $source => $target ) {
|
|
if ( isset( $package[ $source ] ) ) {
|
|
$package[ $target ] = $package[ $source ];
|
|
unset( $package[ $source ] );
|
|
}
|
|
}
|
|
|
|
return $package;
|
|
}
|
|
|
|
/**
|
|
* Unsets keys that aren't in `$allowed_keys`.
|
|
*
|
|
* @param array $package Package data.
|
|
* @param array $allowed_keys Keys that will be left in the array, if present. Other keys are unset.
|
|
*
|
|
* @return array
|
|
*/
|
|
private static function unset_unused_keys( $package, $allowed_keys ) {
|
|
return array_intersect_key( $package, array_flip( $allowed_keys ) );
|
|
}
|
|
|
|
/**
|
|
* Maps a package's "type" prop ("box"/"envelope") to "is_letter" (true/false).
|
|
*
|
|
* "type" is the format used by WCShipping.
|
|
* "is_letter" is the format used by WCS&T.
|
|
*
|
|
* @param array $package Package data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private static function map_type_to_is_letter( $package ) {
|
|
if ( isset( $package['type'] ) ) {
|
|
$package['is_letter'] = 'envelope' === $package['type'];
|
|
}
|
|
unset( $package['type'] );
|
|
|
|
return $package;
|
|
}
|
|
|
|
/**
|
|
* Maps a package's "is_letter" prop (true/false) to "type" ("box"/"envelope").
|
|
*
|
|
* "type" is the format used by WCShipping.
|
|
* "is_letter" is the format used by WCS&T.
|
|
*
|
|
* @param array $package Package data.
|
|
*
|
|
* @return array
|
|
*/
|
|
private static function map_is_letter_to_type( $package ) {
|
|
if ( isset( $package['is_letter'] ) ) {
|
|
$package['type'] = $package['is_letter'] ? 'envelope' : 'box';
|
|
}
|
|
unset( $package['is_letter'] );
|
|
|
|
return $package;
|
|
}
|
|
}
|