title: How To Display WP_List_Tables on frontend page
body: <p><strong>CURRENT ISSUE:</strong>
  I have been able to successfully create a variety of table Lists from my WP's sql database within the Dashboard admin area as well as create plugins utilizing WP_LIST_TABLE however am running into difficulty ON how I can display the same table on the frontend of my website using a shortcode. Normally I would add something like:</p>
  
  <pre><code> add_shortcode('joblist', 'Job_List_Plugin');
  </code></pre>
  
  <p>However on this occasion it does not seem to be working. page not producing the table, instead you just see the shortcode you added to the page so in this case [joblist]</p>
  
  <p><strong>QUESTION:</strong>
  How would I add a shortcode element to the following code that would allow me to display this table on a front end page for logged in visitors to see? Examples/Snippets would be appreciated.</p>
  
  <pre><code> if ( ! class_exists( 'WP_List_Table' ) ) {
      require_once( ABSPATH . 'wp-admin/includes/class-wp-list-table.php' );
   }
  
   class Job_List extends WP_List_Table {
  
      /** Class constructor */
      public function __construct() {
          parent::__construct( [
              'singular' =&gt; __( 'Custom List', 'red' ), //singular name of the listed records
              'plural'   =&gt; __( 'Custom Lists', 'red' ), //plural name of the listed records
              'ajax'     =&gt; false //does this table support ajax?
          ] );
      }
  
  
      /**
       * Retrieve members data from the database
       *
       * @param int $per_page
       * @param int $page_number
       *
       * @return mixed
       */
      public static function get_jobs( $per_page = 10, $page_number = 1 ) {
  
          global $wpdb;
          $query = "SELECT * FROM custom_table ORDER BY PrintOrder";
  
          if( ! empty( $_REQUEST['s'] ) ){
           $search = esc_sql( $_REQUEST['s'] );
      $query .= " WHERE Description LIKE '%{$search}%'";
      }
  
          if ( ! empty( $_REQUEST['orderby'] ) ) {
              $query .= ' ORDER BY ' . esc_sql( $_REQUEST['orderby'] );
              $query .= ! empty( $_REQUEST['order'] ) ? ' ' . esc_sql( $_REQUEST['order'] ) : ' ASC';
          }
  
          $query .= " LIMIT $per_page";
          $query .= ' OFFSET ' . ( $page_number - 1 ) * $per_page;
  
          $result = $wpdb-&gt;get_results( $query, 'ARRAY_A' );
  
          return $result;
      }
  
      /**
       * Returns the count of records in the database.
       *
       * @return null|string
       */
      public static function record_count() {
          global $wpdb;
  
          $query = "SELECT COUNT(*) FROM custom_table";
          if( ! empty( $_REQUEST['s'] ) ){
           $search = esc_sql( $_REQUEST['s'] );
           $query .= " WHERE Description LIKE '%{$search}%'";
          }
          return $wpdb-&gt;get_var( $query );
      }
  
      /** Text displayed when no member data is available */
      public function no_items() {
          _e( 'There is nothing display at this time.', 'red' );
      }
  
      /**
       * Render a column when no column specific method exist.
       *
       * @param array $item
       * @param string $column_name
       *
       * @return mixed
       */
      public function column_default( $item, $column_name ) {
          switch ( $column_name ) {
          case 'Description':
          case 'Class':
          case 'EmpName':
          case 'StartTime':
              return $item[ $column_name ];
          default:
              return print_r( $item, true ); //Show the whole array for troubleshooting purposes
      }
  }
  
  
  /**
   *  Associative array of columns
   *
   * @return array
   */
  function get_columns() {
      $columns = [
          'Description' =&gt; __( 'Classification', 'red' ),
          'Class'    =&gt; __( 'Class', 'red' ),
          'EmpName'    =&gt; __( 'Employer Name', 'red' ),
          'StartTime'    =&gt; __( 'Start Time', 'red' )
      ];
  
      return $columns;
  }
  
  
  /**
   * Columns to make sortable.
   *
   * @return array
   */
  public function get_sortable_columns() {
      $sortable_columns = array(
          'Description' =&gt; array( 'Classification', true ),
          'Class' =&gt; array ( 'Class', true)
      );
  
      return $sortable_columns;
  }
  /**
   * Handles data query and filter, sorting, and pagination.
   */
  public function prepare_items() {
  
      $this-&gt;_column_headers = $this-&gt;get_column_info();
  
      /** Process bulk action */
      $this-&gt;process_bulk_action();
  
      $per_page     = $this-&gt;get_items_per_page( 'jobs_per_page', 7 );
      $current_page = $this-&gt;get_pagenum();
      $total_items  = self::record_count();
  
      $this-&gt;set_pagination_args( [
          'total_items' =&gt; $total_items, //calculate the total number of items
          'per_page'    =&gt; $per_page //determine how many items to show on a page
      ] );
  
      $this-&gt;items = self::get_jobs( $per_page, $current_page );
  }
  
  
  
  
   }
  
   class Job_List_Plugin {
  
  // class instance
  static $instance;
  
  // joblist WP_List_Table object
  public $joblist_obj;
  
  // class constructor
  public function __construct() {
     add_filter( 'set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3 );
     add_action( 'admin_menu', [ $this, 'plugin_menu' ] );
  }
  
  
  public static function set_screen( $status, $option, $value ) {
      return $value;
  }
  
  public function plugin_menu() {
  
      $hook = add_menu_page(
          'Job List',
          'Job List',
          'manage_options',
          'joblist_viewer',
          [ $this, 'plugin_settings_page' ]
      );
  
      add_action( "load-$hook", [ $this, 'screen_option' ] );
  
  }
  
  
  /**
   * Plugin page
   */
  public function plugin_settings_page() {
      ?&gt;
      &lt;style&gt;
        table {display: block;overflow-x: scroll;}
        th {min-width:100px;font-size:10px;}
        p.search-box {float:none;}
        #post-body-content {width:98%;}
      &lt;/style&gt;
          &lt;h2&gt;IBEW 353 Member Management Portal&lt;/h2&gt;
          &lt;p&gt;To locate a specific Member enter their Card Number in the search field provided.&lt;/p&gt;
                  &lt;div id="post-body-content"&gt;
                      &lt;div class="meta-box-sortables ui-sortable"&gt;
                          &lt;form method="post"&gt;
     &lt;input type="hidden" name="page" value="joblist_viewer" /&gt;
                              &lt;?php
                              $this-&gt;joblist_obj-&gt;prepare_items();
                              $this-&gt;joblist_obj-&gt;search_box('Search', 'search');
                              $this-&gt;joblist_obj-&gt;display(); ?&gt;
                          &lt;/form&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;br class="clear"&gt;
  &lt;?php
  }
  
  /**
   * Screen options
   */
  public function screen_option() {
  
      $option = 'per_page';
      $args   = [
          'label'   =&gt; 'Jobs Per Page:',
          'default' =&gt; 5,
          'option'  =&gt; 'jobs_per_page'
      ];
  
      add_screen_option( $option, $args );
  
      $this-&gt;joblist_obj = new Job_List();
  }
  
  
  /** Singleton instance */
  public static function get_instance() {
      if ( ! isset( self::$instance ) ) {
          self::$instance = new self();
      }
  
      return self::$instance;
  }
  
   }
  
   add_action( 'plugins_loaded', function () {
      Job_List_Plugin::get_instance();
   } );
  </code></pre>
  
  <p><strong>UPDATE</strong>
  With the help from @Jared Chu I was able to get a bit of headway however am now getting an error. But at least I am seeing the shortcode beginning to work. </p>
  
  <p>Here is what I edited.</p>
  
  <p>line 203 (class construct) I added</p>
  
  <pre><code>// class constructor
  public function __construct() {
     add_filter( 'set-screen-option', [ __CLASS__, 'set_screen' ], 10, 3 );
     add_action( 'admin_menu', [ $this, 'plugin_menu' ] );
     add_shortcode('joblist', [ $this, 'plugin_settings_page' ] ); // Added shortcode as per suggestion from @Jared Chu
  }
  </code></pre>
  
  <p>The public function "plugin_settings_page" contains this code</p>
  
  <pre><code> /**
   * Plugin page
   */
  public function plugin_settings_page() {
      ?&gt;
      &lt;style&gt;
        table {display: block;overflow-x: scroll;}
        th {min-width:100px;font-size:10px;}
        p.search-box {float:none;}
        #post-body-content {width:98%;}
      &lt;/style&gt;
          &lt;h2&gt;IBEW 353 Member Management Portal&lt;/h2&gt;
          &lt;p&gt;To locate a specific Member enter their Card Number in the search field provided.&lt;/p&gt;
                  &lt;div id="post-body-content"&gt;
                      &lt;div class="meta-box-sortables ui-sortable"&gt;
                          &lt;form method="post"&gt;
   &lt;input type="hidden" name="page" value="joblist_viewer" /&gt;
                              &lt;?php
                              $this-&gt;joblist_obj-&gt;prepare_items();
                              $this-&gt;joblist_obj-&gt;search_box('Search', 'search');
                              $this-&gt;joblist_obj-&gt;display(); ?&gt;
                          &lt;/form&gt;
                      &lt;/div&gt;
                  &lt;/div&gt;
              &lt;br class="clear"&gt;
  &lt;?php
  }
  </code></pre>
  
  <p>however when I view the page I dropped the shortcode into I get the following error:</p>
  
  <p>Fatal error: Uncaught Error: Call to a member function prepare_items() on null in C:\wamp64\www\dev1\wp-content\plugins\Job-List-Plugin\index.php on line 249</p>