PluginProbe ʕ •ᴥ•ʔ
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI / 3.5.2
Everest Forms – Contact Form, Payment Form, Quiz, Survey & Custom Form Builder with AI v3.5.2
3.5.2 3.5.1 3.5.0 3.4.8 3.4.7 3.4.6 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.1.5.1 1.1.6 1.1.7 1.1.8 1.1.9 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.3.0 1.3.1 1.3.2 1.3.3 1.3.4 1.4.0 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.4.9 1.5.0 1.5.1 1.5.10 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 1.6.6.1 1.6.7 1.7.0 1.7.0.1 1.7.0.2 1.7.0.3 1.7.1 1.7.2 1.7.2.1 1.7.2.2 1.7.3 1.7.4 1.7.5 1.7.5.1 1.7.5.2 1.7.6 1.7.7 1.7.7.1 1.7.7.2 1.7.8 1.7.9 1.8.0 1.8.0.1 1.8.1 1.8.2 1.8.2.1 1.8.2.2 1.8.2.3 1.8.3 1.8.4 1.8.5 1.8.6 1.8.7 1.8.8 1.8.9 1.9.0 1.9.0.1 1.9.1 1.9.2 1.9.3 1.9.4 1.9.4.1 1.9.5 1.9.6 1.9.7 1.9.8 1.9.9 2.0.0 2.0.0.1 2.0.1 2.0.2 2.0.3 2.0.3.1 2.0.4 2.0.4.1 2.0.5 2.0.6 2.0.7 2.0.8 2.0.8.1 2.0.9 3.0.0 3.0.0.1 3.0.1 3.0.2 3.0.3 3.0.3.1 3.0.4 3.0.4.1 3.0.4.2 3.0.5 3.0.5.1 3.0.5.2 3.0.6 3.0.6.1 3.0.7.1 3.0.8 3.0.8.1 3.0.9 3.0.9.1 3.0.9.2 3.0.9.3 3.0.9.4 3.0.9.5 3.1.0 3.1.1 3.1.2 3.2.0 3.2.1 3.2.2 3.2.3 3.2.4 3.2.5 3.2.6 3.3.0 3.4.0 3.4.1 3.4.2 3.4.2.1 3.4.3 3.4.4 3.4.5 trunk 1.0 1.0.1 1.0.2 1.0.3
everest-forms / includes / admin / class-evf-base-list-table.php
everest-forms / includes / admin Last commit date
builder 1 month ago form-migrator 1 month ago plugin-updates 8 years ago settings 1 month ago views 1 month ago class-evf-admin-addons.php 4 months ago class-evf-admin-assets.php 2 weeks ago class-evf-admin-builder.php 2 months ago class-evf-admin-dashboard.php 1 month ago class-evf-admin-editor.php 4 years ago class-evf-admin-embed-wizard.php 2 years ago class-evf-admin-entries-table-list.php 2 months ago class-evf-admin-entries.php 2 months ago class-evf-admin-form-templates.php 1 month ago class-evf-admin-forms-table-list.php 4 months ago class-evf-admin-forms.php 4 months ago class-evf-admin-import-export.php 1 month ago class-evf-admin-menus.php 1 month ago class-evf-admin-notices.php 4 months ago class-evf-admin-preview-confirmation.php 1 year ago class-evf-admin-settings.php 1 month ago class-evf-admin-tools.php 2 months ago class-evf-admin-welcome.php 2 years ago class-evf-admin.php 2 months ago class-evf-base-list-table.php 4 months ago evf-admin-functions.php 1 month ago
class-evf-base-list-table.php
545 lines
1 <?php
2 /**
3 * EverestForms Base List Table
4 *
5 * Abstract base class for all EverestForms table list classes.
6 * This class extends WP_List_Table and provides common functionality
7 * for both forms and entries table lists.
8 *
9 * @package EverestForms\Admin
10 * @since 3.4.3
11 */
12
13 defined( 'ABSPATH' ) || exit;
14
15 if ( ! class_exists( 'WP_List_Table' ) ) {
16 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
17 }
18
19 /**
20 * Base table list class.
21 *
22 * This abstract class provides a foundation for all EverestForms table implementations.
23 * Child classes should extend this class and implement/override methods as needed.
24 *
25 * @abstract
26 */
27 abstract class EVF_Base_List_Table extends WP_List_Table {
28
29 /**
30 * Initialize the base table list.
31 *
32 * @param array $args An associative array of arguments.
33 */
34 public function __construct( $args = array() ) {
35 parent::__construct( $args );
36 }
37
38 /**
39 * No items found text.
40 *
41 * Default implementation. Child classes should override this method.
42 */
43 public function no_items() {
44 esc_html_e( 'No items found.', 'everest-forms' );
45 }
46
47 /**
48 * Process bulk actions.
49 *
50 * Default implementation. Child classes should override this method.
51 */
52 public function process_bulk_action() {
53 // Child classes should implement their own bulk action logic.
54 }
55
56 /**
57 * Get bulk actions.
58 *
59 * Default implementation. Child classes should override this method.
60 *
61 * @return array
62 */
63 protected function get_bulk_actions() {
64 return array();
65 }
66
67 /**
68 * Get a list of sortable columns.
69 *
70 * Default implementation. Child classes can override this method.
71 *
72 * @return array
73 */
74 protected function get_sortable_columns() {
75 return array();
76 }
77
78 /**
79 * Extra controls to be displayed between bulk actions and pagination.
80 *
81 * Default implementation. Child classes can override this method.
82 *
83 * @param string $which The location of the extra table nav markup.
84 */
85 protected function extra_tablenav( $which ) {
86 // Child classes can implement their own extra tablenav logic.
87 }
88
89 /**
90 * Display content above the table.
91 *
92 * This method can be overridden by child classes to add custom content
93 * above the table structure (before tablenav and the actual table).
94 *
95 * @since 3.4.3
96 */
97 protected function display_above_table() {
98 /**
99 * Hook to add content above the table.
100 *
101 * @param EVF_Base_List_Table $table The current table instance.
102 */
103 do_action( 'everest_forms_above_table', $this );
104
105 // Default implementation - adds the everest-forms-extra-table-nav div
106 ?>
107 <div class="everest-forms-extra-table-nav">
108 <?php
109 /**
110 * Hook to add content inside the extra table nav div.
111 *
112 * @param EVF_Base_List_Table $table The current table instance.
113 */
114 do_action( 'everest_forms_extra_table_nav_content', $this );
115 ?>
116 </div>
117 <?php
118 }
119
120 /**
121 * Display the table with above-table content support.
122 *
123 * Overrides parent display() to add content above the table and wrap everything in a div.
124 */
125 public function display() {
126 // Opening wrapper div
127 echo '<div class="everest-forms-table-wrapper">';
128
129 // Display content above the table.
130 $this->display_above_table();
131
132 $singular = $this->_args['singular'];
133
134 $this->display_tablenav( 'top' );
135
136 $this->screen->render_screen_reader_content( 'heading_list' );
137 ?>
138 <div class="everest-forms-table-container">
139 <table class="wp-list-table <?php echo implode( ' ', $this->get_table_classes() ); ?>">
140 <thead>
141 <tr>
142 <?php $this->print_column_headers(); ?>
143 </tr>
144 </thead>
145
146 <tbody id="the-list"
147 <?php
148 if ( $singular ) {
149 echo " data-wp-lists='list:$singular'";
150 }
151 ?>
152 >
153 <?php $this->display_rows_or_placeholder(); ?>
154 </tbody>
155
156 <tfoot>
157 <tr>
158 <?php $this->print_column_headers( false ); ?>
159 </tr>
160 </tfoot>
161
162 </table>
163 </div>
164 <?php
165 $this->display_tablenav( 'bottom' );
166
167 // Closing wrapper div
168 echo '</div>';
169 }
170
171 /**
172 * Table list views.
173 *
174 * Default implementation. Child classes can override this method.
175 *
176 * @return array
177 */
178 protected function get_views() {
179 return array();
180 }
181
182 /**
183 * Column cb (checkbox).
184 *
185 * Default implementation for checkbox column.
186 * Child classes can override this method.
187 *
188 * @param object $item Item object.
189 * @return string
190 */
191 public function column_cb( $item ) {
192 if ( ! isset( $item->ID ) ) {
193 return '';
194 }
195 return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" />', $this->_args['singular'], $item->ID );
196 }
197
198 /**
199 * Renders the columns.
200 *
201 * Default implementation for rendering columns.
202 * Child classes can override this method.
203 *
204 * @param object $item Item object.
205 * @param string $column_name Column Name.
206 * @return string
207 */
208 public function column_default( $item, $column_name ) {
209 return '';
210 }
211
212 /**
213 * Helper method to sanitize text field from request.
214 *
215 * @param string $key The request parameter key.
216 * @return string Sanitized value or empty string.
217 */
218 protected function get_sanitized_request( $key ) {
219 return isset( $_REQUEST[ $key ] ) ? sanitize_text_field( wp_unslash( $_REQUEST[ $key ] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification
220 }
221
222 /**
223 * Helper method to get integer value from request.
224 *
225 * @param string $key The request parameter key.
226 * @return int Sanitized integer value or 0.
227 */
228 protected function get_int_request( $key ) {
229 return isset( $_REQUEST[ $key ] ) ? absint( $_REQUEST[ $key ] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification
230 }
231
232 /**
233 * Helper method to check if a request parameter exists.
234 *
235 * @param string $key The request parameter key.
236 * @return bool True if parameter exists, false otherwise.
237 */
238 protected function has_request( $key ) {
239 return isset( $_REQUEST[ $key ] ); // phpcs:ignore WordPress.Security.NonceVerification
240 }
241
242 /**
243 * Get a list of CSS classes for the table element.
244 *
245 * @return array List of CSS class names.
246 */
247 protected function get_table_classes() {
248 $classes = parent::get_table_classes();
249 $classes[] = 'evf-base-list-table';
250 return $classes;
251 }
252
253 /**
254 * Get the current URL with sanitized server variables.
255 *
256 * @return string Current URL.
257 */
258 protected function get_current_url() {
259 $http_host = isset( $_SERVER['HTTP_HOST'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_HOST'] ) ) : '';
260 $request_uri = isset( $_SERVER['REQUEST_URI'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REQUEST_URI'] ) ) : '';
261
262 if ( empty( $http_host ) || empty( $request_uri ) ) {
263 return admin_url();
264 }
265
266 $current_url = set_url_scheme( 'http://' . $http_host . $request_uri );
267 $removable_query_args = wp_removable_query_args();
268
269 return remove_query_arg( $removable_query_args, $current_url );
270 }
271
272 /**
273 * Get the display text for pagination showing current range of items.
274 *
275 * @param int $current Current page number.
276 * @param int $per_page Number of items per page.
277 * @param int $total_items Total number of items.
278 * @return string HTML output for displaying item range.
279 */
280 protected function get_pagination_display_text( $current, $per_page, $total_items ) {
281 $start = ( ( $current - 1 ) * $per_page ) + 1;
282 $end = min( $current * $per_page, $total_items );
283
284 return '<span class="displaying-num">' . sprintf(
285 /* translators: 1: start number, 2: end number, 3: total number */
286 esc_html__( 'Showing %1$s-%2$s of %3$s entries', 'everest-forms' ),
287 number_format_i18n( $start ),
288 number_format_i18n( $end ),
289 number_format_i18n( $total_items )
290 ) . '</span>';
291 }
292
293 /**
294 * Get first and last page navigation buttons.
295 *
296 * @param int $current Current page number.
297 * @param int $total_pages Total number of pages.
298 * @param string $current_url Current URL without pagination args.
299 * @return array Array of HTML strings for navigation buttons.
300 */
301 protected function get_first_last_buttons( $current, $total_pages, $current_url ) {
302 $buttons = array();
303
304 // First page button.
305 if ( 1 === $current ) {
306 $buttons['first'] = '<span class="tablenav-pages-navspan button disabled first-page" aria-hidden="true" title="' . esc_attr__( 'First page', 'everest-forms' ) . '">&laquo;</span>';
307 } else {
308 $buttons['first'] = sprintf(
309 "<a class='first-page button' href='%s' title='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
310 esc_url( add_query_arg( 'paged', 1, $current_url ) ),
311 esc_attr__( 'First page', 'everest-forms' ),
312 esc_html__( 'First page', 'everest-forms' ),
313 '&laquo;'
314 );
315 }
316
317 // Last page button.
318 if ( $total_pages === $current ) {
319 $buttons['last'] = '<span class="tablenav-pages-navspan button disabled last-page" aria-hidden="true" title="' . esc_attr__( 'Last page', 'everest-forms' ) . '">&raquo;</span>';
320 } else {
321 $buttons['last'] = sprintf(
322 "<a class='last-page button' href='%s' title='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
323 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
324 esc_attr__( 'Last page', 'everest-forms' ),
325 esc_html__( 'Last page', 'everest-forms' ),
326 '&raquo;'
327 );
328 }
329
330 return $buttons;
331 }
332
333 /**
334 * Get previous and next page navigation buttons.
335 *
336 * @param int $current Current page number.
337 * @param int $total_pages Total number of pages.
338 * @param string $current_url Current URL without pagination args.
339 * @return array Array of HTML strings for navigation buttons.
340 */
341 protected function get_prev_next_buttons( $current, $total_pages, $current_url ) {
342 $buttons = array();
343
344 // Previous page button.
345 if ( 1 === $current ) {
346 $buttons['prev'] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&lsaquo;</span>';
347 } else {
348 $buttons['prev'] = sprintf(
349 "<a class='prev-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
350 esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
351 esc_html__( 'Previous page', 'everest-forms' ),
352 '&lsaquo;'
353 );
354 }
355
356 // Next page button.
357 if ( $total_pages === $current ) {
358 $buttons['next'] = '<span class="tablenav-pages-navspan button disabled" aria-hidden="true">&rsaquo;</span>';
359 } else {
360 $buttons['next'] = sprintf(
361 "<a class='next-page button' href='%s'><span class='screen-reader-text'>%s</span><span aria-hidden='true'>%s</span></a>",
362 esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ),
363 esc_html__( 'Next page', 'everest-forms' ),
364 '&rsaquo;'
365 );
366 }
367
368 return $buttons;
369 }
370
371 /**
372 * Get numbered page links for pagination.
373 *
374 * @param int $current Current page number.
375 * @param int $total_pages Total number of pages.
376 * @param string $current_url Current URL without pagination args.
377 * @return array Array of HTML strings for page number links.
378 */
379 protected function get_page_number_links( $current, $total_pages, $current_url ) {
380 $page_links = array();
381 $mid_size = 2;
382 $end_size = 1;
383
384 for ( $n = 1; $n <= $total_pages; $n++ ) {
385 $show_link = false;
386
387 // Show first and last pages.
388 if ( $n <= $end_size || $n > $total_pages - $end_size ) {
389 $show_link = true;
390 }
391
392 // Show pages around current page.
393 if ( $n >= $current - $mid_size && $n <= $current + $mid_size ) {
394 $show_link = true;
395 }
396
397 if ( $show_link ) {
398 if ( $n === $current ) {
399 $page_links[] = sprintf(
400 "<span class='page-numbers current' aria-current='page'>%s</span>",
401 number_format_i18n( $n )
402 );
403 } else {
404 $page_links[] = sprintf(
405 "<a class='page-numbers' href='%s' aria-label='%s'>%s</a>",
406 esc_url( add_query_arg( 'paged', $n, $current_url ) ),
407 /* translators: %s: page number */
408 esc_attr( sprintf( __( 'Page %s', 'everest-forms' ), number_format_i18n( $n ) ) ),
409 number_format_i18n( $n )
410 );
411 }
412 } elseif ( ! empty( $page_links ) && strpos( $page_links[ count( $page_links ) - 1 ], 'dots' ) === false ) {
413 $page_links[] = '<span class="page-numbers dots" aria-hidden="true">...</span>';
414 }
415 }
416
417 return $page_links;
418 }
419
420 /**
421 * Display the pagination.
422 *
423 * Enhanced pagination with numbered page links, first/last buttons, and items per page selector.
424 * Only displays at the bottom of the table.
425 *
426 * @param string $which The location of the pagination nav.
427 */
428 protected function pagination( $which ) {
429 if ( 'top' === $which ) {
430 return;
431 }
432
433 if ( empty( $this->_pagination_args ) ) {
434 return;
435 }
436
437 $total_items = $this->_pagination_args['total_items'];
438 $total_pages = $this->_pagination_args['total_pages'];
439 $infinite_scroll = false;
440
441 if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
442 $infinite_scroll = $this->_pagination_args['infinite_scroll'];
443 }
444
445 $current = $this->get_pagenum();
446 $per_page = $this->_pagination_args['per_page'];
447 $current_url = $this->get_current_url();
448
449 // Get display text showing current range.
450 $output = $this->get_pagination_display_text( $current, $per_page, $total_items );
451
452 // Build page links array.
453 $page_links = array();
454
455 // Get first/last buttons.
456 $first_last = $this->get_first_last_buttons( $current, $total_pages, $current_url );
457 $page_links[] = $first_last['first'];
458
459 // Get prev/next buttons.
460 $prev_next = $this->get_prev_next_buttons( $current, $total_pages, $current_url );
461 $page_links[] = $prev_next['prev'];
462
463 // Get numbered page links.
464 $number_links = $this->get_page_number_links( $current, $total_pages, $current_url );
465 $page_links = array_merge( $page_links, $number_links );
466
467 // Add next and last buttons.
468 $page_links[] = $prev_next['next'];
469 $page_links[] = $first_last['last'];
470
471 $pagination_links_class = 'pagination-links';
472 if ( ! empty( $infinite_scroll ) ) {
473 $pagination_links_class .= ' hide-if-js';
474 }
475 $output .= "\n<span class='$pagination_links_class'>" . implode( "\n", $page_links ) . '</span>';
476
477 if ( $total_pages ) {
478 $page_class = $total_pages < 2 ? ' one-page' : '';
479 } else {
480 $page_class = ' no-pages';
481 }
482 $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
483
484 echo $this->_pagination; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
485 }
486
487 /**
488 * Get current page number.
489 *
490 * @return int Current page number.
491 */
492 public function get_pagenum() {
493 $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification
494
495 if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) {
496 $pagenum = $this->_pagination_args['total_pages'];
497 }
498
499 return max( 1, $pagenum );
500 }
501
502 /**
503 * Display the search box.
504 *
505 * @param string $text The 'submit' button label.
506 * @param string $input_id ID attribute value for the search input field.
507 */
508 public function search_box( $text, $input_id ) {
509 if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
510 return;
511 }
512
513 $input_id = $input_id . '-search-input';
514
515 if ( ! empty( $_REQUEST['orderby'] ) ) {
516 echo '<input type="hidden" name="orderby" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) ) . '" />';
517 }
518 if ( ! empty( $_REQUEST['order'] ) ) {
519 echo '<input type="hidden" name="order" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) . '" />';
520 }
521 ?>
522 <div class="search-box evf-search">
523 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>">
524 <?php echo esc_html( $text ); ?>:
525 </label>
526
527 <input type="search"
528 id="<?php echo esc_attr( $input_id ); ?>"
529 name="s"
530 value="<?php _admin_search_query(); ?>"
531 placeholder="<?php echo esc_attr( $text ); ?>" />
532
533 <button type="submit" id="search-submit" class="evf-search-submit button">
534 <span class="screen-reader-text"><?php echo esc_html( $text ); ?></span>
535 <svg xmlns="http://www.w3.org/2000/svg" width="20" height="20" fill="none" viewBox="0 0 24 24">
536 <path fill="currentColor" fill-rule="evenodd"
537 d="M4 11a7 7 0 1 1 12.042 4.856 1.012 1.012 0 0 0-.186.186A7 7 0 0 1 4 11Zm12.618 7.032a9 9 0 1 1 1.414-1.414l3.675 3.675a1 1 0 0 1-1.414 1.414l-3.675-3.675Z"
538 clip-rule="evenodd"></path>
539 </svg>
540 </button>
541 </div>
542 <?php
543 }
544 }
545