PluginProbe ʕ •ᴥ•ʔ
Strong Testimonials / 3.3.2
Strong Testimonials v3.3.2
3.3.2 3.3.1 trunk 1.0.1 2.30.9 2.31.10 2.32 2.32.1 2.32.2 2.32.3 2.32.4 2.33 2.34 2.35 2.36 2.37 2.38 2.38.1 2.39 2.39.1 2.39.2 2.39.3 2.40.0 2.40.1 2.40.2 2.40.3 2.40.4 2.40.5 2.40.6 2.40.7 2.41.0 2.41.1 2.50.0 2.50.1 2.50.2 2.50.3 2.50.4 2.51.0 2.51.1 2.51.2 2.51.3 2.51.4 2.51.5 2.51.6 2.51.7 2.51.8 2.51.9 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.1.10 3.1.11 3.1.12 3.1.13 3.1.14 3.1.15 3.1.16 3.1.17 3.1.18 3.1.19 3.1.2 3.1.20 3.1.3 3.1.4 3.1.5 3.1.6 3.1.7 3.1.8 3.1.9 3.2.0 3.2.1 3.2.10 3.2.11 3.2.12 3.2.13 3.2.14 3.2.15 3.2.16 3.2.17 3.2.18 3.2.19 3.2.2 3.2.20 3.2.21 3.2.22 3.2.3 3.2.4 3.2.5 3.2.6 3.2.7 3.2.8 3.2.9 3.3.0
strong-testimonials / admin / class-strong-testimonials-list-table.php
strong-testimonials / admin Last commit date
challenge 1 year ago css 1 week ago img 1 year ago js 1 month ago menu 1 month ago partials 2 weeks ago rest-api 1 week ago scss 1 year ago settings 1 week ago uninstall 1 year ago wpchill 1 month ago admin-notices.php 6 months ago admin.php 1 month ago class-strong-testimonials-addons.php 1 month ago class-strong-testimonials-admin-category-list.php 1 year ago class-strong-testimonials-admin-list.php 1 year ago class-strong-testimonials-admin-scripts.php 1 month ago class-strong-testimonials-admin.php 1 month ago class-strong-testimonials-debug.php 6 months ago class-strong-testimonials-exporter.php 1 year ago class-strong-testimonials-help.php 1 year ago class-strong-testimonials-helper.php 1 month ago class-strong-testimonials-list-table.php 1 year ago class-strong-testimonials-lite-vs-pro-page.php 1 month ago class-strong-testimonials-post-editor.php 7 months ago class-strong-testimonials-review.php 1 year ago class-strong-testimonials-updater.php 1 month ago class-strong-testimonials-upsell.php 1 week ago class-strong-views-list-table.php 1 month ago class-walker-strong-category-checklist.php 1 year ago class-walker-strong-form-category-checklist.php 1 year ago class-wpmtst-onboarding.php 1 year ago compat.php 1 year ago custom-fields-ajax.php 1 year ago custom-fields.php 1 week ago form-preview.php 1 year ago view-list-order.php 1 year ago views-ajax.php 1 month ago views-validate.php 1 year ago views.php 1 month ago
class-strong-testimonials-list-table.php
1218 lines
1 <?php
2 /**
3 * Base class for displaying a list of items in an ajaxified HTML table.
4 *
5 * -!- This is a copy of /wp-admin/includes/class-wp-list-table.php. -!-
6 * See Codex for reasoning.
7 * @link http://codex.wordpress.org/Class_Reference/WP_List_Table
8 *
9 * @since 3.1.0
10 * @access private
11 */
12
13 if ( ! class_exists( 'Strong_Testimonials_List_Table' ) ) :
14
15 class Strong_Testimonials_List_Table {
16
17 /**
18 * The current list of items
19 *
20 * @since 3.1.0
21 * @var array
22 * @access public
23 */
24 public $items;
25
26 /**
27 * Various information about the current table
28 *
29 * @since 3.1.0
30 * @var array
31 * @access protected
32 */
33 protected $_args;
34
35 /**
36 * Various information needed for displaying the pagination
37 *
38 * @since 3.1.0
39 * @var array
40 */
41 protected $_pagination_args = array();
42
43 /**
44 * The current screen
45 *
46 * @since 3.1.0
47 * @var object
48 * @access protected
49 */
50 protected $screen;
51
52 /**
53 * Cached bulk actions
54 *
55 * @since 3.1.0
56 * @var array
57 * @access private
58 */
59 private $_actions;
60
61 /**
62 * Cached pagination output
63 *
64 * @since 3.1.0
65 * @var string
66 * @access private
67 */
68 private $_pagination;
69
70 /**
71 * The view switcher modes.
72 *
73 * @since 4.1.0
74 * @var array
75 * @access protected
76 */
77 protected $modes = array();
78
79 /**
80 * Stores the value returned by ->get_column_info()
81 *
82 * @var array
83 */
84 protected $_column_headers;
85
86 protected $compat_fields = array( '_args', '_pagination_args', 'screen', '_actions', '_pagination' );
87
88 protected $compat_methods = array(
89 'set_pagination_args',
90 'get_views',
91 'get_bulk_actions',
92 'bulk_actions',
93 'row_actions',
94 'months_dropdown',
95 'view_switcher',
96 'comments_bubble',
97 'get_items_per_page',
98 'pagination',
99 'get_sortable_columns',
100 'get_column_info',
101 'get_table_classes',
102 'display_tablenav',
103 'extra_tablenav',
104 'single_row_columns',
105 );
106
107 /**
108 * Constructor.
109 *
110 * The child class should call this constructor from its own constructor to override
111 * the default $args.
112 *
113 * @since 3.1.0
114 * @access public
115 *
116 * @param array|string $args {
117 * Array or string of arguments.
118 *
119 * @type string $plural Plural value used for labels and the objects being listed.
120 * This affects things such as CSS class-names and nonces used
121 * in the list table, e.g. 'posts'. Default empty.
122 * @type string $singular Singular label for an object being listed, e.g. 'post'.
123 * Default empty
124 * @type bool $ajax Whether the list table supports AJAX. This includes loading
125 * and sorting data, for example. If true, the class will call
126 * the {@see _js_vars()} method in the footer to provide variables
127 * to any scripts handling AJAX events. Default false.
128 * @type string $screen String containing the hook name used to determine the current
129 * screen. If left null, the current screen will be automatically set.
130 * Default null.
131 * }
132 */
133 public function __construct( $args = array() ) {
134 $args = wp_parse_args(
135 $args,
136 array(
137 'plural' => '',
138 'singular' => '',
139 'ajax' => false,
140 'screen' => null,
141 )
142 );
143
144 $this->screen = convert_to_screen( $args['screen'] );
145
146 add_filter( "manage_{$this->screen->id}_columns", array( $this, 'get_columns' ), 0 );
147
148 if ( ! $args['plural'] ) {
149 $args['plural'] = $this->screen->base;
150 }
151
152 $args['plural'] = sanitize_key( $args['plural'] );
153 $args['singular'] = sanitize_key( $args['singular'] );
154
155 $this->_args = $args;
156
157 if ( $args['ajax'] ) {
158 // wp_enqueue_script( 'list-table' );
159 add_action( 'admin_footer', array( $this, '_js_vars' ) );
160 }
161
162 if ( empty( $this->modes ) ) {
163 $this->modes = array(
164 'list' => esc_html__( 'List View', 'strong-testimonials' ),
165 'excerpt' => esc_html__( 'Excerpt View', 'strong-testimonials' ),
166 );
167 }
168 }
169
170 /**
171 * Make private properties readable for backwards compatibility.
172 *
173 * @since 4.0.0
174 * @access public
175 *
176 * @param string $name Property to get.
177 * @return mixed Property.
178 */
179 public function __get( $name ) {
180 if ( in_array( $name, $this->compat_fields, true ) ) {
181 return $this->$name;
182 }
183 }
184
185 /**
186 * Make private properties settable for backwards compatibility.
187 *
188 * @since 4.0.0
189 * @access public
190 *
191 * @param string $name Property to check if set.
192 * @param mixed $value Property value.
193 * @return mixed Newly-set property.
194 */
195 public function __set( $name, $value ) {
196 if ( in_array( $name, $this->compat_fields, true ) ) {
197 return $this->$name = $value;
198 }
199 }
200
201 /**
202 * Make private properties checkable for backwards compatibility.
203 *
204 * @since 4.0.0
205 * @access public
206 *
207 * @param string $name Property to check if set.
208 * @return bool Whether the property is set.
209 */
210 public function __isset( $name ) {
211 if ( in_array( $name, $this->compat_fields, true ) ) {
212 return isset( $this->$name );
213 }
214 }
215
216 /**
217 * Make private properties un-settable for backwards compatibility.
218 *
219 * @since 4.0.0
220 * @access public
221 *
222 * @param string $name Property to unset.
223 */
224 public function __unset( $name ) {
225 if ( in_array( $name, $this->compat_fields, true ) ) {
226 unset( $this->$name );
227 }
228 }
229
230 /**
231 * Make private/protected methods readable for backwards compatibility.
232 *
233 * @since 4.0.0
234 * @access public
235 *
236 * @param callable $name Method to call.
237 * @param array $arguments Arguments to pass when calling.
238 * @return mixed|bool Return value of the callback, false otherwise.
239 */
240 public function __call( $name, $arguments ) {
241 if ( in_array( $name, $this->compat_methods, true ) ) {
242 return call_user_func_array( array( $this, $name ), $arguments );
243 }
244 return false;
245 }
246
247 /**
248 * Checks the current user's permissions
249 *
250 * @since 3.1.0
251 * @access public
252 * @abstract
253 */
254 public function ajax_user_can() {
255 die( 'function WP_List_Table::ajax_user_can() must be over-ridden in a sub-class.' );
256 }
257
258 /**
259 * Prepares the list of items for displaying.
260 * @uses WP_List_Table::set_pagination_args()
261 *
262 * @since 3.1.0
263 * @access public
264 * @abstract
265 */
266 public function prepare_items() {
267 die( 'function WP_List_Table::prepare_items() must be over-ridden in a sub-class.' );
268 }
269
270 /**
271 * An internal method that sets all the necessary pagination arguments
272 *
273 * @param array $args An associative array with information about the pagination
274 * @access protected
275 */
276 protected function set_pagination_args( $args ) {
277 $args = wp_parse_args(
278 $args,
279 array(
280 'total_items' => 0,
281 'total_pages' => 0,
282 'per_page' => 0,
283 )
284 );
285
286 if ( ! $args['total_pages'] && $args['per_page'] > 0 ) {
287 $args['total_pages'] = ceil( $args['total_items'] / $args['per_page'] );
288 }
289
290 // Redirect if page number is invalid and headers are not already sent.
291 if ( ! headers_sent() && ( ! defined( 'DOING_AJAX' ) || ! DOING_AJAX ) && $args['total_pages'] > 0 && $this->get_pagenum() > $args['total_pages'] ) {
292 wp_redirect( add_query_arg( 'paged', $args['total_pages'] ) );
293 exit;
294 }
295
296 $this->_pagination_args = $args;
297 }
298
299 /**
300 * Access the pagination args.
301 *
302 * @since 3.1.0
303 * @access public
304 *
305 * @param string $key Pagination argument to retrieve. Common values include 'total_items',
306 * 'total_pages', 'per_page', or 'infinite_scroll'.
307 * @return int Number of items that correspond to the given pagination argument.
308 */
309 public function get_pagination_arg( $key ) {
310 if ( 'page' === $key ) {
311 return $this->get_pagenum();
312 }
313
314 if ( isset( $this->_pagination_args[ $key ] ) ) {
315 return $this->_pagination_args[ $key ];
316 }
317 }
318
319 /**
320 * Whether the table has items to display or not
321 *
322 * @since 3.1.0
323 * @access public
324 *
325 * @return bool
326 */
327 public function has_items() {
328 return ! empty( $this->items );
329 }
330
331 /**
332 * Message to be displayed when there are no items
333 *
334 * @since 3.1.0
335 * @access public
336 */
337 public function no_items() {
338 esc_html_e( 'No items found.', 'strong-testimonials' );
339 }
340
341 /**
342 * Display the search box.
343 *
344 * @since 3.1.0
345 * @access public
346 *
347 * @param string $text The search button text
348 * @param string $input_id The search input id
349 */
350 public function search_box( $text, $input_id ) {
351 if ( empty( $_REQUEST['s'] ) && ! $this->has_items() ) {
352 return;
353 }
354
355 $input_id = $input_id . '-search-input';
356
357 if ( ! empty( $_REQUEST['orderby'] ) ) {
358 echo '<input type="hidden" name="orderby" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) ) ) . '">';
359 }
360 if ( ! empty( $_REQUEST['order'] ) ) {
361 echo '<input type="hidden" name="order" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) . '">';
362 }
363 if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
364 echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['post_mime_type'] ) ) ) . '">';
365 }
366 if ( ! empty( $_REQUEST['detached'] ) ) {
367 echo '<input type="hidden" name="detached" value="' . esc_attr( sanitize_text_field( wp_unslash( $_REQUEST['detached'] ) ) ) . '">';
368 }
369 ?>
370 <p class="search-box">
371 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_html( $text ); ?>:</label>
372 <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="s" value="<?php _admin_search_query(); ?>">
373 <?php submit_button( esc_html( $text ), 'button', '', false, array( 'id' => 'search-submit' ) ); ?>
374 </p>
375 <?php
376 }
377
378 /**
379 * Get an associative array ( id => link ) with the list
380 * of views available on this table.
381 *
382 * @since 3.1.0
383 * @access protected
384 *
385 * @return array
386 */
387 protected function get_views() {
388 return array();
389 }
390
391 /**
392 * Display the list of views available on this table.
393 *
394 * @since 3.1.0
395 * @access public
396 */
397 public function views() {
398 $views = $this->get_views();
399 /**
400 * Filter the list of available list table views.
401 *
402 * The dynamic portion of the hook name, `$this->screen->id`, refers
403 * to the ID of the current screen, usually a string.
404 *
405 * @since 3.5.0
406 *
407 * @param array $views An array of available list table views.
408 */
409 $views = apply_filters( "views_{$this->screen->id}", $views );
410
411 if ( empty( $views ) ) {
412 return;
413 }
414
415 echo "<ul class='subsubsub'>\n";
416 foreach ( $views as $class => $view ) {
417 $views[ $class ] = "\t<li class='$class'>$view";
418 }
419 echo implode( " |</li>\n", wp_kses_post( $views ) ) . "</li>\n";
420 echo '</ul>';
421 }
422
423 /**
424 * Get an associative array ( option_name => option_title ) with the list
425 * of bulk actions available on this table.
426 *
427 * @since 3.1.0
428 * @access protected
429 *
430 * @return array
431 */
432 protected function get_bulk_actions() {
433 return array();
434 }
435
436 /**
437 * Display the bulk actions dropdown.
438 *
439 * @since 3.1.0
440 * @access protected
441 *
442 * @param string $which The location of the bulk actions: 'top' or 'bottom'.
443 * This is designated as optional for backwards-compatibility.
444 */
445 protected function bulk_actions( $which = '' ) {
446 if ( is_null( $this->_actions ) ) {
447 $no_new_actions = $this->get_bulk_actions();
448 $this->_actions = $no_new_actions;
449 /**
450 * Filter the list table Bulk Actions drop-down.
451 *
452 * The dynamic portion of the hook name, `$this->screen->id`, refers
453 * to the ID of the current screen, usually a string.
454 *
455 * This filter can currently only be used to remove bulk actions.
456 *
457 * @since 3.5.0
458 *
459 * @param array $actions An array of the available bulk actions.
460 */
461 $this->_actions = apply_filters( "bulk_actions-{$this->screen->id}", $this->_actions ); // phpcs:ignore
462 $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
463 $two = '';
464 } else {
465 $two = '2';
466 }
467
468 if ( empty( $this->_actions ) ) {
469 return;
470 }
471
472 echo "<label for='bulk-action-selector-" . esc_attr( $which ) . "' class='screen-reader-text'>" . esc_html__( 'Select bulk action', 'strong-testimonials' ) . '</label>';
473 echo "<select name='action" . esc_attr( $two ) . "' id='bulk-action-selector-" . esc_attr( $which ) . "'>\n";
474 echo "<option value='-1' selected='selected'>" . esc_html__( 'Bulk Actions', 'strong-testimonials' ) . "</option>\n";
475
476 foreach ( $this->_actions as $name => $title ) {
477 $class = 'edit' === $name ? 'hide-if-no-js' : '';
478
479 echo "\t<option value='" . esc_attr( $name ) . "' class='" . esc_attr( $class ) . "'>" . esc_html( $title ) . "</option>\n";
480 }
481
482 echo "</select>\n";
483
484 submit_button( esc_html__( 'Apply', 'strong-testimonials' ), 'action', '', false, array( 'id' => "doaction$two" ) );
485 echo "\n";
486 }
487
488 /**
489 * Get the current action selected from the bulk actions dropdown.
490 *
491 * @since 3.1.0
492 * @access public
493 *
494 * @return string|bool The action name or False if no action was selected
495 */
496 public function current_action() {
497 if ( isset( $_REQUEST['filter_action'] ) && ! empty( $_REQUEST['filter_action'] ) ) {
498 return false;
499 }
500
501 if ( isset( $_REQUEST['action'] ) && -1 !== (int) $_REQUEST['action'] ) {
502 return sanitize_text_field( wp_unslash( $_REQUEST['action'] ) );
503 }
504
505 if ( isset( $_REQUEST['action2'] ) && -1 !== (int) $_REQUEST['action2'] ) {
506 return sanitize_text_field( wp_unslash( $_REQUEST['action2'] ) );
507 }
508
509 return false;
510 }
511
512 /**
513 * Generate row actions div
514 *
515 * @since 3.1.0
516 * @access protected
517 *
518 * @param array $actions The list of actions
519 * @param bool $always_visible Whether the actions should be always visible
520 * @return string
521 */
522 protected function row_actions( $actions, $always_visible = false ) {
523 $action_count = count( $actions );
524 $i = 0;
525
526 if ( ! $action_count ) {
527 return '';
528 }
529
530 $out = '<div class="' . ( $always_visible ? 'row-actions visible' : 'row-actions' ) . '">';
531 foreach ( $actions as $action => $link ) {
532 ++$i;
533 ( $i === $action_count ) ? $sep = '' : $sep = ' | ';
534 $out .= "<span class='$action'>$link$sep</span>";
535 }
536 $out .= '</div>';
537
538 return $out;
539 }
540
541 /**
542 * Display a monthly dropdown for filtering items
543 *
544 * @since 3.1.0
545 * @access protected
546 *
547 * @param string $post_type
548 */
549 protected function months_dropdown( $post_type ) {
550 global $wpdb, $wp_locale;
551
552 /**
553 * Filter whether to remove the 'Months' drop-down from the post list table.
554 *
555 * @since 4.2.0
556 *
557 * @param bool $disable Whether to disable the drop-down. Default false.
558 * @param string $post_type The post type.
559 */
560 if ( apply_filters( 'disable_months_dropdown', false, $post_type ) ) {
561 return;
562 }
563
564 $months = $wpdb->get_results(
565 $wpdb->prepare(
566 "
567 SELECT DISTINCT YEAR( post_date ) AS year, MONTH( post_date ) AS month
568 FROM $wpdb->posts
569 WHERE post_type = %s
570 ORDER BY post_date DESC
571 ",
572 $post_type
573 )
574 );
575
576 /**
577 * Filter the 'Months' drop-down results.
578 *
579 * @since 3.7.0
580 *
581 * @param object $months The months drop-down query results.
582 * @param string $post_type The post type.
583 */
584 $months = apply_filters( 'months_dropdown_results', $months, $post_type );
585
586 $month_count = count( $months );
587
588 if ( ! $month_count || ( 1 === $month_count && 0 === (int) $months[0]->month ) ) {
589 return;
590 }
591
592 $m = isset( $_GET['m'] ) ? (int) $_GET['m'] : 0;
593 ?>
594 <label for="filter-by-date" class="screen-reader-text"><?php esc_html_e( 'Filter by date', 'strong-testimonials' ); ?></label>
595 <select name="m" id="filter-by-date">
596 <option<?php selected( $m, 0 ); ?> value="0"><?php esc_html_e( 'All dates', 'strong-testimonials' ); ?></option>
597 <?php
598 foreach ( $months as $arc_row ) {
599 if ( 0 === (int) $arc_row->year ) {
600 continue;
601 }
602
603 $month = zeroise( $arc_row->month, 2 );
604 $year = $arc_row->year;
605
606 printf(
607 "<option %s value='%s'>%s</option>\n",
608 selected( $m, $year . $month, false ),
609 esc_attr( $arc_row->year . $month ),
610 /* translators: 1: month name, 2: 4-digit year */
611 sprintf( '%1$s %2$d', esc_html( $wp_locale->get_month( $month ) ), esc_html( $year ) )
612 );
613 }
614 ?>
615 </select>
616 <?php
617 }
618
619 /**
620 * Display a view switcher
621 *
622 * @since 3.1.0
623 * @access protected
624 *
625 * @param string $current_mode
626 */
627 protected function view_switcher( $current_mode ) {
628 ?>
629 <input type="hidden" name="mode" value="<?php echo esc_attr( $current_mode ); ?>">
630 <div class="view-switch">
631 <?php
632 foreach ( $this->modes as $mode => $title ) {
633 $classes = array( 'view-' . $mode );
634 if ( $current_mode === $mode ) {
635 $classes[] = 'current';
636 }
637 printf(
638 "<a href='%s' class='%s' id='view-switch-%s'><span class='screen-reader-text'>%s</span></a>\n",
639 esc_url( add_query_arg( 'mode', $mode ) ),
640 esc_attr( implode( ' ', $classes ) ),
641 esc_attr( $mode ),
642 esc_html( $title )
643 );
644 }
645 ?>
646 </div>
647 <?php
648 }
649
650 /**
651 * Display a comment count bubble
652 *
653 * @since 3.1.0
654 * @access protected
655 *
656 * @param int $post_id The post ID.
657 * @param int $pending_comments Number of pending comments.
658 */
659 protected function comments_bubble( $post_id, $pending_comments ) {
660 // translators: %s is the number of pending comments.
661 $pending_phrase = sprintf( __( '%s pending', 'strong-testimonials' ), number_format( $pending_comments ) );
662
663 if ( $pending_comments ) {
664 echo '<strong>';
665 }
666
667 echo "<a href='" . esc_url( add_query_arg( 'p', absint( $post_id ), admin_url( 'edit-comments.php' ) ) ) . "' title='" . esc_attr( $pending_phrase ) . "' class='post-com-count'><span class='comment-count'>" . absint( number_format_i18n( get_comments_number() ) ) . '</span></a>';
668
669 if ( $pending_comments ) {
670 echo '</strong>';
671 }
672 }
673
674 /**
675 * Get the current page number
676 *
677 * @since 3.1.0
678 * @access public
679 *
680 * @return int
681 */
682 public function get_pagenum() {
683 $pagenum = isset( $_REQUEST['paged'] ) ? absint( $_REQUEST['paged'] ) : 0;
684
685 if ( isset( $this->_pagination_args['total_pages'] ) && $pagenum > $this->_pagination_args['total_pages'] ) {
686 $pagenum = $this->_pagination_args['total_pages'];
687 }
688
689 return max( 1, $pagenum );
690 }
691
692 /**
693 * Get number of items to display on a single page
694 *
695 * @since 3.1.0
696 * @access protected
697 *
698 * @param string $option
699 * @param int $default_per_page
700 * @return int
701 */
702 protected function get_items_per_page( $option, $default_per_page = 20 ) {
703 $per_page = (int) get_user_option( $option );
704 if ( empty( $per_page ) || $per_page < 1 ) {
705 $per_page = $default_per_page;
706 }
707
708 /**
709 * Filter the number of items to be displayed on each page of the list table.
710 *
711 * The dynamic hook name, $option, refers to the `per_page` option depending
712 * on the type of list table in use. Possible values include: 'edit_comments_per_page',
713 * 'sites_network_per_page', 'site_themes_network_per_page', 'themes_network_per_page',
714 * 'users_network_per_page', 'edit_post_per_page', 'edit_page_per_page',
715 * 'edit_{$post_type}_per_page', etc.
716 *
717 * @since 2.9.0
718 *
719 * @param int $per_page Number of items to be displayed. Default 20.
720 */
721 return (int) apply_filters( $option, $per_page );
722 }
723
724 /**
725 * Display the pagination.
726 *
727 * @since 3.1.0
728 * @access protected
729 *
730 * @param string $which
731 */
732 protected function pagination( $which ) {
733 if ( empty( $this->_pagination_args ) ) {
734 return;
735 }
736
737 $total_items = $this->_pagination_args['total_items'];
738 $total_pages = $this->_pagination_args['total_pages'];
739 $infinite_scroll = false;
740 if ( isset( $this->_pagination_args['infinite_scroll'] ) ) {
741 $infinite_scroll = $this->_pagination_args['infinite_scroll'];
742 }
743 // translators: %s is the count of pagin ation items.
744 $output = '<span class="displaying-num">' . sprintf( _n( '%s item', '%s items', $total_items, 'strong-testimonials' ), number_format_i18n( $total_items ) ) . '</span>';
745
746 $current = $this->get_pagenum();
747
748 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
749
750 $current_url = remove_query_arg( array( 'hotkeys_highlight_last', 'hotkeys_highlight_first' ), $current_url );
751
752 $page_links = array();
753
754 $disable_first = '';
755 $disable_last = '';
756 if ( 1 === absint( $current ) ) {
757 $disable_first = ' disabled';
758 }
759 if ( absint( $current ) === absint( $total_pages ) ) {
760 $disable_last = ' disabled';
761 }
762 $page_links[] = sprintf(
763 "<a class='%s' title='%s' href='%s'>%s</a>",
764 'first-page' . $disable_first,
765 esc_attr__( 'Go to the first page', 'strong-testimonials' ),
766 esc_url( remove_query_arg( 'paged', $current_url ) ),
767 '&laquo;'
768 );
769
770 $page_links[] = sprintf(
771 "<a class='%s' title='%s' href='%s'>%s</a>",
772 'prev-page' . $disable_first,
773 esc_attr__( 'Go to the previous page', 'strong-testimonials' ),
774 esc_url( add_query_arg( 'paged', max( 1, $current - 1 ), $current_url ) ),
775 '&lsaquo;'
776 );
777
778 if ( 'bottom' === $which ) {
779 $html_current_page = $current;
780 } else {
781 $html_current_page = sprintf(
782 "%s<input class='current-page' id='current-page-selector' title='%s' type='text' name='paged' value='%s' size='%d'>",
783 '<label for="current-page-selector" class="screen-reader-text">' . __( 'Select Page', 'strong-testimonials' ) . '</label>',
784 esc_attr__( 'Current page', 'strong-testimonials' ),
785 $current,
786 strlen( $total_pages )
787 );
788 }
789 $html_total_pages = sprintf( "<span class='total-pages'>%s</span>", number_format_i18n( $total_pages ) );
790 // translators: %1$s is the current page number. %1$s is the total number of pages.
791 $page_links[] = '<span class="paging-input">' . sprintf( _x( '%1$s of %1$s', 'paging', 'strong-testimonials' ), $html_current_page, $html_total_pages ) . '</span>';
792
793 $page_links[] = sprintf(
794 "<a class='%s' title='%s' href='%s'>%s</a>",
795 'next-page' . $disable_last,
796 esc_attr__( 'Go to the next page', 'strong-testimonials' ),
797 esc_url( add_query_arg( 'paged', min( $total_pages, $current + 1 ), $current_url ) ),
798 '&rsaquo;'
799 );
800
801 $page_links[] = sprintf(
802 "<a class='%s' title='%s' href='%s'>%s</a>",
803 'last-page' . $disable_last,
804 esc_attr__( 'Go to the last page', 'strong-testimonials' ),
805 esc_url( add_query_arg( 'paged', $total_pages, $current_url ) ),
806 '&raquo;'
807 );
808
809 $pagination_links_class = 'pagination-links';
810 if ( ! empty( $infinite_scroll ) ) {
811 $pagination_links_class = ' hide-if-js';
812 }
813 $output .= "\n<span class='$pagination_links_class'>" . implode( "\n", $page_links ) . '</span>';
814
815 if ( $total_pages ) {
816 $page_class = $total_pages < 2 ? ' one-page' : '';
817 } else {
818 $page_class = ' no-pages';
819 }
820 $this->_pagination = "<div class='tablenav-pages{$page_class}'>$output</div>";
821
822 echo $this->_pagination;
823 }
824
825 /**
826 * Get a list of columns. The format is:
827 * 'internal-name' => 'Title'
828 *
829 * @since 3.1.0
830 * @access public
831 * @abstract
832 *
833 * @return array
834 */
835 public function get_columns() {
836 die( 'function WP_List_Table::get_columns() must be over-ridden in a sub-class.' );
837 }
838
839 /**
840 * Get a list of sortable columns. The format is:
841 * 'internal-name' => 'orderby'
842 * or
843 * 'internal-name' => array( 'orderby', true )
844 *
845 * The second format will make the initial sorting order be descending
846 *
847 * @since 3.1.0
848 * @access protected
849 *
850 * @return array
851 */
852 protected function get_sortable_columns() {
853 return array();
854 }
855
856 /**
857 * Get a list of all, hidden and sortable columns, with filter applied
858 *
859 * @since 3.1.0
860 * @access protected
861 *
862 * @return array
863 */
864 protected function get_column_info() {
865 if ( isset( $this->_column_headers ) ) {
866 return $this->_column_headers;
867 }
868
869 $columns = get_column_headers( $this->screen );
870 $hidden = get_hidden_columns( $this->screen );
871
872 $sortable_columns = $this->get_sortable_columns();
873 /**
874 * Filter the list table sortable columns for a specific screen.
875 *
876 * The dynamic portion of the hook name, `$this->screen->id`, refers
877 * to the ID of the current screen, usually a string.
878 *
879 * @since 3.5.0
880 *
881 * @param array $sortable_columns An array of sortable columns.
882 */
883 $_sortable = apply_filters( "manage_{$this->screen->id}_sortable_columns", $sortable_columns );
884
885 $sortable = array();
886 foreach ( $_sortable as $id => $data ) {
887 if ( empty( $data ) ) {
888 continue;
889 }
890
891 $data = (array) $data;
892 if ( ! isset( $data[1] ) ) {
893 $data[1] = false;
894 }
895
896 $sortable[ $id ] = $data;
897 }
898
899 $this->_column_headers = array( $columns, $hidden, $sortable );
900
901 return $this->_column_headers;
902 }
903
904 /**
905 * Return number of visible columns
906 *
907 * @since 3.1.0
908 * @access public
909 *
910 * @return int
911 */
912 public function get_column_count() {
913 list ( $columns, $hidden ) = $this->get_column_info();
914 $hidden = array_intersect( array_keys( $columns ), array_filter( $hidden ) );
915 return count( $columns ) - count( $hidden );
916 }
917
918 /**
919 * Print column headers, accounting for hidden and sortable columns.
920 *
921 * @since 3.1.0
922 * @access public
923 *
924 * @param bool $with_id Whether to set the id attribute or not
925 */
926 public function print_column_headers( $with_id = true ) {
927 list( $columns, $hidden, $sortable ) = $this->get_column_info();
928
929 $current_url = set_url_scheme( 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'] );
930 $current_url = remove_query_arg( 'paged', $current_url );
931
932 if ( isset( $_GET['orderby'] ) ) {
933 $current_orderby = sanitize_text_field( wp_unslash( $_GET['orderby'] ) );
934 } else {
935 $current_orderby = '';
936 }
937
938 if ( isset( $_GET['order'] ) && 'desc' === $_GET['order'] ) {
939 $current_order = 'desc';
940 } else {
941 $current_order = 'asc';
942 }
943
944 if ( ! empty( $columns['cb'] ) ) {
945 static $cb_counter = 1;
946 $columns['cb'] = '<label class="screen-reader-text" for="cb-select-all-' . $cb_counter . '">' . esc_html__( 'Select All', 'strong-testimonials' ) . '</label>'
947 . '<input id="cb-select-all-' . $cb_counter . '" type="checkbox">';
948 ++$cb_counter;
949 }
950
951 foreach ( $columns as $column_key => $column_display_name ) {
952 $class = array( 'manage-column', "column-$column_key" );
953
954 $style = '';
955 if ( in_array( $column_key, $hidden, true ) ) {
956 $style = 'display:none;';
957 }
958
959 $style = ' style="' . $style . '"';
960
961 if ( 'cb' === $column_key ) {
962 $class[] = 'check-column';
963 } elseif ( in_array( $column_key, array( 'posts', 'comments', 'links' ), true ) ) {
964 $class[] = 'num';
965 }
966
967 if ( isset( $sortable[ $column_key ] ) ) {
968 list( $orderby, $desc_first ) = $sortable[ $column_key ];
969
970 if ( $current_orderby === $orderby ) {
971 $order = 'asc' === $current_order ? 'desc' : 'asc';
972 $class[] = 'sorted';
973 $class[] = $current_order;
974 } else {
975 $order = $desc_first ? 'desc' : 'asc';
976 $class[] = 'sortable';
977 $class[] = $desc_first ? 'asc' : 'desc';
978 }
979
980 $column_display_name = '<a href="' . esc_url( add_query_arg( compact( 'orderby', 'order' ), $current_url ) ) . '"><span>' . $column_display_name . '</span><span class="sorting-indicator"></span></a>';
981 }
982
983 $id = $with_id ? "id='$column_key'" : '';
984
985 if ( ! empty( $class ) ) {
986 $class = "class='" . implode( ' ', $class ) . "'";
987 }
988
989 echo "<th scope='col' $id $class $style>$column_display_name</th>";
990 }
991 }
992
993 /**
994 * Display the table
995 *
996 * @since 3.1.0
997 * @access public
998 */
999 public function display() {
1000 $singular = $this->_args['singular'];
1001
1002 $this->display_tablenav( 'top' );
1003
1004 ?>
1005 <table class="wp-list-table <?php echo esc_attr( implode( ' ', $this->get_table_classes() ) ); ?>">
1006 <thead>
1007 <tr>
1008 <?php $this->print_column_headers(); ?>
1009 </tr>
1010 </thead>
1011
1012 <tbody id="the-list"
1013 <?php
1014 if ( $singular ) {
1015 echo " data-wp-lists='list:" . esc_attr( $singular ) . "'";
1016 }
1017 ?>
1018 >
1019 <?php $this->display_rows_or_placeholder(); ?>
1020 </tbody>
1021
1022 <tfoot>
1023 <tr>
1024 <?php $this->print_column_headers( false ); ?>
1025 </tr>
1026 </tfoot>
1027
1028 </table>
1029 <?php
1030 $this->display_tablenav( 'bottom' );
1031 }
1032
1033 /**
1034 * Get a list of CSS classes for the list table table tag.
1035 *
1036 * @since 3.1.0
1037 * @access protected
1038 *
1039 * @return array List of CSS classes for the table tag.
1040 */
1041 protected function get_table_classes() {
1042 return array( 'widefat', 'fixed', 'striped', $this->_args['plural'] );
1043 }
1044
1045 /**
1046 * Generate the table navigation above or below the table
1047 *
1048 * @since 3.1.0
1049 * @access protected
1050 * @param string $which
1051 */
1052 protected function display_tablenav( $which ) {
1053 if ( 'top' === $which ) {
1054 wp_nonce_field( 'bulk-' . $this->_args['plural'] );
1055 }
1056 ?>
1057 <div class="tablenav <?php echo esc_attr( $which ); ?>">
1058
1059 <div class="alignleft actions bulkactions">
1060 <?php $this->bulk_actions( $which ); ?>
1061 </div>
1062 <?php
1063 $this->extra_tablenav( $which );
1064 $this->pagination( $which );
1065 ?>
1066
1067 <br class="clear">
1068 </div>
1069 <?php
1070 }
1071
1072 /**
1073 * Extra controls to be displayed between bulk actions and pagination
1074 *
1075 * @since 3.1.0
1076 * @access protected
1077 *
1078 * @param string $which
1079 */
1080 protected function extra_tablenav( $which ) {}
1081
1082 /**
1083 * Generate the tbody element for the list table.
1084 *
1085 * @since 3.1.0
1086 * @access public
1087 */
1088 public function display_rows_or_placeholder() {
1089 if ( $this->has_items() ) {
1090 $this->display_rows();
1091 } else {
1092 echo '<tr class="no-items"><td class="colspanchange" colspan="' . absint( $this->get_column_count() ) . '">';
1093 $this->no_items();
1094 echo '</td></tr>';
1095 }
1096 }
1097
1098 /**
1099 * Generate the table rows
1100 *
1101 * @since 3.1.0
1102 * @access public
1103 */
1104 public function display_rows() {
1105 foreach ( $this->items as $item ) {
1106 $this->single_row( $item );
1107 }
1108 }
1109
1110 /**
1111 * Generates content for a single row of the table
1112 *
1113 * @since 3.1.0
1114 * @access public
1115 *
1116 * @param object $item The current item
1117 */
1118 public function single_row( $item ) {
1119 echo '<tr>';
1120 $this->single_row_columns( $item );
1121 echo '</tr>';
1122 }
1123
1124 protected function column_default( $item, $column_name ) {}
1125
1126 protected function column_cb( $item ) {}
1127
1128 /**
1129 * Generates the columns for a single row of the table
1130 *
1131 * @since 3.1.0
1132 * @access protected
1133 *
1134 * @param object $item The current item
1135 */
1136 protected function single_row_columns( $item ) {
1137 list( $columns, $hidden ) = $this->get_column_info();
1138
1139 foreach ( $columns as $column_name => $column_display_name ) {
1140 $class = "class='$column_name column-$column_name'";
1141
1142 $style = '';
1143 if ( in_array( $column_name, $hidden, true ) ) {
1144 $style = ' style="display:none;"';
1145 }
1146
1147 $attributes = "$class$style";
1148
1149 if ( 'cb' === $column_name ) {
1150 echo '<th scope="row" class="check-column">';
1151 echo $this->column_cb( $item );
1152 echo '</th>';
1153 } elseif ( method_exists( $this, 'column_' . $column_name ) ) {
1154 echo "<td $attributes>";
1155 echo call_user_func( array( $this, 'column_' . $column_name ), $item );
1156 echo '</td>';
1157 } else {
1158 echo "<td $attributes>";
1159 echo $this->column_default( $item, $column_name );
1160 echo '</td>';
1161 }
1162 }
1163 }
1164
1165 /**
1166 * Handle an incoming ajax request (called from admin-ajax.php)
1167 *
1168 * @since 3.1.0
1169 * @access public
1170 */
1171 public function ajax_response() {
1172 $this->prepare_items();
1173
1174 ob_start();
1175 if ( ! empty( $_REQUEST['no_placeholder'] ) ) {
1176 $this->display_rows();
1177 } else {
1178 $this->display_rows_or_placeholder();
1179 }
1180
1181 $rows = ob_get_clean();
1182
1183 $response = array( 'rows' => $rows );
1184
1185 if ( isset( $this->_pagination_args['total_items'] ) ) {
1186 $response['total_items_i18n'] = sprintf(
1187 // translators: %s is the number of items. Singular and plural forms are used.
1188 _n( '%s item', '%s items', $this->_pagination_args['total_items'], 'strong-testimonials' ),
1189 number_format_i18n( $this->_pagination_args['total_items'] )
1190 );
1191 }
1192 if ( isset( $this->_pagination_args['total_pages'] ) ) {
1193 $response['total_pages'] = $this->_pagination_args['total_pages'];
1194 $response['total_pages_i18n'] = number_format_i18n( $this->_pagination_args['total_pages'] );
1195 }
1196
1197 die( wp_json_encode( $response ) );
1198 }
1199
1200 /**
1201 * Send required variables to JavaScript land
1202 *
1203 * @access public
1204 */
1205 public function _js_vars() {
1206 $args = array(
1207 'class' => get_class( $this ),
1208 'screen' => array(
1209 'id' => $this->screen->id,
1210 'base' => $this->screen->base,
1211 ),
1212 );
1213
1214 printf( "<script type='text/javascript'>list_args = %s;</script>\n", wp_json_encode( $args ) );
1215 }
1216 }
1217
1218 endif;