woothemes /
woocommerce
This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
| 1 | <?php |
||
| 2 | |||
| 3 | if ( ! defined( 'ABSPATH' ) ) { |
||
| 4 | exit; // Exit if accessed directly |
||
| 5 | } |
||
| 6 | |||
| 7 | /** |
||
| 8 | * Checkout |
||
| 9 | * |
||
| 10 | * The WooCommerce checkout class handles the checkout process, collecting user data and processing the payment. |
||
| 11 | * |
||
| 12 | * @class WC_Checkout |
||
| 13 | * @version 2.1.0 |
||
| 14 | * @package WooCommerce/Classes |
||
| 15 | * @category Class |
||
| 16 | * @author WooThemes |
||
| 17 | */ |
||
| 18 | class WC_Checkout { |
||
| 19 | |||
| 20 | /** @var array Array of posted form data. */ |
||
| 21 | public $posted; |
||
| 22 | |||
| 23 | /** @var array Array of fields to display on the checkout. */ |
||
| 24 | public $checkout_fields; |
||
| 25 | |||
| 26 | /** @var bool Whether or not the user must create an account to checkout. */ |
||
| 27 | public $must_create_account; |
||
| 28 | |||
| 29 | /** @var bool Whether or not signups are allowed. */ |
||
| 30 | public $enable_signup; |
||
| 31 | |||
| 32 | /** @var object The shipping method being used. */ |
||
| 33 | private $shipping_method; |
||
| 34 | |||
| 35 | /** @var WC_Payment_Gateway|string The payment gateway being used. */ |
||
| 36 | private $payment_method; |
||
| 37 | |||
| 38 | /** @var int ID of customer. */ |
||
| 39 | private $customer_id; |
||
| 40 | |||
| 41 | /** @var array Where shipping_methods are stored. */ |
||
| 42 | public $shipping_methods; |
||
| 43 | |||
| 44 | /** |
||
| 45 | * @var WC_Checkout The single instance of the class |
||
| 46 | * @since 2.1 |
||
| 47 | */ |
||
| 48 | protected static $_instance = null; |
||
| 49 | |||
| 50 | /** @var Bool */ |
||
| 51 | public $enable_guest_checkout; |
||
| 52 | |||
| 53 | /** |
||
| 54 | * Main WC_Checkout Instance. |
||
| 55 | * |
||
| 56 | * Ensures only one instance of WC_Checkout is loaded or can be loaded. |
||
| 57 | * |
||
| 58 | * @since 2.1 |
||
| 59 | * @static |
||
| 60 | * @return WC_Checkout Main instance |
||
| 61 | */ |
||
| 62 | public static function instance() { |
||
| 63 | if ( is_null( self::$_instance ) ) |
||
| 64 | self::$_instance = new self(); |
||
| 65 | return self::$_instance; |
||
| 66 | } |
||
| 67 | |||
| 68 | /** |
||
| 69 | * Cloning is forbidden. |
||
| 70 | * |
||
| 71 | * @since 2.1 |
||
| 72 | */ |
||
| 73 | public function __clone() { |
||
| 74 | _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'woocommerce' ), '2.1' ); |
||
| 75 | } |
||
| 76 | |||
| 77 | /** |
||
| 78 | * Unserializing instances of this class is forbidden. |
||
| 79 | * |
||
| 80 | * @since 2.1 |
||
| 81 | */ |
||
| 82 | public function __wakeup() { |
||
| 83 | _doing_it_wrong( __FUNCTION__, __( 'Cheatin’ huh?', 'woocommerce' ), '2.1' ); |
||
| 84 | } |
||
| 85 | |||
| 86 | /** |
||
| 87 | * Constructor for the checkout class. Hooks in methods and defines checkout fields. |
||
| 88 | * |
||
| 89 | * @access public |
||
| 90 | */ |
||
| 91 | public function __construct () { |
||
| 92 | add_action( 'woocommerce_checkout_billing', array( $this,'checkout_form_billing' ) ); |
||
| 93 | add_action( 'woocommerce_checkout_shipping', array( $this,'checkout_form_shipping' ) ); |
||
| 94 | |||
| 95 | $this->enable_signup = get_option( 'woocommerce_enable_signup_and_login_from_checkout' ) == 'yes' ? true : false; |
||
| 96 | $this->enable_guest_checkout = get_option( 'woocommerce_enable_guest_checkout' ) == 'yes' ? true : false; |
||
| 97 | $this->must_create_account = $this->enable_guest_checkout || is_user_logged_in() ? false : true; |
||
| 98 | |||
| 99 | // Define all Checkout fields |
||
| 100 | $this->checkout_fields['billing'] = WC()->countries->get_address_fields( $this->get_value( 'billing_country' ), 'billing_' ); |
||
| 101 | $this->checkout_fields['shipping'] = WC()->countries->get_address_fields( $this->get_value( 'shipping_country' ), 'shipping_' ); |
||
| 102 | |||
| 103 | View Code Duplication | if ( get_option( 'woocommerce_registration_generate_username' ) == 'no' ) { |
|
| 104 | $this->checkout_fields['account']['account_username'] = array( |
||
| 105 | 'type' => 'text', |
||
| 106 | 'label' => __( 'Account username', 'woocommerce' ), |
||
| 107 | 'required' => true, |
||
| 108 | 'placeholder' => _x( 'Username', 'placeholder', 'woocommerce' ) |
||
| 109 | ); |
||
| 110 | } |
||
| 111 | |||
| 112 | View Code Duplication | if ( get_option( 'woocommerce_registration_generate_password' ) == 'no' ) { |
|
| 113 | $this->checkout_fields['account']['account_password'] = array( |
||
| 114 | 'type' => 'password', |
||
| 115 | 'label' => __( 'Account password', 'woocommerce' ), |
||
| 116 | 'required' => true, |
||
| 117 | 'placeholder' => _x( 'Password', 'placeholder', 'woocommerce' ) |
||
| 118 | ); |
||
| 119 | } |
||
| 120 | |||
| 121 | $this->checkout_fields['order'] = array( |
||
| 122 | 'order_comments' => array( |
||
| 123 | 'type' => 'textarea', |
||
| 124 | 'class' => array('notes'), |
||
| 125 | 'label' => __( 'Order Notes', 'woocommerce' ), |
||
| 126 | 'placeholder' => _x('Notes about your order, e.g. special notes for delivery.', 'placeholder', 'woocommerce') |
||
| 127 | ) |
||
| 128 | ); |
||
| 129 | |||
| 130 | $this->checkout_fields = apply_filters( 'woocommerce_checkout_fields', $this->checkout_fields ); |
||
| 131 | |||
| 132 | do_action( 'woocommerce_checkout_init', $this ); |
||
| 133 | } |
||
| 134 | |||
| 135 | /** |
||
| 136 | * Checkout process. |
||
| 137 | */ |
||
| 138 | public function check_cart_items() { |
||
| 139 | // When we process the checkout, lets ensure cart items are rechecked to prevent checkout |
||
| 140 | do_action('woocommerce_check_cart_items'); |
||
| 141 | } |
||
| 142 | |||
| 143 | /** |
||
| 144 | * Output the billing information form. |
||
| 145 | */ |
||
| 146 | public function checkout_form_billing() { |
||
| 147 | wc_get_template( 'checkout/form-billing.php', array( 'checkout' => $this ) ); |
||
| 148 | } |
||
| 149 | |||
| 150 | /** |
||
| 151 | * Output the shipping information form. |
||
| 152 | */ |
||
| 153 | public function checkout_form_shipping() { |
||
| 154 | wc_get_template( 'checkout/form-shipping.php', array( 'checkout' => $this ) ); |
||
| 155 | } |
||
| 156 | |||
| 157 | /** |
||
| 158 | * Create an order. Error codes: |
||
| 159 | * 520 - Cannot insert order into the database. |
||
| 160 | * 521 - Cannot get order after creation. |
||
| 161 | * 522 - Cannot update order. |
||
| 162 | * 525 - Cannot create line item. |
||
| 163 | * 526 - Cannot create fee item. |
||
| 164 | * 527 - Cannot create shipping item. |
||
| 165 | * 528 - Cannot create tax item. |
||
| 166 | * 529 - Cannot create coupon item. |
||
| 167 | * @access public |
||
| 168 | * @throws Exception |
||
| 169 | * @return int|WP_ERROR |
||
| 170 | */ |
||
| 171 | public function create_order() { |
||
| 172 | global $wpdb; |
||
| 173 | |||
| 174 | // Give plugins the opportunity to create an order themselves |
||
| 175 | if ( $order_id = apply_filters( 'woocommerce_create_order', null, $this ) ) { |
||
| 176 | return $order_id; |
||
| 177 | } |
||
| 178 | |||
| 179 | try { |
||
| 180 | // Start transaction if available |
||
| 181 | wc_transaction_query( 'start' ); |
||
| 182 | |||
| 183 | $order_data = array( |
||
| 184 | 'status' => apply_filters( 'woocommerce_default_order_status', 'pending' ), |
||
| 185 | 'customer_id' => $this->customer_id, |
||
| 186 | 'customer_note' => isset( $this->posted['order_comments'] ) ? $this->posted['order_comments'] : '', |
||
| 187 | 'cart_hash' => md5( json_encode( wc_clean( WC()->cart->get_cart_for_session() ) ) . WC()->cart->total ), |
||
| 188 | 'created_via' => 'checkout', |
||
| 189 | ); |
||
| 190 | |||
| 191 | // Insert or update the post data |
||
| 192 | $order_id = absint( WC()->session->order_awaiting_payment ); |
||
| 193 | |||
| 194 | /** |
||
| 195 | * If there is an order pending payment, we can resume it here so |
||
| 196 | * long as it has not changed. If the order has changed, i.e. |
||
| 197 | * different items or cost, create a new order. We use a hash to |
||
| 198 | * detect changes which is based on cart items + order total. |
||
| 199 | */ |
||
| 200 | if ( $order_id && $order_data['cart_hash'] === get_post_meta( $order_id, '_cart_hash', true ) && ( $order = wc_get_order( $order_id ) ) && $order->has_status( array( 'pending', 'failed' ) ) ) { |
||
| 201 | |||
| 202 | $order_data['order_id'] = $order_id; |
||
| 203 | $order = wc_update_order( $order_data ); |
||
| 204 | |||
| 205 | if ( is_wp_error( $order ) ) { |
||
| 206 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 522 ) ); |
||
| 207 | } else { |
||
| 208 | $order->remove_order_items(); |
||
| 209 | do_action( 'woocommerce_resume_order', $order_id ); |
||
| 210 | } |
||
| 211 | |||
| 212 | } else { |
||
| 213 | |||
| 214 | $order = wc_create_order( $order_data ); |
||
| 215 | |||
| 216 | if ( is_wp_error( $order ) ) { |
||
| 217 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 520 ) ); |
||
| 218 | } elseif ( false === $order ) { |
||
| 219 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 521 ) ); |
||
| 220 | } else { |
||
| 221 | $order_id = $order->id; |
||
| 222 | do_action( 'woocommerce_new_order', $order_id ); |
||
| 223 | } |
||
| 224 | } |
||
| 225 | |||
| 226 | // Store the line items to the new/resumed order |
||
| 227 | foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) { |
||
| 228 | $item_id = $order->add_product( |
||
| 229 | $values['data'], |
||
| 230 | $values['quantity'], |
||
| 231 | array( |
||
| 232 | 'variation' => $values['variation'], |
||
| 233 | 'totals' => array( |
||
| 234 | 'subtotal' => $values['line_subtotal'], |
||
| 235 | 'subtotal_tax' => $values['line_subtotal_tax'], |
||
| 236 | 'total' => $values['line_total'], |
||
| 237 | 'tax' => $values['line_tax'], |
||
| 238 | 'tax_data' => $values['line_tax_data'] // Since 2.2 |
||
| 239 | ) |
||
| 240 | ) |
||
| 241 | ); |
||
| 242 | |||
| 243 | if ( ! $item_id ) { |
||
| 244 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 525 ) ); |
||
| 245 | } |
||
| 246 | |||
| 247 | // Allow plugins to add order item meta |
||
| 248 | do_action( 'woocommerce_add_order_item_meta', $item_id, $values, $cart_item_key ); |
||
| 249 | } |
||
| 250 | |||
| 251 | // Store fees |
||
| 252 | foreach ( WC()->cart->get_fees() as $fee_key => $fee ) { |
||
| 253 | $item_id = $order->add_fee( $fee ); |
||
| 254 | |||
| 255 | if ( ! $item_id ) { |
||
| 256 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 526 ) ); |
||
| 257 | } |
||
| 258 | |||
| 259 | // Allow plugins to add order item meta to fees |
||
| 260 | do_action( 'woocommerce_add_order_fee_meta', $order_id, $item_id, $fee, $fee_key ); |
||
| 261 | } |
||
| 262 | |||
| 263 | // Store shipping for all packages |
||
| 264 | foreach ( WC()->shipping->get_packages() as $package_key => $package ) { |
||
| 265 | if ( isset( $package['rates'][ $this->shipping_methods[ $package_key ] ] ) ) { |
||
| 266 | $item_id = $order->add_shipping( $package['rates'][ $this->shipping_methods[ $package_key ] ] ); |
||
| 267 | |||
| 268 | if ( ! $item_id ) { |
||
| 269 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 527 ) ); |
||
| 270 | } |
||
| 271 | |||
| 272 | // Allows plugins to add order item meta to shipping |
||
| 273 | do_action( 'woocommerce_add_shipping_order_item', $order_id, $item_id, $package_key ); |
||
| 274 | } |
||
| 275 | } |
||
| 276 | |||
| 277 | // Store tax rows |
||
| 278 | foreach ( array_keys( WC()->cart->taxes + WC()->cart->shipping_taxes ) as $tax_rate_id ) { |
||
| 279 | if ( $tax_rate_id && ! $order->add_tax( $tax_rate_id, WC()->cart->get_tax_amount( $tax_rate_id ), WC()->cart->get_shipping_tax_amount( $tax_rate_id ) ) && apply_filters( 'woocommerce_cart_remove_taxes_zero_rate_id', 'zero-rated' ) !== $tax_rate_id ) { |
||
| 280 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 528 ) ); |
||
| 281 | } |
||
| 282 | } |
||
| 283 | |||
| 284 | // Store coupons |
||
| 285 | foreach ( WC()->cart->get_coupons() as $code => $coupon ) { |
||
| 286 | if ( ! $order->add_coupon( $code, WC()->cart->get_coupon_discount_amount( $code ), WC()->cart->get_coupon_discount_tax_amount( $code ) ) ) { |
||
| 287 | throw new Exception( sprintf( __( 'Error %d: Unable to create order. Please try again.', 'woocommerce' ), 529 ) ); |
||
| 288 | } |
||
| 289 | } |
||
| 290 | |||
| 291 | // Billing address |
||
| 292 | $billing_address = array(); |
||
| 293 | View Code Duplication | if ( $this->checkout_fields['billing'] ) { |
|
| 294 | foreach ( array_keys( $this->checkout_fields['billing'] ) as $field ) { |
||
| 295 | $field_name = str_replace( 'billing_', '', $field ); |
||
| 296 | $billing_address[ $field_name ] = $this->get_posted_address_data( $field_name ); |
||
| 297 | } |
||
| 298 | } |
||
| 299 | |||
| 300 | // Shipping address. |
||
| 301 | $shipping_address = array(); |
||
| 302 | View Code Duplication | if ( $this->checkout_fields['shipping'] ) { |
|
| 303 | foreach ( array_keys( $this->checkout_fields['shipping'] ) as $field ) { |
||
| 304 | $field_name = str_replace( 'shipping_', '', $field ); |
||
| 305 | $shipping_address[ $field_name ] = $this->get_posted_address_data( $field_name, 'shipping' ); |
||
| 306 | } |
||
| 307 | } |
||
| 308 | |||
| 309 | $order->set_address( $billing_address, 'billing' ); |
||
| 310 | $order->set_address( $shipping_address, 'shipping' ); |
||
| 311 | $order->set_payment_method( $this->payment_method ); |
||
| 312 | $order->set_total( WC()->cart->shipping_total, 'shipping' ); |
||
| 313 | $order->set_total( WC()->cart->get_cart_discount_total(), 'cart_discount' ); |
||
| 314 | $order->set_total( WC()->cart->get_cart_discount_tax_total(), 'cart_discount_tax' ); |
||
| 315 | $order->set_total( WC()->cart->tax_total, 'tax' ); |
||
| 316 | $order->set_total( WC()->cart->shipping_tax_total, 'shipping_tax' ); |
||
| 317 | $order->set_total( WC()->cart->total ); |
||
| 318 | |||
| 319 | // Update user meta |
||
| 320 | if ( $this->customer_id ) { |
||
| 321 | if ( apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) ) { |
||
| 322 | foreach ( $billing_address as $key => $value ) { |
||
| 323 | update_user_meta( $this->customer_id, 'billing_' . $key, $value ); |
||
| 324 | } |
||
| 325 | if ( WC()->cart->needs_shipping() ) { |
||
| 326 | foreach ( $shipping_address as $key => $value ) { |
||
| 327 | update_user_meta( $this->customer_id, 'shipping_' . $key, $value ); |
||
| 328 | } |
||
| 329 | } |
||
| 330 | } |
||
| 331 | do_action( 'woocommerce_checkout_update_user_meta', $this->customer_id, $this->posted ); |
||
| 332 | } |
||
| 333 | |||
| 334 | // Let plugins add meta |
||
| 335 | do_action( 'woocommerce_checkout_update_order_meta', $order_id, $this->posted ); |
||
| 336 | |||
| 337 | // If we got here, the order was created without problems! |
||
| 338 | wc_transaction_query( 'commit' ); |
||
| 339 | |||
| 340 | } catch ( Exception $e ) { |
||
| 341 | // There was an error adding order data! |
||
| 342 | wc_transaction_query( 'rollback' ); |
||
| 343 | return new WP_Error( 'checkout-error', $e->getMessage() ); |
||
| 344 | } |
||
| 345 | |||
| 346 | return $order_id; |
||
| 347 | } |
||
| 348 | |||
| 349 | /** |
||
| 350 | * Process the checkout after the confirm order button is pressed. |
||
| 351 | */ |
||
| 352 | public function process_checkout() { |
||
| 353 | try { |
||
| 354 | if ( empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-process_checkout' ) ) { |
||
| 355 | WC()->session->set( 'refresh_totals', true ); |
||
| 356 | throw new Exception( __( 'We were unable to process your order, please try again.', 'woocommerce' ) ); |
||
| 357 | } |
||
| 358 | |||
| 359 | if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) { |
||
| 360 | define( 'WOOCOMMERCE_CHECKOUT', true ); |
||
| 361 | } |
||
| 362 | |||
| 363 | // Prevent timeout |
||
| 364 | @set_time_limit(0); |
||
| 365 | |||
| 366 | do_action( 'woocommerce_before_checkout_process' ); |
||
| 367 | |||
| 368 | if ( WC()->cart->is_empty() ) { |
||
| 369 | throw new Exception( sprintf( __( 'Sorry, your session has expired. <a href="%s" class="wc-backward">Return to shop</a>', 'woocommerce' ), esc_url( wc_get_page_permalink( 'shop' ) ) ) ); |
||
| 370 | } |
||
| 371 | |||
| 372 | do_action( 'woocommerce_checkout_process' ); |
||
| 373 | |||
| 374 | // Checkout fields (not defined in checkout_fields) |
||
| 375 | $this->posted['terms'] = isset( $_POST['terms'] ) ? 1 : 0; |
||
| 376 | $this->posted['createaccount'] = isset( $_POST['createaccount'] ) && ! empty( $_POST['createaccount'] ) ? 1 : 0; |
||
| 377 | $this->posted['payment_method'] = isset( $_POST['payment_method'] ) ? stripslashes( $_POST['payment_method'] ) : ''; |
||
| 378 | $this->posted['shipping_method'] = isset( $_POST['shipping_method'] ) ? $_POST['shipping_method'] : ''; |
||
| 379 | $this->posted['ship_to_different_address'] = isset( $_POST['ship_to_different_address'] ) ? true : false; |
||
| 380 | |||
| 381 | if ( isset( $_POST['shiptobilling'] ) ) { |
||
| 382 | _deprecated_argument( 'WC_Checkout::process_checkout()', '2.1', 'The "shiptobilling" field is deprecated. The template files are out of date' ); |
||
| 383 | |||
| 384 | $this->posted['ship_to_different_address'] = $_POST['shiptobilling'] ? false : true; |
||
| 385 | } |
||
| 386 | |||
| 387 | // Ship to billing only option |
||
| 388 | if ( wc_ship_to_billing_address_only() ) { |
||
| 389 | $this->posted['ship_to_different_address'] = false; |
||
| 390 | } |
||
| 391 | |||
| 392 | // Update customer shipping and payment method to posted method |
||
| 393 | $chosen_shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); |
||
| 394 | |||
| 395 | if ( isset( $this->posted['shipping_method'] ) && is_array( $this->posted['shipping_method'] ) ) { |
||
| 396 | foreach ( $this->posted['shipping_method'] as $i => $value ) { |
||
| 397 | $chosen_shipping_methods[ $i ] = wc_clean( $value ); |
||
| 398 | } |
||
| 399 | } |
||
| 400 | |||
| 401 | WC()->session->set( 'chosen_shipping_methods', $chosen_shipping_methods ); |
||
| 402 | WC()->session->set( 'chosen_payment_method', $this->posted['payment_method'] ); |
||
| 403 | |||
| 404 | // Note if we skip shipping |
||
| 405 | $skipped_shipping = false; |
||
| 406 | |||
| 407 | // Get posted checkout_fields and do validation |
||
| 408 | foreach ( $this->checkout_fields as $fieldset_key => $fieldset ) { |
||
| 409 | |||
| 410 | // Skip shipping if not needed |
||
| 411 | if ( $fieldset_key == 'shipping' && ( $this->posted['ship_to_different_address'] == false || ! WC()->cart->needs_shipping_address() ) ) { |
||
| 412 | $skipped_shipping = true; |
||
| 413 | continue; |
||
| 414 | } |
||
| 415 | |||
| 416 | // Skip account if not needed |
||
| 417 | if ( $fieldset_key == 'account' && ( is_user_logged_in() || ( $this->must_create_account == false && empty( $this->posted['createaccount'] ) ) ) ) { |
||
|
0 ignored issues
–
show
|
|||
| 418 | continue; |
||
| 419 | } |
||
| 420 | |||
| 421 | foreach ( $fieldset as $key => $field ) { |
||
| 422 | |||
| 423 | if ( ! isset( $field['type'] ) ) { |
||
| 424 | $field['type'] = 'text'; |
||
| 425 | } |
||
| 426 | |||
| 427 | // Get Value |
||
| 428 | switch ( $field['type'] ) { |
||
| 429 | case "checkbox" : |
||
| 430 | $this->posted[ $key ] = isset( $_POST[ $key ] ) ? 1 : 0; |
||
| 431 | break; |
||
| 432 | case "multiselect" : |
||
| 433 | $this->posted[ $key ] = isset( $_POST[ $key ] ) ? implode( ', ', array_map( 'wc_clean', $_POST[ $key ] ) ) : ''; |
||
| 434 | break; |
||
| 435 | case "textarea" : |
||
| 436 | $this->posted[ $key ] = isset( $_POST[ $key ] ) ? wp_strip_all_tags( wp_check_invalid_utf8( stripslashes( $_POST[ $key ] ) ) ) : ''; |
||
| 437 | break; |
||
| 438 | default : |
||
| 439 | $this->posted[ $key ] = isset( $_POST[ $key ] ) ? ( is_array( $_POST[ $key ] ) ? array_map( 'wc_clean', $_POST[ $key ] ) : wc_clean( $_POST[ $key ] ) ) : ''; |
||
| 440 | break; |
||
| 441 | } |
||
| 442 | |||
| 443 | // Hooks to allow modification of value |
||
| 444 | $this->posted[ $key ] = apply_filters( 'woocommerce_process_checkout_' . sanitize_title( $field['type'] ) . '_field', $this->posted[ $key ] ); |
||
| 445 | $this->posted[ $key ] = apply_filters( 'woocommerce_process_checkout_field_' . $key, $this->posted[ $key ] ); |
||
| 446 | |||
| 447 | // Validation: Required fields |
||
| 448 | if ( isset( $field['required'] ) && $field['required'] && ( ! isset( $this->posted[ $key ] ) || "" === $this->posted[ $key ] ) ) { |
||
| 449 | switch ( $fieldset_key ) { |
||
| 450 | case 'shipping' : |
||
| 451 | $field_label = sprintf( _x( 'Shipping %s', 'Shipping FIELDNAME', 'woocommerce' ), $field['label'] ); |
||
| 452 | break; |
||
| 453 | case 'billing' : |
||
| 454 | $field_label = sprintf( _x( 'Billing %s', 'Billing FIELDNAME', 'woocommerce' ), $field['label'] ); |
||
| 455 | break; |
||
| 456 | default : |
||
| 457 | $field_label = $field['label']; |
||
| 458 | break; |
||
| 459 | } |
||
| 460 | wc_add_notice( apply_filters( 'woocommerce_checkout_required_field_notice', sprintf( _x( '%s is a required field.', 'FIELDNAME is a required field.', 'woocommerce' ), '<strong>' . $field_label . '</strong>' ), $field_label ), 'error' ); |
||
| 461 | } |
||
| 462 | |||
| 463 | if ( ! empty( $this->posted[ $key ] ) ) { |
||
| 464 | |||
| 465 | // Validation rules |
||
| 466 | if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) { |
||
| 467 | foreach ( $field['validate'] as $rule ) { |
||
| 468 | switch ( $rule ) { |
||
| 469 | case 'postcode' : |
||
| 470 | $this->posted[ $key ] = strtoupper( str_replace( ' ', '', $this->posted[ $key ] ) ); |
||
| 471 | |||
| 472 | if ( ! WC_Validation::is_postcode( $this->posted[ $key ], $_POST[ $fieldset_key . '_country' ] ) ) : |
||
| 473 | wc_add_notice( __( 'Please enter a valid postcode/ZIP.', 'woocommerce' ), 'error' ); |
||
| 474 | else : |
||
| 475 | $this->posted[ $key ] = wc_format_postcode( $this->posted[ $key ], $_POST[ $fieldset_key . '_country' ] ); |
||
| 476 | endif; |
||
| 477 | break; |
||
| 478 | View Code Duplication | case 'phone' : |
|
| 479 | $this->posted[ $key ] = wc_format_phone_number( $this->posted[ $key ] ); |
||
| 480 | |||
| 481 | if ( ! WC_Validation::is_phone( $this->posted[ $key ] ) ) |
||
| 482 | wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid phone number.', 'woocommerce' ), 'error' ); |
||
| 483 | break; |
||
| 484 | View Code Duplication | case 'email' : |
|
| 485 | $this->posted[ $key ] = strtolower( $this->posted[ $key ] ); |
||
| 486 | |||
| 487 | if ( ! is_email( $this->posted[ $key ] ) ) |
||
| 488 | wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not a valid email address.', 'woocommerce' ), 'error' ); |
||
| 489 | break; |
||
| 490 | case 'state' : |
||
| 491 | // Get valid states |
||
| 492 | $valid_states = WC()->countries->get_states( isset( $_POST[ $fieldset_key . '_country' ] ) ? $_POST[ $fieldset_key . '_country' ] : ( 'billing' === $fieldset_key ? WC()->customer->get_country() : WC()->customer->get_shipping_country() ) ); |
||
| 493 | |||
| 494 | if ( ! empty( $valid_states ) && is_array( $valid_states ) ) { |
||
| 495 | $valid_state_values = array_flip( array_map( 'strtolower', $valid_states ) ); |
||
| 496 | |||
| 497 | // Convert value to key if set |
||
| 498 | if ( isset( $valid_state_values[ strtolower( $this->posted[ $key ] ) ] ) ) { |
||
| 499 | $this->posted[ $key ] = $valid_state_values[ strtolower( $this->posted[ $key ] ) ]; |
||
| 500 | } |
||
| 501 | } |
||
| 502 | |||
| 503 | // Only validate if the country has specific state options |
||
| 504 | if ( ! empty( $valid_states ) && is_array( $valid_states ) && sizeof( $valid_states ) > 0 ) { |
||
| 505 | if ( ! in_array( $this->posted[ $key ], array_keys( $valid_states ) ) ) { |
||
| 506 | wc_add_notice( '<strong>' . $field['label'] . '</strong> ' . __( 'is not valid. Please enter one of the following:', 'woocommerce' ) . ' ' . implode( ', ', $valid_states ), 'error' ); |
||
| 507 | } |
||
| 508 | } |
||
| 509 | break; |
||
| 510 | } |
||
| 511 | } |
||
| 512 | } |
||
| 513 | } |
||
| 514 | } |
||
| 515 | } |
||
| 516 | |||
| 517 | // Update customer location to posted location so we can correctly check available shipping methods |
||
| 518 | if ( isset( $this->posted['billing_country'] ) ) { |
||
| 519 | WC()->customer->set_country( $this->posted['billing_country'] ); |
||
| 520 | } |
||
| 521 | if ( isset( $this->posted['billing_state'] ) ) { |
||
| 522 | WC()->customer->set_state( $this->posted['billing_state'] ); |
||
| 523 | } |
||
| 524 | if ( isset( $this->posted['billing_postcode'] ) ) { |
||
| 525 | WC()->customer->set_postcode( $this->posted['billing_postcode'] ); |
||
| 526 | } |
||
| 527 | |||
| 528 | // Shipping Information |
||
| 529 | if ( ! $skipped_shipping ) { |
||
| 530 | |||
| 531 | // Update customer location to posted location so we can correctly check available shipping methods |
||
| 532 | if ( isset( $this->posted['shipping_country'] ) ) { |
||
| 533 | WC()->customer->set_shipping_country( $this->posted['shipping_country'] ); |
||
| 534 | } |
||
| 535 | if ( isset( $this->posted['shipping_state'] ) ) { |
||
| 536 | WC()->customer->set_shipping_state( $this->posted['shipping_state'] ); |
||
| 537 | } |
||
| 538 | if ( isset( $this->posted['shipping_postcode'] ) ) { |
||
| 539 | WC()->customer->set_shipping_postcode( $this->posted['shipping_postcode'] ); |
||
| 540 | } |
||
| 541 | |||
| 542 | } else { |
||
| 543 | |||
| 544 | // Update customer location to posted location so we can correctly check available shipping methods |
||
| 545 | if ( isset( $this->posted['billing_country'] ) ) { |
||
| 546 | WC()->customer->set_shipping_country( $this->posted['billing_country'] ); |
||
| 547 | } |
||
| 548 | if ( isset( $this->posted['billing_state'] ) ) { |
||
| 549 | WC()->customer->set_shipping_state( $this->posted['billing_state'] ); |
||
| 550 | } |
||
| 551 | if ( isset( $this->posted['billing_postcode'] ) ) { |
||
| 552 | WC()->customer->set_shipping_postcode( $this->posted['billing_postcode'] ); |
||
| 553 | } |
||
| 554 | |||
| 555 | } |
||
| 556 | |||
| 557 | // Update cart totals now we have customer address |
||
| 558 | WC()->cart->calculate_totals(); |
||
| 559 | |||
| 560 | // Terms |
||
| 561 | if ( ! isset( $_POST['woocommerce_checkout_update_totals'] ) && empty( $this->posted['terms'] ) && wc_get_page_id( 'terms' ) > 0 && apply_filters( 'woocommerce_checkout_show_terms', true ) ) { |
||
| 562 | wc_add_notice( __( 'You must accept our Terms & Conditions.', 'woocommerce' ), 'error' ); |
||
| 563 | } |
||
| 564 | |||
| 565 | if ( WC()->cart->needs_shipping() ) { |
||
| 566 | $shipping_country = WC()->customer->get_shipping_country(); |
||
| 567 | |||
| 568 | if ( empty( $shipping_country ) ) { |
||
| 569 | wc_add_notice( __( 'Please enter an address to continue.', 'woocommerce' ), 'error' ); |
||
| 570 | } elseif ( ! in_array( WC()->customer->get_shipping_country(), array_keys( WC()->countries->get_shipping_countries() ) ) ) { |
||
| 571 | wc_add_notice( sprintf( __( 'Unfortunately <strong>we do not ship %s</strong>. Please enter an alternative shipping address.', 'woocommerce' ), WC()->countries->shipping_to_prefix() . ' ' . WC()->customer->get_shipping_country() ), 'error' ); |
||
| 572 | } |
||
| 573 | |||
| 574 | // Validate Shipping Methods |
||
| 575 | $packages = WC()->shipping->get_packages(); |
||
| 576 | $this->shipping_methods = WC()->session->get( 'chosen_shipping_methods' ); |
||
| 577 | |||
| 578 | foreach ( $packages as $i => $package ) { |
||
| 579 | if ( ! isset( $package['rates'][ $this->shipping_methods[ $i ] ] ) ) { |
||
| 580 | wc_add_notice( __( 'No shipping method has been selected. Please double check your address, or contact us if you need any help.', 'woocommerce' ), 'error' ); |
||
| 581 | $this->shipping_methods[ $i ] = ''; |
||
| 582 | } |
||
| 583 | } |
||
| 584 | } |
||
| 585 | |||
| 586 | if ( WC()->cart->needs_payment() ) { |
||
| 587 | // Payment Method |
||
| 588 | $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); |
||
| 589 | |||
| 590 | if ( ! isset( $available_gateways[ $this->posted['payment_method'] ] ) ) { |
||
| 591 | $this->payment_method = ''; |
||
| 592 | wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' ); |
||
| 593 | } else { |
||
| 594 | $this->payment_method = $available_gateways[ $this->posted['payment_method'] ]; |
||
| 595 | $this->payment_method->validate_fields(); |
||
| 596 | } |
||
| 597 | } else { |
||
| 598 | $available_gateways = array(); |
||
| 599 | } |
||
| 600 | |||
| 601 | // Action after validation |
||
| 602 | do_action( 'woocommerce_after_checkout_validation', $this->posted ); |
||
| 603 | |||
| 604 | if ( ! isset( $_POST['woocommerce_checkout_update_totals'] ) && wc_notice_count( 'error' ) == 0 ) { |
||
| 605 | |||
| 606 | // Customer accounts |
||
| 607 | $this->customer_id = apply_filters( 'woocommerce_checkout_customer_id', get_current_user_id() ); |
||
| 608 | |||
| 609 | if ( ! is_user_logged_in() && ( $this->must_create_account || ! empty( $this->posted['createaccount'] ) ) ) { |
||
| 610 | |||
| 611 | $username = ! empty( $this->posted['account_username'] ) ? $this->posted['account_username'] : ''; |
||
| 612 | $password = ! empty( $this->posted['account_password'] ) ? $this->posted['account_password'] : ''; |
||
| 613 | $new_customer = wc_create_new_customer( $this->posted['billing_email'], $username, $password ); |
||
| 614 | |||
| 615 | if ( is_wp_error( $new_customer ) ) { |
||
| 616 | throw new Exception( $new_customer->get_error_message() ); |
||
| 617 | } |
||
| 618 | |||
| 619 | $this->customer_id = $new_customer; |
||
| 620 | |||
| 621 | wc_set_customer_auth_cookie( $this->customer_id ); |
||
| 622 | |||
| 623 | // As we are now logged in, checkout will need to refresh to show logged in data |
||
| 624 | WC()->session->set( 'reload_checkout', true ); |
||
| 625 | |||
| 626 | // Also, recalculate cart totals to reveal any role-based discounts that were unavailable before registering |
||
| 627 | WC()->cart->calculate_totals(); |
||
| 628 | |||
| 629 | // Add customer info from other billing fields |
||
| 630 | if ( $this->posted['billing_first_name'] && apply_filters( 'woocommerce_checkout_update_customer_data', true, $this ) ) { |
||
| 631 | $userdata = array( |
||
| 632 | 'ID' => $this->customer_id, |
||
| 633 | 'first_name' => $this->posted['billing_first_name'] ? $this->posted['billing_first_name'] : '', |
||
| 634 | 'last_name' => $this->posted['billing_last_name'] ? $this->posted['billing_last_name'] : '', |
||
| 635 | 'display_name' => $this->posted['billing_first_name'] ? $this->posted['billing_first_name'] : '' |
||
| 636 | ); |
||
| 637 | wp_update_user( apply_filters( 'woocommerce_checkout_customer_userdata', $userdata, $this ) ); |
||
| 638 | } |
||
| 639 | } |
||
| 640 | |||
| 641 | // Do a final stock check at this point |
||
| 642 | $this->check_cart_items(); |
||
| 643 | |||
| 644 | // Abort if errors are present |
||
| 645 | if ( wc_notice_count( 'error' ) > 0 ) |
||
| 646 | throw new Exception(); |
||
| 647 | |||
| 648 | $order_id = $this->create_order(); |
||
| 649 | |||
| 650 | if ( is_wp_error( $order_id ) ) { |
||
| 651 | throw new Exception( $order_id->get_error_message() ); |
||
| 652 | } |
||
| 653 | |||
| 654 | do_action( 'woocommerce_checkout_order_processed', $order_id, $this->posted ); |
||
| 655 | |||
| 656 | // Process payment |
||
| 657 | if ( WC()->cart->needs_payment() ) { |
||
| 658 | |||
| 659 | // Store Order ID in session so it can be re-used after payment failure |
||
| 660 | WC()->session->order_awaiting_payment = $order_id; |
||
| 661 | |||
| 662 | // Process Payment |
||
| 663 | $result = $available_gateways[ $this->posted['payment_method'] ]->process_payment( $order_id ); |
||
| 664 | |||
| 665 | // Redirect to success/confirmation/payment page |
||
| 666 | if ( isset( $result['result'] ) && 'success' === $result['result'] ) { |
||
| 667 | |||
| 668 | $result = apply_filters( 'woocommerce_payment_successful_result', $result, $order_id ); |
||
| 669 | |||
| 670 | if ( is_ajax() ) { |
||
| 671 | wp_send_json( $result ); |
||
| 672 | } else { |
||
| 673 | wp_redirect( $result['redirect'] ); |
||
| 674 | exit; |
||
| 675 | } |
||
| 676 | |||
| 677 | } |
||
| 678 | |||
| 679 | } else { |
||
| 680 | |||
| 681 | if ( empty( $order ) ) { |
||
| 682 | $order = wc_get_order( $order_id ); |
||
| 683 | } |
||
| 684 | |||
| 685 | // No payment was required for order |
||
| 686 | $order->payment_complete(); |
||
| 687 | |||
| 688 | // Empty the Cart |
||
| 689 | WC()->cart->empty_cart(); |
||
| 690 | |||
| 691 | // Get redirect |
||
| 692 | $return_url = $order->get_checkout_order_received_url(); |
||
| 693 | |||
| 694 | // Redirect to success/confirmation/payment page |
||
| 695 | if ( is_ajax() ) { |
||
| 696 | wp_send_json( array( |
||
| 697 | 'result' => 'success', |
||
| 698 | 'redirect' => apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $return_url, $order ) |
||
| 699 | ) ); |
||
| 700 | } else { |
||
| 701 | wp_safe_redirect( |
||
| 702 | apply_filters( 'woocommerce_checkout_no_payment_needed_redirect', $return_url, $order ) |
||
| 703 | ); |
||
| 704 | exit; |
||
| 705 | } |
||
| 706 | |||
| 707 | } |
||
| 708 | |||
| 709 | } |
||
| 710 | |||
| 711 | } catch ( Exception $e ) { |
||
| 712 | if ( ! empty( $e ) ) { |
||
| 713 | wc_add_notice( $e->getMessage(), 'error' ); |
||
| 714 | } |
||
| 715 | } |
||
| 716 | |||
| 717 | // If we reached this point then there were errors |
||
| 718 | if ( is_ajax() ) { |
||
| 719 | |||
| 720 | // only print notices if not reloading the checkout, otherwise they're lost in the page reload |
||
| 721 | if ( ! isset( WC()->session->reload_checkout ) ) { |
||
| 722 | ob_start(); |
||
| 723 | wc_print_notices(); |
||
| 724 | $messages = ob_get_clean(); |
||
| 725 | } |
||
| 726 | |||
| 727 | $response = array( |
||
| 728 | 'result' => 'failure', |
||
| 729 | 'messages' => isset( $messages ) ? $messages : '', |
||
| 730 | 'refresh' => isset( WC()->session->refresh_totals ) ? 'true' : 'false', |
||
| 731 | 'reload' => isset( WC()->session->reload_checkout ) ? 'true' : 'false' |
||
| 732 | ); |
||
| 733 | |||
| 734 | unset( WC()->session->refresh_totals, WC()->session->reload_checkout ); |
||
| 735 | |||
| 736 | wp_send_json( $response ); |
||
| 737 | } |
||
| 738 | } |
||
| 739 | |||
| 740 | /** |
||
| 741 | * Get a posted address field after sanitization and validation. |
||
| 742 | * @param string $key |
||
| 743 | * @param string $type billing for shipping |
||
| 744 | * @return string |
||
| 745 | */ |
||
| 746 | public function get_posted_address_data( $key, $type = 'billing' ) { |
||
| 747 | if ( 'billing' === $type || false === $this->posted['ship_to_different_address'] ) { |
||
| 748 | $return = isset( $this->posted[ 'billing_' . $key ] ) ? $this->posted[ 'billing_' . $key ] : ''; |
||
| 749 | } else { |
||
| 750 | $return = isset( $this->posted[ 'shipping_' . $key ] ) ? $this->posted[ 'shipping_' . $key ] : ''; |
||
| 751 | } |
||
| 752 | |||
| 753 | // Use logged in user's billing email if neccessary |
||
| 754 | if ( 'email' === $key && empty( $return ) && is_user_logged_in() ) { |
||
| 755 | $current_user = wp_get_current_user(); |
||
| 756 | $return = $current_user->user_email; |
||
| 757 | } |
||
| 758 | return $return; |
||
| 759 | } |
||
| 760 | |||
| 761 | /** |
||
| 762 | * Gets the value either from the posted data, or from the users meta data. |
||
| 763 | * |
||
| 764 | * @access public |
||
| 765 | * @param string $input |
||
| 766 | * @return string|null |
||
| 767 | */ |
||
| 768 | public function get_value( $input ) { |
||
| 769 | if ( ! empty( $_POST[ $input ] ) ) { |
||
| 770 | |||
| 771 | return wc_clean( $_POST[ $input ] ); |
||
| 772 | |||
| 773 | } else { |
||
| 774 | |||
| 775 | $value = apply_filters( 'woocommerce_checkout_get_value', null, $input ); |
||
| 776 | |||
| 777 | if ( $value !== null ) { |
||
| 778 | return $value; |
||
| 779 | } |
||
| 780 | |||
| 781 | // Get the billing_ and shipping_ address fields |
||
| 782 | if ( isset( $this->checkout_fields['shipping'] ) && isset( $this->checkout_fields['billing'] ) ) { |
||
| 783 | |||
| 784 | $address_fields = array_merge( $this->checkout_fields['billing'], $this->checkout_fields['shipping'] ); |
||
| 785 | |||
| 786 | if ( is_user_logged_in() && is_array( $address_fields ) && array_key_exists( $input, $address_fields ) ) { |
||
| 787 | $current_user = wp_get_current_user(); |
||
| 788 | |||
| 789 | if ( $meta = get_user_meta( $current_user->ID, $input, true ) ) { |
||
| 790 | return $meta; |
||
| 791 | } |
||
| 792 | |||
| 793 | if ( $input == 'billing_email' ) { |
||
| 794 | return $current_user->user_email; |
||
| 795 | } |
||
| 796 | } |
||
| 797 | |||
| 798 | } |
||
| 799 | |||
| 800 | switch ( $input ) { |
||
| 801 | case 'billing_country' : |
||
| 802 | return apply_filters( 'default_checkout_country', WC()->customer->get_country() ? WC()->customer->get_country() : '', 'billing' ); |
||
| 803 | case 'billing_state' : |
||
| 804 | return apply_filters( 'default_checkout_state', WC()->customer->get_state() ? WC()->customer->get_state() : '', 'billing' ); |
||
| 805 | case 'billing_postcode' : |
||
| 806 | return apply_filters( 'default_checkout_postcode', WC()->customer->get_postcode() ? WC()->customer->get_postcode() : '', 'billing' ); |
||
| 807 | case 'shipping_country' : |
||
| 808 | return apply_filters( 'default_checkout_country', WC()->customer->get_shipping_country() ? WC()->customer->get_shipping_country() : '', 'shipping' ); |
||
| 809 | case 'shipping_state' : |
||
| 810 | return apply_filters( 'default_checkout_state', WC()->customer->get_shipping_state() ? WC()->customer->get_shipping_state() : '', 'shipping' ); |
||
| 811 | case 'shipping_postcode' : |
||
| 812 | return apply_filters( 'default_checkout_postcode', WC()->customer->get_shipping_postcode() ? WC()->customer->get_shipping_postcode() : '', 'shipping' ); |
||
| 813 | default : |
||
| 814 | return apply_filters( 'default_checkout_' . $input, null, $input ); |
||
| 815 | } |
||
| 816 | } |
||
| 817 | } |
||
| 818 | } |
||
| 819 |
When comparing two booleans, it is generally considered safer to use the strict comparison operator.