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/components/class-list-table.php +141 -2 1.6.82.7.0 View file →
@@ -3,8 +3,9 @@
3 3 defined( 'ABSPATH' ) || die();
4 4
5 5 use Elementor\Plugin;
6 6 use Sellkit\Admin\Funnel\Importer\Ajax_Handler;
7 +use Sellkit\Global_Checkout\Checkout;
7 8
8 9 /**
9 10 * List Table component class.
10 11 *
@@ -9,8 +10,9 @@
9 10 * List Table component class.
10 11 *
11 12 * @since 1.1.0
12 13 * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
14 + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
13 15 */
14 16 class Sellkit_Admin_List_Table {
15 17
16 18 /**
@@ -58,8 +60,13 @@
58 60 $post_type = sellkit_htmlspecialchars( INPUT_POST, 'post_type' );
59 61 $paged = filter_input( INPUT_POST, 'paged', FILTER_SANITIZE_NUMBER_INT );
60 62 $posts_per_page = filter_input( INPUT_POST, 'posts_per_page', FILTER_SANITIZE_NUMBER_INT );
61 63 $search_args = filter_input( INPUT_POST, 'args', FILTER_DEFAULT, FILTER_FORCE_ARRAY );
64 + $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
65 + $list_status = isset( $_POST['list_status'] ) ? sanitize_text_field( wp_unslash( $_POST['list_status'] ) ) : 'all';
66 + if ( ! in_array( $list_status, [ 'all', 'publish', 'draft' ], true ) ) {
67 + $list_status = 'all';
68 + }
62 69
63 70 /**
64 71 * Filter List Table query arguments.
65 72 *
@@ -80,8 +87,22 @@
80 87 $args[ $search_arg['param'] ] = $search_arg['value'];
81 88 }
82 89 }
83 90
91 + $not_in = $this->get_list_table_post__not_in( $post_type, $page );
92 + if ( ! empty( $not_in ) ) {
93 + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in -- Exclude global checkout funnel from list.
94 + $args['post__not_in'] = $not_in;
95 + }
96 +
97 + if ( 'publish' === $list_status ) {
98 + $args['post_status'] = 'publish';
99 + } elseif ( 'draft' === $list_status ) {
100 + $args['post_status'] = 'draft';
101 + } else {
102 + $args['post_status'] = [ 'publish', 'draft', 'pending', 'private', 'future' ];
103 + }
104 +
84 105 // Query.
85 106 $query = new \WP_Query( $args );
86 107
87 108 /**
@@ -91,8 +112,9 @@
91 112 *
92 113 * @param array $args The taxonomy arguments.
93 114 */
94 115 $posts = apply_filters( "sellkit_list_table_{$post_type}_posts", $query->posts );
116 + $posts = $this->prepare_posts_for_list_table( $posts );
95 117
96 118 /**
97 119 * Filter List Table columns.
98 120 *
@@ -104,17 +126,109 @@
104 126 'labels' => [],
105 127 'values' => [],
106 128 ], $posts );
107 129
130 + $list_counts = $this->get_list_status_counts( $post_type, $page );
131 +
108 132 // Send response.
109 133 wp_send_json_success( [
110 134 'posts' => $posts,
111 135 'max_num_pages' => $query->max_num_pages,
112 136 'columns' => $columns,
137 + 'list_counts' => $list_counts,
113 138 ] );
114 139 }
115 140
116 141 /**
142 + * Post IDs excluded from list queries (e.g. global checkout funnel).
143 + *
144 + * @since 2.4.0
145 + *
146 + * @param string $post_type Post type.
147 + * @param string $page Admin page slug context.
148 + * @return int[]
149 + */
150 + private function get_list_table_post__not_in( $post_type, $page ) {
151 + if ( 'sellkit-funnels' === $post_type && 'checkout' !== $page ) {
152 + $global_checkout_id = (int) get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 );
153 + if ( $global_checkout_id > 0 ) {
154 + return [ $global_checkout_id ];
155 + }
156 + }
157 + return [];
158 + }
159 +
160 + /**
161 + * Counts for All / Active / Inactive list filters (respects post__not_in).
162 + *
163 + * @since 2.4.0
164 + *
165 + * @param string $post_type Post type.
166 + * @param string $page Admin page slug context.
167 + * @return array{all:int,publish:int,draft:int}
168 + */
169 + private function get_list_status_counts( $post_type, $page ) {
170 + $not_in = $this->get_list_table_post__not_in( $post_type, $page );
171 + $base = [
172 + 'post_type' => $post_type,
173 + 'posts_per_page' => -1,
174 + 'fields' => 'ids',
175 + 'no_found_rows' => false,
176 + ];
177 + if ( ! empty( $not_in ) ) {
178 + // phpcs:ignore WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_post__not_in
179 + $base['post__not_in'] = $not_in;
180 + }
181 +
182 + $statuses_all = [ 'publish', 'draft', 'pending', 'private', 'future' ];
183 + $q_all = new \WP_Query( array_merge( $base, [ 'post_status' => $statuses_all ] ) );
184 + $q_pub = new \WP_Query( array_merge( $base, [ 'post_status' => 'publish' ] ) );
185 + $q_dra = new \WP_Query( array_merge( $base, [ 'post_status' => 'draft' ] ) );
186 +
187 + return [
188 + 'all' => (int) $q_all->found_posts,
189 + 'publish' => (int) $q_pub->found_posts,
190 + 'draft' => (int) $q_dra->found_posts,
191 + ];
192 + }
193 +
194 + /**
195 + * Add formatted published / modified dates for list table rows (JSON).
196 + *
197 + * @since 2.4.0
198 + *
199 + * @param array $posts Posts from WP_Query.
200 + * @return array
201 + */
202 + private function prepare_posts_for_list_table( $posts ) {
203 + if ( empty( $posts ) || ! is_array( $posts ) ) {
204 + return $posts;
205 + }
206 +
207 + $date_time_format = get_option( 'date_format' ) . ' ' . get_option( 'time_format' );
208 +
209 + foreach ( $posts as $key => $post ) {
210 + if ( ! $post instanceof \WP_Post ) {
211 + continue;
212 + }
213 +
214 + $row = array_merge(
215 + $post->to_array(),
216 + [
217 + 'custom_date' => get_the_date( 'M d, Y', $post ),
218 + 'custom_date_with_time' => mysql2date( $date_time_format, $post->post_date ),
219 + 'custom_modified_date' => get_the_modified_date( 'M d, Y', $post ),
220 + 'custom_modified_date_with_time' => mysql2date( $date_time_format, $post->post_modified ),
221 + ]
222 + );
223 +
224 + $posts[ $key ] = (object) $row;
225 + }
226 +
227 + return $posts;
228 + }
229 +
230 + /**
117 231 * Handle post actions.
118 232 *
119 233 * @since 1.1.0
120 234 */
@@ -124,8 +238,12 @@
124 238 // Sanitize.
125 239 $post = filter_input( INPUT_POST, 'post', FILTER_DEFAULT, FILTER_FORCE_ARRAY );
126 240 $sub_action = sellkit_htmlspecialchars( INPUT_POST, 'sub_action' );
127 241
242 + if ( is_array( $post ) && count( $post ) < 3 ) {
243 + $post = (array) get_post( $post['ID'] );
244 + }
245 +
128 246 call_user_func( [ $this, "handle_post_{$sub_action}" ], $post );
129 247 }
130 248
131 249 /**
@@ -339,8 +457,12 @@
339 457 return $data;
340 458 }
341 459
342 460 foreach ( $data['funnel']['sellkit_steps'] as $step ) {
461 + if ( ! array_key_exists( 'page_id', $step ) ) {
462 + continue;
463 + }
464 +
343 465 $id = $step['page_id'];
344 466 $post = get_post( $id );
345 467 $export_data = get_post_meta( $id );
346 468
@@ -402,9 +524,15 @@
402 524 if ( empty( $posts ) ) {
403 525 wp_send_json_error();
404 526 }
405 527
528 + $global_checkout_id = intval( get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 ) );
529 +
406 530 foreach ( $posts as $post ) {
531 + if ( $post->ID === $global_checkout_id ) {
532 + continue;
533 + }
534 +
407 535 $post = (array) $post;
408 536
409 537 $data['data'][] = $this->export_single_funnel( $post );
410 538 }
@@ -418,16 +546,21 @@
418 546 * @since 1.5.0
419 547 */
420 548 private function handle_post_import_funnel() {
421 549 $json = filter_input( INPUT_POST, 'funnel', FILTER_DEFAULT );
550 + $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
422 551 $data = json_decode( $json );
423 552
553 + if ( 'multi' === $data->type && 'checkout' === $page ) {
554 + wp_send_json_error( esc_html__( 'You can not import multiple funnels to the global checkout.', 'sellkit' ) );
555 + }
556 +
424 557 $ajax_handler = new Ajax_Handler();
425 558
426 559 if ( 'single' === $data->type ) {
427 560 $funnel_data = $data->data->funnel;
428 561 $steps_data = $data->data->step;
429 - $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
562 + $funnel_id = $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
430 563 }
431 564
432 565 if ( 'multi' === $data->type ) {
433 566 foreach ( $data->data as $item ) {
@@ -432,11 +565,17 @@
432 565 if ( 'multi' === $data->type ) {
433 566 foreach ( $data->data as $item ) {
434 567 $funnel_data = $item->funnel;
435 568 $steps_data = $item->step;
436 - $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
569 + $funnel_id = $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
437 570 }
438 571 }
572 +
573 + if ( 'checkout' === $page && (int) $funnel_id > 0 ) {
574 + update_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, $funnel_id );
575 + }
576 +
577 + wp_send_json_success();
439 578 }
440 579 }
441 580
442 581 Sellkit_Admin_List_Table::get_instance();