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 +123 -4 1.7.42.7.0 View file →
@@ -10,8 +10,9 @@
10 10 * List Table component class.
11 11 *
12 12 * @since 1.1.0
13 13 * @SuppressWarnings(PHPMD.UnusedPrivateMethod)
14 + * @SuppressWarnings(PHPMD.ExcessiveClassComplexity)
14 15 */
15 16 class Sellkit_Admin_List_Table {
16 17
17 18 /**
@@ -60,8 +61,12 @@
60 61 $paged = filter_input( INPUT_POST, 'paged', FILTER_SANITIZE_NUMBER_INT );
61 62 $posts_per_page = filter_input( INPUT_POST, 'posts_per_page', FILTER_SANITIZE_NUMBER_INT );
62 63 $search_args = filter_input( INPUT_POST, 'args', FILTER_DEFAULT, FILTER_FORCE_ARRAY );
63 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 + }
64 69
65 70 /**
66 71 * Filter List Table query arguments.
67 72 *
@@ -82,13 +87,22 @@
82 87 $args[ $search_arg['param'] ] = $search_arg['value'];
83 88 }
84 89 }
85 90
86 - if ( 'checkout' !== $page ) {
87 - $global_checkout_id = get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 );
88 - $args['post__not_in'] = [ $global_checkout_id ];
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;
89 95 }
90 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 +
91 105 // Query.
92 106 $query = new \WP_Query( $args );
93 107
94 108 /**
@@ -98,8 +112,9 @@
98 112 *
99 113 * @param array $args The taxonomy arguments.
100 114 */
101 115 $posts = apply_filters( "sellkit_list_table_{$post_type}_posts", $query->posts );
116 + $posts = $this->prepare_posts_for_list_table( $posts );
102 117
103 118 /**
104 119 * Filter List Table columns.
105 120 *
@@ -111,17 +126,109 @@
111 126 'labels' => [],
112 127 'values' => [],
113 128 ], $posts );
114 129
130 + $list_counts = $this->get_list_status_counts( $post_type, $page );
131 +
115 132 // Send response.
116 133 wp_send_json_success( [
117 134 'posts' => $posts,
118 135 'max_num_pages' => $query->max_num_pages,
119 136 'columns' => $columns,
137 + 'list_counts' => $list_counts,
120 138 ] );
121 139 }
122 140
123 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 + /**
124 231 * Handle post actions.
125 232 *
126 233 * @since 1.1.0
127 234 */
@@ -131,9 +238,9 @@
131 238 // Sanitize.
132 239 $post = filter_input( INPUT_POST, 'post', FILTER_DEFAULT, FILTER_FORCE_ARRAY );
133 240 $sub_action = sellkit_htmlspecialchars( INPUT_POST, 'sub_action' );
134 241
135 - if ( count( $post ) < 3 ) {
242 + if ( is_array( $post ) && count( $post ) < 3 ) {
136 243 $post = (array) get_post( $post['ID'] );
137 244 }
138 245
139 246 call_user_func( [ $this, "handle_post_{$sub_action}" ], $post );
@@ -417,9 +524,15 @@
417 524 if ( empty( $posts ) ) {
418 525 wp_send_json_error();
419 526 }
420 527
528 + $global_checkout_id = intval( get_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, 0 ) );
529 +
421 530 foreach ( $posts as $post ) {
531 + if ( $post->ID === $global_checkout_id ) {
532 + continue;
533 + }
534 +
422 535 $post = (array) $post;
423 536
424 537 $data['data'][] = $this->export_single_funnel( $post );
425 538 }
@@ -436,8 +549,12 @@
436 549 $json = filter_input( INPUT_POST, 'funnel', FILTER_DEFAULT );
437 550 $page = filter_input( INPUT_POST, 'page', FILTER_SANITIZE_FULL_SPECIAL_CHARS );
438 551 $data = json_decode( $json );
439 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 +
440 557 $ajax_handler = new Ajax_Handler();
441 558
442 559 if ( 'single' === $data->type ) {
443 560 $funnel_data = $data->data->funnel;
@@ -455,8 +572,10 @@
455 572
456 573 if ( 'checkout' === $page && (int) $funnel_id > 0 ) {
457 574 update_option( Checkout::SELLKIT_GLOBAL_CHECKOUT_OPTION, $funnel_id );
458 575 }
576 +
577 + wp_send_json_success();
459 578 }
460 579 }
461 580
462 581 Sellkit_Admin_List_Table::get_instance();