Passed
Push — main ( aaef5c...e4c121 )
by TARIQ
71:39
created
packages/woocommerce-blocks/src/StoreApi/Utilities/Pagination.php 2 patches
Indentation   +55 added lines, -55 removed lines patch added patch discarded remove patch
@@ -6,66 +6,66 @@
 block discarded – undo
6 6
  */
7 7
 class Pagination {
8 8
 
9
-	/**
10
-	 * Add pagination headers to a response object.
11
-	 *
12
-	 * @param \WP_REST_Response $response Reference to the response object.
13
-	 * @param \WP_REST_Request  $request The request object.
14
-	 * @param int               $total_items Total items found.
15
-	 * @param int               $total_pages Total pages found.
16
-	 * @return \WP_REST_Response
17
-	 */
18
-	public function add_headers( $response, $request, $total_items, $total_pages ) {
19
-		$response->header( 'X-WP-Total', $total_items );
20
-		$response->header( 'X-WP-TotalPages', $total_pages );
9
+    /**
10
+     * Add pagination headers to a response object.
11
+     *
12
+     * @param \WP_REST_Response $response Reference to the response object.
13
+     * @param \WP_REST_Request  $request The request object.
14
+     * @param int               $total_items Total items found.
15
+     * @param int               $total_pages Total pages found.
16
+     * @return \WP_REST_Response
17
+     */
18
+    public function add_headers( $response, $request, $total_items, $total_pages ) {
19
+        $response->header( 'X-WP-Total', $total_items );
20
+        $response->header( 'X-WP-TotalPages', $total_pages );
21 21
 
22
-		$current_page = $this->get_current_page( $request );
23
-		$link_base    = $this->get_link_base( $request );
22
+        $current_page = $this->get_current_page( $request );
23
+        $link_base    = $this->get_link_base( $request );
24 24
 
25
-		if ( $current_page > 1 ) {
26
-			$previous_page = $current_page - 1;
27
-			if ( $previous_page > $total_pages ) {
28
-				$previous_page = $total_pages;
29
-			}
30
-			$this->add_page_link( $response, 'prev', $previous_page, $link_base );
31
-		}
25
+        if ( $current_page > 1 ) {
26
+            $previous_page = $current_page - 1;
27
+            if ( $previous_page > $total_pages ) {
28
+                $previous_page = $total_pages;
29
+            }
30
+            $this->add_page_link( $response, 'prev', $previous_page, $link_base );
31
+        }
32 32
 
33
-		if ( $total_pages > $current_page ) {
34
-			$this->add_page_link( $response, 'next', ( $current_page + 1 ), $link_base );
35
-		}
33
+        if ( $total_pages > $current_page ) {
34
+            $this->add_page_link( $response, 'next', ( $current_page + 1 ), $link_base );
35
+        }
36 36
 
37
-		return $response;
38
-	}
37
+        return $response;
38
+    }
39 39
 
40
-	/**
41
-	 * Get current page.
42
-	 *
43
-	 * @param \WP_REST_Request $request The request object.
44
-	 * @return int Get the page from the request object.
45
-	 */
46
-	protected function get_current_page( $request ) {
47
-		return (int) $request->get_param( 'page' );
48
-	}
40
+    /**
41
+     * Get current page.
42
+     *
43
+     * @param \WP_REST_Request $request The request object.
44
+     * @return int Get the page from the request object.
45
+     */
46
+    protected function get_current_page( $request ) {
47
+        return (int) $request->get_param( 'page' );
48
+    }
49 49
 
50
-	/**
51
-	 * Get base for links from the request object.
52
-	 *
53
-	 * @param \WP_REST_Request $request The request object.
54
-	 * @return string
55
-	 */
56
-	protected function get_link_base( $request ) {
57
-		return add_query_arg( $request->get_query_params(), rest_url( $request->get_route() ) );
58
-	}
50
+    /**
51
+     * Get base for links from the request object.
52
+     *
53
+     * @param \WP_REST_Request $request The request object.
54
+     * @return string
55
+     */
56
+    protected function get_link_base( $request ) {
57
+        return add_query_arg( $request->get_query_params(), rest_url( $request->get_route() ) );
58
+    }
59 59
 
60
-	/**
61
-	 * Add a page link.
62
-	 *
63
-	 * @param \WP_REST_Response $response Reference to the response object.
64
-	 * @param string            $name Page link name. e.g. prev.
65
-	 * @param int               $page Page number.
66
-	 * @param string            $link_base Base URL.
67
-	 */
68
-	protected function add_page_link( &$response, $name, $page, $link_base ) {
69
-		$response->link_header( $name, add_query_arg( 'page', $page, $link_base ) );
70
-	}
60
+    /**
61
+     * Add a page link.
62
+     *
63
+     * @param \WP_REST_Response $response Reference to the response object.
64
+     * @param string            $name Page link name. e.g. prev.
65
+     * @param int               $page Page number.
66
+     * @param string            $link_base Base URL.
67
+     */
68
+    protected function add_page_link( &$response, $name, $page, $link_base ) {
69
+        $response->link_header( $name, add_query_arg( 'page', $page, $link_base ) );
70
+    }
71 71
 }
Please login to merge, or discard this patch.
Spacing   +16 added lines, -16 removed lines patch added patch discarded remove patch
@@ -15,23 +15,23 @@  discard block
 block discarded – undo
15 15
 	 * @param int               $total_pages Total pages found.
16 16
 	 * @return \WP_REST_Response
17 17
 	 */
18
-	public function add_headers( $response, $request, $total_items, $total_pages ) {
19
-		$response->header( 'X-WP-Total', $total_items );
20
-		$response->header( 'X-WP-TotalPages', $total_pages );
18
+	public function add_headers($response, $request, $total_items, $total_pages) {
19
+		$response->header('X-WP-Total', $total_items);
20
+		$response->header('X-WP-TotalPages', $total_pages);
21 21
 
22
-		$current_page = $this->get_current_page( $request );
23
-		$link_base    = $this->get_link_base( $request );
22
+		$current_page = $this->get_current_page($request);
23
+		$link_base    = $this->get_link_base($request);
24 24
 
25
-		if ( $current_page > 1 ) {
25
+		if ($current_page > 1) {
26 26
 			$previous_page = $current_page - 1;
27
-			if ( $previous_page > $total_pages ) {
27
+			if ($previous_page > $total_pages) {
28 28
 				$previous_page = $total_pages;
29 29
 			}
30
-			$this->add_page_link( $response, 'prev', $previous_page, $link_base );
30
+			$this->add_page_link($response, 'prev', $previous_page, $link_base);
31 31
 		}
32 32
 
33
-		if ( $total_pages > $current_page ) {
34
-			$this->add_page_link( $response, 'next', ( $current_page + 1 ), $link_base );
33
+		if ($total_pages > $current_page) {
34
+			$this->add_page_link($response, 'next', ($current_page + 1), $link_base);
35 35
 		}
36 36
 
37 37
 		return $response;
@@ -43,8 +43,8 @@  discard block
 block discarded – undo
43 43
 	 * @param \WP_REST_Request $request The request object.
44 44
 	 * @return int Get the page from the request object.
45 45
 	 */
46
-	protected function get_current_page( $request ) {
47
-		return (int) $request->get_param( 'page' );
46
+	protected function get_current_page($request) {
47
+		return (int) $request->get_param('page');
48 48
 	}
49 49
 
50 50
 	/**
@@ -53,8 +53,8 @@  discard block
 block discarded – undo
53 53
 	 * @param \WP_REST_Request $request The request object.
54 54
 	 * @return string
55 55
 	 */
56
-	protected function get_link_base( $request ) {
57
-		return add_query_arg( $request->get_query_params(), rest_url( $request->get_route() ) );
56
+	protected function get_link_base($request) {
57
+		return add_query_arg($request->get_query_params(), rest_url($request->get_route()));
58 58
 	}
59 59
 
60 60
 	/**
@@ -65,7 +65,7 @@  discard block
 block discarded – undo
65 65
 	 * @param int               $page Page number.
66 66
 	 * @param string            $link_base Base URL.
67 67
 	 */
68
-	protected function add_page_link( &$response, $name, $page, $link_base ) {
69
-		$response->link_header( $name, add_query_arg( 'page', $page, $link_base ) );
68
+	protected function add_page_link(&$response, $name, $page, $link_base) {
69
+		$response->link_header($name, add_query_arg('page', $page, $link_base));
70 70
 	}
71 71
 }
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/NoticeHandler.php 2 patches
Indentation   +50 added lines, -50 removed lines patch added patch discarded remove patch
@@ -10,63 +10,63 @@
 block discarded – undo
10 10
  */
11 11
 class NoticeHandler {
12 12
 
13
-	/**
14
-	 * Convert queued error notices into an exception.
15
-	 *
16
-	 * For example, Payment methods may add error notices during validate_fields call to prevent checkout.
17
-	 * Since we're not rendering notices at all, we need to convert them to exceptions.
18
-	 *
19
-	 * This method will find the first error message and thrown an exception instead. Discards notices once complete.
20
-	 *
21
-	 * @throws RouteException If an error notice is detected, Exception is thrown.
22
-	 *
23
-	 * @param string $error_code Error code for the thrown exceptions.
24
-	 */
25
-	public static function convert_notices_to_exceptions( $error_code = 'unknown_server_error' ) {
26
-		if ( 0 === wc_notice_count( 'error' ) ) {
27
-			wc_clear_notices();
28
-			return;
29
-		}
13
+    /**
14
+     * Convert queued error notices into an exception.
15
+     *
16
+     * For example, Payment methods may add error notices during validate_fields call to prevent checkout.
17
+     * Since we're not rendering notices at all, we need to convert them to exceptions.
18
+     *
19
+     * This method will find the first error message and thrown an exception instead. Discards notices once complete.
20
+     *
21
+     * @throws RouteException If an error notice is detected, Exception is thrown.
22
+     *
23
+     * @param string $error_code Error code for the thrown exceptions.
24
+     */
25
+    public static function convert_notices_to_exceptions( $error_code = 'unknown_server_error' ) {
26
+        if ( 0 === wc_notice_count( 'error' ) ) {
27
+            wc_clear_notices();
28
+            return;
29
+        }
30 30
 
31
-		$error_notices = wc_get_notices( 'error' );
31
+        $error_notices = wc_get_notices( 'error' );
32 32
 
33
-		// Prevent notices from being output later on.
34
-		wc_clear_notices();
33
+        // Prevent notices from being output later on.
34
+        wc_clear_notices();
35 35
 
36
-		foreach ( $error_notices as $error_notice ) {
37
-			throw new RouteException( $error_code, wp_strip_all_tags( $error_notice['notice'] ), 400 );
38
-		}
39
-	}
36
+        foreach ( $error_notices as $error_notice ) {
37
+            throw new RouteException( $error_code, wp_strip_all_tags( $error_notice['notice'] ), 400 );
38
+        }
39
+    }
40 40
 
41
-	/**
42
-	 * Collects queued error notices into a \WP_Error.
43
-	 *
44
-	 * For example, cart validation processes may add error notices to prevent checkout.
45
-	 * Since we're not rendering notices at all, we need to catch them and group them in a single WP_Error instance.
46
-	 *
47
-	 * This method will discard notices once complete.
48
-	 *
49
-	 * @param string $error_code Error code for the thrown exceptions.
50
-	 *
51
-	 * @return \WP_Error The WP_Error object containing all error notices.
52
-	 */
53
-	public static function convert_notices_to_wp_errors( $error_code = 'unknown_server_error' ) {
54
-		$errors = new WP_Error();
41
+    /**
42
+     * Collects queued error notices into a \WP_Error.
43
+     *
44
+     * For example, cart validation processes may add error notices to prevent checkout.
45
+     * Since we're not rendering notices at all, we need to catch them and group them in a single WP_Error instance.
46
+     *
47
+     * This method will discard notices once complete.
48
+     *
49
+     * @param string $error_code Error code for the thrown exceptions.
50
+     *
51
+     * @return \WP_Error The WP_Error object containing all error notices.
52
+     */
53
+    public static function convert_notices_to_wp_errors( $error_code = 'unknown_server_error' ) {
54
+        $errors = new WP_Error();
55 55
 
56
-		if ( 0 === wc_notice_count( 'error' ) ) {
57
-			wc_clear_notices();
58
-			return $errors;
59
-		}
56
+        if ( 0 === wc_notice_count( 'error' ) ) {
57
+            wc_clear_notices();
58
+            return $errors;
59
+        }
60 60
 
61
-		$error_notices = wc_get_notices( 'error' );
61
+        $error_notices = wc_get_notices( 'error' );
62 62
 
63
-		// Prevent notices from being output later on.
64
-		wc_clear_notices();
63
+        // Prevent notices from being output later on.
64
+        wc_clear_notices();
65 65
 
66
-		foreach ( $error_notices as $error_notice ) {
67
-			$errors->add( $error_code, wp_strip_all_tags( $error_notice['notice'] ) );
68
-		}
66
+        foreach ( $error_notices as $error_notice ) {
67
+            $errors->add( $error_code, wp_strip_all_tags( $error_notice['notice'] ) );
68
+        }
69 69
 
70
-		return $errors;
71
-	}
70
+        return $errors;
71
+    }
72 72
 }
Please login to merge, or discard this patch.
Spacing   +10 added lines, -10 removed lines patch added patch discarded remove patch
@@ -22,19 +22,19 @@  discard block
 block discarded – undo
22 22
 	 *
23 23
 	 * @param string $error_code Error code for the thrown exceptions.
24 24
 	 */
25
-	public static function convert_notices_to_exceptions( $error_code = 'unknown_server_error' ) {
26
-		if ( 0 === wc_notice_count( 'error' ) ) {
25
+	public static function convert_notices_to_exceptions($error_code = 'unknown_server_error') {
26
+		if (0 === wc_notice_count('error')) {
27 27
 			wc_clear_notices();
28 28
 			return;
29 29
 		}
30 30
 
31
-		$error_notices = wc_get_notices( 'error' );
31
+		$error_notices = wc_get_notices('error');
32 32
 
33 33
 		// Prevent notices from being output later on.
34 34
 		wc_clear_notices();
35 35
 
36
-		foreach ( $error_notices as $error_notice ) {
37
-			throw new RouteException( $error_code, wp_strip_all_tags( $error_notice['notice'] ), 400 );
36
+		foreach ($error_notices as $error_notice) {
37
+			throw new RouteException($error_code, wp_strip_all_tags($error_notice['notice']), 400);
38 38
 		}
39 39
 	}
40 40
 
@@ -50,21 +50,21 @@  discard block
 block discarded – undo
50 50
 	 *
51 51
 	 * @return \WP_Error The WP_Error object containing all error notices.
52 52
 	 */
53
-	public static function convert_notices_to_wp_errors( $error_code = 'unknown_server_error' ) {
53
+	public static function convert_notices_to_wp_errors($error_code = 'unknown_server_error') {
54 54
 		$errors = new WP_Error();
55 55
 
56
-		if ( 0 === wc_notice_count( 'error' ) ) {
56
+		if (0 === wc_notice_count('error')) {
57 57
 			wc_clear_notices();
58 58
 			return $errors;
59 59
 		}
60 60
 
61
-		$error_notices = wc_get_notices( 'error' );
61
+		$error_notices = wc_get_notices('error');
62 62
 
63 63
 		// Prevent notices from being output later on.
64 64
 		wc_clear_notices();
65 65
 
66
-		foreach ( $error_notices as $error_notice ) {
67
-			$errors->add( $error_code, wp_strip_all_tags( $error_notice['notice'] ) );
66
+		foreach ($error_notices as $error_notice) {
67
+			$errors->add($error_code, wp_strip_all_tags($error_notice['notice']));
68 68
 		}
69 69
 
70 70
 		return $errors;
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/ProductQueryFilters.php 2 patches
Indentation   +165 added lines, -165 removed lines patch added patch discarded remove patch
@@ -7,100 +7,100 @@  discard block
 block discarded – undo
7 7
  * Product Query filters class.
8 8
  */
9 9
 class ProductQueryFilters {
10
-	/**
11
-	 * Get filtered min price for current products.
12
-	 *
13
-	 * @param \WP_REST_Request $request The request object.
14
-	 * @return object
15
-	 */
16
-	public function get_filtered_price( $request ) {
17
-		global $wpdb;
18
-
19
-		// Regenerate the products query without min/max price request params.
20
-		unset( $request['min_price'], $request['max_price'] );
21
-
22
-		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
23
-		$product_query = new ProductQuery();
24
-
25
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
26
-		add_filter( 'posts_pre_query', '__return_empty_array' );
27
-
28
-		$query_args                   = $product_query->prepare_objects_query( $request );
29
-		$query_args['no_found_rows']  = true;
30
-		$query_args['posts_per_page'] = -1;
31
-		$query                        = new \WP_Query();
32
-		$result                       = $query->query( $query_args );
33
-		$product_query_sql            = $query->request;
34
-
35
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
36
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
37
-
38
-		$price_filter_sql = "
10
+    /**
11
+     * Get filtered min price for current products.
12
+     *
13
+     * @param \WP_REST_Request $request The request object.
14
+     * @return object
15
+     */
16
+    public function get_filtered_price( $request ) {
17
+        global $wpdb;
18
+
19
+        // Regenerate the products query without min/max price request params.
20
+        unset( $request['min_price'], $request['max_price'] );
21
+
22
+        // Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
23
+        $product_query = new ProductQuery();
24
+
25
+        add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
26
+        add_filter( 'posts_pre_query', '__return_empty_array' );
27
+
28
+        $query_args                   = $product_query->prepare_objects_query( $request );
29
+        $query_args['no_found_rows']  = true;
30
+        $query_args['posts_per_page'] = -1;
31
+        $query                        = new \WP_Query();
32
+        $result                       = $query->query( $query_args );
33
+        $product_query_sql            = $query->request;
34
+
35
+        remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
36
+        remove_filter( 'posts_pre_query', '__return_empty_array' );
37
+
38
+        $price_filter_sql = "
39 39
 			SELECT min( min_price ) as min_price, MAX( max_price ) as max_price
40 40
 			FROM {$wpdb->wc_product_meta_lookup}
41 41
 			WHERE product_id IN ( {$product_query_sql} )
42 42
 		";
43 43
 
44
-		return $wpdb->get_row( $price_filter_sql ); // phpcs:ignore
45
-	}
46
-
47
-	/**
48
-	 * Get stock status counts for the current products.
49
-	 *
50
-	 * @param \WP_REST_Request $request The request object.
51
-	 * @return array status=>count pairs.
52
-	 */
53
-	public function get_stock_status_counts( $request ) {
54
-		global $wpdb;
55
-		$product_query         = new ProductQuery();
56
-		$stock_status_options  = array_map( 'esc_sql', array_keys( wc_get_product_stock_status_options() ) );
57
-		$hide_outofstock_items = get_option( 'woocommerce_hide_out_of_stock_items' );
58
-		if ( 'yes' === $hide_outofstock_items ) {
59
-			unset( $stock_status_options['outofstock'] );
60
-		}
61
-
62
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
63
-		add_filter( 'posts_pre_query', '__return_empty_array' );
64
-
65
-		$query_args = $product_query->prepare_objects_query( $request );
66
-		unset( $query_args['stock_status'] );
67
-		$query_args['no_found_rows']  = true;
68
-		$query_args['posts_per_page'] = -1;
69
-		$query                        = new \WP_Query();
70
-		$result                       = $query->query( $query_args );
71
-		$product_query_sql            = $query->request;
72
-
73
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
74
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
75
-
76
-		$stock_status_counts = array();
77
-
78
-		foreach ( $stock_status_options as $status ) {
79
-			$stock_status_count_sql = $this->generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options );
80
-
81
-			$result = $wpdb->get_row( $stock_status_count_sql ); // phpcs:ignore
82
-			$stock_status_counts[ $status ] = $result->status_count;
83
-		}
84
-
85
-		return $stock_status_counts;
86
-	}
87
-
88
-	/**
89
-	 * Generate calculate query by stock status.
90
-	 *
91
-	 * @param string $status status to calculate.
92
-	 * @param string $product_query_sql product query for current filter state.
93
-	 * @param array  $stock_status_options available stock status options.
94
-	 *
95
-	 * @return false|string
96
-	 */
97
-	private function generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options ) {
98
-		if ( ! in_array( $status, $stock_status_options, true ) ) {
99
-			return false;
100
-		}
101
-		global $wpdb;
102
-		$status = esc_sql( $status );
103
-		return "
44
+        return $wpdb->get_row( $price_filter_sql ); // phpcs:ignore
45
+    }
46
+
47
+    /**
48
+     * Get stock status counts for the current products.
49
+     *
50
+     * @param \WP_REST_Request $request The request object.
51
+     * @return array status=>count pairs.
52
+     */
53
+    public function get_stock_status_counts( $request ) {
54
+        global $wpdb;
55
+        $product_query         = new ProductQuery();
56
+        $stock_status_options  = array_map( 'esc_sql', array_keys( wc_get_product_stock_status_options() ) );
57
+        $hide_outofstock_items = get_option( 'woocommerce_hide_out_of_stock_items' );
58
+        if ( 'yes' === $hide_outofstock_items ) {
59
+            unset( $stock_status_options['outofstock'] );
60
+        }
61
+
62
+        add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
63
+        add_filter( 'posts_pre_query', '__return_empty_array' );
64
+
65
+        $query_args = $product_query->prepare_objects_query( $request );
66
+        unset( $query_args['stock_status'] );
67
+        $query_args['no_found_rows']  = true;
68
+        $query_args['posts_per_page'] = -1;
69
+        $query                        = new \WP_Query();
70
+        $result                       = $query->query( $query_args );
71
+        $product_query_sql            = $query->request;
72
+
73
+        remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
74
+        remove_filter( 'posts_pre_query', '__return_empty_array' );
75
+
76
+        $stock_status_counts = array();
77
+
78
+        foreach ( $stock_status_options as $status ) {
79
+            $stock_status_count_sql = $this->generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options );
80
+
81
+            $result = $wpdb->get_row( $stock_status_count_sql ); // phpcs:ignore
82
+            $stock_status_counts[ $status ] = $result->status_count;
83
+        }
84
+
85
+        return $stock_status_counts;
86
+    }
87
+
88
+    /**
89
+     * Generate calculate query by stock status.
90
+     *
91
+     * @param string $status status to calculate.
92
+     * @param string $product_query_sql product query for current filter state.
93
+     * @param array  $stock_status_options available stock status options.
94
+     *
95
+     * @return false|string
96
+     */
97
+    private function generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options ) {
98
+        if ( ! in_array( $status, $stock_status_options, true ) ) {
99
+            return false;
100
+        }
101
+        global $wpdb;
102
+        $status = esc_sql( $status );
103
+        return "
104 104
 			SELECT COUNT( DISTINCT posts.ID ) as status_count
105 105
 			FROM {$wpdb->posts} as posts
106 106
 			INNER JOIN {$wpdb->postmeta} as postmeta ON posts.ID = postmeta.post_id
@@ -108,53 +108,53 @@  discard block
 block discarded – undo
108 108
             AND postmeta.meta_value = '{$status}'
109 109
 			WHERE posts.ID IN ( {$product_query_sql} )
110 110
 		";
111
-	}
112
-
113
-	/**
114
-	 * Get attribute counts for the current products.
115
-	 *
116
-	 * @param \WP_REST_Request $request The request object.
117
-	 * @param array            $attributes Attributes to count, either names or ids.
118
-	 * @return array termId=>count pairs.
119
-	 */
120
-	public function get_attribute_counts( $request, $attributes = [] ) {
121
-		global $wpdb;
122
-
123
-		// Remove paging and sorting params from the request.
124
-		$request->set_param( 'page', null );
125
-		$request->set_param( 'per_page', null );
126
-		$request->set_param( 'order', null );
127
-		$request->set_param( 'orderby', null );
128
-
129
-		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
130
-		$product_query = new ProductQuery();
131
-
132
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
133
-		add_filter( 'posts_pre_query', '__return_empty_array' );
134
-
135
-		$query_args                   = $product_query->prepare_objects_query( $request );
136
-		$query_args['no_found_rows']  = true;
137
-		$query_args['posts_per_page'] = -1;
138
-		$query                        = new \WP_Query();
139
-		$result                       = $query->query( $query_args );
140
-		$product_query_sql            = $query->request;
141
-
142
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
143
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
144
-
145
-		if ( count( $attributes ) === count( array_filter( $attributes, 'is_numeric' ) ) ) {
146
-			$attributes = array_map( 'wc_attribute_taxonomy_name_by_id', wp_parse_id_list( $attributes ) );
147
-		}
148
-
149
-		$attributes_to_count     = array_map(
150
-			function( $attribute ) {
151
-				$attribute = wc_sanitize_taxonomy_name( $attribute );
152
-				return esc_sql( $attribute );
153
-			},
154
-			$attributes
155
-		);
156
-		$attributes_to_count_sql = 'AND term_taxonomy.taxonomy IN ("' . implode( '","', $attributes_to_count ) . '")';
157
-		$attribute_count_sql     = "
111
+    }
112
+
113
+    /**
114
+     * Get attribute counts for the current products.
115
+     *
116
+     * @param \WP_REST_Request $request The request object.
117
+     * @param array            $attributes Attributes to count, either names or ids.
118
+     * @return array termId=>count pairs.
119
+     */
120
+    public function get_attribute_counts( $request, $attributes = [] ) {
121
+        global $wpdb;
122
+
123
+        // Remove paging and sorting params from the request.
124
+        $request->set_param( 'page', null );
125
+        $request->set_param( 'per_page', null );
126
+        $request->set_param( 'order', null );
127
+        $request->set_param( 'orderby', null );
128
+
129
+        // Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
130
+        $product_query = new ProductQuery();
131
+
132
+        add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
133
+        add_filter( 'posts_pre_query', '__return_empty_array' );
134
+
135
+        $query_args                   = $product_query->prepare_objects_query( $request );
136
+        $query_args['no_found_rows']  = true;
137
+        $query_args['posts_per_page'] = -1;
138
+        $query                        = new \WP_Query();
139
+        $result                       = $query->query( $query_args );
140
+        $product_query_sql            = $query->request;
141
+
142
+        remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
143
+        remove_filter( 'posts_pre_query', '__return_empty_array' );
144
+
145
+        if ( count( $attributes ) === count( array_filter( $attributes, 'is_numeric' ) ) ) {
146
+            $attributes = array_map( 'wc_attribute_taxonomy_name_by_id', wp_parse_id_list( $attributes ) );
147
+        }
148
+
149
+        $attributes_to_count     = array_map(
150
+            function( $attribute ) {
151
+                $attribute = wc_sanitize_taxonomy_name( $attribute );
152
+                return esc_sql( $attribute );
153
+            },
154
+            $attributes
155
+        );
156
+        $attributes_to_count_sql = 'AND term_taxonomy.taxonomy IN ("' . implode( '","', $attributes_to_count ) . '")';
157
+        $attribute_count_sql     = "
158 158
 			SELECT COUNT( DISTINCT posts.ID ) as term_count, terms.term_id as term_count_id
159 159
 			FROM {$wpdb->posts} AS posts
160 160
 			INNER JOIN {$wpdb->term_relationships} AS term_relationships ON posts.ID = term_relationships.object_id
@@ -165,40 +165,40 @@  discard block
 block discarded – undo
165 165
 			GROUP BY terms.term_id
166 166
 		";
167 167
 
168
-		$results = $wpdb->get_results( $attribute_count_sql ); // phpcs:ignore
168
+        $results = $wpdb->get_results( $attribute_count_sql ); // phpcs:ignore
169 169
 
170
-		return array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
171
-	}
170
+        return array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
171
+    }
172 172
 
173
-	/**
174
-	 * Get rating counts for the current products.
175
-	 *
176
-	 * @param \WP_REST_Request $request The request object.
177
-	 * @return array rating=>count pairs.
178
-	 */
179
-	public function get_rating_counts( $request ) {
180
-		global $wpdb;
173
+    /**
174
+     * Get rating counts for the current products.
175
+     *
176
+     * @param \WP_REST_Request $request The request object.
177
+     * @return array rating=>count pairs.
178
+     */
179
+    public function get_rating_counts( $request ) {
180
+        global $wpdb;
181 181
 
182
-		// Regenerate the products query without rating request params.
183
-		unset( $request['rating'] );
182
+        // Regenerate the products query without rating request params.
183
+        unset( $request['rating'] );
184 184
 
185
-		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
186
-		$product_query = new ProductQuery();
185
+        // Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
186
+        $product_query = new ProductQuery();
187 187
 
188
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
189
-		add_filter( 'posts_pre_query', '__return_empty_array' );
188
+        add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
189
+        add_filter( 'posts_pre_query', '__return_empty_array' );
190 190
 
191
-		$query_args                   = $product_query->prepare_objects_query( $request );
192
-		$query_args['no_found_rows']  = true;
193
-		$query_args['posts_per_page'] = -1;
194
-		$query                        = new \WP_Query();
195
-		$result                       = $query->query( $query_args );
196
-		$product_query_sql            = $query->request;
191
+        $query_args                   = $product_query->prepare_objects_query( $request );
192
+        $query_args['no_found_rows']  = true;
193
+        $query_args['posts_per_page'] = -1;
194
+        $query                        = new \WP_Query();
195
+        $result                       = $query->query( $query_args );
196
+        $product_query_sql            = $query->request;
197 197
 
198
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
199
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
198
+        remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
199
+        remove_filter( 'posts_pre_query', '__return_empty_array' );
200 200
 
201
-		$rating_count_sql = "
201
+        $rating_count_sql = "
202 202
 			SELECT COUNT( DISTINCT product_id ) as product_count, ROUND( average_rating, 0 ) as rounded_average_rating
203 203
 			FROM {$wpdb->wc_product_meta_lookup}
204 204
 			WHERE product_id IN ( {$product_query_sql} )
@@ -207,8 +207,8 @@  discard block
 block discarded – undo
207 207
 			ORDER BY rounded_average_rating ASC
208 208
 		";
209 209
 
210
-		$results = $wpdb->get_results( $rating_count_sql ); // phpcs:ignore
210
+        $results = $wpdb->get_results( $rating_count_sql ); // phpcs:ignore
211 211
 
212
-		return array_map( 'absint', wp_list_pluck( $results, 'product_count', 'rounded_average_rating' ) );
213
-	}
212
+        return array_map( 'absint', wp_list_pluck( $results, 'product_count', 'rounded_average_rating' ) );
213
+    }
214 214
 }
Please login to merge, or discard this patch.
Spacing   +58 added lines, -58 removed lines patch added patch discarded remove patch
@@ -13,27 +13,27 @@  discard block
 block discarded – undo
13 13
 	 * @param \WP_REST_Request $request The request object.
14 14
 	 * @return object
15 15
 	 */
16
-	public function get_filtered_price( $request ) {
16
+	public function get_filtered_price($request) {
17 17
 		global $wpdb;
18 18
 
19 19
 		// Regenerate the products query without min/max price request params.
20
-		unset( $request['min_price'], $request['max_price'] );
20
+		unset($request['min_price'], $request['max_price']);
21 21
 
22 22
 		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
23 23
 		$product_query = new ProductQuery();
24 24
 
25
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
26
-		add_filter( 'posts_pre_query', '__return_empty_array' );
25
+		add_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10, 2);
26
+		add_filter('posts_pre_query', '__return_empty_array');
27 27
 
28
-		$query_args                   = $product_query->prepare_objects_query( $request );
28
+		$query_args                   = $product_query->prepare_objects_query($request);
29 29
 		$query_args['no_found_rows']  = true;
30 30
 		$query_args['posts_per_page'] = -1;
31 31
 		$query                        = new \WP_Query();
32
-		$result                       = $query->query( $query_args );
32
+		$result                       = $query->query($query_args);
33 33
 		$product_query_sql            = $query->request;
34 34
 
35
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
36
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
35
+		remove_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10);
36
+		remove_filter('posts_pre_query', '__return_empty_array');
37 37
 
38 38
 		$price_filter_sql = "
39 39
 			SELECT min( min_price ) as min_price, MAX( max_price ) as max_price
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
 			WHERE product_id IN ( {$product_query_sql} )
42 42
 		";
43 43
 
44
-		return $wpdb->get_row( $price_filter_sql ); // phpcs:ignore
44
+		return $wpdb->get_row($price_filter_sql); // phpcs:ignore
45 45
 	}
46 46
 
47 47
 	/**
@@ -50,36 +50,36 @@  discard block
 block discarded – undo
50 50
 	 * @param \WP_REST_Request $request The request object.
51 51
 	 * @return array status=>count pairs.
52 52
 	 */
53
-	public function get_stock_status_counts( $request ) {
53
+	public function get_stock_status_counts($request) {
54 54
 		global $wpdb;
55 55
 		$product_query         = new ProductQuery();
56
-		$stock_status_options  = array_map( 'esc_sql', array_keys( wc_get_product_stock_status_options() ) );
57
-		$hide_outofstock_items = get_option( 'woocommerce_hide_out_of_stock_items' );
58
-		if ( 'yes' === $hide_outofstock_items ) {
59
-			unset( $stock_status_options['outofstock'] );
56
+		$stock_status_options  = array_map('esc_sql', array_keys(wc_get_product_stock_status_options()));
57
+		$hide_outofstock_items = get_option('woocommerce_hide_out_of_stock_items');
58
+		if ('yes' === $hide_outofstock_items) {
59
+			unset($stock_status_options['outofstock']);
60 60
 		}
61 61
 
62
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
63
-		add_filter( 'posts_pre_query', '__return_empty_array' );
62
+		add_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10, 2);
63
+		add_filter('posts_pre_query', '__return_empty_array');
64 64
 
65
-		$query_args = $product_query->prepare_objects_query( $request );
66
-		unset( $query_args['stock_status'] );
65
+		$query_args = $product_query->prepare_objects_query($request);
66
+		unset($query_args['stock_status']);
67 67
 		$query_args['no_found_rows']  = true;
68 68
 		$query_args['posts_per_page'] = -1;
69 69
 		$query                        = new \WP_Query();
70
-		$result                       = $query->query( $query_args );
70
+		$result                       = $query->query($query_args);
71 71
 		$product_query_sql            = $query->request;
72 72
 
73
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
74
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
73
+		remove_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10);
74
+		remove_filter('posts_pre_query', '__return_empty_array');
75 75
 
76 76
 		$stock_status_counts = array();
77 77
 
78
-		foreach ( $stock_status_options as $status ) {
79
-			$stock_status_count_sql = $this->generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options );
78
+		foreach ($stock_status_options as $status) {
79
+			$stock_status_count_sql = $this->generate_stock_status_count_query($status, $product_query_sql, $stock_status_options);
80 80
 
81
-			$result = $wpdb->get_row( $stock_status_count_sql ); // phpcs:ignore
82
-			$stock_status_counts[ $status ] = $result->status_count;
81
+			$result = $wpdb->get_row($stock_status_count_sql); // phpcs:ignore
82
+			$stock_status_counts[$status] = $result->status_count;
83 83
 		}
84 84
 
85 85
 		return $stock_status_counts;
@@ -94,12 +94,12 @@  discard block
 block discarded – undo
94 94
 	 *
95 95
 	 * @return false|string
96 96
 	 */
97
-	private function generate_stock_status_count_query( $status, $product_query_sql, $stock_status_options ) {
98
-		if ( ! in_array( $status, $stock_status_options, true ) ) {
97
+	private function generate_stock_status_count_query($status, $product_query_sql, $stock_status_options) {
98
+		if (!in_array($status, $stock_status_options, true)) {
99 99
 			return false;
100 100
 		}
101 101
 		global $wpdb;
102
-		$status = esc_sql( $status );
102
+		$status = esc_sql($status);
103 103
 		return "
104 104
 			SELECT COUNT( DISTINCT posts.ID ) as status_count
105 105
 			FROM {$wpdb->posts} as posts
@@ -117,43 +117,43 @@  discard block
 block discarded – undo
117 117
 	 * @param array            $attributes Attributes to count, either names or ids.
118 118
 	 * @return array termId=>count pairs.
119 119
 	 */
120
-	public function get_attribute_counts( $request, $attributes = [] ) {
120
+	public function get_attribute_counts($request, $attributes = []) {
121 121
 		global $wpdb;
122 122
 
123 123
 		// Remove paging and sorting params from the request.
124
-		$request->set_param( 'page', null );
125
-		$request->set_param( 'per_page', null );
126
-		$request->set_param( 'order', null );
127
-		$request->set_param( 'orderby', null );
124
+		$request->set_param('page', null);
125
+		$request->set_param('per_page', null);
126
+		$request->set_param('order', null);
127
+		$request->set_param('orderby', null);
128 128
 
129 129
 		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
130 130
 		$product_query = new ProductQuery();
131 131
 
132
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
133
-		add_filter( 'posts_pre_query', '__return_empty_array' );
132
+		add_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10, 2);
133
+		add_filter('posts_pre_query', '__return_empty_array');
134 134
 
135
-		$query_args                   = $product_query->prepare_objects_query( $request );
135
+		$query_args                   = $product_query->prepare_objects_query($request);
136 136
 		$query_args['no_found_rows']  = true;
137 137
 		$query_args['posts_per_page'] = -1;
138 138
 		$query                        = new \WP_Query();
139
-		$result                       = $query->query( $query_args );
139
+		$result                       = $query->query($query_args);
140 140
 		$product_query_sql            = $query->request;
141 141
 
142
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
143
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
142
+		remove_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10);
143
+		remove_filter('posts_pre_query', '__return_empty_array');
144 144
 
145
-		if ( count( $attributes ) === count( array_filter( $attributes, 'is_numeric' ) ) ) {
146
-			$attributes = array_map( 'wc_attribute_taxonomy_name_by_id', wp_parse_id_list( $attributes ) );
145
+		if (count($attributes) === count(array_filter($attributes, 'is_numeric'))) {
146
+			$attributes = array_map('wc_attribute_taxonomy_name_by_id', wp_parse_id_list($attributes));
147 147
 		}
148 148
 
149
-		$attributes_to_count     = array_map(
150
-			function( $attribute ) {
151
-				$attribute = wc_sanitize_taxonomy_name( $attribute );
152
-				return esc_sql( $attribute );
149
+		$attributes_to_count = array_map(
150
+			function($attribute) {
151
+				$attribute = wc_sanitize_taxonomy_name($attribute);
152
+				return esc_sql($attribute);
153 153
 			},
154 154
 			$attributes
155 155
 		);
156
-		$attributes_to_count_sql = 'AND term_taxonomy.taxonomy IN ("' . implode( '","', $attributes_to_count ) . '")';
156
+		$attributes_to_count_sql = 'AND term_taxonomy.taxonomy IN ("' . implode('","', $attributes_to_count) . '")';
157 157
 		$attribute_count_sql     = "
158 158
 			SELECT COUNT( DISTINCT posts.ID ) as term_count, terms.term_id as term_count_id
159 159
 			FROM {$wpdb->posts} AS posts
@@ -165,9 +165,9 @@  discard block
 block discarded – undo
165 165
 			GROUP BY terms.term_id
166 166
 		";
167 167
 
168
-		$results = $wpdb->get_results( $attribute_count_sql ); // phpcs:ignore
168
+		$results = $wpdb->get_results($attribute_count_sql); // phpcs:ignore
169 169
 
170
-		return array_map( 'absint', wp_list_pluck( $results, 'term_count', 'term_count_id' ) );
170
+		return array_map('absint', wp_list_pluck($results, 'term_count', 'term_count_id'));
171 171
 	}
172 172
 
173 173
 	/**
@@ -176,27 +176,27 @@  discard block
 block discarded – undo
176 176
 	 * @param \WP_REST_Request $request The request object.
177 177
 	 * @return array rating=>count pairs.
178 178
 	 */
179
-	public function get_rating_counts( $request ) {
179
+	public function get_rating_counts($request) {
180 180
 		global $wpdb;
181 181
 
182 182
 		// Regenerate the products query without rating request params.
183
-		unset( $request['rating'] );
183
+		unset($request['rating']);
184 184
 
185 185
 		// Grab the request from the WP Query object, and remove SQL_CALC_FOUND_ROWS and Limits so we get a list of all products.
186 186
 		$product_query = new ProductQuery();
187 187
 
188
-		add_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10, 2 );
189
-		add_filter( 'posts_pre_query', '__return_empty_array' );
188
+		add_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10, 2);
189
+		add_filter('posts_pre_query', '__return_empty_array');
190 190
 
191
-		$query_args                   = $product_query->prepare_objects_query( $request );
191
+		$query_args                   = $product_query->prepare_objects_query($request);
192 192
 		$query_args['no_found_rows']  = true;
193 193
 		$query_args['posts_per_page'] = -1;
194 194
 		$query                        = new \WP_Query();
195
-		$result                       = $query->query( $query_args );
195
+		$result                       = $query->query($query_args);
196 196
 		$product_query_sql            = $query->request;
197 197
 
198
-		remove_filter( 'posts_clauses', array( $product_query, 'add_query_clauses' ), 10 );
199
-		remove_filter( 'posts_pre_query', '__return_empty_array' );
198
+		remove_filter('posts_clauses', array($product_query, 'add_query_clauses'), 10);
199
+		remove_filter('posts_pre_query', '__return_empty_array');
200 200
 
201 201
 		$rating_count_sql = "
202 202
 			SELECT COUNT( DISTINCT product_id ) as product_count, ROUND( average_rating, 0 ) as rounded_average_rating
@@ -207,8 +207,8 @@  discard block
 block discarded – undo
207 207
 			ORDER BY rounded_average_rating ASC
208 208
 		";
209 209
 
210
-		$results = $wpdb->get_results( $rating_count_sql ); // phpcs:ignore
210
+		$results = $wpdb->get_results($rating_count_sql); // phpcs:ignore
211 211
 
212
-		return array_map( 'absint', wp_list_pluck( $results, 'product_count', 'rounded_average_rating' ) );
212
+		return array_map('absint', wp_list_pluck($results, 'product_count', 'rounded_average_rating'));
213 213
 	}
214 214
 }
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/ProductQuery.php 2 patches
Indentation   +483 added lines, -483 removed lines patch added patch discarded remove patch
@@ -9,490 +9,490 @@
 block discarded – undo
9 9
  * Helper class to handle product queries for the API.
10 10
  */
11 11
 class ProductQuery {
12
-	/**
13
-	 * Prepare query args to pass to WP_Query for a REST API request.
14
-	 *
15
-	 * @param \WP_REST_Request $request Request data.
16
-	 * @return array
17
-	 */
18
-	public function prepare_objects_query( $request ) {
19
-		$args = [
20
-			'offset'              => $request['offset'],
21
-			'order'               => $request['order'],
22
-			'orderby'             => $request['orderby'],
23
-			'paged'               => $request['page'],
24
-			'post__in'            => $request['include'],
25
-			'post__not_in'        => $request['exclude'],
26
-			'posts_per_page'      => $request['per_page'] ? $request['per_page'] : -1,
27
-			'post_parent__in'     => $request['parent'],
28
-			'post_parent__not_in' => $request['parent_exclude'],
29
-			'search'              => $request['search'], // This uses search rather than s intentionally to handle searches internally.
30
-			'fields'              => 'ids',
31
-			'ignore_sticky_posts' => true,
32
-			'post_status'         => 'publish',
33
-			'date_query'          => [],
34
-			'post_type'           => 'product',
35
-		];
36
-
37
-		// If searching for a specific SKU, allow any post type.
38
-		if ( ! empty( $request['sku'] ) ) {
39
-			$args['post_type'] = [ 'product', 'product_variation' ];
40
-		}
41
-
42
-		// Taxonomy query to filter products by type, category, tag, shipping class, and attribute.
43
-		$tax_query = [];
44
-
45
-		// Filter product type by slug.
46
-		if ( ! empty( $request['type'] ) ) {
47
-			if ( 'variation' === $request['type'] ) {
48
-				$args['post_type'] = 'product_variation';
49
-			} else {
50
-				$args['post_type'] = 'product';
51
-				$tax_query[]       = [
52
-					'taxonomy' => 'product_type',
53
-					'field'    => 'slug',
54
-					'terms'    => $request['type'],
55
-				];
56
-			}
57
-		}
58
-
59
-		if ( 'date' === $args['orderby'] ) {
60
-			$args['orderby'] = 'date ID';
61
-		}
62
-
63
-		// Set before into date query. Date query must be specified as an array of an array.
64
-		if ( isset( $request['before'] ) ) {
65
-			$args['date_query'][0]['before'] = $request['before'];
66
-		}
67
-
68
-		// Set after into date query. Date query must be specified as an array of an array.
69
-		if ( isset( $request['after'] ) ) {
70
-			$args['date_query'][0]['after'] = $request['after'];
71
-		}
72
-
73
-		// Set date query column. Defaults to post_date.
74
-		if ( isset( $request['date_column'] ) && ! empty( $args['date_query'][0] ) ) {
75
-			$args['date_query'][0]['column'] = 'post_' . $request['date_column'];
76
-		}
77
-
78
-		// Set custom args to handle later during clauses.
79
-		$custom_keys = [
80
-			'sku',
81
-			'min_price',
82
-			'max_price',
83
-			'stock_status',
84
-		];
85
-
86
-		foreach ( $custom_keys as $key ) {
87
-			if ( ! empty( $request[ $key ] ) ) {
88
-				$args[ $key ] = $request[ $key ];
89
-			}
90
-		}
91
-
92
-		$operator_mapping = [
93
-			'in'     => 'IN',
94
-			'not_in' => 'NOT IN',
95
-			'and'    => 'AND',
96
-		];
97
-
98
-		// Gets all registered product taxonomies and prefixes them with `tax_`.
99
-		// This is neeeded to avoid situations where a users registers a new product taxonomy with the same name as default field.
100
-		// eg an `sku` taxonomy will be mapped to `tax_sku`.
101
-		$all_product_taxonomies = array_map(
102
-			function ( $value ) {
103
-				return '_unstable_tax_' . $value;
104
-			},
105
-			get_taxonomies( array( 'object_type' => array( 'product' ) ), 'names' )
106
-		);
107
-
108
-		// Map between taxonomy name and arg key.
109
-		$default_taxonomies = [
110
-			'product_cat' => 'category',
111
-			'product_tag' => 'tag',
112
-		];
113
-
114
-		$taxonomies = array_merge( $all_product_taxonomies, $default_taxonomies );
115
-
116
-		// Set tax_query for each passed arg.
117
-		foreach ( $taxonomies as $taxonomy => $key ) {
118
-			if ( ! empty( $request[ $key ] ) ) {
119
-				$operator    = $request->get_param( $key . '_operator' ) && isset( $operator_mapping[ $request->get_param( $key . '_operator' ) ] ) ? $operator_mapping[ $request->get_param( $key . '_operator' ) ] : 'IN';
120
-				$tax_query[] = [
121
-					'taxonomy' => $taxonomy,
122
-					'field'    => 'term_id',
123
-					'terms'    => $request[ $key ],
124
-					'operator' => $operator,
125
-				];
126
-			}
127
-		}
128
-
129
-		// Filter by attributes.
130
-		if ( ! empty( $request['attributes'] ) ) {
131
-			$att_queries = [];
132
-
133
-			foreach ( $request['attributes'] as $attribute ) {
134
-				if ( empty( $attribute['term_id'] ) && empty( $attribute['slug'] ) ) {
135
-					continue;
136
-				}
137
-				if ( in_array( $attribute['attribute'], wc_get_attribute_taxonomy_names(), true ) ) {
138
-					$operator      = isset( $attribute['operator'], $operator_mapping[ $attribute['operator'] ] ) ? $operator_mapping[ $attribute['operator'] ] : 'IN';
139
-					$att_queries[] = [
140
-						'taxonomy' => $attribute['attribute'],
141
-						'field'    => ! empty( $attribute['term_id'] ) ? 'term_id' : 'slug',
142
-						'terms'    => ! empty( $attribute['term_id'] ) ? $attribute['term_id'] : $attribute['slug'],
143
-						'operator' => $operator,
144
-					];
145
-				}
146
-			}
147
-
148
-			if ( 1 < count( $att_queries ) ) {
149
-				// Add relation arg when using multiple attributes.
150
-				$relation    = $request->get_param( 'attribute_relation' ) && isset( $operator_mapping[ $request->get_param( 'attribute_relation' ) ] ) ? $operator_mapping[ $request->get_param( 'attribute_relation' ) ] : 'IN';
151
-				$tax_query[] = [
152
-					'relation' => $relation,
153
-					$att_queries,
154
-				];
155
-			} else {
156
-				$tax_query = array_merge( $tax_query, $att_queries );
157
-			}
158
-		}
159
-
160
-		// Build tax_query if taxonomies are set.
161
-		if ( ! empty( $tax_query ) ) {
162
-			if ( ! empty( $args['tax_query'] ) ) {
163
-				$args['tax_query'] = array_merge( $tax_query, $args['tax_query'] ); // phpcs:ignore
164
-			} else {
165
-				$args['tax_query'] = $tax_query; // phpcs:ignore
166
-			}
167
-		}
168
-
169
-		// Filter featured.
170
-		if ( is_bool( $request['featured'] ) ) {
171
-			$args['tax_query'][] = [
172
-				'taxonomy' => 'product_visibility',
173
-				'field'    => 'name',
174
-				'terms'    => 'featured',
175
-				'operator' => true === $request['featured'] ? 'IN' : 'NOT IN',
176
-			];
177
-		}
178
-
179
-		// Filter by on sale products.
180
-		if ( is_bool( $request['on_sale'] ) ) {
181
-			$on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in';
182
-			$on_sale_ids = wc_get_product_ids_on_sale();
183
-
184
-			// Use 0 when there's no on sale products to avoid return all products.
185
-			$on_sale_ids = empty( $on_sale_ids ) ? [ 0 ] : $on_sale_ids;
186
-
187
-			$args[ $on_sale_key ] += $on_sale_ids;
188
-		}
189
-
190
-		$catalog_visibility = $request->get_param( 'catalog_visibility' );
191
-		$rating             = $request->get_param( 'rating' );
192
-		$visibility_options = wc_get_product_visibility_options();
193
-
194
-		if ( in_array( $catalog_visibility, array_keys( $visibility_options ), true ) ) {
195
-			$exclude_from_catalog = 'search' === $catalog_visibility ? '' : 'exclude-from-catalog';
196
-			$exclude_from_search  = 'catalog' === $catalog_visibility ? '' : 'exclude-from-search';
197
-
198
-			$args['tax_query'][] = [
199
-				'taxonomy'      => 'product_visibility',
200
-				'field'         => 'name',
201
-				'terms'         => [ $exclude_from_catalog, $exclude_from_search ],
202
-				'operator'      => 'hidden' === $catalog_visibility ? 'AND' : 'NOT IN',
203
-				'rating_filter' => true,
204
-			];
205
-		}
206
-
207
-		if ( $rating ) {
208
-			$rating_terms = [];
209
-			foreach ( $rating as $value ) {
210
-				$rating_terms[] = 'rated-' . $value;
211
-			}
212
-			$args['tax_query'][] = [
213
-				'taxonomy' => 'product_visibility',
214
-				'field'    => 'name',
215
-				'terms'    => $rating_terms,
216
-			];
217
-		}
218
-
219
-		$orderby = $request->get_param( 'orderby' );
220
-		$order   = $request->get_param( 'order' );
221
-
222
-		$ordering_args   = wc()->query->get_catalog_ordering_args( $orderby, $order );
223
-		$args['orderby'] = $ordering_args['orderby'];
224
-		$args['order']   = $ordering_args['order'];
225
-
226
-		if ( 'include' === $orderby ) {
227
-			$args['orderby'] = 'post__in';
228
-		} elseif ( 'id' === $orderby ) {
229
-			$args['orderby'] = 'ID'; // ID must be capitalized.
230
-		} elseif ( 'slug' === $orderby ) {
231
-			$args['orderby'] = 'name';
232
-		}
233
-
234
-		if ( $ordering_args['meta_key'] ) {
235
-			$args['meta_key'] = $ordering_args['meta_key']; // phpcs:ignore
236
-		}
237
-
238
-		return $args;
239
-	}
240
-
241
-	/**
242
-	 * Get results of query.
243
-	 *
244
-	 * @param \WP_REST_Request $request Request data.
245
-	 * @return array
246
-	 */
247
-	public function get_results( $request ) {
248
-		$query_args = $this->prepare_objects_query( $request );
249
-
250
-		add_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10, 2 );
251
-
252
-		$query       = new \WP_Query();
253
-		$results     = $query->query( $query_args );
254
-		$total_posts = $query->found_posts;
255
-
256
-		// Out-of-bounds, run the query again without LIMIT for total count.
257
-		if ( $total_posts < 1 && $query_args['paged'] > 1 ) {
258
-			unset( $query_args['paged'] );
259
-			$count_query = new \WP_Query();
260
-			$count_query->query( $query_args );
261
-			$total_posts = $count_query->found_posts;
262
-		}
263
-
264
-		remove_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10 );
265
-
266
-		return [
267
-			'results' => $results,
268
-			'total'   => (int) $total_posts,
269
-			'pages'   => $query->query_vars['posts_per_page'] > 0 ? (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ) : 1,
270
-		];
271
-	}
272
-
273
-	/**
274
-	 * Get objects.
275
-	 *
276
-	 * @param \WP_REST_Request $request Request data.
277
-	 * @return array
278
-	 */
279
-	public function get_objects( $request ) {
280
-		$results = $this->get_results( $request );
281
-
282
-		return [
283
-			'objects' => array_map( 'wc_get_product', $results['results'] ),
284
-			'total'   => $results['total'],
285
-			'pages'   => $results['pages'],
286
-		];
287
-	}
288
-
289
-	/**
290
-	 * Get last modified date for all products.
291
-	 *
292
-	 * @return int timestamp.
293
-	 */
294
-	public function get_last_modified() {
295
-		global $wpdb;
296
-
297
-		return strtotime( $wpdb->get_var( "SELECT MAX( post_modified_gmt ) FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' );" ) );
298
-	}
299
-
300
-	/**
301
-	 * Add in conditional search filters for products.
302
-	 *
303
-	 * @param array     $args Query args.
304
-	 * @param \WC_Query $wp_query WC_Query object.
305
-	 * @return array
306
-	 */
307
-	public function add_query_clauses( $args, $wp_query ) {
308
-		global $wpdb;
309
-
310
-		if ( $wp_query->get( 'search' ) ) {
311
-			$search         = '%' . $wpdb->esc_like( $wp_query->get( 'search' ) ) . '%';
312
-			$search_query   = wc_product_sku_enabled()
313
-				? $wpdb->prepare( " AND ( $wpdb->posts.post_title LIKE %s OR wc_product_meta_lookup.sku LIKE %s ) ", $search, $search )
314
-				: $wpdb->prepare( " AND $wpdb->posts.post_title LIKE %s ", $search );
315
-			$args['where'] .= $search_query;
316
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
317
-		}
318
-
319
-		if ( $wp_query->get( 'sku' ) ) {
320
-			$skus = explode( ',', $wp_query->get( 'sku' ) );
321
-			// Include the current string as a SKU too.
322
-			if ( 1 < count( $skus ) ) {
323
-				$skus[] = $wp_query->get( 'sku' );
324
-			}
325
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
326
-			$args['where'] .= ' AND wc_product_meta_lookup.sku IN ("' . implode( '","', array_map( 'esc_sql', $skus ) ) . '")';
327
-		}
328
-
329
-		if ( $wp_query->get( 'stock_status' ) ) {
330
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
331
-			$args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode( '","', array_map( 'esc_sql', $wp_query->get( 'stock_status' ) ) ) . '")';
332
-		} elseif ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
333
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
334
-			$args['where'] .= ' AND wc_product_meta_lookup.stock_status NOT IN ("outofstock")';
335
-		}
336
-
337
-		if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
338
-			$args = $this->add_price_filter_clauses( $args, $wp_query );
339
-		}
340
-
341
-		return $args;
342
-	}
343
-
344
-	/**
345
-	 * Add in conditional price filters.
346
-	 *
347
-	 * @param array     $args Query args.
348
-	 * @param \WC_Query $wp_query WC_Query object.
349
-	 * @return array
350
-	 */
351
-	protected function add_price_filter_clauses( $args, $wp_query ) {
352
-		global $wpdb;
353
-
354
-		$adjust_for_taxes = $this->adjust_price_filters_for_displayed_taxes();
355
-		$args['join']     = $this->append_product_sorting_table_join( $args['join'] );
356
-
357
-		if ( $wp_query->get( 'min_price' ) ) {
358
-			$min_price_filter = $this->prepare_price_filter( $wp_query->get( 'min_price' ) );
359
-
360
-			if ( $adjust_for_taxes ) {
361
-				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $min_price_filter, 'min_price', '>=' );
362
-			} else {
363
-				$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.min_price >= %f ', $min_price_filter );
364
-			}
365
-		}
366
-
367
-		if ( $wp_query->get( 'max_price' ) ) {
368
-			$max_price_filter = $this->prepare_price_filter( $wp_query->get( 'max_price' ) );
369
-
370
-			if ( $adjust_for_taxes ) {
371
-				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $max_price_filter, 'max_price', '<=' );
372
-			} else {
373
-				$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.max_price <= %f ', $max_price_filter );
374
-			}
375
-		}
376
-
377
-		return $args;
378
-	}
379
-
380
-	/**
381
-	 * Get query for price filters when dealing with displayed taxes.
382
-	 *
383
-	 * @param float  $price_filter Price filter to apply.
384
-	 * @param string $column Price being filtered (min or max).
385
-	 * @param string $operator Comparison operator for column.
386
-	 * @return string Constructed query.
387
-	 */
388
-	protected function get_price_filter_query_for_displayed_taxes( $price_filter, $column = 'min_price', $operator = '>=' ) {
389
-		global $wpdb;
390
-
391
-		// Select only used tax classes to avoid unwanted calculations.
392
-		$product_tax_classes = $wpdb->get_col( "SELECT DISTINCT tax_class FROM {$wpdb->wc_product_meta_lookup};" );
393
-
394
-		if ( empty( $product_tax_classes ) ) {
395
-			return '';
396
-		}
397
-
398
-		$or_queries = [];
399
-
400
-		// We need to adjust the filter for each possible tax class and combine the queries into one.
401
-		foreach ( $product_tax_classes as $tax_class ) {
402
-			$adjusted_price_filter = $this->adjust_price_filter_for_tax_class( $price_filter, $tax_class );
403
-			$or_queries[]          = $wpdb->prepare(
404
-				'( wc_product_meta_lookup.tax_class = %s AND wc_product_meta_lookup.`' . esc_sql( $column ) . '` ' . esc_sql( $operator ) . ' %f )',
405
-				$tax_class,
406
-				$adjusted_price_filter
407
-			);
408
-		}
409
-
410
-		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
411
-		return $wpdb->prepare(
412
-			' AND (
12
+    /**
13
+     * Prepare query args to pass to WP_Query for a REST API request.
14
+     *
15
+     * @param \WP_REST_Request $request Request data.
16
+     * @return array
17
+     */
18
+    public function prepare_objects_query( $request ) {
19
+        $args = [
20
+            'offset'              => $request['offset'],
21
+            'order'               => $request['order'],
22
+            'orderby'             => $request['orderby'],
23
+            'paged'               => $request['page'],
24
+            'post__in'            => $request['include'],
25
+            'post__not_in'        => $request['exclude'],
26
+            'posts_per_page'      => $request['per_page'] ? $request['per_page'] : -1,
27
+            'post_parent__in'     => $request['parent'],
28
+            'post_parent__not_in' => $request['parent_exclude'],
29
+            'search'              => $request['search'], // This uses search rather than s intentionally to handle searches internally.
30
+            'fields'              => 'ids',
31
+            'ignore_sticky_posts' => true,
32
+            'post_status'         => 'publish',
33
+            'date_query'          => [],
34
+            'post_type'           => 'product',
35
+        ];
36
+
37
+        // If searching for a specific SKU, allow any post type.
38
+        if ( ! empty( $request['sku'] ) ) {
39
+            $args['post_type'] = [ 'product', 'product_variation' ];
40
+        }
41
+
42
+        // Taxonomy query to filter products by type, category, tag, shipping class, and attribute.
43
+        $tax_query = [];
44
+
45
+        // Filter product type by slug.
46
+        if ( ! empty( $request['type'] ) ) {
47
+            if ( 'variation' === $request['type'] ) {
48
+                $args['post_type'] = 'product_variation';
49
+            } else {
50
+                $args['post_type'] = 'product';
51
+                $tax_query[]       = [
52
+                    'taxonomy' => 'product_type',
53
+                    'field'    => 'slug',
54
+                    'terms'    => $request['type'],
55
+                ];
56
+            }
57
+        }
58
+
59
+        if ( 'date' === $args['orderby'] ) {
60
+            $args['orderby'] = 'date ID';
61
+        }
62
+
63
+        // Set before into date query. Date query must be specified as an array of an array.
64
+        if ( isset( $request['before'] ) ) {
65
+            $args['date_query'][0]['before'] = $request['before'];
66
+        }
67
+
68
+        // Set after into date query. Date query must be specified as an array of an array.
69
+        if ( isset( $request['after'] ) ) {
70
+            $args['date_query'][0]['after'] = $request['after'];
71
+        }
72
+
73
+        // Set date query column. Defaults to post_date.
74
+        if ( isset( $request['date_column'] ) && ! empty( $args['date_query'][0] ) ) {
75
+            $args['date_query'][0]['column'] = 'post_' . $request['date_column'];
76
+        }
77
+
78
+        // Set custom args to handle later during clauses.
79
+        $custom_keys = [
80
+            'sku',
81
+            'min_price',
82
+            'max_price',
83
+            'stock_status',
84
+        ];
85
+
86
+        foreach ( $custom_keys as $key ) {
87
+            if ( ! empty( $request[ $key ] ) ) {
88
+                $args[ $key ] = $request[ $key ];
89
+            }
90
+        }
91
+
92
+        $operator_mapping = [
93
+            'in'     => 'IN',
94
+            'not_in' => 'NOT IN',
95
+            'and'    => 'AND',
96
+        ];
97
+
98
+        // Gets all registered product taxonomies and prefixes them with `tax_`.
99
+        // This is neeeded to avoid situations where a users registers a new product taxonomy with the same name as default field.
100
+        // eg an `sku` taxonomy will be mapped to `tax_sku`.
101
+        $all_product_taxonomies = array_map(
102
+            function ( $value ) {
103
+                return '_unstable_tax_' . $value;
104
+            },
105
+            get_taxonomies( array( 'object_type' => array( 'product' ) ), 'names' )
106
+        );
107
+
108
+        // Map between taxonomy name and arg key.
109
+        $default_taxonomies = [
110
+            'product_cat' => 'category',
111
+            'product_tag' => 'tag',
112
+        ];
113
+
114
+        $taxonomies = array_merge( $all_product_taxonomies, $default_taxonomies );
115
+
116
+        // Set tax_query for each passed arg.
117
+        foreach ( $taxonomies as $taxonomy => $key ) {
118
+            if ( ! empty( $request[ $key ] ) ) {
119
+                $operator    = $request->get_param( $key . '_operator' ) && isset( $operator_mapping[ $request->get_param( $key . '_operator' ) ] ) ? $operator_mapping[ $request->get_param( $key . '_operator' ) ] : 'IN';
120
+                $tax_query[] = [
121
+                    'taxonomy' => $taxonomy,
122
+                    'field'    => 'term_id',
123
+                    'terms'    => $request[ $key ],
124
+                    'operator' => $operator,
125
+                ];
126
+            }
127
+        }
128
+
129
+        // Filter by attributes.
130
+        if ( ! empty( $request['attributes'] ) ) {
131
+            $att_queries = [];
132
+
133
+            foreach ( $request['attributes'] as $attribute ) {
134
+                if ( empty( $attribute['term_id'] ) && empty( $attribute['slug'] ) ) {
135
+                    continue;
136
+                }
137
+                if ( in_array( $attribute['attribute'], wc_get_attribute_taxonomy_names(), true ) ) {
138
+                    $operator      = isset( $attribute['operator'], $operator_mapping[ $attribute['operator'] ] ) ? $operator_mapping[ $attribute['operator'] ] : 'IN';
139
+                    $att_queries[] = [
140
+                        'taxonomy' => $attribute['attribute'],
141
+                        'field'    => ! empty( $attribute['term_id'] ) ? 'term_id' : 'slug',
142
+                        'terms'    => ! empty( $attribute['term_id'] ) ? $attribute['term_id'] : $attribute['slug'],
143
+                        'operator' => $operator,
144
+                    ];
145
+                }
146
+            }
147
+
148
+            if ( 1 < count( $att_queries ) ) {
149
+                // Add relation arg when using multiple attributes.
150
+                $relation    = $request->get_param( 'attribute_relation' ) && isset( $operator_mapping[ $request->get_param( 'attribute_relation' ) ] ) ? $operator_mapping[ $request->get_param( 'attribute_relation' ) ] : 'IN';
151
+                $tax_query[] = [
152
+                    'relation' => $relation,
153
+                    $att_queries,
154
+                ];
155
+            } else {
156
+                $tax_query = array_merge( $tax_query, $att_queries );
157
+            }
158
+        }
159
+
160
+        // Build tax_query if taxonomies are set.
161
+        if ( ! empty( $tax_query ) ) {
162
+            if ( ! empty( $args['tax_query'] ) ) {
163
+                $args['tax_query'] = array_merge( $tax_query, $args['tax_query'] ); // phpcs:ignore
164
+            } else {
165
+                $args['tax_query'] = $tax_query; // phpcs:ignore
166
+            }
167
+        }
168
+
169
+        // Filter featured.
170
+        if ( is_bool( $request['featured'] ) ) {
171
+            $args['tax_query'][] = [
172
+                'taxonomy' => 'product_visibility',
173
+                'field'    => 'name',
174
+                'terms'    => 'featured',
175
+                'operator' => true === $request['featured'] ? 'IN' : 'NOT IN',
176
+            ];
177
+        }
178
+
179
+        // Filter by on sale products.
180
+        if ( is_bool( $request['on_sale'] ) ) {
181
+            $on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in';
182
+            $on_sale_ids = wc_get_product_ids_on_sale();
183
+
184
+            // Use 0 when there's no on sale products to avoid return all products.
185
+            $on_sale_ids = empty( $on_sale_ids ) ? [ 0 ] : $on_sale_ids;
186
+
187
+            $args[ $on_sale_key ] += $on_sale_ids;
188
+        }
189
+
190
+        $catalog_visibility = $request->get_param( 'catalog_visibility' );
191
+        $rating             = $request->get_param( 'rating' );
192
+        $visibility_options = wc_get_product_visibility_options();
193
+
194
+        if ( in_array( $catalog_visibility, array_keys( $visibility_options ), true ) ) {
195
+            $exclude_from_catalog = 'search' === $catalog_visibility ? '' : 'exclude-from-catalog';
196
+            $exclude_from_search  = 'catalog' === $catalog_visibility ? '' : 'exclude-from-search';
197
+
198
+            $args['tax_query'][] = [
199
+                'taxonomy'      => 'product_visibility',
200
+                'field'         => 'name',
201
+                'terms'         => [ $exclude_from_catalog, $exclude_from_search ],
202
+                'operator'      => 'hidden' === $catalog_visibility ? 'AND' : 'NOT IN',
203
+                'rating_filter' => true,
204
+            ];
205
+        }
206
+
207
+        if ( $rating ) {
208
+            $rating_terms = [];
209
+            foreach ( $rating as $value ) {
210
+                $rating_terms[] = 'rated-' . $value;
211
+            }
212
+            $args['tax_query'][] = [
213
+                'taxonomy' => 'product_visibility',
214
+                'field'    => 'name',
215
+                'terms'    => $rating_terms,
216
+            ];
217
+        }
218
+
219
+        $orderby = $request->get_param( 'orderby' );
220
+        $order   = $request->get_param( 'order' );
221
+
222
+        $ordering_args   = wc()->query->get_catalog_ordering_args( $orderby, $order );
223
+        $args['orderby'] = $ordering_args['orderby'];
224
+        $args['order']   = $ordering_args['order'];
225
+
226
+        if ( 'include' === $orderby ) {
227
+            $args['orderby'] = 'post__in';
228
+        } elseif ( 'id' === $orderby ) {
229
+            $args['orderby'] = 'ID'; // ID must be capitalized.
230
+        } elseif ( 'slug' === $orderby ) {
231
+            $args['orderby'] = 'name';
232
+        }
233
+
234
+        if ( $ordering_args['meta_key'] ) {
235
+            $args['meta_key'] = $ordering_args['meta_key']; // phpcs:ignore
236
+        }
237
+
238
+        return $args;
239
+    }
240
+
241
+    /**
242
+     * Get results of query.
243
+     *
244
+     * @param \WP_REST_Request $request Request data.
245
+     * @return array
246
+     */
247
+    public function get_results( $request ) {
248
+        $query_args = $this->prepare_objects_query( $request );
249
+
250
+        add_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10, 2 );
251
+
252
+        $query       = new \WP_Query();
253
+        $results     = $query->query( $query_args );
254
+        $total_posts = $query->found_posts;
255
+
256
+        // Out-of-bounds, run the query again without LIMIT for total count.
257
+        if ( $total_posts < 1 && $query_args['paged'] > 1 ) {
258
+            unset( $query_args['paged'] );
259
+            $count_query = new \WP_Query();
260
+            $count_query->query( $query_args );
261
+            $total_posts = $count_query->found_posts;
262
+        }
263
+
264
+        remove_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10 );
265
+
266
+        return [
267
+            'results' => $results,
268
+            'total'   => (int) $total_posts,
269
+            'pages'   => $query->query_vars['posts_per_page'] > 0 ? (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ) : 1,
270
+        ];
271
+    }
272
+
273
+    /**
274
+     * Get objects.
275
+     *
276
+     * @param \WP_REST_Request $request Request data.
277
+     * @return array
278
+     */
279
+    public function get_objects( $request ) {
280
+        $results = $this->get_results( $request );
281
+
282
+        return [
283
+            'objects' => array_map( 'wc_get_product', $results['results'] ),
284
+            'total'   => $results['total'],
285
+            'pages'   => $results['pages'],
286
+        ];
287
+    }
288
+
289
+    /**
290
+     * Get last modified date for all products.
291
+     *
292
+     * @return int timestamp.
293
+     */
294
+    public function get_last_modified() {
295
+        global $wpdb;
296
+
297
+        return strtotime( $wpdb->get_var( "SELECT MAX( post_modified_gmt ) FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' );" ) );
298
+    }
299
+
300
+    /**
301
+     * Add in conditional search filters for products.
302
+     *
303
+     * @param array     $args Query args.
304
+     * @param \WC_Query $wp_query WC_Query object.
305
+     * @return array
306
+     */
307
+    public function add_query_clauses( $args, $wp_query ) {
308
+        global $wpdb;
309
+
310
+        if ( $wp_query->get( 'search' ) ) {
311
+            $search         = '%' . $wpdb->esc_like( $wp_query->get( 'search' ) ) . '%';
312
+            $search_query   = wc_product_sku_enabled()
313
+                ? $wpdb->prepare( " AND ( $wpdb->posts.post_title LIKE %s OR wc_product_meta_lookup.sku LIKE %s ) ", $search, $search )
314
+                : $wpdb->prepare( " AND $wpdb->posts.post_title LIKE %s ", $search );
315
+            $args['where'] .= $search_query;
316
+            $args['join']   = $this->append_product_sorting_table_join( $args['join'] );
317
+        }
318
+
319
+        if ( $wp_query->get( 'sku' ) ) {
320
+            $skus = explode( ',', $wp_query->get( 'sku' ) );
321
+            // Include the current string as a SKU too.
322
+            if ( 1 < count( $skus ) ) {
323
+                $skus[] = $wp_query->get( 'sku' );
324
+            }
325
+            $args['join']   = $this->append_product_sorting_table_join( $args['join'] );
326
+            $args['where'] .= ' AND wc_product_meta_lookup.sku IN ("' . implode( '","', array_map( 'esc_sql', $skus ) ) . '")';
327
+        }
328
+
329
+        if ( $wp_query->get( 'stock_status' ) ) {
330
+            $args['join']   = $this->append_product_sorting_table_join( $args['join'] );
331
+            $args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode( '","', array_map( 'esc_sql', $wp_query->get( 'stock_status' ) ) ) . '")';
332
+        } elseif ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
333
+            $args['join']   = $this->append_product_sorting_table_join( $args['join'] );
334
+            $args['where'] .= ' AND wc_product_meta_lookup.stock_status NOT IN ("outofstock")';
335
+        }
336
+
337
+        if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
338
+            $args = $this->add_price_filter_clauses( $args, $wp_query );
339
+        }
340
+
341
+        return $args;
342
+    }
343
+
344
+    /**
345
+     * Add in conditional price filters.
346
+     *
347
+     * @param array     $args Query args.
348
+     * @param \WC_Query $wp_query WC_Query object.
349
+     * @return array
350
+     */
351
+    protected function add_price_filter_clauses( $args, $wp_query ) {
352
+        global $wpdb;
353
+
354
+        $adjust_for_taxes = $this->adjust_price_filters_for_displayed_taxes();
355
+        $args['join']     = $this->append_product_sorting_table_join( $args['join'] );
356
+
357
+        if ( $wp_query->get( 'min_price' ) ) {
358
+            $min_price_filter = $this->prepare_price_filter( $wp_query->get( 'min_price' ) );
359
+
360
+            if ( $adjust_for_taxes ) {
361
+                $args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $min_price_filter, 'min_price', '>=' );
362
+            } else {
363
+                $args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.min_price >= %f ', $min_price_filter );
364
+            }
365
+        }
366
+
367
+        if ( $wp_query->get( 'max_price' ) ) {
368
+            $max_price_filter = $this->prepare_price_filter( $wp_query->get( 'max_price' ) );
369
+
370
+            if ( $adjust_for_taxes ) {
371
+                $args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $max_price_filter, 'max_price', '<=' );
372
+            } else {
373
+                $args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.max_price <= %f ', $max_price_filter );
374
+            }
375
+        }
376
+
377
+        return $args;
378
+    }
379
+
380
+    /**
381
+     * Get query for price filters when dealing with displayed taxes.
382
+     *
383
+     * @param float  $price_filter Price filter to apply.
384
+     * @param string $column Price being filtered (min or max).
385
+     * @param string $operator Comparison operator for column.
386
+     * @return string Constructed query.
387
+     */
388
+    protected function get_price_filter_query_for_displayed_taxes( $price_filter, $column = 'min_price', $operator = '>=' ) {
389
+        global $wpdb;
390
+
391
+        // Select only used tax classes to avoid unwanted calculations.
392
+        $product_tax_classes = $wpdb->get_col( "SELECT DISTINCT tax_class FROM {$wpdb->wc_product_meta_lookup};" );
393
+
394
+        if ( empty( $product_tax_classes ) ) {
395
+            return '';
396
+        }
397
+
398
+        $or_queries = [];
399
+
400
+        // We need to adjust the filter for each possible tax class and combine the queries into one.
401
+        foreach ( $product_tax_classes as $tax_class ) {
402
+            $adjusted_price_filter = $this->adjust_price_filter_for_tax_class( $price_filter, $tax_class );
403
+            $or_queries[]          = $wpdb->prepare(
404
+                '( wc_product_meta_lookup.tax_class = %s AND wc_product_meta_lookup.`' . esc_sql( $column ) . '` ' . esc_sql( $operator ) . ' %f )',
405
+                $tax_class,
406
+                $adjusted_price_filter
407
+            );
408
+        }
409
+
410
+        // phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
411
+        return $wpdb->prepare(
412
+            ' AND (
413 413
 				wc_product_meta_lookup.tax_status = "taxable" AND ( 0=1 OR ' . implode( ' OR ', $or_queries ) . ')
414 414
 				OR ( wc_product_meta_lookup.tax_status != "taxable" AND wc_product_meta_lookup.`' . esc_sql( $column ) . '` ' . esc_sql( $operator ) . ' %f )
415 415
 			) ',
416
-			$price_filter
417
-		);
418
-		// phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
419
-	}
420
-
421
-	/**
422
-	 * If price filters need adjustment to work with displayed taxes, this returns true.
423
-	 *
424
-	 * This logic is used when prices are stored in the database differently to how they are being displayed, with regards
425
-	 * to taxes.
426
-	 *
427
-	 * @return boolean
428
-	 */
429
-	protected function adjust_price_filters_for_displayed_taxes() {
430
-		$display  = get_option( 'woocommerce_tax_display_shop' );
431
-		$database = wc_prices_include_tax() ? 'incl' : 'excl';
432
-
433
-		return $display !== $database;
434
-	}
435
-
436
-	/**
437
-	 * Converts price filter from subunits to decimal.
438
-	 *
439
-	 * @param string|int $price_filter Raw price filter in subunit format.
440
-	 * @return float Price filter in decimal format.
441
-	 */
442
-	protected function prepare_price_filter( $price_filter ) {
443
-		return floatval( $price_filter / ( 10 ** wc_get_price_decimals() ) );
444
-	}
445
-
446
-	/**
447
-	 * Adjusts a price filter based on a tax class and whether or not the amount includes or excludes taxes.
448
-	 *
449
-	 * This calculation logic is based on `wc_get_price_excluding_tax` and `wc_get_price_including_tax` in core.
450
-	 *
451
-	 * @param float  $price_filter Price filter amount as entered.
452
-	 * @param string $tax_class Tax class for adjustment.
453
-	 * @return float
454
-	 */
455
-	protected function adjust_price_filter_for_tax_class( $price_filter, $tax_class ) {
456
-		$tax_display    = get_option( 'woocommerce_tax_display_shop' );
457
-		$tax_rates      = WC_Tax::get_rates( $tax_class );
458
-		$base_tax_rates = WC_Tax::get_base_tax_rates( $tax_class );
459
-
460
-		// If prices are shown incl. tax, we want to remove the taxes from the filter amount to match prices stored excl. tax.
461
-		if ( 'incl' === $tax_display ) {
462
-			/**
463
-			 * Filters if taxes should be removed from locations outside the store base location.
464
-			 *
465
-			 * The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing
466
-			 * with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10
467
-			 * regardless of location and taxes.
468
-			 *
469
-			 * @internal Matches filter name in WooCommerce core.
470
-			 *
471
-			 * @param boolean $adjust_non_base_location_prices True by default.
472
-			 * @return boolean
473
-			 */
474
-			$taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $price_filter, $base_tax_rates, true ) : WC_Tax::calc_tax( $price_filter, $tax_rates, true );
475
-			return $price_filter - array_sum( $taxes );
476
-		}
477
-
478
-		// If prices are shown excl. tax, add taxes to match the prices stored in the DB.
479
-		$taxes = WC_Tax::calc_tax( $price_filter, $tax_rates, false );
480
-
481
-		return $price_filter + array_sum( $taxes );
482
-	}
483
-
484
-	/**
485
-	 * Join wc_product_meta_lookup to posts if not already joined.
486
-	 *
487
-	 * @param string $sql SQL join.
488
-	 * @return string
489
-	 */
490
-	protected function append_product_sorting_table_join( $sql ) {
491
-		global $wpdb;
492
-
493
-		if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) {
494
-			$sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id ";
495
-		}
496
-		return $sql;
497
-	}
416
+            $price_filter
417
+        );
418
+        // phpcs:enable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
419
+    }
420
+
421
+    /**
422
+     * If price filters need adjustment to work with displayed taxes, this returns true.
423
+     *
424
+     * This logic is used when prices are stored in the database differently to how they are being displayed, with regards
425
+     * to taxes.
426
+     *
427
+     * @return boolean
428
+     */
429
+    protected function adjust_price_filters_for_displayed_taxes() {
430
+        $display  = get_option( 'woocommerce_tax_display_shop' );
431
+        $database = wc_prices_include_tax() ? 'incl' : 'excl';
432
+
433
+        return $display !== $database;
434
+    }
435
+
436
+    /**
437
+     * Converts price filter from subunits to decimal.
438
+     *
439
+     * @param string|int $price_filter Raw price filter in subunit format.
440
+     * @return float Price filter in decimal format.
441
+     */
442
+    protected function prepare_price_filter( $price_filter ) {
443
+        return floatval( $price_filter / ( 10 ** wc_get_price_decimals() ) );
444
+    }
445
+
446
+    /**
447
+     * Adjusts a price filter based on a tax class and whether or not the amount includes or excludes taxes.
448
+     *
449
+     * This calculation logic is based on `wc_get_price_excluding_tax` and `wc_get_price_including_tax` in core.
450
+     *
451
+     * @param float  $price_filter Price filter amount as entered.
452
+     * @param string $tax_class Tax class for adjustment.
453
+     * @return float
454
+     */
455
+    protected function adjust_price_filter_for_tax_class( $price_filter, $tax_class ) {
456
+        $tax_display    = get_option( 'woocommerce_tax_display_shop' );
457
+        $tax_rates      = WC_Tax::get_rates( $tax_class );
458
+        $base_tax_rates = WC_Tax::get_base_tax_rates( $tax_class );
459
+
460
+        // If prices are shown incl. tax, we want to remove the taxes from the filter amount to match prices stored excl. tax.
461
+        if ( 'incl' === $tax_display ) {
462
+            /**
463
+             * Filters if taxes should be removed from locations outside the store base location.
464
+             *
465
+             * The woocommerce_adjust_non_base_location_prices filter can stop base taxes being taken off when dealing
466
+             * with out of base locations. e.g. If a product costs 10 including tax, all users will pay 10
467
+             * regardless of location and taxes.
468
+             *
469
+             * @internal Matches filter name in WooCommerce core.
470
+             *
471
+             * @param boolean $adjust_non_base_location_prices True by default.
472
+             * @return boolean
473
+             */
474
+            $taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $price_filter, $base_tax_rates, true ) : WC_Tax::calc_tax( $price_filter, $tax_rates, true );
475
+            return $price_filter - array_sum( $taxes );
476
+        }
477
+
478
+        // If prices are shown excl. tax, add taxes to match the prices stored in the DB.
479
+        $taxes = WC_Tax::calc_tax( $price_filter, $tax_rates, false );
480
+
481
+        return $price_filter + array_sum( $taxes );
482
+    }
483
+
484
+    /**
485
+     * Join wc_product_meta_lookup to posts if not already joined.
486
+     *
487
+     * @param string $sql SQL join.
488
+     * @return string
489
+     */
490
+    protected function append_product_sorting_table_join( $sql ) {
491
+        global $wpdb;
492
+
493
+        if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) {
494
+            $sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id ";
495
+        }
496
+        return $sql;
497
+    }
498 498
 }
Please login to merge, or discard this patch.
Spacing   +115 added lines, -115 removed lines patch added patch discarded remove patch
@@ -15,7 +15,7 @@  discard block
 block discarded – undo
15 15
 	 * @param \WP_REST_Request $request Request data.
16 16
 	 * @return array
17 17
 	 */
18
-	public function prepare_objects_query( $request ) {
18
+	public function prepare_objects_query($request) {
19 19
 		$args = [
20 20
 			'offset'              => $request['offset'],
21 21
 			'order'               => $request['order'],
@@ -35,16 +35,16 @@  discard block
 block discarded – undo
35 35
 		];
36 36
 
37 37
 		// If searching for a specific SKU, allow any post type.
38
-		if ( ! empty( $request['sku'] ) ) {
39
-			$args['post_type'] = [ 'product', 'product_variation' ];
38
+		if (!empty($request['sku'])) {
39
+			$args['post_type'] = ['product', 'product_variation'];
40 40
 		}
41 41
 
42 42
 		// Taxonomy query to filter products by type, category, tag, shipping class, and attribute.
43 43
 		$tax_query = [];
44 44
 
45 45
 		// Filter product type by slug.
46
-		if ( ! empty( $request['type'] ) ) {
47
-			if ( 'variation' === $request['type'] ) {
46
+		if (!empty($request['type'])) {
47
+			if ('variation' === $request['type']) {
48 48
 				$args['post_type'] = 'product_variation';
49 49
 			} else {
50 50
 				$args['post_type'] = 'product';
@@ -56,22 +56,22 @@  discard block
 block discarded – undo
56 56
 			}
57 57
 		}
58 58
 
59
-		if ( 'date' === $args['orderby'] ) {
59
+		if ('date' === $args['orderby']) {
60 60
 			$args['orderby'] = 'date ID';
61 61
 		}
62 62
 
63 63
 		// Set before into date query. Date query must be specified as an array of an array.
64
-		if ( isset( $request['before'] ) ) {
64
+		if (isset($request['before'])) {
65 65
 			$args['date_query'][0]['before'] = $request['before'];
66 66
 		}
67 67
 
68 68
 		// Set after into date query. Date query must be specified as an array of an array.
69
-		if ( isset( $request['after'] ) ) {
69
+		if (isset($request['after'])) {
70 70
 			$args['date_query'][0]['after'] = $request['after'];
71 71
 		}
72 72
 
73 73
 		// Set date query column. Defaults to post_date.
74
-		if ( isset( $request['date_column'] ) && ! empty( $args['date_query'][0] ) ) {
74
+		if (isset($request['date_column']) && !empty($args['date_query'][0])) {
75 75
 			$args['date_query'][0]['column'] = 'post_' . $request['date_column'];
76 76
 		}
77 77
 
@@ -83,9 +83,9 @@  discard block
 block discarded – undo
83 83
 			'stock_status',
84 84
 		];
85 85
 
86
-		foreach ( $custom_keys as $key ) {
87
-			if ( ! empty( $request[ $key ] ) ) {
88
-				$args[ $key ] = $request[ $key ];
86
+		foreach ($custom_keys as $key) {
87
+			if (!empty($request[$key])) {
88
+				$args[$key] = $request[$key];
89 89
 			}
90 90
 		}
91 91
 
@@ -99,10 +99,10 @@  discard block
 block discarded – undo
99 99
 		// This is neeeded to avoid situations where a users registers a new product taxonomy with the same name as default field.
100 100
 		// eg an `sku` taxonomy will be mapped to `tax_sku`.
101 101
 		$all_product_taxonomies = array_map(
102
-			function ( $value ) {
102
+			function($value) {
103 103
 				return '_unstable_tax_' . $value;
104 104
 			},
105
-			get_taxonomies( array( 'object_type' => array( 'product' ) ), 'names' )
105
+			get_taxonomies(array('object_type' => array('product')), 'names')
106 106
 		);
107 107
 
108 108
 		// Map between taxonomy name and arg key.
@@ -111,63 +111,63 @@  discard block
 block discarded – undo
111 111
 			'product_tag' => 'tag',
112 112
 		];
113 113
 
114
-		$taxonomies = array_merge( $all_product_taxonomies, $default_taxonomies );
114
+		$taxonomies = array_merge($all_product_taxonomies, $default_taxonomies);
115 115
 
116 116
 		// Set tax_query for each passed arg.
117
-		foreach ( $taxonomies as $taxonomy => $key ) {
118
-			if ( ! empty( $request[ $key ] ) ) {
119
-				$operator    = $request->get_param( $key . '_operator' ) && isset( $operator_mapping[ $request->get_param( $key . '_operator' ) ] ) ? $operator_mapping[ $request->get_param( $key . '_operator' ) ] : 'IN';
117
+		foreach ($taxonomies as $taxonomy => $key) {
118
+			if (!empty($request[$key])) {
119
+				$operator    = $request->get_param($key . '_operator') && isset($operator_mapping[$request->get_param($key . '_operator')]) ? $operator_mapping[$request->get_param($key . '_operator')] : 'IN';
120 120
 				$tax_query[] = [
121 121
 					'taxonomy' => $taxonomy,
122 122
 					'field'    => 'term_id',
123
-					'terms'    => $request[ $key ],
123
+					'terms'    => $request[$key],
124 124
 					'operator' => $operator,
125 125
 				];
126 126
 			}
127 127
 		}
128 128
 
129 129
 		// Filter by attributes.
130
-		if ( ! empty( $request['attributes'] ) ) {
130
+		if (!empty($request['attributes'])) {
131 131
 			$att_queries = [];
132 132
 
133
-			foreach ( $request['attributes'] as $attribute ) {
134
-				if ( empty( $attribute['term_id'] ) && empty( $attribute['slug'] ) ) {
133
+			foreach ($request['attributes'] as $attribute) {
134
+				if (empty($attribute['term_id']) && empty($attribute['slug'])) {
135 135
 					continue;
136 136
 				}
137
-				if ( in_array( $attribute['attribute'], wc_get_attribute_taxonomy_names(), true ) ) {
138
-					$operator      = isset( $attribute['operator'], $operator_mapping[ $attribute['operator'] ] ) ? $operator_mapping[ $attribute['operator'] ] : 'IN';
137
+				if (in_array($attribute['attribute'], wc_get_attribute_taxonomy_names(), true)) {
138
+					$operator      = isset($attribute['operator'], $operator_mapping[$attribute['operator']]) ? $operator_mapping[$attribute['operator']] : 'IN';
139 139
 					$att_queries[] = [
140 140
 						'taxonomy' => $attribute['attribute'],
141
-						'field'    => ! empty( $attribute['term_id'] ) ? 'term_id' : 'slug',
142
-						'terms'    => ! empty( $attribute['term_id'] ) ? $attribute['term_id'] : $attribute['slug'],
141
+						'field'    => !empty($attribute['term_id']) ? 'term_id' : 'slug',
142
+						'terms'    => !empty($attribute['term_id']) ? $attribute['term_id'] : $attribute['slug'],
143 143
 						'operator' => $operator,
144 144
 					];
145 145
 				}
146 146
 			}
147 147
 
148
-			if ( 1 < count( $att_queries ) ) {
148
+			if (1 < count($att_queries)) {
149 149
 				// Add relation arg when using multiple attributes.
150
-				$relation    = $request->get_param( 'attribute_relation' ) && isset( $operator_mapping[ $request->get_param( 'attribute_relation' ) ] ) ? $operator_mapping[ $request->get_param( 'attribute_relation' ) ] : 'IN';
150
+				$relation    = $request->get_param('attribute_relation') && isset($operator_mapping[$request->get_param('attribute_relation')]) ? $operator_mapping[$request->get_param('attribute_relation')] : 'IN';
151 151
 				$tax_query[] = [
152 152
 					'relation' => $relation,
153 153
 					$att_queries,
154 154
 				];
155 155
 			} else {
156
-				$tax_query = array_merge( $tax_query, $att_queries );
156
+				$tax_query = array_merge($tax_query, $att_queries);
157 157
 			}
158 158
 		}
159 159
 
160 160
 		// Build tax_query if taxonomies are set.
161
-		if ( ! empty( $tax_query ) ) {
162
-			if ( ! empty( $args['tax_query'] ) ) {
163
-				$args['tax_query'] = array_merge( $tax_query, $args['tax_query'] ); // phpcs:ignore
161
+		if (!empty($tax_query)) {
162
+			if (!empty($args['tax_query'])) {
163
+				$args['tax_query'] = array_merge($tax_query, $args['tax_query']); // phpcs:ignore
164 164
 			} else {
165 165
 				$args['tax_query'] = $tax_query; // phpcs:ignore
166 166
 			}
167 167
 		}
168 168
 
169 169
 		// Filter featured.
170
-		if ( is_bool( $request['featured'] ) ) {
170
+		if (is_bool($request['featured'])) {
171 171
 			$args['tax_query'][] = [
172 172
 				'taxonomy' => 'product_visibility',
173 173
 				'field'    => 'name',
@@ -177,36 +177,36 @@  discard block
 block discarded – undo
177 177
 		}
178 178
 
179 179
 		// Filter by on sale products.
180
-		if ( is_bool( $request['on_sale'] ) ) {
180
+		if (is_bool($request['on_sale'])) {
181 181
 			$on_sale_key = $request['on_sale'] ? 'post__in' : 'post__not_in';
182 182
 			$on_sale_ids = wc_get_product_ids_on_sale();
183 183
 
184 184
 			// Use 0 when there's no on sale products to avoid return all products.
185
-			$on_sale_ids = empty( $on_sale_ids ) ? [ 0 ] : $on_sale_ids;
185
+			$on_sale_ids = empty($on_sale_ids) ? [0] : $on_sale_ids;
186 186
 
187
-			$args[ $on_sale_key ] += $on_sale_ids;
187
+			$args[$on_sale_key] += $on_sale_ids;
188 188
 		}
189 189
 
190
-		$catalog_visibility = $request->get_param( 'catalog_visibility' );
191
-		$rating             = $request->get_param( 'rating' );
190
+		$catalog_visibility = $request->get_param('catalog_visibility');
191
+		$rating             = $request->get_param('rating');
192 192
 		$visibility_options = wc_get_product_visibility_options();
193 193
 
194
-		if ( in_array( $catalog_visibility, array_keys( $visibility_options ), true ) ) {
194
+		if (in_array($catalog_visibility, array_keys($visibility_options), true)) {
195 195
 			$exclude_from_catalog = 'search' === $catalog_visibility ? '' : 'exclude-from-catalog';
196 196
 			$exclude_from_search  = 'catalog' === $catalog_visibility ? '' : 'exclude-from-search';
197 197
 
198 198
 			$args['tax_query'][] = [
199 199
 				'taxonomy'      => 'product_visibility',
200 200
 				'field'         => 'name',
201
-				'terms'         => [ $exclude_from_catalog, $exclude_from_search ],
201
+				'terms'         => [$exclude_from_catalog, $exclude_from_search],
202 202
 				'operator'      => 'hidden' === $catalog_visibility ? 'AND' : 'NOT IN',
203 203
 				'rating_filter' => true,
204 204
 			];
205 205
 		}
206 206
 
207
-		if ( $rating ) {
207
+		if ($rating) {
208 208
 			$rating_terms = [];
209
-			foreach ( $rating as $value ) {
209
+			foreach ($rating as $value) {
210 210
 				$rating_terms[] = 'rated-' . $value;
211 211
 			}
212 212
 			$args['tax_query'][] = [
@@ -216,22 +216,22 @@  discard block
 block discarded – undo
216 216
 			];
217 217
 		}
218 218
 
219
-		$orderby = $request->get_param( 'orderby' );
220
-		$order   = $request->get_param( 'order' );
219
+		$orderby = $request->get_param('orderby');
220
+		$order   = $request->get_param('order');
221 221
 
222
-		$ordering_args   = wc()->query->get_catalog_ordering_args( $orderby, $order );
222
+		$ordering_args   = wc()->query->get_catalog_ordering_args($orderby, $order);
223 223
 		$args['orderby'] = $ordering_args['orderby'];
224 224
 		$args['order']   = $ordering_args['order'];
225 225
 
226
-		if ( 'include' === $orderby ) {
226
+		if ('include' === $orderby) {
227 227
 			$args['orderby'] = 'post__in';
228
-		} elseif ( 'id' === $orderby ) {
228
+		} elseif ('id' === $orderby) {
229 229
 			$args['orderby'] = 'ID'; // ID must be capitalized.
230
-		} elseif ( 'slug' === $orderby ) {
230
+		} elseif ('slug' === $orderby) {
231 231
 			$args['orderby'] = 'name';
232 232
 		}
233 233
 
234
-		if ( $ordering_args['meta_key'] ) {
234
+		if ($ordering_args['meta_key']) {
235 235
 			$args['meta_key'] = $ordering_args['meta_key']; // phpcs:ignore
236 236
 		}
237 237
 
@@ -244,29 +244,29 @@  discard block
 block discarded – undo
244 244
 	 * @param \WP_REST_Request $request Request data.
245 245
 	 * @return array
246 246
 	 */
247
-	public function get_results( $request ) {
248
-		$query_args = $this->prepare_objects_query( $request );
247
+	public function get_results($request) {
248
+		$query_args = $this->prepare_objects_query($request);
249 249
 
250
-		add_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10, 2 );
250
+		add_filter('posts_clauses', [$this, 'add_query_clauses'], 10, 2);
251 251
 
252 252
 		$query       = new \WP_Query();
253
-		$results     = $query->query( $query_args );
253
+		$results     = $query->query($query_args);
254 254
 		$total_posts = $query->found_posts;
255 255
 
256 256
 		// Out-of-bounds, run the query again without LIMIT for total count.
257
-		if ( $total_posts < 1 && $query_args['paged'] > 1 ) {
258
-			unset( $query_args['paged'] );
257
+		if ($total_posts < 1 && $query_args['paged'] > 1) {
258
+			unset($query_args['paged']);
259 259
 			$count_query = new \WP_Query();
260
-			$count_query->query( $query_args );
260
+			$count_query->query($query_args);
261 261
 			$total_posts = $count_query->found_posts;
262 262
 		}
263 263
 
264
-		remove_filter( 'posts_clauses', [ $this, 'add_query_clauses' ], 10 );
264
+		remove_filter('posts_clauses', [$this, 'add_query_clauses'], 10);
265 265
 
266 266
 		return [
267 267
 			'results' => $results,
268 268
 			'total'   => (int) $total_posts,
269
-			'pages'   => $query->query_vars['posts_per_page'] > 0 ? (int) ceil( $total_posts / (int) $query->query_vars['posts_per_page'] ) : 1,
269
+			'pages'   => $query->query_vars['posts_per_page'] > 0 ? (int) ceil($total_posts / (int) $query->query_vars['posts_per_page']) : 1,
270 270
 		];
271 271
 	}
272 272
 
@@ -276,11 +276,11 @@  discard block
 block discarded – undo
276 276
 	 * @param \WP_REST_Request $request Request data.
277 277
 	 * @return array
278 278
 	 */
279
-	public function get_objects( $request ) {
280
-		$results = $this->get_results( $request );
279
+	public function get_objects($request) {
280
+		$results = $this->get_results($request);
281 281
 
282 282
 		return [
283
-			'objects' => array_map( 'wc_get_product', $results['results'] ),
283
+			'objects' => array_map('wc_get_product', $results['results']),
284 284
 			'total'   => $results['total'],
285 285
 			'pages'   => $results['pages'],
286 286
 		];
@@ -294,7 +294,7 @@  discard block
 block discarded – undo
294 294
 	public function get_last_modified() {
295 295
 		global $wpdb;
296 296
 
297
-		return strtotime( $wpdb->get_var( "SELECT MAX( post_modified_gmt ) FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' );" ) );
297
+		return strtotime($wpdb->get_var("SELECT MAX( post_modified_gmt ) FROM {$wpdb->posts} WHERE post_type IN ( 'product', 'product_variation' );"));
298 298
 	}
299 299
 
300 300
 	/**
@@ -304,38 +304,38 @@  discard block
 block discarded – undo
304 304
 	 * @param \WC_Query $wp_query WC_Query object.
305 305
 	 * @return array
306 306
 	 */
307
-	public function add_query_clauses( $args, $wp_query ) {
307
+	public function add_query_clauses($args, $wp_query) {
308 308
 		global $wpdb;
309 309
 
310
-		if ( $wp_query->get( 'search' ) ) {
311
-			$search         = '%' . $wpdb->esc_like( $wp_query->get( 'search' ) ) . '%';
310
+		if ($wp_query->get('search')) {
311
+			$search         = '%' . $wpdb->esc_like($wp_query->get('search')) . '%';
312 312
 			$search_query   = wc_product_sku_enabled()
313
-				? $wpdb->prepare( " AND ( $wpdb->posts.post_title LIKE %s OR wc_product_meta_lookup.sku LIKE %s ) ", $search, $search )
314
-				: $wpdb->prepare( " AND $wpdb->posts.post_title LIKE %s ", $search );
313
+				? $wpdb->prepare(" AND ( $wpdb->posts.post_title LIKE %s OR wc_product_meta_lookup.sku LIKE %s ) ", $search, $search)
314
+				: $wpdb->prepare(" AND $wpdb->posts.post_title LIKE %s ", $search);
315 315
 			$args['where'] .= $search_query;
316
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
316
+			$args['join']   = $this->append_product_sorting_table_join($args['join']);
317 317
 		}
318 318
 
319
-		if ( $wp_query->get( 'sku' ) ) {
320
-			$skus = explode( ',', $wp_query->get( 'sku' ) );
319
+		if ($wp_query->get('sku')) {
320
+			$skus = explode(',', $wp_query->get('sku'));
321 321
 			// Include the current string as a SKU too.
322
-			if ( 1 < count( $skus ) ) {
323
-				$skus[] = $wp_query->get( 'sku' );
322
+			if (1 < count($skus)) {
323
+				$skus[] = $wp_query->get('sku');
324 324
 			}
325
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
326
-			$args['where'] .= ' AND wc_product_meta_lookup.sku IN ("' . implode( '","', array_map( 'esc_sql', $skus ) ) . '")';
325
+			$args['join']   = $this->append_product_sorting_table_join($args['join']);
326
+			$args['where'] .= ' AND wc_product_meta_lookup.sku IN ("' . implode('","', array_map('esc_sql', $skus)) . '")';
327 327
 		}
328 328
 
329
-		if ( $wp_query->get( 'stock_status' ) ) {
330
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
331
-			$args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode( '","', array_map( 'esc_sql', $wp_query->get( 'stock_status' ) ) ) . '")';
332
-		} elseif ( 'yes' === get_option( 'woocommerce_hide_out_of_stock_items' ) ) {
333
-			$args['join']   = $this->append_product_sorting_table_join( $args['join'] );
329
+		if ($wp_query->get('stock_status')) {
330
+			$args['join']   = $this->append_product_sorting_table_join($args['join']);
331
+			$args['where'] .= ' AND wc_product_meta_lookup.stock_status IN ("' . implode('","', array_map('esc_sql', $wp_query->get('stock_status'))) . '")';
332
+		} elseif ('yes' === get_option('woocommerce_hide_out_of_stock_items')) {
333
+			$args['join']   = $this->append_product_sorting_table_join($args['join']);
334 334
 			$args['where'] .= ' AND wc_product_meta_lookup.stock_status NOT IN ("outofstock")';
335 335
 		}
336 336
 
337
-		if ( $wp_query->get( 'min_price' ) || $wp_query->get( 'max_price' ) ) {
338
-			$args = $this->add_price_filter_clauses( $args, $wp_query );
337
+		if ($wp_query->get('min_price') || $wp_query->get('max_price')) {
338
+			$args = $this->add_price_filter_clauses($args, $wp_query);
339 339
 		}
340 340
 
341 341
 		return $args;
@@ -348,29 +348,29 @@  discard block
 block discarded – undo
348 348
 	 * @param \WC_Query $wp_query WC_Query object.
349 349
 	 * @return array
350 350
 	 */
351
-	protected function add_price_filter_clauses( $args, $wp_query ) {
351
+	protected function add_price_filter_clauses($args, $wp_query) {
352 352
 		global $wpdb;
353 353
 
354 354
 		$adjust_for_taxes = $this->adjust_price_filters_for_displayed_taxes();
355
-		$args['join']     = $this->append_product_sorting_table_join( $args['join'] );
355
+		$args['join']     = $this->append_product_sorting_table_join($args['join']);
356 356
 
357
-		if ( $wp_query->get( 'min_price' ) ) {
358
-			$min_price_filter = $this->prepare_price_filter( $wp_query->get( 'min_price' ) );
357
+		if ($wp_query->get('min_price')) {
358
+			$min_price_filter = $this->prepare_price_filter($wp_query->get('min_price'));
359 359
 
360
-			if ( $adjust_for_taxes ) {
361
-				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $min_price_filter, 'min_price', '>=' );
360
+			if ($adjust_for_taxes) {
361
+				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes($min_price_filter, 'min_price', '>=');
362 362
 			} else {
363
-				$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.min_price >= %f ', $min_price_filter );
363
+				$args['where'] .= $wpdb->prepare(' AND wc_product_meta_lookup.min_price >= %f ', $min_price_filter);
364 364
 			}
365 365
 		}
366 366
 
367
-		if ( $wp_query->get( 'max_price' ) ) {
368
-			$max_price_filter = $this->prepare_price_filter( $wp_query->get( 'max_price' ) );
367
+		if ($wp_query->get('max_price')) {
368
+			$max_price_filter = $this->prepare_price_filter($wp_query->get('max_price'));
369 369
 
370
-			if ( $adjust_for_taxes ) {
371
-				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes( $max_price_filter, 'max_price', '<=' );
370
+			if ($adjust_for_taxes) {
371
+				$args['where'] .= $this->get_price_filter_query_for_displayed_taxes($max_price_filter, 'max_price', '<=');
372 372
 			} else {
373
-				$args['where'] .= $wpdb->prepare( ' AND wc_product_meta_lookup.max_price <= %f ', $max_price_filter );
373
+				$args['where'] .= $wpdb->prepare(' AND wc_product_meta_lookup.max_price <= %f ', $max_price_filter);
374 374
 			}
375 375
 		}
376 376
 
@@ -385,23 +385,23 @@  discard block
 block discarded – undo
385 385
 	 * @param string $operator Comparison operator for column.
386 386
 	 * @return string Constructed query.
387 387
 	 */
388
-	protected function get_price_filter_query_for_displayed_taxes( $price_filter, $column = 'min_price', $operator = '>=' ) {
388
+	protected function get_price_filter_query_for_displayed_taxes($price_filter, $column = 'min_price', $operator = '>=') {
389 389
 		global $wpdb;
390 390
 
391 391
 		// Select only used tax classes to avoid unwanted calculations.
392
-		$product_tax_classes = $wpdb->get_col( "SELECT DISTINCT tax_class FROM {$wpdb->wc_product_meta_lookup};" );
392
+		$product_tax_classes = $wpdb->get_col("SELECT DISTINCT tax_class FROM {$wpdb->wc_product_meta_lookup};");
393 393
 
394
-		if ( empty( $product_tax_classes ) ) {
394
+		if (empty($product_tax_classes)) {
395 395
 			return '';
396 396
 		}
397 397
 
398 398
 		$or_queries = [];
399 399
 
400 400
 		// We need to adjust the filter for each possible tax class and combine the queries into one.
401
-		foreach ( $product_tax_classes as $tax_class ) {
402
-			$adjusted_price_filter = $this->adjust_price_filter_for_tax_class( $price_filter, $tax_class );
401
+		foreach ($product_tax_classes as $tax_class) {
402
+			$adjusted_price_filter = $this->adjust_price_filter_for_tax_class($price_filter, $tax_class);
403 403
 			$or_queries[]          = $wpdb->prepare(
404
-				'( wc_product_meta_lookup.tax_class = %s AND wc_product_meta_lookup.`' . esc_sql( $column ) . '` ' . esc_sql( $operator ) . ' %f )',
404
+				'( wc_product_meta_lookup.tax_class = %s AND wc_product_meta_lookup.`' . esc_sql($column) . '` ' . esc_sql($operator) . ' %f )',
405 405
 				$tax_class,
406 406
 				$adjusted_price_filter
407 407
 			);
@@ -410,8 +410,8 @@  discard block
 block discarded – undo
410 410
 		// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared
411 411
 		return $wpdb->prepare(
412 412
 			' AND (
413
-				wc_product_meta_lookup.tax_status = "taxable" AND ( 0=1 OR ' . implode( ' OR ', $or_queries ) . ')
414
-				OR ( wc_product_meta_lookup.tax_status != "taxable" AND wc_product_meta_lookup.`' . esc_sql( $column ) . '` ' . esc_sql( $operator ) . ' %f )
413
+				wc_product_meta_lookup.tax_status = "taxable" AND ( 0=1 OR ' . implode(' OR ', $or_queries) . ')
414
+				OR ( wc_product_meta_lookup.tax_status != "taxable" AND wc_product_meta_lookup.`' . esc_sql($column) . '` ' . esc_sql($operator) . ' %f )
415 415
 			) ',
416 416
 			$price_filter
417 417
 		);
@@ -427,7 +427,7 @@  discard block
 block discarded – undo
427 427
 	 * @return boolean
428 428
 	 */
429 429
 	protected function adjust_price_filters_for_displayed_taxes() {
430
-		$display  = get_option( 'woocommerce_tax_display_shop' );
430
+		$display  = get_option('woocommerce_tax_display_shop');
431 431
 		$database = wc_prices_include_tax() ? 'incl' : 'excl';
432 432
 
433 433
 		return $display !== $database;
@@ -439,8 +439,8 @@  discard block
 block discarded – undo
439 439
 	 * @param string|int $price_filter Raw price filter in subunit format.
440 440
 	 * @return float Price filter in decimal format.
441 441
 	 */
442
-	protected function prepare_price_filter( $price_filter ) {
443
-		return floatval( $price_filter / ( 10 ** wc_get_price_decimals() ) );
442
+	protected function prepare_price_filter($price_filter) {
443
+		return floatval($price_filter / (10 ** wc_get_price_decimals()));
444 444
 	}
445 445
 
446 446
 	/**
@@ -452,13 +452,13 @@  discard block
 block discarded – undo
452 452
 	 * @param string $tax_class Tax class for adjustment.
453 453
 	 * @return float
454 454
 	 */
455
-	protected function adjust_price_filter_for_tax_class( $price_filter, $tax_class ) {
456
-		$tax_display    = get_option( 'woocommerce_tax_display_shop' );
457
-		$tax_rates      = WC_Tax::get_rates( $tax_class );
458
-		$base_tax_rates = WC_Tax::get_base_tax_rates( $tax_class );
455
+	protected function adjust_price_filter_for_tax_class($price_filter, $tax_class) {
456
+		$tax_display    = get_option('woocommerce_tax_display_shop');
457
+		$tax_rates      = WC_Tax::get_rates($tax_class);
458
+		$base_tax_rates = WC_Tax::get_base_tax_rates($tax_class);
459 459
 
460 460
 		// If prices are shown incl. tax, we want to remove the taxes from the filter amount to match prices stored excl. tax.
461
-		if ( 'incl' === $tax_display ) {
461
+		if ('incl' === $tax_display) {
462 462
 			/**
463 463
 			 * Filters if taxes should be removed from locations outside the store base location.
464 464
 			 *
@@ -471,14 +471,14 @@  discard block
 block discarded – undo
471 471
 			 * @param boolean $adjust_non_base_location_prices True by default.
472 472
 			 * @return boolean
473 473
 			 */
474
-			$taxes = apply_filters( 'woocommerce_adjust_non_base_location_prices', true ) ? WC_Tax::calc_tax( $price_filter, $base_tax_rates, true ) : WC_Tax::calc_tax( $price_filter, $tax_rates, true );
475
-			return $price_filter - array_sum( $taxes );
474
+			$taxes = apply_filters('woocommerce_adjust_non_base_location_prices', true) ? WC_Tax::calc_tax($price_filter, $base_tax_rates, true) : WC_Tax::calc_tax($price_filter, $tax_rates, true);
475
+			return $price_filter - array_sum($taxes);
476 476
 		}
477 477
 
478 478
 		// If prices are shown excl. tax, add taxes to match the prices stored in the DB.
479
-		$taxes = WC_Tax::calc_tax( $price_filter, $tax_rates, false );
479
+		$taxes = WC_Tax::calc_tax($price_filter, $tax_rates, false);
480 480
 
481
-		return $price_filter + array_sum( $taxes );
481
+		return $price_filter + array_sum($taxes);
482 482
 	}
483 483
 
484 484
 	/**
@@ -487,10 +487,10 @@  discard block
 block discarded – undo
487 487
 	 * @param string $sql SQL join.
488 488
 	 * @return string
489 489
 	 */
490
-	protected function append_product_sorting_table_join( $sql ) {
490
+	protected function append_product_sorting_table_join($sql) {
491 491
 		global $wpdb;
492 492
 
493
-		if ( ! strstr( $sql, 'wc_product_meta_lookup' ) ) {
493
+		if (!strstr($sql, 'wc_product_meta_lookup')) {
494 494
 			$sql .= " LEFT JOIN {$wpdb->wc_product_meta_lookup} wc_product_meta_lookup ON $wpdb->posts.ID = wc_product_meta_lookup.product_id ";
495 495
 		}
496 496
 		return $sql;
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/QuantityLimits.php 2 patches
Indentation   +195 added lines, -195 removed lines patch added patch discarded remove patch
@@ -10,199 +10,199 @@
 block discarded – undo
10 10
  * Returns limits for products and cart items when using the StoreAPI and supporting classes.
11 11
  */
12 12
 final class QuantityLimits {
13
-	use DraftOrderTrait;
14
-
15
-	/**
16
-	 * Get quantity limits (min, max, step/multiple) for a product or cart item.
17
-	 *
18
-	 * @param array $cart_item A cart item array.
19
-	 * @return array
20
-	 */
21
-	public function get_cart_item_quantity_limits( $cart_item ) {
22
-		$product = $cart_item['data'] ?? false;
23
-
24
-		if ( ! $product instanceof \WC_Product ) {
25
-			return [
26
-				'minimum'     => 1,
27
-				'maximum'     => null,
28
-				'multiple_of' => 1,
29
-				'editable'    => true,
30
-			];
31
-		}
32
-
33
-		$multiple_of = (int) $this->filter_value( 1, 'multiple_of', $cart_item );
34
-		$minimum     = (int) $this->filter_value( 1, 'minimum', $cart_item );
35
-		$maximum     = (int) $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $cart_item );
36
-		$editable    = (bool) $this->filter_value( ! $product->is_sold_individually(), 'editable', $cart_item );
37
-
38
-		return [
39
-			'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
40
-			'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
41
-			'multiple_of' => $multiple_of,
42
-			'editable'    => $editable,
43
-		];
44
-	}
45
-
46
-	/**
47
-	 * Get limits for product add to cart forms.
48
-	 *
49
-	 * @param \WC_Product $product Product instance.
50
-	 * @return array
51
-	 */
52
-	public function get_add_to_cart_limits( \WC_Product $product ) {
53
-		$multiple_of = $this->filter_value( 1, 'multiple_of', $product );
54
-		$minimum     = $this->filter_value( 1, 'minimum', $product );
55
-		$maximum     = $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $product );
56
-
57
-		return [
58
-			'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
59
-			'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
60
-			'multiple_of' => $multiple_of,
61
-		];
62
-	}
63
-
64
-	/**
65
-	 * Return a number using the closest multiple of another number. Used to enforce step/multiple values.
66
-	 *
67
-	 * @param int    $number Number to round.
68
-	 * @param int    $multiple_of The multiple.
69
-	 * @param string $rounding_function ceil, floor, or round.
70
-	 * @return int
71
-	 */
72
-	public function limit_to_multiple( int $number, int $multiple_of, string $rounding_function = 'round' ) {
73
-		if ( $multiple_of <= 1 ) {
74
-			return $number;
75
-		}
76
-		$rounding_function = in_array( $rounding_function, [ 'ceil', 'floor', 'round' ], true ) ? $rounding_function : 'round';
77
-		return $rounding_function( $number / $multiple_of ) * $multiple_of;
78
-	}
79
-
80
-	/**
81
-	 * Check that a given quantity is valid according to any limits in place.
82
-	 *
83
-	 * @param integer           $quantity Quantity to validate.
84
-	 * @param \WC_Product|array $cart_item Cart item.
85
-	 * @return \WP_Error|true
86
-	 */
87
-	public function validate_cart_item_quantity( $quantity, $cart_item ) {
88
-		$limits = $this->get_cart_item_quantity_limits( $cart_item );
89
-
90
-		if ( ! $limits['editable'] ) {
91
-			return new \WP_Error(
92
-				'readonly_quantity',
93
-				__( 'This item is already in the cart and its quantity cannot be edited', 'woocommerce' )
94
-			);
95
-		}
96
-
97
-		if ( $quantity < $limits['minimum'] ) {
98
-			return new \WP_Error(
99
-				'invalid_quantity',
100
-				sprintf(
101
-					// Translators: %s amount.
102
-					__( 'The minimum quantity that can be added to the cart is %s', 'woocommerce' ),
103
-					$limits['minimum']
104
-				)
105
-			);
106
-		}
107
-
108
-		if ( $quantity > $limits['maximum'] ) {
109
-			return new \WP_Error(
110
-				'invalid_quantity',
111
-				sprintf(
112
-					// Translators: %s amount.
113
-					__( 'The maximum quantity that can be added to the cart is %s', 'woocommerce' ),
114
-					$limits['maximum']
115
-				)
116
-			);
117
-		}
118
-
119
-		if ( $quantity % $limits['multiple_of'] ) {
120
-			return new \WP_Error(
121
-				'invalid_quantity',
122
-				sprintf(
123
-					// Translators: %s amount.
124
-					__( 'The quantity added to the cart must be a multiple of %s', 'woocommerce' ),
125
-					$limits['multiple_of']
126
-				)
127
-			);
128
-		}
129
-
130
-		return true;
131
-	}
132
-
133
-	/**
134
-	 * Get the limit for the total number of a product allowed in the cart.
135
-	 *
136
-	 * This is based on product properties, including remaining stock, and defaults to a maximum of 9999 of any product
137
-	 * in the cart at once.
138
-	 *
139
-	 * @param \WC_Product $product Product instance.
140
-	 * @return int
141
-	 */
142
-	protected function get_product_quantity_limit( \WC_Product $product ) {
143
-		$limits = [ 9999 ];
144
-
145
-		if ( $product->is_sold_individually() ) {
146
-			$limits[] = 1;
147
-		} elseif ( ! $product->backorders_allowed() ) {
148
-			$limits[] = $this->get_remaining_stock( $product );
149
-		}
150
-
151
-		/**
152
-		 * Filters the quantity limit for a product being added to the cart via the Store API.
153
-		 *
154
-		 * Filters the variation option name for custom option slugs.
155
-		 *
156
-		 * @param integer $quantity_limit Quantity limit which defaults to 9999 unless sold individually.
157
-		 * @param \WC_Product $product Product instance.
158
-		 * @return integer
159
-		 */
160
-		return apply_filters( 'woocommerce_store_api_product_quantity_limit', max( min( array_filter( $limits ) ), 1 ), $product );
161
-	}
162
-
163
-	/**
164
-	 * Returns the remaining stock for a product if it has stock.
165
-	 *
166
-	 * This also factors in draft orders.
167
-	 *
168
-	 * @param \WC_Product $product Product instance.
169
-	 * @return integer|null
170
-	 */
171
-	protected function get_remaining_stock( \WC_Product $product ) {
172
-		if ( is_null( $product->get_stock_quantity() ) ) {
173
-			return null;
174
-		}
175
-
176
-		$reserve_stock  = new ReserveStock();
177
-		$reserved_stock = $reserve_stock->get_reserved_stock( $product, $this->get_draft_order_id() );
178
-
179
-		return $product->get_stock_quantity() - $reserved_stock;
180
-	}
181
-
182
-	/**
183
-	 * Get a quantity for a product or cart item by running it through a filter hook.
184
-	 *
185
-	 * @param int|null          $value Value to filter.
186
-	 * @param string            $value_type Type of value. Used for filter suffix.
187
-	 * @param \WC_Product|array $cart_item_or_product Either a cart item or a product instance.
188
-	 * @return mixed
189
-	 */
190
-	protected function filter_value( $value, string $value_type, $cart_item_or_product ) {
191
-		$is_product = $cart_item_or_product instanceof \WC_Product;
192
-		$product    = $is_product ? $cart_item_or_product : $cart_item_or_product['data'];
193
-		$cart_item  = $is_product ? null : $cart_item_or_product;
194
-		/**
195
-		 * Filters the quantity minimum for a cart item in Store API. This allows extensions to control the minimum qty
196
-		 * of items already within the cart.
197
-		 *
198
-		 * The suffix of the hook will vary depending on the value being filtered.
199
-		 * For example, minimum, maximum, multiple_of, editable.
200
-		 *
201
-		 * @param mixed $value The value being filtered.
202
-		 * @param \WC_Product $product The product object.
203
-		 * @param array|null $cart_item The cart item if the product exists in the cart, or null.
204
-		 * @return mixed
205
-		 */
206
-		return apply_filters( "woocommerce_store_api_product_quantity_{$value_type}", $value, $product, $cart_item );
207
-	}
13
+    use DraftOrderTrait;
14
+
15
+    /**
16
+     * Get quantity limits (min, max, step/multiple) for a product or cart item.
17
+     *
18
+     * @param array $cart_item A cart item array.
19
+     * @return array
20
+     */
21
+    public function get_cart_item_quantity_limits( $cart_item ) {
22
+        $product = $cart_item['data'] ?? false;
23
+
24
+        if ( ! $product instanceof \WC_Product ) {
25
+            return [
26
+                'minimum'     => 1,
27
+                'maximum'     => null,
28
+                'multiple_of' => 1,
29
+                'editable'    => true,
30
+            ];
31
+        }
32
+
33
+        $multiple_of = (int) $this->filter_value( 1, 'multiple_of', $cart_item );
34
+        $minimum     = (int) $this->filter_value( 1, 'minimum', $cart_item );
35
+        $maximum     = (int) $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $cart_item );
36
+        $editable    = (bool) $this->filter_value( ! $product->is_sold_individually(), 'editable', $cart_item );
37
+
38
+        return [
39
+            'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
40
+            'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
41
+            'multiple_of' => $multiple_of,
42
+            'editable'    => $editable,
43
+        ];
44
+    }
45
+
46
+    /**
47
+     * Get limits for product add to cart forms.
48
+     *
49
+     * @param \WC_Product $product Product instance.
50
+     * @return array
51
+     */
52
+    public function get_add_to_cart_limits( \WC_Product $product ) {
53
+        $multiple_of = $this->filter_value( 1, 'multiple_of', $product );
54
+        $minimum     = $this->filter_value( 1, 'minimum', $product );
55
+        $maximum     = $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $product );
56
+
57
+        return [
58
+            'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
59
+            'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
60
+            'multiple_of' => $multiple_of,
61
+        ];
62
+    }
63
+
64
+    /**
65
+     * Return a number using the closest multiple of another number. Used to enforce step/multiple values.
66
+     *
67
+     * @param int    $number Number to round.
68
+     * @param int    $multiple_of The multiple.
69
+     * @param string $rounding_function ceil, floor, or round.
70
+     * @return int
71
+     */
72
+    public function limit_to_multiple( int $number, int $multiple_of, string $rounding_function = 'round' ) {
73
+        if ( $multiple_of <= 1 ) {
74
+            return $number;
75
+        }
76
+        $rounding_function = in_array( $rounding_function, [ 'ceil', 'floor', 'round' ], true ) ? $rounding_function : 'round';
77
+        return $rounding_function( $number / $multiple_of ) * $multiple_of;
78
+    }
79
+
80
+    /**
81
+     * Check that a given quantity is valid according to any limits in place.
82
+     *
83
+     * @param integer           $quantity Quantity to validate.
84
+     * @param \WC_Product|array $cart_item Cart item.
85
+     * @return \WP_Error|true
86
+     */
87
+    public function validate_cart_item_quantity( $quantity, $cart_item ) {
88
+        $limits = $this->get_cart_item_quantity_limits( $cart_item );
89
+
90
+        if ( ! $limits['editable'] ) {
91
+            return new \WP_Error(
92
+                'readonly_quantity',
93
+                __( 'This item is already in the cart and its quantity cannot be edited', 'woocommerce' )
94
+            );
95
+        }
96
+
97
+        if ( $quantity < $limits['minimum'] ) {
98
+            return new \WP_Error(
99
+                'invalid_quantity',
100
+                sprintf(
101
+                    // Translators: %s amount.
102
+                    __( 'The minimum quantity that can be added to the cart is %s', 'woocommerce' ),
103
+                    $limits['minimum']
104
+                )
105
+            );
106
+        }
107
+
108
+        if ( $quantity > $limits['maximum'] ) {
109
+            return new \WP_Error(
110
+                'invalid_quantity',
111
+                sprintf(
112
+                    // Translators: %s amount.
113
+                    __( 'The maximum quantity that can be added to the cart is %s', 'woocommerce' ),
114
+                    $limits['maximum']
115
+                )
116
+            );
117
+        }
118
+
119
+        if ( $quantity % $limits['multiple_of'] ) {
120
+            return new \WP_Error(
121
+                'invalid_quantity',
122
+                sprintf(
123
+                    // Translators: %s amount.
124
+                    __( 'The quantity added to the cart must be a multiple of %s', 'woocommerce' ),
125
+                    $limits['multiple_of']
126
+                )
127
+            );
128
+        }
129
+
130
+        return true;
131
+    }
132
+
133
+    /**
134
+     * Get the limit for the total number of a product allowed in the cart.
135
+     *
136
+     * This is based on product properties, including remaining stock, and defaults to a maximum of 9999 of any product
137
+     * in the cart at once.
138
+     *
139
+     * @param \WC_Product $product Product instance.
140
+     * @return int
141
+     */
142
+    protected function get_product_quantity_limit( \WC_Product $product ) {
143
+        $limits = [ 9999 ];
144
+
145
+        if ( $product->is_sold_individually() ) {
146
+            $limits[] = 1;
147
+        } elseif ( ! $product->backorders_allowed() ) {
148
+            $limits[] = $this->get_remaining_stock( $product );
149
+        }
150
+
151
+        /**
152
+         * Filters the quantity limit for a product being added to the cart via the Store API.
153
+         *
154
+         * Filters the variation option name for custom option slugs.
155
+         *
156
+         * @param integer $quantity_limit Quantity limit which defaults to 9999 unless sold individually.
157
+         * @param \WC_Product $product Product instance.
158
+         * @return integer
159
+         */
160
+        return apply_filters( 'woocommerce_store_api_product_quantity_limit', max( min( array_filter( $limits ) ), 1 ), $product );
161
+    }
162
+
163
+    /**
164
+     * Returns the remaining stock for a product if it has stock.
165
+     *
166
+     * This also factors in draft orders.
167
+     *
168
+     * @param \WC_Product $product Product instance.
169
+     * @return integer|null
170
+     */
171
+    protected function get_remaining_stock( \WC_Product $product ) {
172
+        if ( is_null( $product->get_stock_quantity() ) ) {
173
+            return null;
174
+        }
175
+
176
+        $reserve_stock  = new ReserveStock();
177
+        $reserved_stock = $reserve_stock->get_reserved_stock( $product, $this->get_draft_order_id() );
178
+
179
+        return $product->get_stock_quantity() - $reserved_stock;
180
+    }
181
+
182
+    /**
183
+     * Get a quantity for a product or cart item by running it through a filter hook.
184
+     *
185
+     * @param int|null          $value Value to filter.
186
+     * @param string            $value_type Type of value. Used for filter suffix.
187
+     * @param \WC_Product|array $cart_item_or_product Either a cart item or a product instance.
188
+     * @return mixed
189
+     */
190
+    protected function filter_value( $value, string $value_type, $cart_item_or_product ) {
191
+        $is_product = $cart_item_or_product instanceof \WC_Product;
192
+        $product    = $is_product ? $cart_item_or_product : $cart_item_or_product['data'];
193
+        $cart_item  = $is_product ? null : $cart_item_or_product;
194
+        /**
195
+         * Filters the quantity minimum for a cart item in Store API. This allows extensions to control the minimum qty
196
+         * of items already within the cart.
197
+         *
198
+         * The suffix of the hook will vary depending on the value being filtered.
199
+         * For example, minimum, maximum, multiple_of, editable.
200
+         *
201
+         * @param mixed $value The value being filtered.
202
+         * @param \WC_Product $product The product object.
203
+         * @param array|null $cart_item The cart item if the product exists in the cart, or null.
204
+         * @return mixed
205
+         */
206
+        return apply_filters( "woocommerce_store_api_product_quantity_{$value_type}", $value, $product, $cart_item );
207
+    }
208 208
 }
Please login to merge, or discard this patch.
Spacing   +39 added lines, -39 removed lines patch added patch discarded remove patch
@@ -18,10 +18,10 @@  discard block
 block discarded – undo
18 18
 	 * @param array $cart_item A cart item array.
19 19
 	 * @return array
20 20
 	 */
21
-	public function get_cart_item_quantity_limits( $cart_item ) {
21
+	public function get_cart_item_quantity_limits($cart_item) {
22 22
 		$product = $cart_item['data'] ?? false;
23 23
 
24
-		if ( ! $product instanceof \WC_Product ) {
24
+		if (!$product instanceof \WC_Product) {
25 25
 			return [
26 26
 				'minimum'     => 1,
27 27
 				'maximum'     => null,
@@ -30,14 +30,14 @@  discard block
 block discarded – undo
30 30
 			];
31 31
 		}
32 32
 
33
-		$multiple_of = (int) $this->filter_value( 1, 'multiple_of', $cart_item );
34
-		$minimum     = (int) $this->filter_value( 1, 'minimum', $cart_item );
35
-		$maximum     = (int) $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $cart_item );
36
-		$editable    = (bool) $this->filter_value( ! $product->is_sold_individually(), 'editable', $cart_item );
33
+		$multiple_of = (int) $this->filter_value(1, 'multiple_of', $cart_item);
34
+		$minimum     = (int) $this->filter_value(1, 'minimum', $cart_item);
35
+		$maximum     = (int) $this->filter_value($this->get_product_quantity_limit($product), 'maximum', $cart_item);
36
+		$editable    = (bool) $this->filter_value(!$product->is_sold_individually(), 'editable', $cart_item);
37 37
 
38 38
 		return [
39
-			'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
40
-			'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
39
+			'minimum'     => $this->limit_to_multiple($minimum, $multiple_of, 'ceil'),
40
+			'maximum'     => $this->limit_to_multiple($maximum, $multiple_of, 'floor'),
41 41
 			'multiple_of' => $multiple_of,
42 42
 			'editable'    => $editable,
43 43
 		];
@@ -49,14 +49,14 @@  discard block
 block discarded – undo
49 49
 	 * @param \WC_Product $product Product instance.
50 50
 	 * @return array
51 51
 	 */
52
-	public function get_add_to_cart_limits( \WC_Product $product ) {
53
-		$multiple_of = $this->filter_value( 1, 'multiple_of', $product );
54
-		$minimum     = $this->filter_value( 1, 'minimum', $product );
55
-		$maximum     = $this->filter_value( $this->get_product_quantity_limit( $product ), 'maximum', $product );
52
+	public function get_add_to_cart_limits(\WC_Product $product) {
53
+		$multiple_of = $this->filter_value(1, 'multiple_of', $product);
54
+		$minimum     = $this->filter_value(1, 'minimum', $product);
55
+		$maximum     = $this->filter_value($this->get_product_quantity_limit($product), 'maximum', $product);
56 56
 
57 57
 		return [
58
-			'minimum'     => $this->limit_to_multiple( $minimum, $multiple_of, 'ceil' ),
59
-			'maximum'     => $this->limit_to_multiple( $maximum, $multiple_of, 'floor' ),
58
+			'minimum'     => $this->limit_to_multiple($minimum, $multiple_of, 'ceil'),
59
+			'maximum'     => $this->limit_to_multiple($maximum, $multiple_of, 'floor'),
60 60
 			'multiple_of' => $multiple_of,
61 61
 		];
62 62
 	}
@@ -69,12 +69,12 @@  discard block
 block discarded – undo
69 69
 	 * @param string $rounding_function ceil, floor, or round.
70 70
 	 * @return int
71 71
 	 */
72
-	public function limit_to_multiple( int $number, int $multiple_of, string $rounding_function = 'round' ) {
73
-		if ( $multiple_of <= 1 ) {
72
+	public function limit_to_multiple(int $number, int $multiple_of, string $rounding_function = 'round') {
73
+		if ($multiple_of <= 1) {
74 74
 			return $number;
75 75
 		}
76
-		$rounding_function = in_array( $rounding_function, [ 'ceil', 'floor', 'round' ], true ) ? $rounding_function : 'round';
77
-		return $rounding_function( $number / $multiple_of ) * $multiple_of;
76
+		$rounding_function = in_array($rounding_function, ['ceil', 'floor', 'round'], true) ? $rounding_function : 'round';
77
+		return $rounding_function($number / $multiple_of) * $multiple_of;
78 78
 	}
79 79
 
80 80
 	/**
@@ -84,44 +84,44 @@  discard block
 block discarded – undo
84 84
 	 * @param \WC_Product|array $cart_item Cart item.
85 85
 	 * @return \WP_Error|true
86 86
 	 */
87
-	public function validate_cart_item_quantity( $quantity, $cart_item ) {
88
-		$limits = $this->get_cart_item_quantity_limits( $cart_item );
87
+	public function validate_cart_item_quantity($quantity, $cart_item) {
88
+		$limits = $this->get_cart_item_quantity_limits($cart_item);
89 89
 
90
-		if ( ! $limits['editable'] ) {
90
+		if (!$limits['editable']) {
91 91
 			return new \WP_Error(
92 92
 				'readonly_quantity',
93
-				__( 'This item is already in the cart and its quantity cannot be edited', 'woocommerce' )
93
+				__('This item is already in the cart and its quantity cannot be edited', 'woocommerce')
94 94
 			);
95 95
 		}
96 96
 
97
-		if ( $quantity < $limits['minimum'] ) {
97
+		if ($quantity < $limits['minimum']) {
98 98
 			return new \WP_Error(
99 99
 				'invalid_quantity',
100 100
 				sprintf(
101 101
 					// Translators: %s amount.
102
-					__( 'The minimum quantity that can be added to the cart is %s', 'woocommerce' ),
102
+					__('The minimum quantity that can be added to the cart is %s', 'woocommerce'),
103 103
 					$limits['minimum']
104 104
 				)
105 105
 			);
106 106
 		}
107 107
 
108
-		if ( $quantity > $limits['maximum'] ) {
108
+		if ($quantity > $limits['maximum']) {
109 109
 			return new \WP_Error(
110 110
 				'invalid_quantity',
111 111
 				sprintf(
112 112
 					// Translators: %s amount.
113
-					__( 'The maximum quantity that can be added to the cart is %s', 'woocommerce' ),
113
+					__('The maximum quantity that can be added to the cart is %s', 'woocommerce'),
114 114
 					$limits['maximum']
115 115
 				)
116 116
 			);
117 117
 		}
118 118
 
119
-		if ( $quantity % $limits['multiple_of'] ) {
119
+		if ($quantity % $limits['multiple_of']) {
120 120
 			return new \WP_Error(
121 121
 				'invalid_quantity',
122 122
 				sprintf(
123 123
 					// Translators: %s amount.
124
-					__( 'The quantity added to the cart must be a multiple of %s', 'woocommerce' ),
124
+					__('The quantity added to the cart must be a multiple of %s', 'woocommerce'),
125 125
 					$limits['multiple_of']
126 126
 				)
127 127
 			);
@@ -139,13 +139,13 @@  discard block
 block discarded – undo
139 139
 	 * @param \WC_Product $product Product instance.
140 140
 	 * @return int
141 141
 	 */
142
-	protected function get_product_quantity_limit( \WC_Product $product ) {
143
-		$limits = [ 9999 ];
142
+	protected function get_product_quantity_limit(\WC_Product $product) {
143
+		$limits = [9999];
144 144
 
145
-		if ( $product->is_sold_individually() ) {
145
+		if ($product->is_sold_individually()) {
146 146
 			$limits[] = 1;
147
-		} elseif ( ! $product->backorders_allowed() ) {
148
-			$limits[] = $this->get_remaining_stock( $product );
147
+		} elseif (!$product->backorders_allowed()) {
148
+			$limits[] = $this->get_remaining_stock($product);
149 149
 		}
150 150
 
151 151
 		/**
@@ -157,7 +157,7 @@  discard block
 block discarded – undo
157 157
 		 * @param \WC_Product $product Product instance.
158 158
 		 * @return integer
159 159
 		 */
160
-		return apply_filters( 'woocommerce_store_api_product_quantity_limit', max( min( array_filter( $limits ) ), 1 ), $product );
160
+		return apply_filters('woocommerce_store_api_product_quantity_limit', max(min(array_filter($limits)), 1), $product);
161 161
 	}
162 162
 
163 163
 	/**
@@ -168,13 +168,13 @@  discard block
 block discarded – undo
168 168
 	 * @param \WC_Product $product Product instance.
169 169
 	 * @return integer|null
170 170
 	 */
171
-	protected function get_remaining_stock( \WC_Product $product ) {
172
-		if ( is_null( $product->get_stock_quantity() ) ) {
171
+	protected function get_remaining_stock(\WC_Product $product) {
172
+		if (is_null($product->get_stock_quantity())) {
173 173
 			return null;
174 174
 		}
175 175
 
176 176
 		$reserve_stock  = new ReserveStock();
177
-		$reserved_stock = $reserve_stock->get_reserved_stock( $product, $this->get_draft_order_id() );
177
+		$reserved_stock = $reserve_stock->get_reserved_stock($product, $this->get_draft_order_id());
178 178
 
179 179
 		return $product->get_stock_quantity() - $reserved_stock;
180 180
 	}
@@ -187,7 +187,7 @@  discard block
 block discarded – undo
187 187
 	 * @param \WC_Product|array $cart_item_or_product Either a cart item or a product instance.
188 188
 	 * @return mixed
189 189
 	 */
190
-	protected function filter_value( $value, string $value_type, $cart_item_or_product ) {
190
+	protected function filter_value($value, string $value_type, $cart_item_or_product) {
191 191
 		$is_product = $cart_item_or_product instanceof \WC_Product;
192 192
 		$product    = $is_product ? $cart_item_or_product : $cart_item_or_product['data'];
193 193
 		$cart_item  = $is_product ? null : $cart_item_or_product;
@@ -203,6 +203,6 @@  discard block
 block discarded – undo
203 203
 		 * @param array|null $cart_item The cart item if the product exists in the cart, or null.
204 204
 		 * @return mixed
205 205
 		 */
206
-		return apply_filters( "woocommerce_store_api_product_quantity_{$value_type}", $value, $product, $cart_item );
206
+		return apply_filters("woocommerce_store_api_product_quantity_{$value_type}", $value, $product, $cart_item);
207 207
 	}
208 208
 }
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/ArrayUtils.php 2 patches
Indentation   +28 added lines, -28 removed lines patch added patch discarded remove patch
@@ -5,32 +5,32 @@
 block discarded – undo
5 5
  * ArrayUtils class used for custom functions to operate on arrays
6 6
  */
7 7
 class ArrayUtils {
8
-	/**
9
-	 * Join a string with a natural language conjunction at the end.
10
-	 *
11
-	 * @param array $array  The array to join together with the natural language conjunction.
12
-	 * @param bool  $enclose_items_with_quotes Whether each item in the array should be enclosed within quotation marks.
13
-	 *
14
-	 * @return string a string containing a list of items and a natural language conjuction.
15
-	 */
16
-	public static function natural_language_join( $array, $enclose_items_with_quotes = false ) {
17
-		if ( true === $enclose_items_with_quotes ) {
18
-			$array = array_map(
19
-				function( $item ) {
20
-					return '"' . $item . '"';
21
-				},
22
-				$array
23
-			);
24
-		}
25
-		$last = array_pop( $array );
26
-		if ( $array ) {
27
-			return sprintf(
28
-				/* translators: 1: The first n-1 items of a list 2: the last item in the list. */
29
-				__( '%1$s and %2$s', 'woocommerce' ),
30
-				implode( ', ', $array ),
31
-				$last
32
-			);
33
-		}
34
-		return $last;
35
-	}
8
+    /**
9
+     * Join a string with a natural language conjunction at the end.
10
+     *
11
+     * @param array $array  The array to join together with the natural language conjunction.
12
+     * @param bool  $enclose_items_with_quotes Whether each item in the array should be enclosed within quotation marks.
13
+     *
14
+     * @return string a string containing a list of items and a natural language conjuction.
15
+     */
16
+    public static function natural_language_join( $array, $enclose_items_with_quotes = false ) {
17
+        if ( true === $enclose_items_with_quotes ) {
18
+            $array = array_map(
19
+                function( $item ) {
20
+                    return '"' . $item . '"';
21
+                },
22
+                $array
23
+            );
24
+        }
25
+        $last = array_pop( $array );
26
+        if ( $array ) {
27
+            return sprintf(
28
+                /* translators: 1: The first n-1 items of a list 2: the last item in the list. */
29
+                __( '%1$s and %2$s', 'woocommerce' ),
30
+                implode( ', ', $array ),
31
+                $last
32
+            );
33
+        }
34
+        return $last;
35
+    }
36 36
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -13,21 +13,21 @@
 block discarded – undo
13 13
 	 *
14 14
 	 * @return string a string containing a list of items and a natural language conjuction.
15 15
 	 */
16
-	public static function natural_language_join( $array, $enclose_items_with_quotes = false ) {
17
-		if ( true === $enclose_items_with_quotes ) {
16
+	public static function natural_language_join($array, $enclose_items_with_quotes = false) {
17
+		if (true === $enclose_items_with_quotes) {
18 18
 			$array = array_map(
19
-				function( $item ) {
19
+				function($item) {
20 20
 					return '"' . $item . '"';
21 21
 				},
22 22
 				$array
23 23
 			);
24 24
 		}
25
-		$last = array_pop( $array );
26
-		if ( $array ) {
25
+		$last = array_pop($array);
26
+		if ($array) {
27 27
 			return sprintf(
28 28
 				/* translators: 1: The first n-1 items of a list 2: the last item in the list. */
29
-				__( '%1$s and %2$s', 'woocommerce' ),
30
-				implode( ', ', $array ),
29
+				__('%1$s and %2$s', 'woocommerce'),
30
+				implode(', ', $array),
31 31
 				$last
32 32
 			);
33 33
 		}
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/DraftOrderTrait.php 2 patches
Indentation   +53 added lines, -53 removed lines patch added patch discarded remove patch
@@ -7,64 +7,64 @@
 block discarded – undo
7 7
  * Shared functionality for getting and setting draft order IDs from session.
8 8
  */
9 9
 trait DraftOrderTrait {
10
-	/**
11
-	 * Gets draft order data from the customer session.
12
-	 *
13
-	 * @return integer
14
-	 */
15
-	protected function get_draft_order_id() {
16
-		if ( ! wc()->session ) {
17
-			wc()->initialize_session();
18
-		}
19
-		return wc()->session->get( 'store_api_draft_order', 0 );
20
-	}
10
+    /**
11
+     * Gets draft order data from the customer session.
12
+     *
13
+     * @return integer
14
+     */
15
+    protected function get_draft_order_id() {
16
+        if ( ! wc()->session ) {
17
+            wc()->initialize_session();
18
+        }
19
+        return wc()->session->get( 'store_api_draft_order', 0 );
20
+    }
21 21
 
22
-	/**
23
-	 * Updates draft order data in the customer session.
24
-	 *
25
-	 * @param integer $order_id Draft order ID.
26
-	 */
27
-	protected function set_draft_order_id( $order_id ) {
28
-		if ( ! wc()->session ) {
29
-			wc()->initialize_session();
30
-		}
31
-		wc()->session->set( 'store_api_draft_order', $order_id );
32
-	}
22
+    /**
23
+     * Updates draft order data in the customer session.
24
+     *
25
+     * @param integer $order_id Draft order ID.
26
+     */
27
+    protected function set_draft_order_id( $order_id ) {
28
+        if ( ! wc()->session ) {
29
+            wc()->initialize_session();
30
+        }
31
+        wc()->session->set( 'store_api_draft_order', $order_id );
32
+    }
33 33
 
34
-	/**
35
-	 * Uses the draft order ID to return an order object, if valid.
36
-	 *
37
-	 * @return \WC_Order|null;
38
-	 */
39
-	protected function get_draft_order() {
40
-		$draft_order_id = $this->get_draft_order_id();
41
-		$draft_order    = $draft_order_id ? wc_get_order( $draft_order_id ) : false;
34
+    /**
35
+     * Uses the draft order ID to return an order object, if valid.
36
+     *
37
+     * @return \WC_Order|null;
38
+     */
39
+    protected function get_draft_order() {
40
+        $draft_order_id = $this->get_draft_order_id();
41
+        $draft_order    = $draft_order_id ? wc_get_order( $draft_order_id ) : false;
42 42
 
43
-		return $this->is_valid_draft_order( $draft_order ) ? $draft_order : null;
44
-	}
43
+        return $this->is_valid_draft_order( $draft_order ) ? $draft_order : null;
44
+    }
45 45
 
46
-	/**
47
-	 * Whether the passed argument is a draft order or an order that is
48
-	 * pending/failed and the cart hasn't changed.
49
-	 *
50
-	 * @param \WC_Order $order_object Order object to check.
51
-	 * @return boolean Whether the order is valid as a draft order.
52
-	 */
53
-	protected function is_valid_draft_order( $order_object ) {
54
-		if ( ! $order_object instanceof \WC_Order ) {
55
-			return false;
56
-		}
46
+    /**
47
+     * Whether the passed argument is a draft order or an order that is
48
+     * pending/failed and the cart hasn't changed.
49
+     *
50
+     * @param \WC_Order $order_object Order object to check.
51
+     * @return boolean Whether the order is valid as a draft order.
52
+     */
53
+    protected function is_valid_draft_order( $order_object ) {
54
+        if ( ! $order_object instanceof \WC_Order ) {
55
+            return false;
56
+        }
57 57
 
58
-		// Draft orders are okay.
59
-		if ( $order_object->has_status( 'checkout-draft' ) ) {
60
-			return true;
61
-		}
58
+        // Draft orders are okay.
59
+        if ( $order_object->has_status( 'checkout-draft' ) ) {
60
+            return true;
61
+        }
62 62
 
63
-		// Pending and failed orders can be retried if the cart hasn't changed.
64
-		if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
65
-			return true;
66
-		}
63
+        // Pending and failed orders can be retried if the cart hasn't changed.
64
+        if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
65
+            return true;
66
+        }
67 67
 
68
-		return false;
69
-	}
68
+        return false;
69
+    }
70 70
 }
Please login to merge, or discard this patch.
Spacing   +11 added lines, -11 removed lines patch added patch discarded remove patch
@@ -13,10 +13,10 @@  discard block
 block discarded – undo
13 13
 	 * @return integer
14 14
 	 */
15 15
 	protected function get_draft_order_id() {
16
-		if ( ! wc()->session ) {
16
+		if (!wc()->session) {
17 17
 			wc()->initialize_session();
18 18
 		}
19
-		return wc()->session->get( 'store_api_draft_order', 0 );
19
+		return wc()->session->get('store_api_draft_order', 0);
20 20
 	}
21 21
 
22 22
 	/**
@@ -24,11 +24,11 @@  discard block
 block discarded – undo
24 24
 	 *
25 25
 	 * @param integer $order_id Draft order ID.
26 26
 	 */
27
-	protected function set_draft_order_id( $order_id ) {
28
-		if ( ! wc()->session ) {
27
+	protected function set_draft_order_id($order_id) {
28
+		if (!wc()->session) {
29 29
 			wc()->initialize_session();
30 30
 		}
31
-		wc()->session->set( 'store_api_draft_order', $order_id );
31
+		wc()->session->set('store_api_draft_order', $order_id);
32 32
 	}
33 33
 
34 34
 	/**
@@ -38,9 +38,9 @@  discard block
 block discarded – undo
38 38
 	 */
39 39
 	protected function get_draft_order() {
40 40
 		$draft_order_id = $this->get_draft_order_id();
41
-		$draft_order    = $draft_order_id ? wc_get_order( $draft_order_id ) : false;
41
+		$draft_order    = $draft_order_id ? wc_get_order($draft_order_id) : false;
42 42
 
43
-		return $this->is_valid_draft_order( $draft_order ) ? $draft_order : null;
43
+		return $this->is_valid_draft_order($draft_order) ? $draft_order : null;
44 44
 	}
45 45
 
46 46
 	/**
@@ -50,18 +50,18 @@  discard block
 block discarded – undo
50 50
 	 * @param \WC_Order $order_object Order object to check.
51 51
 	 * @return boolean Whether the order is valid as a draft order.
52 52
 	 */
53
-	protected function is_valid_draft_order( $order_object ) {
54
-		if ( ! $order_object instanceof \WC_Order ) {
53
+	protected function is_valid_draft_order($order_object) {
54
+		if (!$order_object instanceof \WC_Order) {
55 55
 			return false;
56 56
 		}
57 57
 
58 58
 		// Draft orders are okay.
59
-		if ( $order_object->has_status( 'checkout-draft' ) ) {
59
+		if ($order_object->has_status('checkout-draft')) {
60 60
 			return true;
61 61
 		}
62 62
 
63 63
 		// Pending and failed orders can be retried if the cart hasn't changed.
64
-		if ( $order_object->needs_payment() && $order_object->has_cart_hash( wc()->cart->get_cart_hash() ) ) {
64
+		if ($order_object->needs_payment() && $order_object->has_cart_hash(wc()->cart->get_cart_hash())) {
65 65
 			return true;
66 66
 		}
67 67
 
Please login to merge, or discard this patch.
packages/woocommerce-blocks/src/StoreApi/Utilities/OrderController.php 2 patches
Indentation   +517 added lines, -517 removed lines patch added patch discarded remove patch
@@ -10,521 +10,521 @@
 block discarded – undo
10 10
  */
11 11
 class OrderController {
12 12
 
13
-	/**
14
-	 * Create order and set props based on global settings.
15
-	 *
16
-	 * @throws RouteException Exception if invalid data is detected.
17
-	 *
18
-	 * @return \WC_Order A new order object.
19
-	 */
20
-	public function create_order_from_cart() {
21
-		if ( wc()->cart->is_empty() ) {
22
-			throw new RouteException(
23
-				'woocommerce_rest_cart_empty',
24
-				__( 'Cannot create order from empty cart.', 'woocommerce' ),
25
-				400
26
-			);
27
-		}
28
-
29
-		add_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
30
-
31
-		$order = new \WC_Order();
32
-		$order->set_status( 'checkout-draft' );
33
-		$order->set_created_via( 'store-api' );
34
-		$this->update_order_from_cart( $order );
35
-
36
-		remove_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
37
-
38
-		return $order;
39
-	}
40
-
41
-	/**
42
-	 * Update an order using data from the current cart.
43
-	 *
44
-	 * @param \WC_Order $order The order object to update.
45
-	 */
46
-	public function update_order_from_cart( \WC_Order $order ) {
47
-		// Ensures Local pickups are accounted for.
48
-		add_filter( 'woocommerce_order_get_tax_location', array( $this, 'handle_local_pickup_taxes' ) );
49
-
50
-		// Ensure cart is current.
51
-		wc()->cart->calculate_shipping();
52
-		wc()->cart->calculate_totals();
53
-
54
-		// Update the current order to match the current cart.
55
-		$this->update_line_items_from_cart( $order );
56
-		$this->update_addresses_from_cart( $order );
57
-		$order->set_currency( get_woocommerce_currency() );
58
-		$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
59
-		$order->set_customer_id( get_current_user_id() );
60
-		$order->set_customer_ip_address( \WC_Geolocation::get_ip_address() );
61
-		$order->set_customer_user_agent( wc_get_user_agent() );
62
-		$order->update_meta_data( 'is_vat_exempt', wc()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no' );
63
-		$order->calculate_totals();
64
-	}
65
-
66
-	/**
67
-	 * Copies order data to customer object (not the session), so values persist for future checkouts.
68
-	 *
69
-	 * @param \WC_Order $order Order object.
70
-	 */
71
-	public function sync_customer_data_with_order( \WC_Order $order ) {
72
-		if ( $order->get_customer_id() ) {
73
-			$customer = new \WC_Customer( $order->get_customer_id() );
74
-			$customer->set_props(
75
-				[
76
-					'billing_first_name'  => $order->get_billing_first_name(),
77
-					'billing_last_name'   => $order->get_billing_last_name(),
78
-					'billing_company'     => $order->get_billing_company(),
79
-					'billing_address_1'   => $order->get_billing_address_1(),
80
-					'billing_address_2'   => $order->get_billing_address_2(),
81
-					'billing_city'        => $order->get_billing_city(),
82
-					'billing_state'       => $order->get_billing_state(),
83
-					'billing_postcode'    => $order->get_billing_postcode(),
84
-					'billing_country'     => $order->get_billing_country(),
85
-					'billing_email'       => $order->get_billing_email(),
86
-					'billing_phone'       => $order->get_billing_phone(),
87
-					'shipping_first_name' => $order->get_shipping_first_name(),
88
-					'shipping_last_name'  => $order->get_shipping_last_name(),
89
-					'shipping_company'    => $order->get_shipping_company(),
90
-					'shipping_address_1'  => $order->get_shipping_address_1(),
91
-					'shipping_address_2'  => $order->get_shipping_address_2(),
92
-					'shipping_city'       => $order->get_shipping_city(),
93
-					'shipping_state'      => $order->get_shipping_state(),
94
-					'shipping_postcode'   => $order->get_shipping_postcode(),
95
-					'shipping_country'    => $order->get_shipping_country(),
96
-					'shipping_phone'      => $order->get_shipping_phone(),
97
-				]
98
-			);
99
-
100
-			$customer->save();
101
-		};
102
-	}
103
-
104
-	/**
105
-	 * Final validation ran before payment is taken.
106
-	 *
107
-	 * By this point we have an order populated with customer data and items.
108
-	 *
109
-	 * @throws RouteException Exception if invalid data is detected.
110
-	 * @param \WC_Order $order Order object.
111
-	 */
112
-	public function validate_order_before_payment( \WC_Order $order ) {
113
-		$needs_shipping          = wc()->cart->needs_shipping();
114
-		$chosen_shipping_methods = wc()->session->get( 'chosen_shipping_methods' );
115
-
116
-		$this->validate_coupons( $order );
117
-		$this->validate_email( $order );
118
-		$this->validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods );
119
-		$this->validate_addresses( $order );
120
-	}
121
-
122
-	/**
123
-	 * Convert a coupon code to a coupon object.
124
-	 *
125
-	 * @param string $coupon_code Coupon code.
126
-	 * @return \WC_Coupon Coupon object.
127
-	 */
128
-	protected function get_coupon( $coupon_code ) {
129
-		return new \WC_Coupon( $coupon_code );
130
-	}
131
-
132
-	/**
133
-	 * Validate coupons applied to the order and remove those that are not valid.
134
-	 *
135
-	 * @throws RouteException Exception if invalid data is detected.
136
-	 * @param \WC_Order $order Order object.
137
-	 */
138
-	protected function validate_coupons( \WC_Order $order ) {
139
-		$coupon_codes  = $order->get_coupon_codes();
140
-		$coupons       = array_filter( array_map( [ $this, 'get_coupon' ], $coupon_codes ) );
141
-		$validators    = [ 'validate_coupon_email_restriction', 'validate_coupon_usage_limit' ];
142
-		$coupon_errors = [];
143
-
144
-		foreach ( $coupons as $coupon ) {
145
-			try {
146
-				array_walk(
147
-					$validators,
148
-					function( $validator, $index, $params ) {
149
-						call_user_func_array( [ $this, $validator ], $params );
150
-					},
151
-					[ $coupon, $order ]
152
-				);
153
-			} catch ( Exception $error ) {
154
-				$coupon_errors[ $coupon->get_code() ] = $error->getMessage();
155
-			}
156
-		}
157
-
158
-		if ( $coupon_errors ) {
159
-			// Remove all coupons that were not valid.
160
-			foreach ( $coupon_errors as $coupon_code => $message ) {
161
-				wc()->cart->remove_coupon( $coupon_code );
162
-			}
163
-
164
-			// Recalculate totals.
165
-			wc()->cart->calculate_totals();
166
-
167
-			// Re-sync order with cart.
168
-			$this->update_order_from_cart( $order );
169
-
170
-			// Return exception so customer can review before payment.
171
-			throw new RouteException(
172
-				'woocommerce_rest_cart_coupon_errors',
173
-				sprintf(
174
-					/* translators: %s Coupon codes. */
175
-					__( 'Invalid coupons were removed from the cart: "%s"', 'woocommerce' ),
176
-					implode( '", "', array_keys( $coupon_errors ) )
177
-				),
178
-				409,
179
-				[
180
-					'removed_coupons' => $coupon_errors,
181
-				]
182
-			);
183
-		}
184
-	}
185
-
186
-	/**
187
-	 * Validates the customer email. This is a required field.
188
-	 *
189
-	 * @throws RouteException Exception if invalid data is detected.
190
-	 * @param \WC_Order $order Order object.
191
-	 */
192
-	protected function validate_email( \WC_Order $order ) {
193
-		$email = $order->get_billing_email();
194
-
195
-		if ( empty( $email ) ) {
196
-			throw new RouteException(
197
-				'woocommerce_rest_missing_email_address',
198
-				__( 'A valid email address is required', 'woocommerce' ),
199
-				400
200
-			);
201
-		}
202
-
203
-		if ( ! is_email( $email ) ) {
204
-			throw new RouteException(
205
-				'woocommerce_rest_invalid_email_address',
206
-				sprintf(
207
-					/* translators: %s provided email. */
208
-					__( 'The provided email address (%s) is not valid—please provide a valid email address', 'woocommerce' ),
209
-					esc_html( $email )
210
-				),
211
-				400
212
-			);
213
-		}
214
-	}
215
-
216
-	/**
217
-	 * Validates customer address data based on the locale to ensure required fields are set.
218
-	 *
219
-	 * @throws RouteException Exception if invalid data is detected.
220
-	 * @param \WC_Order $order Order object.
221
-	 */
222
-	protected function validate_addresses( \WC_Order $order ) {
223
-		$errors           = new \WP_Error();
224
-		$needs_shipping   = wc()->cart->needs_shipping();
225
-		$billing_address  = $order->get_address( 'billing' );
226
-		$shipping_address = $order->get_address( 'shipping' );
227
-
228
-		if ( $needs_shipping && ! $this->validate_allowed_country( $shipping_address['country'], (array) wc()->countries->get_shipping_countries() ) ) {
229
-			throw new RouteException(
230
-				'woocommerce_rest_invalid_address_country',
231
-				sprintf(
232
-					/* translators: %s country code. */
233
-					__( 'Sorry, we do not ship orders to the provided country (%s)', 'woocommerce' ),
234
-					$shipping_address['country']
235
-				),
236
-				400,
237
-				[
238
-					'allowed_countries' => array_keys( wc()->countries->get_shipping_countries() ),
239
-				]
240
-			);
241
-		}
242
-
243
-		if ( ! $this->validate_allowed_country( $billing_address['country'], (array) wc()->countries->get_allowed_countries() ) ) {
244
-			throw new RouteException(
245
-				'woocommerce_rest_invalid_address_country',
246
-				sprintf(
247
-					/* translators: %s country code. */
248
-					__( 'Sorry, we do not allow orders from the provided country (%s)', 'woocommerce' ),
249
-					$billing_address['country']
250
-				),
251
-				400,
252
-				[
253
-					'allowed_countries' => array_keys( wc()->countries->get_allowed_countries() ),
254
-				]
255
-			);
256
-		}
257
-
258
-		if ( $needs_shipping ) {
259
-			$this->validate_address_fields( $shipping_address, 'shipping', $errors );
260
-		}
261
-		$this->validate_address_fields( $billing_address, 'billing', $errors );
262
-
263
-		if ( ! $errors->has_errors() ) {
264
-			return;
265
-		}
266
-
267
-		$errors_by_code = [];
268
-		$error_codes    = $errors->get_error_codes();
269
-		foreach ( $error_codes as $code ) {
270
-			$errors_by_code[ $code ] = $errors->get_error_messages( $code );
271
-		}
272
-
273
-		// Surface errors from first code.
274
-		foreach ( $errors_by_code as $code => $error_messages ) {
275
-			throw new RouteException(
276
-				'woocommerce_rest_invalid_address',
277
-				sprintf(
278
-					/* translators: %s Address type. */
279
-					__( 'There was a problem with the provided %s:', 'woocommerce' ) . ' ' . implode( ', ', $error_messages ),
280
-					'shipping' === $code ? __( 'shipping address', 'woocommerce' ) : __( 'billing address', 'woocommerce' )
281
-				),
282
-				400,
283
-				[
284
-					'errors' => $errors_by_code,
285
-				]
286
-			);
287
-		}
288
-	}
289
-
290
-	/**
291
-	 * Check all required address fields are set and return errors if not.
292
-	 *
293
-	 * @param string $country Country code.
294
-	 * @param array  $allowed_countries List of valid country codes.
295
-	 * @return boolean True if valid.
296
-	 */
297
-	protected function validate_allowed_country( $country, array $allowed_countries ) {
298
-		return array_key_exists( $country, $allowed_countries );
299
-	}
300
-
301
-	/**
302
-	 * Check all required address fields are set and return errors if not.
303
-	 *
304
-	 * @param array     $address Address array.
305
-	 * @param string    $address_type billing or shipping address, used in error messages.
306
-	 * @param \WP_Error $errors Error object.
307
-	 */
308
-	protected function validate_address_fields( $address, $address_type, \WP_Error $errors ) {
309
-		$all_locales    = wc()->countries->get_country_locale();
310
-		$current_locale = isset( $all_locales[ $address['country'] ] ) ? $all_locales[ $address['country'] ] : [];
311
-
312
-		/**
313
-		 * We are not using wc()->counties->get_default_address_fields() here because that is filtered. Instead, this array
314
-		 * is based on assets/js/base/components/cart-checkout/address-form/default-address-fields.js
315
-		 */
316
-		$address_fields = [
317
-			'first_name' => [
318
-				'label'    => __( 'First name', 'woocommerce' ),
319
-				'required' => true,
320
-			],
321
-			'last_name'  => [
322
-				'label'    => __( 'Last name', 'woocommerce' ),
323
-				'required' => true,
324
-			],
325
-			'company'    => [
326
-				'label'    => __( 'Company', 'woocommerce' ),
327
-				'required' => false,
328
-			],
329
-			'address_1'  => [
330
-				'label'    => __( 'Address', 'woocommerce' ),
331
-				'required' => true,
332
-			],
333
-			'address_2'  => [
334
-				'label'    => __( 'Apartment, suite, etc.', 'woocommerce' ),
335
-				'required' => false,
336
-			],
337
-			'country'    => [
338
-				'label'    => __( 'Country/Region', 'woocommerce' ),
339
-				'required' => true,
340
-			],
341
-			'city'       => [
342
-				'label'    => __( 'City', 'woocommerce' ),
343
-				'required' => true,
344
-			],
345
-			'state'      => [
346
-				'label'    => __( 'State/County', 'woocommerce' ),
347
-				'required' => true,
348
-			],
349
-			'postcode'   => [
350
-				'label'    => __( 'Postal code', 'woocommerce' ),
351
-				'required' => true,
352
-			],
353
-		];
354
-
355
-		if ( $current_locale ) {
356
-			foreach ( $current_locale as $key => $field ) {
357
-				if ( isset( $address_fields[ $key ] ) ) {
358
-					$address_fields[ $key ]['label']    = isset( $field['label'] ) ? $field['label'] : $address_fields[ $key ]['label'];
359
-					$address_fields[ $key ]['required'] = isset( $field['required'] ) ? $field['required'] : $address_fields[ $key ]['required'];
360
-				}
361
-			}
362
-		}
363
-
364
-		foreach ( $address_fields as $address_field_key => $address_field ) {
365
-			if ( empty( $address[ $address_field_key ] ) && $address_field['required'] ) {
366
-				/* translators: %s Field label. */
367
-				$errors->add( $address_type, sprintf( __( '%s is required', 'woocommerce' ), $address_field['label'] ), $address_field_key );
368
-			}
369
-		}
370
-	}
371
-
372
-	/**
373
-	 * Check email restrictions of a coupon against the order.
374
-	 *
375
-	 * @throws Exception Exception if invalid data is detected.
376
-	 * @param \WC_Coupon $coupon Coupon object applied to the cart.
377
-	 * @param \WC_Order  $order Order object.
378
-	 */
379
-	protected function validate_coupon_email_restriction( \WC_Coupon $coupon, \WC_Order $order ) {
380
-		$restrictions = $coupon->get_email_restrictions();
381
-
382
-		if ( ! empty( $restrictions ) && $order->get_billing_email() && ! wc()->cart->is_coupon_emails_allowed( [ $order->get_billing_email() ], $restrictions ) ) {
383
-			throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_NOT_YOURS_REMOVED ) );
384
-		}
385
-	}
386
-
387
-	/**
388
-	 * Check usage restrictions of a coupon against the order.
389
-	 *
390
-	 * @throws Exception Exception if invalid data is detected.
391
-	 * @param \WC_Coupon $coupon Coupon object applied to the cart.
392
-	 * @param \WC_Order  $order Order object.
393
-	 */
394
-	protected function validate_coupon_usage_limit( \WC_Coupon $coupon, \WC_Order $order ) {
395
-		$coupon_usage_limit = $coupon->get_usage_limit_per_user();
396
-
397
-		if ( $coupon_usage_limit > 0 ) {
398
-			$data_store  = $coupon->get_data_store();
399
-			$usage_count = $order->get_customer_id() ? $data_store->get_usage_by_user_id( $coupon, $order->get_customer_id() ) : $data_store->get_usage_by_email( $coupon, $order->get_billing_email() );
400
-
401
-			if ( $usage_count >= $coupon_usage_limit ) {
402
-				throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED ) );
403
-			}
404
-		}
405
-	}
406
-
407
-	/**
408
-	 * Check there is a shipping method if it requires shipping.
409
-	 *
410
-	 * @throws RouteException Exception if invalid data is detected.
411
-	 * @param boolean $needs_shipping Current order needs shipping.
412
-	 * @param array   $chosen_shipping_methods Array of shipping methods.
413
-	 */
414
-	public function validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods = array() ) {
415
-		if ( ! $needs_shipping || ! is_array( $chosen_shipping_methods ) ) {
416
-			return;
417
-		}
418
-
419
-		foreach ( $chosen_shipping_methods as $chosen_shipping_method ) {
420
-			if ( false === $chosen_shipping_method ) {
421
-				throw new RouteException(
422
-					'woocommerce_rest_invalid_shipping_option',
423
-					__( 'Sorry, this order requires a shipping option.', 'woocommerce' ),
424
-					400,
425
-					[]
426
-				);
427
-			}
428
-		}
429
-	}
430
-
431
-	/**
432
-	 * Changes default order status to draft for orders created via this API.
433
-	 *
434
-	 * @return string
435
-	 */
436
-	public function default_order_status() {
437
-		return 'checkout-draft';
438
-	}
439
-
440
-	/**
441
-	 * Passes the correct base for local pick orders
442
-	 *
443
-	 * @todo: Remove custom local pickup handling once WooCommerce 6.8.0 is the minimum version.
444
-	 *
445
-	 * @param array $location Taxes location.
446
-	 * @return array updated location that accounts for local pickup.
447
-	 */
448
-	public function handle_local_pickup_taxes( $location ) {
449
-		$customer = wc()->customer;
450
-
451
-		if ( ! empty( $customer ) ) {
452
-			return $customer->get_taxable_address();
453
-		}
454
-
455
-		return $location;
456
-	}
457
-	/**
458
-	 * Create order line items.
459
-	 *
460
-	 * @param \WC_Order $order The order object to update.
461
-	 */
462
-	protected function update_line_items_from_cart( \WC_Order $order ) {
463
-		$cart_controller = new CartController();
464
-		$cart            = $cart_controller->get_cart_instance();
465
-		$cart_hashes     = $cart_controller->get_cart_hashes();
466
-
467
-		if ( $order->get_cart_hash() !== $cart_hashes['line_items'] ) {
468
-			$order->set_cart_hash( $cart_hashes['line_items'] );
469
-			$order->remove_order_items( 'line_item' );
470
-			wc()->checkout->create_order_line_items( $order, $cart );
471
-		}
472
-
473
-		if ( $order->get_meta_data( '_shipping_hash' ) !== $cart_hashes['shipping'] ) {
474
-			$order->update_meta_data( '_shipping_hash', $cart_hashes['shipping'] );
475
-			$order->remove_order_items( 'shipping' );
476
-			wc()->checkout->create_order_shipping_lines( $order, wc()->session->get( 'chosen_shipping_methods' ), wc()->shipping()->get_packages() );
477
-		}
478
-
479
-		if ( $order->get_meta_data( '_coupons_hash' ) !== $cart_hashes['coupons'] ) {
480
-			$order->remove_order_items( 'coupon' );
481
-			$order->update_meta_data( '_coupons_hash', $cart_hashes['coupons'] );
482
-			wc()->checkout->create_order_coupon_lines( $order, $cart );
483
-		}
484
-
485
-		if ( $order->get_meta_data( '_fees_hash' ) !== $cart_hashes['fees'] ) {
486
-			$order->update_meta_data( '_fees_hash', $cart_hashes['fees'] );
487
-			$order->remove_order_items( 'fee' );
488
-			wc()->checkout->create_order_fee_lines( $order, $cart );
489
-		}
490
-
491
-		if ( $order->get_meta_data( '_taxes_hash' ) !== $cart_hashes['taxes'] ) {
492
-			$order->update_meta_data( '_taxes_hash', $cart_hashes['taxes'] );
493
-			$order->remove_order_items( 'tax' );
494
-			wc()->checkout->create_order_tax_lines( $order, $cart );
495
-		}
496
-	}
497
-
498
-	/**
499
-	 * Update address data from cart and/or customer session data.
500
-	 *
501
-	 * @param \WC_Order $order The order object to update.
502
-	 */
503
-	protected function update_addresses_from_cart( \WC_Order $order ) {
504
-		$order->set_props(
505
-			[
506
-				'billing_first_name'  => wc()->customer->get_billing_first_name(),
507
-				'billing_last_name'   => wc()->customer->get_billing_last_name(),
508
-				'billing_company'     => wc()->customer->get_billing_company(),
509
-				'billing_address_1'   => wc()->customer->get_billing_address_1(),
510
-				'billing_address_2'   => wc()->customer->get_billing_address_2(),
511
-				'billing_city'        => wc()->customer->get_billing_city(),
512
-				'billing_state'       => wc()->customer->get_billing_state(),
513
-				'billing_postcode'    => wc()->customer->get_billing_postcode(),
514
-				'billing_country'     => wc()->customer->get_billing_country(),
515
-				'billing_email'       => wc()->customer->get_billing_email(),
516
-				'billing_phone'       => wc()->customer->get_billing_phone(),
517
-				'shipping_first_name' => wc()->customer->get_shipping_first_name(),
518
-				'shipping_last_name'  => wc()->customer->get_shipping_last_name(),
519
-				'shipping_company'    => wc()->customer->get_shipping_company(),
520
-				'shipping_address_1'  => wc()->customer->get_shipping_address_1(),
521
-				'shipping_address_2'  => wc()->customer->get_shipping_address_2(),
522
-				'shipping_city'       => wc()->customer->get_shipping_city(),
523
-				'shipping_state'      => wc()->customer->get_shipping_state(),
524
-				'shipping_postcode'   => wc()->customer->get_shipping_postcode(),
525
-				'shipping_country'    => wc()->customer->get_shipping_country(),
526
-				'shipping_phone'      => wc()->customer->get_shipping_phone(),
527
-			]
528
-		);
529
-	}
13
+    /**
14
+     * Create order and set props based on global settings.
15
+     *
16
+     * @throws RouteException Exception if invalid data is detected.
17
+     *
18
+     * @return \WC_Order A new order object.
19
+     */
20
+    public function create_order_from_cart() {
21
+        if ( wc()->cart->is_empty() ) {
22
+            throw new RouteException(
23
+                'woocommerce_rest_cart_empty',
24
+                __( 'Cannot create order from empty cart.', 'woocommerce' ),
25
+                400
26
+            );
27
+        }
28
+
29
+        add_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
30
+
31
+        $order = new \WC_Order();
32
+        $order->set_status( 'checkout-draft' );
33
+        $order->set_created_via( 'store-api' );
34
+        $this->update_order_from_cart( $order );
35
+
36
+        remove_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
37
+
38
+        return $order;
39
+    }
40
+
41
+    /**
42
+     * Update an order using data from the current cart.
43
+     *
44
+     * @param \WC_Order $order The order object to update.
45
+     */
46
+    public function update_order_from_cart( \WC_Order $order ) {
47
+        // Ensures Local pickups are accounted for.
48
+        add_filter( 'woocommerce_order_get_tax_location', array( $this, 'handle_local_pickup_taxes' ) );
49
+
50
+        // Ensure cart is current.
51
+        wc()->cart->calculate_shipping();
52
+        wc()->cart->calculate_totals();
53
+
54
+        // Update the current order to match the current cart.
55
+        $this->update_line_items_from_cart( $order );
56
+        $this->update_addresses_from_cart( $order );
57
+        $order->set_currency( get_woocommerce_currency() );
58
+        $order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
59
+        $order->set_customer_id( get_current_user_id() );
60
+        $order->set_customer_ip_address( \WC_Geolocation::get_ip_address() );
61
+        $order->set_customer_user_agent( wc_get_user_agent() );
62
+        $order->update_meta_data( 'is_vat_exempt', wc()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no' );
63
+        $order->calculate_totals();
64
+    }
65
+
66
+    /**
67
+     * Copies order data to customer object (not the session), so values persist for future checkouts.
68
+     *
69
+     * @param \WC_Order $order Order object.
70
+     */
71
+    public function sync_customer_data_with_order( \WC_Order $order ) {
72
+        if ( $order->get_customer_id() ) {
73
+            $customer = new \WC_Customer( $order->get_customer_id() );
74
+            $customer->set_props(
75
+                [
76
+                    'billing_first_name'  => $order->get_billing_first_name(),
77
+                    'billing_last_name'   => $order->get_billing_last_name(),
78
+                    'billing_company'     => $order->get_billing_company(),
79
+                    'billing_address_1'   => $order->get_billing_address_1(),
80
+                    'billing_address_2'   => $order->get_billing_address_2(),
81
+                    'billing_city'        => $order->get_billing_city(),
82
+                    'billing_state'       => $order->get_billing_state(),
83
+                    'billing_postcode'    => $order->get_billing_postcode(),
84
+                    'billing_country'     => $order->get_billing_country(),
85
+                    'billing_email'       => $order->get_billing_email(),
86
+                    'billing_phone'       => $order->get_billing_phone(),
87
+                    'shipping_first_name' => $order->get_shipping_first_name(),
88
+                    'shipping_last_name'  => $order->get_shipping_last_name(),
89
+                    'shipping_company'    => $order->get_shipping_company(),
90
+                    'shipping_address_1'  => $order->get_shipping_address_1(),
91
+                    'shipping_address_2'  => $order->get_shipping_address_2(),
92
+                    'shipping_city'       => $order->get_shipping_city(),
93
+                    'shipping_state'      => $order->get_shipping_state(),
94
+                    'shipping_postcode'   => $order->get_shipping_postcode(),
95
+                    'shipping_country'    => $order->get_shipping_country(),
96
+                    'shipping_phone'      => $order->get_shipping_phone(),
97
+                ]
98
+            );
99
+
100
+            $customer->save();
101
+        };
102
+    }
103
+
104
+    /**
105
+     * Final validation ran before payment is taken.
106
+     *
107
+     * By this point we have an order populated with customer data and items.
108
+     *
109
+     * @throws RouteException Exception if invalid data is detected.
110
+     * @param \WC_Order $order Order object.
111
+     */
112
+    public function validate_order_before_payment( \WC_Order $order ) {
113
+        $needs_shipping          = wc()->cart->needs_shipping();
114
+        $chosen_shipping_methods = wc()->session->get( 'chosen_shipping_methods' );
115
+
116
+        $this->validate_coupons( $order );
117
+        $this->validate_email( $order );
118
+        $this->validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods );
119
+        $this->validate_addresses( $order );
120
+    }
121
+
122
+    /**
123
+     * Convert a coupon code to a coupon object.
124
+     *
125
+     * @param string $coupon_code Coupon code.
126
+     * @return \WC_Coupon Coupon object.
127
+     */
128
+    protected function get_coupon( $coupon_code ) {
129
+        return new \WC_Coupon( $coupon_code );
130
+    }
131
+
132
+    /**
133
+     * Validate coupons applied to the order and remove those that are not valid.
134
+     *
135
+     * @throws RouteException Exception if invalid data is detected.
136
+     * @param \WC_Order $order Order object.
137
+     */
138
+    protected function validate_coupons( \WC_Order $order ) {
139
+        $coupon_codes  = $order->get_coupon_codes();
140
+        $coupons       = array_filter( array_map( [ $this, 'get_coupon' ], $coupon_codes ) );
141
+        $validators    = [ 'validate_coupon_email_restriction', 'validate_coupon_usage_limit' ];
142
+        $coupon_errors = [];
143
+
144
+        foreach ( $coupons as $coupon ) {
145
+            try {
146
+                array_walk(
147
+                    $validators,
148
+                    function( $validator, $index, $params ) {
149
+                        call_user_func_array( [ $this, $validator ], $params );
150
+                    },
151
+                    [ $coupon, $order ]
152
+                );
153
+            } catch ( Exception $error ) {
154
+                $coupon_errors[ $coupon->get_code() ] = $error->getMessage();
155
+            }
156
+        }
157
+
158
+        if ( $coupon_errors ) {
159
+            // Remove all coupons that were not valid.
160
+            foreach ( $coupon_errors as $coupon_code => $message ) {
161
+                wc()->cart->remove_coupon( $coupon_code );
162
+            }
163
+
164
+            // Recalculate totals.
165
+            wc()->cart->calculate_totals();
166
+
167
+            // Re-sync order with cart.
168
+            $this->update_order_from_cart( $order );
169
+
170
+            // Return exception so customer can review before payment.
171
+            throw new RouteException(
172
+                'woocommerce_rest_cart_coupon_errors',
173
+                sprintf(
174
+                    /* translators: %s Coupon codes. */
175
+                    __( 'Invalid coupons were removed from the cart: "%s"', 'woocommerce' ),
176
+                    implode( '", "', array_keys( $coupon_errors ) )
177
+                ),
178
+                409,
179
+                [
180
+                    'removed_coupons' => $coupon_errors,
181
+                ]
182
+            );
183
+        }
184
+    }
185
+
186
+    /**
187
+     * Validates the customer email. This is a required field.
188
+     *
189
+     * @throws RouteException Exception if invalid data is detected.
190
+     * @param \WC_Order $order Order object.
191
+     */
192
+    protected function validate_email( \WC_Order $order ) {
193
+        $email = $order->get_billing_email();
194
+
195
+        if ( empty( $email ) ) {
196
+            throw new RouteException(
197
+                'woocommerce_rest_missing_email_address',
198
+                __( 'A valid email address is required', 'woocommerce' ),
199
+                400
200
+            );
201
+        }
202
+
203
+        if ( ! is_email( $email ) ) {
204
+            throw new RouteException(
205
+                'woocommerce_rest_invalid_email_address',
206
+                sprintf(
207
+                    /* translators: %s provided email. */
208
+                    __( 'The provided email address (%s) is not valid—please provide a valid email address', 'woocommerce' ),
209
+                    esc_html( $email )
210
+                ),
211
+                400
212
+            );
213
+        }
214
+    }
215
+
216
+    /**
217
+     * Validates customer address data based on the locale to ensure required fields are set.
218
+     *
219
+     * @throws RouteException Exception if invalid data is detected.
220
+     * @param \WC_Order $order Order object.
221
+     */
222
+    protected function validate_addresses( \WC_Order $order ) {
223
+        $errors           = new \WP_Error();
224
+        $needs_shipping   = wc()->cart->needs_shipping();
225
+        $billing_address  = $order->get_address( 'billing' );
226
+        $shipping_address = $order->get_address( 'shipping' );
227
+
228
+        if ( $needs_shipping && ! $this->validate_allowed_country( $shipping_address['country'], (array) wc()->countries->get_shipping_countries() ) ) {
229
+            throw new RouteException(
230
+                'woocommerce_rest_invalid_address_country',
231
+                sprintf(
232
+                    /* translators: %s country code. */
233
+                    __( 'Sorry, we do not ship orders to the provided country (%s)', 'woocommerce' ),
234
+                    $shipping_address['country']
235
+                ),
236
+                400,
237
+                [
238
+                    'allowed_countries' => array_keys( wc()->countries->get_shipping_countries() ),
239
+                ]
240
+            );
241
+        }
242
+
243
+        if ( ! $this->validate_allowed_country( $billing_address['country'], (array) wc()->countries->get_allowed_countries() ) ) {
244
+            throw new RouteException(
245
+                'woocommerce_rest_invalid_address_country',
246
+                sprintf(
247
+                    /* translators: %s country code. */
248
+                    __( 'Sorry, we do not allow orders from the provided country (%s)', 'woocommerce' ),
249
+                    $billing_address['country']
250
+                ),
251
+                400,
252
+                [
253
+                    'allowed_countries' => array_keys( wc()->countries->get_allowed_countries() ),
254
+                ]
255
+            );
256
+        }
257
+
258
+        if ( $needs_shipping ) {
259
+            $this->validate_address_fields( $shipping_address, 'shipping', $errors );
260
+        }
261
+        $this->validate_address_fields( $billing_address, 'billing', $errors );
262
+
263
+        if ( ! $errors->has_errors() ) {
264
+            return;
265
+        }
266
+
267
+        $errors_by_code = [];
268
+        $error_codes    = $errors->get_error_codes();
269
+        foreach ( $error_codes as $code ) {
270
+            $errors_by_code[ $code ] = $errors->get_error_messages( $code );
271
+        }
272
+
273
+        // Surface errors from first code.
274
+        foreach ( $errors_by_code as $code => $error_messages ) {
275
+            throw new RouteException(
276
+                'woocommerce_rest_invalid_address',
277
+                sprintf(
278
+                    /* translators: %s Address type. */
279
+                    __( 'There was a problem with the provided %s:', 'woocommerce' ) . ' ' . implode( ', ', $error_messages ),
280
+                    'shipping' === $code ? __( 'shipping address', 'woocommerce' ) : __( 'billing address', 'woocommerce' )
281
+                ),
282
+                400,
283
+                [
284
+                    'errors' => $errors_by_code,
285
+                ]
286
+            );
287
+        }
288
+    }
289
+
290
+    /**
291
+     * Check all required address fields are set and return errors if not.
292
+     *
293
+     * @param string $country Country code.
294
+     * @param array  $allowed_countries List of valid country codes.
295
+     * @return boolean True if valid.
296
+     */
297
+    protected function validate_allowed_country( $country, array $allowed_countries ) {
298
+        return array_key_exists( $country, $allowed_countries );
299
+    }
300
+
301
+    /**
302
+     * Check all required address fields are set and return errors if not.
303
+     *
304
+     * @param array     $address Address array.
305
+     * @param string    $address_type billing or shipping address, used in error messages.
306
+     * @param \WP_Error $errors Error object.
307
+     */
308
+    protected function validate_address_fields( $address, $address_type, \WP_Error $errors ) {
309
+        $all_locales    = wc()->countries->get_country_locale();
310
+        $current_locale = isset( $all_locales[ $address['country'] ] ) ? $all_locales[ $address['country'] ] : [];
311
+
312
+        /**
313
+         * We are not using wc()->counties->get_default_address_fields() here because that is filtered. Instead, this array
314
+         * is based on assets/js/base/components/cart-checkout/address-form/default-address-fields.js
315
+         */
316
+        $address_fields = [
317
+            'first_name' => [
318
+                'label'    => __( 'First name', 'woocommerce' ),
319
+                'required' => true,
320
+            ],
321
+            'last_name'  => [
322
+                'label'    => __( 'Last name', 'woocommerce' ),
323
+                'required' => true,
324
+            ],
325
+            'company'    => [
326
+                'label'    => __( 'Company', 'woocommerce' ),
327
+                'required' => false,
328
+            ],
329
+            'address_1'  => [
330
+                'label'    => __( 'Address', 'woocommerce' ),
331
+                'required' => true,
332
+            ],
333
+            'address_2'  => [
334
+                'label'    => __( 'Apartment, suite, etc.', 'woocommerce' ),
335
+                'required' => false,
336
+            ],
337
+            'country'    => [
338
+                'label'    => __( 'Country/Region', 'woocommerce' ),
339
+                'required' => true,
340
+            ],
341
+            'city'       => [
342
+                'label'    => __( 'City', 'woocommerce' ),
343
+                'required' => true,
344
+            ],
345
+            'state'      => [
346
+                'label'    => __( 'State/County', 'woocommerce' ),
347
+                'required' => true,
348
+            ],
349
+            'postcode'   => [
350
+                'label'    => __( 'Postal code', 'woocommerce' ),
351
+                'required' => true,
352
+            ],
353
+        ];
354
+
355
+        if ( $current_locale ) {
356
+            foreach ( $current_locale as $key => $field ) {
357
+                if ( isset( $address_fields[ $key ] ) ) {
358
+                    $address_fields[ $key ]['label']    = isset( $field['label'] ) ? $field['label'] : $address_fields[ $key ]['label'];
359
+                    $address_fields[ $key ]['required'] = isset( $field['required'] ) ? $field['required'] : $address_fields[ $key ]['required'];
360
+                }
361
+            }
362
+        }
363
+
364
+        foreach ( $address_fields as $address_field_key => $address_field ) {
365
+            if ( empty( $address[ $address_field_key ] ) && $address_field['required'] ) {
366
+                /* translators: %s Field label. */
367
+                $errors->add( $address_type, sprintf( __( '%s is required', 'woocommerce' ), $address_field['label'] ), $address_field_key );
368
+            }
369
+        }
370
+    }
371
+
372
+    /**
373
+     * Check email restrictions of a coupon against the order.
374
+     *
375
+     * @throws Exception Exception if invalid data is detected.
376
+     * @param \WC_Coupon $coupon Coupon object applied to the cart.
377
+     * @param \WC_Order  $order Order object.
378
+     */
379
+    protected function validate_coupon_email_restriction( \WC_Coupon $coupon, \WC_Order $order ) {
380
+        $restrictions = $coupon->get_email_restrictions();
381
+
382
+        if ( ! empty( $restrictions ) && $order->get_billing_email() && ! wc()->cart->is_coupon_emails_allowed( [ $order->get_billing_email() ], $restrictions ) ) {
383
+            throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_NOT_YOURS_REMOVED ) );
384
+        }
385
+    }
386
+
387
+    /**
388
+     * Check usage restrictions of a coupon against the order.
389
+     *
390
+     * @throws Exception Exception if invalid data is detected.
391
+     * @param \WC_Coupon $coupon Coupon object applied to the cart.
392
+     * @param \WC_Order  $order Order object.
393
+     */
394
+    protected function validate_coupon_usage_limit( \WC_Coupon $coupon, \WC_Order $order ) {
395
+        $coupon_usage_limit = $coupon->get_usage_limit_per_user();
396
+
397
+        if ( $coupon_usage_limit > 0 ) {
398
+            $data_store  = $coupon->get_data_store();
399
+            $usage_count = $order->get_customer_id() ? $data_store->get_usage_by_user_id( $coupon, $order->get_customer_id() ) : $data_store->get_usage_by_email( $coupon, $order->get_billing_email() );
400
+
401
+            if ( $usage_count >= $coupon_usage_limit ) {
402
+                throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED ) );
403
+            }
404
+        }
405
+    }
406
+
407
+    /**
408
+     * Check there is a shipping method if it requires shipping.
409
+     *
410
+     * @throws RouteException Exception if invalid data is detected.
411
+     * @param boolean $needs_shipping Current order needs shipping.
412
+     * @param array   $chosen_shipping_methods Array of shipping methods.
413
+     */
414
+    public function validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods = array() ) {
415
+        if ( ! $needs_shipping || ! is_array( $chosen_shipping_methods ) ) {
416
+            return;
417
+        }
418
+
419
+        foreach ( $chosen_shipping_methods as $chosen_shipping_method ) {
420
+            if ( false === $chosen_shipping_method ) {
421
+                throw new RouteException(
422
+                    'woocommerce_rest_invalid_shipping_option',
423
+                    __( 'Sorry, this order requires a shipping option.', 'woocommerce' ),
424
+                    400,
425
+                    []
426
+                );
427
+            }
428
+        }
429
+    }
430
+
431
+    /**
432
+     * Changes default order status to draft for orders created via this API.
433
+     *
434
+     * @return string
435
+     */
436
+    public function default_order_status() {
437
+        return 'checkout-draft';
438
+    }
439
+
440
+    /**
441
+     * Passes the correct base for local pick orders
442
+     *
443
+     * @todo: Remove custom local pickup handling once WooCommerce 6.8.0 is the minimum version.
444
+     *
445
+     * @param array $location Taxes location.
446
+     * @return array updated location that accounts for local pickup.
447
+     */
448
+    public function handle_local_pickup_taxes( $location ) {
449
+        $customer = wc()->customer;
450
+
451
+        if ( ! empty( $customer ) ) {
452
+            return $customer->get_taxable_address();
453
+        }
454
+
455
+        return $location;
456
+    }
457
+    /**
458
+     * Create order line items.
459
+     *
460
+     * @param \WC_Order $order The order object to update.
461
+     */
462
+    protected function update_line_items_from_cart( \WC_Order $order ) {
463
+        $cart_controller = new CartController();
464
+        $cart            = $cart_controller->get_cart_instance();
465
+        $cart_hashes     = $cart_controller->get_cart_hashes();
466
+
467
+        if ( $order->get_cart_hash() !== $cart_hashes['line_items'] ) {
468
+            $order->set_cart_hash( $cart_hashes['line_items'] );
469
+            $order->remove_order_items( 'line_item' );
470
+            wc()->checkout->create_order_line_items( $order, $cart );
471
+        }
472
+
473
+        if ( $order->get_meta_data( '_shipping_hash' ) !== $cart_hashes['shipping'] ) {
474
+            $order->update_meta_data( '_shipping_hash', $cart_hashes['shipping'] );
475
+            $order->remove_order_items( 'shipping' );
476
+            wc()->checkout->create_order_shipping_lines( $order, wc()->session->get( 'chosen_shipping_methods' ), wc()->shipping()->get_packages() );
477
+        }
478
+
479
+        if ( $order->get_meta_data( '_coupons_hash' ) !== $cart_hashes['coupons'] ) {
480
+            $order->remove_order_items( 'coupon' );
481
+            $order->update_meta_data( '_coupons_hash', $cart_hashes['coupons'] );
482
+            wc()->checkout->create_order_coupon_lines( $order, $cart );
483
+        }
484
+
485
+        if ( $order->get_meta_data( '_fees_hash' ) !== $cart_hashes['fees'] ) {
486
+            $order->update_meta_data( '_fees_hash', $cart_hashes['fees'] );
487
+            $order->remove_order_items( 'fee' );
488
+            wc()->checkout->create_order_fee_lines( $order, $cart );
489
+        }
490
+
491
+        if ( $order->get_meta_data( '_taxes_hash' ) !== $cart_hashes['taxes'] ) {
492
+            $order->update_meta_data( '_taxes_hash', $cart_hashes['taxes'] );
493
+            $order->remove_order_items( 'tax' );
494
+            wc()->checkout->create_order_tax_lines( $order, $cart );
495
+        }
496
+    }
497
+
498
+    /**
499
+     * Update address data from cart and/or customer session data.
500
+     *
501
+     * @param \WC_Order $order The order object to update.
502
+     */
503
+    protected function update_addresses_from_cart( \WC_Order $order ) {
504
+        $order->set_props(
505
+            [
506
+                'billing_first_name'  => wc()->customer->get_billing_first_name(),
507
+                'billing_last_name'   => wc()->customer->get_billing_last_name(),
508
+                'billing_company'     => wc()->customer->get_billing_company(),
509
+                'billing_address_1'   => wc()->customer->get_billing_address_1(),
510
+                'billing_address_2'   => wc()->customer->get_billing_address_2(),
511
+                'billing_city'        => wc()->customer->get_billing_city(),
512
+                'billing_state'       => wc()->customer->get_billing_state(),
513
+                'billing_postcode'    => wc()->customer->get_billing_postcode(),
514
+                'billing_country'     => wc()->customer->get_billing_country(),
515
+                'billing_email'       => wc()->customer->get_billing_email(),
516
+                'billing_phone'       => wc()->customer->get_billing_phone(),
517
+                'shipping_first_name' => wc()->customer->get_shipping_first_name(),
518
+                'shipping_last_name'  => wc()->customer->get_shipping_last_name(),
519
+                'shipping_company'    => wc()->customer->get_shipping_company(),
520
+                'shipping_address_1'  => wc()->customer->get_shipping_address_1(),
521
+                'shipping_address_2'  => wc()->customer->get_shipping_address_2(),
522
+                'shipping_city'       => wc()->customer->get_shipping_city(),
523
+                'shipping_state'      => wc()->customer->get_shipping_state(),
524
+                'shipping_postcode'   => wc()->customer->get_shipping_postcode(),
525
+                'shipping_country'    => wc()->customer->get_shipping_country(),
526
+                'shipping_phone'      => wc()->customer->get_shipping_phone(),
527
+            ]
528
+        );
529
+    }
530 530
 }
Please login to merge, or discard this patch.
Spacing   +125 added lines, -125 removed lines patch added patch discarded remove patch
@@ -18,22 +18,22 @@  discard block
 block discarded – undo
18 18
 	 * @return \WC_Order A new order object.
19 19
 	 */
20 20
 	public function create_order_from_cart() {
21
-		if ( wc()->cart->is_empty() ) {
21
+		if (wc()->cart->is_empty()) {
22 22
 			throw new RouteException(
23 23
 				'woocommerce_rest_cart_empty',
24
-				__( 'Cannot create order from empty cart.', 'woocommerce' ),
24
+				__('Cannot create order from empty cart.', 'woocommerce'),
25 25
 				400
26 26
 			);
27 27
 		}
28 28
 
29
-		add_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
29
+		add_filter('woocommerce_default_order_status', array($this, 'default_order_status'));
30 30
 
31 31
 		$order = new \WC_Order();
32
-		$order->set_status( 'checkout-draft' );
33
-		$order->set_created_via( 'store-api' );
34
-		$this->update_order_from_cart( $order );
32
+		$order->set_status('checkout-draft');
33
+		$order->set_created_via('store-api');
34
+		$this->update_order_from_cart($order);
35 35
 
36
-		remove_filter( 'woocommerce_default_order_status', array( $this, 'default_order_status' ) );
36
+		remove_filter('woocommerce_default_order_status', array($this, 'default_order_status'));
37 37
 
38 38
 		return $order;
39 39
 	}
@@ -43,23 +43,23 @@  discard block
 block discarded – undo
43 43
 	 *
44 44
 	 * @param \WC_Order $order The order object to update.
45 45
 	 */
46
-	public function update_order_from_cart( \WC_Order $order ) {
46
+	public function update_order_from_cart(\WC_Order $order) {
47 47
 		// Ensures Local pickups are accounted for.
48
-		add_filter( 'woocommerce_order_get_tax_location', array( $this, 'handle_local_pickup_taxes' ) );
48
+		add_filter('woocommerce_order_get_tax_location', array($this, 'handle_local_pickup_taxes'));
49 49
 
50 50
 		// Ensure cart is current.
51 51
 		wc()->cart->calculate_shipping();
52 52
 		wc()->cart->calculate_totals();
53 53
 
54 54
 		// Update the current order to match the current cart.
55
-		$this->update_line_items_from_cart( $order );
56
-		$this->update_addresses_from_cart( $order );
57
-		$order->set_currency( get_woocommerce_currency() );
58
-		$order->set_prices_include_tax( 'yes' === get_option( 'woocommerce_prices_include_tax' ) );
59
-		$order->set_customer_id( get_current_user_id() );
60
-		$order->set_customer_ip_address( \WC_Geolocation::get_ip_address() );
61
-		$order->set_customer_user_agent( wc_get_user_agent() );
62
-		$order->update_meta_data( 'is_vat_exempt', wc()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no' );
55
+		$this->update_line_items_from_cart($order);
56
+		$this->update_addresses_from_cart($order);
57
+		$order->set_currency(get_woocommerce_currency());
58
+		$order->set_prices_include_tax('yes' === get_option('woocommerce_prices_include_tax'));
59
+		$order->set_customer_id(get_current_user_id());
60
+		$order->set_customer_ip_address(\WC_Geolocation::get_ip_address());
61
+		$order->set_customer_user_agent(wc_get_user_agent());
62
+		$order->update_meta_data('is_vat_exempt', wc()->cart->get_customer()->get_is_vat_exempt() ? 'yes' : 'no');
63 63
 		$order->calculate_totals();
64 64
 	}
65 65
 
@@ -68,9 +68,9 @@  discard block
 block discarded – undo
68 68
 	 *
69 69
 	 * @param \WC_Order $order Order object.
70 70
 	 */
71
-	public function sync_customer_data_with_order( \WC_Order $order ) {
72
-		if ( $order->get_customer_id() ) {
73
-			$customer = new \WC_Customer( $order->get_customer_id() );
71
+	public function sync_customer_data_with_order(\WC_Order $order) {
72
+		if ($order->get_customer_id()) {
73
+			$customer = new \WC_Customer($order->get_customer_id());
74 74
 			$customer->set_props(
75 75
 				[
76 76
 					'billing_first_name'  => $order->get_billing_first_name(),
@@ -109,14 +109,14 @@  discard block
 block discarded – undo
109 109
 	 * @throws RouteException Exception if invalid data is detected.
110 110
 	 * @param \WC_Order $order Order object.
111 111
 	 */
112
-	public function validate_order_before_payment( \WC_Order $order ) {
112
+	public function validate_order_before_payment(\WC_Order $order) {
113 113
 		$needs_shipping          = wc()->cart->needs_shipping();
114
-		$chosen_shipping_methods = wc()->session->get( 'chosen_shipping_methods' );
114
+		$chosen_shipping_methods = wc()->session->get('chosen_shipping_methods');
115 115
 
116
-		$this->validate_coupons( $order );
117
-		$this->validate_email( $order );
118
-		$this->validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods );
119
-		$this->validate_addresses( $order );
116
+		$this->validate_coupons($order);
117
+		$this->validate_email($order);
118
+		$this->validate_selected_shipping_methods($needs_shipping, $chosen_shipping_methods);
119
+		$this->validate_addresses($order);
120 120
 	}
121 121
 
122 122
 	/**
@@ -125,8 +125,8 @@  discard block
 block discarded – undo
125 125
 	 * @param string $coupon_code Coupon code.
126 126
 	 * @return \WC_Coupon Coupon object.
127 127
 	 */
128
-	protected function get_coupon( $coupon_code ) {
129
-		return new \WC_Coupon( $coupon_code );
128
+	protected function get_coupon($coupon_code) {
129
+		return new \WC_Coupon($coupon_code);
130 130
 	}
131 131
 
132 132
 	/**
@@ -135,45 +135,45 @@  discard block
 block discarded – undo
135 135
 	 * @throws RouteException Exception if invalid data is detected.
136 136
 	 * @param \WC_Order $order Order object.
137 137
 	 */
138
-	protected function validate_coupons( \WC_Order $order ) {
138
+	protected function validate_coupons(\WC_Order $order) {
139 139
 		$coupon_codes  = $order->get_coupon_codes();
140
-		$coupons       = array_filter( array_map( [ $this, 'get_coupon' ], $coupon_codes ) );
141
-		$validators    = [ 'validate_coupon_email_restriction', 'validate_coupon_usage_limit' ];
140
+		$coupons       = array_filter(array_map([$this, 'get_coupon'], $coupon_codes));
141
+		$validators    = ['validate_coupon_email_restriction', 'validate_coupon_usage_limit'];
142 142
 		$coupon_errors = [];
143 143
 
144
-		foreach ( $coupons as $coupon ) {
144
+		foreach ($coupons as $coupon) {
145 145
 			try {
146 146
 				array_walk(
147 147
 					$validators,
148
-					function( $validator, $index, $params ) {
149
-						call_user_func_array( [ $this, $validator ], $params );
148
+					function($validator, $index, $params) {
149
+						call_user_func_array([$this, $validator], $params);
150 150
 					},
151
-					[ $coupon, $order ]
151
+					[$coupon, $order]
152 152
 				);
153
-			} catch ( Exception $error ) {
154
-				$coupon_errors[ $coupon->get_code() ] = $error->getMessage();
153
+			} catch (Exception $error) {
154
+				$coupon_errors[$coupon->get_code()] = $error->getMessage();
155 155
 			}
156 156
 		}
157 157
 
158
-		if ( $coupon_errors ) {
158
+		if ($coupon_errors) {
159 159
 			// Remove all coupons that were not valid.
160
-			foreach ( $coupon_errors as $coupon_code => $message ) {
161
-				wc()->cart->remove_coupon( $coupon_code );
160
+			foreach ($coupon_errors as $coupon_code => $message) {
161
+				wc()->cart->remove_coupon($coupon_code);
162 162
 			}
163 163
 
164 164
 			// Recalculate totals.
165 165
 			wc()->cart->calculate_totals();
166 166
 
167 167
 			// Re-sync order with cart.
168
-			$this->update_order_from_cart( $order );
168
+			$this->update_order_from_cart($order);
169 169
 
170 170
 			// Return exception so customer can review before payment.
171 171
 			throw new RouteException(
172 172
 				'woocommerce_rest_cart_coupon_errors',
173 173
 				sprintf(
174 174
 					/* translators: %s Coupon codes. */
175
-					__( 'Invalid coupons were removed from the cart: "%s"', 'woocommerce' ),
176
-					implode( '", "', array_keys( $coupon_errors ) )
175
+					__('Invalid coupons were removed from the cart: "%s"', 'woocommerce'),
176
+					implode('", "', array_keys($coupon_errors))
177 177
 				),
178 178
 				409,
179 179
 				[
@@ -189,24 +189,24 @@  discard block
 block discarded – undo
189 189
 	 * @throws RouteException Exception if invalid data is detected.
190 190
 	 * @param \WC_Order $order Order object.
191 191
 	 */
192
-	protected function validate_email( \WC_Order $order ) {
192
+	protected function validate_email(\WC_Order $order) {
193 193
 		$email = $order->get_billing_email();
194 194
 
195
-		if ( empty( $email ) ) {
195
+		if (empty($email)) {
196 196
 			throw new RouteException(
197 197
 				'woocommerce_rest_missing_email_address',
198
-				__( 'A valid email address is required', 'woocommerce' ),
198
+				__('A valid email address is required', 'woocommerce'),
199 199
 				400
200 200
 			);
201 201
 		}
202 202
 
203
-		if ( ! is_email( $email ) ) {
203
+		if (!is_email($email)) {
204 204
 			throw new RouteException(
205 205
 				'woocommerce_rest_invalid_email_address',
206 206
 				sprintf(
207 207
 					/* translators: %s provided email. */
208
-					__( 'The provided email address (%s) is not valid—please provide a valid email address', 'woocommerce' ),
209
-					esc_html( $email )
208
+					__('The provided email address (%s) is not valid—please provide a valid email address', 'woocommerce'),
209
+					esc_html($email)
210 210
 				),
211 211
 				400
212 212
 			);
@@ -219,65 +219,65 @@  discard block
 block discarded – undo
219 219
 	 * @throws RouteException Exception if invalid data is detected.
220 220
 	 * @param \WC_Order $order Order object.
221 221
 	 */
222
-	protected function validate_addresses( \WC_Order $order ) {
222
+	protected function validate_addresses(\WC_Order $order) {
223 223
 		$errors           = new \WP_Error();
224 224
 		$needs_shipping   = wc()->cart->needs_shipping();
225
-		$billing_address  = $order->get_address( 'billing' );
226
-		$shipping_address = $order->get_address( 'shipping' );
225
+		$billing_address  = $order->get_address('billing');
226
+		$shipping_address = $order->get_address('shipping');
227 227
 
228
-		if ( $needs_shipping && ! $this->validate_allowed_country( $shipping_address['country'], (array) wc()->countries->get_shipping_countries() ) ) {
228
+		if ($needs_shipping && !$this->validate_allowed_country($shipping_address['country'], (array) wc()->countries->get_shipping_countries())) {
229 229
 			throw new RouteException(
230 230
 				'woocommerce_rest_invalid_address_country',
231 231
 				sprintf(
232 232
 					/* translators: %s country code. */
233
-					__( 'Sorry, we do not ship orders to the provided country (%s)', 'woocommerce' ),
233
+					__('Sorry, we do not ship orders to the provided country (%s)', 'woocommerce'),
234 234
 					$shipping_address['country']
235 235
 				),
236 236
 				400,
237 237
 				[
238
-					'allowed_countries' => array_keys( wc()->countries->get_shipping_countries() ),
238
+					'allowed_countries' => array_keys(wc()->countries->get_shipping_countries()),
239 239
 				]
240 240
 			);
241 241
 		}
242 242
 
243
-		if ( ! $this->validate_allowed_country( $billing_address['country'], (array) wc()->countries->get_allowed_countries() ) ) {
243
+		if (!$this->validate_allowed_country($billing_address['country'], (array) wc()->countries->get_allowed_countries())) {
244 244
 			throw new RouteException(
245 245
 				'woocommerce_rest_invalid_address_country',
246 246
 				sprintf(
247 247
 					/* translators: %s country code. */
248
-					__( 'Sorry, we do not allow orders from the provided country (%s)', 'woocommerce' ),
248
+					__('Sorry, we do not allow orders from the provided country (%s)', 'woocommerce'),
249 249
 					$billing_address['country']
250 250
 				),
251 251
 				400,
252 252
 				[
253
-					'allowed_countries' => array_keys( wc()->countries->get_allowed_countries() ),
253
+					'allowed_countries' => array_keys(wc()->countries->get_allowed_countries()),
254 254
 				]
255 255
 			);
256 256
 		}
257 257
 
258
-		if ( $needs_shipping ) {
259
-			$this->validate_address_fields( $shipping_address, 'shipping', $errors );
258
+		if ($needs_shipping) {
259
+			$this->validate_address_fields($shipping_address, 'shipping', $errors);
260 260
 		}
261
-		$this->validate_address_fields( $billing_address, 'billing', $errors );
261
+		$this->validate_address_fields($billing_address, 'billing', $errors);
262 262
 
263
-		if ( ! $errors->has_errors() ) {
263
+		if (!$errors->has_errors()) {
264 264
 			return;
265 265
 		}
266 266
 
267 267
 		$errors_by_code = [];
268 268
 		$error_codes    = $errors->get_error_codes();
269
-		foreach ( $error_codes as $code ) {
270
-			$errors_by_code[ $code ] = $errors->get_error_messages( $code );
269
+		foreach ($error_codes as $code) {
270
+			$errors_by_code[$code] = $errors->get_error_messages($code);
271 271
 		}
272 272
 
273 273
 		// Surface errors from first code.
274
-		foreach ( $errors_by_code as $code => $error_messages ) {
274
+		foreach ($errors_by_code as $code => $error_messages) {
275 275
 			throw new RouteException(
276 276
 				'woocommerce_rest_invalid_address',
277 277
 				sprintf(
278 278
 					/* translators: %s Address type. */
279
-					__( 'There was a problem with the provided %s:', 'woocommerce' ) . ' ' . implode( ', ', $error_messages ),
280
-					'shipping' === $code ? __( 'shipping address', 'woocommerce' ) : __( 'billing address', 'woocommerce' )
279
+					__('There was a problem with the provided %s:', 'woocommerce') . ' ' . implode(', ', $error_messages),
280
+					'shipping' === $code ? __('shipping address', 'woocommerce') : __('billing address', 'woocommerce')
281 281
 				),
282 282
 				400,
283 283
 				[
@@ -294,8 +294,8 @@  discard block
 block discarded – undo
294 294
 	 * @param array  $allowed_countries List of valid country codes.
295 295
 	 * @return boolean True if valid.
296 296
 	 */
297
-	protected function validate_allowed_country( $country, array $allowed_countries ) {
298
-		return array_key_exists( $country, $allowed_countries );
297
+	protected function validate_allowed_country($country, array $allowed_countries) {
298
+		return array_key_exists($country, $allowed_countries);
299 299
 	}
300 300
 
301 301
 	/**
@@ -305,9 +305,9 @@  discard block
 block discarded – undo
305 305
 	 * @param string    $address_type billing or shipping address, used in error messages.
306 306
 	 * @param \WP_Error $errors Error object.
307 307
 	 */
308
-	protected function validate_address_fields( $address, $address_type, \WP_Error $errors ) {
308
+	protected function validate_address_fields($address, $address_type, \WP_Error $errors) {
309 309
 		$all_locales    = wc()->countries->get_country_locale();
310
-		$current_locale = isset( $all_locales[ $address['country'] ] ) ? $all_locales[ $address['country'] ] : [];
310
+		$current_locale = isset($all_locales[$address['country']]) ? $all_locales[$address['country']] : [];
311 311
 
312 312
 		/**
313 313
 		 * We are not using wc()->counties->get_default_address_fields() here because that is filtered. Instead, this array
@@ -315,56 +315,56 @@  discard block
 block discarded – undo
315 315
 		 */
316 316
 		$address_fields = [
317 317
 			'first_name' => [
318
-				'label'    => __( 'First name', 'woocommerce' ),
318
+				'label'    => __('First name', 'woocommerce'),
319 319
 				'required' => true,
320 320
 			],
321 321
 			'last_name'  => [
322
-				'label'    => __( 'Last name', 'woocommerce' ),
322
+				'label'    => __('Last name', 'woocommerce'),
323 323
 				'required' => true,
324 324
 			],
325 325
 			'company'    => [
326
-				'label'    => __( 'Company', 'woocommerce' ),
326
+				'label'    => __('Company', 'woocommerce'),
327 327
 				'required' => false,
328 328
 			],
329 329
 			'address_1'  => [
330
-				'label'    => __( 'Address', 'woocommerce' ),
330
+				'label'    => __('Address', 'woocommerce'),
331 331
 				'required' => true,
332 332
 			],
333 333
 			'address_2'  => [
334
-				'label'    => __( 'Apartment, suite, etc.', 'woocommerce' ),
334
+				'label'    => __('Apartment, suite, etc.', 'woocommerce'),
335 335
 				'required' => false,
336 336
 			],
337 337
 			'country'    => [
338
-				'label'    => __( 'Country/Region', 'woocommerce' ),
338
+				'label'    => __('Country/Region', 'woocommerce'),
339 339
 				'required' => true,
340 340
 			],
341 341
 			'city'       => [
342
-				'label'    => __( 'City', 'woocommerce' ),
342
+				'label'    => __('City', 'woocommerce'),
343 343
 				'required' => true,
344 344
 			],
345 345
 			'state'      => [
346
-				'label'    => __( 'State/County', 'woocommerce' ),
346
+				'label'    => __('State/County', 'woocommerce'),
347 347
 				'required' => true,
348 348
 			],
349 349
 			'postcode'   => [
350
-				'label'    => __( 'Postal code', 'woocommerce' ),
350
+				'label'    => __('Postal code', 'woocommerce'),
351 351
 				'required' => true,
352 352
 			],
353 353
 		];
354 354
 
355
-		if ( $current_locale ) {
356
-			foreach ( $current_locale as $key => $field ) {
357
-				if ( isset( $address_fields[ $key ] ) ) {
358
-					$address_fields[ $key ]['label']    = isset( $field['label'] ) ? $field['label'] : $address_fields[ $key ]['label'];
359
-					$address_fields[ $key ]['required'] = isset( $field['required'] ) ? $field['required'] : $address_fields[ $key ]['required'];
355
+		if ($current_locale) {
356
+			foreach ($current_locale as $key => $field) {
357
+				if (isset($address_fields[$key])) {
358
+					$address_fields[$key]['label']    = isset($field['label']) ? $field['label'] : $address_fields[$key]['label'];
359
+					$address_fields[$key]['required'] = isset($field['required']) ? $field['required'] : $address_fields[$key]['required'];
360 360
 				}
361 361
 			}
362 362
 		}
363 363
 
364
-		foreach ( $address_fields as $address_field_key => $address_field ) {
365
-			if ( empty( $address[ $address_field_key ] ) && $address_field['required'] ) {
364
+		foreach ($address_fields as $address_field_key => $address_field) {
365
+			if (empty($address[$address_field_key]) && $address_field['required']) {
366 366
 				/* translators: %s Field label. */
367
-				$errors->add( $address_type, sprintf( __( '%s is required', 'woocommerce' ), $address_field['label'] ), $address_field_key );
367
+				$errors->add($address_type, sprintf(__('%s is required', 'woocommerce'), $address_field['label']), $address_field_key);
368 368
 			}
369 369
 		}
370 370
 	}
@@ -376,11 +376,11 @@  discard block
 block discarded – undo
376 376
 	 * @param \WC_Coupon $coupon Coupon object applied to the cart.
377 377
 	 * @param \WC_Order  $order Order object.
378 378
 	 */
379
-	protected function validate_coupon_email_restriction( \WC_Coupon $coupon, \WC_Order $order ) {
379
+	protected function validate_coupon_email_restriction(\WC_Coupon $coupon, \WC_Order $order) {
380 380
 		$restrictions = $coupon->get_email_restrictions();
381 381
 
382
-		if ( ! empty( $restrictions ) && $order->get_billing_email() && ! wc()->cart->is_coupon_emails_allowed( [ $order->get_billing_email() ], $restrictions ) ) {
383
-			throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_NOT_YOURS_REMOVED ) );
382
+		if (!empty($restrictions) && $order->get_billing_email() && !wc()->cart->is_coupon_emails_allowed([$order->get_billing_email()], $restrictions)) {
383
+			throw new Exception($coupon->get_coupon_error(\WC_Coupon::E_WC_COUPON_NOT_YOURS_REMOVED));
384 384
 		}
385 385
 	}
386 386
 
@@ -391,15 +391,15 @@  discard block
 block discarded – undo
391 391
 	 * @param \WC_Coupon $coupon Coupon object applied to the cart.
392 392
 	 * @param \WC_Order  $order Order object.
393 393
 	 */
394
-	protected function validate_coupon_usage_limit( \WC_Coupon $coupon, \WC_Order $order ) {
394
+	protected function validate_coupon_usage_limit(\WC_Coupon $coupon, \WC_Order $order) {
395 395
 		$coupon_usage_limit = $coupon->get_usage_limit_per_user();
396 396
 
397
-		if ( $coupon_usage_limit > 0 ) {
397
+		if ($coupon_usage_limit > 0) {
398 398
 			$data_store  = $coupon->get_data_store();
399
-			$usage_count = $order->get_customer_id() ? $data_store->get_usage_by_user_id( $coupon, $order->get_customer_id() ) : $data_store->get_usage_by_email( $coupon, $order->get_billing_email() );
399
+			$usage_count = $order->get_customer_id() ? $data_store->get_usage_by_user_id($coupon, $order->get_customer_id()) : $data_store->get_usage_by_email($coupon, $order->get_billing_email());
400 400
 
401
-			if ( $usage_count >= $coupon_usage_limit ) {
402
-				throw new Exception( $coupon->get_coupon_error( \WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED ) );
401
+			if ($usage_count >= $coupon_usage_limit) {
402
+				throw new Exception($coupon->get_coupon_error(\WC_Coupon::E_WC_COUPON_USAGE_LIMIT_REACHED));
403 403
 			}
404 404
 		}
405 405
 	}
@@ -411,16 +411,16 @@  discard block
 block discarded – undo
411 411
 	 * @param boolean $needs_shipping Current order needs shipping.
412 412
 	 * @param array   $chosen_shipping_methods Array of shipping methods.
413 413
 	 */
414
-	public function validate_selected_shipping_methods( $needs_shipping, $chosen_shipping_methods = array() ) {
415
-		if ( ! $needs_shipping || ! is_array( $chosen_shipping_methods ) ) {
414
+	public function validate_selected_shipping_methods($needs_shipping, $chosen_shipping_methods = array()) {
415
+		if (!$needs_shipping || !is_array($chosen_shipping_methods)) {
416 416
 			return;
417 417
 		}
418 418
 
419
-		foreach ( $chosen_shipping_methods as $chosen_shipping_method ) {
420
-			if ( false === $chosen_shipping_method ) {
419
+		foreach ($chosen_shipping_methods as $chosen_shipping_method) {
420
+			if (false === $chosen_shipping_method) {
421 421
 				throw new RouteException(
422 422
 					'woocommerce_rest_invalid_shipping_option',
423
-					__( 'Sorry, this order requires a shipping option.', 'woocommerce' ),
423
+					__('Sorry, this order requires a shipping option.', 'woocommerce'),
424 424
 					400,
425 425
 					[]
426 426
 				);
@@ -445,10 +445,10 @@  discard block
 block discarded – undo
445 445
 	 * @param array $location Taxes location.
446 446
 	 * @return array updated location that accounts for local pickup.
447 447
 	 */
448
-	public function handle_local_pickup_taxes( $location ) {
448
+	public function handle_local_pickup_taxes($location) {
449 449
 		$customer = wc()->customer;
450 450
 
451
-		if ( ! empty( $customer ) ) {
451
+		if (!empty($customer)) {
452 452
 			return $customer->get_taxable_address();
453 453
 		}
454 454
 
@@ -459,39 +459,39 @@  discard block
 block discarded – undo
459 459
 	 *
460 460
 	 * @param \WC_Order $order The order object to update.
461 461
 	 */
462
-	protected function update_line_items_from_cart( \WC_Order $order ) {
462
+	protected function update_line_items_from_cart(\WC_Order $order) {
463 463
 		$cart_controller = new CartController();
464 464
 		$cart            = $cart_controller->get_cart_instance();
465 465
 		$cart_hashes     = $cart_controller->get_cart_hashes();
466 466
 
467
-		if ( $order->get_cart_hash() !== $cart_hashes['line_items'] ) {
468
-			$order->set_cart_hash( $cart_hashes['line_items'] );
469
-			$order->remove_order_items( 'line_item' );
470
-			wc()->checkout->create_order_line_items( $order, $cart );
467
+		if ($order->get_cart_hash() !== $cart_hashes['line_items']) {
468
+			$order->set_cart_hash($cart_hashes['line_items']);
469
+			$order->remove_order_items('line_item');
470
+			wc()->checkout->create_order_line_items($order, $cart);
471 471
 		}
472 472
 
473
-		if ( $order->get_meta_data( '_shipping_hash' ) !== $cart_hashes['shipping'] ) {
474
-			$order->update_meta_data( '_shipping_hash', $cart_hashes['shipping'] );
475
-			$order->remove_order_items( 'shipping' );
476
-			wc()->checkout->create_order_shipping_lines( $order, wc()->session->get( 'chosen_shipping_methods' ), wc()->shipping()->get_packages() );
473
+		if ($order->get_meta_data('_shipping_hash') !== $cart_hashes['shipping']) {
474
+			$order->update_meta_data('_shipping_hash', $cart_hashes['shipping']);
475
+			$order->remove_order_items('shipping');
476
+			wc()->checkout->create_order_shipping_lines($order, wc()->session->get('chosen_shipping_methods'), wc()->shipping()->get_packages());
477 477
 		}
478 478
 
479
-		if ( $order->get_meta_data( '_coupons_hash' ) !== $cart_hashes['coupons'] ) {
480
-			$order->remove_order_items( 'coupon' );
481
-			$order->update_meta_data( '_coupons_hash', $cart_hashes['coupons'] );
482
-			wc()->checkout->create_order_coupon_lines( $order, $cart );
479
+		if ($order->get_meta_data('_coupons_hash') !== $cart_hashes['coupons']) {
480
+			$order->remove_order_items('coupon');
481
+			$order->update_meta_data('_coupons_hash', $cart_hashes['coupons']);
482
+			wc()->checkout->create_order_coupon_lines($order, $cart);
483 483
 		}
484 484
 
485
-		if ( $order->get_meta_data( '_fees_hash' ) !== $cart_hashes['fees'] ) {
486
-			$order->update_meta_data( '_fees_hash', $cart_hashes['fees'] );
487
-			$order->remove_order_items( 'fee' );
488
-			wc()->checkout->create_order_fee_lines( $order, $cart );
485
+		if ($order->get_meta_data('_fees_hash') !== $cart_hashes['fees']) {
486
+			$order->update_meta_data('_fees_hash', $cart_hashes['fees']);
487
+			$order->remove_order_items('fee');
488
+			wc()->checkout->create_order_fee_lines($order, $cart);
489 489
 		}
490 490
 
491
-		if ( $order->get_meta_data( '_taxes_hash' ) !== $cart_hashes['taxes'] ) {
492
-			$order->update_meta_data( '_taxes_hash', $cart_hashes['taxes'] );
493
-			$order->remove_order_items( 'tax' );
494
-			wc()->checkout->create_order_tax_lines( $order, $cart );
491
+		if ($order->get_meta_data('_taxes_hash') !== $cart_hashes['taxes']) {
492
+			$order->update_meta_data('_taxes_hash', $cart_hashes['taxes']);
493
+			$order->remove_order_items('tax');
494
+			wc()->checkout->create_order_tax_lines($order, $cart);
495 495
 		}
496 496
 	}
497 497
 
@@ -500,7 +500,7 @@  discard block
 block discarded – undo
500 500
 	 *
501 501
 	 * @param \WC_Order $order The order object to update.
502 502
 	 */
503
-	protected function update_addresses_from_cart( \WC_Order $order ) {
503
+	protected function update_addresses_from_cart(\WC_Order $order) {
504 504
 		$order->set_props(
505 505
 			[
506 506
 				'billing_first_name'  => wc()->customer->get_billing_first_name(),
Please login to merge, or discard this patch.
plugins/woocommerce/packages/woocommerce-blocks/src/StoreApi/Formatters.php 2 patches
Indentation   +32 added lines, -32 removed lines patch added patch discarded remove patch
@@ -10,38 +10,38 @@
 block discarded – undo
10 10
  * Allows formatter classes to be registered. Formatters are exposed to extensions via the ExtendSchema class.
11 11
  */
12 12
 class Formatters {
13
-	/**
14
-	 * Holds an array of formatter class instances.
15
-	 *
16
-	 * @var array
17
-	 */
18
-	private $formatters = [];
13
+    /**
14
+     * Holds an array of formatter class instances.
15
+     *
16
+     * @var array
17
+     */
18
+    private $formatters = [];
19 19
 
20
-	/**
21
-	 * Get a new instance of a formatter class.
22
-	 *
23
-	 * @throws Exception An Exception is thrown if a non-existing formatter is used and the user is admin.
24
-	 *
25
-	 * @param string $name Name of the formatter.
26
-	 * @return FormatterInterface Formatter class instance.
27
-	 */
28
-	public function __get( $name ) {
29
-		if ( ! isset( $this->formatters[ $name ] ) ) {
30
-			if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'manage_woocommerce' ) ) {
31
-				throw new Exception( $name . ' formatter does not exist' );
32
-			}
33
-			return new DefaultFormatter();
34
-		}
35
-		return $this->formatters[ $name ];
36
-	}
20
+    /**
21
+     * Get a new instance of a formatter class.
22
+     *
23
+     * @throws Exception An Exception is thrown if a non-existing formatter is used and the user is admin.
24
+     *
25
+     * @param string $name Name of the formatter.
26
+     * @return FormatterInterface Formatter class instance.
27
+     */
28
+    public function __get( $name ) {
29
+        if ( ! isset( $this->formatters[ $name ] ) ) {
30
+            if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'manage_woocommerce' ) ) {
31
+                throw new Exception( $name . ' formatter does not exist' );
32
+            }
33
+            return new DefaultFormatter();
34
+        }
35
+        return $this->formatters[ $name ];
36
+    }
37 37
 
38
-	/**
39
-	 * Register a formatter class for usage.
40
-	 *
41
-	 * @param string $name Name of the formatter.
42
-	 * @param string $class A formatter class name.
43
-	 */
44
-	public function register( $name, $class ) {
45
-		$this->formatters[ $name ] = new $class();
46
-	}
38
+    /**
39
+     * Register a formatter class for usage.
40
+     *
41
+     * @param string $name Name of the formatter.
42
+     * @param string $class A formatter class name.
43
+     */
44
+    public function register( $name, $class ) {
45
+        $this->formatters[ $name ] = new $class();
46
+    }
47 47
 }
Please login to merge, or discard this patch.
Spacing   +7 added lines, -7 removed lines patch added patch discarded remove patch
@@ -25,14 +25,14 @@  discard block
 block discarded – undo
25 25
 	 * @param string $name Name of the formatter.
26 26
 	 * @return FormatterInterface Formatter class instance.
27 27
 	 */
28
-	public function __get( $name ) {
29
-		if ( ! isset( $this->formatters[ $name ] ) ) {
30
-			if ( defined( 'WP_DEBUG' ) && WP_DEBUG && current_user_can( 'manage_woocommerce' ) ) {
31
-				throw new Exception( $name . ' formatter does not exist' );
28
+	public function __get($name) {
29
+		if (!isset($this->formatters[$name])) {
30
+			if (defined('WP_DEBUG') && WP_DEBUG && current_user_can('manage_woocommerce')) {
31
+				throw new Exception($name . ' formatter does not exist');
32 32
 			}
33 33
 			return new DefaultFormatter();
34 34
 		}
35
-		return $this->formatters[ $name ];
35
+		return $this->formatters[$name];
36 36
 	}
37 37
 
38 38
 	/**
@@ -41,7 +41,7 @@  discard block
 block discarded – undo
41 41
 	 * @param string $name Name of the formatter.
42 42
 	 * @param string $class A formatter class name.
43 43
 	 */
44
-	public function register( $name, $class ) {
45
-		$this->formatters[ $name ] = new $class();
44
+	public function register($name, $class) {
45
+		$this->formatters[$name] = new $class();
46 46
 	}
47 47
 }
Please login to merge, or discard this patch.