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/admin/class-steps.php +194 -20 1.2.32.7.0 View file →
@@ -5,8 +5,10 @@
5 5 /**
6 6 * Steps class.
7 7 *
8 8 * @since 1.1.0
9 + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
10 + * @SuppressWarnings(PHPMD.CyclomaticComplexity)
9 11 */
10 12 class Sellkit_Admin_Steps {
11 13
12 14 /**
@@ -57,11 +59,35 @@
57 59 add_filter( 'template_include', [ $this, 'load_page_template' ], 10 );
58 60 add_action( 'wp_ajax_sellkit_steps_get_coupons', [ $this, 'get_coupons' ] );
59 61 add_action( 'wp_loaded', [ $this, 'sellkit_steps_flush_rules' ] );
60 62 add_action( 'sellkit_after_toggle_status_sellkit-funnels', [ $this, 'update_steps_post_status' ], 10, 2 );
63 + add_action( 'sellkit_funnels_after_delete_posts_sellkit-funnels', [ $this, 'remove_steps_pages' ], 10, 1 );
64 +
65 + add_action( 'wp_loaded', [ $this, 'sellkit_set_sellkit_translation_mode' ] );
61 66 }
62 67
63 68 /**
69 + * Removes steps pages.
70 + *
71 + * @since 1.5.4
72 + * @return void
73 + * @param array $post Posts.
74 + */
75 + public function remove_steps_pages( $post ) {
76 + $nodes = get_post_meta( $post['ID'], 'nodes' );
77 +
78 + if ( empty( $nodes[0] ) ) {
79 + return;
80 + }
81 +
82 + foreach ( $nodes[0] as $node ) {
83 + if ( isset( $node['page_id'] ) ) {
84 + wp_delete_post( $node['page_id'] );
85 + }
86 + }
87 + }
88 +
89 + /**
64 90 * Get default funnels.
65 91 *
66 92 * @since 1.1.0
67 93 */
@@ -69,9 +95,13 @@
69 95 return [
70 96 'sales-page' => esc_html__( 'Sales Page', 'sellkit' ),
71 97 'checkout' => esc_html__( 'Checkout', 'sellkit' ),
72 98 'thankyou' => esc_html__( 'Thank You', 'sellkit' ),
99 + 'decision' => esc_html__( 'Condition', 'sellkit' ),
73 100 'upsell' => esc_html__( 'Upsell', 'sellkit' ),
101 + 'downsell' => esc_html__( 'Downsell', 'sellkit' ),
102 + 'optin-confirmation' => esc_html__( 'Opt-in Confirmation', 'sellkit' ),
103 + 'optin' => esc_html__( 'Opt-in', 'sellkit' ),
74 104 ];
75 105 }
76 106
77 107 /**
@@ -85,9 +115,17 @@
85 115 foreach ( $steps as $step_number => $step ) {
86 116 $step['funnel_id'] = $funnel_id;
87 117 $step['number'] = $step_number;
88 118
89 - update_post_meta( $step['page_id'], 'step_data', $step );
119 + if ( array_key_exists( 'page_id', $step ) ) {
120 + $translated_step = apply_filters( 'wpml_object_id', $step['page_id'], 'sellkit_step', true ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
121 +
122 + if ( $step['page_id'] !== $translated_step ) {
123 + update_post_meta( $translated_step, 'step_data', $step );
124 + }
125 +
126 + update_post_meta( $step['page_id'], 'step_data', $step );
127 + }
90 128 }
91 129 }
92 130
93 131 /**
@@ -131,8 +169,12 @@
131 169 check_ajax_referer( 'sellkit', 'nonce' );
132 170
133 171 $input_value = sellkit_htmlspecialchars( INPUT_GET, 'input_value' );
134 172
173 + if ( ! sellkit()->has_valid_dependencies() ) {
174 + wp_send_json_error( __( 'Please install and activate WooCommerce.', 'sellkit' ) );
175 + }
176 +
135 177 $filtered_products = [];
136 178
137 179 $args = [
138 180 'status' => 'any',
@@ -144,9 +186,9 @@
144 186
145 187 $all_products = wc_get_products( $args );
146 188
147 189 foreach ( $all_products as $product ) {
148 - if ( $product->get_type() !== 'variable' ) {
190 + if ( $product->get_type() !== 'variable' && $product->get_type() !== 'external' ) {
149 191 $filtered_products[] = [
150 192 'label' => $product->get_title(),
151 193 'value' => $product->get_id(),
152 194 ];
@@ -178,10 +220,14 @@
178 220
179 221 $filtered_products = [];
180 222 $products_id = filter_input( INPUT_GET, 'products_id', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY );
181 223
224 + if ( ! sellkit()->has_valid_dependencies() ) {
225 + wp_send_json_error( __( 'Please install and activate WooCommerce.', 'sellkit' ) );
226 + }
227 +
182 228 if ( empty( $products_id ) ) {
183 - wp_send_json_error( __( 'Please send some product ids' ) );
229 + wp_send_json_error( __( 'Please send some product ids', 'sellkit' ) );
184 230 }
185 231
186 232 $products_id = is_array( $products_id ) ? $products_id : [ $products_id ];
187 233
@@ -188,12 +234,17 @@
188 234 foreach ( $products_id as $product_id ) {
189 235 $product = wc_get_product( $product_id );
190 236
191 237 if ( empty( $product ) ) {
192 - wp_send_json_error( __( 'Product does not exist', 'sellkit' ) );
193 238 continue;
194 239 }
195 240
241 + $data = $product->get_data();
242 +
243 + if ( 'trash' === $data['status'] ) {
244 + continue;
245 + }
246 +
196 247 $attributes = $product->get_attributes();
197 248 $label = $product->get_title();
198 249
199 250 if ( $product->get_type() === 'variation' ) {
@@ -206,8 +257,9 @@
206 257 'id' => $product->get_id(),
207 258 'title' => $label,
208 259 'thumbnail' => $product->get_image(),
209 260 'regular_price' => $product->get_regular_price( 'edit' ),
261 + 'sale_price' => ( $product->is_on_sale() ) ? $product->get_sale_price() : false,
210 262 ];
211 263 }
212 264
213 265 wp_send_json_success( $filtered_products );
@@ -217,37 +269,118 @@
217 269 * Filter step data before saving.
218 270 *
219 271 * @since 1.1.0
220 272 * @param string $post_id Post id.
273 + * @SuppressWarnings(PHPMD.NPathComplexity)
221 274 */
222 275 public function after_create_step_callback( $post_id ) {
223 - $steps = get_post_meta( $post_id, 'sellkit_steps', true );
224 - $last_step = end( $steps );
276 + $sub_action_data = sellkit_post( 'sub_action_data' );
277 + $origin_node = isset( $sub_action_data['origin_node'] ) ? $sub_action_data['origin_node'] : '';
278 + $target_node = ! empty( $sub_action_data['target_node'] ) ? $sub_action_data['target_node'] : null;
279 + $target_index = isset( $sub_action_data['target_index'] ) ? $sub_action_data['target_index'] : 0;
280 + $nodes = get_post_meta( $post_id, 'nodes', true );
281 + $last_node = end( $nodes );
225 282
226 - array_pop( $steps );
283 + array_pop( $nodes );
227 284
228 - $new_step_id = wp_insert_post( [
285 + $new_node_id = wp_insert_post( [
229 286 'post_type' => self::SELLKIT_STEP_POST_TYPE,
230 - 'post_title' => $last_step['title'],
231 - 'post_name' => sanitize_title( $last_step['title'] ),
287 + 'post_title' => $last_node['title'],
288 + 'post_name' => sanitize_title( $last_node['title'] ),
232 289 'post_status' => 'publish',
233 290 ] );
234 291
235 - $last_step['page_id'] = $new_step_id;
236 - $last_step['slug'] = get_post_field( 'post_name', $new_step_id );
292 + $current_target = [ 'nodeId' => $target_node ];
293 + $last_node['page_id'] = $new_node_id;
294 + $last_node['slug'] = get_post_field( 'post_name', $new_node_id );
295 + $last_node['targets'] = ! is_null( $target_node ) ? [ $current_target ] : [];
237 296
238 - $step_data = $last_step;
239 - $step_data['funnel_id'] = $post_id;
240 - $step_data['number'] = count( $steps );
297 + if (
298 + 'decision' === $last_node['type']['key'] && ! is_null( $target_node ) ||
299 + 'upsell' === $last_node['type']['key'] && ! is_null( $target_node ) ||
300 + 'downsell' === $last_node['type']['key'] && ! is_null( $target_node )
301 + ) {
302 + $last_node['targets'] = [
303 + $current_target,
304 + $current_target
305 + ];
306 + }
241 307
242 - update_post_meta( $new_step_id, 'step_data', $step_data );
308 + // Adding current target info the the step.
309 + $last_node['current_target_index'] = $target_index;
243 310
244 - $new_steps = array_merge( $steps, [ $last_step ] );
311 + if ( 'last-node' === $origin_node ) {
312 + $first_end_path_node_key = self::get_first_end_path_node_key( $nodes );
313 + $last_node['origin_node'] = 'last-node';
245 314
246 - update_post_meta( $post_id, 'sellkit_steps', $new_steps );
315 + if ( $first_end_path_node_key ) {
316 + unset( $nodes[ $first_end_path_node_key ]['origin_node'] );
317 + }
318 + }
319 +
320 + $node_data = $last_node;
321 + $node_data['funnel_id'] = $post_id;
322 + $node_data['number'] = count( $nodes );
323 +
324 + update_post_meta( $new_node_id, 'step_data', $node_data );// it should be updated.
325 +
326 + $old_node_keys = array_keys( $nodes );
327 + $nodes[ end( $old_node_keys ) + 1 ] = $last_node;
328 + $keys = array_keys( $nodes );
329 +
330 + if (
331 + 'last-node' !== $origin_node && ! empty( $nodes[ $origin_node ] ) &&
332 + 'decision' !== $nodes[ $origin_node ]['type']['key'] &&
333 + 'upsell' !== $nodes[ $origin_node ]['type']['key'] &&
334 + 'downsell' !== $nodes[ $origin_node ]['type']['key']
335 + ) {
336 + $nodes[ $origin_node ]['targets'] = [ [ 'nodeId' => strval( end( $keys ) ) ] ];
337 + }
338 +
339 + if (
340 + 'last-node' !== $origin_node && isset( $nodes[ $origin_node ]['type'] ) &&
341 + (
342 + 'decision' === $nodes[ $origin_node ]['type']['key'] ||
343 + 'upsell' === $nodes[ $origin_node ]['type']['key'] ||
344 + 'downsell' === $nodes[ $origin_node ]['type']['key']
345 + )
346 + ) {
347 + if ( is_array( $nodes[ $origin_node ]['targets'] ) && empty( $nodes[ $origin_node ]['targets'][0] ) ) {
348 + $nodes[ $origin_node ]['targets'][0] = ! empty( $target_node ) ? [ 'nodeId' => $target_node ] : null;
349 + }
350 +
351 + if ( is_array( $nodes[ $origin_node ]['targets'] ) && empty( $nodes[ $origin_node ]['targets'][1] ) ) {
352 + $nodes[ $origin_node ]['targets'][1] = ! empty( $target_node ) ? [ 'nodeId' => $target_node ] : null;
353 + }
354 +
355 + $nodes[ $origin_node ]['targets'][ (int) $target_index ] = [ 'nodeId' => strval( end( $old_node_keys ) + 1 ) ];
356 + }
357 +
358 + if ( '' === $origin_node && null === $target_node ) {
359 + update_post_meta( $post_id, 'nodes', [ 1 => $last_node ] );
360 + return;
361 + }
362 +
363 + update_post_meta( $post_id, 'nodes', $nodes );
247 364 }
248 365
249 366 /**
367 + * Gets last node origin node
368 + *
369 + * @param array $nodes Nodes.
370 + * @since 1.5.0
371 + */
372 + public static function get_first_end_path_node_key( $nodes ) {
373 + foreach ( $nodes as $key => $node ) {
374 + if ( ! empty( $node['origin_node'] ) && 'last-node' === $node['origin_node'] ) {
375 + return $key;
376 + }
377 + }
378 +
379 + return false;
380 + }
381 +
382 + /**
250 383 * Loading page templates.
251 384 *
252 385 * @since 1.1.0
253 386 * @param string $template Template name.
@@ -259,8 +392,12 @@
259 392 if ( 'string' !== gettype( $template ) || ! is_object( $post ) || self::SELLKIT_STEP_POST_TYPE !== $post->post_type ) {
260 393 return $template;
261 394 }
262 395
396 + if ( has_blocks( $post ) ) {
397 + return $template;
398 + }
399 +
263 400 remove_action( 'wp_head', 'adjacent_posts_rel_link_wp_head' );
264 401 add_filter( 'next_post_rel_link', '__return_empty_string' );
265 402 add_filter( 'previous_post_rel_link', '__return_empty_string' );
266 403
@@ -340,12 +477,12 @@
340 477 if ( get_post_field( 'post_name', $page_id ) === $slug ) {
341 478 return;
342 479 }
343 480
344 - $post_data = get_post_meta( $funnel_id, 'sellkit_steps', true );
481 + $post_data = get_post_meta( $funnel_id, 'nodes', true );
345 482 $post_data[ $selected_step ]['slug'] = get_post_field( 'post_name', $page_id );
346 483
347 - update_post_meta( $funnel_id, 'sellkit_steps', $post_data );
484 + update_post_meta( $funnel_id, 'nodes', $post_data );
348 485 }
349 486
350 487 /**
351 488 * Delete step page id.
@@ -384,8 +521,12 @@
384 521 */
385 522 public function update_steps_post_status( $funnel_id, $new_status ) {
386 523 $steps = get_post_meta( $funnel_id, 'sellkit_steps', true );
387 524
525 + if ( ! is_array( $steps ) ) {
526 + return;
527 + }
528 +
388 529 foreach ( $steps as $step ) {
389 530 if ( $step['page_id'] === $funnel_id ) {
390 531 continue;
391 532 }
@@ -393,8 +534,41 @@
393 534 wp_update_post(array(
394 535 'ID' => $step['page_id'],
395 536 'post_status' => $new_status,
396 537 ) );
538 + }
539 + }
540 +
541 + /**
542 + * Make SellKit custom post types translatable by default and set step_data custom field to "Copy".
543 + *
544 + * @since 2.3.2
545 + */
546 + public function sellkit_set_sellkit_translation_mode() {
547 + if ( function_exists( 'wpml_load_settings_helper' ) ) {
548 + global $sitepress;
549 +
550 + if ( $sitepress instanceof SitePress ) {
551 + $settings_helper = wpml_load_settings_helper();
552 +
553 + $post_types = [
554 + 'sellkit_step',
555 + 'sellkit-discount',
556 + 'sellkit-coupon',
557 + 'sellkit-alert',
558 + ];
559 +
560 + foreach ( $post_types as $post_type ) {
561 + $settings_helper->set_post_type_translatable( $post_type );
562 + $settings_helper->set_post_type_translation_unlocked_option( $post_type, true );
563 +
564 + if ( class_exists( '\WPML\Settings\PostType\Automatic' ) ) {
565 + \WPML\Settings\PostType\Automatic::set( $post_type, true );
566 + }
567 + }
568 +
569 + do_action( 'wpml_save_custom_field_translation_option', 'step_data', WPML_COPY_CUSTOM_FIELD ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound -- WPML API.
570 + }
397 571 }
398 572 }
399 573 }
400 574