Current File : /home/resuelf/www/wp-content/plugins/aawp/src/ActivityLogs/ListTable.php |
<?php
namespace AAWP\ActivityLogs;
use WP_List_Table;
if ( ! class_exists( 'WP_List_Table' ) ) {
require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php';
}
/**
* Class ListTable.
*
* @since 3.19
*/
class ListTable extends WP_List_Table {
/**
* DB Class.
*
* @var \AAWP\ActivityLogs\DB DB.
*/
private $db;
/**
* ListTable constructor.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\DB $db DB.
*/
public function __construct( $db ) {
$this->db = $db;
parent::__construct(
[
'plural' => esc_html__( 'Logs', 'aawp' ),
'singular' => esc_html__( 'Log', 'aawp' ),
]
);
}
/**
* Prepare table list items.
*
* @global wpdb $wpdb
*/
public function prepare_items() {
if ( ! $this->db->is_logging_enabled() ) {
return;
}
global $wpdb;
$this->prepare_column_headers();
$per_page = $this->get_items_per_page( 'aawp_log_items_per_page', 15 );
$where = $this->get_items_query_where();
$order = $this->get_items_query_order();
$limit = $this->get_items_query_limit();
$offset = $this->get_items_query_offset();
$query_items = "
SELECT id, timestamp, user_id, component, level, message, context
FROM {$wpdb->prefix}aawp_logs
{$where} {$order} {$limit} {$offset}
";
$this->items = $wpdb->get_results( $query_items ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.DirectDatabaseQuery.DirectQuery
$total_items = $this->get_total();
$this->set_pagination_args(
[
'total_items' => $total_items,
'per_page' => $per_page,
'total_pages' => ceil( $total_items / $per_page ),
]
);
}
/**
* Get prepared LIMIT clause for items query
*
* @global wpdb $wpdb
*
* @return string Prepared LIMIT clause for items query.
*/
protected function get_items_query_limit() {
global $wpdb;
$per_page = $this->get_items_per_page( 'aawp_log_items_per_page', 15 );
return $wpdb->prepare( 'LIMIT %d', $per_page );
}
/**
* Get prepared OFFSET clause for items query
*
* @global wpdb $wpdb
*
* @return string Prepared OFFSET clause for items query.
*/
protected function get_items_query_offset() {
global $wpdb;
$per_page = $this->get_items_per_page( 'aawp_log_items_per_page', 15 );
$current_page = $this->get_pagenum();
if ( 1 < $current_page ) {
$offset = $per_page * ( $current_page - 1 );
} else {
$offset = 0;
}
return $wpdb->prepare( 'OFFSET %d', $offset );
}
/**
* Get prepared ORDER BY clause for items query
*
* @return string Prepared ORDER BY clause for items query.
*/
protected function get_items_query_order() {
$valid_orders = [ 'id', 'component', 'timestamp', 'user_id' ];
if ( ! empty( $_REQUEST['orderby'] ) && in_array( $_REQUEST['orderby'], $valid_orders, true ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$by = sanitize_sql_orderby( wp_unslash( $_REQUEST['orderby'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
} else {
$by = 'timestamp';
}
$by = esc_sql( $by );
if ( ! empty( $_REQUEST['order'] ) && 'asc' === strtolower( $_REQUEST['order'] ) ) { // phpcs:ignore
$order = 'ASC';
} else {
$order = 'DESC';
}
return "ORDER BY {$by} {$order}, id {$order}";
}
/**
* Column id.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_id( $item ) {
return absint( $item->id );
}
/**
* Column date.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_timestamp( $item ) {
return esc_html( $item->timestamp ) . ' (' . human_time_diff( strtotime( $item->timestamp ) ) . ' ago )';
}
/**
* Column level.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_level( $item ) {
return absint( $item->level );
}
/**
* Column User ID.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_user( $item ) {
$user_id = absint( $item->user_id );
if ( 0 !== $user_id ) {
$user = get_user_by( 'id', $user_id );
$email = ! empty( $user->user_email ) ? $user->user_email : 'User ID: ' . $user_id;
$roles = ! empty( $user->roles ) && is_array( $user->roles ) ? implode( ',', $user->roles ) : '';
return ! empty( $roles ) ? $email . ' (' . ucfirst( $roles ) . ')' : $email;
}
return esc_html__( 'System', 'aawp' );
}
/**
* Column log_component.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_component( $item ) {
return ! empty( $item->component ) ? esc_html( $item->component ) : '';
}
/**
* Column message.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_message( $item ) {
return ! empty( $item->message ) ? wp_kses_post( $item->message ) : '';
}
/**
* Column context.
*
* @since 3.19
*
* @param \AAWP\ActivityLogs\Log $item List table item.
*
* @return int|string
*/
public function column_context( $item ) {
return ! empty( $item->context ) ? $item->context : '';
}
/**
* Get a list of sortable columns.
*
* @return array
*/
protected function get_sortable_columns() {
return [
'id' => [ 'id', 'asc' ],
'timestamp' => [ 'timestamp', 'asc' ],
'component' => [ 'level', 'asc' ],
'user' => [ 'user', 'asc' ],
'source' => [ 'source', 'asc' ],
];
}
/**
* Prepares the _column_headers property which is used by WP_Table_List at rendering.
* It merges the columns and the sortable columns.
*
* @since 3.19
*/
private function prepare_column_headers() {
$this->_column_headers = [
$this->get_columns(),
[],
$this->get_sortable_columns(),
];
}
/**
* Returns the columns names for rendering.
*
* @since 3.19
*
* @return array
*/
public function get_columns() {
return apply_filters(
'aawp_activity_logs_get_columns',
[
'id' => __( 'ID', 'aawp' ),
'timestamp' => __( 'Timestamp', 'aawp' ),
'user' => __( 'User', 'aawp' ),
'component' => __( 'Component', 'aawp' ),
'message' => __( 'Message', 'aawp' ),
]
);
}
/**
* Display component dropdown
*
* @global wpdb $wpdb
*/
public function component_dropdown() {
$components = [
[
'value' => 'licensing',
'label' => __( ' Licensing', 'aawp' ),
],
[
'value' => 'aawp',
'label' => __( 'AAWP API', 'aawp' ),
],
[
'value' => 'amazon',
'label' => __( 'Amazon API', 'aawp' ),
],
[
'value' => 'settings',
'label' => __( 'Settings', 'aawp' ),
],
[
'value' => 'product',
'label' => __( 'Product', 'aawp' ),
],
[
'value' => 'plugin',
'label' => __( 'Plugin Update', 'aawp' ),
],
];
$selected_component = isset( $_REQUEST['component'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['component'] ) ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
?>
<label for="filter-by-component" class="screen-reader-text"><?php esc_html_e( 'Filter by component', 'aawp' ); ?></label>
<select name="component" id="filter-by-component">
<option<?php selected( $selected_component, '' ); ?> value=""><?php esc_html_e( 'All components', 'aawp' ); ?></option>
<?php
foreach ( $components as $comp ) {
printf(
'<option%1$s value="%2$s">%3$s</option>',
selected( $selected_component, $comp['value'], false ),
esc_attr( $comp['value'] ),
esc_html( $comp['label'] )
);
}
?>
</select>
<?php
}
/**
* Display date selector
*
* @since 3.19
*
* @return mixed HTML output
*/
protected function date_select() {
?>
<label for="start-date" class="screen-reader-text"><?php esc_html_e( 'Start date', 'aawp' ); ?></label>
<?php if ( ! empty( $_GET['startdate'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
<input placeholder="<?php esc_attr_e( 'Start date', 'aawp' ); ?>" name="startdate" id="start-date" type="date" value="<?php echo esc_attr( wp_unslash( $_GET['startdate'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>" />
<?php else : ?>
<input placeholder="<?php esc_attr_e( 'Start date', 'aawp' ); ?>" name="startdate" id="start-date" type="text" onfocus="(this.type='date')" />
<?php endif; ?>
<label for="end-date" class="screen-reader-text"><?php esc_html_e( 'End date', 'aawp' ); ?></label>
<?php if ( ! empty( $_GET['enddate'] ) ) : // phpcs:ignore WordPress.Security.NonceVerification.Recommended ?>
<input placeholder="<?php esc_attr_e( 'End date', 'aawp' ); ?>" name="enddate" id="end-date" type="date" value="<?php echo esc_attr( wp_unslash( $_GET['enddate'] ) ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized ?>" />
<?php else : ?>
<input placeholder="<?php esc_attr_e( 'End date', 'aawp' ); ?>" name="enddate" id="end-date" type="text" onfocus="(this.type='date')" />
<?php endif; ?>
<?php
}
/**
* Generate the table navigation above or below the table.
*
* @since 3.19
*
* @param string $which Which position.
*/
protected function display_tablenav( $which ) {
if ( ! $this->get_total() ) {
return;
}
?>
<div class="tablenav <?php echo esc_attr( $which ); ?>">
<?php
if ( 'top' === $which ) {
$this->extra_tablenav( $which );
$this->clear_all();
}
$this->pagination( $which );
?>
<br class="clear" />
</div>
<?php
}
/**
* Table list actions.
*
* @since 3.19
*
* @param string $which Position of navigation (top or bottom).
*/
protected function extra_tablenav( $which ) {
$this->component_dropdown();
$this->date_select();
submit_button( esc_html__( 'Filter', 'aawp' ), '', 'filter-action', false );
}
/**
* No items text.
*
* @since 3.19
*/
public function no_items() {
if ( ! $this->db->is_logging_enabled() ) {
esc_html_e( 'Activity Logging is currently disabled. Please enable logging to start saving logs in the database.', 'aawp' );
} else {
esc_html_e( 'No logs found.', 'aawp' );
}
}
/**
* Clear all log logs.
*
* @since 3.19
*/
private function clear_all() {
?>
<button
name="clear-all"
type="submit"
class="button"
value="1"><?php esc_html_e( 'Delete All Logs', 'aawp' ); ?></button>
<?php
}
/**
* Display list table page.
*
* @since 3.19
*/
public function render_page() {
$this->prepare_column_headers();
$this->process_admin_ui();
$this->prepare_items();
echo '<div class="aawp-list-table aawp-list-table--logs">';
echo '<form action="admin.php?page=aawp-logs" id="' . esc_attr( $this->_args['plural'] ) . '-filter" method="post">';
parent::display();
echo wp_nonce_field( 'aawp_logs_listtable_actions' ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
echo '</form>';
echo '</div>';
}
/**
* Get prepared WHERE clause for items query
*
* @global wpdb $wpdb
*
* @return string Prepared WHERE clause for items query.
*/
protected function get_items_query_where() {
global $wpdb;
$where_conditions = [];
$where_values = [];
if ( ! empty( $_REQUEST['component'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$where_conditions[] = 'component LIKE %s';
$where_values[] = '%' . $wpdb->esc_like( sanitize_text_field( wp_unslash( $_REQUEST['component'] ) ) ) . '%'; // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
if ( ! empty( $_REQUEST['startdate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$where_conditions[] = 'timestamp > %s';
$where_values[] = sanitize_text_field( $_REQUEST['startdate'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
if ( ! empty( $_REQUEST['enddate'] ) ) { // phpcs:ignore WordPress.Security.NonceVerification.Recommended
$where_conditions[] = 'timestamp < %s';
$where_values[] = sanitize_text_field( $_REQUEST['enddate'] ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended
}
if ( ! empty( $where_conditions ) ) {
return $wpdb->prepare( 'WHERE 1 = 1 AND ' . implode( ' AND ', $where_conditions ), $where_values ); // phpcs:ignore WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare
} else {
return '';
}
}
/**
* Update URL when table showing.
* _wp_http_referer is used only on bulk actions, we remove it to keep the $_GET shorter.
*
* @since 3.19
*/
public function process_admin_ui() {
if ( empty( $_REQUEST['_wpnonce'] ) ) {
return;
}
$verify = wp_verify_nonce( sanitize_key( wp_unslash( $_REQUEST['_wpnonce'] ) ), 'aawp_logs_listtable_actions' );
//phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! empty( $_REQUEST['clear-all'] ) && $verify ) {
$this->db->clear_all();
}
//phpcs:enable WordPress.Security.NonceVerification.Recommended
}
/**
* Check if the database table exist.
*
* @since 3.19
*
* @return bool
*/
public function table_exists() {
return $this->db->table_exists();
}
/**
* Get total logs.
*
* @since 3.19
*
* @return int
*/
public function get_total() {
return $this->db->get_total();
}
}