PluginProbe
Float menu – awesome floating side menu / 7.2.5
Float menu – awesome floating side menu v7.2.5
7.2.5 trunk 2.1 2.2 3.0.1 3.1 3.2.2 3.3.1 3.5 3.5.1 3.5.2 3.5.3. 3.5.4 4.0 4.1 4.1.1 4.2 4.3 4.3.1 4.3.2 5.0 5.0.1 5.0.2 5.0.3 5.1 All 57 releases
float-menu / classes / Admin / ListTable.php

ListTable.php in Float menu – awesome floating side menu 7.2.5, at classes/Admin/ListTable.php

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