PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.7.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.7.0
2.7.0 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 All 43 releases
← All changes | includes/funnel/class.php +178 -15 1.2.52.7.0 View file →
@@ -1,7 +1,8 @@
1 1 <?php
2 2
3 3 use Elementor\Utils as ElementorUtils;
4 +use Sellkit\Global_Checkout\Checkout as Global_Checkout;
4 5
5 6 defined( 'ABSPATH' ) || die();
6 7
7 8 /**
@@ -7,8 +8,10 @@
7 8 /**
8 9 * Class Sellkit_Funnel
9 10 *
10 11 * @since 1.1.0
12 + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
13 + * @SuppressWarnings(PHPMD.NPathComplexity)
11 14 */
12 15 class Sellkit_Funnel {
13 16
14 17 /**
@@ -27,8 +30,24 @@
27 30 */
28 31 public $next_step_data;
29 32
30 33 /**
34 + * Next no step data.
35 + *
36 + * @var array $next_no_step_data.
37 + * @since 1.5.0
38 + */
39 + public $next_no_step_data;
40 +
41 + /**
42 + * Ending node step data.
43 + *
44 + * @var array $end_node_step_data.
45 + * @since 1.5.0
46 + */
47 + public $end_node_step_data;
48 +
49 + /**
31 50 * The current step data.
32 51 *
33 52 * @var array $current_step_data.
34 53 * @since 1.1.0
@@ -56,9 +75,13 @@
56 75 $page_id = self::get_page_id();
57 76 }
58 77
59 78 if ( empty( $page_id ) ) {
60 - return;
79 + $page_id = $this->get_funnel_step_homepage_id();
80 +
81 + if ( empty( $page_id ) ) {
82 + return;
83 + }
61 84 }
62 85
63 86 $this->set_funnel_data( $page_id );
64 87
@@ -69,8 +92,57 @@
69 92 add_action( 'wp_enqueue_scripts', [ $this, 'enqueue_funnel_frontend_script' ] );
70 93 }
71 94
72 95 /**
96 + * Gets funnel step homepage id.
97 + *
98 + * @since 1.9.6
99 + * @return int|bool
100 + */
101 + private function get_funnel_step_homepage_id() {
102 + if ( is_admin() ) {
103 + return false;
104 + }
105 +
106 + $front_page_id = get_option( 'page_on_front', 0 );
107 +
108 + if ( empty( $front_page_id ) ) {
109 + return false;
110 + }
111 +
112 + $scheme = ( ! empty( $_SERVER['HTTPS'] ) && 'off' !== $_SERVER['HTTPS'] ) ? 'https' : 'http';
113 +
114 + $host = sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ); // phpcs:ignore
115 + $request_uri = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) ); // phpcs:ignore
116 +
117 + $url = esc_url( "$scheme://$host$request_uri" );
118 + $home_url = get_home_url() . '/';
119 +
120 + if ( '/' !== substr( $url, -1 ) ) {
121 + $home_url = get_home_url();
122 + }
123 +
124 + if ( $home_url !== $url ) {
125 + return false;
126 + }
127 +
128 + $post_id = url_to_postid( $url );
129 +
130 + if ( empty( $post_id ) ) {
131 + return false;
132 + }
133 +
134 + $post_type = get_post_type( $post_id );
135 + $status = Funnel_Homepage::check_funnel_step_status( $post_id, $post_type );
136 +
137 + if ( $status && intval( $post_id ) === intval( $front_page_id ) ) {
138 + return $front_page_id;
139 + }
140 +
141 + return false;
142 + }
143 +
144 + /**
73 145 * Class Instance.
74 146 *
75 147 * @since 1.1.0
76 148 * @return Sellkit_Funnel|null
@@ -104,12 +176,39 @@
104 176 echo '<meta name="robots" content="noindex" />';
105 177 } );
106 178 }
107 179
108 - $funnel_data = get_post_meta( $this->current_step_data['funnel_id'], 'sellkit_steps', true );
180 + $funnel_data = (array) get_post_meta( $this->current_step_data['funnel_id'], 'nodes', true );
181 + $is_flowchart = true;
109 182
110 - $this->funnel_id = $this->current_step_data['funnel_id'];
111 - $this->next_step_data = ! empty( $funnel_data[ $this->current_step_data['number'] + 1 ] ) ? $funnel_data[ $this->current_step_data['number'] + 1 ] : false;
183 + if ( empty( $funnel_data ) ) {
184 + $funnel_data = get_post_meta( $this->current_step_data['funnel_id'], 'sellkit_steps', true );
185 + $is_flowchart = false;
186 + }
187 +
188 + $this->funnel_id = $this->current_step_data['funnel_id'];
189 +
190 + if ( false === $is_flowchart ) {
191 + $this->next_step_data = ! empty( $funnel_data[ $this->current_step_data['number'] + 1 ] ) ? $funnel_data[ $this->current_step_data['number'] + 1 ] : false;
192 + }
193 +
194 + if (
195 + true === $is_flowchart &&
196 + ! empty( $this->current_step_data['targets'] ) &&
197 + ! empty( $funnel_data[ $this->current_step_data['targets'][0]['nodeId'] ] )
198 + ) {
199 + $this->next_step_data = 'none' !== $funnel_data[ $this->current_step_data['targets'][0]['nodeId'] ] ? $funnel_data[ $this->current_step_data['targets'][0]['nodeId'] ] : false;
200 + }
201 +
202 + if ( true === $is_flowchart && ! empty( $this->current_step_data['targets'][1]['nodeId'] ) ) {
203 + $this->next_no_step_data = ! empty( $funnel_data[ $this->current_step_data['targets'][1]['nodeId'] ] ) ? $funnel_data[ $this->current_step_data['targets'][1]['nodeId'] ] : false;
204 + }
205 +
206 + $end_node_id = $this->get_end_node_id( $funnel_data );
207 +
208 + if ( ! empty( $end_node_id ) ) {
209 + $this->end_node_step_data = $funnel_data[ $end_node_id ];
210 + }
112 211 }
113 212
114 213 /**
115 214 * Enqueue funnel frontend scripts.
@@ -149,12 +248,16 @@
149 248 * @return array
150 249 */
151 250 public function get_localize_data() {
152 251 if ( ! empty( $this->next_step_data['page_id'] ) ) {
153 - $next_step_link = add_query_arg( [
154 - 'post_type' => Sellkit_Admin_Steps::SELLKIT_STEP_POST_TYPE,
155 - 'p' => $this->next_step_data['page_id'],
156 - ], site_url() );
252 + $next_step_link = ! empty( $this->next_step_data['page_id'] ) ? get_the_permalink( $this->next_step_data['page_id'] ) : '';
253 +
254 + if ( empty( $next_step_link ) ) {
255 + $next_step_link = add_query_arg( [
256 + 'post_type' => Sellkit_Admin_Steps::SELLKIT_STEP_POST_TYPE,
257 + 'p' => $this->next_step_data['page_id'],
258 + ], site_url() );
259 + }
157 260 }
158 261
159 262 return [
160 263 'currentStep' => $this->current_step_data,
@@ -171,13 +274,18 @@
171 274 * @return false|int
172 275 * @SuppressWarnings(PHPMD.NPathComplexity)
173 276 */
174 277 public static function get_page_id() {
175 - $page_id = sellkit_htmlspecialchars( INPUT_POST, 'sellkit_current_page_id' );
176 - $preview = sellkit_htmlspecialchars( INPUT_GET, 'preview' );
278 + $page_id = sellkit_htmlspecialchars( INPUT_POST, 'sellkit_current_page_id' );
279 + $structure = get_option( 'permalink_structure' );
280 + $post_data = filter_input( INPUT_POST, 'post_data', FILTER_DEFAULT );
177 281
178 - if ( ! empty( $preview ) ) {
179 - return false;
282 + if ( ! empty( $post_data ) ) {
283 + parse_str( $post_data, $post_data );
284 +
285 + if ( ! empty( $post_data['sellkit_current_page_id'] ) ) {
286 + return (int) $post_data['sellkit_current_page_id'];
287 + }
180 288 }
181 289
182 290 if ( is_numeric( $page_id ) ) {
183 291 return $page_id;
@@ -182,11 +290,29 @@
182 290 if ( is_numeric( $page_id ) ) {
183 291 return $page_id;
184 292 }
185 293
294 + // Stripe Express Checkout (and similar express flows) POST to wc-ajax=checkout
295 + // without SellKit's hidden fields. Fall back to the checkout step id stored in
296 + // the WC session when the user first landed on the funnel checkout page so we
297 + // can still resolve the funnel context on the server side. The stored value is
298 + // only trusted when recent, to avoid reusing stale ids from older visits.
299 + if ( wp_doing_ajax() && function_exists( 'WC' ) && is_object( WC()->session ) ) {
300 + $session_page_id = (int) WC()->session->get( 'sellkit_current_page_id' );
301 + $session_time = (int) WC()->session->get( 'sellkit_current_page_id_time' );
302 +
303 + if ( $session_page_id > 0 && ( time() - $session_time ) < HOUR_IN_SECONDS ) {
304 + return $session_page_id;
305 + }
306 + }
307 +
186 308 $current_url = esc_url_raw( remove_query_arg( 'order-key' ) );
187 309
188 - if ( empty( strpos( $current_url, 'sellkit_step' ) ) ) {
310 + if ( ! empty( $structure ) ) {
311 + $current_url = self::get_base_url( $current_url );
312 + }
313 +
314 + if ( empty( strpos( $current_url, Funnel_Redirect::$step_base ) ) && ! empty( get_option( 'rewrite_rules' ) ) ) {
189 315 return false;
190 316 }
191 317
192 318 if ( empty( $current_url ) ) {
@@ -216,8 +342,25 @@
216 342 return $page->ID;
217 343 }
218 344
219 345 /**
346 + * Gets main url.
347 + *
348 + * @since 1.5.4
349 + * @param string $url Url.
350 + * @return string
351 + */
352 + private static function get_base_url( $url ) {
353 + $parsed = wp_parse_url( $url );
354 +
355 + if ( empty( $parsed['query'] ) ) {
356 + return $url;
357 + }
358 +
359 + return explode( '?', $url )[0];
360 + }
361 +
362 + /**
220 363 * Customization order pages in admin area.
221 364 *
222 365 * @since 1.1.0
223 366 */
@@ -269,9 +412,10 @@
269 412 $order_number = $parent_order->get_order_number();
270 413 $parent_order_html = sprintf( '<p class="form-field form-field-wide" style= "margin-top: 20px;"><strong>%s: </strong>', esc_html__( 'SellKit Parent Order', 'sellkit' ) );
271 414 $parent_order_html .= sprintf( '<span style= "display: block;"><a href="%1s"><strong>#%2s</strong></a></span>', get_edit_post_link( $main_order_id ), esc_attr( $order_number ) );
272 415 $parent_order_html .= '</p>';
273 - echo $parent_order_html;
416 +
417 + echo wp_kses_post( $parent_order_html );
274 418 }
275 419
276 420 if ( is_numeric( $upsell_order_id ) ) {
277 421 $upsell_order = wc_get_order( $upsell_order_id );
@@ -278,10 +422,29 @@
278 422 $order_number = $upsell_order->get_order_number();
279 423 $upsell_order_html = sprintf( '<p class="form-field form-field-wide" style= "margin-top: 20px;"><strong>%s: </strong>', esc_html__( 'SellKit Upsell Order', 'sellkit' ) );
280 424 $upsell_order_html .= sprintf( '<span style= "display: block;"><a href="%1s"><strong>#%2s</strong></a></span>', get_edit_post_link( $upsell_order_id ), esc_attr( $order_number ) );
281 425 $upsell_order_html .= '</p>';
282 - echo $upsell_order_html;
426 +
427 + echo wp_kses_post( $upsell_order_html );
283 428 }
429 + }
430 +
431 + /**
432 + * Gets end node.
433 + *
434 + * @since 1.5.0
435 + * @param array $funnels Funnels array.
436 + */
437 + public function get_end_node_id( $funnels ) {
438 + $funnels = (array) $funnels;
439 +
440 + foreach ( $funnels as $key => $funnel ) {
441 + if ( ! empty( $funnel['origin_node'] ) && 'last-node' === $funnel['origin_node'] ) {
442 + return $key;
443 + }
444 + }
445 +
446 + return false;
284 447 }
285 448 }
286 449
287 450 if ( ! function_exists( 'sellkit_funnel' ) ) {