Add_To_Cart
Summary
Handles requests from the Add to Cart button for products
Source
File: src/BigCommerce/Cart/Add_To_Cart.php
class Add_To_Cart { const ACTION = 'cart'; /** * @param int $post_id * @param CartApi $cart_api * * @return void * @action bigcommerce/action_endpoint/ . self::ACTION */ public function handle_request( $post_id, CartApi $cart_api ) { if ( ! $this->validate_request( $post_id, $_POST ) ) { $error = new \WP_Error( 'unknown_product', __( 'We were unable to process your request. Please go back and try again.', 'bigcommerce' ) ); do_action( 'bigcommerce/form/error', $error, $_POST, home_url( '/' ) ); return; } $product = new Product( $post_id ); $product_id = $product->bc_id(); $variant_id = $this->get_variant_id( $product, $_POST ); $options = []; // Options are sanitized bellow $submitted_options = empty( $_POST[ 'option' ] ) ? [] : (array) $_POST[ 'option' ]; // phpcs:ignore $option_config = $product->options(); $modifier_config = $product->modifiers(); foreach ( $option_config as $config ) { if ( array_key_exists( $config[ 'id' ], $submitted_options ) ) { $options[ $config[ 'id' ] ] = absint( $submitted_options[ $config[ 'id' ] ] ); } } foreach ( $modifier_config as $config ) { if ( array_key_exists( $config[ 'id' ], $submitted_options ) ) { $options[ $config[ 'id' ] ] = $this->sanitize_option( $submitted_options[ $config[ 'id' ] ], $config ); } } $quantity = array_key_exists( 'quantity', $_POST ) ? absint( $_POST[ 'quantity' ] ) : 1; $cart = new Cart( $cart_api ); try { $response = $cart->add_line_item( $product_id, $options, $quantity ); $this->handle_response( $response, $cart, $post_id, $product_id, $variant_id ); } catch ( ApiException $e ) { $this->handle_exception( $e, $cart ); } } private function sanitize_option( $value, $config ) { switch ( $config[ 'type' ] ) { case 'date': return strtotime( $value ); case 'multi_line_text': return sanitize_textarea_field( $value ); case 'numbers_only_text': return filter_var( $value, FILTER_SANITIZE_NUMBER_FLOAT, FILTER_FLAG_ALLOW_FRACTION|FILTER_FLAG_ALLOW_THOUSAND ); case 'text': return sanitize_text_field( $value ); default: // checkboxes, selects, and radios return (int) $value; } } /** * @param \BigCommerce\Api\v3\Model\Cart|null $response * @param Cart $cart * @param int $post_id * * @param int $product_id * @param int $variant_id * * @return void */ protected function handle_response( $response, Cart $cart, $post_id, $product_id, $variant_id ) { $cart_url = $cart->get_cart_url(); /** * Triggered when a form is successfully processed. * * @param string $message The message that will display to the user * @param array $submission The data submitted to the form * @param string $url The URL to redirect the user to * @param array $data Additional data to store with the message */ do_action( 'bigcommerce/form/success', __( '1 item added to Cart', 'bigcommerce' ), $_POST, $cart_url, [ 'key' => 'add_to_cart', 'cart_id' => $cart->get_cart_id(), 'post_id' => $post_id, 'product_id' => $product_id, 'variant_id' => $variant_id, ] ); wp_safe_redirect( esc_url_raw( $cart_url ), 303 ); exit(); } /** * @param ApiException $e * @param Cart $cart * * @return void */ protected function handle_exception( ApiException $e, $cart ) { if ( strpos( (string) $e->getCode(), '4' ) === 0 ) { $body = $e->getResponseBody(); if ( $body && ! empty( $body->title ) ) { $message = sprintf( '[%d] %s', $e->getCode(), $body->title ); } else { $message = $e->getMessage(); } $error = new \WP_Error( 'api_error', sprintf( __( 'There was an error adding this product to your cart. Error message: "%s"', 'bigcommerce' ), $message ), [ 'exception' => [ 'message' => $e->getMessage(), 'code' => $e->getCode() ] ] ); } else { $error = new \WP_Error( 'api_error', __( 'There was an error adding this product to your cart. It might be out of stock or unavailable.', 'bigcommerce' ), [ 'exception' => [ 'message' => $e->getMessage(), 'code' => $e->getCode(), ], ] ); } do_action( 'bigcommerce/form/error', $error, $_POST, $cart->get_cart_url() ); } protected function validate_request( $post_id, $submission ) { $post = get_post( $post_id ); if ( empty( $post ) ) { return false; } if ( Product::NAME !== $post->post_type ) { return false; } if ( $post->post_status !== 'publish' ) { return false; } return true; } /** * Get product variant id from submission * * @param Product $product * @param $submission * * @return int */ protected function get_variant_id( Product $product, $submission ) { if ( ! empty( $submission[ 'variant_id' ] ) ) { return (int) $submission[ 'variant_id' ]; } $data = $product->get_source_data(); foreach ( $data->variants as $variant ) { foreach ( $variant->option_values as $option ) { $key = 'option-' . $option->option_id; if ( ! isset( $submission[ $key ] ) ) { continue 2; } if ( $submission[ $key ] != $option->id ) { continue 2; } } // all options matched, we have a winner return $variant->id; } // fall back to the first variant if ( ! empty( $data->variants ) ) { return reset( $data->variants )->id; } return 0; } }