Opened 3 years ago
#54720 new defect (bug)
WP_List_Table Inside Metabox With Bulk Actions Not Working on Submit
Reported by: | muhammadfaizanhaidar | Owned by: | |
---|---|---|---|
Milestone: | Awaiting Review | Priority: | normal |
Severity: | normal | Version: | 5.8.2 |
Component: | Posts, Post Types | Keywords: | 2nd-opinion needs-dev-note |
Focuses: | Cc: |
Description
I'm trying to display a WP_List_table inside a metabox. The metabox is for questions which are from assessment_question custom post type.The metabox is being displayed on an other custom post type 'cs_questionnaire'. The table columns display some data taken from questions. Also I am using bulk actions to link questions to a questionnaire.
What's happening is that it all looks fine until I click the Publish/Update button on the custom post type edit screen. If the WP_List_Table has bulk actions it will redirect back to the /wp-admin/edit.php page, if I remove the bulk actions then it Works fine. And in both cases, the nonce stays the same and no extra nonce is created.
I've whole code below. I have already overridden the display_tablenav function by commenting the nonce generating code. It stops working when I provide bulk actions else it works fine with the following code.
<?php /** * Generates The User Grade Listing for Admin */ if ( ! class_exists( 'WP_List_Table' ) ) { require_once ABSPATH . 'wp-admin/includes/class-wp-list-table.php'; } class Class_Conditional_Shortcode_Questions_Listing extends WP_List_Table { // define dataset for WP_List_Table => data /** Class constructor */ public function __construct() { parent::__construct( array( 'singular' => __( 'Question', 'conditional-shortcode' ), // singular name of the listed records 'plural' => __( 'Questions', 'conditional-shortcode' ), // plural name of the listed records 'ajax' => false, // does this table support ajax? ) ); } /** * Function to filter data based on order , order_by & searched items * * @param string $orderby * @param string $order * @param string $search_term * @return array $users_array() */ public function list_table_data_fun( $orderby = '', $order = '', $search_term = '' ) { $args = array(); $questions_array = array(); $questions = ''; $flag = false; if ( ! empty( $search_term ) ) { $args = array( 'fields' => 'ids', 'orderby' => $orderby, 'order' => $order, 'search' => intval( sanitize_text_field( $_REQUEST['s'] ) ), 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); } else { if ( $order == 'asc' && $orderby == 'id' ) { $args = array( 'orderby' => 'ID', 'order' => 'ASC', 'fields' => 'ids', 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); } elseif ( $order == 'desc' && $orderby == 'id' ) { $args = array( 'orderby' => 'ID', 'order' => 'DESC', 'fields' => 'ids', 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); } elseif ( $order == 'desc' && $orderby == 'title' ) { $args = array( 'orderby' => 'name', 'order' => 'DESC', 'fields' => 'ids', 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); } elseif ( $order == 'asc' && $orderby == 'title' ) { $args = array( 'orderby' => 'name', 'order' => 'ASC', 'fields' => 'ids', 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); } else { $args = array( 'orderby' => 'ID', 'order' => 'DESC', 'fields' => 'ids', 'post_type' => 'assessment_question', 'posts_per_page' => -1, ); $flag = true; } } $questions = get_transient( 'pd_questions' ); if ( $flag == false ) { $questions = get_posts( $args ); } elseif ( $flag == true && ! $questions ) { $questions = get_posts( $args ); set_transient( 'pd_questions', $questions, 1 * DAY_IN_SECONDS ); } if ( count( $questions ) > 0 ) { foreach ( $questions as $question_id ) { $question = get_post_meta( $question_id ?? 0, CONDITIONAL_SHORTCODE_ASSESSMENT_QUESTION_META, true )['question'] ?? 'NA'; $questions_array[] = array( 'id' => $question_id, 'title' => '<b>' . get_the_title( $question_id ) . '</b>', 'question' => $question, ); } } return $questions_array; } // prepare_items public function prepare_items() { $orderby = sanitize_text_field( isset( $_GET['orderby'] ) ? trim( $_GET['orderby'] ) : '' ); $order = sanitize_text_field( isset( $_GET['order'] ) ? trim( $_GET['order'] ) : '' ); $search_term = sanitize_text_field( isset( $_POST['s'] ) ? trim( $_POST['s'] ) : '' ); if ( $search_term == '' ) { $search_term = sanitize_text_field( isset( $_GET['s'] ) ? trim( $_GET['s'] ) : '' ); } $datas = $this->list_table_data_fun( $orderby, $order, $search_term ); $per_page = 30; $current_page = $this->get_pagenum(); $total_items = count( $datas ); $this->set_pagination_args( array( 'total_items' => $total_items, 'per_page' => $per_page, ) ); $this->items = array_slice( $datas, ( ( $current_page - 1 ) * $per_page ), $per_page ); $columns = $this->get_columns(); $hidden = $this->get_hidden_columns(); $sortable = $this->get_sortable_columns(); $this->_column_headers = array( $columns, $hidden, $sortable ); $this->process_bulk_action(); } public function get_bulk_actions() { return array( 'add_questions' => __( 'Add Questions', 'conditional-shortcode' ), 'remove_questions' => __( 'Remove Questions', 'conditional-shortcode' ), ); } // get_columns public function get_columns() { $columns = array( 'cb' => '<input type="checkbox" />', 'id' => __( 'ID', 'conditional-shortcode' ), 'title' => __( 'Title', 'conditional-shortcode' ), 'question' => __( 'Questions', 'conditional-shortcode' ), 'action' => __( 'Action', 'conditional-shortcode' ), ); return $columns; } public function get_hidden_columns() { return array( '' ); } public function get_sortable_columns() { return array( 'title' => array( 'title', true ), 'id' => array( 'id', true ), ); } /** * Generate the table navigation above or below the table. * * @since 3.1.0 * @access protected * * @param string $which */ protected function display_tablenav( $which ) { // REMOVED NONCE -- INTERFERING WITH SAVING POSTS ON METABOXES // Add better detection if this class is used on meta box or not. /* if ( 'top' == $which ) { wp_nonce_field( 'bulk-' . $this->_args['plural'] ); } */ ?> <div class="tablenav <?php echo esc_attr( $which ); ?>"> <div class="alignleft actions bulkactions"> <?php $this->bulk_actions( $which ); ?> </div> <?php $this->extra_tablenav( $which ); $this->pagination( $which ); ?> <br class="clear"/> </div> <?php } // column_default public function column_default( $item, $column_name ) { $post_id = get_the_ID(); switch ( $column_name ) { case 'cb': case 'id': case 'title': case 'question': return $item[ $column_name ]; case 'action': return '<a href="?post=' . $post_id . '&action=edit&action1=add_question&question_id=' . $item['id'] . '&questionnaire_id=' . $post_id . '">Add Question</a>'; default: return 'no value'; } } public function column_title( $item ) { $post_id = get_the_ID(); $action = array( 'edit' => sprintf( '<a href="?post=%d&action=%s&action1=%s&question_id=%d&questionnaire_id=%d">Add Question</a>', $post_id, 'edit', 'add_question', $item['id'], $post_id ), ); return sprintf( '%1$s %2$s', $item['title'], $this->row_actions( $action ) ); } function column_cb( $item ) { return sprintf( '<input type="checkbox" name="add-questions[]" value="%d" />', $item['id'] ); } function no_items() { esc_html_e( 'No Questions Found.', 'conditional-shortcode' ); } public function process_bulk_action() { // security check! if ( isset( $_POST['_wpnonce'] ) && ! empty( $_POST['_wpnonce'] ) ) { $nonce = filter_input( INPUT_POST, '_wpnonce', FILTER_SANITIZE_STRING ); $action = 'bulk-' . $this->_args['plural']; if ( ! wp_verify_nonce( $nonce, $action ) ) { wp_die( 'Nope! Security check failed!' ); } } $action = $this->current_action(); switch ( $action ) { case 'delete_questions': wp_die( 'Delete something' ); break; case 'add_questions': wp_die( 'Save something' ); break; default: // do nothing or something else return; break; } wp_redirect( esc_url( add_query_arg() ) ); exit; return; } } /** * Shows the List table for all questions. * * @return void */ function conditional_shortcode_questions_list_table_layout() { $table = new Class_Conditional_Shortcode_Questions_Listing(); printf( '<div class="wrap" id="wpse-list-table"><h2>%s</h2>', __( '', 'conditional-shortcode' ) ); echo '<form id="wpse-list-table-form" method="post">'; $page = filter_input( INPUT_GET, 'page', FILTER_SANITIZE_STRIPPED ); $paged = filter_input( INPUT_GET, 'paged', FILTER_SANITIZE_NUMBER_INT ); printf( '<input type="hidden" name="page" value="%s" />', $page ); printf( '<input type="hidden" name="paged" value="%d" />', $paged ); $table->prepare_items(); // this will prepare the items AND process the bulk actions $table->search_box( __( 'Search question by id' ), 'conditional-shortcode' ); // Needs To be called after $myRequestTable->prepare_items() $table->display(); echo '</form>'; echo '</div>'; } conditional_shortcode_questions_list_table_layout();
I was able to resolve this issue by changing the value of name attribute of bulk actions select field. Like from name to names. What I think the issue could be is when here the name="action" for this select and it has some value xyz on the other side WordPress save post looks for action to be equal to edit.
Can we provide a way of changing this name attributes value either by providing a filter or by changing it. But I think changing name attribute would require a lot of other code changes so its better to provide a filter for custom use. Or add a comment on top so someone else using WP LIST Table in a metabox must override this function with custom value to name attribute.
For clarity I changed
This echo '<select name="action' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
To this echo '<select name="actions' . $two . '" id="bulk-action-selector-' . esc_attr( $which ) . "\">\n";
Thanks!