/includes/class-wc-form-handler.php

  1. <?php 
  2.  
  3. if ( ! defined( 'ABSPATH' ) ) { 
  4. exit; // Exit if accessed directly 
  5.  
  6. /** 
  7. * Handle frontend forms. 
  8. * 
  9. * @class WC_Form_Handler 
  10. * @version 2.2.0 
  11. * @package WooCommerce/Classes/ 
  12. * @category Class 
  13. * @author WooThemes 
  14. */ 
  15. class WC_Form_Handler { 
  16.  
  17. /** 
  18. * Hook in methods. 
  19. */ 
  20. public static function init() { 
  21. add_action( 'template_redirect', array( __CLASS__, 'redirect_reset_password_link' ) ); 
  22. add_action( 'template_redirect', array( __CLASS__, 'save_address' ) ); 
  23. add_action( 'template_redirect', array( __CLASS__, 'save_account_details' ) ); 
  24. add_action( 'wp_loaded', array( __CLASS__, 'checkout_action' ), 20 ); 
  25. add_action( 'wp_loaded', array( __CLASS__, 'process_login' ), 20 ); 
  26. add_action( 'wp_loaded', array( __CLASS__, 'process_registration' ), 20 ); 
  27. add_action( 'wp_loaded', array( __CLASS__, 'process_lost_password' ), 20 ); 
  28. add_action( 'wp_loaded', array( __CLASS__, 'process_reset_password' ), 20 ); 
  29. add_action( 'wp_loaded', array( __CLASS__, 'cancel_order' ), 20 ); 
  30. add_action( 'wp_loaded', array( __CLASS__, 'order_again' ), 20 ); 
  31. add_action( 'wp_loaded', array( __CLASS__, 'update_cart_action' ), 20 ); 
  32. add_action( 'wp_loaded', array( __CLASS__, 'add_to_cart_action' ), 20 ); 
  33.  
  34. // May need $wp global to access query vars. 
  35. add_action( 'wp', array( __CLASS__, 'pay_action' ), 20 ); 
  36. add_action( 'wp', array( __CLASS__, 'add_payment_method_action' ), 20 ); 
  37. add_action( 'wp', array( __CLASS__, 'delete_payment_method_action' ), 20 ); 
  38. add_action( 'wp', array( __CLASS__, 'set_default_payment_method_action' ), 20 ); 
  39.  
  40. /** 
  41. * Remove key and login from querystring, set cookie, and redirect to account page to show the form. 
  42. */ 
  43. public static function redirect_reset_password_link() { 
  44. if ( is_account_page() && ! empty( $_GET['key'] ) && ! empty( $_GET['login'] ) ) { 
  45. $value = sprintf( '%s:%s', wp_unslash( $_GET['login'] ), wp_unslash( $_GET['key'] ) ); 
  46. WC_Shortcode_My_Account::set_reset_password_cookie( $value ); 
  47.  
  48. wp_safe_redirect( add_query_arg( 'show-reset-form', 'true', wc_lostpassword_url() ) ); 
  49. exit; 
  50.  
  51. /** 
  52. * Save and and update a billing or shipping address if the 
  53. * form was submitted through the user account page. 
  54. */ 
  55. public static function save_address() { 
  56. global $wp; 
  57.  
  58. if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 
  59. return; 
  60.  
  61. if ( empty( $_POST['action'] ) || 'edit_address' !== $_POST['action'] || empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-edit_address' ) ) { 
  62. return; 
  63.  
  64. $user_id = get_current_user_id(); 
  65.  
  66. if ( $user_id <= 0 ) { 
  67. return; 
  68.  
  69. $load_address = isset( $wp->query_vars['edit-address'] ) ? wc_edit_address_i18n( sanitize_title( $wp->query_vars['edit-address'] ), true ) : 'billing'; 
  70.  
  71. $address = WC()->countries->get_address_fields( esc_attr( $_POST[ $load_address . '_country' ] ), $load_address . '_' ); 
  72.  
  73. foreach ( $address as $key => $field ) { 
  74.  
  75. if ( ! isset( $field['type'] ) ) { 
  76. $field['type'] = 'text'; 
  77.  
  78. // Get Value. 
  79. switch ( $field['type'] ) { 
  80. case 'checkbox' : 
  81. $_POST[ $key ] = (int) isset( $_POST[ $key ] ); 
  82. break; 
  83. default : 
  84. $_POST[ $key ] = isset( $_POST[ $key ] ) ? wc_clean( $_POST[ $key ] ) : ''; 
  85. break; 
  86.  
  87. // Hook to allow modification of value. 
  88. $_POST[ $key ] = apply_filters( 'woocommerce_process_myaccount_field_' . $key, $_POST[ $key ] ); 
  89.  
  90. // Validation: Required fields. 
  91. if ( ! empty( $field['required'] ) && empty( $_POST[ $key ] ) ) { 
  92. wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), $field['label'] ), 'error' ); 
  93.  
  94. if ( ! empty( $_POST[ $key ] ) ) { 
  95.  
  96. // Validation rules. 
  97. if ( ! empty( $field['validate'] ) && is_array( $field['validate'] ) ) { 
  98. foreach ( $field['validate'] as $rule ) { 
  99. switch ( $rule ) { 
  100. case 'postcode' : 
  101. $_POST[ $key ] = strtoupper( str_replace( ' ', '', $_POST[ $key ] ) ); 
  102.  
  103. if ( ! WC_Validation::is_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ) ) { 
  104. wc_add_notice( __( 'Please enter a valid postcode / ZIP.', 'woocommerce' ), 'error' ); 
  105. } else { 
  106. $_POST[ $key ] = wc_format_postcode( $_POST[ $key ], $_POST[ $load_address . '_country' ] ); 
  107. break; 
  108. case 'phone' : 
  109. $_POST[ $key ] = wc_format_phone_number( $_POST[ $key ] ); 
  110.  
  111. if ( ! WC_Validation::is_phone( $_POST[ $key ] ) ) { 
  112. wc_add_notice( sprintf( __( '%s is not a valid phone number.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' ); 
  113. break; 
  114. case 'email' : 
  115. $_POST[ $key ] = strtolower( $_POST[ $key ] ); 
  116.  
  117. if ( ! is_email( $_POST[ $key ] ) ) { 
  118. wc_add_notice( sprintf( __( '%s is not a valid email address.', 'woocommerce' ), '<strong>' . $field['label'] . '</strong>' ), 'error' ); 
  119. break; 
  120.  
  121. do_action( 'woocommerce_after_save_address_validation', $user_id, $load_address, $address ); 
  122.  
  123. if ( 0 === wc_notice_count( 'error' ) ) { 
  124.  
  125. foreach ( $address as $key => $field ) { 
  126. update_user_meta( $user_id, $key, $_POST[ $key ] ); 
  127.  
  128. wc_add_notice( __( 'Address changed successfully.', 'woocommerce' ) ); 
  129.  
  130. do_action( 'woocommerce_customer_save_address', $user_id, $load_address ); 
  131.  
  132. wp_safe_redirect( wc_get_endpoint_url( 'edit-address', '', wc_get_page_permalink( 'myaccount' ) ) ); 
  133. exit; 
  134.  
  135. /** 
  136. * Save the password/account details and redirect back to the my account page. 
  137. */ 
  138. public static function save_account_details() { 
  139.  
  140. if ( 'POST' !== strtoupper( $_SERVER['REQUEST_METHOD'] ) ) { 
  141. return; 
  142.  
  143. if ( empty( $_POST['action'] ) || 'save_account_details' !== $_POST['action'] || empty( $_POST['_wpnonce'] ) || ! wp_verify_nonce( $_POST['_wpnonce'], 'save_account_details' ) ) { 
  144. return; 
  145.  
  146. $errors = new WP_Error(); 
  147. $user = new stdClass(); 
  148.  
  149. $user->ID = (int) get_current_user_id(); 
  150. $current_user = get_user_by( 'id', $user->ID ); 
  151.  
  152. if ( $user->ID <= 0 ) { 
  153. return; 
  154.  
  155. $account_first_name = ! empty( $_POST['account_first_name'] ) ? wc_clean( $_POST['account_first_name'] ) : ''; 
  156. $account_last_name = ! empty( $_POST['account_last_name'] ) ? wc_clean( $_POST['account_last_name'] ) : ''; 
  157. $account_email = ! empty( $_POST['account_email'] ) ? wc_clean( $_POST['account_email'] ) : ''; 
  158. $pass_cur = ! empty( $_POST['password_current'] ) ? $_POST['password_current'] : ''; 
  159. $pass1 = ! empty( $_POST['password_1'] ) ? $_POST['password_1'] : ''; 
  160. $pass2 = ! empty( $_POST['password_2'] ) ? $_POST['password_2'] : ''; 
  161. $save_pass = true; 
  162.  
  163. $user->first_name = $account_first_name; 
  164. $user->last_name = $account_last_name; 
  165.  
  166. // Prevent emails being displayed, or leave alone. 
  167. $user->display_name = is_email( $current_user->display_name ) ? $user->first_name : $current_user->display_name; 
  168.  
  169. // Handle required fields 
  170. $required_fields = apply_filters( 'woocommerce_save_account_details_required_fields', array( 
  171. 'account_first_name' => __( 'First name', 'woocommerce' ),  
  172. 'account_last_name' => __( 'Last name', 'woocommerce' ),  
  173. 'account_email' => __( 'Email address', 'woocommerce' ),  
  174. ) ); 
  175.  
  176. foreach ( $required_fields as $field_key => $field_name ) { 
  177. if ( empty( $_POST[ $field_key ] ) ) { 
  178. wc_add_notice( sprintf( __( '%s is a required field.', 'woocommerce' ), '<strong>' . esc_html( $field_name ) . '</strong>' ), 'error' ); 
  179.  
  180. if ( $account_email ) { 
  181. $account_email = sanitize_email( $account_email ); 
  182. if ( ! is_email( $account_email ) ) { 
  183. wc_add_notice( __( 'Please provide a valid email address.', 'woocommerce' ), 'error' ); 
  184. } elseif ( email_exists( $account_email ) && $account_email !== $current_user->user_email ) { 
  185. wc_add_notice( __( 'This email address is already registered.', 'woocommerce' ), 'error' ); 
  186. $user->user_email = $account_email; 
  187.  
  188. if ( ! empty( $pass_cur ) && empty( $pass1 ) && empty( $pass2 ) ) { 
  189. wc_add_notice( __( 'Please fill out all password fields.', 'woocommerce' ), 'error' ); 
  190. $save_pass = false; 
  191. } elseif ( ! empty( $pass1 ) && empty( $pass_cur ) ) { 
  192. wc_add_notice( __( 'Please enter your current password.', 'woocommerce' ), 'error' ); 
  193. $save_pass = false; 
  194. } elseif ( ! empty( $pass1 ) && empty( $pass2 ) ) { 
  195. wc_add_notice( __( 'Please re-enter your password.', 'woocommerce' ), 'error' ); 
  196. $save_pass = false; 
  197. } elseif ( ( ! empty( $pass1 ) || ! empty( $pass2 ) ) && $pass1 !== $pass2 ) { 
  198. wc_add_notice( __( 'New passwords do not match.', 'woocommerce' ), 'error' ); 
  199. $save_pass = false; 
  200. } elseif ( ! empty( $pass1 ) && ! wp_check_password( $pass_cur, $current_user->user_pass, $current_user->ID ) ) { 
  201. wc_add_notice( __( 'Your current password is incorrect.', 'woocommerce' ), 'error' ); 
  202. $save_pass = false; 
  203.  
  204. if ( $pass1 && $save_pass ) { 
  205. $user->user_pass = $pass1; 
  206.  
  207. // Allow plugins to return their own errors. 
  208. do_action_ref_array( 'woocommerce_save_account_details_errors', array( &$errors, &$user ) ); 
  209.  
  210. if ( $errors->get_error_messages() ) { 
  211. foreach ( $errors->get_error_messages() as $error ) { 
  212. wc_add_notice( $error, 'error' ); 
  213.  
  214. if ( wc_notice_count( 'error' ) === 0 ) { 
  215.  
  216. wp_update_user( $user ); 
  217.  
  218. wc_add_notice( __( 'Account details changed successfully.', 'woocommerce' ) ); 
  219.  
  220. do_action( 'woocommerce_save_account_details', $user->ID ); 
  221.  
  222. wp_safe_redirect( wc_get_page_permalink( 'myaccount' ) ); 
  223. exit; 
  224.  
  225. /** 
  226. * Process the checkout form. 
  227. */ 
  228. public static function checkout_action() { 
  229. if ( isset( $_POST['woocommerce_checkout_place_order'] ) || isset( $_POST['woocommerce_checkout_update_totals'] ) ) { 
  230.  
  231. if ( WC()->cart->is_empty() ) { 
  232. wp_redirect( wc_get_page_permalink( 'cart' ) ); 
  233. exit; 
  234.  
  235. if ( ! defined( 'WOOCOMMERCE_CHECKOUT' ) ) { 
  236. define( 'WOOCOMMERCE_CHECKOUT', true ); 
  237.  
  238. WC()->checkout()->process_checkout(); 
  239.  
  240. /** 
  241. * Process the pay form. 
  242. */ 
  243. public static function pay_action() { 
  244. global $wp; 
  245.  
  246. if ( isset( $_POST['woocommerce_pay'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-pay' ) ) { 
  247.  
  248. ob_start(); 
  249.  
  250. // Pay for existing order 
  251. $order_key = $_GET['key']; 
  252. $order_id = absint( $wp->query_vars['order-pay'] ); 
  253. $order = wc_get_order( $order_id ); 
  254.  
  255. if ( $order->get_id() == $order_id && $order->get_order_key() == $order_key && $order->needs_payment() ) { 
  256.  
  257. do_action( 'woocommerce_before_pay_action', $order ); 
  258.  
  259. WC()->customer->set_props( array( 
  260. 'billing_country' => $order->get_billing_country() ? $order->get_billing_country() : null,  
  261. 'billing_state' => $order->get_billing_state() ? $order->get_billing_state() : null,  
  262. 'billing_postcode' => $order->get_billing_postcode() ? $order->get_billing_postcode() : null,  
  263. 'billing_city' => $order->get_billing_city() ? $order->get_billing_city() : null,  
  264. ) ); 
  265. WC()->customer->save(); 
  266.  
  267. // Terms 
  268. if ( ! empty( $_POST['terms-field'] ) && empty( $_POST['terms'] ) ) { 
  269. wc_add_notice( __( 'You must accept our Terms & Conditions.', 'woocommerce' ), 'error' ); 
  270. return; 
  271.  
  272. // Update payment method 
  273. if ( $order->needs_payment() ) { 
  274. $payment_method = isset( $_POST['payment_method'] ) ? wc_clean( $_POST['payment_method'] ) : false; 
  275. $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); 
  276.  
  277. if ( ! $payment_method ) { 
  278. wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' ); 
  279. return; 
  280.  
  281. // Update meta 
  282. update_post_meta( $order_id, '_payment_method', $payment_method ); 
  283.  
  284. if ( isset( $available_gateways[ $payment_method ] ) ) { 
  285. $payment_method_title = $available_gateways[ $payment_method ]->get_title(); 
  286. } else { 
  287. $payment_method_title = ''; 
  288.  
  289. update_post_meta( $order_id, '_payment_method_title', $payment_method_title ); 
  290.  
  291. // Validate 
  292. $available_gateways[ $payment_method ]->validate_fields(); 
  293.  
  294. // Process 
  295. if ( wc_notice_count( 'error' ) == 0 ) { 
  296.  
  297. $result = $available_gateways[ $payment_method ]->process_payment( $order_id ); 
  298.  
  299. // Redirect to success/confirmation/payment page 
  300. if ( 'success' === $result['result'] ) { 
  301. wp_redirect( $result['redirect'] ); 
  302. exit; 
  303. } else { 
  304. // No payment was required for order 
  305. $order->payment_complete(); 
  306. wp_safe_redirect( $order->get_checkout_order_received_url() ); 
  307. exit; 
  308.  
  309. do_action( 'woocommerce_after_pay_action', $order ); 
  310.  
  311.  
  312. /** 
  313. * Process the add payment method form. 
  314. */ 
  315. public static function add_payment_method_action() { 
  316. if ( isset( $_POST['woocommerce_add_payment_method'], $_POST['payment_method'], $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-add-payment-method' ) ) { 
  317.  
  318. ob_start(); 
  319.  
  320. $payment_method = wc_clean( $_POST['payment_method'] ); 
  321.  
  322. $available_gateways = WC()->payment_gateways->get_available_payment_gateways(); 
  323. // Validate 
  324. $available_gateways[ $payment_method ]->validate_fields(); 
  325.  
  326. // Process 
  327. if ( wc_notice_count( 'wc_errors' ) == 0 ) { 
  328. $result = $available_gateways[ $payment_method ]->add_payment_method(); 
  329. // Redirect to success/confirmation/payment page 
  330. if ( 'success' === $result['result'] ) { 
  331. wc_add_notice( __( 'Payment method added.', 'woocommerce' ) ); 
  332. wp_redirect( $result['redirect'] ); 
  333. exit(); 
  334.  
  335.  
  336. /** 
  337. * Process the delete payment method form. 
  338. */ 
  339. public static function delete_payment_method_action() { 
  340. global $wp; 
  341.  
  342. if ( isset( $wp->query_vars['delete-payment-method'] ) ) { 
  343.  
  344. $token_id = absint( $wp->query_vars['delete-payment-method'] ); 
  345. $token = WC_Payment_Tokens::get( $token_id ); 
  346.  
  347. if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'delete-payment-method-' . $token_id ) ) { 
  348. wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' ); 
  349. } else { 
  350. WC_Payment_Tokens::delete( $token_id ); 
  351. wc_add_notice( __( 'Payment method deleted.', 'woocommerce' ) ); 
  352.  
  353. wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) ); 
  354. exit(); 
  355.  
  356.  
  357. /** 
  358. * Process the delete payment method form. 
  359. */ 
  360. public static function set_default_payment_method_action() { 
  361. global $wp; 
  362.  
  363. if ( isset( $wp->query_vars['set-default-payment-method'] ) ) { 
  364.  
  365. $token_id = absint( $wp->query_vars['set-default-payment-method'] ); 
  366. $token = WC_Payment_Tokens::get( $token_id ); 
  367.  
  368. if ( is_null( $token ) || get_current_user_id() !== $token->get_user_id() || false === wp_verify_nonce( $_REQUEST['_wpnonce'], 'set-default-payment-method-' . $token_id ) ) { 
  369. wc_add_notice( __( 'Invalid payment method.', 'woocommerce' ), 'error' ); 
  370. } else { 
  371. WC_Payment_Tokens::set_users_default( $token->get_user_id(), intval( $token_id ) ); 
  372. wc_add_notice( __( 'This payment method was successfully set as your default.', 'woocommerce' ) ); 
  373.  
  374. wp_redirect( wc_get_account_endpoint_url( 'payment-methods' ) ); 
  375. exit(); 
  376.  
  377.  
  378. /** 
  379. * Remove from cart/update. 
  380. */ 
  381. public static function update_cart_action() { 
  382.  
  383. if ( ! empty( $_POST['apply_coupon'] ) && ! empty( $_POST['coupon_code'] ) ) { 
  384.  
  385. // Add Discount 
  386. WC()->cart->add_discount( sanitize_text_field( $_POST['coupon_code'] ) ); 
  387.  
  388. } elseif ( isset( $_GET['remove_coupon'] ) ) { 
  389.  
  390. // Remove Coupon Codes 
  391. WC()->cart->remove_coupon( wc_clean( $_GET['remove_coupon'] ) ); 
  392.  
  393. } elseif ( ! empty( $_GET['remove_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) { 
  394.  
  395. // Remove from cart 
  396. $cart_item_key = sanitize_text_field( $_GET['remove_item'] ); 
  397.  
  398. if ( $cart_item = WC()->cart->get_cart_item( $cart_item_key ) ) { 
  399. WC()->cart->remove_cart_item( $cart_item_key ); 
  400.  
  401. $product = wc_get_product( $cart_item['product_id'] ); 
  402.  
  403. $item_removed_title = apply_filters( 'woocommerce_cart_item_removed_title', $product ? sprintf( _x( '“%s”', 'Item name in quotes', 'woocommerce' ), $product->get_name() ) : __( 'Item', 'woocommerce' ), $cart_item ); 
  404.  
  405. // Don't show undo link if removed item is out of stock. 
  406. if ( $product->is_in_stock() && $product->has_enough_stock( $cart_item['quantity'] ) ) { 
  407. $removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title ); 
  408. $removed_notice .= ' <a href="' . esc_url( WC()->cart->get_undo_url( $cart_item_key ) ) . '">' . __( 'Undo?', 'woocommerce' ) . '</a>'; 
  409. } else { 
  410. $removed_notice = sprintf( __( '%s removed.', 'woocommerce' ), $item_removed_title ); 
  411.  
  412. wc_add_notice( $removed_notice ); 
  413.  
  414. $referer = wp_get_referer() ? remove_query_arg( array( 'remove_item', 'add-to-cart', 'added-to-cart' ), add_query_arg( 'removed_item', '1', wp_get_referer() ) ) : wc_get_cart_url(); 
  415. wp_safe_redirect( $referer ); 
  416. exit; 
  417.  
  418. } elseif ( ! empty( $_GET['undo_item'] ) && isset( $_GET['_wpnonce'] ) && wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-cart' ) ) { 
  419.  
  420. // Undo Cart Item 
  421. $cart_item_key = sanitize_text_field( $_GET['undo_item'] ); 
  422.  
  423. WC()->cart->restore_cart_item( $cart_item_key ); 
  424.  
  425. $referer = wp_get_referer() ? remove_query_arg( array( 'undo_item', '_wpnonce' ), wp_get_referer() ) : wc_get_cart_url(); 
  426. wp_safe_redirect( $referer ); 
  427. exit; 
  428.  
  429.  
  430. // Update Cart - checks apply_coupon too because they are in the same form 
  431. if ( ( ! empty( $_POST['apply_coupon'] ) || ! empty( $_POST['update_cart'] ) || ! empty( $_POST['proceed'] ) ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'woocommerce-cart' ) ) { 
  432.  
  433. $cart_updated = false; 
  434. $cart_totals = isset( $_POST['cart'] ) ? $_POST['cart'] : ''; 
  435.  
  436. if ( ! WC()->cart->is_empty() && is_array( $cart_totals ) ) { 
  437. foreach ( WC()->cart->get_cart() as $cart_item_key => $values ) { 
  438.  
  439. $_product = $values['data']; 
  440.  
  441. // Skip product if no updated quantity was posted 
  442. if ( ! isset( $cart_totals[ $cart_item_key ] ) || ! isset( $cart_totals[ $cart_item_key ]['qty'] ) ) { 
  443. continue; 
  444.  
  445. // Sanitize 
  446. $quantity = apply_filters( 'woocommerce_stock_amount_cart_item', wc_stock_amount( preg_replace( "/[^0-9\.]/", '', $cart_totals[ $cart_item_key ]['qty'] ) ), $cart_item_key ); 
  447.  
  448. if ( '' === $quantity || $quantity == $values['quantity'] ) 
  449. continue; 
  450.  
  451. // Update cart validation 
  452. $passed_validation = apply_filters( 'woocommerce_update_cart_validation', true, $cart_item_key, $values, $quantity ); 
  453.  
  454. // is_sold_individually 
  455. if ( $_product->is_sold_individually() && $quantity > 1 ) { 
  456. wc_add_notice( sprintf( __( 'You can only have 1 %s in your cart.', 'woocommerce' ), $_product->get_name() ), 'error' ); 
  457. $passed_validation = false; 
  458.  
  459. if ( $passed_validation ) { 
  460. WC()->cart->set_quantity( $cart_item_key, $quantity, false ); 
  461. $cart_updated = true; 
  462.  
  463. // Trigger action - let 3rd parties update the cart if they need to and update the $cart_updated variable 
  464. $cart_updated = apply_filters( 'woocommerce_update_cart_action_cart_updated', $cart_updated ); 
  465.  
  466. if ( $cart_updated ) { 
  467. // Recalc our totals 
  468. WC()->cart->calculate_totals(); 
  469.  
  470. if ( ! empty( $_POST['proceed'] ) ) { 
  471. wp_safe_redirect( wc_get_checkout_url() ); 
  472. exit; 
  473. } elseif ( $cart_updated ) { 
  474. wc_add_notice( __( 'Cart updated.', 'woocommerce' ) ); 
  475. $referer = remove_query_arg( array( 'remove_coupon', 'add-to-cart' ), ( wp_get_referer() ? wp_get_referer() : wc_get_cart_url() ) ); 
  476. wp_safe_redirect( $referer ); 
  477. exit; 
  478.  
  479. /** 
  480. * Place a previous order again. 
  481. */ 
  482. public static function order_again() { 
  483.  
  484. // Nothing to do 
  485. if ( ! isset( $_GET['order_again'] ) || ! is_user_logged_in() || ! isset( $_GET['_wpnonce'] ) || ! wp_verify_nonce( $_GET['_wpnonce'], 'woocommerce-order_again' ) ) { 
  486. return; 
  487.  
  488. // Clear current cart 
  489. WC()->cart->empty_cart(); 
  490.  
  491. // Load the previous order - Stop if the order does not exist 
  492. $order = wc_get_order( absint( $_GET['order_again'] ) ); 
  493.  
  494. if ( ! $order->get_id() ) { 
  495. return; 
  496.  
  497. if ( ! $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_order_again', array( 'completed' ) ) ) ) { 
  498. return; 
  499.  
  500. // Make sure the user is allowed to order again. By default it check if the 
  501. // previous order belonged to the current user. 
  502. if ( ! current_user_can( 'order_again', $order->get_id() ) ) { 
  503. return; 
  504.  
  505. // Copy products from the order to the cart 
  506. $order_items = $order->get_items(); 
  507. foreach ( $order_items as $item ) { 
  508. // Load all product info including variation data 
  509. $product_id = (int) apply_filters( 'woocommerce_add_to_cart_product_id', $item->get_product_id() ); 
  510. $quantity = $item->get_quantity(); 
  511. $variation_id = $item->get_variation_id(); 
  512. $variations = array(); 
  513. $cart_item_data = apply_filters( 'woocommerce_order_again_cart_item_data', array(), $item, $order ); 
  514.  
  515. foreach ( $item->get_meta_data() as $meta ) { 
  516. if ( taxonomy_is_product_attribute( $meta->key ) ) { 
  517. $term = get_term_by( 'slug', $meta->value, $meta->key ); 
  518. $variations[ $meta->key ] = $term ? $term->name : $meta->value; 
  519. } elseif ( meta_is_product_attribute( $meta->key, $meta->value, $product_id ) ) { 
  520. $variations[ $meta->key ] = $meta->value; 
  521.  
  522. // Add to cart validation 
  523. if ( ! apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations, $cart_item_data ) ) { 
  524. continue; 
  525.  
  526. WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations, $cart_item_data ); 
  527.  
  528. do_action( 'woocommerce_ordered_again', $order->get_id() ); 
  529.  
  530. $num_items_in_cart = count( WC()->cart->get_cart() ); 
  531. $num_items_in_original_order = count( $order_items ); 
  532.  
  533. if ( $num_items_in_original_order > $num_items_in_cart ) { 
  534. wc_add_notice( 
  535. sprintf( _n( 
  536. '%d item from your previous order is currently unavailable and could not be added to your cart.',  
  537. '%d items from your previous order are currently unavailable and could not be added to your cart.',  
  538. $num_items_in_original_order - $num_items_in_cart,  
  539. 'woocommerce' 
  540. ), $num_items_in_original_order - $num_items_in_cart ),  
  541. 'error' 
  542. ); 
  543.  
  544. if ( $num_items_in_cart > 0 ) { 
  545. wc_add_notice( __( 'The cart has been filled with the items from your previous order.', 'woocommerce' ) ); 
  546.  
  547. // Redirect to cart 
  548. wp_safe_redirect( wc_get_cart_url() ); 
  549. exit; 
  550.  
  551. /** 
  552. * Cancel a pending order. 
  553. */ 
  554. public static function cancel_order() { 
  555. if ( isset( $_GET['cancel_order'] ) && isset( $_GET['order'] ) && isset( $_GET['order_id'] ) ) { 
  556.  
  557. $order_key = $_GET['order']; 
  558. $order_id = absint( $_GET['order_id'] ); 
  559. $order = wc_get_order( $order_id ); 
  560. $user_can_cancel = current_user_can( 'cancel_order', $order_id ); 
  561. $order_can_cancel = $order->has_status( apply_filters( 'woocommerce_valid_order_statuses_for_cancel', array( 'pending', 'failed' ) ) ); 
  562. $redirect = $_GET['redirect']; 
  563.  
  564. if ( $order->has_status( 'cancelled' ) ) { 
  565. // Already cancelled - take no action 
  566. } elseif ( $user_can_cancel && $order_can_cancel && $order->get_id() === $order_id && $order->get_order_key() === $order_key ) { 
  567.  
  568. // Cancel the order + restore stock 
  569. WC()->session->set( 'order_awaiting_payment', false ); 
  570. $order->update_status( 'cancelled', __( 'Order cancelled by customer.', 'woocommerce' ) ); 
  571.  
  572. // Message 
  573. wc_add_notice( apply_filters( 'woocommerce_order_cancelled_notice', __( 'Your order was cancelled.', 'woocommerce' ) ), apply_filters( 'woocommerce_order_cancelled_notice_type', 'notice' ) ); 
  574.  
  575. do_action( 'woocommerce_cancelled_order', $order->get_id() ); 
  576.  
  577. } elseif ( $user_can_cancel && ! $order_can_cancel ) { 
  578. wc_add_notice( __( 'Your order can no longer be cancelled. Please contact us if you need assistance.', 'woocommerce' ), 'error' ); 
  579. } else { 
  580. wc_add_notice( __( 'Invalid order.', 'woocommerce' ), 'error' ); 
  581.  
  582. if ( $redirect ) { 
  583. wp_safe_redirect( $redirect ); 
  584. exit; 
  585.  
  586. /** 
  587. * Add to cart action. 
  588. * 
  589. * Checks for a valid request, does validation (via hooks) and then redirects if valid. 
  590. * 
  591. * @param bool $url (default: false) 
  592. */ 
  593. public static function add_to_cart_action( $url = false ) { 
  594. if ( empty( $_REQUEST['add-to-cart'] ) || ! is_numeric( $_REQUEST['add-to-cart'] ) ) { 
  595. return; 
  596.  
  597. $product_id = apply_filters( 'woocommerce_add_to_cart_product_id', absint( $_REQUEST['add-to-cart'] ) ); 
  598. $was_added_to_cart = false; 
  599. $adding_to_cart = wc_get_product( $product_id ); 
  600.  
  601. if ( ! $adding_to_cart ) { 
  602. return; 
  603.  
  604. $add_to_cart_handler = apply_filters( 'woocommerce_add_to_cart_handler', $adding_to_cart->get_type(), $adding_to_cart ); 
  605.  
  606. // Variable product handling 
  607. if ( 'variable' === $add_to_cart_handler ) { 
  608. $was_added_to_cart = self::add_to_cart_handler_variable( $product_id ); 
  609.  
  610. // Grouped Products 
  611. } elseif ( 'grouped' === $add_to_cart_handler ) { 
  612. $was_added_to_cart = self::add_to_cart_handler_grouped( $product_id ); 
  613.  
  614. // Custom Handler 
  615. } elseif ( has_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler ) ) { 
  616. do_action( 'woocommerce_add_to_cart_handler_' . $add_to_cart_handler, $url ); 
  617.  
  618. // Simple Products 
  619. } else { 
  620. $was_added_to_cart = self::add_to_cart_handler_simple( $product_id ); 
  621.  
  622. // If we added the product to the cart we can now optionally do a redirect. 
  623. if ( $was_added_to_cart && wc_notice_count( 'error' ) === 0 ) { 
  624. // If has custom URL redirect there 
  625. if ( $url = apply_filters( 'woocommerce_add_to_cart_redirect', $url ) ) { 
  626. wp_safe_redirect( $url ); 
  627. exit; 
  628. } elseif ( get_option( 'woocommerce_cart_redirect_after_add' ) === 'yes' ) { 
  629. wp_safe_redirect( wc_get_cart_url() ); 
  630. exit; 
  631.  
  632. /** 
  633. * Handle adding simple products to the cart. 
  634. * @since 2.4.6 Split from add_to_cart_action 
  635. * @param int $product_id 
  636. * @return bool success or not 
  637. */ 
  638. private static function add_to_cart_handler_simple( $product_id ) { 
  639. $quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] ); 
  640. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity ); 
  641.  
  642. if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity ) !== false ) { 
  643. wc_add_to_cart_message( array( $product_id => $quantity ), true ); 
  644. return true; 
  645. return false; 
  646.  
  647. /** 
  648. * Handle adding grouped products to the cart. 
  649. * @since 2.4.6 Split from add_to_cart_action 
  650. * @param int $product_id 
  651. * @return bool success or not 
  652. */ 
  653. private static function add_to_cart_handler_grouped( $product_id ) { 
  654. $was_added_to_cart = false; 
  655. $added_to_cart = array(); 
  656.  
  657. if ( ! empty( $_REQUEST['quantity'] ) && is_array( $_REQUEST['quantity'] ) ) { 
  658. $quantity_set = false; 
  659.  
  660. foreach ( $_REQUEST['quantity'] as $item => $quantity ) { 
  661. if ( $quantity <= 0 ) { 
  662. continue; 
  663. $quantity_set = true; 
  664.  
  665. // Add to cart validation 
  666. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $item, $quantity ); 
  667.  
  668. if ( $passed_validation && WC()->cart->add_to_cart( $item, $quantity ) !== false ) { 
  669. $was_added_to_cart = true; 
  670. $added_to_cart[ $item ] = $quantity; 
  671.  
  672. if ( ! $was_added_to_cart && ! $quantity_set ) { 
  673. wc_add_notice( __( 'Please choose the quantity of items you wish to add to your cart…', 'woocommerce' ), 'error' ); 
  674. } elseif ( $was_added_to_cart ) { 
  675. wc_add_to_cart_message( $added_to_cart ); 
  676. return true; 
  677. } elseif ( $product_id ) { 
  678. /** Link on product archives */ 
  679. wc_add_notice( __( 'Please choose a product to add to your cart…', 'woocommerce' ), 'error' ); 
  680. return false; 
  681.  
  682. /** 
  683. * Handle adding variable products to the cart. 
  684. * @since 2.4.6 Split from add_to_cart_action 
  685. * @param int $product_id 
  686. * @return bool success or not 
  687. */ 
  688. private static function add_to_cart_handler_variable( $product_id ) { 
  689. $adding_to_cart = wc_get_product( $product_id ); 
  690. $variation_id = empty( $_REQUEST['variation_id'] ) ? '' : absint( $_REQUEST['variation_id'] ); 
  691. $quantity = empty( $_REQUEST['quantity'] ) ? 1 : wc_stock_amount( $_REQUEST['quantity'] ); 
  692. $missing_attributes = array(); 
  693. $variations = array(); 
  694. $attributes = $adding_to_cart->get_attributes(); 
  695.  
  696. // If no variation ID is set, attempt to get a variation ID from posted attributes. 
  697. if ( empty( $variation_id ) ) { 
  698. $data_store = WC_Data_Store::load( 'product' ); 
  699. $variation_id = $data_store->find_matching_product_variation( $adding_to_cart, wp_unslash( $_POST ) ); 
  700.  
  701. // Validate the attributes. 
  702. try { 
  703. if ( empty( $variation_id ) ) { 
  704. throw new Exception( __( 'Please choose product options…', 'woocommerce' ) ); 
  705.  
  706. $variation_data = wc_get_product_variation_attributes( $variation_id ); 
  707.  
  708. foreach ( $attributes as $attribute ) { 
  709. if ( ! $attribute['is_variation'] ) { 
  710. continue; 
  711.  
  712. $taxonomy = 'attribute_' . sanitize_title( $attribute['name'] ); 
  713.  
  714. if ( isset( $_REQUEST[ $taxonomy ] ) ) { 
  715. // Get value from post data 
  716. if ( $attribute['is_taxonomy'] ) { 
  717. // Don't use wc_clean as it destroys sanitized characters 
  718. $value = sanitize_title( stripslashes( $_REQUEST[ $taxonomy ] ) ); 
  719. } else { 
  720. $value = wc_clean( stripslashes( $_REQUEST[ $taxonomy ] ) ); 
  721.  
  722. // Get valid value from variation 
  723. $valid_value = isset( $variation_data[ $taxonomy ] ) ? $variation_data[ $taxonomy ] : ''; 
  724.  
  725. // Allow if valid or show error. 
  726. if ( '' === $valid_value || $valid_value === $value ) { 
  727. $variations[ $taxonomy ] = $value; 
  728. } else { 
  729. throw new Exception( sprintf( __( 'Invalid value posted for %s', 'woocommerce' ), wc_attribute_label( $attribute['name'] ) ) ); 
  730. } else { 
  731. $missing_attributes[] = wc_attribute_label( $attribute['name'] ); 
  732. if ( ! empty( $missing_attributes ) ) { 
  733. throw new Exception( sprintf( _n( '%s is a required field', '%s are required fields', sizeof( $missing_attributes ), 'woocommerce' ), wc_format_list_of_items( $missing_attributes ) ) ); 
  734. } catch ( Exception $e ) { 
  735. wc_add_notice( $e->getMessage(), 'error' ); 
  736. return false; 
  737.  
  738. // Add to cart validation 
  739. $passed_validation = apply_filters( 'woocommerce_add_to_cart_validation', true, $product_id, $quantity, $variation_id, $variations ); 
  740.  
  741. if ( $passed_validation && WC()->cart->add_to_cart( $product_id, $quantity, $variation_id, $variations ) !== false ) { 
  742. wc_add_to_cart_message( array( $product_id => $quantity ), true ); 
  743. return true; 
  744.  
  745. return false; 
  746.  
  747. /** 
  748. * Process the login form. 
  749. */ 
  750. public static function process_login() { 
  751. $nonce_value = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : ''; 
  752. $nonce_value = isset( $_POST['woocommerce-login-nonce'] ) ? $_POST['woocommerce-login-nonce'] : $nonce_value; 
  753.  
  754. if ( ! empty( $_POST['login'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-login' ) ) { 
  755.  
  756. try { 
  757. $creds = array( 
  758. 'user_password' => $_POST['password'],  
  759. 'remember' => isset( $_POST['rememberme'] ),  
  760. ); 
  761.  
  762. $username = trim( $_POST['username'] ); 
  763. $validation_error = new WP_Error(); 
  764. $validation_error = apply_filters( 'woocommerce_process_login_errors', $validation_error, $_POST['username'], $_POST['password'] ); 
  765.  
  766. if ( $validation_error->get_error_code() ) { 
  767. throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $validation_error->get_error_message() ); 
  768.  
  769. if ( empty( $username ) ) { 
  770. throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . __( 'Username is required.', 'woocommerce' ) ); 
  771.  
  772. if ( is_email( $username ) && apply_filters( 'woocommerce_get_username_from_email', true ) ) { 
  773. $user = get_user_by( 'email', $username ); 
  774.  
  775. if ( isset( $user->user_login ) ) { 
  776. $creds['user_login'] = $user->user_login; 
  777. } else { 
  778. throw new Exception( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . __( 'A user could not be found with this email address.', 'woocommerce' ) ); 
  779. } else { 
  780. $creds['user_login'] = $username; 
  781.  
  782. // On multisite, ensure user exists on current site, if not add them before allowing login. 
  783. if ( is_multisite() ) { 
  784. $user_data = get_user_by( 'login', $username ); 
  785.  
  786. if ( $user_data && ! is_user_member_of_blog( $user_data->ID, get_current_blog_id() ) ) { 
  787. add_user_to_blog( get_current_blog_id(), $user_data->ID, 'customer' ); 
  788.  
  789. // Perform the login 
  790. $user = wp_signon( apply_filters( 'woocommerce_login_credentials', $creds ), is_ssl() ); 
  791.  
  792. if ( is_wp_error( $user ) ) { 
  793. $message = $user->get_error_message(); 
  794. $message = str_replace( '<strong>' . esc_html( $creds['user_login'] ) . '</strong>', '<strong>' . esc_html( $username ) . '</strong>', $message ); 
  795. throw new Exception( $message ); 
  796. } else { 
  797.  
  798. if ( ! empty( $_POST['redirect'] ) ) { 
  799. $redirect = $_POST['redirect']; 
  800. } elseif ( wp_get_referer() ) { 
  801. $redirect = wp_get_referer(); 
  802. } else { 
  803. $redirect = wc_get_page_permalink( 'myaccount' ); 
  804.  
  805. wp_redirect( apply_filters( 'woocommerce_login_redirect', $redirect, $user ) ); 
  806. exit; 
  807. } catch ( Exception $e ) { 
  808. wc_add_notice( apply_filters( 'login_errors', $e->getMessage() ), 'error' ); 
  809. do_action( 'woocommerce_login_failed' ); 
  810.  
  811. /** 
  812. * Handle lost password form. 
  813. */ 
  814. public static function process_lost_password() { 
  815. if ( isset( $_POST['wc_reset_password'] ) && isset( $_POST['user_login'] ) && isset( $_POST['_wpnonce'] ) && wp_verify_nonce( $_POST['_wpnonce'], 'lost_password' ) ) { 
  816. $success = WC_Shortcode_My_Account::retrieve_password(); 
  817.  
  818. // If successful, redirect to my account with query arg set 
  819. if ( $success ) { 
  820. wp_redirect( add_query_arg( 'reset-link-sent', 'true', remove_query_arg( array( 'key', 'login', 'reset' ) ) ) ); 
  821. exit; 
  822.  
  823. /** 
  824. * Handle reset password form. 
  825. */ 
  826. public static function process_reset_password() { 
  827. $posted_fields = array( 'wc_reset_password', 'password_1', 'password_2', 'reset_key', 'reset_login', '_wpnonce' ); 
  828.  
  829. foreach ( $posted_fields as $field ) { 
  830. if ( ! isset( $_POST[ $field ] ) ) { 
  831. return; 
  832. $posted_fields[ $field ] = $_POST[ $field ]; 
  833.  
  834. if ( ! wp_verify_nonce( $posted_fields['_wpnonce'], 'reset_password' ) ) { 
  835. return; 
  836.  
  837. $user = WC_Shortcode_My_Account::check_password_reset_key( $posted_fields['reset_key'], $posted_fields['reset_login'] ); 
  838.  
  839. if ( $user instanceof WP_User ) { 
  840. if ( empty( $posted_fields['password_1'] ) ) { 
  841. wc_add_notice( __( 'Please enter your password.', 'woocommerce' ), 'error' ); 
  842.  
  843. if ( $posted_fields['password_1'] !== $posted_fields['password_2'] ) { 
  844. wc_add_notice( __( 'Passwords do not match.', 'woocommerce' ), 'error' ); 
  845.  
  846. $errors = new WP_Error(); 
  847.  
  848. do_action( 'validate_password_reset', $errors, $user ); 
  849.  
  850. wc_add_wp_error_notices( $errors ); 
  851.  
  852. if ( 0 === wc_notice_count( 'error' ) ) { 
  853. WC_Shortcode_My_Account::reset_password( $user, $posted_fields['password_1'] ); 
  854.  
  855. do_action( 'woocommerce_customer_reset_password', $user ); 
  856.  
  857. wp_redirect( add_query_arg( 'password-reset', 'true', wc_get_page_permalink( 'myaccount' ) ) ); 
  858. exit; 
  859.  
  860. /** 
  861. * Process the registration form. 
  862. */ 
  863. public static function process_registration() { 
  864. $nonce_value = isset( $_POST['_wpnonce'] ) ? $_POST['_wpnonce'] : ''; 
  865. $nonce_value = isset( $_POST['woocommerce-register-nonce'] ) ? $_POST['woocommerce-register-nonce'] : $nonce_value; 
  866.  
  867. if ( ! empty( $_POST['register'] ) && wp_verify_nonce( $nonce_value, 'woocommerce-register' ) ) { 
  868. $username = 'no' === get_option( 'woocommerce_registration_generate_username' ) ? $_POST['username'] : ''; 
  869. $password = 'no' === get_option( 'woocommerce_registration_generate_password' ) ? $_POST['password'] : ''; 
  870. $email = $_POST['email']; 
  871.  
  872. try { 
  873. $validation_error = new WP_Error(); 
  874. $validation_error = apply_filters( 'woocommerce_process_registration_errors', $validation_error, $username, $password, $email ); 
  875.  
  876. if ( $validation_error->get_error_code() ) { 
  877. throw new Exception( $validation_error->get_error_message() ); 
  878.  
  879. // Anti-spam trap 
  880. if ( ! empty( $_POST['email_2'] ) ) { 
  881. throw new Exception( __( 'Anti-spam field was filled in.', 'woocommerce' ) ); 
  882.  
  883. $new_customer = wc_create_new_customer( sanitize_email( $email ), wc_clean( $username ), $password ); 
  884.  
  885. if ( is_wp_error( $new_customer ) ) { 
  886. throw new Exception( $new_customer->get_error_message() ); 
  887.  
  888. if ( apply_filters( 'woocommerce_registration_auth_new_customer', true, $new_customer ) ) { 
  889. wc_set_customer_auth_cookie( $new_customer ); 
  890.  
  891. wp_safe_redirect( apply_filters( 'woocommerce_registration_redirect', wp_get_referer() ? wp_get_referer() : wc_get_page_permalink( 'myaccount' ) ) ); 
  892. exit; 
  893.  
  894. } catch ( Exception $e ) { 
  895. wc_add_notice( '<strong>' . __( 'Error:', 'woocommerce' ) . '</strong> ' . $e->getMessage(), 'error' ); 
  896.  
  897. WC_Form_Handler::init(); 
.