PluginProbe
Button Generator – Easily Create Custom Buttons with Icons and Analytics / 3.2
Button Generator – Easily Create Custom Buttons with Icons and Analytics v3.2
trunk 1.1.1 2.0 2.1 2.2 2.3.2 2.3.3 2.3.4 2.3.5 2.3.6 2.3.7 2.3.8 2.3.9 3.0 3.0.1 3.0.2 3.0.3 3.1 3.1.1 3.1.2 3.1.3 3.2 3.2.1 3.2.2 3.2.3 All 28 releases
button-generation / classes / Admin / ListTable.php

ListTable.php in Button Generator – Easily Create Custom Buttons with Icons and Analytics 3.2, at classes/Admin/ListTable.php

383 lines 14.2 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Class ListTable
5 *
6 * @package WowPlugin
7 * @subpackage Admin
8 * @author Dmytro Lobov <dev@wow-company.com>, Wow-Company
9 * @copyright 2024 Dmytro Lobov
10 * @license GPL-2.0+
11 *
12 * @see https://developer.wordpress.org/reference/classes/wp_list_table/
13 */
14
15 namespace ButtonGenerator\Admin;
16
17 defined( 'ABSPATH' ) || exit;
18
19 use WP_List_Table;
20 use ButtonGenerator\WOWP_Plugin;
21
22 class ListTable extends WP_List_Table {
23
24 public int $per_page = 30;
25
26 public function __construct() {
27 // Set parent defaults
28 parent::__construct( array(
29 'ajax' => false,
30 ) );
31 $this->process_bulk_action();
32 }
33
34 public function column_default( $item, $column_name ) {
35 return $item[ $column_name ];
36 }
37
38 // phpcs:disable WordPress.Security.NonceVerification.Recommended
39 public function search_box( $text, $input_id ) {
40 $input_id .= '-search-input';
41 if ( ! empty( $_REQUEST['orderby'] ) ) {
42 $orderby = sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) );
43 echo '<input type="hidden" name="orderby" value="' . esc_attr( $orderby ) . '" />';
44 }
45 if ( ! empty( $_REQUEST['order'] ) ) {
46 $order = sanitize_text_field( wp_unslash( $_REQUEST['order'] ) );
47 echo '<input type="hidden" name="order" value="' . esc_attr( $order ) . '" />';
48 }
49 ?>
50 <p class="search-box">
51 <label class="screen-reader-text" for="<?php
52 echo esc_attr( $input_id ) ?>"><?php
53 echo esc_html( $text ); ?>
54 :</label>
55 <input type="search" id="<?php
56 echo esc_attr( $input_id ) ?>" name="s" value="<?php
57 _admin_search_query(); ?>"/>
58 <?php
59 submit_button( $text, 'button', false, false, array( 'ID' => 'search-submit' ) ); ?>
60 </p>
61 <?php
62 }
63 // phpcs:enable
64
65 public function column_title( $item ): string {
66 $title = ! empty( $item['title'] ) ? $item['title'] : __( 'Button', 'button-generation' ) . '#' . $item['ID'];
67 $param = DBManager::get_param_id( $item['ID'] );
68 $actions = [
69 'id' => 'ID: ' . $item['ID'],
70 'edit' => '<a href="' . esc_url( Link::edit( $item['ID'] ) ) . '">' . esc_html__( 'Edit',
71 'button-generation' ) . '</a>',
72 'duplicate' => '<a href="' . esc_url( Link::duplicate( $item['ID'] ) ) . '">' . esc_html__( 'Duplicate',
73 'button-generation' ) . '</a>',
74 'delete' => '<a href="' . esc_url( Link::remove( $item['ID'] ) ) . '" >' . esc_html__( 'Delete',
75 'button-generation' ) . '</a>',
76 'export' => '<a href="' . esc_url( Link::export( $item['ID'] ) ) . '" >' . esc_html__( 'Export',
77 'button-generation' ) . '</a>',
78 ];
79 if ( ! empty( $param['link'] ) ) {
80 $actions['view'] = '<a href="' . esc_url( $param['link'] ) . '" target="_blank">' . esc_html__( 'View',
81 'button-generation' ) . '</a>';
82 }
83
84
85 return $title . $this->row_actions( $actions );
86 }
87
88 public function prepare_items(): void {
89 $columns = $this->get_columns();
90 $hidden = $this->get_hidden_columns();
91 $sortable = $this->get_sortable_columns();
92 $data = $this->table_data();
93 $perPage = 30;
94 $currentPage = $this->get_pagenum();
95 if ( $data ) {
96 usort( $data, [ &$this, 'sort_data' ] );
97 $data = array_slice( $data, ( ( $currentPage - 1 ) * $perPage ), $perPage );
98 }
99 $totalItems = $this->list_count();
100 $this->_column_headers = [ $columns, $hidden, $sortable ];
101 $this->items = $data;
102 $this->set_pagination_args( [
103 'total_items' => $totalItems,
104 'per_page' => $perPage,
105 'total_pages' => ceil( $totalItems / $perPage ),
106 ] );
107 }
108
109 public function get_columns(): array {
110 return [
111 'cb' => '<input type="checkbox" />',
112 'title' => __( 'Title', 'button-generation' ),
113 'code' => __( 'Shortcode', 'button-generation' ),
114 'tag' => __( 'Tag', 'button-generation' ),
115 'mode' => __( 'Test mode',
116 'button-generation' ) . '<sup class="has-tooltip" data-tooltip="' . __( 'The item will only be displayed for administrators.',
117 'button-generation' ) . '">ℹ</sup>',
118 'status' => __( 'Status',
119 'button-generation' ) . '<sup class="has-tooltip" data-tooltip="' . __( 'Display item on the Frontend.',
120 'button-generation' ) . '">ℹ</sup>',
121 ];
122 }
123
124 public function get_hidden_columns(): array {
125 return [];
126 }
127
128 public function get_sortable_columns(): array {
129 return [
130 'ID' => [ 'ID', false ],
131 ];
132 }
133
134 private function table_data(): array {
135 $data = [];
136 $paged = $this->get_paged();
137 $offset = $this->per_page * ( $paged - 1 );
138
139 $result = $this->get_results();
140
141 $slug = WOWP_Plugin::SLUG;
142 $shortcode = WOWP_Plugin::SHORTCODE;
143
144 if ( empty( $result ) ) {
145 return $data;
146 }
147
148 $main_link = add_query_arg( [
149 'page' => $slug,
150 'tab' => 'settings',
151 'action' => 'update'
152 ], admin_url( 'admin.php' ) );
153 foreach ( $result as $key => $value ) {
154 $title = ! empty( $value->title ) ? $value->title : __( 'Button', 'button-generation' ) . ' #' . $value->id;
155 $tooltip_off = esc_attr__( 'Click to deactivate.', 'button-generation' );
156 $tooltip_on = esc_attr__( 'Click to activate.', 'button-generation' );
157 $status_off = '<a href="' . esc_url( Link::activate_url( $value->id ) ) . '" class="wpie-toogle is-off has-tooltip is-pointer" data-tooltip="' . esc_attr( $tooltip_on ) . '"><span></span></a>';
158 $status_on = '<a href="' . esc_url( Link::deactivate_url( $value->id ) ) . '" class="wpie-toogle is-on has-tooltip is-pointer" data-tooltip="' . esc_attr( $tooltip_off ) . '"><span></span></a>';
159 $status = ! empty( $value->status ) ? $status_off : $status_on;
160
161 $mode_tooltip_off = esc_attr__( 'Click to disable.', 'button-generation' );
162 $mode_tooltip_on = esc_attr__( 'Click to enable.', 'button-generation' );
163
164 $mode_off = '<a href="' . esc_url( Link::activate_mode( $value->id ) ) . '" class="wpie-toogle is-off has-tooltip is-pointer" data-tooltip="' . esc_attr( $mode_tooltip_on ) . '"><span></span></a>';
165 $mode_on = '<a href="' . esc_url( Link::deactivate_mode( $value->id ) ) . '" class="wpie-toogle is-on has-tooltip is-pointer" data-tooltip="' . esc_attr( $mode_tooltip_off ) . '"><span></span></a>';
166
167 $mode = empty( $value->mode ) ? $mode_off : $mode_on;
168
169 $tag = '';
170 if ( isset( $value->tag ) ) {
171 $tag_url = add_query_arg( [
172 'page' => WOWP_Plugin::SLUG,
173 'tag' => $value->tag
174 ], admin_url( 'admin.php' ) );
175 $tag = '<a href="' . esc_url( $tag_url ) . '">' . esc_attr( $value->tag ) . '</a>';
176 }
177
178 $link = add_query_arg( [ 'id' => $value->id ], $main_link );
179
180 $data[] = array(
181 'ID' => $value->id,
182 'title' => '<a href="' . esc_url( $link ) . '">' . esc_html( $title ) . '</a>',
183 'code' => '<div class="wpie-field">
184 <label class="wpie-field__label has-icon">
185 <span class="has-tooltip is-pointer on-right can-copy" data-tooltip="Copy"><span class="dashicons dashicons-shortcode is-pointer" ></span></span>
186 <input type="text" value="[' . esc_attr( $shortcode ) . ' id=\'' . absint( $value->id ) . '\']" readonly>
187 </label>
188 </div>',
189 'tag' => $tag,
190 'mode' => $mode,
191 'status' => $status,
192 );
193 }
194
195 return $data;
196 }
197
198 public function column_cb( $item ) {
199 return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', 'ID', $item['ID'] );
200 }
201
202 public function get_paged(): int {
203 return isset( $_GET['paged'] ) ? absint( $_GET['paged'] ) : 1; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
204 }
205
206 public function get_search() {
207 $verify = AdminActions::verify( WOWP_Plugin::PREFIX . '_list_action' );
208
209 if ( ! $verify ) {
210 return false;
211 }
212
213 // phpcs:disable WordPress.Security.NonceVerification.Missing -- Nonce verification is handled elsewhere.
214 return ! empty( $_POST['s'] ) ? urldecode( trim( sanitize_text_field( wp_unslash( $_POST['s'] ) ) ) ) : false;
215 // phpcs:enable
216 }
217
218 public function list_count(): int {
219 $result = $this->get_results();
220
221 if ( empty( $result ) ) {
222 return 0;
223 }
224 $count = count( $result );
225
226
227 return (int) $count;
228 }
229
230 public function get_results() {
231 global $wpdb;
232
233 $search = $this->get_search();
234
235 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
236 $tag_search = ( ! empty( $_REQUEST['tag'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['tag'] ) ) : '';
237 $tag_search = ( $tag_search === 'all' ) ? '' : $tag_search;
238
239
240 $result = '';
241
242 $table = esc_sql($wpdb->prefix . WOWP_Plugin::PREFIX);
243
244 // Table name is sanitized elsewhere.
245 if ( empty( $search ) ) {
246 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
247 $result = $wpdb->get_results( "SELECT * FROM {$table} ORDER BY id DESC" );
248 if ( ! empty( $tag_search ) ) {
249 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
250 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE tag=%s ORDER BY id DESC",
251 $tag_search ) );
252 }
253 } elseif ( trim( $search ) === 'UnTitle' ) {
254 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
255 $result = $wpdb->get_results( "SELECT * FROM {$table} WHERE title='' ORDER BY id DESC" );
256 if ( ! empty( $tag_search ) ) {
257 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
258 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE title='' AND tag=%s ORDER BY id DESC",
259 $tag_search ) );
260 }
261 } elseif ( is_numeric( $search ) ) {
262 if ( ! empty( $tag_search ) ) {
263 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
264 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE id=%d AND tag=%s ORDER BY id DESC",
265 absint( $search ), $tag_search ) );
266 } else {
267 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
268 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE id=%d ORDER BY id DESC",
269 absint( $search ) ) );
270 }
271 } else {
272 $wild = '%';
273 $find = sanitize_text_field( $search );
274 $like = $wild . $wpdb->esc_like( $find ) . $wild;
275 if ( ! empty( $tag_search ) ) {
276 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
277 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE title LIKE %s AND tag=%s ORDER BY id DESC",
278 $like, $tag_search ) );
279 } else {
280 // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching
281 $result = $wpdb->get_results( $wpdb->prepare( "SELECT * FROM {$table} WHERE title LIKE %s ORDER BY id DESC",
282 $like ) );
283 }
284 }
285
286 return $result;
287 }
288
289
290 public function get_bulk_actions(): array {
291 $actions = [
292 'delete' => __( 'Delate', 'button-generation' ),
293 'activate' => __( 'Activate', 'button-generation' ),
294 'deactivate' => __( 'Deactivate', 'button-generation' ),
295 'test_on' => __( 'Test mode ON', 'button-generation' ),
296 'test_off' => __( 'Test mode OFF', 'button-generation' ),
297 ];
298
299 return $actions;
300 }
301
302 public function process_bulk_action(): bool {
303
304 $verify = AdminActions::verify( WOWP_Plugin::PREFIX . '_list_action' );
305
306 if ( ! $verify ) {
307 return false;
308 }
309
310 // phpcs:ignore WordPress.Security.NonceVerification.Missing
311 $ids = isset( $_POST['ID'] ) ? ( map_deep( $_POST['ID'], 'absint' ) ) : false;
312 $action = $this->current_action();
313 if ( ! is_array( $ids ) ) {
314 $ids = [ $ids ];
315 }
316 if ( empty( $action ) ) {
317 return false;
318 }
319
320 foreach ( $ids as $id ) {
321 if ( 'delete' === $this->current_action() ) {
322 DBManager::delete( $id );
323 }
324 if ( 'activate' === $this->current_action() ) {
325 DBManager::update( [ 'status' => '' ], [ 'ID' => $id ], [ '%d' ] );
326 }
327 if ( 'deactivate' === $this->current_action() ) {
328 DBManager::update( [ 'status' => '1' ], [ 'ID' => $id ], [ '%d' ] );
329 }
330 if ( 'test_on' === $this->current_action() ) {
331 DBManager::update( [ 'mode' => '1' ], [ 'ID' => $id ], [ '%d' ] );
332 }
333 if ( 'test_off' === $this->current_action() ) {
334 DBManager::update( [ 'mode' => '' ], [ 'ID' => $id ], [ '%d' ] );
335 }
336 }
337
338 return true;
339 }
340
341 protected function extra_tablenav( $which ) {
342 if ( 'top' === $which ) {
343 $tags = DBManager::get_tags_from_table();
344
345 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
346 $tag_search = ( ! empty( $_REQUEST['tag'] ) ) ? sanitize_text_field( wp_unslash( $_REQUEST['tag'] ) ) : '';
347 $tag_search = ( $tag_search === 'all' ) ? '' : $tag_search;
348
349 echo '<div class="alignleft actions"><label for="filter-by-tag" class="screen-reader-text">' . esc_html__( 'Filter by tag',
350 'button-generation' ) . '</label>';
351 echo '<select name="tag" id="filter-by-tag">';
352 echo '<option value="all"' . selected( 'all', $tag_search, false ) . '>' . esc_html__( 'All',
353 'button-generation' ) . '</option>';
354
355 if ( ! empty( $tags ) ) {
356 foreach ( $tags as $tag ) {
357 if ( empty( $tag['tag'] ) ) {
358 continue;
359 }
360 echo '<option value="' . esc_attr( trim( $tag['tag'] ) ) . '"' . selected( $tag['tag'], $tag_search,
361 false ) . '>' . esc_html( $tag['tag'] ) . '</option>';
362 }
363 }
364 echo '</select>';
365 submit_button( __( 'Filter', 'button-generation' ), 'secondary', 'action', false );
366 echo '</div>';
367 }
368 }
369
370 private function sort_data( $a, $b ): int {
371 // If no sort, default to title
372 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
373 $orderby = ( ! empty( $_GET['orderby'] ) ) ? sanitize_text_field( wp_unslash( $_GET['orderby'] ) ) : 'ID';
374 // If no order, default to asc
375 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
376 $order = ( ! empty( $_GET['order'] ) ) ? sanitize_text_field( wp_unslash( $_GET['order'] ) ) : 'desc';
377 // Determine sort order
378 $result = strnatcmp( $a[ $orderby ], $b[ $orderby ] );
379
380 // Send final sort direction to usort
381 return ( $order === 'asc' ) ? $result : - $result;
382 }
383 }