PluginProbe ʕ •ᴥ•ʔ
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin / 4.9.0
WP Mail SMTP by WPForms – The Most Popular SMTP and Email Log Plugin v4.9.0
4.9.0 0.9.6 1.0.0 1.0.1 1.0.2 1.1.0 1.2.0 1.2.1 1.2.2 1.2.3 1.2.4 1.2.5 1.3.0 1.3.1 1.3.2 1.3.3 1.4.0 1.4.1 1.4.2 1.5.0 1.5.1 1.5.2 1.6.0 1.6.2 1.7.0 1.7.1 1.8.0 1.8.1 1.9.0 2.0.0 2.0.1 2.1.1 2.2.1 2.3.1 2.4.0 2.5.0 2.5.1 2.6.0 2.7.0 2.8.0 2.9.0 3.0.1 3.0.2 3.0.3 3.1.0 3.10.0 3.11.0 3.11.1 3.2.0 3.2.1 3.3.0 3.4.0 3.5.0 3.5.1 3.5.2 3.6.1 3.7.0 3.8.0 3.8.2 3.9.0 4.0.1 4.1.0 4.1.1 4.2.0 4.3.0 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.8.0 trunk 0.10.0 0.10.1 0.11.1 0.11.2 0.3.1 0.3.2 0.4 0.4.1 0.4.2 0.5.0 0.5.1 0.5.2 0.6 0.7 0.8 0.8.2 0.8.3 0.8.4 0.8.5 0.8.6 0.8.7 0.9.0 0.9.1 0.9.2 0.9.3 0.9.4 0.9.5
wp-mail-smtp / src / Admin / DebugEvents / Table.php
wp-mail-smtp / src / Admin / DebugEvents Last commit date
DebugEvents.php 6 days ago Event.php 6 days ago EventsCollection.php 6 days ago Migration.php 6 days ago Table.php 6 days ago
Table.php
583 lines
1 <?php
2
3 namespace WPMailSMTP\Admin\DebugEvents;
4
5 use WPMailSMTP\Helpers\Helpers;
6
7 if ( ! class_exists( 'WP_List_Table', false ) ) {
8 require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
9 }
10
11 /**
12 * Class Table that displays the list of debug events.
13 *
14 * @since 3.0.0
15 */
16 class Table extends \WP_List_Table {
17
18 /**
19 * Number of debug events by different types.
20 *
21 * @since 3.0.0
22 *
23 * @var array
24 */
25 public $counts;
26
27 /**
28 * Set up a constructor that references the parent constructor.
29 * Using the parent reference to set some default configs.
30 *
31 * @since 3.0.0
32 */
33 public function __construct() {
34
35 // Set parent defaults.
36 parent::__construct(
37 [
38 'singular' => 'event',
39 'plural' => 'events',
40 'ajax' => false,
41 ]
42 );
43
44 // Include polyfill if mbstring PHP extension is not enabled.
45 if ( ! function_exists( 'mb_substr' ) || ! function_exists( 'mb_strlen' ) ) {
46 Helpers::include_mbstring_polyfill();
47 }
48 }
49
50 /**
51 * Get the debug event types for filtering purpose.
52 *
53 * @since 3.0.0
54 *
55 * @return array Associative array of debug event types StatusCode=>Name.
56 */
57 public function get_types() {
58
59 return Event::get_types();
60 }
61
62 /**
63 * Get the items counts for various types of debug logs.
64 *
65 * @since 3.0.0
66 */
67 public function get_counts() {
68
69 $this->counts = [];
70
71 // Base params with applied filters.
72 $base_params = $this->get_filters_query_params();
73
74 $total_params = $base_params;
75 unset( $total_params['type'] );
76 $this->counts['total'] = ( new EventsCollection( $total_params ) )->get_count();
77
78 foreach ( $this->get_types() as $type => $name ) {
79 $collection = new EventsCollection( array_merge( $base_params, [ 'type' => $type ] ) );
80
81 $this->counts[ 'type_' . $type ] = $collection->get_count();
82 }
83
84 /**
85 * Filters items counts by various types of debug events.
86 *
87 * @since 3.0.0
88 *
89 * @param array $counts {
90 * Items counts by types.
91 *
92 * @type integer $total Total items count.
93 * @type integer $status_{$type_key} Items count by type.
94 * }
95 */
96 $this->counts = apply_filters( 'wp_mail_smtp_admin_debug_events_table_get_counts', $this->counts );
97 }
98
99 /**
100 * Retrieve the view types.
101 *
102 * @since 3.0.0
103 */
104 public function get_views() {
105
106 $base_url = $this->get_filters_base_url();
107 $current_type = $this->get_filtered_types();
108
109 $views = [];
110
111 $views['all'] = sprintf(
112 '<a href="%1$s" %2$s>%3$s&nbsp;<span class="count">(%4$d)</span></a>',
113 esc_url( remove_query_arg( 'type', $base_url ) ),
114 $current_type === false ? 'class="current"' : '',
115 esc_html__( 'All', 'wp-mail-smtp' ),
116 intval( $this->counts['total'] )
117 );
118
119 foreach ( $this->get_types() as $type => $type_label ) {
120
121 $count = intval( $this->counts[ 'type_' . $type ] );
122
123 // Skipping types with no events.
124 if ( $count === 0 && $current_type !== $type ) {
125 continue;
126 }
127
128 $views[ $type ] = sprintf(
129 '<a href="%1$s" %2$s>%3$s&nbsp;<span class="count">(%4$d)</span></a>',
130 esc_url( add_query_arg( 'type', $type, $base_url ) ),
131 $current_type === $type ? 'class="current"' : '',
132 esc_html( $type_label ),
133 $count
134 );
135
136 }
137
138 /**
139 * Filters debug event item views.
140 *
141 * @since 3.0.0
142 *
143 * @param array $views {
144 * Debug event items views by types.
145 *
146 * @type string $all Total items view.
147 * @type integer $status_key Items views by type.
148 * }
149 * @param array $counts {
150 * Items counts by types.
151 *
152 * @type integer $total Total items count.
153 * @type integer $status_{$status_key} Items count by types.
154 * }
155 */
156 return apply_filters( 'wp_mail_smtp_admin_debug_events_table_get_views', $views, $this->counts );
157 }
158
159 /**
160 * Define the table columns.
161 *
162 * @since 3.0.0
163 *
164 * @return array Associative array of slug=>Name columns data.
165 */
166 public function get_columns() {
167
168 return [
169 'event' => esc_html__( 'Event', 'wp-mail-smtp' ),
170 'type' => esc_html__( 'Type', 'wp-mail-smtp' ),
171 'content' => esc_html__( 'Content', 'wp-mail-smtp' ),
172 'initiator' => esc_html__( 'Source', 'wp-mail-smtp' ),
173 'created_at' => esc_html__( 'Date', 'wp-mail-smtp' ),
174 ];
175 }
176
177 /**
178 * Display the main event title with a link to open event details.
179 *
180 * @since 3.0.0
181 *
182 * @param Event $item Event object.
183 *
184 * @return string
185 */
186 public function column_event( $item ) {
187
188 return '<strong>' .
189 '<a href="#" data-event-id="' . esc_attr( $item->get_id() ) . '"' .
190 ' class="js-wp-mail-smtp-debug-event-preview row-title event-preview" title="' . esc_attr( $item->get_title() ) . '">' .
191 esc_html( $item->get_title() ) .
192 '</a>' .
193 '</strong>';
194 }
195
196 /**
197 * Display event's type.
198 *
199 * @since 3.0.0
200 *
201 * @param Event $item Event object.
202 *
203 * @return string
204 */
205 public function column_type( $item ) {
206
207 return esc_html( $item->get_type_name() );
208 }
209
210 /**
211 * Display event's content.
212 *
213 * @since 3.0.0
214 *
215 * @param Event $item Event object.
216 *
217 * @return string
218 */
219 public function column_content( $item ) {
220
221 $content = $item->get_content();
222
223 if ( mb_strlen( $content ) > 100 ) {
224 $content = mb_substr( $content, 0, 100 ) . '...';
225 }
226
227 return wp_kses_post( $content );
228 }
229
230 /**
231 * Display event's wp_mail initiator.
232 *
233 * @since 3.0.0
234 *
235 * @param Event $item Event object.
236 *
237 * @return string
238 */
239 public function column_initiator( $item ) {
240
241 return esc_html( $item->get_initiator() );
242 }
243
244 /**
245 * Display event's created date.
246 *
247 * @since 3.0.0
248 *
249 * @param Event $item Event object.
250 *
251 * @return string
252 */
253 public function column_created_at( $item ) {
254
255 return $item->get_created_at_formatted();
256 }
257
258 /**
259 * Return type filter value or FALSE.
260 *
261 * @since 3.0.0
262 *
263 * @return bool|integer
264 */
265 public function get_filtered_types() {
266
267 if ( ! isset( $_REQUEST['type'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
268 return false;
269 }
270
271 return intval( $_REQUEST['type'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
272 }
273
274 /**
275 * Return date filter value or FALSE.
276 *
277 * @since 3.0.0
278 *
279 * @return bool|array
280 */
281 public function get_filtered_dates() {
282
283 if ( empty( $_REQUEST['date'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
284 return false;
285 }
286
287 $dates = (array) explode( ' - ', sanitize_text_field( wp_unslash( $_REQUEST['date'] ) ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
288
289 return array_map( 'sanitize_text_field', $dates );
290 }
291
292 /**
293 * Return search filter values or FALSE.
294 *
295 * @since 3.0.0
296 *
297 * @return bool|array
298 */
299 public function get_filtered_search() {
300
301 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
302 if ( empty( $_REQUEST['search'] ) ) {
303 return false;
304 }
305
306 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
307 return sanitize_text_field( wp_unslash( $_REQUEST['search'] ) );
308 }
309
310 /**
311 * Whether the event log is filtered or not.
312 *
313 * @since 3.0.0
314 *
315 * @return bool
316 */
317 public function is_filtered() {
318
319 $is_filtered = false;
320
321 if (
322 $this->get_filtered_search() !== false ||
323 $this->get_filtered_dates() !== false ||
324 $this->get_filtered_types() !== false
325 ) {
326 $is_filtered = true;
327 }
328
329 return $is_filtered;
330 }
331
332 /**
333 * Get current filters query parameters.
334 *
335 * @since 3.0.0
336 *
337 * @return array
338 */
339 public function get_filters_query_params() {
340
341 $params = [
342 'search' => $this->get_filtered_search(),
343 'type' => $this->get_filtered_types(),
344 'date' => $this->get_filtered_dates(),
345 ];
346
347 return array_filter(
348 $params,
349 function ( $v ) {
350 return $v !== false;
351 }
352 );
353 }
354
355 /**
356 * Get current filters base url.
357 *
358 * @since 3.0.0
359 *
360 * @return string
361 */
362 public function get_filters_base_url() {
363
364 $base_url = DebugEvents::get_page_url();
365 $filters_params = $this->get_filters_query_params();
366
367 if ( isset( $filters_params['search'] ) ) {
368 $base_url = add_query_arg( 'search', $filters_params['search'], $base_url );
369 }
370
371 if ( isset( $filters_params['type'] ) ) {
372 $base_url = add_query_arg( 'type', $filters_params['type'], $base_url );
373 }
374
375 if ( isset( $filters_params['date'] ) ) {
376 $base_url = add_query_arg( 'date', implode( ' - ', $filters_params['date'] ), $base_url );
377 }
378
379 return $base_url;
380 }
381
382 /**
383 * Get the data, prepare pagination, process bulk actions.
384 * Prepare columns for display.
385 *
386 * @since 3.0.0
387 */
388 public function prepare_items() {
389
390 // Retrieve count.
391 $this->get_counts();
392
393 // Prepare all the params to pass to our Collection. All sanitization is done in that class.
394 $params = $this->get_filters_query_params();
395
396 // Total amount for pagination with WHERE clause - super quick count DB request.
397 $total_items = ( new EventsCollection( $params ) )->get_count();
398
399 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
400 if ( ! empty( $_REQUEST['orderby'] ) && in_array( $_REQUEST['orderby'], [ 'event', 'type', 'content', 'initiator', 'created_at' ], true ) ) {
401 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
402 $params['orderby'] = sanitize_key( $_REQUEST['orderby'] );
403 }
404
405 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
406 if ( ! empty( $_REQUEST['order'] ) ) {
407 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
408 $params['order'] = strtoupper( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) === 'DESC' ? 'DESC' : 'ASC';
409 }
410
411 $params['offset'] = ( $this->get_pagenum() - 1 ) * EventsCollection::$per_page;
412
413 // Get the data from the DB using parameters defined above.
414 $collection = new EventsCollection( $params );
415 $this->items = $collection->get();
416
417 /*
418 * Register our pagination options & calculations.
419 */
420 $this->set_pagination_args(
421 [
422 'total_items' => $total_items,
423 'per_page' => EventsCollection::$per_page,
424 ]
425 );
426 }
427
428 /**
429 * Display the search box.
430 *
431 * @since 1.7.0
432 *
433 * @param string $text The 'submit' button label.
434 * @param string $input_id ID attribute value for the search input field.
435 */
436 public function search_box( $text, $input_id ) {
437
438 if ( ! $this->is_filtered() && ! $this->has_items() ) {
439 return;
440 }
441
442 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
443 $search = ! empty( $_REQUEST['search'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search'] ) ) : '';
444
445 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
446 if ( ! empty( $_REQUEST['orderby'] ) && in_array( $_REQUEST['orderby'], [ 'event', 'type', 'content', 'initiator', 'created_at' ], true ) ) {
447 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
448 $order_by = sanitize_text_field( wp_unslash( $_REQUEST['orderby'] ) );
449 echo '<input type="hidden" name="orderby" value="' . esc_attr( $order_by ) . '" />';
450 }
451
452 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
453 if ( ! empty( $_REQUEST['order'] ) ) {
454 // phpcs:ignore WordPress.Security.NonceVerification.Recommended
455 $order = strtoupper( sanitize_text_field( wp_unslash( $_REQUEST['order'] ) ) ) === 'DESC' ? 'DESC' : 'ASC';
456 echo '<input type="hidden" name="order" value="' . esc_attr( $order ) . '" />';
457 }
458 ?>
459
460 <p class="search-box">
461 <label class="screen-reader-text" for="<?php echo esc_attr( $input_id ); ?>"><?php echo esc_html( $text ); ?>:</label>
462 <input type="search" id="<?php echo esc_attr( $input_id ); ?>" name="search" value="<?php echo esc_attr( $search ); ?>" />
463 <?php submit_button( $text, '', '', false, [ 'id' => 'search-submit' ] ); ?>
464 </p>
465
466 <?php
467 }
468
469 /**
470 * Whether the table has items to display or not.
471 *
472 * @since 3.0.0
473 *
474 * @return bool
475 */
476 public function has_items() {
477
478 return count( $this->items ) > 0;
479 }
480
481 /**
482 * Message to be displayed when there are no items.
483 *
484 * @since 3.0.0
485 */
486 public function no_items() {
487
488 if ( $this->is_filtered() ) {
489 esc_html_e( 'No events found.', 'wp-mail-smtp' );
490 } else {
491 esc_html_e( 'No events have been logged for now.', 'wp-mail-smtp' );
492 }
493 }
494
495 /**
496 * Displays the table.
497 *
498 * @since 3.0.0
499 */
500 public function display() {
501
502 $this->_column_headers = [ $this->get_columns(), [], [] ];
503
504 parent::display();
505 }
506
507 /**
508 * Hide the tablenav if there are no items in the table.
509 * And remove the bulk action nonce and code.
510 *
511 * @since 3.0.0
512 *
513 * @param string $which Which tablenav: top or bottom.
514 */
515 protected function display_tablenav( $which ) {
516
517 if ( ! $this->has_items() ) {
518 return;
519 }
520 ?>
521
522 <div class="tablenav <?php echo esc_attr( $which ); ?>">
523
524 <?php
525 $this->extra_tablenav( $which );
526 $this->pagination( $which );
527 ?>
528
529 <br class="clear" />
530 </div>
531 <?php
532 }
533
534 /**
535 * Extra controls to be displayed between bulk actions and pagination.
536 *
537 * @since 3.0.0
538 *
539 * @param string $which Which tablenav: top or bottom.
540 */
541 protected function extra_tablenav( $which ) {
542
543 if ( $which !== 'top' || ! $this->has_items() ) {
544 return;
545 }
546
547 $date = $this->get_filtered_dates() !== false ? implode( ' - ', $this->get_filtered_dates() ) : '';
548 ?>
549 <div class="alignleft actions wp-mail-smtp-filter-date">
550
551 <input type="text" name="date" class="regular-text wp-mail-smtp-filter-date-selector wp-mail-smtp-filter-date__control"
552 placeholder="<?php esc_attr_e( 'Select a date range', 'wp-mail-smtp' ); ?>"
553 value="<?php echo esc_attr( $date ); ?>">
554
555 <button type="submit" name="action" value="filter_date" class="button wp-mail-smtp-filter-date__btn">
556 <?php esc_html_e( 'Filter', 'wp-mail-smtp' ); ?>
557 </button>
558
559 </div>
560 <?php
561 if ( current_user_can( wp_mail_smtp()->get_capability_manage_options() ) ) {
562 wp_nonce_field( 'wp_mail_smtp_debug_events', 'wp-mail-smtp-debug-events-nonce', false );
563 printf(
564 '<button id="wp-mail-smtp-delete-all-debug-events-button" type="button" class="button">%s</button>',
565 esc_html__( 'Delete All Events', 'wp-mail-smtp' )
566 );
567 }
568 }
569
570 /**
571 * Get the name of the primary column.
572 * Important for the mobile view.
573 *
574 * @since 3.0.0
575 *
576 * @return string The name of the primary column.
577 */
578 protected function get_primary_column_name() {
579
580 return 'event';
581 }
582 }
583