PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / trunk
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster vtrunk
2.6.0 trunk 1.1.0 1.1.4 1.2.1 1.2.2 1.2.3 1.2.5 1.2.9 1.3.1 1.3.2 1.5.0 1.5.1 1.5.4 1.5.7 1.5.8 1.5.9 1.6.2 1.6.5 1.6.8 1.7.2 1.7.4 1.7.5 1.7.9 1.8.1 All 42 releases
sellkit / includes / elementor / modules / checkout / widgets / checkout.php

checkout.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster trunk, at includes/elementor/modules/checkout/widgets/checkout.php

311 lines 10.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 defined( 'ABSPATH' ) || die();
4
5 use Sellkit\Elementor\Modules\Checkout\Widgets\{ Settings_Controls, Style_Controls };
6 use Sellkit\Elementor\Modules\Checkout\Classes\{Global_Hooks, Local_Hooks, Multi_Step, Helper };
7 use Elementor\Plugin as Elementor;
8 use Sellkit\Global_Checkout\Checkout;
9
10 /**
11 * Checkout class.
12 *
13 * @SuppressWarnings(PHPMD.NPathComplexity)
14 * @since 1.1.0
15 */
16 class Sellkit_Elementor_Checkout_Widget extends Sellkit_Elementor_Base_Widget {
17
18 public function __construct( $data = [], $args = null ) {
19 parent::__construct( $data, $args );
20
21 add_action( 'elementor/frontend/after_enqueue_scripts', [ $this, 'frontend_enqueue_scripts' ], 10 );
22 add_action( 'elementor/editor/after_enqueue_scripts', [ $this, 'editor_enqueue_scripts' ], 10 );
23 }
24
25 public function get_name() {
26 return 'sellkit-checkout';
27 }
28
29 public function get_title() {
30 return __( 'Checkout Form', 'sellkit' );
31 }
32
33 public function get_icon() {
34 return 'sellkit-element-icon sellkit-checkout-icon';
35 }
36
37 public function frontend_enqueue_scripts() {
38 wp_enqueue_script( 'wc-checkout' );
39 }
40
41 public function editor_enqueue_scripts() {
42 wp_enqueue_script( 'wc-checkout' );
43 }
44
45 public function is_reload_preview_required() {
46 return true;
47 }
48
49 public function get_style_depends() {
50 return [ 'font-awesome' ];
51 }
52
53 /**
54 * Apply multi-step functionality.
55 *
56 * @return void
57 * @since 1.1.0
58 */
59 private function apply_multi_step_design( $settings ) {
60 new Multi_Step( $settings );
61 }
62
63 /**
64 * Apply local hooks.
65 *
66 * @return void
67 * @since 1.1.0
68 */
69 private function apply_local_hooks( $settings ) {
70 new Local_Hooks( $settings, $this );
71 }
72
73 protected function register_controls() {
74 require_once __DIR__ . '/settings-controls.php';
75 require_once __DIR__ . '/style-controls.php';
76
77 new Settings_Controls();
78 new Style_Controls();
79 }
80
81 /**
82 * @SuppressWarnings(PHPMD.CyclomaticComplexity)
83 */
84 protected function render() {
85 if ( ! function_exists( 'wc' ) ) {
86 return;
87 }
88
89 $settings = $this->get_settings_for_display();
90 $checkout_id = get_the_ID();
91 $step_data = get_post_meta( $checkout_id, 'step_data', true );
92 $global_checkout = apply_filters( 'sellkit_global_checkout_activated', false );
93 $global_checkout_id = get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 );
94 $current_funnel_id = ( ! empty( $step_data ) ) ? $step_data['funnel_id'] : -1;
95 $empty_cart_msg = $settings['empty_cart']; // phpcs:ignore
96
97 $order_key = ! empty( sellkit_htmlspecialchars( INPUT_GET, 'order-key' ) ) ? sellkit_htmlspecialchars( INPUT_GET, 'order-key' ) : sellkit_htmlspecialchars( INPUT_GET, 'key' );
98
99 if (
100 $global_checkout &&
101 is_wc_endpoint_url( 'order-received' ) &&
102 ! empty( $order_key )
103 ) {
104 $order_id = wc_get_order_id_by_order_key( $order_key );
105
106 if ( empty( $order_id ) ) {
107 /* translators: %s: Empty cart message. */
108 echo sprintf(
109 '<div class="elementor-alert elementor-alert-info sellkit-checkout-empty-cart-message-box">%s</div>',
110 esc_html( $empty_cart_msg )
111 );
112
113 return;
114 }
115
116 // Valid order on the order-received endpoint: render WooCommerce's thank-you
117 // template instead of the checkout form. SellKit's redirect_after_purchase
118 // already runs earlier on template_redirect, but express-checkout flows that
119 // skip SellKit's hidden fields (so no sellkit_funnel_next_step_data meta is
120 // saved) fall through to here and must not show a filled-in checkout form.
121 echo '<div class="woocommerce">';
122 wc_get_template( 'checkout/thankyou.php', [ 'order' => wc_get_order( $order_id ) ] );
123 echo '</div>';
124
125 return;
126 }
127
128 if (
129 $global_checkout &&
130 0 === WC()->cart->get_cart_contents_count() &&
131 ! is_wc_endpoint_url( 'order-received' )
132 ) {
133 /* translators: %s: Empty cart message. */
134 echo sprintf(
135 '<div class="elementor-alert elementor-alert-info sellkit-checkout-empty-cart-message-box">%s</div>',
136 esc_html( $empty_cart_msg )
137 );
138
139 return;
140 }
141
142 if (
143 false === $global_checkout &&
144 intval( $global_checkout_id ) !== intval( $current_funnel_id ) &&
145 is_array( $step_data ) &&
146 (
147 ! array_key_exists( 'data', $step_data ) ||
148 ! array_key_exists( 'list', $step_data['data']['products'] )
149 )
150 ) {
151 /* translators: %s: Empty cart message. */
152 echo sprintf(
153 '<div class="elementor-alert elementor-alert-info sellkit-checkout-empty-cart-message-box">%s</div>',
154 esc_html( $empty_cart_msg )
155 );
156 return;
157 }
158
159 add_filter( 'woocommerce_is_checkout', function() {
160 return true;
161 }, 10 );
162
163 $this->clear_sellkit_checkout_custom_hooks( $settings );
164
165 $shipping_destination = get_option( 'woocommerce_ship_to_destination', true );
166
167 if ( 'multi-step' === $settings['layout-type'] ) {
168 $this->apply_multi_step_design( $settings );
169
170 remove_action( 'woocommerce_checkout_billing', [ WC()->checkout(), 'checkout_form_billing' ] );
171
172 if ( 'billing_only' === $shipping_destination ) {
173 remove_action( 'woocommerce_checkout_shipping', [ WC()->checkout(), 'checkout_form_shipping' ] );
174 add_action( 'woocommerce_checkout_shipping', [ WC()->checkout(), 'checkout_form_billing' ], 10 );
175 }
176 }
177
178 if ( 'one-page' === $settings['layout-type'] ) {
179 remove_action( 'woocommerce_checkout_billing', [ WC()->checkout(), 'checkout_form_billing' ] );
180
181 if ( 'billing_only' === $shipping_destination ) {
182 remove_action( 'woocommerce_checkout_shipping', [ WC()->checkout(), 'checkout_form_shipping' ] );
183 add_action( 'woocommerce_checkout_shipping', [ WC()->checkout(), 'checkout_form_billing' ], 10 );
184 } else {
185 add_action( 'woocommerce_checkout_order_review', [ WC()->checkout(), 'checkout_form_billing' ], 10 );
186 }
187 }
188
189 $this->apply_local_hooks( $settings );
190
191 if ( 'one-page' === $settings['layout-type'] ) {
192 $this->add_render_attribute(
193 'wrapper',
194 'class',
195 'sellkit-checkout-widget-one-page-build sellkit-checkout-widget-main-wrapper'
196 );
197 } else {
198 $this->add_render_attribute(
199 'wrapper',
200 'class',
201 'sellkit-checkout-widget-multi-page-build sellkit-checkout-widget-main-wrapper'
202 );
203 }
204
205 if ( Elementor::$instance->editor->is_edit_mode() ) {
206 $current_user = wp_get_current_user()->ID;
207 }
208
209 echo '<div ' . $this->get_render_attribute_string( 'wrapper' ) . ' >'; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- Elementor-generated attributes.
210 echo do_shortcode( '[woocommerce_checkout]' );
211 echo do_shortcode( '[sellkit_checkout_widget_simulated]' );
212 echo '</div>';
213
214 do_action( 'sellkit-after-checkout-content', $settings );
215
216 if ( Elementor::$instance->editor->is_edit_mode() ) {
217 wp_set_current_user( $current_user );
218 }
219
220 }
221
222 /**
223 * Remove every function attached to sellkit checkout custom hooks.
224 *
225 * @param array $settings widget settings.
226 * @since 1.1.0
227 * @return void
228 */
229 private function clear_sellkit_checkout_custom_hooks( $settings ) {
230 // Removed function that attached to custom hooks to prevent any error.
231 remove_all_actions( 'sellkit-checkout-cart-item' );
232 remove_all_actions( 'sellkit-checkout-step-a-begins' );
233 remove_all_actions( 'sellkit-checkout-step-a-ends' );
234 remove_all_actions( 'sellkit-checkout-step-b-begins' );
235 remove_all_actions( 'sellkit-checkout-step-b-ends' );
236 remove_all_actions( 'sellkit-checkout-widget-step-two-header' );
237 remove_all_actions( 'sellkit-checkout-step-c-begins' );
238 remove_all_actions( 'sellkit-checkout-multistep-third-step-back-btn' );
239 remove_all_actions( 'sellkit-checkout-step-c-ends' );
240 remove_all_actions( 'sellkit-checkout-widget-step-three-header' );
241 remove_all_actions( 'sellkit-checkout-multistep-sidebar-begins' );
242 remove_all_actions( 'sellkit-checkout-multistep-sidebar-ends' );
243 remove_all_actions( 'sellkit-checkout-widget-breadcrumb-desktop' );
244 remove_all_actions( 'sellkit-checkout-widget-breadcrumb-mobile' );
245 remove_all_actions( 'sellkit_checkout_shipping_fields' );
246 remove_all_actions( 'sellkit_checkout_billing_fields' );
247 remove_all_actions( 'sellkit_checkout_after_shipping_section' );
248 remove_all_actions( 'sellkit_checkout_one_page_express_methods' );
249 remove_all_actions( 'sellkit-checkout-widget-custom-coupon-form' );
250 remove_all_filters( 'woocommerce_locate_template' );
251
252 // !TODO We can use this method to move / remove billing and shipping fields.
253 add_action( 'woocommerce_checkout_shipping', [ WC()->checkout(), 'checkout_form_shipping' ] ); // ! added for theme integration. Astra.
254 remove_action( 'woocommerce_checkout_billing', [ WC()->checkout(), 'checkout_form_shipping' ] ); // ! added for theme integration. Astra.
255
256 if ( Elementor::$instance->editor->is_edit_mode() ) {
257 $this->editor_mode( $settings );
258 }
259 }
260
261 /**
262 * Editor mode, Render widget content on clicking it's wrapper.
263 *
264 * @since 1.1.0
265 * @return void
266 */
267 private function editor_mode( $settings ) {
268 add_action( 'sellkit_checkout_required_hidden_fields', function() {
269 echo '<input type="hidden" name="sellkit-elementor-editor-mode" value="true" >';
270 } );
271
272 // Some frontend Hooks doesn't work in editor mode.
273 // So we just hide them in editor mode, BUT we use real hooks in frontend.
274 // Purpose is to increase user experience in editor mode.
275
276 if ( 'yes' !== $settings['show_cart_items'] ) {
277 $this->hide_items_in_editor( 'cart_item' );
278 }
279
280 if ( 'yes' !== $settings['show_cart_edit'] ) {
281 $this->hide_items_in_editor( 'sellkit-one-page-checkout-product-qty' );
282
283 add_filter( 'sellkit-checkout-widget-disable-quantity', [ Helper::instance(), 'checkout_order_hidden_quantity' ], 10, 2 );
284 }
285
286 if ( 'yes' !== $settings['show_shipping_method'] ) {
287 $this->hide_items_in_editor( 'sellkit-one-page-shipping-methods' );
288 }
289
290 add_action( 'sellkit-checkout-widget-custom-coupon-form', function() use ( $settings ) {
291 Local_Hooks::coupon_form( $settings );
292 } );
293
294 if ( 'yes' !== $settings['show_coupon_field'] ) {
295 $this->hide_items_in_editor( 'coupon-form' );
296 }
297
298 if ( 'yes' !== $settings['order_summary_show_image'] ) {
299 $this->hide_items_in_editor( 'sellkit-checkout-widget-item-image' );
300 }
301 }
302
303 private function hide_items_in_editor( $class ) {
304 echo sprintf(
305 /** Translators : %s : class name */
306 '<style>.%s { display:none !important; }</style>',
307 esc_attr( $class )
308 );
309 }
310 }
311