emailResender = $emailResender; $this->columnManager = new WPML_ColumnManager(); } function addActionsAndFilters() { add_action( 'admin_init', array( $this, 'init') ); add_action( 'current_screen', [ $this, 'process' ] ); add_filter( 'wp_mail_logging_admin_logs_localize_strings', [ $this, 'add_localize_strings' ] ); } function init() { global $status, $page, $hook_suffix; parent::__construct( array( 'singular' => 'email', // singular name of the listed records 'plural' => 'emails',// plural name of the listed records 'ajax' => false, // does this table support ajax? ) ); } /** * Process user actions. * * @since 1.11.0 * * @param \WP_Screen $current_screen Current \WP_Screen object. * * @return void */ public function process( $current_screen ) { global $wp_logging_list_page; if ( $current_screen->id !== $wp_logging_list_page ) { return; } $this->process_action(); $this->add_notices(); add_filter( 'removable_query_args', [ $this, 'removable_query_args' ] ); } /** * Process action the admin initiated. * * @since 1.11.0 * @since 1.13.0 Updated the user capability check. * * @return void */ public function process_action() { $current_action = $this->current_action(); if ( empty( $current_action ) || ! in_array( $current_action, self::ALLOWED_ACTIONS ) ) { return; } if ( ! WPML_Utils::can_current_user_access_wp_mail_logging_submissions() ) { return; } $results = 0; if ( ! empty( $_GET[ self::SINGLE_LOG_ACTION_NONCE ] ) && check_admin_referer( self::SINGLE_LOG_ACTION_NONCE, self::SINGLE_LOG_ACTION_NONCE ) && ! empty( $_GET['email_log_id'] ) ) { // Number of logs we tried to perform action. $attempt_action_logs = 1; $process_single_action = $this->process_single_log_action( absint( $_GET['email_log_id'] ), $current_action ); if ( $process_single_action ) { $results = 1; } } else { $process_bulk_action = $this->process_bulk_action( true ); $results = ! empty( $process_bulk_action['success'] ) ? $process_bulk_action['success'] : 0; $attempt_action_logs = ! empty( $process_bulk_action['attempt'] ) ? $process_bulk_action['attempt'] : 0; } // Action redirect args. $action_redirect = [ 'delete' => 'deleted', 'resend' => 'resent' ]; wp_safe_redirect( add_query_arg( [ $action_redirect[ $current_action ] => absint( $results ), 'attempt_log_count' => absint( $attempt_action_logs ), ], remove_query_arg( [ 'action', 'action2', '_wpnonce', 'email_log_id', 'paged', '_wp_http_referer', 'wp-mail-logging-single-log-action-nonce' ] ) ) ); exit; } /** * Add notices for performed action. * * @since 1.11.0 * * @return void */ public function add_notices() { $deleted = filter_input( INPUT_GET, 'deleted', FILTER_VALIDATE_INT ); $resent = filter_input( INPUT_GET, 'resent', FILTER_VALIDATE_INT ); $attempt_log_count = filter_input( INPUT_GET, 'attempt_log_count', FILTER_VALIDATE_INT ); // If nothing was attempted to performed. if ( empty( $attempt_log_count ) ) { return; } if ( ! is_null( $deleted ) ) { if ( $deleted === 0 ) { $this->add_notice( _n( 'Unable to delete email log.', 'Unable to delete email logs.', $attempt_log_count, 'wp-mail-logging' ), 'error' ); return; } if ( $deleted === $attempt_log_count ) { if ( $deleted === 1 ) { $notice_message = __( 'Email log was successfully deleted.', 'wp-mail-logging' ); } else { $notice_message = sprintf( /* translators: %d: Number of email logs that was successfully deleted. */ _n( '%d email log was successfully deleted.', '%d email logs were successfully deleted!', $deleted, 'wp-mail-logging' ), $deleted ); } $this->add_notice( $notice_message, 'success' ); return; } $this->add_notice( _n( 'One of the emails failed to be deleted.', 'Some emails failed to be deleted.', $attempt_log_count - $deleted, 'wp-mail-logging' ), 'warning' ); return; } if ( ! is_null( $resent ) ) { if ( $resent === 0 ) { $this->add_notice( _n( 'Unable to add email to the sending queue.', 'Unable to add emails to the sending queue.', $attempt_log_count, 'wp-mail-logging' ), 'error' ); return; } if ( $resent === $attempt_log_count ) { if ( $resent === 1 ) { $notice_message = __( 'Email was added to the sending queue.', 'wp-mail-logging' ); } else { $notice_message = sprintf( /* translators: %d: Number of email logs that was added to the sending queue. */ _n( '%d email was added to the sending queue.', '%d emails were added to the sending queue.', $resent, 'wp-mail-logging' ), $resent ); } $this->add_notice( $notice_message ); return; } $this->add_notice( _n( 'One email failed to be added to the sending queue.', 'Some emails failed to be added to the sending queue.', $attempt_log_count - $resent, 'wp-mail-logging' ), 'warning' ); } } /** * Remove certain arguments from a query string that WordPress should always hide for users. * * @since 1.11.0 * * @param array $removable_query_args An array of parameters to remove from the URL. * * @return array Extended/filtered array of parameters to remove from the URL. */ public function removable_query_args( $removable_query_args ) { $removable_query_args[] = 'deleted'; $removable_query_args[] = 'resent'; $removable_query_args[] = 'attempt_log_count'; $removable_query_args[] = 'email'; $removable_query_args[] = 'wpml-list_table_nonce'; return $removable_query_args; } /** * Add the single log action nonce and the current page URL in * the localized strings. * * @since 1.11.0 * * @param array $data Data to be localized for JS usage. * * @return array */ public function add_localize_strings( $data ) { $data[ 'single_log_action_nonce' ] = wp_create_nonce( self::SINGLE_LOG_ACTION_NONCE ); $data[ 'single_log_action_key' ] = self::SINGLE_LOG_ACTION_NONCE; $data[ 'admin_email_logs_url' ] = $this->get_page_base_url(); return $data; } /** * Is displayed if no item is available to render * @since 1.0 * @see WP_List_Table::no_items() */ function no_items() { _e( 'No email found.', 'wp-mail-logging' ); return; } public function get_views() { $views = []; // Get base url. $email_log_page_url = $this->get_page_base_url(); foreach ( Email_Log_Collection::get_statuses() as $status => $label ) { $views[ $status ] = sprintf( '%3$s (%4$d)', esc_url( add_query_arg( 'status', $status, $email_log_page_url ) ), $this->get_current_status() == $status ? 'class="current"' : '', esc_html( $label ), absint( $this->statuses_counts[ $status ] ) ); } return $views; } /** * Get the base URL of the WP Mail Logging page. * * @since 1.11.0 * * @return string */ private function get_page_base_url() { return add_query_arg( 'page', 'wpml_plugin_log', WPML_Utils::get_admin_page_url() ); } /** * Defines the available columns. * * @since 1.0 * @since 1.11.0 Handle attachments column. * * @see WP_List_Table::get_columns() */ function get_columns() { $settings = SettingsTab::get_settings([]); $columns = array_merge(['cb' => ''], $this->columnManager->getColumns(), $this->get_actions_column() ); if ( empty( $settings['display-host'] ) ) { unset( $columns['host'] ); } if ( empty( $settings['display-attachments'] ) ) { unset( $columns['attachments'] ); } return $columns; } /** * Column to display in mobile. * * @since 1.11.0 * * @inerhitDoc */ protected function get_primary_column_name() { return WPML_ColumnManager::COLUMN_TIMESTAMP; } /** * The actions column. * * @since 1.11.0 * * @return string[] */ private function get_actions_column() { return [ 'actions' => '' ]; } /** * Define which columns are hidden * @since 1.0 * @return array */ function get_hidden_columns() { return array( 'plugin_version', 'mail_id', ); } /** * Sanitize orderby parameter. * @s * @return string sanitized orderby parameter */ private function sanitize_orderby() { $allowed = array_keys( $this->get_sortable_columns() ); return WPML_Utils::sanitize_expected_value( ( ! empty( $_GET['orderby'] ) ) ? $_GET['orderby'] : null, $allowed, 'mail_id' ); } /** * Sanitize order parameter. * @return string sanitized order parameter */ private function sanitize_order() { return WPML_Utils::sanitize_expected_value( ( !empty( $_GET['order'] ) ) ? $_GET['order'] : null, array('desc', 'asc'), 'desc'); } /** * Prepares the items for rendering * @since 1.0 * @param string|boolean $search string you want to search for. Default false. * @see WP_List_Table::prepare_items() */ function prepare_items( $search = false ) { $columns = $this->get_columns(); $hidden = $this->get_hidden_columns(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $per_page = $this->get_items_per_page( 'per_page', 25 ); $search_place = ! empty( $_REQUEST['search']['place'] ) ? sanitize_key( $_REQUEST['search']['place'] ) : ''; $search = ! empty( $_REQUEST['search']['term'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search']['term'] ) ) : $search; $log_collection = new Email_Log_Collection( Mail::get_table(), Mail::get_searchable_fields() ); $log_collection->search( $search )->search_place( $search_place ); $this->statuses_counts = $log_collection->get_statuses_count(); $this->items = $log_collection->status( $this->get_current_status() ) ->sort_by( $this->sanitize_orderby() ) ->order( $this->sanitize_order() ) ->limit( $per_page ) ->offset( ( $this->get_pagenum() - 1 ) * $per_page ) ->find_list(); $this->set_pagination_args( [ 'total_items' => $log_collection->count()->find_list(), // The total number of items. 'per_page' => $per_page, // Number of items per page. ] ); } /** * Display the search box. * * @since 1.12.0 * * @param string $text The 'submit' button label. * @param string $input_id ID attribute value for the search input field. */ public function search_box( $text, $input_id ) { if ( ! $this->has_items() ) { return; } $search_place = ! empty( $_REQUEST['search']['place'] ) ? sanitize_key( $_REQUEST['search']['place'] ) : 'people'; $search_term = ! empty( $_REQUEST['search']['term'] ) ? sanitize_text_field( wp_unslash( $_REQUEST['search']['term'] ) ) : ''; if ( ! empty( $_REQUEST['orderby'] ) && in_array( $_REQUEST['orderby'], [ 'timestamp', 'host', 'receiver', 'subject' ], true ) ) { echo ''; } if ( ! empty( $_REQUEST['order'] ) ) { $order = strtoupper( sanitize_key( $_REQUEST['order'] ) ); $order = $order === 'ASC' ? 'ASC' : 'DESC'; echo ''; } $columns = $this->columnManager->getColumns(); $columns['message'] = __( 'Message', 'wp-mail-logging' ); ?>
'search-submit' ) ); ?>
$v ) { // Check if we need to remove host or attachment. if ( ( $v === 'host' && empty( $settings['display-host'] ) ) || ( $v === 'attachments' && empty( $settings['display-attachments'] ) ) ) { unset( $searchable_fields[ $k ] ); } } return $searchable_fields; } /** * Process action for a single log. * * @since 1.11.0 * * @param int $email_log_id Email Log ID in context. * @param string $action Action to perform. * * @return bool */ private function process_single_log_action( $email_log_id, $action ) { if ( empty( $email_log_id ) ) { return false; } $perform_action = $this->perform_action( $email_log_id, $action ); if ( is_wp_error( $perform_action ) || ! $perform_action ) { return false; } return true; } /** * Perform an action to an email log. * * @since 1.11.0 * * @param int $email_log_id Email Log ID in context. * @param string $action Action to perform to a mail. * * @return bool|\WP_Error Returns WP_Error when provided `$action` is invalid. * Otherwise returns a `bool` of whether the Mail is found or not. */ private function perform_action( $email_log_id, $action ) { if ( ! in_array( $action, [ 'delete', 'resend' ], true ) ) { return new \WP_Error( 'wp-mail-logging-invalid-action', __( 'Invalid request!', 'wp-mail-logging' ) ); } $mail = Mail::find_one( $email_log_id ); if ( $mail === false ) { return false; } switch ( $action ) { case 'delete': return $mail->delete(); case 'resend': $this->resend_email( $mail ); break; default: return false; } return true; } /** * Processes bulk actions. * * @since 1.0 * @since 1.11.0 Add first argument which is a bool whether to return a value or not. * * @param bool $return_info Whether to return a value or not. Default `false`. * * @return void|array */ function process_bulk_action( $return_info = false ) { if ( false === $this->current_action() ) { return; } if ( ! check_admin_referer( WPML_Email_Log_List::NONCE_LIST_TABLE, WPML_Email_Log_List::NONCE_LIST_TABLE . '_nonce' ) || ! in_array( $this->current_action(), [ 'delete', 'resend' ], true ) ) { return; } // Holds the number of Mail attempted to perform action with. $attempted_action_counter = 0; // Holds the number of successful actions performed. $successful_action_counter = 0; $current_action = $this->current_action(); // Loop through each of the item. foreach ( $_REQUEST[ $this->_args['singular'] ] as $item_id ) { $attempted_action_counter++; $perform_action = $this->perform_action( $item_id, $current_action ); if ( is_wp_error( $perform_action ) ) { continue; } if ( $perform_action ) { $successful_action_counter++; } } // For backward compatibility. if ( ! $return_info ) { return; } return [ 'success' => $successful_action_counter, 'attempt' => $attempted_action_counter, ]; } /** * Add notice to notices container. * * @since 1.11.0 * * @param string $message Notice message. * @param string $type Notice type. Default 'info'. * * @return void */ private function add_notice( $message, $type = 'info' ) { $this->notices[] = [ 'type' => $type, 'message' => $message, ]; } /** * Get the current status of email logs to display. * * @since 1.11.0 * * @return mixed */ private function get_current_status() { if ( ! is_null( $this->current_status ) ) { return $this->current_status; } // Get the current status. $current_status = filter_input( INPUT_GET, 'status', FILTER_SANITIZE_NUMBER_INT ); if ( empty( $current_status ) || ! array_key_exists( $current_status, Email_Log_Collection::get_statuses() ) ) { $current_status = Email_Log_Collection::STATUS_ALL; } $this->current_status = $current_status; return $this->current_status; } /** * Renders the cell. * @since 1.0 * @param array $item The current item. * @param string $column_name The current column name. * @return string The cell content */ function column_default( $item, $column_name ) { if ( $column_name === 'actions' ) { return $this->display_actions_icons( $item['mail_id'] ); } return ( new SanitizedColumnDecorator( $this->columnManager->getColumnRenderer( $column_name ) ) )->render( $item, ColumnFormat::FULL ); } /** * Display the action icons in the column. * * @since 1.11.0 * * @param int $email_log_id Email Log ID. * * @return string */ private function display_actions_icons( $email_log_id ) { $assets_url = WPML_Init::getInstance()->getService( 'plugin' )->get_assets_url(); $view_title = sprintf( /* * translators: %d: Email Log ID to view. */ __( 'View log #%d', 'wp-mail-logging' ), $email_log_id ); $resend_title = sprintf( /* * translators: %d: Email Log ID to resend. */ __( 'Resend log #%d', 'wp-mail-logging' ), $email_log_id ); $delete_title = sprintf( /* * translators: %d: Email Log ID to delete. */ __( 'Delete log #%d', 'wp-mail-logging' ), $email_log_id ); return '