TGMPA_List_Table

List table class for handling plugins.

Defined (1)

The class is defined in the following location(s).

/includes/class-tgm-plugin-activation.php  
  1. class TGMPA_List_Table extends WP_List_Table { 
  2.  
  3. /** 
  4. * References parent constructor and sets defaults for class. 
  5. * The constructor also grabs a copy of $instance from the TGMPA class 
  6. * and stores it in the global object TGM_Plugin_Activation::$instance. 
  7. * @since 2.2.0 
  8. * @global unknown $status 
  9. * @global string $page 
  10. */ 
  11. public function __construct() { 
  12.  
  13. global $status, $page; 
  14.  
  15. parent::__construct( 
  16. array( 
  17. 'singular' => 'plugin',  
  18. 'plural' => 'plugins',  
  19. 'ajax' => false,  
  20. ); 
  21.  
  22.  
  23. /** 
  24. * Gathers and renames all of our plugin information to be used by 
  25. * WP_List_Table to create our table. 
  26. * @since 2.2.0 
  27. * @return array $table_data Information for use in table 
  28. */ 
  29. protected function _gather_plugin_data() { 
  30.  
  31. /** Load thickbox for plugin links */ 
  32. TGM_Plugin_Activation::$instance->admin_init(); 
  33. TGM_Plugin_Activation::$instance->thickbox(); 
  34.  
  35. /** Prep variables for use and grab list of all installed plugins */ 
  36. $table_data = array(); 
  37. $i = 0; 
  38. $installed_plugins = get_plugins(); 
  39.  
  40. foreach ( TGM_Plugin_Activation::$instance->plugins as $plugin ) { 
  41. if ( is_plugin_active( $plugin['file_path'] ) ) 
  42. continue; // No need to display plugins if they are installed and activated 
  43.  
  44. $table_data[$i]['sanitized_plugin'] = $plugin['name']; 
  45. $table_data[$i]['slug'] = $this->_get_plugin_data_from_name( $plugin['name'] ); 
  46.  
  47. $external_url = $this->_get_plugin_data_from_name( $plugin['name'], 'external_url' ); 
  48. $source = $this->_get_plugin_data_from_name( $plugin['name'], 'source' ); 
  49.  
  50. if ( $external_url && preg_match( '|^http(s)?://|', $external_url ) ) { 
  51. $table_data[$i]['plugin'] = '<strong><a href="' . esc_url( $external_url ) . '" title="' . $plugin['name'] . '" target="_blank">' . $plugin['name'] . '</a></strong>'; 
  52. elseif ( ! $source || preg_match( '|^http://wordpress.org/extend/plugins/|', $source ) ) { 
  53. $url = add_query_arg( 
  54. array( 
  55. 'tab' => 'plugin-information',  
  56. 'plugin' => $this->_get_plugin_data_from_name( $plugin['name'] ),  
  57. 'TB_iframe' => 'true',  
  58. 'width' => '640',  
  59. 'height' => '500',  
  60. ),  
  61. admin_url( 'plugin-install.php' ) 
  62. ); 
  63.  
  64. $table_data[$i]['plugin'] = '<strong><a href="' . esc_url( $url ) . '" class="thickbox" title="' . $plugin['name'] . '">' . $plugin['name'] . '</a></strong>'; 
  65. else { 
  66. $table_data[$i]['plugin'] = '<strong>' . $plugin['name'] . '</strong>'; // No hyperlink 
  67.  
  68. if ( isset( $table_data[$i]['plugin'] ) && (array) $table_data[$i]['plugin'] ) 
  69. $plugin['name'] = $table_data[$i]['plugin']; 
  70.  
  71. if ( isset( $plugin['external_url'] ) ) { 
  72. /** The plugin is linked to an external source */ 
  73. $table_data[$i]['source'] = __( 'External Link', TGM_Plugin_Activation::$instance->domain ); 
  74. elseif ( isset( $plugin['source'] ) ) { 
  75. /** The plugin must be from a private repository */ 
  76. if ( preg_match( '|^http(s)?://|', $plugin['source'] ) ) 
  77. $table_data[$i]['source'] = __( 'Private Repository', TGM_Plugin_Activation::$instance->domain ); 
  78. /** The plugin is pre-packaged with the theme */ 
  79. else 
  80. $table_data[$i]['source'] = __( 'Pre-Packaged', TGM_Plugin_Activation::$instance->domain ); 
  81. /** The plugin is from the WordPress repository */ 
  82. else { 
  83. $table_data[$i]['source'] = __( 'WordPress Repository', TGM_Plugin_Activation::$instance->domain ); 
  84.  
  85. $table_data[$i]['type'] = $plugin['required'] ? __( 'Required', TGM_Plugin_Activation::$instance->domain ) : __( 'Recommended', TGM_Plugin_Activation::$instance->domain ); 
  86.  
  87. if ( ! isset( $installed_plugins[$plugin['file_path']] ) ) 
  88. $table_data[$i]['status'] = sprintf( '%1$s', __( 'Not Installed', TGM_Plugin_Activation::$instance->domain ) ); 
  89. elseif ( is_plugin_inactive( $plugin['file_path'] ) ) 
  90. $table_data[$i]['status'] = sprintf( '%1$s', __( 'Installed But Not Activated', TGM_Plugin_Activation::$instance->domain ) ); 
  91.  
  92. $table_data[$i]['file_path'] = $plugin['file_path']; 
  93. $table_data[$i]['url'] = isset( $plugin['source'] ) ? $plugin['source'] : 'repo'; 
  94.  
  95. $i++; 
  96.  
  97. /** Sort plugins by Required/Recommended type and by alphabetical listing within each type */ 
  98. $resort = array(); 
  99. $req = array(); 
  100. $rec = array(); 
  101.  
  102. /** Grab all the plugin types */ 
  103. foreach ( $table_data as $plugin ) 
  104. $resort[] = $plugin['type']; 
  105.  
  106. /** Sort each plugin by type */ 
  107. foreach ( $resort as $type ) 
  108. if ( 'Required' == $type ) 
  109. $req[] = $type; 
  110. else 
  111. $rec[] = $type; 
  112.  
  113. /** Sort alphabetically each plugin type array, merge them and then sort in reverse (lists Required plugins first) */  
  114. sort( $req ); 
  115. sort( $rec ); 
  116. array_merge( $resort, $req, $rec ); 
  117. array_multisort( $resort, SORT_DESC, $table_data ); 
  118.  
  119. return $table_data; 
  120.  
  121.  
  122. /** 
  123. * Retrieve plugin data, given the plugin name. Taken from the 
  124. * TGM_Plugin_Activation class. 
  125. * Loops through the registered plugins looking for $name. If it finds it,  
  126. * it returns the $data from that plugin. Otherwise, returns false. 
  127. * @since 2.2.0 
  128. * @param string $name Name of the plugin, as it was registered 
  129. * @param string $data Optional. Array key of plugin data to return. Default is slug 
  130. * @return string|boolean Plugin slug if found, false otherwise 
  131. */ 
  132. protected function _get_plugin_data_from_name( $name, $data = 'slug' ) { 
  133.  
  134. foreach ( TGM_Plugin_Activation::$instance->plugins as $plugin => $values ) { 
  135. if ( $name == $values['name'] && isset( $values[$data] ) ) 
  136. return $values[$data]; 
  137.  
  138. return false; 
  139.  
  140.  
  141. /** 
  142. * Create default columns to display important plugin information 
  143. * like type, action and status. 
  144. * @since 2.2.0 
  145. * @param array $item 
  146. * @param string $column_name 
  147. */ 
  148. public function column_default( $item, $column_name ) { 
  149.  
  150. switch ( $column_name ) { 
  151. case 'source': 
  152. case 'type': 
  153. case 'status': 
  154. return $item[$column_name]; 
  155.  
  156.  
  157. /** 
  158. * Create default title column along with action links of 'Install' 
  159. * and 'Activate'. 
  160. * @since 2.2.0 
  161. * @param array $item 
  162. * @return string The action hover links 
  163. */ 
  164. public function column_plugin( $item ) { 
  165.  
  166. $installed_plugins = get_plugins(); 
  167.  
  168. /** No need to display any hover links */ 
  169. if ( is_plugin_active( $item['file_path'] ) ) 
  170. $actions = array(); 
  171.  
  172. /** We need to display the 'Install' hover link */ 
  173. if ( ! isset( $installed_plugins[$item['file_path']] ) ) { 
  174. $actions = array( 
  175. 'install' => sprintf( 
  176. '<a href="%1$s" title="Install %2$s">Install</a>',  
  177. wp_nonce_url( 
  178. add_query_arg( 
  179. array( 
  180. 'page' => TGM_Plugin_Activation::$instance->menu,  
  181. 'plugin' => $item['slug'],  
  182. 'plugin_name' => $item['sanitized_plugin'],  
  183. 'plugin_source' => $item['url'],  
  184. 'tgmpa-install' => 'install-plugin',  
  185. ),  
  186. admin_url( TGM_Plugin_Activation::$instance->parent_url_slug ) 
  187. ),  
  188. 'tgmpa-install' 
  189. ),  
  190. $item['sanitized_plugin'] 
  191. ),  
  192. ); 
  193. /** We need to display the 'Activate' hover link */ 
  194. elseif ( is_plugin_inactive( $item['file_path'] ) ) { 
  195. $actions = array( 
  196. 'activate' => sprintf( 
  197. '<a href="%1$s" title="Activate %2$s">Activate</a>',  
  198. add_query_arg( 
  199. array( 
  200. 'page' => TGM_Plugin_Activation::$instance->menu,  
  201. 'plugin' => $item['slug'],  
  202. 'plugin_name' => $item['sanitized_plugin'],  
  203. 'plugin_source' => $item['url'],  
  204. 'tgmpa-activate' => 'activate-plugin',  
  205. 'tgmpa-activate-nonce' => wp_create_nonce( 'tgmpa-activate' ),  
  206. ),  
  207. admin_url( TGM_Plugin_Activation::$instance->parent_url_slug ) 
  208. ),  
  209. $item['sanitized_plugin'] 
  210. ),  
  211. ); 
  212.  
  213. return sprintf( '%1$s %2$s', $item['plugin'], $this->row_actions( $actions ) ); 
  214.  
  215.  
  216. /** 
  217. * Required for bulk installing. 
  218. * Adds a checkbox for each plugin. 
  219. * @since 2.2.0 
  220. * @param array $item 
  221. * @return string The input checkbox with all necessary info 
  222. */ 
  223. public function column_cb( $item ) { 
  224.  
  225. $value = $item['file_path'] . ', ' . $item['url'] . ', ' . $item['sanitized_plugin']; 
  226. return sprintf( '<input type="checkbox" name="%1$s[]" value="%2$s" id="%3$s" />', $this->_args['singular'], $value, $item['sanitized_plugin'] ); 
  227.  
  228.  
  229. /** 
  230. * Sets default message within the plugins table if no plugins 
  231. * are left for interaction. 
  232. * Hides the menu item to prevent the user from clicking and 
  233. * getting a permissions error. 
  234. * @since 2.2.0 
  235. */ 
  236. public function no_items() { 
  237.  
  238. printf( __( 'No plugins to install or activate. <a href="%1$s" title="Return to the Dashboard">Return to the Dashboard</a>', TGM_Plugin_Activation::$instance->domain ), admin_url() ); 
  239. echo '<style type="text/css">#adminmenu .wp-submenu li.current { display: none !important; }</style>'; 
  240.  
  241.  
  242. /** 
  243. * Output all the column information within the table. 
  244. * @since 2.2.0 
  245. * @return array $columns The column names 
  246. */ 
  247. public function get_columns() { 
  248.  
  249. $columns = array( 
  250. 'cb' => '<input type="checkbox" />',  
  251. 'plugin' => __( 'Plugin', TGM_Plugin_Activation::$instance->domain ),  
  252. 'source' => __( 'Source', TGM_Plugin_Activation::$instance->domain ),  
  253. 'type' => __( 'Type', TGM_Plugin_Activation::$instance->domain ),  
  254. 'status' => __( 'Status', TGM_Plugin_Activation::$instance->domain ) 
  255. ); 
  256.  
  257. return $columns; 
  258.  
  259.  
  260. /** 
  261. * Defines all types of bulk actions for handling 
  262. * registered plugins. 
  263. * @since 2.2.0 
  264. * @return array $actions The bulk actions for the plugin install table 
  265. */ 
  266. public function get_bulk_actions() { 
  267.  
  268. $actions = array( 
  269. 'tgmpa-bulk-install' => __( 'Install', TGM_Plugin_Activation::$instance->domain ),  
  270. 'tgmpa-bulk-activate' => __( 'Activate', TGM_Plugin_Activation::$instance->domain ),  
  271. ); 
  272.  
  273. return $actions; 
  274.  
  275.  
  276. /** 
  277. * Processes bulk installation and activation actions. 
  278. * The bulk installation process looks either for the $_POST 
  279. * information or for the plugin info within the $_GET variable if 
  280. * a user has to use WP_Filesystem to enter their credentials. 
  281. * @since 2.2.0 
  282. */ 
  283. public function process_bulk_actions() { 
  284.  
  285. /** Bulk installation process */ 
  286. if ( 'tgmpa-bulk-install' === $this->current_action() ) { 
  287. check_admin_referer( 'bulk-' . $this->_args['plural'] ); 
  288.  
  289. /** Prep variables to be populated */ 
  290. $plugins_to_install = array(); 
  291. $plugin_installs = array(); 
  292. $plugin_path = array(); 
  293. $plugin_name = array(); 
  294.  
  295. /** Look first to see if information has been passed via WP_Filesystem */ 
  296. if ( isset( $_GET[sanitize_key( 'plugins' )] ) ) 
  297. $plugins = explode( ', ', stripslashes( $_GET[sanitize_key( 'plugins' )] ) ); 
  298. /** Looks like the user can use the direct method, take from $_POST */ 
  299. elseif ( isset( $_POST[sanitize_key( 'plugin' )] ) ) 
  300. $plugins = (array) $_POST[sanitize_key( 'plugin' )]; 
  301. /** Nothing has been submitted */ 
  302. else 
  303. $plugins = array(); 
  304.  
  305. $a = 0; // Incremental variable 
  306.  
  307. /** Grab information from $_POST if available */ 
  308. if ( isset( $_POST[sanitize_key( 'plugin' )] ) ) { 
  309. foreach ( $plugins as $plugin_data ) 
  310. $plugins_to_install[] = explode( ', ', $plugin_data ); 
  311.  
  312. foreach ( $plugins_to_install as $plugin_data ) { 
  313. $plugin_installs[] = $plugin_data[0]; 
  314. $plugin_path[] = $plugin_data[1]; 
  315. $plugin_name[] = $plugin_data[2]; 
  316. /** Information has been passed via $_GET */ 
  317. else { 
  318. foreach ( $plugins as $key => $value ) { 
  319. /** Grab plugin slug for each plugin */ 
  320. if ( 0 == $key % 3 || 0 == $key ) { 
  321. $plugins_to_install[] = $value; 
  322. $plugin_installs[] = $value; 
  323. $a++; 
  324.  
  325. /** Look first to see if information has been passed via WP_Filesystem */ 
  326. if ( isset( $_GET[sanitize_key( 'plugin_paths' )] ) ) 
  327. $plugin_paths = explode( ', ', stripslashes( $_GET[sanitize_key( 'plugin_paths' )] ) ); 
  328. /** Looks like the user doesn't need to enter his FTP creds */ 
  329. elseif ( isset( $_POST[sanitize_key( 'plugin' )] ) ) 
  330. $plugin_paths = (array) $plugin_path; 
  331. /** Nothing has been submitted */ 
  332. else 
  333. $plugin_paths = array(); 
  334.  
  335. /** Look first to see if information has been passed via WP_Filesystem */ 
  336. if ( isset( $_GET[sanitize_key( 'plugin_names' )] ) ) 
  337. $plugin_names = explode( ', ', stripslashes( $_GET[sanitize_key( 'plugin_names' )] ) ); 
  338. /** Looks like the user doesn't need to enter his FTP creds */ 
  339. elseif ( isset( $_POST[sanitize_key( 'plugin' )] ) ) 
  340. $plugin_names = (array) $plugin_name; 
  341. /** Nothing has been submitted */ 
  342. else 
  343. $plugin_names = array(); 
  344.  
  345. $b = 0; // Incremental variable 
  346.  
  347. /** Loop through plugin slugs and remove already installed plugins from the list */ 
  348. foreach ( $plugin_installs as $key => $plugin ) { 
  349. if ( preg_match( '|.php$|', $plugin ) ) { 
  350. unset( $plugin_installs[$key] ); 
  351.  
  352. /** If the plugin path isn't in the $_GET variable, we can unset the corresponding path */ 
  353. if ( ! isset( $_GET[sanitize_key( 'plugin_paths' )] ) ) 
  354. unset( $plugin_paths[$b] ); 
  355.  
  356. /** If the plugin name isn't in the $_GET variable, we can unset the corresponding name */ 
  357. if ( ! isset( $_GET[sanitize_key( 'plugin_names' )] ) ) 
  358. unset( $plugin_names[$b] ); 
  359. $b++; 
  360.  
  361. /** No need to proceed further if we have no plugins to install */ 
  362. if ( empty( $plugin_installs ) ) 
  363. return false; 
  364.  
  365. /** Reset array indexes in case we removed already installed plugins */ 
  366. $plugin_installs = array_values( $plugin_installs ); 
  367. $plugin_paths = array_values( $plugin_paths ); 
  368. $plugin_names = array_values( $plugin_names ); 
  369.  
  370. /** If we grabbed our plugin info from $_GET, we need to decode it for use */ 
  371. $plugin_installs = array_map( 'urldecode', $plugin_installs ); 
  372. $plugin_paths = array_map( 'urldecode', $plugin_paths ); 
  373. $plugin_names = array_map( 'urldecode', $plugin_names ); 
  374.  
  375. /** Pass all necessary information via URL if WP_Filesystem is needed */ 
  376. $url = wp_nonce_url( 
  377. add_query_arg( 
  378. array( 
  379. 'page' => TGM_Plugin_Activation::$instance->menu,  
  380. 'tgmpa-action' => 'install-selected',  
  381. 'plugins' => urlencode( implode( ', ', $plugins ) ),  
  382. 'plugin_paths' => urlencode( implode( ', ', $plugin_paths ) ),  
  383. 'plugin_names' => urlencode( implode( ', ', $plugin_names ) ),  
  384. ),  
  385. admin_url( TGM_Plugin_Activation::$instance->parent_url_slug ) 
  386. ),  
  387. 'bulk-plugins' 
  388. ); 
  389. $method = ''; // Leave blank so WP_Filesystem can populate it as necessary 
  390. $fields = array( sanitize_key( 'action' ), sanitize_key( '_wp_http_referer' ), sanitize_key( '_wpnonce' ) ); // Extra fields to pass to WP_Filesystem 
  391.  
  392. if ( false === ( $creds = request_filesystem_credentials( $url, $method, false, false, $fields ) ) ) 
  393. return true; 
  394.  
  395. if ( ! WP_Filesystem( $creds ) ) { 
  396. request_filesystem_credentials( $url, $method, true, false, $fields ); // Setup WP_Filesystem 
  397. return true; 
  398.  
  399. require_once ABSPATH . 'wp-admin/includes/plugin-install.php'; // Need for plugins_api 
  400. require_once ABSPATH . 'wp-admin/includes/class-wp-upgrader.php'; // Need for upgrade classes 
  401.  
  402. /** Store all information in arrays since we are processing a bulk installation */ 
  403. $api = array(); 
  404. $sources = array(); 
  405. $install_path = array(); 
  406.  
  407. $c = 0; // Incremental variable 
  408.  
  409. /** Loop through each plugin to install and try to grab information from WordPress API, if not create 'tgmpa-empty' scalar */ 
  410. foreach ( $plugin_installs as $plugin ) { 
  411. $api[$c] = plugins_api( 'plugin_information', array( 'slug' => $plugin, 'fields' => array( 'sections' => false ) ) ) ? plugins_api( 'plugin_information', array( 'slug' => $plugin, 'fields' => array( 'sections' => false ) ) ) : (object) $api[$c] = 'tgmpa-empty'; 
  412. $c++; 
  413.  
  414. if ( is_wp_error( $api ) ) 
  415. wp_die( TGM_Plugin_Activation::$instance->strings['oops'] . var_dump( $api ) ); 
  416.  
  417. $d = 0; // Incremental variable 
  418.  
  419. /** Capture download links from $api or set install link to pre-packaged/private repo */ 
  420. foreach ( $api as $object ) { 
  421. $sources[$d] = isset( $object->download_link ) && 'repo' == $plugin_paths[$d] ? $object->download_link : $plugin_paths[$d]; 
  422. $d++; 
  423.  
  424. /** Finally, all the data is prepared to be sent to the installer */ 
  425. $url = add_query_arg( array( 'page' => TGM_Plugin_Activation::$instance->menu ), admin_url( TGM_Plugin_Activation::$instance->parent_url_slug ) ); 
  426. $nonce = 'bulk-plugins'; 
  427. $names = $plugin_names; 
  428.  
  429. /** Create a new instance of TGM_Bulk_Installer */ 
  430. $installer = new TGM_Bulk_Installer( $skin = new TGM_Bulk_Installer_Skin( compact( 'url', 'nonce', 'names' ) ) ); 
  431.  
  432. /** Wrap the install process with the appropriate HTML */ 
  433. echo '<div class="tgmpa wrap">'; 
  434. screen_icon( apply_filters( 'tgmpa_default_screen_icon', 'themes' ) ); 
  435. echo '<h2>' . esc_html( get_admin_page_title() ) . '</h2>'; 
  436. /** Process the bulk installation submissions */ 
  437. $installer->bulk_install( $sources ); 
  438. echo '</div>'; 
  439.  
  440. return true; 
  441.  
  442. /** Bulk activation process */ 
  443. if ( 'tgmpa-bulk-activate' === $this->current_action() ) { 
  444. check_admin_referer( 'bulk-' . $this->_args['plural'] ); 
  445.  
  446. /** Grab plugin data from $_POST */ 
  447. $plugins = isset( $_POST[sanitize_key( 'plugin' )] ) ? (array) $_POST[sanitize_key( 'plugin' )] : array(); 
  448. $plugins_to_activate = array(); 
  449.  
  450. /** Split plugin value into array with plugin file path, plugin source and plugin name */ 
  451. foreach ( $plugins as $i => $plugin ) 
  452. $plugins_to_activate[] = explode( ', ', $plugin ); 
  453.  
  454. foreach ( $plugins_to_activate as $i => $array ) { 
  455. if ( ! preg_match( '|.php$|', $array[0] ) ) // Plugins that haven't been installed yet won't have the correct file path 
  456. unset( $plugins_to_activate[$i] ); 
  457.  
  458. /** Return early if there are no plugins to activate */ 
  459. if ( empty( $plugins_to_activate ) ) 
  460. return; 
  461.  
  462. $plugins = array(); 
  463. $plugin_names = array(); 
  464.  
  465. foreach ( $plugins_to_activate as $plugin_string ) { 
  466. $plugins[] = $plugin_string[0]; 
  467. $plugin_names[] = $plugin_string[2]; 
  468.  
  469. $count = count( $plugin_names ); // Count so we can use _n function 
  470. $last_plugin = array_pop( $plugin_names ); // Pop off last name to prep for readability 
  471. $imploded = empty( $plugin_names ) ? '<strong>' . $last_plugin . '</strong>' : '<strong>' . ( implode( ', ', $plugin_names ) . '</strong> and <strong>' . $last_plugin . '</strong>.' ); 
  472.  
  473. /** Now we are good to go - let's start activating plugins */ 
  474. $activate = activate_plugins( $plugins ); 
  475.  
  476. if ( is_wp_error( $activate ) ) 
  477. echo '<div id="message" class="error"><p>' . $activate->get_error_message() . '</p></div>'; 
  478. else 
  479. printf( '<div id="message" class="updated"><p>%1$s %2$s</p></div>', _n( 'The following plugin was activated successfully:', 'The following plugins were activated successfully:', $count, TGM_Plugin_Activation::$instance->domain ), $imploded ); 
  480.  
  481. /** Update recently activated plugins option */ 
  482. $recent = (array) get_option( 'recently_activated' ); 
  483.  
  484. foreach ( $plugins as $plugin => $time ) 
  485. if ( isset( $recent[$plugin] ) ) 
  486. unset( $recent[$plugin] ); 
  487.  
  488. update_option( 'recently_activated', $recent ); 
  489.  
  490. unset( $_POST ); // Reset the $_POST variable in case user wants to perform one action after another 
  491.  
  492. /** 
  493. * Prepares all of our information to be outputted into a usable table. 
  494. * @since 2.2.0 
  495. */ 
  496. public function prepare_items() { 
  497.  
  498. $per_page = 100; // Set it high so we shouldn't have to worry about pagination 
  499. $columns = $this->get_columns(); // Get all necessary column information 
  500. $hidden = array(); // No columns to hide, but we must set as an array 
  501. $sortable = array(); // No reason to make sortable columns 
  502. $this->_column_headers = array( $columns, $hidden, $sortable ); // Get all necessary column headers 
  503.  
  504. /** Process our bulk actions here */ 
  505. $this->process_bulk_actions(); 
  506.  
  507. /** Store all of our plugin data into $items array so WP_List_Table can use it */ 
  508. $this->items = $this->_gather_plugin_data(); 
  509.  
  510.