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 +137 -2 1.7.22.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 /**
@@ -406,9 +524,15 @@
406 524 if ( empty( $posts ) ) {
407 525 wp_send_json_error();
408 526 }
409 527
528 + $global_checkout_id = intval( get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 ) );
529 +
410 530 foreach ( $posts as $post ) {
531 + if ( $post->ID === $global_checkout_id ) {
532 + continue;
533 + }
534 +
411 535 $post = (array) $post;
412 536
413 537 $data['data'][] = $this->export_single_funnel( $post );
414 538 }
@@ -422,16 +546,21 @@
422 546 * @since 1.5.0
423 547 */
424 548 private function handle_post_import_funnel() {
425 549 $json = filter_input( INPUT_POST, 'funnel', FILTER_DEFAULT );
550 + $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
426 551 $data = json_decode( $json );
427 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 +
428 557 $ajax_handler = new Ajax_Handler();
429 558
430 559 if ( 'single' === $data->type ) {
431 560 $funnel_data = $data->data->funnel;
432 561 $steps_data = $data->data->step;
433 - $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
562 + $funnel_id = $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
434 563 }
435 564
436 565 if ( 'multi' === $data->type ) {
437 566 foreach ( $data->data as $item ) {
@@ -436,11 +565,17 @@
436 565 if ( 'multi' === $data->type ) {
437 566 foreach ( $data->data as $item ) {
438 567 $funnel_data = $item->funnel;
439 568 $steps_data = $item->step;
440 - $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
569 + $funnel_id = $ajax_handler->import_funnel_by_data( $funnel_data, $steps_data );
441 570 }
442 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();
443 578 }
444 579 }
445 580
446 581 Sellkit_Admin_List_Table::get_instance();