| @@ -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(); |