From 44ab680fe1143b4d76388de038338dff35686365 Mon Sep 17 00:00:00 2001 From: Corey McKrill <916023+coreymckrill@users.noreply.github.com> Date: Mon, 11 Dec 2023 12:27:26 -0800 Subject: [PATCH] Logging: Fix pagination and filtering on DB log list table (#41870) Fixes some issues where pagination and filters were not persisting in the DB log list table view after running a bulk action. Also adds a way to customize the number of log entries shown per page. Fixes #39359 --- .../changelog/fix-39359-db-log-pagination | 4 ++ .../admin/class-wc-admin-log-table-list.php | 31 +++++++++- .../includes/admin/class-wc-admin-menus.php | 1 + .../includes/admin/class-wc-admin-status.php | 57 +++++++++++++++---- .../views/html-admin-page-status-logs-db.php | 34 ++++++----- .../Internal/Admin/Logging/PageController.php | 28 +++++++-- 6 files changed, 120 insertions(+), 35 deletions(-) create mode 100644 plugins/woocommerce/changelog/fix-39359-db-log-pagination diff --git a/plugins/woocommerce/changelog/fix-39359-db-log-pagination b/plugins/woocommerce/changelog/fix-39359-db-log-pagination new file mode 100644 index 00000000000..a9b13b6571d --- /dev/null +++ b/plugins/woocommerce/changelog/fix-39359-db-log-pagination @@ -0,0 +1,4 @@ +Significance: minor +Type: fix + +Fix problems with pagination and filtering for the database logger list table view diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-log-table-list.php b/plugins/woocommerce/includes/admin/class-wc-admin-log-table-list.php index 07fa5748cb2..9ab804d05a7 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-log-table-list.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-log-table-list.php @@ -17,6 +17,12 @@ if ( ! class_exists( 'WP_List_Table' ) ) { } class WC_Admin_Log_Table_List extends WP_List_Table { + /** + * The key for the user option of how many list table items to display per page. + * + * @const string + */ + public const PER_PAGE_USER_OPTION_KEY = 'woocommerce_status_log_items_per_page'; /** * Initialize the log table list. @@ -330,7 +336,10 @@ class WC_Admin_Log_Table_List extends WP_List_Table { $this->prepare_column_headers(); - $per_page = $this->get_items_per_page( 'woocommerce_status_log_items_per_page', 10 ); + $per_page = $this->get_items_per_page( + self::PER_PAGE_USER_OPTION_KEY, + $this->get_per_page_default() + ); $where = $this->get_items_query_where(); $order = $this->get_items_query_order(); @@ -367,7 +376,11 @@ class WC_Admin_Log_Table_List extends WP_List_Table { protected function get_items_query_limit() { global $wpdb; - $per_page = $this->get_items_per_page( 'woocommerce_status_log_items_per_page', 10 ); + $per_page = $this->get_items_per_page( + self::PER_PAGE_USER_OPTION_KEY, + $this->get_per_page_default() + ); + return $wpdb->prepare( 'LIMIT %d', $per_page ); } @@ -381,7 +394,10 @@ class WC_Admin_Log_Table_List extends WP_List_Table { protected function get_items_query_offset() { global $wpdb; - $per_page = $this->get_items_per_page( 'woocommerce_status_log_items_per_page', 10 ); + $per_page = $this->get_items_per_page( + self::PER_PAGE_USER_OPTION_KEY, + $this->get_per_page_default() + ); $current_page = $this->get_pagenum(); if ( 1 < $current_page ) { $offset = $per_page * ( $current_page - 1 ); @@ -457,4 +473,13 @@ class WC_Admin_Log_Table_List extends WP_List_Table { $this->get_sortable_columns(), ); } + + /** + * Helper to get the default value for the per_page arg. + * + * @return int + */ + public function get_per_page_default(): int { + return 20; + } } diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-menus.php b/plugins/woocommerce/includes/admin/class-wc-admin-menus.php index 53e914007ff..ee648728ca6 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-menus.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-menus.php @@ -326,6 +326,7 @@ class WC_Admin_Menus { 'woocommerce_webhooks_per_page', FileListTable::PER_PAGE_USER_OPTION_KEY, SearchListTable::PER_PAGE_USER_OPTION_KEY, + WC_Admin_Log_Table_List::PER_PAGE_USER_OPTION_KEY, ); if ( in_array( $option, $screen_options, true ) ) { diff --git a/plugins/woocommerce/includes/admin/class-wc-admin-status.php b/plugins/woocommerce/includes/admin/class-wc-admin-status.php index e30dd2cdc57..3ec0e4cb351 100644 --- a/plugins/woocommerce/includes/admin/class-wc-admin-status.php +++ b/plugins/woocommerce/includes/admin/class-wc-admin-status.php @@ -15,6 +15,12 @@ defined( 'ABSPATH' ) || exit; * WC_Admin_Status Class. */ class WC_Admin_Status { + /** + * An instance of the DB log handler list table. + * + * @var WC_Admin_Log_Table_List + */ + private static $db_log_list_table; /** * Handles output of the reports page in admin. @@ -133,15 +139,17 @@ class WC_Admin_Status { * Show the log page contents for db log handler. */ public static function status_logs_db() { - if ( ! empty( $_REQUEST['flush-logs'] ) ) { // WPCS: input var ok, CSRF ok. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce handled in flush_db_logs(). + if ( isset( $_REQUEST['flush-logs'] ) ) { self::flush_db_logs(); } - if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['log'] ) ) { // WPCS: input var ok, CSRF ok. + // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- Nonce handled in log_table_bulk_actions(). + if ( isset( $_REQUEST['action'] ) && isset( $_REQUEST['log'] ) ) { self::log_table_bulk_actions(); } - $log_table_list = new WC_Admin_Log_Table_List(); + $log_table_list = self::get_db_log_list_table(); $log_table_list->prepare_items(); include_once __DIR__ . '/views/html-admin-page-status-logs-db.php'; @@ -306,20 +314,38 @@ class WC_Admin_Status { exit(); } + /** + * Return a stored instance of the DB log list table class. + * + * @return WC_Admin_Log_Table_List + */ + public static function get_db_log_list_table() { + if ( is_null( self::$db_log_list_table ) ) { + self::$db_log_list_table = new WC_Admin_Log_Table_List(); + } + + return self::$db_log_list_table; + } + + /** * Clear DB log table. * * @since 3.0.0 */ private static function flush_db_logs() { - if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-status-logs' ) ) { // WPCS: input var ok, sanitization ok. - wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) ); + check_admin_referer( 'bulk-logs' ); + + if ( ! current_user_can( 'manage_woocommerce' ) ) { + wp_die( esc_html__( 'You do not have permission to manage log entries.', 'woocommerce' ) ); } WC_Log_Handler_DB::flush(); - wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) ); - exit(); + $sendback = wp_sanitize_redirect( admin_url( 'admin.php?page=wc-status&tab=logs' ) ); + + wp_safe_redirect( $sendback ); + exit; } /** @@ -328,15 +354,22 @@ class WC_Admin_Status { * @since 3.0.0 */ private static function log_table_bulk_actions() { - if ( empty( $_REQUEST['_wpnonce'] ) || ! wp_verify_nonce( $_REQUEST['_wpnonce'], 'woocommerce-status-logs' ) ) { // WPCS: input var ok, sanitization ok. - wp_die( esc_html__( 'Action failed. Please refresh the page and retry.', 'woocommerce' ) ); + check_admin_referer( 'bulk-logs' ); + + if ( ! current_user_can( 'manage_woocommerce' ) ) { + wp_die( esc_html__( 'You do not have permission to manage log entries.', 'woocommerce' ) ); } - $log_ids = array_map( 'absint', (array) isset( $_REQUEST['log'] ) ? wp_unslash( $_REQUEST['log'] ) : array() ); // WPCS: input var ok, sanitization ok. + $log_ids = (array) filter_input( INPUT_GET, 'log', FILTER_CALLBACK, array( 'options' => 'absint' ) ); - if ( ( isset( $_REQUEST['action'] ) && 'delete' === $_REQUEST['action'] ) || ( isset( $_REQUEST['action2'] ) && 'delete' === $_REQUEST['action2'] ) ) { // WPCS: input var ok, sanitization ok. + $action = self::get_db_log_list_table()->current_action(); + + if ( 'delete' === $action ) { WC_Log_Handler_DB::delete( $log_ids ); - wp_safe_redirect( esc_url_raw( admin_url( 'admin.php?page=wc-status&tab=logs' ) ) ); + + $sendback = remove_query_arg( array( 'action', 'action2', 'log', '_wpnonce', '_wp_http_referer' ), wp_get_referer() ); + + wp_safe_redirect( $sendback ); exit(); } } diff --git a/plugins/woocommerce/includes/admin/views/html-admin-page-status-logs-db.php b/plugins/woocommerce/includes/admin/views/html-admin-page-status-logs-db.php index 594013a104c..3ac07ecc410 100644 --- a/plugins/woocommerce/includes/admin/views/html-admin-page-status-logs-db.php +++ b/plugins/woocommerce/includes/admin/views/html-admin-page-status-logs-db.php @@ -9,16 +9,29 @@ if ( ! defined( 'ABSPATH' ) ) { exit; } +$delete_confirmation_js = sprintf( + "return window.confirm( '%s' )", + esc_js( __( 'Are you sure you want to clear all logs from the database?', 'woocommerce' ) ) +); ?> -
- search_box( __( 'Search logs', 'woocommerce' ), 'log' ); ?> - display(); ?> - + - - + search_box( __( 'Search logs', 'woocommerce' ), 'log' ); ?> + display(); ?> + + esc_attr( $delete_confirmation_js ), + ) + ); + ?>
-get_query_params( array( 'view' ) ); + $params = $this->get_query_params( array( 'view' ) ); + $handler = $this->get_default_handler(); + $list_table = null; - if ( in_array( $params['view'], array( 'list_files', 'search_results' ), true ) ) { - $list_table = $this->get_list_table( $params['view'] ); + switch ( $handler ) { + case LogHandlerFileV2::class: + if ( in_array( $params['view'], array( 'list_files', 'search_results' ), true ) ) { + $list_table = $this->get_list_table( $params['view'] ); + } + break; + case 'WC_Log_Handler_DB': + $list_table = WC_Admin_Status::get_db_log_list_table(); + break; + } + if ( $list_table instanceof WP_List_Table ) { // Ensure list table columns are initialized early enough to enable column hiding, if available. $list_table->prepare_column_headers(); @@ -448,6 +461,11 @@ class PageController { * @return void */ private function handle_list_table_bulk_actions(): void { + // Bail if we're not using the file handler. + if ( LogHandlerFileV2::class !== $this->get_default_handler() ) { + return; + } + $params = $this->get_query_params( array( 'file_id', 'view' ) ); // Bail if this is not the list table view.