class-wc-form-handler.php 42 KB

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