diff --git a/includes/hide.php b/includes/hide.php index 097ef69c..7b59b323 100644 --- a/includes/hide.php +++ b/includes/hide.php @@ -255,7 +255,7 @@ function fastwc_should_hide_cart_button_for_product( $should_hide ) { $fastwc_hidden_products = fastwc_get_products_to_hide_buttons(); $product_id = 0; - if ( ! empty( WC()->cart ) ) { + if ( ! empty( $fastwc_hidden_products ) && ! empty( WC()->cart ) ) { $cart = WC()->cart->get_cart(); foreach ( $cart as $cart_item ) { diff --git a/includes/routes.php b/includes/routes.php index 2c7a3db6..e83d023f 100644 --- a/includes/routes.php +++ b/includes/routes.php @@ -8,176 +8,86 @@ // Define the API route base path. define( 'FASTWC_ROUTES_BASE', 'wc/fast/v1' ); +// Load route base class. +require_once FASTWC_PATH . 'includes/routes/class-route.php'; // Provides an API for polling shipping options. -require_once FASTWC_PATH . 'includes/routes/shipping.php'; +require_once FASTWC_PATH . 'includes/routes/class-shipping.php'; // Provides an API that exposes shipping zones. -require_once FASTWC_PATH . 'includes/routes/shipping-zones.php'; +require_once FASTWC_PATH . 'includes/routes/class-shipping-zones.php'; // Provides an API that exposes plugin info. -require_once FASTWC_PATH . 'includes/routes/plugin-info.php'; +require_once FASTWC_PATH . 'includes/routes/class-plugin-info.php'; // Provides an API that exposes product attributes. -require_once FASTWC_PATH . 'includes/routes/product-attributes.php'; +require_once FASTWC_PATH . 'includes/routes/class-product-attributes.php'; // Provides an API that exposes orders with refunds. -require_once FASTWC_PATH . 'includes/routes/refunds.php'; +require_once FASTWC_PATH . 'includes/routes/class-refunds.php'; // Provides an API that exposes a list of disabled Fast webhooks. -require_once FASTWC_PATH . 'includes/routes/webhooks.php'; +require_once FASTWC_PATH . 'includes/routes/class-webhooks.php'; +// Provides an API that exposes a test authorization header. +require_once FASTWC_PATH . 'includes/routes/class-auth-test.php'; /** * Register Fast Woocommerce routes for the REST API. */ function fastwc_rest_api_init() { // Register a utility route to get information on installed plugins. - register_rest_route( - FASTWC_ROUTES_BASE . '/store', - 'plugins', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_get_plugin_info', - 'permission_callback' => 'fastwc_api_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/store/plugins' ); + new \FastWC\Routes\Plugin_Info(); // Register a route to collect all possible shipping locations. - register_rest_route( - FASTWC_ROUTES_BASE, - 'shipping_zones', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_get_zones', - 'permission_callback' => 'fastwc_api_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/shipping_zones' ); + new \FastWC\Routes\Shipping_Zones(); // Register a route to calculate available shipping rates. // FE -> OMS -> Blender -> (pID, variantID, Shipping info, CustomerID)Plugin. - register_rest_route( - FASTWC_ROUTES_BASE, - 'shipping', - array( - 'methods' => 'POST', - 'callback' => 'fastwc_calculate_shipping', - 'permission_callback' => 'fastwc_api_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/shipping' ); + new \FastWC\Routes\Shipping(); // Register a route to load product attributes. - register_rest_route( - FASTWC_ROUTES_BASE, - 'product/attributes', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_get_product_attributes', - 'permission_callback' => 'fastwc_api_managewc_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/product/attributes' ); + new \FastWC\Routes\Product_Attributes(); // Register a route to get all orders with refunds. - register_rest_route( - FASTWC_ROUTES_BASE, - 'refunds', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_get_orders_with_refunds', - 'permission_callback' => 'fastwc_api_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/refunds' ); + new \FastWC\Routes\Refunds(); // Register a route to get all disabled Fast webhooks. - register_rest_route( - FASTWC_ROUTES_BASE, - 'webhooks', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_route_get_disabled_webhooks', - 'permission_callback' => 'fastwc_api_permission_callback', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/webhooks' ); + new \FastWC\Routes\Webhooks(); // Register a route to test the Authorization header. - register_rest_route( - FASTWC_ROUTES_BASE, - 'authecho', - array( - 'methods' => 'GET', - 'callback' => 'fastwc_test_authorization_header', - 'permission_callback' => '__return_true', - ) - ); - - fastwc_log_info( 'Registered route: ' . FASTWC_ROUTES_BASE . '/authecho' ); + new \FastWC\Routes\Auth_Test(); } add_action( 'rest_api_init', 'fastwc_rest_api_init' ); /** - * REST API permissions callback. + * Abstract REST API permissions callback. + * + * @param string $capability Capability name to check. + * @param string $log_string Initial string for the permission check log. * * @return bool */ -function fastwc_api_permission_callback() { +function fastwc_api_general_permission_callback( $capability, $log_string ) { // Make sure an instance of WooCommerce is loaded. // This will load the `WC_REST_Authentication` class, which // handles the API consumer key and secret. WC(); - $has_permission = current_user_can( 'manage_options' ); + $has_permission = current_user_can( $capability ); - fastwc_log_info( 'API Permission Callback: ' . ( $has_permission ? 'granted' : 'denied' ) ); + fastwc_log_info( $log_string . ': ' . ( $has_permission ? 'granted' : 'denied' ) ); return $has_permission; } /** - * REST API permissions callback for product attributes + * REST API permissions callback. * * @return bool */ -function fastwc_api_managewc_permission_callback() { - // Make sure an instance of WooCommerce is loaded. - // This will load the `WC_REST_Authentication` class, which - // handles the API consumer key and secret. - WC(); - - $has_permission = current_user_can( 'manage_woocommerce' ); - - fastwc_log_info( 'API Product Attributes Permission Callback: ' . ( $has_permission ? 'granted' : 'denied' ) ); - - return $has_permission; +function fastwc_api_permission_callback() { + return fastwc_api_general_permission_callback( 'manage_options', 'API Manage Options Permission Callback' ); } /** - * Test the Authorization header. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. + * REST API permissions callback for product attributes. * - * @return array|WP_Error|WP_REST_Response + * @return bool */ -function fastwc_test_authorization_header( $request ) { - $auth_header = 'No Authorization Header'; - - $headers = $request->get_headers(); - - if ( ! empty( $headers['authorization'] ) ) { - $header_count = count( $headers['authorization'] ); - - if ( is_array( $headers['authorization'] ) && $header_count > 0 ) { - $auth_header = $headers['authorization'][0]; - } elseif ( is_string( $headers['authorization'] ) ) { - $auth_header = $headers['authorization']; - } - } - - fastwc_log_info( 'Authorization header endpoint called: ' . $auth_header ); - - return new WP_REST_Response( $auth_header, 200 ); +function fastwc_api_managewc_permission_callback() { + return fastwc_api_general_permission_callback( 'manage_woocommerce', 'API Manage WooCommerce Permission Callback' ); } diff --git a/includes/routes/class-auth-test.php b/includes/routes/class-auth-test.php new file mode 100644 index 00000000..3da06021 --- /dev/null +++ b/includes/routes/class-auth-test.php @@ -0,0 +1,59 @@ +request = $request; + + $auth_header = 'No Authorization Header'; + + $headers = $this->request->get_headers(); + + if ( ! empty( $headers['authorization'] ) ) { + $header_count = count( $headers['authorization'] ); + + if ( is_array( $headers['authorization'] ) && $header_count > 0 ) { + $auth_header = $headers['authorization'][0]; + } elseif ( is_string( $headers['authorization'] ) ) { + $auth_header = $headers['authorization']; + } + } + + \fastwc_log_info( 'Authorization header endpoint called: ' . $auth_header ); + + return new \WP_REST_Response( $auth_header, 200 ); + } +} diff --git a/includes/routes/class-plugin-info.php b/includes/routes/class-plugin-info.php new file mode 100644 index 00000000..1f24afeb --- /dev/null +++ b/includes/routes/class-plugin-info.php @@ -0,0 +1,79 @@ + $value ) { + $is_active = ( in_array( $key, $active_plugins, true ) ) ? true : false; + $plugins[] = array( + 'name' => $value['Name'], + 'version' => $value['Version'], + 'active' => $is_active, + ); + } + + return new \WP_REST_Response( $plugins, 200 ); + } +} diff --git a/includes/routes/class-product-attributes.php b/includes/routes/class-product-attributes.php new file mode 100644 index 00000000..ca81cd74 --- /dev/null +++ b/includes/routes/class-product-attributes.php @@ -0,0 +1,120 @@ +request = $request; + + $product_id = $this->request->get_param( 'productId' ); + $variant_id = $this->request->get_param( 'variantId' ); + $return = array(); + + if ( ! empty( $product_id ) ) { + $product = \wc_get_product( $product_id ); + } + + if ( ! empty( $product ) ) { + $return = $this->get_product_variant_attributes( $product, $variant_id ); + } + + return new \WP_REST_Response( $return, 200 ); + } + + /** + * Get the list of available attribute names for variants. + * + * @param WC_Product $product The product. + * @param int $variant_id The variant. + * + * @return array + */ + protected function get_product_variant_attributes( $product, $variant_id ) { + $return = array(); + + if ( $product->is_type( 'variable' ) && ! empty( $variant_id ) ) { + + $variations = $product->get_available_variations(); + if ( ! empty( $variations ) ) { + + // Get the variation attributes. + foreach ( $variations as $variation ) { + if ( (int) $variant_id === (int) $variation['variation_id'] ) { + $return['attKeys'] = array_keys( $variation['attributes'] ); + $return['values'] = $variation['attributes']; + break; + } + } + + // Get attribute labels. + $attribue_labels = array(); + $attributes = $product->get_attributes(); + foreach ( $attributes as $key => $attribute ) { + $att_key = $this->standardize_attribute_key( $key ); + $attribute_labels[ $att_key ] = \wc_attribute_label( $attribute->get_name(), $product ); + } + $return['labels'] = $attribute_labels; + + $variation_attributes = $product->get_variation_attributes(); + $attribute_options = array(); + foreach ( $variation_attributes as $key => $options ) { + $att_key = $this->standardize_attribute_key( $key ); + $attribute_options[ $att_key ] = array(); + foreach ( $options as $option ) { + $attribute_options[ $att_key ][] = array( + 'label' => $option, + 'value' => $option, + ); + } + } + $return['options'] = $attribute_options; + } + } + + return $return; + } + + /** + * Standardize the attribute key. + * + * @param string $att_key Non-normalized key. + * + * @return array + */ + protected function standardize_attribute_key( $att_key ) { + return 'attribute_' . sanitize_title( $att_key ); + } + +} diff --git a/includes/routes/class-refunds.php b/includes/routes/class-refunds.php new file mode 100644 index 00000000..d70f9632 --- /dev/null +++ b/includes/routes/class-refunds.php @@ -0,0 +1,272 @@ +request = $request; + + $refund_type = $this->get_refund_type(); + + if ( 'full' === $refund_type ) { + $orders = $this->get_orders_with_full_refunds(); + } else { + $orders = $this->get_all_orders_with_refunds( $refund_type ); + } + + return new WP_REST_Response( $orders ); + } + + /** + * Get the requested refund type. + * + * @return string + */ + protected function get_refund_type() { + $refund_types = array( 'partial', 'full', 'all' ); + $refund_type = 'all'; + + if ( + ! empty( $this->request['refund_type'] ) && + in_array( $this->request['refund_type'], $refund_types, true ) + ) { + $refund_type = $this->request['refund_type']; + } + + return $refund_type; + } + + /** + * Get orders with full refunds. + * + * @param bool $get_ids Flag to fetch IDs. + * + * @return array + */ + protected function get_orders_with_full_refunds( $get_ids = false ) { + $args = $this->get_orders_query_args( $get_ids ); + $orders = \wc_get_orders( $args ); + + // Convert objects to their data. + if ( ! empty( $orders ) && false === $get_ids ) { + $orders_data = array(); + + foreach ( $orders as $order ) { + $orders_data[] = $order->get_data(); + } + + $orders = $orders_data; + } + + return $orders; + } + + /** + * Get the query args for orders with full refunds. + * + * @param bool $get_ids Flag to fetch IDs. + * + * @return array + */ + protected function get_orders_query_args( $get_ids = fasle ) { + // Set the default query args. + $args = array( + 'limit' => isset( $this->request['per_page'] ) ? $this->request['per_page'] : -1, + 'order' => isset( $this->request['order'] ) ? $this->request['order'] : 'DESC', + 'orderby' => isset( $this->request['orderby'] ) ? $this->request['orderby'] : 'date', + 'paged' => isset( $this->request['page'] ) ? $this->request['page'] : '', + 'exclude' => isset( $this->request['exclude'] ) ? $this->request['exclude'] : array(), + 'paginate' => isset( $this->request['paginate'] ) ? $this->request['paginate'] : false, + ); + + if ( isset( $this->request['date'] ) ) { + $args['date_created'] = $this->request['date']; + } elseif ( isset( $this->request['after'] ) ) { + $args['date_created'] = '>' . strtotime( $this->request['after'] ); + } elseif ( isset( $this->request['before'] ) ) { + $args['date_created'] = '<' . strtotime( $this->request['before'] ); + } + + $args['return'] = $get_ids ? 'ids' : 'objects'; + $args['status'] = array( 'wc-refunded' ); + + if ( 'id' === $args['orderby'] ) { + $args['orderby'] = 'ID'; // ID must be capitalized. + } + + return $args; + } + + /** + * Get all orders with refunds. + * + * @param string $refund_type Flag to get partial, full, or all refunds. + * + * @return array + */ + protected function get_all_orders_with_refunds( $refund_type ) { + $refunds = $this->get_refunds(); + $orders = $this->parse_refunds( $refunds, $refund_type ); + + return $orders; + } + + /** + * Get the query args to use for fetching refunds. + * + * @return array + */ + protected function get_refunds_query_args() { + // Set the default query args. + $query_args = array( + 'fields' => 'id=>parent', + 'post_type' => 'shop_order_refund', + 'post_status' => 'any', + 'posts_per_page' => isset( $this->request['per_page'] ) ? $this->request['per_page'] : -1, + 'order' => isset( $this->request['order'] ) ? $this->request['order'] : '', + 'orderby' => isset( $this->request['orderby'] ) ? $this->request['orderby'] : '', + 'paged' => isset( $this->request['page'] ) ? $this->request['page'] : '', + 'post_parent__in' => isset( $this->request['include'] ) ? $this->request['include'] : '', + 'post_parent__not_in' => isset( $this->request['exclude'] ) ? $this->request['exclude'] : '', + 'date_query' => array(), + ); + + // For partial refunds, exclude full refunded orders from the list. + $refund_type = $this->get_refund_type(); + if ( 'partial' === $refund_type ) { + // Get ID's of orders with full refunds. + $full_refund_orders = $this->get_orders_with_full_refunds( true ); + + if ( ! empty( $full_refund_orders ) ) { + if ( empty( $query_args['post_parent__not_in'] ) ) { + $query_args['post_parent__not_in'] = $full_refund_orders; + } else { + $query_args['post_parent__not_in'] = array_merge( + $query_args['post_parent__not_in'], + $full_refund_orders + ); + } + } + } + + if ( 'date' === $query_args['orderby'] ) { + $query_args['orderby'] = 'date ID'; + } + + // Set before into date query. Date query must be specified as an array of an array. + if ( isset( $this->request['before'] ) ) { + $query_args['date_query'][0]['before'] = $this->request['before']; + } + + // Set after into date query. Date query must be specified as an array of an array. + if ( isset( $this->request['after'] ) ) { + $query_args['date_query'][0]['after'] = $this->request['after']; + } + + if ( 'include' === $query_args['orderby'] ) { + $query_args['orderby'] = 'post__in'; + } elseif ( 'id' === $query_args['orderby'] ) { + $query_args['orderby'] = 'ID'; // ID must be capitalized. + } elseif ( 'slug' === $query_args['orderby'] ) { + $query_args['orderby'] = 'name'; + } + + return $query_args; + } + + /** + * Get the list of refunds. + * + * @return WP_Query + */ + protected function get_refunds() { + $query_args = $this->get_refunds_query_args(); + + \add_filter( 'posts_distinct', array( $this, 'refunds_distinct' ) ); + \add_filter( 'posts_fields', array( $this, 'refunds_fields' ) ); + + $refunds = new \WP_Query( $query_args ); + + \remove_filter( 'posts_distinct', array( $this, 'refunds_distinct' ) ); + \remove_filter( 'posts_fields', array( $this, 'refunds_fields' ) ); + + return $refunds; + } + + /** + * Parse the list of refunds and return a list of orders. + * + * @param WP_Query $refunds The list of refunds. + * @param string $refund_type Flag to get partial, full, or all refunds. + * + * @return array + */ + protected function parse_refunds( $refunds, $refund_type ) { + $orders = array(); + + if ( ! empty( $refunds->posts ) ) { + foreach ( $refunds->posts as $refund ) { + $order = \wc_get_order( $refund->post_parent ); + + if ( ! empty( $order ) ) { + $status = $order->get_status(); + + if ( + ( 'wc-refunded' !== $status && 'partial' === $refund_type ) || + 'all' === $refund_type + ) { + $orders[] = $order->get_data(); + } + } + } + } + + return $orders; + } + + /** + * Make sure to return distinct values on the refunds. + * + * @return string + */ + public function refunds_distinct() { + return 'DISTINCT'; + } + + /** + * Swap the order of the fields in the query. + * + * @param string $fields The fields string from the query. + * + * @return string + */ + public function refunds_fields( $fields ) { + $fields_arr = array_reverse( explode( ', ', $fields ) ); + + return $fields_arr[0]; + } +} diff --git a/includes/routes/class-route.php b/includes/routes/class-route.php new file mode 100644 index 00000000..12372ef9 --- /dev/null +++ b/includes/routes/class-route.php @@ -0,0 +1,97 @@ +init(); + $this->register(); + } + + /** + * Initialize the route arguments. + */ + protected function init() { + if ( empty( $this->callback ) ) { + $this->callback = array( $this, 'callback' ); + } + } + + /** + * Register the route. + */ + protected function register() { + register_rest_route( + $this->namespace, + $this->route, + array( + 'methods' => $this->methods, + 'callback' => $this->callback, + 'permission_callback' => $this->permission_callback, + ) + ); + + \fastwc_log_info( 'Registered route: ' . $this->namespace . $this->route ); + } + + /** + * Route callback function. + * + * @param WP_REST_Request $request JSON request for shipping endpoint. + */ + abstract public function callback( $request ); +} diff --git a/includes/routes/class-shipping-zones.php b/includes/routes/class-shipping-zones.php new file mode 100644 index 00000000..93c2e95a --- /dev/null +++ b/includes/routes/class-shipping-zones.php @@ -0,0 +1,100 @@ +get_zone_locations(); + + $loc_arr = array_merge( + $loc_arr, + $this->parse_locations( $locations, $loc_arr ) + ); + } + + return new \WP_REST_Response( $loc_arr, 200 ); + } + + /** + * Parse locations. + * + * @param array $locations List of locations to parse. + * @param array $loc_arr Location array. + * + * @return array + */ + protected function parse_locations( $locations, $loc_arr ) { + $new_loc_arr = array(); + + foreach ( $locations as $location ) { + if ( 'country' !== $location->type && 'state' !== $location->type ) { + continue; + } + + // Do not insert item with same code. + if ( ! $this->loc_arr_has_location( $loc_arr, $location ) ) { + $new_loc_arr[] = array( + 'code' => $location->code, + 'type' => $location->type, + ); + } + } + + return $new_loc_arr; + } + + /** + * Check loc_arr if location already exists. + * + * @param array $loc_arr Array of locations. + * @param stdClass $location Location to check. + * + * @return bool + */ + protected function loc_arr_has_location( $loc_arr, $location ) { + foreach ( $loc_arr as $li ) { + if ( + ! empty( $li->code ) && + ! empty( $location->code ) && + $li->code === $location->code + ) { + return true; + } + } + + return false; + } +} diff --git a/includes/routes/class-shipping.php b/includes/routes/class-shipping.php new file mode 100644 index 00000000..541632ab --- /dev/null +++ b/includes/routes/class-shipping.php @@ -0,0 +1,388 @@ + 1 address. + * + * @param WP_REST_Request $request JSON request for shipping endpoint. + * + * @return array|WP_Error|WP_REST_Response + * + * @throws Exception If failed to add items to cart or no shipping options available for address. + */ + public function callback( $request ) { + $this->request = $request; + + $params = $this->request->get_params(); + $return = false; + + // This is needed for session to work. + \WC()->frontend_includes(); + + $this->init_wc_session(); + $this->init_wc_customer(); + $this->init_wc_cart(); + $return = $this->add_line_items_to_cart( $params ); + + if ( false === $return ) { + $return = $this->update_customer_information( $params ); + } + + if ( false === $return ) { + $return = $this->calculate_packages(); + } + + // Cleanup cart. + \WC()->cart->empty_cart(); + + return $return; + } + + /** + * Initialize the WC session. + */ + protected function init_wc_session() { + if ( null === \WC()->session ) { + $session_class = \apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' ); + \WC()->session = new $session_class(); + \WC()->session->init(); + } + } + + /** + * Initialize the WC customer. + */ + protected function init_wc_customer() { + if ( null === \WC()->customer ) { + \WC()->customer = new \WC_Customer( get_current_user_id(), false ); + } + } + + /** + * Initialize the WC cart. + */ + protected function init_wc_cart() { + if ( null === \WC()->cart ) { + \WC()->cart = new \WC_Cart(); + // We need to force a refresh of the cart contents + // from session here (cart contents are normally + // refreshed on wp_loaded, which has already happened + // by this point). + \WC()->cart->get_cart(); + + // This cart may contain items from prev session empty before using. + \WC()->cart->empty_cart(); + } + } + + /** + * Add line items to cart. + * + * @param array $params The request params. + * + * @return mixed + */ + protected function add_line_items_to_cart( $params ) { + // Add body line items to cart. + foreach ( $params['line_items'] as $line_item ) { + $variation_id = ! empty( $line_item['variation_id'] ) ? $line_item['variation_id'] : 0; + + $variation_attribute_values = array(); + + // For now hardcode to grab first object as we shouldnt need more. + if ( ! empty( $line_item['variation_attribute_values'] ) ) { + // If there are attributes use it when adding item to cart which are required to get shipping options back. + $variation_attribute_values = $line_item['variation_attribute_values']; + } + + try { + \WC()->cart->add_to_cart( $line_item['product_id'], $line_item['quantity'], $variation_id, $variation_attribute_values ); + } catch ( \Exception $e ) { + return \WP_Error( 'add_to_cart_error', $e->getMessage(), array( 'status' => 500 ) ); + } + } + + // Return false to indicate no error. + return false; + } + + /** + * Update customer information. + * + * @param array $params The request params. + * + * @return mixed + */ + protected function update_customer_information( $params ) { + $customer_props = array( + 'shipping_country' => $params['shipping']['country'], + 'shipping_state' => $params['shipping']['state'], + 'shipping_postcode' => $params['shipping']['postcode'], + 'shipping_city' => $params['shipping']['city'], + 'shipping_address_1' => $params['shipping']['address_1'], + 'shipping_address_2' => $params['shipping']['address_2'], + ); + + // Add billing address info if it is part of the request. + if ( ! empty( $params['billing'] ) && is_array( $params['billing'] ) ) { + $customer_props = wp_parse_args( + $params['billing'], + $customer_props + ); + } + + // Update customer information. + \WC()->customer->set_props( $customer_props ); + + // Save what we added. + \WC()->customer->save(); + + // Calculate shipping. + \WC()->cart->calculate_shipping(); + \WC()->cart->calculate_totals(); + + // See if we need to calculate anything. + if ( ! \WC()->cart->needs_shipping() ) { + return new \WP_Error( 'shipping_methods_error', 'no shipping methods available for product and address', array( 'status' => 400 ) ); + } + + // Return false for no error. + return false; + } + + /** + * Calculate packages + * + * @return mixed + */ + protected function calculate_packages() { + // Get packages for the cart. + $packages = \WC()->cart->get_shipping_packages(); + + // Currently we only support 1 shipping address per package. + if ( count( $packages ) > 1 ) { + // Perform address check to make sure all are the same. + $count_packages = count( $packages ); + for ( $x = 1; $x < $count_packages; $x++ ) { + if ( $packages[0]->destination !== $packages[ $x ]->destination ) { + return new \WP_Error( 'shipping_packages', 'Shipping package to > 1 address is not supported', array( 'status' => 400 ) ); + } + } + } + + // Add package ID to array. + foreach ( $packages as $key => $package ) { + if ( ! isset( $packages[ $key ]['package_id'] ) ) { + $packages[ $key ]['package_id'] = $key; + } + } + $calculated_packages = \WC()->shipping()->calculate_shipping( $packages ); + + $resp = $this->get_item_response( $calculated_packages ); + + return new \WP_REST_Response( $resp, 200 ); + } + + /** + * Build JSON response for line item. + * + * @param array $package WooCommerce shipping packages. + * + * @return array + */ + protected function get_item_response( $package ) { + // Add product names and quantities. + $items = array(); + foreach ( $package[0]['contents'] as $item_id => $values ) { + $items[] = array( + 'key' => $item_id, + 'name' => $values['data']->get_name(), + 'quantity' => $values['quantity'], + 'product_id' => $values['product_id'], + 'variation_id' => $values['variation_id'], + 'line_subtotal' => $values['line_subtotal'], + 'line_subtotal_tax' => $values['line_subtotal_tax'], + 'line_total' => $values['line_total'], + 'line_tax' => $values['line_tax'], + ); + } + + return array( + 'package_id' => $package[0]['package_id'], + 'destination' => + array( + 'address_1' => $package[0]['destination']['address_1'], + 'address_2' => $package[0]['destination']['address_2'], + 'city' => $package[0]['destination']['city'], + 'state' => $package[0]['destination']['state'], + 'postcode' => $package[0]['destination']['postcode'], + 'country' => $package[0]['destination']['country'], + ), + 'items' => $items, + 'shipping_rates' => $this->prepare_rates_response( $package ), + ); + } + + /** + * Prepare an array of rates from a package for the response. + * + * @param array $package Shipping package complete with rates from WooCommerce. + * + * @return array + */ + protected function prepare_rates_response( $package ) { + $rates = $package [0]['rates']; + + $response = array(); + + foreach ( $rates as $rate ) { + $response[] = $this->get_rate_response( $rate ); + } + + return $response; + } + + + /** + * Response for a single rate. + * + * @param WC_Shipping_Rate $rate Rate object. + * + * @return array + */ + protected function get_rate_response( $rate ) { + $rate_info = array( + 'rate_id' => $this->get_rate_prop( $rate, 'id' ), + 'name' => $this->prepare_html_response( $this->get_rate_prop( $rate, 'label' ) ), + 'description' => $this->prepare_html_response( $this->get_rate_prop( $rate, 'description' ) ), + 'delivery_time' => $this->prepare_html_response( $this->get_rate_prop( $rate, 'delivery_time' ) ), + 'price' => $this->get_rate_prop( $rate, 'cost' ), + 'taxes' => $this->get_rate_prop( $rate, 'taxes' ), + 'instance_id' => $this->get_rate_prop( $rate, 'instance_id' ), + 'method_id' => $this->get_rate_prop( $rate, 'method_id' ), + 'meta_data' => $this->get_rate_meta_data( $rate ), + ); + + return array_merge( + $rate_info, + $this->get_store_currency_response() + ); + } + + /** + * Prepares a list of store currency data to return in responses. + * + * @return array + */ + protected function get_store_currency_response() { + $position = \get_option( 'woocommerce_currency_pos' ); + $symbol = html_entity_decode( \get_woocommerce_currency_symbol( $currency ) ); + $prefix = ''; + $suffix = ''; + + switch ( $position ) { + case 'left_space': + $prefix = $symbol . ' '; + break; + case 'left': + $prefix = $symbol; + break; + case 'right_space': + $suffix = ' ' . $symbol; + break; + case 'right': + $suffix = $symbol; + break; + default: + break; + } + + return array( + 'currency_code' => \get_woocommerce_currency(), + 'currency_symbol' => $symbol, + 'currency_minor_unit' => \wc_get_price_decimals(), + 'currency_decimal_separator' => \wc_get_price_decimal_separator(), + 'currency_thousand_separator' => \wc_get_price_thousand_separator(), + 'currency_prefix' => $prefix, + 'currency_suffix' => $suffix, + ); + } + + + /** + * Gets a prop of the rate object, if callable. + * + * @param WC_Shipping_Rate $rate Rate object. + * @param string $prop Prop name. + * @return string + */ + protected function get_rate_prop( $rate, $prop ) { + $getter = 'get_' . $prop; + return \is_callable( array( $rate, $getter ) ) ? $rate->$getter() : ''; + } + + /** + * Converts rate meta data into a suitable response object. + * + * @param WC_Shipping_Rate $rate Rate object. + * @return array + */ + protected function get_rate_meta_data( $rate ) { + $meta_data = $rate->get_meta_data(); + + return array_reduce( + array_keys( $meta_data ), + function( $return, $key ) use ( $meta_data ) { + $return[] = array( + 'key' => $key, + 'value' => $meta_data[ $key ], + ); + return $return; + }, + array() + ); + } + + /** + * Prepares HTML based content, such as post titles and content, for the API response. + * + * The wptexturize, convert_chars, and trim functions are also used in the `the_title` filter. + * The function wp_kses_post removes disallowed HTML tags. + * + * @param string|array $response Data to format. + * + * @return string|array Formatted data. + */ + protected function prepare_html_response( $response ) { + if ( is_array( $response ) ) { + return array_map( 'fastwc_prepare_html_response', $response ); + } + return is_scalar( $response ) ? \wp_kses_post( trim( \convert_chars( \wptexturize( $response ) ) ) ) : $response; + } +} diff --git a/includes/routes/class-webhooks.php b/includes/routes/class-webhooks.php new file mode 100644 index 00000000..9ce1f71d --- /dev/null +++ b/includes/routes/class-webhooks.php @@ -0,0 +1,44 @@ +get_data(); + } + } + + return new \WP_REST_Response( $webhooks, 200 ); + } +} diff --git a/includes/routes/plugin-info.php b/includes/routes/plugin-info.php deleted file mode 100644 index c67e8e2f..00000000 --- a/includes/routes/plugin-info.php +++ /dev/null @@ -1,56 +0,0 @@ - $value ) { - $is_active = ( in_array( $key, $active_plugins, true ) ) ? true : false; - $plugins[] = array( - 'name' => $value['Name'], - 'version' => $value['Version'], - 'active' => $is_active, - ); - } - - return new WP_REST_Response( $plugins, 200 ); -} diff --git a/includes/routes/product-attributes.php b/includes/routes/product-attributes.php deleted file mode 100644 index 29a57847..00000000 --- a/includes/routes/product-attributes.php +++ /dev/null @@ -1,95 +0,0 @@ -get_param( 'productId' ); - $variant_id = $request->get_param( 'variantId' ); - $return = array(); - - if ( ! empty( $product_id ) ) { - $product = wc_get_product( $product_id ); - } - - if ( ! empty( $product ) ) { - $return = fastwc_get_product_variant_attributes( $product, $variant_id ); - } - - return new WP_REST_Response( $return, 200 ); -} - -/** - * Get the list of available attribute names for variants. - * - * @param WC_Product $product The product. - * @param int $variant_id The variant. - * - * @return array - */ -function fastwc_get_product_variant_attributes( $product, $variant_id ) { - $return = array(); - - if ( $product->is_type( 'variable' ) && ! empty( $variant_id ) ) { - - $variations = $product->get_available_variations(); - if ( ! empty( $variations ) ) { - - // Get the variation attributes. - foreach ( $variations as $variation ) { - if ( (int) $variant_id === (int) $variation['variation_id'] ) { - $return['attKeys'] = array_keys( $variation['attributes'] ); - $return['values'] = $variation['attributes']; - break; - } - } - - // Get attribute labels. - $attribue_labels = array(); - $attributes = $product->get_attributes(); - foreach ( $attributes as $key => $attribute ) { - $att_key = fastwc_standardize_attribute_key( $key ); - $attribute_labels[ $att_key ] = wc_attribute_label( $attribute->get_name(), $product ); - } - $return['labels'] = $attribute_labels; - - $variation_attributes = $product->get_variation_attributes(); - $attribute_options = array(); - foreach ( $variation_attributes as $key => $options ) { - $att_key = fastwc_standardize_attribute_key( $key ); - $attribute_options[ $att_key ] = array(); - foreach ( $options as $option ) { - $attribute_options[ $att_key ][] = array( - 'label' => $option, - 'value' => $option, - ); - } - } - $return['options'] = $attribute_options; - } - } - - return $return; -} - -/** - * Standardize the attribute key. - * - * @param string $att_key Non-normalized key. - * - * @return array - */ -function fastwc_standardize_attribute_key( $att_key ) { - return 'attribute_' . sanitize_title( $att_key ); -} diff --git a/includes/routes/refunds.php b/includes/routes/refunds.php deleted file mode 100644 index 43e4c41b..00000000 --- a/includes/routes/refunds.php +++ /dev/null @@ -1,264 +0,0 @@ -get_data(); - } - - $orders = $orders_data; - } - - return $orders; -} - -/** - * Get the query args for orders with full refunds. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. - * @param bool $get_ids Flag to fetch IDs. - * - * @return array - */ -function fastwc_get_orders_query_args( $request, $get_ids = fasle ) { - // Set the default query args. - $args = array( - 'limit' => isset( $request['per_page'] ) ? $request['per_page'] : -1, - 'order' => isset( $request['order'] ) ? $request['order'] : 'DESC', - 'orderby' => isset( $request['orderby'] ) ? $request['orderby'] : 'date', - 'paged' => isset( $request['page'] ) ? $request['page'] : '', - 'exclude' => isset( $request['exclude'] ) ? $request['exclude'] : array(), - 'paginate' => isset( $request['paginate'] ) ? $request['paginate'] : false, - ); - - if ( isset( $request['date'] ) ) { - $args['date_created'] = $request['date']; - } elseif ( isset( $request['after'] ) ) { - $args['date_created'] = '>' . strtotime( $request['after'] ); - } elseif ( isset( $request['before'] ) ) { - $args['date_created'] = '<' . strtotime( $request['before'] ); - } - - $args['return'] = $get_ids ? 'ids' : 'objects'; - $args['status'] = array( 'wc-refunded' ); - - if ( 'id' === $args['orderby'] ) { - $args['orderby'] = 'ID'; // ID must be capitalized. - } - - return $args; -} - -/** - * Get all orders with refunds. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. - * @param string $refund_type Flag to get partial, full, or all refunds. - * - * @return array - */ -function fastwc_get_all_orders_with_refunds( $request, $refund_type ) { - $refunds = fastwc_get_refunds( $request ); - $orders = fastwc_parse_refunds( $refunds, $refund_type ); - - return $orders; -} - -/** - * Get the query args to use for fetching refunds. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. - * - * @return array - */ -function fastwc_get_refunds_query_args( $request ) { - // Set the default query args. - $query_args = array( - 'fields' => 'id=>parent', - 'post_type' => 'shop_order_refund', - 'post_status' => 'any', - 'posts_per_page' => isset( $request['per_page'] ) ? $request['per_page'] : -1, - 'order' => isset( $request['order'] ) ? $request['order'] : '', - 'orderby' => isset( $request['orderby'] ) ? $request['orderby'] : '', - 'paged' => isset( $request['page'] ) ? $request['page'] : '', - 'post_parent__in' => isset( $request['include'] ) ? $request['include'] : '', - 'post_parent__not_in' => isset( $request['exclude'] ) ? $request['exclude'] : '', - 'date_query' => array(), - ); - - // For partial refunds, exclude full refunded orders from the list. - $refund_type = fastwc_get_refund_type( $request ); - if ( 'partial' === $refund_type ) { - // Get ID's of orders with full refunds. - $full_refund_orders = fastwc_get_orders_with_full_refunds( $request, true ); - - if ( ! empty( $full_refund_orders ) ) { - if ( empty( $query_args['post_parent__not_in'] ) ) { - $query_args['post_parent__not_in'] = $full_refund_orders; - } else { - $query_args['post_parent__not_in'] = array_merge( - $query_args['post_parent__not_in'], - $full_refund_orders - ); - } - } - } - - if ( 'date' === $query_args['orderby'] ) { - $query_args['orderby'] = 'date ID'; - } - - // Set before into date query. Date query must be specified as an array of an array. - if ( isset( $request['before'] ) ) { - $query_args['date_query'][0]['before'] = $request['before']; - } - - // Set after into date query. Date query must be specified as an array of an array. - if ( isset( $request['after'] ) ) { - $query_args['date_query'][0]['after'] = $request['after']; - } - - if ( 'include' === $query_args['orderby'] ) { - $query_args['orderby'] = 'post__in'; - } elseif ( 'id' === $query_args['orderby'] ) { - $query_args['orderby'] = 'ID'; // ID must be capitalized. - } elseif ( 'slug' === $query_args['orderby'] ) { - $query_args['orderby'] = 'name'; - } - - return $query_args; -} - -/** - * Get the list of refunds. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. - * - * @return WP_Query - */ -function fastwc_get_refunds( $request ) { - $query_args = fastwc_get_refunds_query_args( $request ); - - add_filter( 'posts_distinct', 'fastwc_refunds_distinct' ); - add_filter( 'posts_fields', 'fastwc_refunds_fields' ); - - $refunds = new WP_Query( $query_args ); - - remove_filter( 'posts_distinct', 'fastwc_refunds_distinct' ); - remove_filter( 'posts_fields', 'fastwc_refunds_fields' ); - - return $refunds; -} - -/** - * Parse the list of refunds and return a list of orders. - * - * @param WP_Query $refunds The list of refunds. - * @param string $refund_type Flag to get partial, full, or all refunds. - * - * @return array - */ -function fastwc_parse_refunds( $refunds, $refund_type ) { - $orders = array(); - - if ( ! empty( $refunds->posts ) ) { - foreach ( $refunds->posts as $refund ) { - $order = wc_get_order( $refund->post_parent ); - - if ( ! empty( $order ) ) { - $status = $order->get_status(); - - if ( - ( 'wc-refunded' !== $status && 'partial' === $refund_type ) || - 'all' === $refund_type - ) { - $orders[] = $order->get_data(); - } - } - } - } - - return $orders; -} - -/** - * Make sure to return distinct values on the refunds. - * - * @return string - */ -function fastwc_refunds_distinct() { - return 'DISTINCT'; -} - -/** - * Swap the order of the fields in the query. - * - * @param string $fields The fields string from the query. - * - * @return string - */ -function fastwc_refunds_fields( $fields ) { - $fields_arr = array_reverse( explode( ', ', $fields ) ); - - return $fields_arr[0]; -} diff --git a/includes/routes/shipping-zones.php b/includes/routes/shipping-zones.php deleted file mode 100644 index 6cc66957..00000000 --- a/includes/routes/shipping-zones.php +++ /dev/null @@ -1,79 +0,0 @@ -get_zone_locations(); - - $loc_arr = array_merge( - $loc_arr, - fastwc_parse_locations( $locations, $loc_arr ) - ); - } - - return new WP_REST_Response( $loc_arr, 200 ); -} - -/** - * Parse locations. - * - * @param array $locations List of locations to parse. - * @param array $loc_arr Location array. - * - * @return array - */ -function fastwc_parse_locations( $locations, $loc_arr ) { - $new_loc_arr = array(); - - foreach ( $locations as $location ) { - if ( 'country' !== $location->type && 'state' !== $location->type ) { - continue; - } - - // Do not insert item with same code. - if ( ! fastwc_loc_arr_has_location( $loc_arr, $location ) ) { - $new_loc_arr[] = array( - 'code' => $location->code, - 'type' => $location->type, - ); - } - } - - return $new_loc_arr; -} - -/** - * Check loc_arr if location already exists. - * - * @param array $loc_arr Array of locations. - * @param stdClass $location Location to check. - * - * @return bool - */ -function fastwc_loc_arr_has_location( $loc_arr, $location ) { - foreach ( $loc_arr as $li ) { - if ( $li->code === $location->code ) { - return true; - } - } - - return false; -} diff --git a/includes/routes/shipping.php b/includes/routes/shipping.php deleted file mode 100644 index c0723ba4..00000000 --- a/includes/routes/shipping.php +++ /dev/null @@ -1,365 +0,0 @@ - 1 address. - * - * @param WP_REST_Request $request JSON request for shipping endpoint. - * @return array|WP_Error|WP_REST_Response - * @throws Exception If failed to add items to cart or no shipping options available for address. - */ -function fastwc_calculate_shipping( WP_REST_Request $request ) { - $params = $request->get_params(); - $return = false; - - // This is needed for session to work. - wc()->frontend_includes(); - - fastwc_shipping_init_wc_session(); - fastwc_shipping_init_wc_customer(); - fastwc_shipping_init_wc_cart(); - $return = fastwc_shipping_add_line_items_to_cart( $params ); - - if ( false === $return ) { - $return = fastwc_shipping_update_customer_information( $params ); - } - - if ( false === $return ) { - $return = fastwc_shipping_calculate_packages(); - } - - // Cleanup cart. - WC()->cart->empty_cart(); - - return $return; -} - -/** - * Initialize the WC session. - */ -function fastwc_shipping_init_wc_session() { - if ( null === WC()->session ) { - $session_class = apply_filters( 'woocommerce_session_handler', 'WC_Session_Handler' ); - WC()->session = new $session_class(); - WC()->session->init(); - } -} - -/** - * Initialize the WC customer. - */ -function fastwc_shipping_init_wc_customer() { - if ( null === WC()->customer ) { - WC()->customer = new WC_Customer( get_current_user_id(), false ); - } -} - -/** - * Initialize the WC cart. - */ -function fastwc_shipping_init_wc_cart() { - if ( null === WC()->cart ) { - WC()->cart = new WC_Cart(); - // We need to force a refresh of the cart contents - // from session here (cart contents are normally - // refreshed on wp_loaded, which has already happened - // by this point). - WC()->cart->get_cart(); - - // This cart may contain items from prev session empty before using - WC()->cart->empty_cart(); - } -} - -/** - * Add line items to cart. - * - * @param array $params The request params. - * - * @return mixed - */ -function fastwc_shipping_add_line_items_to_cart( $params ) { - // Add body line items to cart. - foreach ( $params['line_items'] as $line_item ) { - $variation_id = ! empty( $line_item['variation_id'] ) ? $line_item['variation_id'] : 0; - - $variation_attribute_values = array(); - - // For now hardcode to grab first object as we shouldnt need more. - if ( ! empty( $line_item['variation_attribute_values'] ) ) { - // If there are attributes use it when adding item to cart which are required to get shipping options back. - $variation_attribute_values = $line_item['variation_attribute_values']; - } - - try { - WC()->cart->add_to_cart( $line_item['product_id'], $line_item['quantity'], $variation_id, $variation_attribute_values ); - } catch ( \Exception $e ) { - return WP_Error( 'add_to_cart_error', $e->getMessage(), array( 'status' => 500 ) ); - } - } - - // Return false to indicate no error. - return false; -} - -/** - * Update customer information. - * - * @param array $params The request params. - * - * @return mixed - */ -function fastwc_shipping_update_customer_information( $params ) { - // Update customer information. - wc()->customer->set_props( - array( - 'shipping_country' => $params['shipping']['country'], - 'shipping_state' => $params['shipping']['state'], - 'shipping_postcode' => $params['shipping']['postcode'], - 'shipping_city' => $params['shipping']['city'], - 'shipping_address_1' => $params['shipping']['address_1'], - 'shipping_address_2' => $params['shipping']['address_2'], - ) - ); - // Save what we added. - WC()->customer->save(); - - // Calculate shipping. - WC()->cart->calculate_shipping(); - WC()->cart->calculate_totals(); - - // See if we need to calculate anything. - if ( ! WC()->cart->needs_shipping() ) { - return new WP_Error( 'shipping_methods_error', 'no shipping methods available for product and address', array( 'status' => 400 ) ); - } - - // Return false for no error. - return false; -} - -/** - * Calculate packages - * - * @return mixed - */ -function fastwc_shipping_calculate_packages() { - // Get packages for the cart. - $packages = WC()->cart->get_shipping_packages(); - - // Currently we only support 1 shipping address per package. - if ( count( $packages ) > 1 ) { - // Perform address check to make sure all are the same - for ( $x = 1; $x < count( $packages ); $x++ ) { - if ( $packages[0]->destination !== $packages[ $x ]->destination ) { - return new WP_Error( 'shipping_packages', 'Shipping package to > 1 address is not supported', array( 'status' => 400 ) ); - } - } - } - - // Add package ID to array. - foreach ( $packages as $key => $package ) { - if ( ! isset( $packages[ $key ]['package_id'] ) ) { - $packages[ $key ]['package_id'] = $key; - } - } - $calculated_packages = wc()->shipping()->calculate_shipping( $packages ); - - $resp = fastwc_get_item_response( $calculated_packages ); - - return new WP_REST_Response( $resp, 200 ); -} - -/** - * Build JSON response for line item. - * - * @param array $package WooCommerce shipping packages. - * @return array - */ -function fastwc_get_item_response( $package ) { - // Add product names and quantities. - $items = array(); - foreach ( $package[0]['contents'] as $item_id => $values ) { - $items[] = array( - 'key' => $item_id, - 'name' => $values['data']->get_name(), - 'quantity' => $values['quantity'], - 'product_id' => $values['product_id'], - 'variation_id' => $values['variation_id'], - 'line_subtotal' => $values['line_subtotal'], - 'line_subtotal_tax' => $values['line_subtotal_tax'], - 'line_total' => $values['line_total'], - 'line_tax' => $values['line_tax'], - ); - } - - return array( - 'package_id' => $package[0]['package_id'], - 'destination' => - array( - 'address_1' => $package[0]['destination']['address_1'], - 'address_2' => $package[0]['destination']['address_2'], - 'city' => $package[0]['destination']['city'], - 'state' => $package[0]['destination']['state'], - 'postcode' => $package[0]['destination']['postcode'], - 'country' => $package[0]['destination']['country'], - ), - 'items' => $items, - 'shipping_rates' => fastwc_prepare_rates_response( $package ), - ); -} - -/** - * Prepare an array of rates from a package for the response. - * - * @param array $package Shipping package complete with rates from WooCommerce. - * @return array - */ -function fastwc_prepare_rates_response( $package ) { - $rates = $package [0]['rates']; - - $response = array(); - - foreach ( $rates as $rate ) { - $response[] = fastwc_get_rate_response( $rate ); - } - - return $response; -} - - -/** - * Response for a single rate. - * - * @param WC_Shipping_Rate $rate Rate object. - * @return array - */ -function fastwc_get_rate_response( $rate ) { - return array_merge( - array( - 'rate_id' => fastwc_get_rate_prop( $rate, 'id' ), - 'name' => fastwc_prepare_html_response( fastwc_get_rate_prop( $rate, 'label' ) ), - 'description' => fastwc_prepare_html_response( fastwc_get_rate_prop( $rate, 'description' ) ), - 'delivery_time' => fastwc_prepare_html_response( fastwc_get_rate_prop( $rate, 'delivery_time' ) ), - 'price' => fastwc_get_rate_prop( $rate, 'cost' ), - 'taxes' => fastwc_get_rate_prop( $rate, 'taxes' ), - 'instance_id' => fastwc_get_rate_prop( $rate, 'instance_id' ), - 'method_id' => fastwc_get_rate_prop( $rate, 'method_id' ), - 'meta_data' => fastwc_get_rate_meta_data( $rate ), - ), - fastwc_get_store_currency_response() - ); -} - -/** - * Prepares a list of store currency data to return in responses. - * - * @return array - */ -function fastwc_get_store_currency_response() { - $position = get_option( 'woocommerce_currency_pos' ); - $symbol = html_entity_decode( get_woocommerce_currency_symbol() ); - $prefix = ''; - $suffix = ''; - - switch ( $position ) { - case 'left_space': - $prefix = $symbol . ' '; - break; - case 'left': - $prefix = $symbol; - break; - case 'right_space': - $suffix = ' ' . $symbol; - break; - case 'right': - $suffix = $symbol; - break; - default: - break; - } - - return array( - 'currency_code' => get_woocommerce_currency(), - 'currency_symbol' => $symbol, - 'currency_minor_unit' => wc_get_price_decimals(), - 'currency_decimal_separator' => wc_get_price_decimal_separator(), - 'currency_thousand_separator' => wc_get_price_thousand_separator(), - 'currency_prefix' => $prefix, - 'currency_suffix' => $suffix, - ); -} - - -/** - * Gets a prop of the rate object, if callable. - * - * @param WC_Shipping_Rate $rate Rate object. - * @param string $prop Prop name. - * @return string - */ -function fastwc_get_rate_prop( $rate, $prop ) { - $getter = 'get_' . $prop; - return \is_callable( array( $rate, $getter ) ) ? $rate->$getter() : ''; -} - -/** - * Converts rate meta data into a suitable response object. - * - * @param WC_Shipping_Rate $rate Rate object. - * @return array - */ -function fastwc_get_rate_meta_data( $rate ) { - $meta_data = $rate->get_meta_data(); - - return array_reduce( - array_keys( $meta_data ), - function( $return, $key ) use ( $meta_data ) { - $return[] = array( - 'key' => $key, - 'value' => $meta_data[ $key ], - ); - return $return; - }, - array() - ); -} - -/** - * Prepares HTML based content, such as post titles and content, for the API response. - * - * The wptexturize, convert_chars, and trim functions are also used in the `the_title` filter. - * The function wp_kses_post removes disallowed HTML tags. - * - * @param string|array $response Data to format. - * @return string|array Formatted data. - */ -function fastwc_prepare_html_response( $response ) { - if ( is_array( $response ) ) { - return array_map( 'fastwc_prepare_html_response', $response ); - } - return is_scalar( $response ) ? wp_kses_post( trim( convert_chars( wptexturize( $response ) ) ) ) : $response; -} - -/** - * Convert monetary values from WooCommerce to string based integers, using - * the smallest unit of a currency. - * - * @param string|float $amount Monetary amount with decimals. - * @param int $decimals Number of decimals the amount is formatted with. - * @param int $rounding_mode Defaults to the PHP_ROUND_HALF_UP constant. - * @return string The new amount. - */ -function prepare_money_response( $amount, $decimals = 2, $rounding_mode = PHP_ROUND_HALF_UP ) { - return (string) intval( - round( - ( (float) wc_format_decimal( $amount ) ) * ( 10 ** $decimals ), - 0, - absint( $rounding_mode ) - ) - ); -} diff --git a/includes/routes/webhooks.php b/includes/routes/webhooks.php deleted file mode 100644 index e85865f6..00000000 --- a/includes/routes/webhooks.php +++ /dev/null @@ -1,24 +0,0 @@ -get_data(); - } - } - - return new WP_REST_Response( $webhooks, 200 ); -}