PluginProbe
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster / 1.7.5
SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster v1.7.5
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 / admin / class-posts.php

class-posts.php in SellKit – Funnel builder and checkout optimizer for WooCommerce to sell more, faster 1.7.5, at includes/admin/class-posts.php

429 lines 10.6 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 /**
6 * Forms class.
7 *
8 * @since 1.1.0
9 * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
10 * @SuppressWarnings(PHPMD.NPathComplexity)
11 */
12 class Sellkit_Admin_Posts {
13
14 /**
15 * Class instance.
16 *
17 * @since 1.1.0
18 * @var Sellkit_Admin_Posts
19 */
20 private static $instance = null;
21
22 /**
23 * Sub Action.
24 *
25 * @since 1.1.0
26 * @var string
27 */
28 public $sub_action = '';
29
30 /**
31 * Page.
32 *
33 * @since 1.7.4
34 * @var string
35 */
36 public $page;
37
38 /**
39 * Get a class instance.
40 *
41 * @since 1.1.0
42 *
43 * @return Sellkit_Admin_Posts Class instance.
44 */
45 public static function get_instance() {
46 if ( null === self::$instance ) {
47 self::$instance = new self();
48 }
49
50 return self::$instance;
51 }
52
53 /**
54 * Class constructor.
55 *
56 * @since 1.1.0
57 */
58 public function __construct() {
59 add_action( 'wp_ajax_sellkit_post_save', [ $this, 'save_post' ] );
60 add_action( 'wp_ajax_sellkit_post_get', [ $this, 'get_post' ] );
61 add_action( 'wp_ajax_sellkit_post_remove', [ $this, 'remove_post' ] );
62 }
63
64 /**
65 * Remove post.
66 *
67 * @since 1.1.0
68 */
69 public function remove_post() {
70 check_ajax_referer( 'sellkit', 'nonce' );
71
72 $post_id = sellkit_htmlspecialchars( INPUT_POST, 'post_id' );
73
74 $result = wp_delete_post( $post_id );
75
76 if ( empty( $result ) ) {
77 wp_send_json_error( __( 'something went wrong', 'sellkit' ) );
78 }
79
80 wp_send_json_success( __( 'The process has been completed.', 'sellkit' ) );
81 }
82
83 /**
84 * Get post data.
85 *
86 * @since 1.1.0
87 */
88 public function get_post() {
89 check_ajax_referer( 'sellkit', 'nonce' );
90
91 $post_id = sellkit_htmlspecialchars( INPUT_GET, 'post_id' );
92 $page = sellkit_htmlspecialchars( INPUT_GET, 'page' );
93
94 $post_data = get_post_meta( $post_id );
95
96 // Get post meta (without key) returns array by default, Now converts them to singles.
97 $post_data = array_map( function( $meta ) {
98 return $meta[0];
99 }, $post_data );
100
101 if ( ! empty( $post_data['conditions'] ) ) {
102 $post_data['conditions'] = unserialize( $post_data['conditions'] ); // phpcs:ignore WordPress.PHP
103 }
104
105 if ( ! empty( $post_data['filters'] ) ) {
106 $post_data['filters'] = unserialize( $post_data['filters'] ); // phpcs:ignore WordPress.PHP
107 }
108
109 if ( ! empty( $post_data['sellkit_steps'] ) ) {
110 $post_data['sellkit_steps'] = unserialize( $post_data['sellkit_steps'] ); // phpcs:ignore WordPress.PHP
111 }
112
113 if ( ! empty( $post_data['nodes'] ) ) {
114 delete_post_meta( $post_id, 'sellkit_steps' );
115 unset( $post_data['sellkit_steps'] );
116
117 $post_data['nodes'] = (object) unserialize( $post_data['nodes'] ); // phpcs:ignore WordPress.PHP
118 }
119
120 $post_data['data_is_converted'] = false;
121
122 if ( empty( $post_data['nodes'] ) && ! empty( $post_data['sellkit_steps'] ) ) {
123 $nodes = self::convert_steps_to_nodes( $post_data['sellkit_steps'] );
124
125 update_post_meta( $post_id, 'nodes', $nodes );
126 delete_post_meta( $post_id, 'sellkit_steps' );
127 unset( $post_data['sellkit_steps'] );
128
129 $post_data['nodes'] = $nodes;
130 $post_data['data_is_converted'] = true;
131 }
132
133 $post_data['sellkit_post_title'] = html_entity_decode( get_the_title( $post_id ) );
134 $post_data['sellkit_post_slug'] = get_post_field( 'post_name', $post_id );
135 $post_data['sellkit_post_status'] = get_post_status( $post_id );
136
137 // Unset sales-page when user exploring global checkout page.
138 if ( 'checkout' === $page ) {
139 foreach ( $post_data['nodes'] as $key => $step ) {
140 if ( 'sales-page' === $step['type']->key ) {
141 unset( $post_data['nodes']->$key );
142 }
143 }
144 }
145
146 wp_send_json_success( [ 'post_data' => $post_data ] );
147 }
148
149 /**
150 * Converts steps to nodes.
151 *
152 * @since 1.5.0
153 * @param array $steps Steps.
154 */
155 public static function convert_steps_to_nodes( $steps ) {
156 $nodes = [];
157 $final_steps = $steps;
158
159 if ( empty( $steps[0]['targets'] ) ) {
160 $final_steps = self::add_decision_node_before_upsells( $steps );
161 }
162
163 foreach ( $final_steps as $key => $step ) {
164 $nodes[ $key ] = $step;
165
166 if ( ! empty( $step['type']->key ) && 'decision' !== $step['type']->key ) {
167 $nodes[ $key ]['targets'] = count( $final_steps ) > $key + 1 ? [ [ 'nodeId' => strval( $key + 1 ) ] ] : [];
168 }
169
170 if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key && count( $final_steps ) > $key + 1 ) {
171 $nodes[ $key ]['targets'] = [
172 [
173 'nodeId' => strval( $key + 1 )
174 ],
175 [
176 'nodeId' => strval( $key + 1 )
177 ]
178 ];
179 }
180
181 if ( ! empty( $step['type']->key ) && 'decision' === $step['type']->key ) {
182 if ( is_object( $step['targets'][0] ) ) {
183 $step['targets'][0] = (array) $step['targets'][0];
184 }
185
186 if ( is_object( $step['targets'][1] ) ) {
187 $step['targets'][1] = (array) $step['targets'][1];
188 }
189
190 if ( empty( $final_steps[ $step['targets'][0]['nodeId'] ] ) ) {
191 $nodes[ $key ]['targets'][0] = '';
192 }
193
194 if ( empty( $final_steps[ $step['targets'][1]['nodeId'] ] ) ) {
195 $nodes[ $key ]['targets'][1] = '';
196 }
197 }
198
199 $nodes[ $key ]['jsx'] = $step['title'];
200 }
201
202 return (object) $nodes;
203 }
204
205 /**
206 * Adds decision node before upsells.
207 *
208 * @since 1.5.0
209 * @param array $steps Steps.
210 */
211 public static function add_decision_node_before_upsells( $steps ) {
212 $final_steps = [];
213 $upsell_num = 0;
214
215 foreach ( $steps as $key => $step ) {
216 $step['type'] = (object) $step['type'];
217 $step['data'] = (object) $step['data'];
218
219 if ( ! empty( $step['type']->key ) && 'upsell' === $step['type']->key ) {
220 $new_node_id = wp_insert_post( [
221 'post_type' => Sellkit_Admin_Steps::SELLKIT_STEP_POST_TYPE,
222 'post_title' => __( 'Decision', 'sellkit' ),
223 'post_name' => sanitize_title( __( 'Decision', 'sellkit' ) ),
224 'post_status' => 'publish',
225 ] );
226
227 $type_object = new stdClass();
228 $type_object->title = esc_html__( 'Decision', 'sellkit' );
229 $type_object->key = 'decision';
230
231 $decision_node = [
232 'title' => esc_html__( 'Decision', 'sellkit' ),
233 'type' => $type_object,
234 'current_target_index' => 0,
235 'page_id' => $new_node_id,
236 'slug' => get_post_field( 'post_name', $new_node_id ),
237 'funnel_id' => $step['funnel_id'],
238 'targets' => [
239 [
240 'nodeId' => strval( $key + 1 + $upsell_num )
241 ],
242 [
243 'nodeId' => strval( $key + 2 + $upsell_num )
244 ]
245 ],
246 'data' => [
247 'conditions' => ! empty( $step['data']->conditions ) ? $step['data']->conditions : []
248 ]
249 ];
250
251 update_post_meta( $new_node_id, 'step_data', $decision_node );
252
253 $final_steps[] = $decision_node;
254
255 $upsell_num++;
256 }
257
258 $final_steps[] = $step;
259 }
260
261 return $final_steps;
262 }
263
264 /**
265 * Save post.
266 *
267 * @since 1.1.0
268 */
269 public function save_post() {
270 check_ajax_referer( 'sellkit', 'nonce' );
271
272 $fields = sellkit_post( 'fields' );
273 $post_id = sellkit_htmlspecialchars( INPUT_POST, 'post_id' );
274 $post_type = sellkit_htmlspecialchars( INPUT_POST, 'post_type' );
275 $this->sub_action = sellkit_htmlspecialchars( INPUT_POST, 'sub_action' );
276 $this->page = sellkit_htmlspecialchars( INPUT_POST, 'page' );
277
278 $sanitized_fields = $this->sanitize_fields( $fields );
279
280 $this->validate_fields( $sanitized_fields );
281
282 $target_post_id = $this->handle_save_post( $sanitized_fields, $post_type, $post_id );
283
284 if ( empty( $target_post_id ) ) {
285 wp_send_json_error( [ __( 'something went wrong', 'sellkit' ) ] );
286 }
287
288 if ( $post_id ) {
289 wp_send_json_success( [
290 'post_id' => $post_id,
291 'message' => __( 'The update process has been completed.', 'sellkit' ),
292 ] );
293 }
294
295 wp_send_json_success( [
296 'post_id' => $target_post_id,
297 'message' => __( 'The creation process has been completed.', 'sellkit' ),
298 ] );
299 }
300
301 /**
302 * Update or add new post.
303 *
304 * @param array $data All data.
305 * @param string $post_type The post type.
306 * @param bool $post_id The post Id.
307 * @return bool|integer
308 *
309 * @since 1.1.0
310 * @SuppressWarnings(PHPMD.NPathComplexity)
311 */
312 private function handle_save_post( $data, $post_type, $post_id = false ) {
313 $title = sanitize_text_field( $data['sellkit_post_title'] );
314 $slug = ! empty( $data['sellkit_post_slug'] ) ? sanitize_text_field( $data['sellkit_post_slug'] ) : '';
315 $post_status = 'publish' === $data['sellkit_post_status'] ? 'publish' : 'draft';
316
317 $post_args = [
318 'post_title' => $title,
319 'post_name' => $slug ?: sanitize_title( $title ),
320 'post_type' => $post_type,
321 'post_status' => $post_status,
322 ];
323
324 if ( ! $post_id ) {
325 $new_post_id = wp_insert_post( $post_args );
326 }
327
328 if ( $post_id ) {
329 $post_args = array_merge( $post_args, [ 'ID' => $post_id ] );
330 $new_post_id = wp_update_post( $post_args );
331
332 do_action( "sellkit_posts_after_saving_$post_type", $post_id );
333 }
334
335 if ( empty( $new_post_id ) || is_wp_error( $new_post_id ) ) {
336 return false;
337 }
338
339 foreach ( $data as $name => $value ) {
340 if ( 'sellkit_post_title' === $name || 'sellkit_post_status' === $name ) {
341 continue;
342 }
343
344 update_post_meta( $new_post_id, $name, $value );
345
346 if ( 'sellkit_steps' === $name || 'nodes' === $name ) {
347 do_action( 'sellkit_funnels_update_steps', $value, $new_post_id );
348 }
349 }
350
351 if ( empty( $data['conditions'] ) ) {
352 delete_post_meta( $new_post_id, 'conditions' );
353 }
354
355 do_action( "sellkit_funnels_after_$this->sub_action", $post_id );
356
357 if ( empty( $data['sellkit_steps'] ) ) {
358 delete_post_meta( $new_post_id, 'sellkit_steps' );
359 }
360
361 if ( empty( $data['nodes'] ) ) {
362 delete_post_meta( $new_post_id, 'nodes' );
363 }
364
365 if ( 'checkout' === $this->page ) {
366 update_option( 'sellkit_global_checkout_id', $new_post_id );
367 }
368
369 return $new_post_id;
370 }
371
372 /**
373 * Sanitize fields.
374 *
375 * @param array $fields Fields.
376 *
377 * @return array
378 *
379 * @since 1.1.0
380 */
381 private function sanitize_fields( $fields ) {
382 $new_fields = [];
383
384 foreach ( $fields as $key => $field ) {
385 if ( is_array( $fields[ $key ] ) ) {
386 $new_fields[ $key ] = $this->sanitize_fields( $fields[ $key ] );
387 }
388
389 $field_value = sanitize_meta( $key, $field, 'post' );
390
391 if ( ! is_array( $fields[ $key ] ) ) {
392 $new_fields[ $key ] = $field_value;
393 }
394 }
395
396 if ( ! empty( $new_fields['conditions'] ) ) {
397 $new_fields['conditions'] = sellkit_condition_row_sanitization( $new_fields['conditions'] );
398 }
399
400 if ( ! empty( $new_fields['filters'] ) ) {
401 $new_fields['filters'] = sellkit_filter_row_sanitization( $new_fields['filters'] );
402 }
403
404 return $new_fields;
405 }
406
407 /**
408 * Validate fields.
409 *
410 * @param array $fields Fields.
411 *
412 * @since 1.1.0
413 */
414 public function validate_fields( $fields ) {
415 $errors = [];
416 if ( empty( $fields['sellkit_post_title'] ) ) {
417 $errors[] = __( 'Post title should not be empty.', 'sellkit' );
418 }
419
420 if ( empty( $errors ) ) {
421 return;
422 }
423
424 wp_send_json_error( $errors );
425 }
426 }
427
428 Sellkit_Admin_Posts::get_instance();
429