PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 2.3.0
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v2.3.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 1.8.1 All 42 releases
← All changes | includes/admin/class-posts.php +229 -2 1.3.12.3.0 View file →
@@ -5,8 +5,10 @@
5 5 /**
6 6 * Forms class.
7 7 *
8 8 * @since 1.1.0
9 + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
10 + * @SuppressWarnings(PHPMD.NPathComplexity)
9 11 */
10 12 class Sellkit_Admin_Posts {
11 13
12 14 /**
@@ -25,8 +27,16 @@
25 27 */
26 28 public $sub_action = '';
27 29
28 30 /**
31 + * Page.
32 + *
33 + * @since 1.7.4
34 + * @var string
35 + */
36 + public $page;
37 +
38 + /**
29 39 * Get a class instance.
30 40 *
31 41 * @since 1.1.0
32 42 *
@@ -78,8 +88,9 @@
78 88 public function get_post() {
79 89 check_ajax_referer( 'sellkit', 'nonce' );
80 90
81 91 $post_id = sellkit_htmlspecialchars( INPUT_GET, 'post_id' );
92 + $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
82 93
83 94 $post_data = get_post_meta( $post_id );
84 95
85 96 // Get post meta (without key) returns array by default, Now converts them to singles.
@@ -98,16 +109,168 @@
98 109 if ( ! empty( $post_data['sellkit_steps'] ) ) {
99 110 $post_data['sellkit_steps'] = unserialize( $post_data['sellkit_steps'] ); // phpcs:ignore WordPress.PHP
100 111 }
101 112
113 + if ( ! empty( $post_data['nodes'] ) ) {
114 + delete_post_meta( $post_id, 'sellkit_steps' );
115 + unset( $post_data['sellkit_steps'] );
116 +
117 + $new_node = $this->check_product_status( $post_data['nodes'] );
118 +
119 + $post_data['nodes'] = $new_node;
120 + }
121 +
122 + $post_data['data_is_converted'] = false;
123 +
124 + if ( empty( $post_data['nodes'] ) && ! empty( $post_data['sellkit_steps'] ) ) {
125 + $nodes = self::convert_steps_to_nodes( $post_data['sellkit_steps'] );
126 +
127 + update_post_meta( $post_id, 'nodes', $nodes );
128 + delete_post_meta( $post_id, 'sellkit_steps' );
129 + unset( $post_data['sellkit_steps'] );
130 +
131 + $post_data['nodes'] = $nodes;
132 + $post_data['data_is_converted'] = true;
133 + }
134 +
102 135 $post_data['sellkit_post_title'] = html_entity_decode( get_the_title( $post_id ) );
103 136 $post_data['sellkit_post_slug'] = get_post_field( 'post_name', $post_id );
104 137 $post_data['sellkit_post_status'] = get_post_status( $post_id );
105 138
139 + // Unset sales-page when user exploring global checkout page.
140 + if ( 'checkout' === $page && ! empty( $post_data['nodes'] ) ) {
141 + foreach ( $post_data['nodes'] as $key => $step ) {
142 + if ( is_array( $step['type'] ) && 'sales-page' === $step['type']['key'] ) {
143 + unset( $post_data['nodes']->$key );
144 + }
145 +
146 + if ( is_object( $step['type'] ) && 'sales-page' === $step['type']->key ) {
147 + unset( $post_data['nodes']->$key );
148 + }
149 + }
150 + }
151 +
106 152 wp_send_json_success( [ 'post_data' => $post_data ] );
107 153 }
108 154
109 155 /**
156 + * Converts steps to nodes.
157 + *
158 + * @since 1.5.0
159 + * @param array $steps Steps.
160 + */
161 + public static function convert_steps_to_nodes( $steps ) {
162 + $nodes = [];
163 + $final_steps = $steps;
164 +
165 + $first_key = array_key_first( $steps );
166 +
167 + if ( empty( $steps[ $first_key ]['targets'] ) ) {
168 + $final_steps = self::add_decision_node_before_upsells( $steps );
169 + }
170 +
171 + foreach ( $final_steps as $key => $step ) {
172 + $nodes[ $key ] = $step;
173 +
174 + if ( ! empty( $step['type']->key ) && 'decision' !== $step['type']->key ) {
175 + $nodes[ $key ]['targets'] = count( $final_steps ) > $key + 1 ? [ [ 'nodeId' => strval( $key + 1 ) ] ] : [];
176 + }
177 +
178 + if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key && count( $final_steps ) > $key + 1 ) {
179 + $nodes[ $key ]['targets'] = [
180 + [
181 + 'nodeId' => strval( $key + 1 )
182 + ],
183 + [
184 + 'nodeId' => strval( $key + 1 )
185 + ]
186 + ];
187 + }
188 +
189 + if ( ! empty( $step['type']->key ) && 'decision' === $step['type']->key ) {
190 + if ( is_object( $step['targets'][0] ) ) {
191 + $step['targets'][0] = (array) $step['targets'][0];
192 + }
193 +
194 + if ( is_object( $step['targets'][1] ) ) {
195 + $step['targets'][1] = (array) $step['targets'][1];
196 + }
197 +
198 + if ( empty( $final_steps[ $step['targets'][0]['nodeId'] ] ) ) {
199 + $nodes[ $key ]['targets'][0] = '';
200 + }
201 +
202 + if ( empty( $final_steps[ $step['targets'][1]['nodeId'] ] ) ) {
203 + $nodes[ $key ]['targets'][1] = '';
204 + }
205 + }
206 +
207 + $nodes[ $key ]['jsx'] = $step['title'];
208 + }
209 +
210 + return (object) $nodes;
211 + }
212 +
213 + /**
214 + * Adds decision node before upsells.
215 + *
216 + * @since 1.5.0
217 + * @param array $steps Steps.
218 + */
219 + public static function add_decision_node_before_upsells( $steps ) {
220 + $final_steps = [];
221 + $upsell_num = 0;
222 +
223 + foreach ( $steps as $key => $step ) {
224 + $step['type'] = (object) $step['type'];
225 + $step['data'] = ! empty( $step['data'] ) ? (object) $step['data'] : null;
226 +
227 + if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key ) {
228 + $new_node_id = wp_insert_post( [
229 + 'post_type' => Sellkit_Admin_Steps::SELLKIT_STEP_POST_TYPE,
230 + 'post_title' => __( 'Decision', 'sellkit' ),
231 + 'post_name' => sanitize_title( __( 'Decision', 'sellkit' ) ),
232 + 'post_status' => 'publish',
233 + ] );
234 +
235 + $type_object = new stdClass();
236 + $type_object->title = esc_html__( 'Decision', 'sellkit' );
237 + $type_object->key = 'decision';
238 +
239 + $decision_node = [
240 + 'title' => esc_html__( 'Decision', 'sellkit' ),
241 + 'type' => $type_object,
242 + 'current_target_index' => 0,
243 + 'page_id' => $new_node_id,
244 + 'slug' => get_post_field( 'post_name', $new_node_id ),
245 + 'funnel_id' => $step['funnel_id'],
246 + 'targets' => [
247 + [
248 + 'nodeId' => strval( $key + 1 + $upsell_num )
249 + ],
250 + [
251 + 'nodeId' => strval( $key + 2 + $upsell_num )
252 + ]
253 + ],
254 + 'data' => [
255 + 'conditions' => ! empty( $step['data']->conditions ) ? $step['data']->conditions : []
256 + ]
257 + ];
258 +
259 + update_post_meta( $new_node_id, 'step_data', $decision_node );
260 +
261 + $final_steps[] = $decision_node;
262 +
263 + $upsell_num++;
264 + }
265 +
266 + $final_steps[] = $step;
267 + }
268 +
269 + return $final_steps;
270 + }
271 +
272 + /**
110 273 * Save post.
111 274 *
112 275 * @since 1.1.0
113 276 */
@@ -117,8 +280,9 @@
117 280 $fields = sellkit_post( 'fields' );
118 281 $post_id = sellkit_htmlspecialchars( INPUT_POST, 'post_id' );
119 282 $post_type = sellkit_htmlspecialchars( INPUT_POST, 'post_type' );
120 283 $this->sub_action = sellkit_htmlspecialchars( INPUT_POST, 'sub_action' );
284 + $this->page = sellkit_htmlspecialchars( INPUT_POST, 'page' );
121 285
122 286 $sanitized_fields = $this->sanitize_fields( $fields );
123 287
124 288 $this->validate_fields( $sanitized_fields );
@@ -154,11 +318,15 @@
154 318 * @SuppressWarnings(PHPMD.NPathComplexity)
155 319 */
156 320 private function handle_save_post( $data, $post_type, $post_id = false ) {
157 321 $title = sanitize_text_field( $data['sellkit_post_title'] );
158 - $slug = sanitize_text_field( $data['sellkit_post_slug'] );
322 + $slug = ! empty( $data['sellkit_post_slug'] ) ? sanitize_text_field( $data['sellkit_post_slug'] ) : '';
159 323 $post_status = 'publish' === $data['sellkit_post_status'] ? 'publish' : 'draft';
160 324
325 + if ( isset( $data['sellkit_global_checkout_header_footer_templates'] ) && 'checkout' === $this->page ) {
326 + unset( $data['sellkit_global_checkout_header_footer_templates'] );
327 + }
328 +
161 329 $post_args = [
162 330 'post_title' => $title,
163 331 'post_name' => $slug ?: sanitize_title( $title ),
164 332 'post_type' => $post_type,
@@ -186,9 +354,9 @@
186 354 }
187 355
188 356 update_post_meta( $new_post_id, $name, $value );
189 357
190 - if ( 'sellkit_steps' === $name ) {
358 + if ( 'sellkit_steps' === $name || 'nodes' === $name ) {
191 359 do_action( 'sellkit_funnels_update_steps', $value, $new_post_id );
192 360 }
193 361 }
194 362
@@ -201,8 +369,16 @@
201 369 if ( empty( $data['sellkit_steps'] ) ) {
202 370 delete_post_meta( $new_post_id, 'sellkit_steps' );
203 371 }
204 372
373 + if ( empty( $data['nodes'] ) ) {
374 + delete_post_meta( $new_post_id, 'nodes' );
375 + }
376 +
377 + if ( 'checkout' === $this->page ) {
378 + update_option( 'sellkit_global_checkout_id', $new_post_id );
379 + }
380 +
205 381 return $new_post_id;
206 382 }
207 383
208 384 /**
@@ -257,8 +433,59 @@
257 433 return;
258 434 }
259 435
260 436 wp_send_json_error( $errors );
437 + }
438 +
439 + /**
440 + * Check product status
441 + *
442 + * @param mixed $nodes List of node data.
443 + * @since 1.7.9
444 + * @return array
445 + */
446 + public function check_product_status( $nodes ) {
447 + $nodes = (object) unserialize( $nodes ); // phpcs:ignore WordPress.PHP
448 + $new_node = [];
449 +
450 + if ( ! class_exists( 'WooCommerce' ) ) {
451 + return $new_node;
452 + }
453 +
454 + foreach ( $nodes as $index => $node ) {
455 + if ( ! empty( $node['page_id'] ) ) {
456 + $node['link'] = get_the_permalink( $node['page_id'] );
457 + }
458 +
459 + if ( 'checkout' !== $node['type']['key'] ) {
460 + $new_node[ $index ] = $node;
461 + continue;
462 + }
463 +
464 + if ( ! empty( $node['data']['products'] ) && ! empty( $node['data']['products']['list'] ) ) {
465 + foreach ( $node['data']['products']['list'] as $key => $product ) {
466 + $product_obj = wc_get_product( $key );
467 +
468 + if ( empty( $product_obj ) ) {
469 + unset( $node['data']['products']['list'][ $key ] );
470 + }
471 +
472 + $data = ! empty( $product_obj ) ? $product_obj->get_data() : [];
473 +
474 + if ( ! empty( $data['status'] ) && 'trash' === $data['status'] ) {
475 + unset( $node['data']['products']['list'][ $key ] );
476 + }
477 + }
478 + }
479 +
480 + $new_node[ $index ] = $node;
481 + }
482 +
483 + if ( empty( $new_node ) ) {
484 + return $node;
485 + }
486 +
487 + return $new_node;
261 488 }
262 489 }
263 490
264 491 Sellkit_Admin_Posts::get_instance();