2012-12-31 18:25:09 +00:00
< ? php
/**
2015-11-03 13:53:50 +00:00
* Checkout Shortcode
2012-12-31 18:25:09 +00:00
*
* Used on the checkout page , the checkout shortcode displays the checkout process .
*
2020-08-05 16:36:24 +00:00
* @ package WooCommerce\Shortcodes\Checkout
2018-03-09 16:25:29 +00:00
* @ version 2.0 . 0
*/
defined ( 'ABSPATH' ) || exit ;
/**
* Shortcode checkout class .
2012-12-31 18:25:09 +00:00
*/
class WC_Shortcode_Checkout {
/**
* Get the shortcode content .
*
2018-03-09 16:25:29 +00:00
* @ param array $atts Shortcode attributes .
2012-12-31 18:25:09 +00:00
* @ return string
*/
public static function get ( $atts ) {
2013-08-09 16:11:15 +00:00
return WC_Shortcodes :: shortcode_wrapper ( array ( __CLASS__ , 'output' ), $atts );
2012-12-31 18:25:09 +00:00
}
/**
* Output the shortcode .
*
2018-03-09 16:25:29 +00:00
* @ param array $atts Shortcode attributes .
2012-12-31 18:25:09 +00:00
*/
public static function output ( $atts ) {
2014-06-08 20:33:11 +00:00
global $wp ;
2013-05-31 15:13:14 +00:00
2018-03-09 16:25:29 +00:00
// Check cart class is loaded or abort.
2014-02-26 15:27:26 +00:00
if ( is_null ( WC () -> cart ) ) {
return ;
}
2018-03-09 16:25:29 +00:00
// Backwards compatibility with old pay and thanks link arguments.
if ( isset ( $_GET [ 'order' ] ) && isset ( $_GET [ 'key' ] ) ) { // WPCS: input var ok, CSRF ok.
2016-11-23 16:15:00 +00:00
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.' );
2013-05-31 15:13:14 +00:00
2018-03-09 16:25:29 +00:00
// Get the order to work out what we are showing.
$order_id = absint ( $_GET [ 'order' ] ); // WPCS: input var ok.
2015-08-15 20:50:42 +00:00
$order = wc_get_order ( $order_id );
2013-05-31 15:13:14 +00:00
2015-08-15 20:50:42 +00:00
if ( $order && $order -> has_status ( 'pending' ) ) {
2018-03-09 16:25:29 +00:00
$wp -> query_vars [ 'order-pay' ] = absint ( $_GET [ 'order' ] ); // WPCS: input var ok.
2014-05-30 16:43:21 +00:00
} else {
2018-03-09 16:25:29 +00:00
$wp -> query_vars [ 'order-received' ] = absint ( $_GET [ 'order' ] ); // WPCS: input var ok.
2014-05-30 16:43:21 +00:00
}
2013-05-31 15:13:14 +00:00
}
2018-03-09 16:25:29 +00:00
// Handle checkout actions.
2013-05-31 15:13:14 +00:00
if ( ! empty ( $wp -> query_vars [ 'order-pay' ] ) ) {
self :: order_pay ( $wp -> query_vars [ 'order-pay' ] );
} elseif ( isset ( $wp -> query_vars [ 'order-received' ] ) ) {
self :: order_received ( $wp -> query_vars [ 'order-received' ] );
} else {
self :: checkout ();
}
}
/**
2015-11-03 13:31:20 +00:00
* Show the pay page .
2015-08-15 20:50:42 +00:00
*
2018-03-09 16:25:29 +00:00
* @ throws Exception When validate fails .
* @ param int $order_id Order ID .
2013-05-31 15:13:14 +00:00
*/
2013-08-15 09:22:38 +00:00
private static function order_pay ( $order_id ) {
2012-12-31 18:25:09 +00:00
2013-05-31 15:13:14 +00:00
do_action ( 'before_woocommerce_pay' );
$order_id = absint ( $order_id );
2017-07-14 09:48:43 +00:00
// Pay for existing order.
2018-03-09 16:25:29 +00:00
if ( isset ( $_GET [ 'pay_for_order' ], $_GET [ 'key' ] ) && $order_id ) { // WPCS: input var ok, CSRF ok.
2017-07-14 09:48:43 +00:00
try {
2020-05-06 16:14:53 +00:00
$order_key = isset ( $_GET [ 'key' ] ) ? wc_clean ( wp_unslash ( $_GET [ 'key' ] ) ) : '' ; // WPCS: input var ok, CSRF ok.
$order = wc_get_order ( $order_id );
2013-05-31 15:13:14 +00:00
2017-07-14 09:48:43 +00:00
// Order or payment link is invalid.
2019-01-21 16:02:28 +00:00
if ( ! $order || $order -> get_id () !== $order_id || ! hash_equals ( $order -> get_order_key (), $order_key ) ) {
2017-07-14 09:48:43 +00:00
throw new Exception ( __ ( 'Sorry, this order is invalid and cannot be paid for.' , 'woocommerce' ) );
}
2017-05-15 15:53:06 +00:00
2017-07-14 09:48:43 +00:00
// Logged out customer does not have permission to pay for this order.
if ( ! current_user_can ( 'pay_for_order' , $order_id ) && ! is_user_logged_in () ) {
2018-03-09 16:25:29 +00:00
echo '<div class="woocommerce-info">' . esc_html__ ( 'Please log in to your account below to continue to the payment form.' , 'woocommerce' ) . '</div>' ;
woocommerce_login_form (
array (
'redirect' => $order -> get_checkout_payment_url (),
)
);
2017-07-14 09:48:43 +00:00
return ;
}
2015-10-06 11:33:45 +00:00
2020-01-24 11:26:50 +00:00
// Add notice if logged in customer is trying to pay for guest order.
if ( ! $order -> get_user_id () && is_user_logged_in () ) {
// If order has does not have same billing email then current logged in user then show warning.
if ( $order -> get_billing_email () !== wp_get_current_user () -> user_email ) {
wc_print_notice ( __ ( 'You are paying for a guest order. Please continue with payment only if you recognize this order.' , 'woocommerce' ), 'error' );
}
}
2017-07-14 09:48:43 +00:00
// Logged in customer trying to pay for someone else's order.
if ( ! current_user_can ( 'pay_for_order' , $order_id ) ) {
throw new Exception ( __ ( 'This order cannot be paid for. Please contact us if you need assistance.' , 'woocommerce' ) );
}
2013-09-06 14:39:45 +00:00
2017-07-14 09:48:43 +00:00
// Does not need payment.
if ( ! $order -> needs_payment () ) {
2018-03-09 16:25:29 +00:00
/* translators: %s: order status */
2017-07-14 09:48:43 +00:00
throw new Exception ( sprintf ( __ ( 'This order’s status is “%s”—it cannot be paid for. Please contact us if you need assistance.' , 'woocommerce' ), wc_get_order_status_name ( $order -> get_status () ) ) );
}
2013-05-31 15:13:14 +00:00
2018-06-08 15:58:33 +00:00
// Ensure order items are still stocked if paying for a failed order. Pending orders do not need this check because stock is held.
2019-01-10 10:43:14 +00:00
if ( ! $order -> has_status ( wc_get_is_pending_statuses () ) ) {
2018-06-08 15:58:33 +00:00
$quantities = array ();
foreach ( $order -> get_items () as $item_key => $item ) {
if ( $item && is_callable ( array ( $item , 'get_product' ) ) ) {
$product = $item -> get_product ();
if ( ! $product ) {
continue ;
}
$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 ();
}
}
foreach ( $order -> get_items () as $item_key => $item ) {
if ( $item && is_callable ( array ( $item , 'get_product' ) ) ) {
$product = $item -> get_product ();
if ( ! $product ) {
continue ;
}
if ( ! apply_filters ( 'woocommerce_pay_order_product_in_stock' , $product -> is_in_stock (), $product , $order ) ) {
/* translators: %s: product name */
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 () ) );
}
2018-11-07 13:54:41 +00:00
// We only need to check products managing stock, with a limited stock qty.
if ( ! $product -> managing_stock () || $product -> backorders_allowed () ) {
continue ;
}
2018-06-08 15:58:33 +00:00
// Check stock based on all items in the cart and consider any held stock within pending orders.
2020-05-06 16:14:53 +00:00
$held_stock = wc_get_held_stock_quantity ( $product , $order -> get_id () );
2018-06-08 15:58:33 +00:00
$required_stock = $quantities [ $product -> get_stock_managed_by_id () ];
2019-12-13 14:16:30 +00:00
if ( ! apply_filters ( 'woocommerce_pay_order_product_has_enough_stock' , ( $product -> get_stock_quantity () >= ( $held_stock + $required_stock ) ), $product , $order ) ) {
2018-06-08 15:58:33 +00:00
/* translators: 1: product name 2: quantity in stock */
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 ) ) );
}
2017-07-14 09:48:43 +00:00
}
}
}
2017-05-15 15:53:06 +00:00
2018-03-09 16:25:29 +00:00
WC () -> customer -> set_props (
array (
'billing_country' => $order -> get_billing_country () ? $order -> get_billing_country () : null ,
'billing_state' => $order -> get_billing_state () ? $order -> get_billing_state () : null ,
'billing_postcode' => $order -> get_billing_postcode () ? $order -> get_billing_postcode () : null ,
)
);
2017-05-15 15:53:06 +00:00
WC () -> customer -> save ();
$available_gateways = WC () -> payment_gateways -> get_available_payment_gateways ();
2018-03-09 16:25:29 +00:00
if ( count ( $available_gateways ) ) {
2017-05-15 15:53:06 +00:00
current ( $available_gateways ) -> set_current ();
}
2018-03-09 16:25:29 +00:00
wc_get_template (
2019-01-04 16:39:57 +00:00
'checkout/form-pay.php' ,
array (
2018-03-09 16:25:29 +00:00
'order' => $order ,
'available_gateways' => $available_gateways ,
'order_button_text' => apply_filters ( 'woocommerce_pay_order_button_text' , __ ( 'Pay for order' , 'woocommerce' ) ),
)
);
2017-07-14 09:48:43 +00:00
} catch ( Exception $e ) {
2018-04-19 17:26:21 +00:00
wc_print_notice ( $e -> getMessage (), 'error' );
2013-05-31 15:13:14 +00:00
}
} elseif ( $order_id ) {
2013-04-23 15:42:34 +00:00
2018-03-09 16:25:29 +00:00
// Pay for order after checkout step.
$order_key = isset ( $_GET [ 'key' ] ) ? wc_clean ( wp_unslash ( $_GET [ 'key' ] ) ) : '' ; // WPCS: input var ok, CSRF ok.
$order = wc_get_order ( $order_id );
2015-10-06 11:33:45 +00:00
2019-01-21 16:02:28 +00:00
if ( $order && $order -> get_id () === $order_id && hash_equals ( $order -> get_order_key (), $order_key ) ) {
2013-07-19 12:30:27 +00:00
2015-09-05 12:06:57 +00:00
if ( $order -> needs_payment () ) {
2013-07-19 12:30:27 +00:00
2017-07-15 16:41:34 +00:00
wc_get_template ( 'checkout/order-receipt.php' , array ( 'order' => $order ) );
2018-03-09 16:25:29 +00:00
2013-07-19 12:30:27 +00:00
} else {
2018-03-09 16:25:29 +00:00
/* translators: %s: order status */
2018-04-19 17:26:21 +00:00
wc_print_notice ( sprintf ( __ ( 'This order’s status is “%s”—it cannot be paid for. Please contact us if you need assistance.' , 'woocommerce' ), wc_get_order_status_name ( $order -> get_status () ) ), 'error' );
2013-07-19 12:30:27 +00:00
}
} else {
2018-04-19 17:26:21 +00:00
wc_print_notice ( __ ( 'Sorry, this order is invalid and cannot be paid for.' , 'woocommerce' ), 'error' );
2013-05-31 15:13:14 +00:00
}
} else {
2018-04-19 17:26:21 +00:00
wc_print_notice ( __ ( 'Invalid order.' , 'woocommerce' ), 'error' );
2013-05-31 15:13:14 +00:00
}
do_action ( 'after_woocommerce_pay' );
}
/**
2015-11-03 13:31:20 +00:00
* Show the thanks page .
2015-08-15 20:50:42 +00:00
*
2018-03-09 16:25:29 +00:00
* @ param int $order_id Order ID .
2013-05-31 15:13:14 +00:00
*/
2013-08-15 09:22:38 +00:00
private static function order_received ( $order_id = 0 ) {
2013-05-31 15:13:14 +00:00
$order = false ;
2018-03-09 16:25:29 +00:00
// Get the order.
2013-05-31 15:13:14 +00:00
$order_id = apply_filters ( 'woocommerce_thankyou_order_id' , absint ( $order_id ) );
2018-03-09 16:25:29 +00:00
$order_key = apply_filters ( 'woocommerce_thankyou_order_key' , empty ( $_GET [ 'key' ] ) ? '' : wc_clean ( wp_unslash ( $_GET [ 'key' ] ) ) ); // WPCS: input var ok, CSRF ok.
2013-05-31 15:13:14 +00:00
if ( $order_id > 0 ) {
2014-08-15 12:29:21 +00:00
$order = wc_get_order ( $order_id );
2019-01-21 16:02:28 +00:00
if ( ! $order || ! hash_equals ( $order -> get_order_key (), $order_key ) ) {
2016-02-15 15:11:04 +00:00
$order = false ;
}
2013-04-23 15:42:34 +00:00
}
2018-03-09 16:25:29 +00:00
// Empty awaiting payment session.
2013-11-25 14:01:32 +00:00
unset ( WC () -> session -> order_awaiting_payment );
2013-05-31 15:13:14 +00:00
2019-11-28 14:10:33 +00:00
// In case order is created from admin, but paid by the actual customer, store the ip address of the payer
// when they visit the payment confirmation page.
2019-11-29 14:32:38 +00:00
if ( $order && $order -> is_created_via ( 'admin' ) ) {
2018-08-13 12:37:21 +00:00
$order -> set_customer_ip_address ( WC_Geolocation :: get_ip_address () );
$order -> save ();
}
2018-03-09 16:25:29 +00:00
// Empty current cart.
2016-06-09 09:38:55 +00:00
wc_empty_cart ();
2013-11-25 12:45:04 +00:00
wc_get_template ( 'checkout/thankyou.php' , array ( 'order' => $order ) );
2013-05-31 15:13:14 +00:00
}
/**
2015-11-03 13:31:20 +00:00
* Show the checkout .
2013-05-31 15:13:14 +00:00
*/
2013-08-15 09:22:38 +00:00
private static function checkout () {
2019-01-03 23:52:45 +00:00
// Show non-cart errors.
do_action ( 'woocommerce_before_checkout_form_cart_notices' );
2018-03-09 16:25:29 +00:00
// Check cart has contents.
2018-06-10 18:58:47 +00:00
if ( WC () -> cart -> is_empty () && ! is_customize_preview () && apply_filters ( 'woocommerce_checkout_redirect_empty_cart' , true ) ) {
2013-04-23 15:42:34 +00:00
return ;
2014-11-12 15:47:27 +00:00
}
2018-03-09 16:25:29 +00:00
// Check cart contents for errors.
2014-11-12 15:47:27 +00:00
do_action ( 'woocommerce_check_cart_items' );
2012-12-31 18:25:09 +00:00
2018-03-09 16:25:29 +00:00
// Calc totals.
2013-11-25 14:01:32 +00:00
WC () -> cart -> calculate_totals ();
2012-12-31 18:25:09 +00:00
2018-03-09 16:25:29 +00:00
// Get checkout object.
2013-11-25 14:01:32 +00:00
$checkout = WC () -> checkout ();
2012-12-31 18:25:09 +00:00
2018-03-09 16:25:29 +00:00
if ( empty ( $_POST ) && wc_notice_count ( 'error' ) > 0 ) { // WPCS: input var ok, CSRF ok.
2012-12-31 18:25:09 +00:00
2013-11-25 12:45:04 +00:00
wc_get_template ( 'checkout/cart-errors.php' , array ( 'checkout' => $checkout ) );
2019-05-22 07:49:53 +00:00
wc_clear_notices ();
2012-12-31 18:25:09 +00:00
} else {
2018-03-21 22:57:10 +00:00
$non_js_checkout = ! empty ( $_POST [ 'woocommerce_checkout_update_totals' ] ); // WPCS: input var ok, CSRF ok.
2012-12-31 18:25:09 +00:00
2018-03-09 16:25:29 +00:00
if ( wc_notice_count ( 'error' ) === 0 && $non_js_checkout ) {
2016-10-12 10:16:30 +00:00
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' ) );
2017-03-07 20:24:24 +00:00
}
2012-12-31 18:25:09 +00:00
2013-11-25 12:45:04 +00:00
wc_get_template ( 'checkout/form-checkout.php' , array ( 'checkout' => $checkout ) );
2012-12-31 18:25:09 +00:00
}
}
2014-01-26 09:19:17 +00:00
}