[wp-trac] [WordPress Trac] #54720: WP_List_Table Inside Metabox With Bulk Actions Not Working on Submit

WordPress Trac noreply at wordpress.org
Mon Jan 3 11:40:53 UTC 2022


#54720: WP_List_Table Inside Metabox With Bulk Actions Not Working on Submit
----------------------------------+----------------------------------------
 Reporter:  muhammadfaizanhaidar  |      Owner:  (none)
     Type:  defect (bug)          |     Status:  new
 Priority:  normal                |  Milestone:  Awaiting Review
Component:  Posts, Post Types     |    Version:  5.8.2
 Severity:  normal                |   Keywords:  2nd-opinion needs-dev-note
  Focuses:                        |
----------------------------------+----------------------------------------
 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
 <?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!

-- 
Ticket URL: <https://core.trac.wordpress.org/ticket/54720>
WordPress Trac <https://core.trac.wordpress.org/>
WordPress publishing platform


More information about the wp-trac mailing list