| 1 |
<?php |
| 2 |
namespace Sellkit\Blocks\Render; |
| 3 |
|
| 4 |
defined( 'ABSPATH' ) || exit; |
| 5 |
|
| 6 |
use Sellkit\Blocks\Sellkit_Blocks; |
| 7 |
use Sellkit\Global_Checkout\Checkout as Global_Checkout; |
| 8 |
|
| 9 |
/** |
| 10 |
* Checkout block. |
| 11 |
* |
| 12 |
* @since 2.3.0 |
| 13 |
*/ |
| 14 |
class Checkout { |
| 15 |
/** |
| 16 |
* Check block activation. |
| 17 |
* |
| 18 |
* @since 2.3.0 |
| 19 |
* @return boolean |
| 20 |
*/ |
| 21 |
public function is_active() { |
| 22 |
return true; |
| 23 |
} |
| 24 |
|
| 25 |
/** |
| 26 |
* Register block from meta. |
| 27 |
* |
| 28 |
* @since 2.3.0 |
| 29 |
*/ |
| 30 |
public function register_block_meta() { |
| 31 |
register_block_type_from_metadata( |
| 32 |
__DIR__, |
| 33 |
[ |
| 34 |
'render_callback' => [ $this, 'render' ], |
| 35 |
] |
| 36 |
); |
| 37 |
} |
| 38 |
|
| 39 |
/** |
| 40 |
* Check block has inner blocks. |
| 41 |
* |
| 42 |
* @since 2.3.0 |
| 43 |
* @return boolean |
| 44 |
*/ |
| 45 |
public function has_inner_blocks() { |
| 46 |
return true; |
| 47 |
} |
| 48 |
|
| 49 |
/** |
| 50 |
* Check block has inner blocks. |
| 51 |
* |
| 52 |
* @since 2.3.0 |
| 53 |
* @return boolean |
| 54 |
*/ |
| 55 |
public function get_inner_block() { |
| 56 |
$shipping_destination = get_option( 'woocommerce_ship_to_destination', true ); |
| 57 |
|
| 58 |
$inner_blocks = [ |
| 59 |
'checkout-contact-information' => 'block-editor/blocks/checkout/inner-blocks/contact-information/class', |
| 60 |
'checkout-form-shipping' => 'block-editor/blocks/checkout/inner-blocks/form-shipping/class', |
| 61 |
'checkout-cart-shipping' => 'block-editor/blocks/checkout/inner-blocks/cart-shipping/class', |
| 62 |
'checkout-review-order' => 'block-editor/blocks/checkout/inner-blocks/review-order/class', |
| 63 |
'checkout-billing-details' => 'block-editor/blocks/checkout/inner-blocks/billing-details/class', |
| 64 |
'checkout-payment' => 'block-editor/blocks/checkout/inner-blocks/payment/class', |
| 65 |
'checkout-payment-continue' => 'block-editor/blocks/checkout/inner-blocks/payment-continue/class', |
| 66 |
]; |
| 67 |
|
| 68 |
if ( 'billing_only' === $shipping_destination ) { |
| 69 |
$inner_blocks = [ |
| 70 |
'checkout-contact-information' => 'block-editor/blocks/checkout/inner-blocks/contact-information/class', |
| 71 |
'checkout-billing-details' => 'block-editor/blocks/checkout/inner-blocks/billing-details/class', |
| 72 |
'checkout-cart-shipping' => 'block-editor/blocks/checkout/inner-blocks/cart-shipping/class', |
| 73 |
'checkout-review-order' => 'block-editor/blocks/checkout/inner-blocks/review-order/class', |
| 74 |
'checkout-payment' => 'block-editor/blocks/checkout/inner-blocks/payment/class', |
| 75 |
'checkout-payment-continue' => 'block-editor/blocks/checkout/inner-blocks/payment-continue/class', |
| 76 |
]; |
| 77 |
} |
| 78 |
|
| 79 |
return $inner_blocks; |
| 80 |
} |
| 81 |
|
| 82 |
/** |
| 83 |
* Clears all custom actions and filters related to SellKit checkout process. |
| 84 |
* |
| 85 |
* @since 2.3.0 |
| 86 |
*/ |
| 87 |
public function clear_sellkit_checkout_custom_hooks() { |
| 88 |
remove_all_actions( 'sellkit_block_checkout_shipping_fields' ); |
| 89 |
remove_all_actions( 'sellkit_block_checkout_billing_fields' ); |
| 90 |
remove_all_actions( 'sellkit_block_checkout_after_shipping_section' ); |
| 91 |
remove_all_actions( 'sellkit-checkout-widget-express-methods' ); |
| 92 |
remove_all_actions( 'sellkit-checkout-widget-custom-coupon-form' ); |
| 93 |
remove_all_actions( 'sellkit-checkout-widget-custom-coupon-form' ); |
| 94 |
remove_all_actions( 'woocommerce_checkout_update_order_review' ); |
| 95 |
remove_all_filters( 'woocommerce_locate_template' ); |
| 96 |
} |
| 97 |
|
| 98 |
/** |
| 99 |
* Register express checkout integrations for block checkout. |
| 100 |
* |
| 101 |
* @since 2.3.0 |
| 102 |
* @return void |
| 103 |
*/ |
| 104 |
private function setup_express_checkout_integrations() { |
| 105 |
sellkit()->load_files( [ |
| 106 |
'elementor/modules/checkout/integrations/integration', |
| 107 |
'elementor/modules/checkout/integrations/paypal-for-woocommerce', |
| 108 |
'elementor/modules/checkout/integrations/woo-payment-gateway', |
| 109 |
'elementor/modules/checkout/integrations/stripe-for-woocommerce', |
| 110 |
'elementor/modules/checkout/integrations/klarma-checkout-woocommerce', |
| 111 |
'elementor/modules/checkout/integrations/amazon-pay-woocommerce', |
| 112 |
'elementor/modules/checkout/integrations/stripe-woocommerce-official', |
| 113 |
] ); |
| 114 |
|
| 115 |
$gateways = [ |
| 116 |
'Paypal_For_Woocommerce', |
| 117 |
'Woo_Payment_Gateway', |
| 118 |
'Stripe_For_Woocommerce', |
| 119 |
'Klarma_Checkout_Woocommerce', |
| 120 |
'Amazon_Pay_Woocommerce', |
| 121 |
'Stripe_Woocommerce_Official', |
| 122 |
]; |
| 123 |
|
| 124 |
foreach ( $gateways as $gateway ) { |
| 125 |
$class = 'Sellkit\Elementor\Modules\Checkout\Integrations\\' . $gateway; |
| 126 |
$class = new $class(); |
| 127 |
$class->run(); |
| 128 |
} |
| 129 |
} |
| 130 |
|
| 131 |
/** |
| 132 |
* Render express checkout section for block checkout. |
| 133 |
* |
| 134 |
* @param array $attributes Checkout block attributes. |
| 135 |
* @since 2.3.0 |
| 136 |
* @return string |
| 137 |
*/ |
| 138 |
private function express_checkout_html( $attributes ) { |
| 139 |
if ( empty( $attributes['showExpressCheckout'] ) ) { |
| 140 |
return ''; |
| 141 |
} |
| 142 |
|
| 143 |
ob_start(); |
| 144 |
do_action( 'sellkit-checkout-widget-express-methods' ); |
| 145 |
$methods = trim( ob_get_clean() ); |
| 146 |
|
| 147 |
if ( empty( $methods ) ) { |
| 148 |
return ''; |
| 149 |
} |
| 150 |
|
| 151 |
ob_start(); |
| 152 |
?> |
| 153 |
<section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-1"> |
| 154 |
<fieldset class="express-box sellkit-checkout-widget-divider"> |
| 155 |
<legend class="sellkit-express-checkout-legend heading"> |
| 156 |
<?php echo esc_html__( 'Express Checkout', 'sellkit' ); ?> |
| 157 |
</legend> |
| 158 |
<div class="express-methods"> |
| 159 |
<?php echo wp_kses_post( $methods ); ?> |
| 160 |
</div> |
| 161 |
</fieldset> |
| 162 |
</section> |
| 163 |
<section class="sellkit-checkout-widget-express-checkout sellkit-checkout-express-checkout-step-2"> |
| 164 |
<fieldset id="sellkit-checkout-or-divider" class="divider-box sellkit-checkout-widget-divider"> |
| 165 |
<legend class="heading"><?php echo esc_html__( 'OR', 'sellkit' ); ?></legend> |
| 166 |
</fieldset> |
| 167 |
</section> |
| 168 |
<?php |
| 169 |
|
| 170 |
return ob_get_clean(); |
| 171 |
} |
| 172 |
|
| 173 |
/** |
| 174 |
* Render block in front-end. |
| 175 |
* |
| 176 |
* @param array $attributes Block attributes. |
| 177 |
* @param string $content Block content. |
| 178 |
* @param \WP_Block $block Block object. |
| 179 |
* @since 2.3.0 |
| 180 |
* @return string |
| 181 |
*/ |
| 182 |
public function render( $attributes, $content, $block ) { |
| 183 |
if ( ! function_exists( 'wc' ) ) { |
| 184 |
return; |
| 185 |
} |
| 186 |
|
| 187 |
if ( ! is_admin() ) { |
| 188 |
Sellkit_Blocks::load_scripts( 'checkout' ); |
| 189 |
Sellkit_Blocks::load_scripts( 'checkout', 'checkout-external', [ 'wc-checkout', 'wc-country-select', 'wp-api' ] ); |
| 190 |
|
| 191 |
wp_localize_script('sellkit-block-checkout-script', 'sellkit_block_checkout', [ |
| 192 |
'nonce' => wp_create_nonce( 'sellkit_block_checkout' ), |
| 193 |
'wcNeedShipping' => ( function_exists( 'WC' ) ) ? WC()->cart->needs_shipping() : '', |
| 194 |
'url' => [ |
| 195 |
'assets' => sellkit()->plugin_url() . 'assets/', |
| 196 |
], |
| 197 |
] ); |
| 198 |
} |
| 199 |
|
| 200 |
$block_html = ''; |
| 201 |
$wrapper_attributes = get_block_wrapper_attributes( [ |
| 202 |
'class' => 'sellkit-checkout-widget-one-page-build sellkit-block-checkout-main-wrapper', |
| 203 |
] ); |
| 204 |
|
| 205 |
do_action( 'sellkit_block_before_checkout_form' ); |
| 206 |
|
| 207 |
if ( sellkit()->has_pro ) { |
| 208 |
$this->setup_express_checkout_integrations(); |
| 209 |
$block_html .= $this->express_checkout_html( $attributes ); |
| 210 |
} |
| 211 |
|
| 212 |
foreach ( $block->inner_blocks as $inner_block ) { |
| 213 |
$block_name = str_replace( 'sellkit-inner-blocks/', '', $inner_block->parsed_block['blockName'] ); |
| 214 |
$block_name = str_replace( '-', ' ', $block_name ); |
| 215 |
$block_name = ucwords( $block_name ); |
| 216 |
$block_name = str_replace(' ', '_', $block_name ); |
| 217 |
$block_content = $inner_block->render(); |
| 218 |
$class_name = 'Sellkit\Blocks\Inner_Block\\' . ucwords( $block_name ); |
| 219 |
|
| 220 |
if ( ! class_exists( $class_name ) ) { |
| 221 |
$block_html .= $inner_block->render(); |
| 222 |
continue; |
| 223 |
} |
| 224 |
|
| 225 |
$new_class = new $class_name(); |
| 226 |
if ( method_exists( $new_class, $block_name ) ) { |
| 227 |
$block_html .= $new_class->$block_name( $block_content, $inner_block->attributes ); |
| 228 |
} |
| 229 |
} |
| 230 |
|
| 231 |
global $woocommerce; |
| 232 |
|
| 233 |
$checkout = $woocommerce->checkout; |
| 234 |
|
| 235 |
do_action( 'woocommerce_before_checkout_form', $checkout ); |
| 236 |
|
| 237 |
// If checkout registration is disabled and not logged in, the user cannot checkout. |
| 238 |
if ( ! $checkout->is_registration_enabled() && $checkout->is_registration_required() && ! is_user_logged_in() ) { |
| 239 |
echo esc_html( apply_filters( 'woocommerce_checkout_must_be_logged_in_message', esc_html__( 'You must be logged in to checkout.', 'sellkit' ) ) ); |
| 240 |
return; |
| 241 |
} |
| 242 |
|
| 243 |
$extra_class = ''; |
| 244 |
|
| 245 |
if ( WC()->cart && ! WC()->cart->needs_shipping() ) { |
| 246 |
$extra_class = 'sellkit-checkout-virtual-session'; |
| 247 |
} |
| 248 |
|
| 249 |
$block_html = sprintf( |
| 250 |
' |
| 251 |
<div %1$s> |
| 252 |
<div class="woocommerce"> |
| 253 |
<div id="sellkit-checkout-widget-id"> |
| 254 |
<form name="checkout" method="post" class="checkout woocommerce-checkout %2$s" action="%3$s" enctype="multipart/form-data"> |
| 255 |
%4$s |
| 256 |
</form> |
| 257 |
%5$s |
| 258 |
</div> |
| 259 |
</div> |
| 260 |
</div> |
| 261 |
', |
| 262 |
wp_kses_data( $wrapper_attributes ), |
| 263 |
esc_attr( $extra_class ), |
| 264 |
esc_url( wc_get_checkout_url() ), |
| 265 |
stripslashes( $block_html ), |
| 266 |
do_action( 'woocommerce_after_checkout_form', $checkout ) |
| 267 |
); |
| 268 |
|
| 269 |
$checkout_id = get_the_ID(); |
| 270 |
$step_data = get_post_meta( $checkout_id, 'step_data', true ); |
| 271 |
$global_checkout = apply_filters( 'sellkit_global_checkout_activated', false ); |
| 272 |
$global_checkout_id = get_option( Global_Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 ); |
| 273 |
$current_funnel_id = ( ! empty( $step_data ) ) ? $step_data['funnel_id'] : -1; |
| 274 |
$empty_cart_msg = esc_html( $attributes['emptyCartMessage'] ); |
| 275 |
|
| 276 |
$order_key = ! empty( sellkit_htmlspecialchars( INPUT_GET, 'order-key' ) ) ? sellkit_htmlspecialchars( INPUT_GET, 'order-key' ) : sellkit_htmlspecialchars( INPUT_GET, 'key' ); |
| 277 |
|
| 278 |
if ( |
| 279 |
$global_checkout && |
| 280 |
is_wc_endpoint_url( 'order-received' ) && |
| 281 |
! empty( $order_key ) |
| 282 |
) { |
| 283 |
$order_id = wc_get_order_id_by_order_key( $order_key ); |
| 284 |
|
| 285 |
if ( empty( $order_id ) ) { |
| 286 |
$block_html = sprintf( |
| 287 |
' |
| 288 |
<div %1$s> |
| 289 |
<div class="woocommerce"> |
| 290 |
<div id="sellkit-checkout-widget-id"> |
| 291 |
<div class="woocommerce-info">%2$s</div> |
| 292 |
</div> |
| 293 |
</div> |
| 294 |
</div>' |
| 295 |
, |
| 296 |
wp_kses_data( $wrapper_attributes ), |
| 297 |
wp_kses_post( $empty_cart_msg ) |
| 298 |
); |
| 299 |
|
| 300 |
return $block_html; |
| 301 |
} |
| 302 |
|
| 303 |
// Valid order on the order-received endpoint: render WooCommerce's thank-you |
| 304 |
// template instead of the checkout form. SellKit's own redirect_after_purchase |
| 305 |
// already runs earlier on template_redirect, but express-checkout flows that |
| 306 |
// skip SellKit's hidden fields (so no sellkit_funnel_next_step_data meta is |
| 307 |
// saved) fall through to here and must not show a filled-in checkout form. |
| 308 |
ob_start(); |
| 309 |
echo '<div class="woocommerce">'; |
| 310 |
wc_get_template( 'checkout/thankyou.php', [ 'order' => wc_get_order( $order_id ) ] ); |
| 311 |
echo '</div>'; |
| 312 |
$thankyou_html = ob_get_clean(); |
| 313 |
|
| 314 |
return sprintf( |
| 315 |
'<div %1$s>%2$s</div>', |
| 316 |
wp_kses_data( $wrapper_attributes ), |
| 317 |
$thankyou_html // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- WooCommerce template output. |
| 318 |
); |
| 319 |
} |
| 320 |
|
| 321 |
if ( |
| 322 |
$global_checkout && |
| 323 |
0 === WC()->cart->get_cart_contents_count() && |
| 324 |
! is_wc_endpoint_url( 'order-received' ) |
| 325 |
) { |
| 326 |
$block_html = sprintf( |
| 327 |
' |
| 328 |
<div %1$s> |
| 329 |
<div class="woocommerce"> |
| 330 |
<div id="sellkit-checkout-widget-id"> |
| 331 |
<div class="woocommerce-info">%2$s</div> |
| 332 |
</div> |
| 333 |
</div> |
| 334 |
</div>' |
| 335 |
, |
| 336 |
wp_kses_data( $wrapper_attributes ), |
| 337 |
wp_kses_post( $empty_cart_msg ) |
| 338 |
); |
| 339 |
|
| 340 |
return $block_html; |
| 341 |
} |
| 342 |
|
| 343 |
if ( |
| 344 |
false === $global_checkout && |
| 345 |
intval( $global_checkout_id ) !== intval( $current_funnel_id ) && |
| 346 |
is_array( $step_data ) && |
| 347 |
( |
| 348 |
! array_key_exists( 'data', $step_data ) || |
| 349 |
! array_key_exists( 'list', $step_data['data']['products'] ) |
| 350 |
) |
| 351 |
) { |
| 352 |
$block_html = sprintf( |
| 353 |
' |
| 354 |
<div %1$s> |
| 355 |
<div class="woocommerce"> |
| 356 |
<div id="sellkit-checkout-widget-id"> |
| 357 |
<div class="woocommerce-info">%2$s</div> |
| 358 |
</div> |
| 359 |
</div> |
| 360 |
</div>' |
| 361 |
, |
| 362 |
wp_kses_data( $wrapper_attributes ), |
| 363 |
wp_kses_post( $empty_cart_msg ) |
| 364 |
); |
| 365 |
|
| 366 |
return $block_html; |
| 367 |
} |
| 368 |
|
| 369 |
add_filter( 'woocommerce_is_checkout', function() { |
| 370 |
return true; |
| 371 |
}, 10 ); |
| 372 |
|
| 373 |
$this->clear_sellkit_checkout_custom_hooks(); |
| 374 |
|
| 375 |
return $block_html; |
| 376 |
} |
| 377 |
} |
| 378 |
|