PageRenderTime 21ms CodeModel.GetById 14ms RepoModel.GetById 0ms app.codeStats 0ms

/wp-content/plugins/woocommerce/includes/shortcodes/class-wc-shortcode-checkout.php

https://gitlab.com/campus-academy/krowkaramel
PHP | 297 lines | 168 code | 64 blank | 65 comment | 53 complexity | a302b908e3230fa074288ea838355d5f MD5 | raw file
  1. <?php
  2. /**
  3. * Checkout Shortcode
  4. *
  5. * Used on the checkout page, the checkout shortcode displays the checkout process.
  6. *
  7. * @package WooCommerce\Shortcodes\Checkout
  8. * @version 2.0.0
  9. */
  10. defined( 'ABSPATH' ) || exit;
  11. /**
  12. * Shortcode checkout class.
  13. */
  14. class WC_Shortcode_Checkout {
  15. /**
  16. * Get the shortcode content.
  17. *
  18. * @param array $atts Shortcode attributes.
  19. * @return string
  20. */
  21. public static function get( $atts ) {
  22. return WC_Shortcodes::shortcode_wrapper( array( __CLASS__, 'output' ), $atts );
  23. }
  24. /**
  25. * Output the shortcode.
  26. *
  27. * @param array $atts Shortcode attributes.
  28. */
  29. public static function output( $atts ) {
  30. global $wp;
  31. // Check cart class is loaded or abort.
  32. if ( is_null( WC()->cart ) ) {
  33. return;
  34. }
  35. // Backwards compatibility with old pay and thanks link arguments.
  36. if ( isset( $_GET['order'] ) && isset( $_GET['key'] ) ) { // WPCS: input var ok, CSRF ok.
  37. wc_deprecated_argument( __CLASS__ . '->' . __FUNCTION__, '2.1', '"order" is no longer used to pass an order ID. Use the order-pay or order-received endpoint instead.' );
  38. // Get the order to work out what we are showing.
  39. $order_id = absint( $_GET['order'] ); // WPCS: input var ok.
  40. $order = wc_get_order( $order_id );
  41. if ( $order && $order->has_status( 'pending' ) ) {
  42. $wp->query_vars['order-pay'] = absint( $_GET['order'] ); // WPCS: input var ok.
  43. } else {
  44. $wp->query_vars['order-received'] = absint( $_GET['order'] ); // WPCS: input var ok.
  45. }
  46. }
  47. // Handle checkout actions.
  48. if ( ! empty( $wp->query_vars['order-pay'] ) ) {
  49. self::order_pay( $wp->query_vars['order-pay'] );
  50. } elseif ( isset( $wp->query_vars['order-received'] ) ) {
  51. self::order_received( $wp->query_vars['order-received'] );
  52. } else {
  53. self::checkout();
  54. }
  55. }
  56. /**
  57. * Show the pay page.
  58. *
  59. * @throws Exception When validate fails.
  60. * @param int $order_id Order ID.
  61. */
  62. private static function order_pay( $order_id ) {
  63. do_action( 'before_woocommerce_pay' );
  64. $order_id = absint( $order_id );
  65. // Pay for existing order.
  66. if ( isset( $_GET['pay_for_order'], $_GET['key'] ) && $order_id ) { // WPCS: input var ok, CSRF ok.
  67. try {
  68. $order_key = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // WPCS: input var ok, CSRF ok.
  69. $order = wc_get_order( $order_id );
  70. // Order or payment link is invalid.
  71. if ( ! $order || $order->get_id() !== $order_id || ! hash_equals( $order->get_order_key(), $order_key ) ) {
  72. throw new Exception( __( 'Sorry, this order is invalid and cannot be paid for.', 'woocommerce' ) );
  73. }
  74. // Logged out customer does not have permission to pay for this order.
  75. if ( ! current_user_can( 'pay_for_order', $order_id ) && ! is_user_logged_in() ) {
  76. echo '<div class="woocommerce-info">' . esc_html__( 'Please log in to your account below to continue to the payment form.', 'woocommerce' ) . '</div>';
  77. woocommerce_login_form(
  78. array(
  79. 'redirect' => $order->get_checkout_payment_url(),
  80. )
  81. );
  82. return;
  83. }
  84. // Add notice if logged in customer is trying to pay for guest order.
  85. if ( ! $order->get_user_id() && is_user_logged_in() ) {
  86. // If order has does not have same billing email then current logged in user then show warning.
  87. if ( $order->get_billing_email() !== wp_get_current_user()->user_email ) {
  88. wc_print_notice( __( 'You are paying for a guest order. Please continue with payment only if you recognize this order.', 'woocommerce' ), 'error' );
  89. }
  90. }
  91. // Logged in customer trying to pay for someone else's order.
  92. if ( ! current_user_can( 'pay_for_order', $order_id ) ) {
  93. throw new Exception( __( 'This order cannot be paid for. Please contact us if you need assistance.', 'woocommerce' ) );
  94. }
  95. // Does not need payment.
  96. if ( ! $order->needs_payment() ) {
  97. /* translators: %s: order status */
  98. throw new Exception( sprintf( __( 'This order&rsquo;s status is &ldquo;%s&rdquo;&mdash;it cannot be paid for. Please contact us if you need assistance.', 'woocommerce' ), wc_get_order_status_name( $order->get_status() ) ) );
  99. }
  100. // Ensure order items are still stocked if paying for a failed order. Pending orders do not need this check because stock is held.
  101. if ( ! $order->has_status( wc_get_is_pending_statuses() ) ) {
  102. $quantities = array();
  103. foreach ( $order->get_items() as $item_key => $item ) {
  104. if ( $item && is_callable( array( $item, 'get_product' ) ) ) {
  105. $product = $item->get_product();
  106. if ( ! $product ) {
  107. continue;
  108. }
  109. $quantities[ $product->get_stock_managed_by_id() ] = isset( $quantities[ $product->get_stock_managed_by_id() ] ) ? $quantities[ $product->get_stock_managed_by_id() ] + $item->get_quantity() : $item->get_quantity();
  110. }
  111. }
  112. foreach ( $order->get_items() as $item_key => $item ) {
  113. if ( $item && is_callable( array( $item, 'get_product' ) ) ) {
  114. $product = $item->get_product();
  115. if ( ! $product ) {
  116. continue;
  117. }
  118. if ( ! apply_filters( 'woocommerce_pay_order_product_in_stock', $product->is_in_stock(), $product, $order ) ) {
  119. /* translators: %s: product name */
  120. throw new Exception( sprintf( __( 'Sorry, "%s" is no longer in stock so this order cannot be paid for. We apologize for any inconvenience caused.', 'woocommerce' ), $product->get_name() ) );
  121. }
  122. // We only need to check products managing stock, with a limited stock qty.
  123. if ( ! $product->managing_stock() || $product->backorders_allowed() ) {
  124. continue;
  125. }
  126. // Check stock based on all items in the cart and consider any held stock within pending orders.
  127. $held_stock = wc_get_held_stock_quantity( $product, $order->get_id() );
  128. $required_stock = $quantities[ $product->get_stock_managed_by_id() ];
  129. if ( ! apply_filters( 'woocommerce_pay_order_product_has_enough_stock', ( $product->get_stock_quantity() >= ( $held_stock + $required_stock ) ), $product, $order ) ) {
  130. /* translators: 1: product name 2: quantity in stock */
  131. throw new Exception( sprintf( __( 'Sorry, we do not have enough "%1$s" in stock to fulfill your order (%2$s available). We apologize for any inconvenience caused.', 'woocommerce' ), $product->get_name(), wc_format_stock_quantity_for_display( $product->get_stock_quantity() - $held_stock, $product ) ) );
  132. }
  133. }
  134. }
  135. }
  136. WC()->customer->set_props(
  137. array(
  138. 'billing_country' => $order->get_billing_country() ? $order->get_billing_country() : null,
  139. 'billing_state' => $order->get_billing_state() ? $order->get_billing_state() : null,
  140. 'billing_postcode' => $order->get_billing_postcode() ? $order->get_billing_postcode() : null,
  141. )
  142. );
  143. WC()->customer->save();
  144. $available_gateways = WC()->payment_gateways->get_available_payment_gateways();
  145. if ( count( $available_gateways ) ) {
  146. current( $available_gateways )->set_current();
  147. }
  148. wc_get_template(
  149. 'checkout/form-pay.php',
  150. array(
  151. 'order' => $order,
  152. 'available_gateways' => $available_gateways,
  153. 'order_button_text' => apply_filters( 'woocommerce_pay_order_button_text', __( 'Pay for order', 'woocommerce' ) ),
  154. )
  155. );
  156. } catch ( Exception $e ) {
  157. wc_print_notice( $e->getMessage(), 'error' );
  158. }
  159. } elseif ( $order_id ) {
  160. // Pay for order after checkout step.
  161. $order_key = isset( $_GET['key'] ) ? wc_clean( wp_unslash( $_GET['key'] ) ) : ''; // WPCS: input var ok, CSRF ok.
  162. $order = wc_get_order( $order_id );
  163. if ( $order && $order->get_id() === $order_id && hash_equals( $order->get_order_key(), $order_key ) ) {
  164. if ( $order->needs_payment() ) {
  165. wc_get_template( 'checkout/order-receipt.php', array( 'order' => $order ) );
  166. } else {
  167. /* translators: %s: order status */
  168. wc_print_notice( sprintf( __( 'This order&rsquo;s status is &ldquo;%s&rdquo;&mdash;it cannot be paid for. Please contact us if you need assistance.', 'woocommerce' ), wc_get_order_status_name( $order->get_status() ) ), 'error' );
  169. }
  170. } else {
  171. wc_print_notice( __( 'Sorry, this order is invalid and cannot be paid for.', 'woocommerce' ), 'error' );
  172. }
  173. } else {
  174. wc_print_notice( __( 'Invalid order.', 'woocommerce' ), 'error' );
  175. }
  176. do_action( 'after_woocommerce_pay' );
  177. }
  178. /**
  179. * Show the thanks page.
  180. *
  181. * @param int $order_id Order ID.
  182. */
  183. private static function order_received( $order_id = 0 ) {
  184. $order = false;
  185. // Get the order.
  186. $order_id = apply_filters( 'woocommerce_thankyou_order_id', absint( $order_id ) );
  187. $order_key = apply_filters( 'woocommerce_thankyou_order_key', empty( $_GET['key'] ) ? '' : wc_clean( wp_unslash( $_GET['key'] ) ) ); // WPCS: input var ok, CSRF ok.
  188. if ( $order_id > 0 ) {
  189. $order = wc_get_order( $order_id );
  190. if ( ! $order || ! hash_equals( $order->get_order_key(), $order_key ) ) {
  191. $order = false;
  192. }
  193. }
  194. // Empty awaiting payment session.
  195. unset( WC()->session->order_awaiting_payment );
  196. // In case order is created from admin, but paid by the actual customer, store the ip address of the payer
  197. // when they visit the payment confirmation page.
  198. if ( $order && $order->is_created_via( 'admin' ) ) {
  199. $order->set_customer_ip_address( WC_Geolocation::get_ip_address() );
  200. $order->save();
  201. }
  202. // Empty current cart.
  203. wc_empty_cart();
  204. wc_get_template( 'checkout/thankyou.php', array( 'order' => $order ) );
  205. }
  206. /**
  207. * Show the checkout.
  208. */
  209. private static function checkout() {
  210. // Show non-cart errors.
  211. do_action( 'woocommerce_before_checkout_form_cart_notices' );
  212. // Check cart has contents.
  213. if ( WC()->cart->is_empty() && ! is_customize_preview() && apply_filters( 'woocommerce_checkout_redirect_empty_cart', true ) ) {
  214. return;
  215. }
  216. // Check cart contents for errors.
  217. do_action( 'woocommerce_check_cart_items' );
  218. // Calc totals.
  219. WC()->cart->calculate_totals();
  220. // Get checkout object.
  221. $checkout = WC()->checkout();
  222. if ( empty( $_POST ) && wc_notice_count( 'error' ) > 0 ) { // WPCS: input var ok, CSRF ok.
  223. wc_get_template( 'checkout/cart-errors.php', array( 'checkout' => $checkout ) );
  224. wc_clear_notices();
  225. } else {
  226. $non_js_checkout = ! empty( $_POST['woocommerce_checkout_update_totals'] ); // WPCS: input var ok, CSRF ok.
  227. if ( wc_notice_count( 'error' ) === 0 && $non_js_checkout ) {
  228. wc_add_notice( __( 'The order totals have been updated. Please confirm your order by pressing the "Place order" button at the bottom of the page.', 'woocommerce' ) );
  229. }
  230. wc_get_template( 'checkout/form-checkout.php', array( 'checkout' => $checkout ) );
  231. }
  232. }
  233. }