0

I'm using extended WP_List_Table class to output my custom DB data. Facing with a problem - if I search or filter my data, everything works fine, but if I go to the next page or click any sorted header, my data will reset. This happened, because paging and sorting not included search string or filter params ($_REQUEST['s']) and I don't understand, how to include it. If I switch my global table <form> method from POST to GET, it will solve the problem, but because action is empty, whole query string including to action and after 3-4 iteration I will get 414 error (uri too large).

<?php

if ( !class_exists( 'WP_List_Table' ) ) {
    require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
}

class BWCU_List_Table extends WP_List_Table {

    private $_user_fields_mapping = [];

    function __construct( $user_fields_mapping ) {

        $this->_user_fields_mapping = $user_fields_mapping;

        parent::__construct(
            [
                'singular' => 'blacklist',
                'plural'   => 'blacklists',
                'ajax'     => false,
            ]
        );

        add_screen_option(
            'per_page',
            [
                'label'   => __( 'Items per page', 'textdomain' ),
                'default' => 10,
                'option'  => 'per_page',
            ]
        );

    }

    function get_columns() {
        $columns = [
            'cb'        => '<input type="checkbox" />', //Render a checkbox instead of text
            'value'     => __('Name', 'textdomain'),
            'type'      => __('Type', 'textdomain'),
            'reason'    => __('Reason', 'textdomain'),
            'user_id'   => __('User', 'textdomain'),
            'order_id'  => __('Order', 'textdomain'),
            'date'      => __('Date', 'textdomain'),
        ];

        return $columns;
    }

    function column_default( $item, $column_name ) {
        return $item[ $column_name ];
    }

    function column_cb( $item ) {
        return sprintf(
            '<input type="checkbox" name="id[]" value="%s" />',
            $item['ID']
        );
    }

    function column_value( $item ) {
        return $item['value'];
    }

    function column_type( $item ) {
        return $this->_user_fields_mapping[ $item['type'] ]['name'];
    }

    function column_reason( $item ) {
        return $item['reason'];
    }

    function column_user( $item ) {
        $user_data = get_userdata( $item['user_id'] );
        return !empty( $item['user_id'] ) ? sprintf('<a href="%s" target="_blank">%s</a>', get_edit_user_link( $item['user_id'] ), $user_data->user_login ) : '&mdash;';
    }

    function column_order( $item ) {
        return !empty( $item['order_id'] ) ? sprintf('<a href="/wp-admin/post.php?post=%d&action=edit" target="_blank">%s%d</a>', $item['order_id'] , __('Order ', 'textdomain' ), $item['order_id'] ) : '&mdash;';
    }

    function column_date( $item ) {
        return $item['created_at'];
    }

    function process_bulk_action() {
        global $wpdb;

        if ( 'delete' === $this->current_action() ) {
            $ids = isset( $_REQUEST['id'] ) ? $_REQUEST['id'] : [];

            if ( !empty( $ids ) ) {
                $placeholders = array_fill(0, count( $ids ), '%d');
                $wpdb->query(
                    $wpdb->prepare(
                        'DELETE FROM ' . $wpdb->prefix . 'bl_data WHERE id IN(' . implode(', ', $placeholders ) . ')',
                        $ids
                    )
                );
            }
        }
    }

    function prepare_items() {
        global $wpdb;

        $per_page = get_user_meta( get_current_user_id(), get_current_screen()->get_option( 'per_page', 'option' ), true ) ? : 10;
        $columns = $this->get_columns();
        $hidden = [];
        $sortable = $this->get_sortable_columns();

        // here we configure table headers, defined in our methods
        $this->_column_headers = [ $columns, $hidden, $sortable ];

        // [OPTIONAL] process bulk action if any
        $this->process_bulk_action();

        // prepare query params, as usual current page, order by and order direction
        $paged = isset($_REQUEST['paged']) ? max(0, intval($_REQUEST['paged'] - 1) * $per_page) : 0;
        $orderby = (isset($_REQUEST['orderby']) && in_array($_REQUEST['orderby'], array_keys($this->get_sortable_columns()))) ? $_REQUEST['orderby'] : 'value';
        $order = (isset($_REQUEST['order']) && in_array($_REQUEST['order'], array('asc', 'desc'))) ? $_REQUEST['order'] : 'asc';

        $where = $args = [];
        if ( isset( $_REQUEST['s'] ) && !empty( $_REQUEST['s'] ) ) {
            $where[] =  'value LIKE "%%%s%%"';
            $args[] =  $_REQUEST['s'];
        }

        if ( isset( $_REQUEST['filter-type'] ) && !empty( $_REQUEST['filter-type'] ) && ( $_REQUEST['filter-type'] != '0' ) ) {
            $where[] = 'type="%s"';
            $args[] = $_REQUEST['filter-type'];
        }

        $where = !empty( $where ) ? ' WHERE ' . implode(' AND ', $where) : '';
        $total_query = 'SELECT COUNT(*) FROM ' . $wpdb->prefix . 'bl_data' . $where;
        $total_items = $wpdb->get_var( $wpdb->prepare( $total_query, $args ) );

        array_push( $args, $per_page, $paged );

        $query = 'SELECT ID, value, type, reason, order_id, user_id, created_at FROM ' . $wpdb->prefix . 'bl_data' . $where . ' ORDER BY ' . $orderby . ' ' . $order . ' LIMIT %d OFFSET %d';

        $this->items = $wpdb->get_results(
            $wpdb->prepare( $query, $args ),
            ARRAY_A
        );

        $this->set_pagination_args(
            [
                'total_items' => $total_items,
                'per_page' => $per_page,
                'total_pages' => ceil( $total_items / $per_page )
            ]
        );
    }

    function no_items() {
        _e( 'No records found.', 'textdomain' );
    }

    function get_sortable_columns() {
        $sortable_columns = [
            'value' => ['value', true],
            'type' => ['type', false],
            'user_id' => ['user_id', false],
            'order_id' => ['order_id', false],
            'date' => ['date', false],
        ];
        return $sortable_columns;
    }

    function get_bulk_actions() {
        $actions = [
            'delete' => __('Delete', 'textdomain')
        ];
        return $actions;
    }

    function extra_tablenav( $which ) {
        if ( $which == "top" ){
            ?>
            <div class="alignleft actions bulkactions">
                <select name="filter-type" id="filter-by-type">
                    <option value="0">All types</option>
                    <?php foreach ( $this->_user_fields_mapping as $field_id => $field_data ): ?>
                    <?php $selected = ( $_REQUEST['filter-type'] == $field_id ) ? ' selected' : ''; ?>
                    <option value="<?php echo $field_id; ?>"<?php echo $selected; ?>><?php echo $field_data['name']; ?></option>
                    <?php endforeach; ?>
                </select>
                <input type="submit" class="button">
                </div>
                <?php
        }
    }

    function search_box( $text, $input_id ) {
        if ( empty( $_REQUEST['s'] ) && !$this->has_items() ) {
            return;
        }

        $input_id = $input_id . '-search-input';

        if ( ! empty( $_REQUEST['orderby'] ) ) {
            echo '<input type="hidden" name="orderby" value="' . esc_attr( $_REQUEST['orderby'] ) . '" />';
        }

        if ( ! empty( $_REQUEST['order'] ) ) {
            echo '<input type="hidden" name="order" value="' . esc_attr( $_REQUEST['order'] ) . '" />';
        }

        if ( ! empty( $_REQUEST['post_mime_type'] ) ) {
            echo '<input type="hidden" name="post_mime_type" value="' . esc_attr( $_REQUEST['post_mime_type'] ) . '" />';
        }

        if ( ! empty( $_REQUEST['detached'] ) ) {
            echo '<input type="hidden" name="detached" value="' . esc_attr( $_REQUEST['detached'] ) . '" />';
        }
        ?>
        <p class="search-box">
            <label class="screen-reader-text" for="<?php echo $input_id ?>"><?php echo $text; ?>:</label>
            <input type="search" id="<?php echo $input_id ?>" name="s" value="<?php _admin_search_query(); ?>" />
            <?php submit_button( $text, 'button', false, false, ['id' => 'search-submit'] ); ?>
        </p>
        <?php
    }
}
1

2 Answers 2

0

At this moment, the only solution for me is to switch form method to GET and remove _wp_http_referer from $_SERVER['REQUEST_URI'] with remove_query_arg() in prepare_items() function.

More detailed info in this answer.

0

Add the following code just above the prepare_items() function

if ( ! empty( $_REQUEST['_wp_http_referer'] && ! empty( $_SERVER['REQUEST_URI'] ) ) ) {
    $url = esc_url_raw( wp_unslash( $_SERVER['REQUEST_URI'] ) );
    $url = remove_query_arg( array( '_wp_http_referer', '_wpnonce' ), $url );

    wp_safe_redirect( $url );

    exit;
}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.