: str_replace(): Passing null to parameter #2 ($replace) of type array|string is deprecated in
'trash' => esc_html__( 'Move to Trash', 'wpforms-lite' ),
* Generates the table navigation above or below the table.
* @param string $which The location of the bulk actions: 'top' or 'bottom'.
protected function display_tablenav( $which ) {
if ( $this->has_items() ) {
parent::display_tablenav( $which );
echo '<div class="tablenav ' . esc_attr( $which ) . '">';
if ( $this->is_trash_view() ) {
echo '<div class="alignleft actions bulkactions">';
$this->extra_tablenav( $which );
echo '<br class="clear" />';
* List of CSS classes for the "WP_List_Table" table tag.
* @global string $mode List table view mode.
protected function get_table_classes() {
// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
$mode = get_user_setting( 'posts_list_mode', 'list' );
$mode_class = esc_attr( 'table-view-' . $mode );
'wpforms-table-list-payments',
// For styling purposes, we'll add a dedicated class name for determining the number of visible columns.
// The ideal threshold for applying responsive styling is set at "5" columns based on the need for "Tablet" view.
$columns_class = $this->get_column_count() > 5 ? 'many' : 'few';
$classes[] = "has-{$columns_class}-columns";
* Get valid status from request.
private function get_valid_status_from_request() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended, WordPress.Security.ValidatedSanitizedInput.InputNotSanitized, WordPress.Security.ValidatedSanitizedInput.MissingUnslash
return ! empty( $_REQUEST['status'] ) && ( ValueValidator::is_valid( $_REQUEST['status'], 'status' ) || $_REQUEST['status'] === self::TRASH ) ? $_REQUEST['status'] : '';
* Get number of payments for the current status.
* Note that this function also validates the status internally.
private function get_valid_status_count_from_request() {
// Retrieve the current status.
$current_status = $this->get_valid_status_from_request();
return $current_status && isset( $this->counts[ $current_status ] ) ? $this->counts[ $current_status ] : $this->counts['total'];
* Get search where value.
* @param string $search_key Search where key.
* @return string Return default search where value if not valid key provided.
private function get_search_where( $search_key ) {
$allowed_values = $this->get_allowed_search_where();
return $search_key && isset( $allowed_values[ $search_key ] ) ? $allowed_values[ $search_key ] : $allowed_values[ Search::TITLE ];
private function get_search_where_key() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$where_key = isset( $_GET['search_where'] ) ? sanitize_key( $_GET['search_where'] ) : '';
return isset( $this->get_allowed_search_where()[ $where_key ] ) ? $where_key : Search::TITLE;
* Get allowed search where values.
private function get_allowed_search_where() {
if ( ! $search_values ) {
Search::TITLE => __( 'Payment Title', 'wpforms-lite' ),
Search::TRANSACTION_ID => __( 'Transaction ID', 'wpforms-lite' ),
Search::EMAIL => __( 'Customer Email', 'wpforms-lite' ),
Search::SUBSCRIPTION_ID => __( 'Subscription ID', 'wpforms-lite' ),
Search::CREDIT_CARD => __( 'Last 4 digits of credit card', 'wpforms-lite' ),
Search::ANY => __( 'Any payment field', 'wpforms-lite' ),
* Get search where value.
* @param string $mode_key Search mode key.
* @return string Return default search mode value if not valid key provided.
private function get_search_mode( $mode_key ) {
$allowed_modes = $this->get_allowed_search_modes();
return $mode_key && isset( $allowed_modes[ $mode_key ] ) ? $allowed_modes[ $mode_key ] : $allowed_modes[ Search::MODE_EQUALS ];
private function get_search_mode_key() {
// phpcs:ignore WordPress.Security.NonceVerification.Recommended
$where_mode = isset( $_GET['search_mode'] ) ? sanitize_key( $_GET['search_mode'] ) : '';
return isset( $this->get_allowed_search_modes()[ $where_mode ] ) ? $where_mode : Search::MODE_CONTAINS;
* Get allowed search mode params.
private function get_allowed_search_modes() {
Search::MODE_CONTAINS => __( 'contains', 'wpforms-lite' ),
Search::MODE_EQUALS => __( 'equals', 'wpforms-lite' ),
Search::MODE_STARTS => __( 'starts with', 'wpforms-lite' ),
private function setup_counts() {
// Define the general views with their respective arguments.
// Generate filterable status views with their respective arguments.
foreach ( ValueValidator::get_allowed_one_time_statuses() as $status => $label ) {
// Calculate the counts for each view and store them in the $this->counts array.
foreach ( $views as $status => $status_args ) {
$this->counts[ $status ] = wpforms()->get( 'payment_queries' )->count_all( array_merge( $this->table_query_args, $status_args ) );
// If the current view is the trash view, set the 'total' count to the 'trash' count.
if ( $this->is_trash_view() ) {
$this->counts['total'] = $this->counts['trash'];
// Otherwise, set the 'total' count to the 'published' count.
$this->counts['total'] = $this->counts['published'];
private function get_order_by() {
// phpcs:disable WordPress.Security.NonceVerification.Recommended
if ( ! isset( $_GET['orderby'] ) ) {
if ( $_GET['orderby'] === 'date' ) {
return 'date_updated_gmt';
if ( $_GET['orderby'] === 'total' ) {
// phpcs:enable WordPress.Security.NonceVerification.Recommended
* Get payment column value.
* @param array $item Payment item.
private function get_column_title( array $item ) {
$title = $this->get_payment_title( $item );
$na_status = empty( $title ) ? sprintf( '<span class="payment-title-is-empty">- %s</span>', Helpers::get_placeholder_na_text() ) : '';
if ( ! $item['is_published'] ) {
return sprintf( '<span>#%1$d %2$s</span> %3$s', $item['id'], esc_html( $title ), $na_status );
$single_url = add_query_arg(
'page' => 'wpforms-payments',
'payment_id' => absint( $item['id'] ),
return sprintf( '<a href="%1$s">#%2$d %3$s</a> %4$s', esc_url( $single_url ), $item['id'], esc_html( $title ), $na_status );
* @param array $item Payment item.
private function get_column_date( $item ) {
$date = $item['date_updated_gmt'];
$timestamp = strtotime( $date );
/* translators: %s - relative time difference, e.g. "5 minutes", "12 days". */
$human = sprintf( esc_html__( '%s ago', 'wpforms-lite' ), human_time_diff( $timestamp ) );
return sprintf( '<span title="%s">%s</span>', gmdate( 'Y-m-d H:i', $timestamp ), $human );
* Get gateway column value.
* @param array $item Payment item.
private function get_column_gateway( array $item ) {
if ( ! isset( $item['gateway'] ) || ! ValueValidator::is_valid( $item['gateway'], 'gateway' ) ) {
return ValueValidator::get_allowed_gateways()[ $item['gateway'] ];
* Get total column value.
* @param array $item Payment item.
private function get_column_total( array $item ) {
return esc_html( $this->get_formatted_amount_from_item( $item ) );
* @param array $item Payment item.
private function get_column_form( array $item ) {
// Display "N/A" placeholder text if the form is not found or not published.
if ( empty( $item['form_id'] ) || get_post_status( $item['form_id'] ) !== 'publish' ) {
return Helpers::get_placeholder_na_text();
$form = wpforms()->get( 'form' )->get( $item['form_id'] );
if ( ! $form || $form->post_status !== 'publish' ) {
return Helpers::get_placeholder_na_text();
// Display the form name with a link to the form builder.
$name = ! empty( $form->post_title ) ? $form->post_title : $form->post_name;
remove_query_arg( 'paged' )
return sprintf( '<a href="%s">%s</a>', esc_url( $url ), wp_kses_post( $name ) );
* Get status column value.
* @param array $item Payment item.
private function get_column_status( array $item ) {
if ( ! isset( $item['status'] ) || ! ValueValidator::is_valid( $item['status'], 'status' ) ) {
return Helpers::get_placeholder_na_text();
'<span class="wpforms-payment-status status-%1$s">%2$s</span>',
strtolower( $item['status'] ),
$item['status'] === 'partrefund' ? __( '% Refunded', 'wpforms-lite' ) : ValueValidator::get_allowed_statuses()[ $item['status'] ]
* Get subscription column value.
* @param array $item Payment item.
private function get_column_subscription( array $item ) {
if ( $item['type'] === self::ONE_TIME ) {
return Helpers::get_placeholder_na_text();
$amount = $this->get_formatted_amount_from_item( $item );
$description = Helpers::get_subscription_description( $item['id'], $amount );
$status = $this->get_subscription_status( $item );
'<span class="wpforms-subscription-status status-%1$s" title="%2$s">%3$s</span>',
sanitize_html_class( $status ),
$status ? ValueValidator::get_allowed_subscription_statuses()[ $status ] : '',
* @param array $item Payment item.
private function get_column_type( array $item ) {
if ( ! isset( $item['type'] ) || ! ValueValidator::is_valid( $item['type'], 'type' ) ) {
return Helpers::get_placeholder_na_text();
return ValueValidator::get_allowed_types()[ $item['type'] ];
* Show the coupon code used for the payment.
* If the coupon code is not found, show N/A.
* @param array $item Payment item.
private function get_column_coupon( $item ) {
$payment_meta = wpforms()->get( 'payment_meta' )->get_all( $item['id'] );
// If the coupon info is empty, show N/A.
if ( empty( $payment_meta['coupon_info'] ) || empty( $payment_meta['coupon_id'] ) ) {
return Helpers::get_placeholder_na_text();
$payment_meta['coupon_id']->value,
remove_query_arg( 'paged' )
'<a href="%1$s" aria-label="%2$s">%3$s</a>',
esc_attr__( 'Filter entries by coupon', 'wpforms-lite' ),
esc_html( $this->get_coupon_name_by_info( $payment_meta['coupon_info']->value ) )