admin_page->enqueue_script( 'list', array( 'jquery-core' ), array( 'list' => array( 'shortcode_popup' => __( 'To embed this table into a post or page, use this Shortcode:', 'tablepress' ), 'donation-message-already-donated' => __( 'Thank you very much! Your donation is highly appreciated. You just contributed to the further development of TablePress!', 'tablepress' ), 'donation-message-maybe-later' => sprintf( __( 'No problem! I still hope you enjoy the benefits that TablePress adds to your site. If you should change your mind, you’ll always find the “Donate” button on the TablePress website.', 'tablepress' ), 'https://tablepress.org/' ), ), ) ); if ( $data['messages']['first_visit'] ) { $this->add_header_message( '' . __( 'Welcome!', 'tablepress' ) . '
' . __( 'Thank you for using TablePress for the first time!', 'tablepress' ) . ' ' . sprintf( __( 'If you encounter any questions or problems, please visit the FAQ, the documentation, and the Support section on the plugin website.', 'tablepress' ), 'https://tablepress.org/faq/', 'https://tablepress.org/documentation/', 'https://tablepress.org/support/', 'https://tablepress.org/' ) . '

' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'first_visit', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ), 'notice-info not-dismissible' ); } if ( $data['messages']['wp_table_reloaded_warning'] ) { $this->add_header_message( '' . __( 'Attention!', 'tablepress' ) . '
' . __( 'You have activated the plugin WP-Table Reloaded, which can not be used together with TablePress.', 'tablepress' ) . '
' . __( 'It is strongly recommended that you switch from WP-Table Reloaded to TablePress, which not only fixes many problems, but also has more and better features than WP-Table Reloaded.', 'tablepress' ) . '
' . sprintf( __( 'Please follow the migration guide to move your tables and then deactivate WP-Table Reloaded!', 'tablepress' ), 'https://tablepress.org/migration-from-wp-table-reloaded/' ) . '
' . '' . __( 'Import your tables from WP-Table Reloaded', 'tablepress' ) . '', 'notice-error not-dismissible' ); } if ( $data['messages']['donation_message'] ) { $this->add_header_message( '' . esc_attr__( 'Tobias Bäthge, developer of TablePress', 'tablepress' ) . '' . __( 'Hi, my name is Tobias, I’m the developer of the TablePress plugin.', 'tablepress' ) . '

' . __( 'Thanks for using it! You’ve installed TablePress over a month ago.', 'tablepress' ) . ' ' . sprintf( _n( 'If everything works and you are satisfied with the results of managing your %s table, isn’t that worth a coffee or two?', 'If everything works and you are satisfied with the results of managing your %s tables, isn’t that worth a coffee or two?', $data['table_count'], 'tablepress' ), $data['table_count'] ) . '
' . sprintf( __( 'Donations help me to continue user support and development of this free software — things for which I spend countless hours of my free time! Thank you very much!', 'tablepress' ), 'https://tablepress.org/donate/' ) . '

' . __( 'Sincerly, Tobias', 'tablepress' ) . '

' . sprintf( '%s', 'https://tablepress.org/donate/', __( 'Sure, I’ll buy you a coffee and support TablePress!', 'tablepress' ) ) . '    ·    ' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'already-donated' ), __( 'I already donated.', 'tablepress' ) ) . '    ·    ' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'maybe-later' ), __( 'No, thanks. Don’t ask again.', 'tablepress' ) ), 'notice-success not-dismissible' ); } if ( $data['messages']['plugin_update_message'] ) { $this->add_header_message( '' . sprintf( __( 'Thank you for updating to TablePress %s!', 'tablepress' ), TablePress::version ) . '
' . sprintf( __( 'Please read the release announcement for more information.', 'tablepress' ), 'https://tablepress.org/news/' ) . ' ' . sprintf( __( 'If you like the new features and enhancements, giving a donation towards the further support and development of TablePress is recommended. Thank you!', 'tablepress' ), 'https://tablepress.org/donate/' ) . '

' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'plugin_update', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ), 'notice-info not-dismissible' ); } $this->process_action_messages( array( 'success_delete' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 1, 'tablepress' ), 'success_delete_plural' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 2, 'tablepress' ), 'error_delete' => __( 'Error: The table could not be deleted.', 'tablepress' ), 'error_save' => __( 'Error: The table could not be saved.', 'tablepress' ), 'success_copy' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 1, 'tablepress' ) . ( ( false !== $data['table_id'] ) ? ' ' . sprintf( __( 'The copied table has the table ID “%s”.', 'tablepress' ), esc_html( $data['table_id'] ) ) : '' ), 'success_copy_plural' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 2, 'tablepress' ), 'error_copy' => __( 'Error: The table could not be copied.', 'tablepress' ), 'error_no_table' => __( 'Error: You did not specify a valid table ID.', 'tablepress' ), 'error_load_table' => __( 'Error: This table could not be loaded!', 'tablepress' ), 'error_bulk_action_invalid' => __( 'Error: This bulk action is invalid!', 'tablepress' ), 'error_no_selection' => __( 'Error: You did not select any tables!', 'tablepress' ), 'error_delete_not_all_tables' => __( 'Notice: Not all selected tables could be deleted!', 'tablepress' ), 'error_copy_not_all_tables' => __( 'Notice: Not all selected tables could be copied!', 'tablepress' ), 'success_import' => __( 'The tables were imported successfully.', 'tablepress' ), 'success_import_wp_table_reloaded' => __( 'The tables were imported successfully from WP-Table Reloaded.', 'tablepress' ), ) ); $this->add_text_box( 'head', array( $this, 'textbox_head' ), 'normal' ); $this->add_text_box( 'tables-list', array( $this, 'textbox_tables_list' ), 'normal' ); add_screen_option( 'per_page', array( 'label' => __( 'Tables', 'tablepress' ), 'default' => 20 ) ); // Admin_Controller contains function to allow changes to this in the Screen Options to be saved $this->wp_list_table = new TablePress_All_Tables_List_Table(); $this->wp_list_table->set_items( $this->data['table_ids'] ); $this->wp_list_table->prepare_items(); // Cleanup Request URI string, which WP_List_Table uses to generate the sort URLs. $_SERVER['REQUEST_URI'] = remove_query_arg( array( 'message', 'table_id' ), $_SERVER['REQUEST_URI'] ); } /** * Render the current view (in this view: without form tag). * * @since 1.0.0 */ public function render() { ?>
print_nav_tab_menu(); // Print all header messages. foreach ( $this->header_messages as $message ) { echo $message; } // For this screen, this is done in textbox_tables_list(), to get the fields into the correct
: // $this->do_text_boxes( 'header' ); ?>
do_text_boxes( 'normal' ); $this->do_meta_boxes( 'normal' ); $this->do_text_boxes( 'additional' ); $this->do_meta_boxes( 'additional' ); // Print all submit buttons. $this->do_text_boxes( 'submit' ); ?>
do_text_boxes( 'side' ); $this->do_meta_boxes( 'side' ); ?>

/]' ) . '" readonly="readonly" />' ); ?>

' . __( 'Search results for “%s”', 'tablepress' ) . '', esc_html( wp_unslash( $_GET['s'] ) ) ); } ?> ' . "\n"; } $this->wp_list_table->search_box( __( 'Search Tables', 'tablepress' ), 'tables_search' ); ?>
). $this->do_text_boxes( 'header' ); $this->wp_list_table->display(); ?>
'list', 'item' => '' ), $text ) { $url = TablePress::url( $params, true, 'admin-post.php' ); $action = esc_attr( $params['action'] ); $item = esc_attr( $params['item'] ); $target = isset( $params['target'] ) ? esc_attr( $params['target'] ) : ''; return "{$text}"; } } // class TablePress_List_View /** * TablePress All Tables List Table Class * @package TablePress * @subpackage Views * @author Tobias Bäthge * @link https://codex.wordpress.org/Class_Reference/WP_List_Table * @since 1.0.0 */ class TablePress_All_Tables_List_Table extends WP_List_Table { /** * Number of items of the initial data set (before sort, search, and pagination). * * @since 1.0.0 * @var int */ protected $items_count = 0; /** * Initialize the List Table. * * @since 1.0.0 */ public function __construct() { $screen = get_current_screen(); // Hide "Last Modified By" column by default. if ( false === get_user_option( 'manage' . $screen->id . 'columnshidden' ) ) { update_user_option( get_current_user_id(), 'manage' . $screen->id . 'columnshidden', array( 'table_last_modified_by' ), true ); } parent::__construct( array( 'singular' => 'tablepress-table', // Singular name of the listed records. 'plural' => 'tablepress-all-tables', // Plural name of the listed records. 'ajax' => false, // Does this list table support AJAX? 'screen' => $screen, // WP_Screen object. ) ); } /** * Set the data items (here: tables) that are to be displayed by the List Tables, and their original count. * * @since 1.0.0 * * @param array $items Tables to be displayed in the List Table. */ public function set_items( array $items ) { $this->items = $items; $this->items_count = count( $items ); } /** * Check whether the user has permissions for certain AJAX actions. * (not used, but must be implemented in this child class) * * @since 1.0.0 * * @return bool true (Default value). */ public function ajax_user_can() { return true; } /** * Get a list of columns in this List Table. * * Format: 'internal-name' => 'Column Title'. * * @since 1.0.0 * * @return array List of columns in this List Table. */ public function get_columns() { $columns = array( 'cb' => $this->has_items() ? '' : '', // Checkbox for "Select all", but only if there are items in the table. // "name" is special in WP, which is why we prefix every entry here, to be safe! 'table_id' => __( 'ID', 'tablepress' ), 'table_name' => __( 'Table Name', 'tablepress' ), 'table_description' => __( 'Description', 'tablepress' ), 'table_author' => __( 'Author', 'tablepress' ), 'table_last_modified_by' => __( 'Last Modified By', 'tablepress' ), 'table_last_modified' => __( 'Last Modified', 'tablepress' ), ); return $columns; } /** * Get a list of columns that are sortable. * * Format: 'internal-name' => array( $field for $item[ $field ], true for already sorted ). * * @since 1.0.0 * * @return array List of sortable columns in this List Table. */ protected function get_sortable_columns() { // No sorting on the Empty List placeholder. if ( ! $this->has_items() ) { return array(); } $sortable_columns = array( 'table_id' => array( 'id', true ), // true means its already sorted 'table_name' => array( 'name', false ), 'table_description' => array( 'description', false ), 'table_author' => array( 'author', false ), 'table_last_modified_by' => array( 'last_modified_by', false ), 'table_last_modified' => array( 'last_modified', false ), ); return $sortable_columns; } /** * Gets the name of the default primary column. * * @since 1.7.0 * * @return string Name of the default primary column, in this case, the table name. */ protected function get_default_primary_column_name() { return 'table_name'; } /** * Render a cell in the "cb" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_cb( /* array */ $item ) { // No `array` type hint to prevent a Strict Standards notice, as the method is inherited. $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] ); $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] ); $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] ); if ( $user_can_copy_table || $user_can_delete_table || $user_can_export_table ) { return ''; } else { return ''; } } /** * Render a cell in the "table_id" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_id( array $item ) { return esc_html( $item['id'] ); } /** * Render a cell in the "table_name" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_name( array $item ) { $user_can_edit_table = current_user_can( 'tablepress_edit_table', $item['id'] ); $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] ); $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] ); $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] ); $user_can_preview_table = current_user_can( 'tablepress_preview_table', $item['id'] ); $edit_url = TablePress::url( array( 'action' => 'edit', 'table_id' => $item['id'] ) ); $copy_url = TablePress::url( array( 'action' => 'copy_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' ); $export_url = TablePress::url( array( 'action' => 'export', 'table_id' => $item['id'] ) ); $delete_url = TablePress::url( array( 'action' => 'delete_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' ); $preview_url = TablePress::url( array( 'action' => 'preview_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' ); if ( '' === trim( $item['name'] ) ) { $item['name'] = __( '(no name)', 'tablepress' ); } if ( $user_can_edit_table ) { $row_text = '' . esc_html( $item['name'] ) . ''; } else { $row_text = '' . esc_html( $item['name'] ) . ''; } $row_actions = array(); if ( $user_can_edit_table ) { $row_actions['edit'] = sprintf( '%3$s', $edit_url, esc_attr( sprintf( __( 'Edit “%s”', 'tablepress' ), $item['name'] ) ), __( 'Edit', 'tablepress' ) ); } $row_actions['shortcode hide-if-no-js'] = sprintf( '%3$s', '#', esc_attr( '[' . TablePress::$shortcode . " id={$item['id']} /]" ), __( 'Show Shortcode', 'tablepress' ) ); if ( $user_can_copy_table ) { $row_actions['copy'] = sprintf( '%3$s', $copy_url, esc_attr( sprintf( __( 'Copy “%s”', 'tablepress' ), $item['name'] ) ), __( 'Copy', 'tablepress' ) ); } if ( $user_can_export_table ) { $row_actions['export'] = sprintf( '%3$s', $export_url, esc_attr( sprintf( __( 'Export “%s”', 'tablepress' ), $item['name'] ) ), _x( 'Export', 'row action', 'tablepress' ) ); } if ( $user_can_delete_table ) { $row_actions['delete'] = sprintf( '%3$s', $delete_url, esc_attr( sprintf( __( 'Delete “%s”', 'tablepress' ), $item['name'] ) ), __( 'Delete', 'tablepress' ) ); } if ( $user_can_preview_table ) { $row_actions['table-preview'] = sprintf( '%3$s', $preview_url, esc_attr( sprintf( __( 'Show a preview of “%s”', 'tablepress' ), $item['name'] ) ), __( 'Preview', 'tablepress' ) ); } return $row_text . $this->row_actions( $row_actions ); } /** * Render a cell in the "table_description" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_description( array $item ) { if ( '' === trim( $item['description'] ) ) { $item['description'] = __( '(no description)', 'tablepress' ); } return esc_html( $item['description'] ); } /** * Render a cell in the "table_author" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_author( array $item ) { return TablePress::get_user_display_name( $item['author'] ); } /** * Render a cell in the "last_modified_by" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_last_modified_by( array $item ) { return TablePress::get_user_display_name( $item['options']['last_editor'] ); } /** * Render a cell in the "table_last_modified" column. * * @since 1.0.0 * * @param array $item Data item for the current row. * @return string HTML content of the cell. */ protected function column_table_last_modified( array $item ) { $modified_timestamp = strtotime( $item['last_modified'] ); $current_timestamp = current_time( 'timestamp' ); $time_diff = $current_timestamp - $modified_timestamp; // Time difference is only shown up to one day. if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) { $time_diff = sprintf( __( '%s ago', 'tablepress' ), human_time_diff( $modified_timestamp, $current_timestamp ) ); } else { $time_diff = TablePress::format_datetime( $item['last_modified'], 'mysql', '
' ); } $readable_time = TablePress::format_datetime( $item['last_modified'], 'mysql', ' ' ); return '' . $time_diff . ''; } /** * Get a list (name => title) bulk actions that are available. * * @since 1.0.0 * * @return array Bulk actions for this table. */ protected function get_bulk_actions() { $bulk_actions = array(); if ( current_user_can( 'tablepress_copy_tables' ) ) { $bulk_actions['copy'] = _x( 'Copy', 'bulk action', 'tablepress' ); } if ( current_user_can( 'tablepress_export_tables' ) ) { $bulk_actions['export'] = _x( 'Export', 'bulk action', 'tablepress' ); } if ( current_user_can( 'tablepress_delete_tables' ) ) { $bulk_actions['delete'] = _x( 'Delete', 'bulk action', 'tablepress' ); } return $bulk_actions; } /** * Render the bulk actions dropdown. * * In comparison with parent class, this has modified HTML (especially no field named "action" as that's being used already)! * * @since 1.0.0 * * @param string $which The location of the bulk actions: 'top' or 'bottom'. * This is designated as optional for backwards-compatibility. */ protected function bulk_actions( $which = '' ) { if ( is_null( $this->_actions ) ) { $no_new_actions = $this->_actions = $this->get_bulk_actions(); /** This filter is documented in the WordPress function WP_List_Table::bulk_actions() in wp-admin/includes/class-wp-list-table.php */ $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions ); $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions ); $two = ''; } else { $two = '2'; } if ( empty( $this->_actions ) ) { return; } $name_id = "bulk-action-{$which}"; echo "\n"; echo "\n"; submit_button( __( 'Apply', 'tablepress' ), 'action', '', false, array( 'id' => "doaction{$two}" ) ); echo "\n"; } /** * Holds the message to be displayed when there are no items in the table. * * @since 1.0.0 */ public function no_items() { _e( 'No tables found.', 'tablepress' ); if ( 0 === $this->items_count ) { $user_can_add_tables = current_user_can( 'tablepress_add_tables' ); $user_can_import_tables = current_user_can( 'tablepress_import_tables' ); $add_url = TablePress::url( array( 'action' => 'add' ) ); $import_url = TablePress::url( array( 'action' => 'import' ) ); if ( $user_can_add_tables && $user_can_import_tables ) { echo ' ' . sprintf( __( 'You should add or import a table to get started!', 'tablepress' ), $add_url, $import_url ); } elseif ( $user_can_add_tables ) { echo ' ' . sprintf( __( 'You should add a table to get started!', 'tablepress' ), $add_url ); } elseif ( $user_can_import_tables ) { echo ' ' . sprintf( __( 'You should import a table to get started!', 'tablepress' ), $import_url ); } } } /** * Generate the elements above or below the table (like bulk actions and pagination). * * In comparison with parent class, this has modified HTML (no nonce field), and a check whether there are items. * * @since 1.0.0 * * @param string $which Location ("top" or "bottom"). */ protected function display_tablenav( $which ) { if ( ! $this->has_items() ) { return; } ?>
bulk_actions( $which ); ?>
extra_tablenav( $which ); $this->pagination( $which ); ?>
load( $item, true, true ); // Don't search corrupted tables, except when debug mode is enabled via $_GET parameter or WP_DEBUG constant. if ( ! $debug && isset( $item['is_corrupted'] ) && $item['is_corrupted'] ) { return false; } // Search from easy to hard, so that "expensive" code maybe doesn't have to run. if ( false !== stripos( $item['id'], $term ) || false !== stripos( $item['name'], $term ) || false !== stripos( $item['description'], $term ) || false !== stripos( TablePress::get_user_display_name( $item['author'] ), $term ) || false !== stripos( TablePress::get_user_display_name( $item['options']['last_editor'] ), $term ) || false !== stripos( TablePress::format_datetime( $item['last_modified'], 'mysql', ' ' ), $term ) || false !== stripos( wp_json_encode( $item['data'] ), $json_encoded_term ) ) { return true; } return false; } /** * Callback to for the array sort function. * * @since 1.0.0 * * @param array $item_a First item that shall be compared to. * @param array $item_b The second item for the comparison. * @return int (-1, 0, 1) depending on which item sorts "higher". */ protected function _order_callback( array $item_a, array $item_b ) { global $orderby, $order; if ( 'last_modified_by' !== $orderby ) { if ( $item_a[ $orderby ] === $item_b[ $orderby ] ) { return 0; } } else { if ( $item_a['options']['last_editor'] === $item_b['options']['last_editor'] ) { return 0; } } // Certain fields require some extra work before being sortable. switch ( $orderby ) { case 'last_modified': // Compare UNIX timestamps for "last modified", which actually is a mySQL datetime string. $result = ( strtotime( $item_a['last_modified'] ) > strtotime( $item_b['last_modified'] ) ) ? 1 : -1; break; case 'author': // Get the actual author name, plain value is just the user ID. $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['author'] ), TablePress::get_user_display_name( $item_b['author'] ) ); break; case 'last_modified_by': // Get the actual last editor name, plain value is just the user ID. $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['options']['last_editor'] ), TablePress::get_user_display_name( $item_b['options']['last_editor'] ) ); break; default: // Other fields (ID, name, description) are sorted as strings. $result = strnatcasecmp( $item_a[ $orderby ], $item_b[ $orderby ] ); } return ( 'asc' === $order ) ? $result : - $result; } /** * Prepares the list of items for displaying, by maybe searching and sorting, and by doing pagination. * * @since 1.0.0 */ public function prepare_items() { global $orderby, $order, $s; wp_reset_vars( array( 'orderby', 'order', 's' ) ); // Maybe search in the items. if ( $s ) { $this->items = array_filter( $this->items, array( $this, '_search_callback' ) ); } // Load actual tables after search for less memory consumption. foreach ( $this->items as &$item ) { // Don't load data, but load table options for access to last_editor. $item = TablePress::$model_table->load( $item, false, true ); } // Break reference in foreach iterator. unset( $item ); // Maybe sort the items. $_sortable_columns = $this->get_sortable_columns(); if ( $orderby && ! empty( $this->items ) && isset( $_sortable_columns["table_{$orderby}"] ) ) { usort( $this->items, array( $this, '_order_callback' ) ); } // Number of records to show per page. $per_page = $this->get_items_per_page( 'tablepress_list_per_page', 20 ); // hard-coded, as in filter in Admin_Controller // Page number the user is currently viewing. $current_page = $this->get_pagenum(); // Number of records in the array. $total_items = count( $this->items ); // Slice items array to hold only items for the current page. $this->items = array_slice( $this->items, ( ( $current_page - 1 ) * $per_page ), $per_page ); // Register pagination options and calculation results. $this->set_pagination_args( array( 'total_items' => $total_items, // Total number of records/items 'per_page' => $per_page, // Number of items per page 'total_pages' => ceil( $total_items / $per_page ), // Total number of pages ) ); } } // class TablePress_All_Tables_List_Table