PluginProbe
TablePress – Tables in WordPress made easy / 3.4
TablePress – Tables in WordPress made easy v3.4
3.4 3.3.4 3.3.3 3.3.2 3.3.1 trunk 1.12 1.14 1.9.2 2.0.4 2.1.7 2.1.8 2.2 2.2.1 2.2.2 2.2.3 2.2.4 2.2.5 2.3 2.3.1 2.3.2 2.4 2.4.1 2.4.2 2.4.3 All 45 releases
← All changes | views/view-list.php +309 -650 1.9.2 → 3.4 View file →
@@ -7,13 +7,16 @@
7 7 * @author Tobias Bäthge
8 8 * @since 1.0.0
9 9 */
10 10
11 +declare(strict_types=1);
12 +
11 13 // Prohibit direct script loading.
12 14 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
13 15
14 16 /**
15 17 * List Tables View class
18 + *
16 19 * @package TablePress
17 20 * @subpackage Views
18 21 * @author Tobias Bäthge
19 22 * @since 1.0.0
@@ -23,11 +26,10 @@
23 26 /**
24 27 * Object for the All Tables List Table.
25 28 *
26 29 * @since 1.0.0
27 - * @var TablePress_All_Tables_List_Table
28 30 */
29 - protected $wp_list_table;
31 + protected \TablePress_All_Tables_List_Table $wp_list_table;
30 32
31 33 /**
32 34 * Set up the view with data and do things that are specific for this view.
33 35 *
@@ -32,93 +34,276 @@
32 34 * Set up the view with data and do things that are specific for this view.
33 35 *
34 36 * @since 1.0.0
35 37 *
36 - * @param string $action Action for this view.
37 - * @param array $data Data for this view.
38 + * @param string $action Action for this view.
39 + * @param array<string, mixed> $data Data for this view.
38 40 */
39 - public function setup( $action, array $data ) {
41 + #[\Override]
42 + public function setup( /* string */ $action, array $data ) /* : void */ {
43 + // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
44 +
40 45 parent::setup( $action, $data );
41 46
42 - add_thickbox();
43 - $this->admin_page->enqueue_script( 'list', array( 'jquery-core' ), array(
44 - 'list' => array(
45 - 'shortcode_popup' => __( 'To embed this table into a post or page, use this Shortcode:', 'tablepress' ),
46 - 'donation-message-already-donated' => __( 'Thank you very much! Your donation is highly appreciated. You just contributed to the further development of TablePress!', 'tablepress' ),
47 - '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&#8217;ll always find the &#8220;Donate&#8221; button on the <a href="%s">TablePress website</a>.', 'tablepress' ), 'https://tablepress.org/' ),
48 - ),
49 - ) );
47 + TablePress::enqueue_script( 'list' );
50 48
51 - if ( $data['messages']['first_visit'] ) {
52 - $this->add_header_message(
53 - '<strong><em>' . __( 'Welcome!', 'tablepress' ) . '</em></strong><br />'
54 - . __( 'Thank you for using TablePress for the first time!', 'tablepress' ) . ' '
55 - . sprintf( __( 'If you encounter any questions or problems, please visit the <a href="%1$s">FAQ</a>, the <a href="%2$s">documentation</a>, and the <a href="%3$s">Support</a> section on the <a href="%4$s">plugin website</a>.', 'tablepress' ), 'https://tablepress.org/faq/', 'https://tablepress.org/documentation/', 'https://tablepress.org/support/', 'https://tablepress.org/' ) . '<br /><br />'
56 - . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'first_visit', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ),
57 - 'notice-info not-dismissible'
49 + $milestone_period_ended = ( strtotime( '2026-10-10' ) < strtotime( 'today' ) );
50 +
51 + if ( $data['messages']['superseded_extensions'] ) {
52 + $superseded_extensions = array(
53 + 'tablepress-advanced-access-rights/tablepress-advanced-access-rights.php' => array(
54 + 'name' => 'TablePress Extension: Advanced Access Rights',
55 + 'compatible' => true,
56 + ),
57 + 'tablepress-auto-export-tables/tablepress-auto-export-tables.php' => array(
58 + 'name' => 'TablePress Extension: Automatic Table Export',
59 + 'compatible' => true,
60 + ),
61 + 'tablepress-cell-highlighting/tablepress-cell-highlighting.php' => array(
62 + 'name' => 'TablePress Extension: Cell Highlighting',
63 + 'compatible' => true,
64 + ),
65 + 'tablepress-datatables-alphabetsearch/tablepress-datatables-alphabetsearch.php' => array(
66 + 'name' => 'TablePress Extension: DataTables AlphabetSearch',
67 + 'compatible' => false,
68 + ),
69 + 'tablepress-datatables-buttons/tablepress-datatables-buttons.php' => array(
70 + 'name' => 'TablePress Extension: DataTables Buttons',
71 + 'compatible' => true,
72 + ),
73 + 'tablepress-datatables-column-filter-widgets/tablepress-datatables-column-filter-widgets.php' => array(
74 + 'name' => 'TablePress Extension: DataTables ColumnFilterWidgets',
75 + 'compatible' => false,
76 + ),
77 + 'tablepress-datatables-columnfilter/tablepress-datatables-columnfilter.php' => array(
78 + 'name' => 'TablePress Extension: DataTables Column Filter',
79 + 'compatible' => false,
80 + ),
81 + 'tablepress-datatables-counter-column/tablepress-datatables-counter-column.php' => array(
82 + 'name' => 'TablePress Extension: DataTables Counter Column',
83 + 'compatible' => true,
84 + ),
85 + 'tablepress-datatables-fixedcolumns/tablepress-datatables-fixedcolumns.php' => array(
86 + 'name' => 'TablePress Extension: DataTables FixedColumns',
87 + 'compatible' => false,
88 + ),
89 + 'tablepress-datatables-fixedheader/tablepress-datatables-fixedheader.php' => array(
90 + 'name' => 'TablePress Extension: DataTables FixedHeader',
91 + 'compatible' => true,
92 + ),
93 + 'tablepress-datatables-inverted-filter/tablepress-datatables-inverted-filter.php' => array(
94 + 'name' => 'TablePress Extension: DataTables Inverted Filter',
95 + 'compatible' => false,
96 + ),
97 + 'tablepress-datatables-row-details/tablepress-datatables-row-details.php' => array(
98 + 'name' => 'TablePress Extension: DataTables Row Details',
99 + 'compatible' => false,
100 + ),
101 + 'tablepress-datatables-rowgroup/tablepress-datatables-rowgroup.php' => array(
102 + 'name' => 'TablePress Extension: DataTables RowGroup',
103 + 'compatible' => false,
104 + ),
105 + 'tablepress-responsive-tables/tablepress-responsive-tables.php' => array(
106 + 'name' => 'TablePress Extension: Responsive Tables',
107 + 'compatible' => false,
108 + ),
109 + 'tablepress-row-filter/tablepress-row-filter.php' => array(
110 + 'name' => 'TablePress Extension: Row Filtering',
111 + 'compatible' => true,
112 + ),
113 + 'tablepress-row-highlighting/tablepress-row-highlighting.php' => array(
114 + 'name' => 'TablePress Extension: Row Highlighting',
115 + 'compatible' => true,
116 + ),
117 + 'tablepress-table-auto-update/tablepress-table-auto-update.php' => array(
118 + 'name' => 'TablePress Extension: Table Auto Update',
119 + 'compatible' => true,
120 + ),
121 + 'tablepress-table-column-order/tablepress-table-column-order.php' => array(
122 + 'name' => 'TablePress Extension: Table Column Order',
123 + 'compatible' => true,
124 + ),
58 125 );
126 +
127 + $active_compatible_superseded_extensions = array();
128 + $active_incompatible_superseded_extensions = array();
129 + foreach ( $superseded_extensions as $plugin => $extension ) {
130 + if ( is_plugin_active( $plugin ) ) {
131 + if ( $extension['compatible'] ) {
132 + $active_compatible_superseded_extensions[] = $extension['name'];
133 + } else {
134 + $active_incompatible_superseded_extensions[] = $extension['name'];
135 + }
136 + }
137 + }
138 +
139 + /*
140 + * If no superseded extensions are used, hide the message, to prevent running the checks on every load of the view.
141 + * This leaves a small risk of an Extension being activated later, but that's acceptable as they are no longer publicly available.
142 + */
143 + if ( empty( $active_incompatible_superseded_extensions ) && ( empty( $active_compatible_superseded_extensions ) || ! tb_tp_fs()->is_free_plan() ) ) {
144 + TablePress::$model_options->update( 'message_superseded_extensions', false );
145 + }
146 +
147 + $message = '';
148 +
149 + $notice_css_classes = 'not-dismissible';
150 +
151 + if ( ! empty( $active_incompatible_superseded_extensions ) ) {
152 + $notice_css_classes .= ' is-error notice-error';
153 +
154 + $message .= '<p style="font-size:16px;">' . __( 'You are using <strong>TablePress Extension plugins</strong> on this website that have been retired many years ago.', 'tablepress' ) . '<br>' . __( 'For technical reasons, some or all features of these outdated plugins <strong>do no longer work</strong>:', 'tablepress' ) . '</p>';
155 + $message .= '<ul style="list-style:disc;margin:0.5em 1em;font-size:16px;">';
156 + foreach ( $active_incompatible_superseded_extensions as $extension ) {
157 + $message .= '<li>' . esc_html( $extension ) . '</li>';
158 + }
159 + $message .= '</ul>';
160 + $message .= '<p style="font-size:16px;"><strong>' . __( 'Keeping them activated can lead to errors on your website.', 'tablepress' ) . '</strong></p>';
161 +
162 + if ( tb_tp_fs()->is_free_plan() ) {
163 + $message .= '<p style="font-size:16px;"><strong>' . sprintf( __( 'To continue using these features, <a href="%s">upgrade to a TablePress Premium license plan</a>!', 'tablepress' ), 'https://tablepress.org/upgrade-extensions/?utm_source=plugin&utm_medium=textlink&utm_content=superseded-extensions-message' ) . '</strong><br>'
164 + . __( 'TablePress Pro and TablePress Max come with updated and heavily improved versions of these features and include direct priority email support.', 'tablepress' ) . '</p>';
165 + }
166 +
167 + if ( ! empty( $active_compatible_superseded_extensions ) && tb_tp_fs()->is_free_plan() ) {
168 + $message .= '<p style="margin-top:1em;font-size:14px;">' . __( 'In addition, these TablePress Extension plugins have been retired and might become incompatible in the future as well:', 'tablepress' ) . '</strong></p>';
169 + $message .= '<ul style="list-style:disc;margin:0.5em 1em;font-size:14px;">';
170 + foreach ( $active_compatible_superseded_extensions as $extension ) {
171 + $message .= '<li>' . esc_html( $extension ) . '</li>';
172 + }
173 + $message .= '</ul>';
174 + }
175 + } elseif ( ! empty( $active_compatible_superseded_extensions ) && tb_tp_fs()->is_free_plan() ) {
176 + $notice_css_classes .= ' is-warning notice-warning';
177 +
178 + $message .= '<p style="font-size:14px;"><strong>' . __( 'You are using TablePress Extension plugins on this website that have been retired and will no longer receive updates or support:', 'tablepress' ) . '</strong></p>';
179 + $message .= '<ul style="list-style:disc;margin:0.5em 1em;">';
180 + foreach ( $active_compatible_superseded_extensions as $extension ) {
181 + $message .= '<li>' . esc_html( $extension ) . '</li>';
182 + }
183 + $message .= '</ul>';
184 + $message .= '<p style="font-size:14px;"><strong>' . __( 'It is possible that these become incompatible with TablePress or WordPress in the future!', 'tablepress' ) . '</strong></p>';
185 + $message .= '<p style="margin-top:1em;font-size:14px;">' . sprintf( __( 'However, their features were heavily improved and are now part of the up-to-date <a href="%s">TablePress Premium versions</a>!', 'tablepress' ), 'https://tablepress.org/upgrade-extensions/?utm_source=plugin&utm_medium=textlink&utm_content=superseded-extensions-message' ) . '</p>';
186 + }
187 +
188 + if ( '' !== $message ) {
189 + if ( tb_tp_fs()->is_free_plan() ) {
190 + $message .= '<p style="font-size:16px;margin-top:1.5em;"><strong>' . __( 'Upgrade to a TablePress Premium license plan now and get:', 'tablepress' ) . '</strong></p>';
191 + $message .= '<ul style="list-style:disc;margin:0.5em 1em;font-size:16px;">';
192 + $message .= '<li>' . __( 'Updated and heavily improved versions of these features!', 'tablepress' ) . '</li>';
193 + $message .= '<li>' . __( 'Direct integration into the user interface!', 'tablepress' ) . '</li>';
194 + $message .= '<li>' . __( 'Regular updates that ensure compatibility with WordPress!', 'tablepress' ) . '</li>';
195 + $message .= '<li>' . __( 'Priority email support!', 'tablepress' ) . '</li>';
196 + $message .= '</ul>';
197 + $message .= '<p style="font-size:16px;"><strong>' . sprintf( __( 'And the best: %s', 'tablepress' ), sprintf( __( 'Use the promo code %1$s during the checkout process for a special offer!', 'tablepress' ), '<code>UPGRADE</code>' ) ) . '</strong></p>';
198 + $message .= '<p style="margin-top:2em;">' . sprintf( '<a href="%s" class="components-button is-primary" style="font-size:14px;margin-right:3em;background:linear-gradient(135deg,#00d184 0%%,#0791e3 100%%);border:none;font-weight:bold;">%s<span class="dashicons dashicons-arrow-right-alt" style="vertical-align:middle;margin:0 0 4px 4px"></span></a>', 'https://tablepress.org/upgrade-extensions/?utm_source=plugin&utm_medium=button&utm_content=superseded-extensions-message', __( 'Upgrade to a TablePress Premium version now!', 'tablepress' ) );
199 + }
200 + $message .= $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'superseded_extensions', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ) . '</p>';
201 +
202 + $title = '<em>' . __( 'Important Notice!', 'tablepress' ) . '</em>';
203 +
204 + $this->add_header_message( $message, $notice_css_classes, $title );
205 + }
59 206 }
60 207
61 - if ( $data['messages']['wp_table_reloaded_warning'] ) {
62 - $this->add_header_message(
63 - '<strong><em>' . __( 'Attention!', 'tablepress' ) . '</em></strong><br />'
64 - . __( 'You have activated the plugin WP-Table Reloaded, which can not be used together with TablePress.', 'tablepress' ) . '<br />'
65 - . __( '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' ) . '<br />'
66 - . sprintf( __( 'Please follow the <a href="%s">migration guide</a> to move your tables and then deactivate WP-Table Reloaded!', 'tablepress' ), 'https://tablepress.org/migration-from-wp-table-reloaded/' ) . '<br />'
67 - . '<a href="' . TablePress::url( array( 'action' => 'import' ) ) . '" class="button button-primary button-large" style="color:#ffffff;margin-top:5px;">' . __( 'Import your tables from WP-Table Reloaded', 'tablepress' ) . '</a>',
68 - 'notice-error not-dismissible'
69 - );
208 + if ( $data['messages']['first_visit'] && ( ! $data['messages']['plugin_update'] || $milestone_period_ended ) ) {
209 + $message = '<p style="font-size:14px;"><strong>' . __( 'Thank you for choosing TablePress, the most popular table plugin for WordPress!', 'tablepress' ) . '</strong></p>';
210 + /* translators: %1$s: URL to FAQ, %2$s: URL to Documentation, %3$s: URL to Support, %4$s: URL to plugin website */
211 + $message .= '<p>' . sprintf( __( 'If you encounter any questions or problems, please visit the <a href="%1$s">FAQ</a>, the <a href="%2$s">Documentation</a>, and the <a href="%3$s">Support</a> section on the <a href="%4$s">plugin website</a>.', 'tablepress' ), 'https://tablepress.org/faq/', 'https://tablepress.org/documentation/', 'https://tablepress.org/support/', 'https://tablepress.org/' ) . '</p>';
212 +
213 + if ( tb_tp_fs()->is_free_plan() ) {
214 + $message .= '<p style="font-size:14px;"><strong>' . sprintf( __( 'More great features for you and your site’s visitors and priority email support are available with a Premium license plan of TablePress. <a href="%s">Go check them out!</a>', 'tablepress' ), 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=first-visit-message' ) . '</strong></p>';
215 + }
216 +
217 + $message .= '<p style="margin-top:1em;">' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'first_visit', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ) . '</p>';
218 +
219 + $title = '<em>' . __( 'Welcome!', 'tablepress' ) . '</em>';
220 +
221 + $this->add_header_message( $message, 'notice-info not-dismissible', $title );
70 222 }
71 223
72 - if ( $data['messages']['donation_message'] ) {
73 - $this->add_header_message(
74 - '<img alt="' . esc_attr__( 'Tobias Bäthge, developer of TablePress', 'tablepress' ) . '" src="https://secure.gravatar.com/avatar/50f1cff2e27a1f522b18ce229c057bc5?s=110" height="110" width="110" style="float:left;margin:1px 10px 40px 0;" />'
75 - . __( 'Hi, my name is Tobias, I&#8217;m the developer of the TablePress plugin.', 'tablepress' ) . '<br /><br />'
76 - . __( 'Thanks for using it! You&#8217;ve installed TablePress over a month ago.', 'tablepress' ) . ' '
77 - . sprintf( _n( 'If everything works and you are satisfied with the results of managing your %s table, isn&#8217;t that worth a coffee or two?', 'If everything works and you are satisfied with the results of managing your %s tables, isn&#8217;t that worth a coffee or two?', $data['table_count'], 'tablepress' ), esc_html( $data['table_count'] ) ) . '<br />'
78 - . sprintf( __( '<a href="%s">Donations</a> help me to continue user support and development of this <em>free</em> software &mdash; things for which I spend countless hours of my free time! Thank you very much!', 'tablepress' ), 'https://tablepress.org/donate/' ) . '<br /><br />'
79 - . __( 'Sincerely, Tobias', 'tablepress' ) . '<br /><br />'
80 - . sprintf( '<a href="%s" target="_blank"><strong>%s</strong></a>', 'https://tablepress.org/donate/', __( 'Sure, I&#8217;ll buy you a coffee and support TablePress!', 'tablepress' ) ) . '&nbsp;&nbsp;&nbsp;&nbsp;&middot;&nbsp;&nbsp;&nbsp;&nbsp;'
81 - . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'already-donated' ), __( 'I already donated.', 'tablepress' ) ) . '&nbsp;&nbsp;&nbsp;&nbsp;&middot;&nbsp;&nbsp;&nbsp;&nbsp;'
82 - . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list', 'target' => 'maybe-later' ), __( 'No, thanks. Don&#8217;t ask again.', 'tablepress' ) ),
83 - 'notice-success not-dismissible'
84 - );
224 + if ( $data['messages']['donation_nag'] && ( ! $data['messages']['plugin_update'] || $milestone_period_ended ) ) {
225 + $message = '<p style="font-size:14px;"><img alt="' . esc_attr__( 'Tobias Bäthge, developer of TablePress', 'tablepress' ) . '" src="https://secure.gravatar.com/avatar/50f1cff2e27a1f522b18ce229c057bc5?s=250" height="125" width="125" style="float:left;margin:2px 15px 30px 0;border-radius:5px;">'
226 + . __( 'Hi, my name is Tobias, I&#8217;m the developer of the TablePress plugin.', 'tablepress' ) . '</p>';
227 + $message .= '<p style="font-size:14px;">' . __( 'Thank you for using it!', 'tablepress' ) . ' ';
228 + if ( $data['table_count'] > 0 ) {
229 + /* translators: %s: Number of tables */
230 + $message .= sprintf( _n( 'I hope that everything works and that you are satisfied with the results of managing your %s table.', 'I hope that everything works and that you are satisfied with the results of managing your %s tables.', $data['table_count'], 'tablepress' ), $data['table_count'] );
231 + } else {
232 + /* translators: %s: URL to TablePress website */
233 + $message .= sprintf( __( 'It looks like you haven’t added a table yet. If you need help to get started, please find more information in the FAQ and Documentation on the <a href="%s">TablePress website</a>.', 'tablepress' ), 'https://tablepress.org/' );
234 + }
235 + $message .= '</p>';
236 + $message .= '<p style="font-size:14px;"><strong>' . sprintf( __( 'I would like to invite you to check out the <a href="%s">Premium versions of TablePress</a>.', 'tablepress' ), 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=upgrade-message' ) . '<br>'
237 + . __( 'The available Pro and Max plans offer user support and many exciting and helpful features for your tables.', 'tablepress' ) . '</strong></p>';
238 + $message .= '<p style="font-size:14px;">' . __( 'Sincerely, Tobias', 'tablepress' ) . '</p>';
239 + $message .= '<p style="margin-top:1em;">' . sprintf( '<a href="%s" class="components-button is-primary" style="font-size:14px;margin-right:3em;color:#ffffff;">%s<span class="dashicons dashicons-arrow-right-alt" style="margin-inline:8px 0"></span></a>', 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=button&utm_content=upgrade-message', __( 'Tell me more about the Premium features', 'tablepress' ) )
240 + . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'donation_nag', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ) . '</p>';
241 +
242 + $title = '<em>' . __( 'TablePress has more to offer!', 'tablepress' ) . '</em>';
243 +
244 + $this->add_header_message( $message, 'notice-success not-dismissible', $title );
85 245 }
86 246
87 - if ( $data['messages']['plugin_update_message'] ) {
88 - $this->add_header_message(
89 - '<strong><em>' . sprintf( __( 'Thank you for updating to TablePress %s!', 'tablepress' ), TablePress::version ) . '</em></strong><br />'
90 - . sprintf( __( 'Please read the <a href="%s">release announcement</a> for more information.', 'tablepress' ), 'https://tablepress.org/news/' ) . ' '
91 - . sprintf( __( 'If you like the new features and enhancements, <a href="%s">giving a donation</a> towards the further support and development of TablePress is recommended. Thank you!', 'tablepress' ), 'https://tablepress.org/donate/' )
92 - . '<br /><br />'
93 - . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'plugin_update', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ),
94 - 'notice-info not-dismissible'
95 - );
247 + if ( $data['messages']['plugin_update'] ) {
248 + if ( $milestone_period_ended ) {
249 + $message = '<p>' . sprintf( __( 'To find out more about what’s new, please read the <a href="%s"><strong>release announcement</strong></a>.', 'tablepress' ), 'https://tablepress.org/news/?utm_source=plugin&utm_medium=textlink&utm_content=plugin-update-message' ) . '</p>';
250 +
251 + if ( tb_tp_fs()->is_free_plan() ) {
252 + $message .= '<p><strong>' . sprintf( __( 'More great features and priority email support are available with a Premium license plan. <a href="%s">Check them out!</a>', 'tablepress' ), 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=plugin-update-message' ) . '</strong></p>';
253 + }
254 +
255 + $title = '<em>' . sprintf( __( 'Thank you for updating to TablePress %s!', 'tablepress' ), TablePress::version ) . '</em>';
256 + $class = 'notice-info not-dismissible';
257 + } else {
258 + $texts_german = in_array( get_user_locale(), array( 'de_DE', 'de_AT', 'de_CH' ), true );
259 + if ( $texts_german ) {
260 + $message = '<p style="font-size:16px;">Wir feiern <strong>25 Millionen Downloads</strong> von TablePress aus dem WordPress-Pluginverzeichnis!<br>Mach mit und <strong>spare 25&#8239;%</strong> beim Upgrade auf TablePress Pro oder TablePress Max!</p>';
261 + } else {
262 + $message = '<p style="font-size:16px;">We’re celebrating <strong>25 million downloads</strong> of TablePress from the WordPress Plugin Directory!<br>Join us and <strong>get 25% off</strong> your TablePress Pro or TablePress Max upgrade!</p>';
263 + }
264 + $url = 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=notice&utm_campaign=upgrade-message340&utm_content=button';
265 + $message .= '<p style="margin-top:1em;margin-bottom:24px;">' . sprintf( '<a href="%s" class="components-button is-primary" target="_blank"><span>%s</span><span class="dashicons dashicons-arrow-right-alt" style="margin-inline:8px 0"></span></a>', $url, $texts_german ? 'Spare jetzt 25&#8239;%' : 'Get 25% off now' ) . '</p>';
266 +
267 + $filename = $texts_german ? 'admin/img/dl-25-period.svg' : 'admin/img/dl-25-comma.svg';
268 + $message .= sprintf( '<img src="%1$s" alt="%2$s">', plugins_url( $filename, TABLEPRESS__FILE__ ), $texts_german ? 'Grafik mit einer Tabelle mit „Downloads“ in der Kopfzeile und der Zahl 25.000.000 im Tabellenkörper' : 'Graphic with a table with “Downloads” in the header and the number 25,000,000 in the body' );
269 +
270 + $title = '';
271 + $class = 'notice-milestone not-dismissible';
272 + }
273 +
274 + $message .= '<p style="margin-top:1em;">' . $this->ajax_link( array( 'action' => 'hide_message', 'item' => 'plugin_update', 'return' => 'list' ), __( 'Hide this message', 'tablepress' ) ) . '</p>';
275 +
276 + $this->add_header_message( $message, $class, $title );
96 277 }
97 278
98 279 $this->process_action_messages( array(
99 - 'success_delete' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 1, 'tablepress' ),
100 - 'success_delete_plural' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 2, 'tablepress' ),
101 - 'error_delete' => __( 'Error: The table could not be deleted.', 'tablepress' ),
102 - 'error_save' => __( 'Error: The table could not be saved.', 'tablepress' ),
103 - '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 &#8220;%s&#8221;.', 'tablepress' ), esc_html( $data['table_id'] ) ) : '' ),
104 - 'success_copy_plural' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 2, 'tablepress' ),
105 - 'error_copy' => __( 'Error: The table could not be copied.', 'tablepress' ),
106 - 'error_no_table' => __( 'Error: You did not specify a valid table ID.', 'tablepress' ),
107 - 'error_load_table' => __( 'Error: This table could not be loaded!', 'tablepress' ),
108 - 'error_bulk_action_invalid' => __( 'Error: This bulk action is invalid!', 'tablepress' ),
109 - 'error_no_selection' => __( 'Error: You did not select any tables!', 'tablepress' ),
110 - 'error_delete_not_all_tables' => __( 'Notice: Not all selected tables could be deleted!', 'tablepress' ),
111 - 'error_copy_not_all_tables' => __( 'Notice: Not all selected tables could be copied!', 'tablepress' ),
112 - 'success_import' => __( 'The tables were imported successfully.', 'tablepress' ),
113 - 'success_import_wp_table_reloaded' => __( 'The tables were imported successfully from WP-Table Reloaded.', 'tablepress' ),
280 + 'success_delete' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 1, 'tablepress' ),
281 + 'success_delete_plural' => _n( 'The table was deleted successfully.', 'The tables were deleted successfully.', 2, 'tablepress' ),
282 + 'error_delete' => __( 'Error: The table could not be deleted.', 'tablepress' ),
283 + 'success_copy' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 1, 'tablepress' )
284 + . ( ( false !== $data['table_id'] )
285 + ? ' ' . ( current_user_can( 'tablepress_edit_table', $data['table_id'] )
286 + ? sprintf( __( 'You can now <a href="%1$s">edit the copied table</a>, which has the table ID “%2$s”.', 'tablepress' ), esc_url( TablePress::url( array( 'action' => 'edit', 'table_id' => $data['table_id'] ) ) ), esc_html( $data['table_id'] ) )
287 + : sprintf( __( 'The copied table has the table ID &#8220;%s&#8221;.', 'tablepress' ), esc_html( $data['table_id'] ) ) )
288 + : ''
289 + ),
290 + 'success_copy_plural' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 2, 'tablepress' ),
291 + 'error_copy' => __( 'Error: The table could not be copied.', 'tablepress' ),
292 + 'error_no_table' => __( 'Error: You did not specify a valid table ID.', 'tablepress' ),
293 + 'error_load_table' => __( 'Error: This table could not be loaded!', 'tablepress' ),
294 + 'error_bulk_action_invalid' => __( 'Error: This bulk action is invalid!', 'tablepress' ),
295 + 'error_no_selection' => __( 'Error: You did not select any tables!', 'tablepress' ),
296 + 'error_delete_not_all_tables' => __( 'Notice: Not all selected tables could be deleted!', 'tablepress' ),
297 + 'error_copy_not_all_tables' => __( 'Notice: Not all selected tables could be copied!', 'tablepress' ),
298 + 'success_import' => __( 'The tables were imported successfully.', 'tablepress' ),
114 299 ) );
115 300
116 301 $this->add_text_box( 'head', array( $this, 'textbox_head' ), 'normal' );
117 302 $this->add_text_box( 'tables-list', array( $this, 'textbox_tables_list' ), 'normal' );
118 303
119 - 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
120 - $this->wp_list_table = new TablePress_All_Tables_List_Table();
304 + 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.
305 + $this->wp_list_table = TablePress::load_class( 'TablePress_All_Tables_List_Table', 'class-all-tables-list-table.php', 'views' );
121 306 $this->wp_list_table->set_items( $this->data['table_ids'] );
122 307 $this->wp_list_table->prepare_items();
123 308
124 309 // Cleanup Request URI string, which WP_List_Table uses to generate the sort URLs.
@@ -129,20 +314,26 @@
129 314 * Render the current view (in this view: without form tag).
130 315 *
131 316 * @since 1.0.0
132 317 */
133 - public function render() {
318 + #[\Override]
319 + public function render(): void {
134 320 ?>
135 321 <div id="tablepress-page" class="wrap">
136 322 <?php
137 323 $this->print_nav_tab_menu();
138 - // Print all header messages.
139 - foreach ( $this->header_messages as $message ) {
140 - echo $message;
141 - }
324 + ?>
325 + <div id="tablepress-body">
326 + <hr class="wp-header-end">
327 + <script>document.querySelectorAll('.notice:has(~#tablepress-page)').forEach(e=>document.querySelector('.wp-header-end').after(e));</script>
328 + <?php
329 + // Print all header messages.
330 + foreach ( $this->header_messages as $message ) {
331 + echo $message;
332 + }
142 333
143 - // For this screen, this is done in textbox_tables_list(), to get the fields into the correct <form>:
144 - // $this->do_text_boxes( 'header' );
334 + // For this screen, this is done in textbox_tables_list(), to get the fields into the correct <form>:
335 + // $this->do_text_boxes( 'header' );.
145 336 ?>
146 337 <div id="poststuff">
147 338 <div id="post-body" class="metabox-holder columns-<?php echo ( isset( $GLOBALS['screen_layout_columns'] ) && ( 2 === $GLOBALS['screen_layout_columns'] ) ) ? '2' : '1'; ?>">
148 339 <div id="postbox-container-2" class="postbox-container">
@@ -164,11 +355,12 @@
164 355 $this->do_meta_boxes( 'side' );
165 356 ?>
166 357 </div>
167 358 </div>
168 - <br class="clear" />
359 + <br class="clear">
169 360 </div>
170 361 </div>
362 + </div>
171 363 <?php
172 364 }
173 365
174 366 /**
@@ -175,25 +367,26 @@
175 367 * Print the screen head text.
176 368 *
177 369 * @since 1.0.0
178 370 *
179 - * @param array $data Data for this screen.
180 - * @param array $box Information about the text box.
371 + * @param array<string, mixed> $data Data for this screen.
372 + * @param array<string, mixed> $box Information about the text box.
181 373 */
182 - public function textbox_head( array $data, array $box ) {
183 - ?>
184 - <p>
185 - <?php _e( 'This is a list of your tables.', 'tablepress' ); ?>
186 - <?php _e( 'Click the corresponding links within the list to edit, copy, delete, or preview a table.', 'tablepress' ); ?>
187 - </p>
188 - <p>
189 - <label class="screen-reader-only" for="table-shortcode-inline"><?php esc_html_e( 'Shortcode text for editor', 'tablepress' ); ?></label>
190 -
191 - <?php printf( __( 'To insert a table into a page, post, or text widget, copy its Shortcode %s and paste it at the desired place in the editor.', 'tablepress' ), '<input type="text" class="table-shortcode table-shortcode-inline" id="table-shortcode-inline" value="' . esc_attr( '[' . TablePress::$shortcode . ' id=<ID> /]' ) . '" readonly="readonly" />' ); ?>
192 - <?php _e( 'Each table has a unique ID that needs to be adjusted in that Shortcode.', 'tablepress' ); ?>
193 - <?php printf( __( 'You can also click the &#8220;%s&#8221; button in the editor toolbar to select and insert a table.', 'tablepress' ), __( 'Table', 'tablepress' ) ); ?>
194 - </p>
195 - <?php
374 + public function textbox_head( array $data, array $box ): void {
375 + echo '<p>';
376 + _e( 'This is a list of your tables.', 'tablepress' );
377 + echo ' ';
378 + // Show the instructions string depending on whether the Block Editor is used on the site or not.
379 + if ( 'block' === $data['site_used_editor'] ) {
380 + printf( __( 'To insert a table into a post or page, add a “%1$s” block in the block editor and select the desired table.', 'tablepress' ), __( 'TablePress table', 'tablepress' ) );
381 + } elseif ( 'elementor' === $data['site_used_editor'] ) {
382 + printf( __( 'To insert a table into a post or page, add a “%1$s” widget in the Elementor editor and select the desired table.', 'tablepress' ), __( 'TablePress table', 'tablepress' ) );
383 + } else {
384 + _e( 'To insert a table into a post or page, paste its Shortcode at the desired place in the editor.', 'tablepress' );
385 + echo ' ';
386 + _e( 'Each table has a unique ID that needs to be adjusted in that Shortcode.', 'tablepress' );
387 + }
388 + echo '</p>';
196 389 }
197 390
198 391 /**
199 392 * Print the content of the "All Tables" text box.
@@ -199,32 +392,33 @@
199 392 * Print the content of the "All Tables" text box.
200 393 *
201 394 * @since 1.0.0
202 395 *
203 - * @param array $data Data for this screen.
204 - * @param array $box Information about the text box.
396 + * @param array<string, mixed> $data Data for this screen.
397 + * @param array<string, mixed> $box Information about the text box.
205 398 */
206 - public function textbox_tables_list( array $data, array $box ) {
399 + public function textbox_tables_list( array $data, array $box ): void {
207 400 if ( ! empty( $_GET['s'] ) ) {
208 401 printf( '<span class="subtitle">' . __( 'Search results for &#8220;%s&#8221;', 'tablepress' ) . '</span>', esc_html( wp_unslash( $_GET['s'] ) ) );
209 402 }
210 - ?>
211 -<form method="get" action="">
212 - <?php
213 - if ( isset( $_GET['page'] ) ) {
214 - echo '<input type="hidden" name="page" value="' . esc_attr( $_GET['page'] ) . '" />' . "\n";
215 - }
216 - $this->wp_list_table->search_box( __( 'Search Tables', 'tablepress' ), 'tables_search' );
217 - ?>
403 + ?>
404 +<form method="get">
405 + <?php
406 + if ( isset( $_GET['page'] ) ) {
407 + echo '<input type="hidden" name="page" value="' . esc_attr( $_GET['page'] ) . '">' . "\n";
408 + }
409 + $this->wp_list_table->search_box( __( 'Search Tables', 'tablepress' ), 'tables_search' );
410 + ?>
218 411 </form>
219 412 <form action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" method="post">
220 - <?php
413 + <?php
221 414 // This prints the nonce and action fields for this screen (done here instead of render(), due to moved <form>).
222 415 $this->do_text_boxes( 'header' );
223 416 $this->wp_list_table->display();
224 - ?>
417 + ?>
225 418 </form>
226 - <?php
419 +<div id="tablepress-list-screen"></div>
420 + <?php
227 421 }
228 422
229 423 /**
230 424 * Create HTML code for an AJAXified link.
@@ -230,556 +424,21 @@
230 424 * Create HTML code for an AJAXified link.
231 425 *
232 426 * @since 1.0.0
233 427 *
234 - * @param array $params Parameters for the URL.
235 - * @param string $text Text for the link.
428 + * @param array<string, mixed> $params Parameters for the URL.
429 + * @param string $text Text for the link.
236 430 * @return string HTML code for the link.
237 431 */
238 - protected function ajax_link( array $params = array( 'action' => 'list', 'item' => '' ), $text ) {
432 + protected function ajax_link( array $params, string $text ): string {
433 + $class = 'ajax-link';
434 + if ( ! empty( $params['class'] ) ) {
435 + $class .= ' ' . esc_attr( $params['class'] );
436 + }
239 437 $url = TablePress::url( $params, true, 'admin-post.php' );
240 438 $action = esc_attr( $params['action'] );
241 439 $item = esc_attr( $params['item'] );
242 - $target = isset( $params['target'] ) ? esc_attr( $params['target'] ) : '';
243 - return "<a class=\"ajax-link\" href=\"{$url}\" data-action=\"{$action}\" data-item=\"{$item}\" data-target=\"{$target}\">{$text}</a>";
440 + $target = esc_attr( $params['target'] ?? '' );
441 + return "<a class=\"{$class}\" href=\"{$url}\" data-action=\"{$action}\" data-item=\"{$item}\" data-target=\"{$target}\">{$text}</a>";
244 442 }
245 443
246 444 } // class TablePress_List_View
247 -
248 -/**
249 - * TablePress All Tables List Table Class
250 - * @package TablePress
251 - * @subpackage Views
252 - * @author Tobias Bäthge
253 - * @link https://codex.wordpress.org/Class_Reference/WP_List_Table
254 - * @since 1.0.0
255 - */
256 -class TablePress_All_Tables_List_Table extends WP_List_Table {
257 -
258 - /**
259 - * Number of items of the initial data set (before sort, search, and pagination).
260 - *
261 - * @since 1.0.0
262 - * @var int
263 - */
264 - protected $items_count = 0;
265 -
266 - /**
267 - * Initialize the List Table.
268 - *
269 - * @since 1.0.0
270 - */
271 - public function __construct() {
272 - $screen = get_current_screen();
273 -
274 - // Hide "Last Modified By" column by default.
275 - if ( false === get_user_option( 'manage' . $screen->id . 'columnshidden' ) ) {
276 - update_user_option( get_current_user_id(), 'manage' . $screen->id . 'columnshidden', array( 'table_last_modified_by' ), true );
277 - }
278 -
279 - parent::__construct( array(
280 - 'singular' => 'tablepress-table', // Singular name of the listed records.
281 - 'plural' => 'tablepress-all-tables', // Plural name of the listed records.
282 - 'ajax' => false, // Does this list table support AJAX?
283 - 'screen' => $screen, // WP_Screen object.
284 - ) );
285 - }
286 -
287 - /**
288 - * Set the data items (here: tables) that are to be displayed by the List Tables, and their original count.
289 - *
290 - * @since 1.0.0
291 - *
292 - * @param array $items Tables to be displayed in the List Table.
293 - */
294 - public function set_items( array $items ) {
295 - $this->items = $items;
296 - $this->items_count = count( $items );
297 - }
298 -
299 - /**
300 - * Check whether the user has permissions for certain AJAX actions.
301 - * (not used, but must be implemented in this child class)
302 - *
303 - * @since 1.0.0
304 - *
305 - * @return bool true (Default value).
306 - */
307 - public function ajax_user_can() {
308 - return true;
309 - }
310 -
311 - /**
312 - * Get a list of columns in this List Table.
313 - *
314 - * Format: 'internal-name' => 'Column Title'.
315 - *
316 - * @since 1.0.0
317 - *
318 - * @return array List of columns in this List Table.
319 - */
320 - public function get_columns() {
321 - $columns = array(
322 - 'cb' => $this->has_items() ? '<input type="checkbox" />' : '', // Checkbox for "Select all", but only if there are items in the table.
323 - // "name" is special in WP, which is why we prefix every entry here, to be safe!
324 - 'table_id' => __( 'ID', 'tablepress' ),
325 - 'table_name' => __( 'Table Name', 'tablepress' ),
326 - 'table_description' => __( 'Description', 'tablepress' ),
327 - 'table_author' => __( 'Author', 'tablepress' ),
328 - 'table_last_modified_by' => __( 'Last Modified By', 'tablepress' ),
329 - 'table_last_modified' => __( 'Last Modified', 'tablepress' ),
330 - );
331 - return $columns;
332 - }
333 -
334 - /**
335 - * Get a list of columns that are sortable.
336 - *
337 - * Format: 'internal-name' => array( $field for $item[ $field ], true for already sorted ).
338 - *
339 - * @since 1.0.0
340 - *
341 - * @return array List of sortable columns in this List Table.
342 - */
343 - protected function get_sortable_columns() {
344 - // No sorting on the Empty List placeholder.
345 - if ( ! $this->has_items() ) {
346 - return array();
347 - }
348 -
349 - $sortable_columns = array(
350 - 'table_id' => array( 'id', true ), // true means its already sorted
351 - 'table_name' => array( 'name', false ),
352 - 'table_description' => array( 'description', false ),
353 - 'table_author' => array( 'author', false ),
354 - 'table_last_modified_by' => array( 'last_modified_by', false ),
355 - 'table_last_modified' => array( 'last_modified', false ),
356 - );
357 - return $sortable_columns;
358 - }
359 -
360 - /**
361 - * Gets the name of the default primary column.
362 - *
363 - * @since 1.7.0
364 - *
365 - * @return string Name of the default primary column, in this case, the table name.
366 - */
367 - protected function get_default_primary_column_name() {
368 - return 'table_name';
369 - }
370 -
371 - /**
372 - * Render a cell in the "cb" column.
373 - *
374 - * @since 1.0.0
375 - *
376 - * @param array $item Data item for the current row.
377 - * @return string HTML content of the cell.
378 - */
379 - protected function column_cb( /* array */ $item ) { // No `array` type hint to prevent a Strict Standards notice, as the method is inherited.
380 - $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
381 - $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
382 - $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
383 -
384 - if ( $user_can_copy_table || $user_can_delete_table || $user_can_export_table ) {
385 - return sprintf(
386 - '<label><span class="screen-reader-text">%1$s</span><input type="checkbox" name="table[]" value="%2$s" /></label>',
387 - esc_html__( 'Bulk action selector', 'tablepress' ),
388 - esc_attr( $item['id'] )
389 - );
390 - } else {
391 - return '';
392 - }
393 - }
394 -
395 - /**
396 - * Render a cell in the "table_id" column.
397 - *
398 - * @since 1.0.0
399 - *
400 - * @param array $item Data item for the current row.
401 - * @return string HTML content of the cell.
402 - */
403 - protected function column_table_id( array $item ) {
404 - return esc_html( $item['id'] );
405 - }
406 -
407 - /**
408 - * Render a cell in the "table_name" column.
409 - *
410 - * @since 1.0.0
411 - *
412 - * @param array $item Data item for the current row.
413 - * @return string HTML content of the cell.
414 - */
415 - protected function column_table_name( array $item ) {
416 - $user_can_edit_table = current_user_can( 'tablepress_edit_table', $item['id'] );
417 - $user_can_copy_table = current_user_can( 'tablepress_copy_table', $item['id'] );
418 - $user_can_export_table = current_user_can( 'tablepress_export_table', $item['id'] );
419 - $user_can_delete_table = current_user_can( 'tablepress_delete_table', $item['id'] );
420 - $user_can_preview_table = current_user_can( 'tablepress_preview_table', $item['id'] );
421 -
422 - $edit_url = TablePress::url( array( 'action' => 'edit', 'table_id' => $item['id'] ) );
423 - $copy_url = TablePress::url( array( 'action' => 'copy_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
424 - $export_url = TablePress::url( array( 'action' => 'export', 'table_id' => $item['id'] ) );
425 - $delete_url = TablePress::url( array( 'action' => 'delete_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
426 - $preview_url = TablePress::url( array( 'action' => 'preview_table', 'item' => $item['id'], 'return' => 'list', 'return_item' => $item['id'] ), true, 'admin-post.php' );
427 -
428 - if ( '' === trim( $item['name'] ) ) {
429 - $item['name'] = __( '(no name)', 'tablepress' );
430 - }
431 -
432 - if ( $user_can_edit_table ) {
433 - $row_text = '<strong><a title="' . esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;', 'tablepress' ), esc_attr( $item['name'] ) ) ) . '" class="row-title" href="' . $edit_url . '">' . esc_html( $item['name'] ) . '</a></strong>';
434 - } else {
435 - $row_text = '<strong>' . esc_html( $item['name'] ) . '</strong>';
436 - }
437 -
438 - $row_actions = array();
439 - if ( $user_can_edit_table ) {
440 - $row_actions['edit'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $edit_url, esc_attr( sprintf( __( 'Edit &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Edit', 'tablepress' ) );
441 - }
442 - $row_actions['shortcode hide-if-no-js'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', '#', esc_attr( '[' . TablePress::$shortcode . " id={$item['id']} /]" ), __( 'Show Shortcode', 'tablepress' ) );
443 - if ( $user_can_copy_table ) {
444 - $row_actions['copy'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $copy_url, esc_attr( sprintf( __( 'Copy &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Copy', 'tablepress' ) );
445 - }
446 - if ( $user_can_export_table ) {
447 - $row_actions['export'] = sprintf( '<a href="%1$s" title="%2$s">%3$s</a>', $export_url, esc_attr( sprintf( __( 'Export &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), _x( 'Export', 'row action', 'tablepress' ) );
448 - }
449 - if ( $user_can_delete_table ) {
450 - $row_actions['delete'] = sprintf( '<a href="%1$s" title="%2$s" class="delete-link">%3$s</a>', $delete_url, esc_attr( sprintf( __( 'Delete &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Delete', 'tablepress' ) );
451 - }
452 - if ( $user_can_preview_table ) {
453 - $row_actions['table-preview'] = sprintf( '<a href="%1$s" title="%2$s" target="_blank">%3$s</a>', $preview_url, esc_attr( sprintf( __( 'Show a preview of &#8220;%s&#8221;', 'tablepress' ), $item['name'] ) ), __( 'Preview', 'tablepress' ) );
454 - }
455 -
456 - return $row_text . $this->row_actions( $row_actions );
457 - }
458 -
459 - /**
460 - * Render a cell in the "table_description" column.
461 - *
462 - * @since 1.0.0
463 - *
464 - * @param array $item Data item for the current row.
465 - * @return string HTML content of the cell.
466 - */
467 - protected function column_table_description( array $item ) {
468 - if ( '' === trim( $item['description'] ) ) {
469 - $item['description'] = __( '(no description)', 'tablepress' );
470 - }
471 - return esc_html( $item['description'] );
472 - }
473 -
474 - /**
475 - * Render a cell in the "table_author" column.
476 - *
477 - * @since 1.0.0
478 - *
479 - * @param array $item Data item for the current row.
480 - * @return string HTML content of the cell.
481 - */
482 - protected function column_table_author( array $item ) {
483 - return TablePress::get_user_display_name( $item['author'] );
484 - }
485 -
486 - /**
487 - * Render a cell in the "last_modified_by" column.
488 - *
489 - * @since 1.0.0
490 - *
491 - * @param array $item Data item for the current row.
492 - * @return string HTML content of the cell.
493 - */
494 - protected function column_table_last_modified_by( array $item ) {
495 - return TablePress::get_user_display_name( $item['options']['last_editor'] );
496 - }
497 -
498 - /**
499 - * Render a cell in the "table_last_modified" column.
500 - *
501 - * @since 1.0.0
502 - *
503 - * @param array $item Data item for the current row.
504 - * @return string HTML content of the cell.
505 - */
506 - protected function column_table_last_modified( array $item ) {
507 - $modified_timestamp = strtotime( $item['last_modified'] );
508 - $current_timestamp = current_time( 'timestamp' );
509 - $time_diff = $current_timestamp - $modified_timestamp;
510 - // Time difference is only shown up to one day.
511 - if ( $time_diff >= 0 && $time_diff < DAY_IN_SECONDS ) {
512 - $time_diff = sprintf( __( '%s ago', 'tablepress' ), human_time_diff( $modified_timestamp, $current_timestamp ) );
513 - } else {
514 - $time_diff = TablePress::format_datetime( $item['last_modified'], 'mysql', '<br />' );
515 - }
516 -
517 - $readable_time = TablePress::format_datetime( $item['last_modified'], 'mysql', ' ' );
518 - return '<abbr title="' . esc_attr( $readable_time ) . '">' . $time_diff . '</abbr>';
519 - }
520 -
521 - /**
522 - * Handles output for the default column.
523 - *
524 - * @since 1.8.0
525 - *
526 - * @param array $item Data item for the current row.
527 - * @param string $column_name Current column name.
528 - */
529 - protected function column_default( /* array */ $item, $column_name ) { // No `array` type hint to prevent a Strict Standards notice, as the method is inherited.
530 - /**
531 - * Fires inside each custom column of the TablePress list table.
532 - *
533 - * @since 1.8.0
534 - *
535 - * @param array $column_name Current column name.
536 - * @param string $item Data item for the current row.
537 - */
538 - do_action( 'manage_tablepress_list_custom_column', $column_name, $item );
539 - }
540 -
541 - /**
542 - * Get a list (name => title) bulk actions that are available.
543 - *
544 - * @since 1.0.0
545 - *
546 - * @return array Bulk actions for this table.
547 - */
548 - protected function get_bulk_actions() {
549 - $bulk_actions = array();
550 -
551 - if ( current_user_can( 'tablepress_copy_tables' ) ) {
552 - $bulk_actions['copy'] = _x( 'Copy', 'bulk action', 'tablepress' );
553 - }
554 - if ( current_user_can( 'tablepress_export_tables' ) ) {
555 - $bulk_actions['export'] = _x( 'Export', 'bulk action', 'tablepress' );
556 - }
557 - if ( current_user_can( 'tablepress_delete_tables' ) ) {
558 - $bulk_actions['delete'] = _x( 'Delete', 'bulk action', 'tablepress' );
559 - }
560 -
561 - return $bulk_actions;
562 - }
563 -
564 - /**
565 - * Render the bulk actions dropdown.
566 - *
567 - * In comparison with parent class, this has modified HTML (especially no field named "action" as that's being used already)!
568 - *
569 - * @since 1.0.0
570 - *
571 - * @param string $which The location of the bulk actions: 'top' or 'bottom'.
572 - * This is designated as optional for backwards-compatibility.
573 - */
574 - protected function bulk_actions( $which = '' ) {
575 - if ( is_null( $this->_actions ) ) {
576 - $no_new_actions = $this->_actions = $this->get_bulk_actions();
577 - /** This filter is documented in the WordPress function WP_List_Table::bulk_actions() in wp-admin/includes/class-wp-list-table.php */
578 - $this->_actions = apply_filters( 'bulk_actions-' . $this->screen->id, $this->_actions );
579 - $this->_actions = array_intersect_assoc( $this->_actions, $no_new_actions );
580 - $two = '';
581 - } else {
582 - $two = '2';
583 - }
584 -
585 - if ( empty( $this->_actions ) ) {
586 - return;
587 - }
588 -
589 - $name_id = "bulk-action-{$which}";
590 - echo "<label for='{$name_id}' class='screen-reader-text'>" . __( 'Select Bulk Action', 'tablepress' ) . "</label>\n";
591 - echo "<select name='{$name_id}' id='{$name_id}'>\n";
592 - echo "<option value='-1' selected='selected'>" . __( 'Bulk Actions', 'tablepress' ) . "</option>\n";
593 - foreach ( $this->_actions as $name => $title ) {
594 - echo "\t<option value='{$name}'>{$title}</option>\n";
595 - }
596 - echo "</select>\n";
597 - submit_button( __( 'Apply', 'tablepress' ), 'action', '', false, array( 'id' => "doaction{$two}" ) );
598 - echo "\n";
599 - }
600 -
601 - /**
602 - * Holds the message to be displayed when there are no items in the table.
603 - *
604 - * @since 1.0.0
605 - */
606 - public function no_items() {
607 - _e( 'No tables found.', 'tablepress' );
608 - if ( 0 === $this->items_count ) {
609 - $user_can_add_tables = current_user_can( 'tablepress_add_tables' );
610 - $user_can_import_tables = current_user_can( 'tablepress_import_tables' );
611 -
612 - $add_url = TablePress::url( array( 'action' => 'add' ) );
613 - $import_url = TablePress::url( array( 'action' => 'import' ) );
614 -
615 - if ( $user_can_add_tables && $user_can_import_tables ) {
616 - echo ' ' . sprintf( __( 'You should <a href="%1$s">add</a> or <a href="%2$s">import</a> a table to get started!', 'tablepress' ), $add_url, $import_url );
617 - } elseif ( $user_can_add_tables ) {
618 - echo ' ' . sprintf( __( 'You should <a href="%s">add</a> a table to get started!', 'tablepress' ), $add_url );
619 - } elseif ( $user_can_import_tables ) {
620 - echo ' ' . sprintf( __( 'You should <a href="%s">import</a> a table to get started!', 'tablepress' ), $import_url );
621 - }
622 - }
623 - }
624 -
625 - /**
626 - * Generate the elements above or below the table (like bulk actions and pagination).
627 - *
628 - * In comparison with parent class, this has modified HTML (no nonce field), and a check whether there are items.
629 - *
630 - * @since 1.0.0
631 - *
632 - * @param string $which Location ("top" or "bottom").
633 - */
634 - protected function display_tablenav( $which ) {
635 - if ( ! $this->has_items() ) {
636 - return;
637 - }
638 - ?>
639 - <div class="tablenav <?php echo esc_attr( $which ); ?>">
640 - <div class="alignleft actions">
641 - <?php $this->bulk_actions( $which ); ?>
642 - </div>
643 - <?php
644 - $this->extra_tablenav( $which );
645 - $this->pagination( $which );
646 - ?>
647 - <br class="clear" />
648 - </div>
649 - <?php
650 - }
651 -
652 - /**
653 - * Callback to determine whether the given $item contains the search term.
654 - *
655 - * @since 1.0.0
656 - *
657 - * @param string $item Table ID that shall be searched.
658 - * @return bool Whether the search term was found or not.
659 - */
660 - protected function _search_callback( $item ) {
661 - static $term, $json_encoded_term;
662 - if ( is_null( $term ) || is_null( $json_encoded_term ) ) {
663 - $term = wp_unslash( $_GET['s'] );
664 - $json_encoded_term = substr( wp_json_encode( $term, TABLEPRESS_JSON_OPTIONS ), 1, -1 );
665 - }
666 -
667 - static $debug;
668 - if ( is_null( $debug ) ) {
669 - // Set debug variable to allow searching in corrupted tables.
670 - $debug = isset( $_GET['debug'] ) ? ( 'true' === $_GET['debug'] ) : WP_DEBUG;
671 - }
672 -
673 - // load table again, with data and options (for last_editor).
674 - $item = TablePress::$model_table->load( $item, true, true );
675 -
676 - // Don't search corrupted tables, except when debug mode is enabled via $_GET parameter or WP_DEBUG constant.
677 - if ( ! $debug && isset( $item['is_corrupted'] ) && $item['is_corrupted'] ) {
678 - return false;
679 - }
680 -
681 - // Search from easy to hard, so that "expensive" code maybe doesn't have to run.
682 - if ( false !== stripos( $item['id'], $term )
683 - || false !== stripos( $item['name'], $term )
684 - || false !== stripos( $item['description'], $term )
685 - || false !== stripos( TablePress::get_user_display_name( $item['author'] ), $term )
686 - || false !== stripos( TablePress::get_user_display_name( $item['options']['last_editor'] ), $term )
687 - || false !== stripos( TablePress::format_datetime( $item['last_modified'], 'mysql', ' ' ), $term )
688 - || false !== stripos( wp_json_encode( $item['data'], TABLEPRESS_JSON_OPTIONS ), $json_encoded_term ) ) {
689 - return true;
690 - }
691 -
692 - return false;
693 - }
694 -
695 - /**
696 - * Callback to for the array sort function.
697 - *
698 - * @since 1.0.0
699 - *
700 - * @param array $item_a First item that shall be compared to.
701 - * @param array $item_b The second item for the comparison.
702 - * @return int (-1, 0, 1) depending on which item sorts "higher".
703 - */
704 - protected function _order_callback( array $item_a, array $item_b ) {
705 - global $orderby, $order;
706 -
707 - if ( 'last_modified_by' !== $orderby ) {
708 - if ( $item_a[ $orderby ] === $item_b[ $orderby ] ) {
709 - return 0;
710 - }
711 - } else {
712 - if ( $item_a['options']['last_editor'] === $item_b['options']['last_editor'] ) {
713 - return 0;
714 - }
715 - }
716 -
717 - // Certain fields require some extra work before being sortable.
718 - switch ( $orderby ) {
719 - case 'last_modified':
720 - // Compare UNIX timestamps for "last modified", which actually is a mySQL datetime string.
721 - $result = ( strtotime( $item_a['last_modified'] ) > strtotime( $item_b['last_modified'] ) ) ? 1 : -1;
722 - break;
723 - case 'author':
724 - // Get the actual author name, plain value is just the user ID.
725 - $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['author'] ), TablePress::get_user_display_name( $item_b['author'] ) );
726 - break;
727 - case 'last_modified_by':
728 - // Get the actual last editor name, plain value is just the user ID.
729 - $result = strnatcasecmp( TablePress::get_user_display_name( $item_a['options']['last_editor'] ), TablePress::get_user_display_name( $item_b['options']['last_editor'] ) );
730 - break;
731 - default:
732 - // Other fields (ID, name, description) are sorted as strings.
733 - $result = strnatcasecmp( $item_a[ $orderby ], $item_b[ $orderby ] );
734 - }
735 -
736 - return ( 'asc' === $order ) ? $result : - $result;
737 - }
738 -
739 - /**
740 - * Prepares the list of items for displaying, by maybe searching and sorting, and by doing pagination.
741 - *
742 - * @since 1.0.0
743 - */
744 - public function prepare_items() {
745 - global $orderby, $order, $s;
746 - wp_reset_vars( array( 'orderby', 'order', 's' ) );
747 -
748 - // Maybe search in the items.
749 - if ( $s ) {
750 - $this->items = array_filter( $this->items, array( $this, '_search_callback' ) );
751 - }
752 -
753 - // Load actual tables after search for less memory consumption.
754 - foreach ( $this->items as &$item ) {
755 - // Don't load data, but load table options for access to last_editor.
756 - $item = TablePress::$model_table->load( $item, false, true );
757 - }
758 - // Break reference in foreach iterator.
759 - unset( $item );
760 -
761 - // Maybe sort the items.
762 - $_sortable_columns = $this->get_sortable_columns();
763 - if ( $orderby && ! empty( $this->items ) && isset( $_sortable_columns[ "table_{$orderby}" ] ) ) {
764 - usort( $this->items, array( $this, '_order_callback' ) );
765 - }
766 -
767 - // Number of records to show per page.
768 - $per_page = $this->get_items_per_page( 'tablepress_list_per_page', 20 ); // hard-coded, as in filter in Admin_Controller
769 - // Page number the user is currently viewing.
770 - $current_page = $this->get_pagenum();
771 - // Number of records in the array.
772 - $total_items = count( $this->items );
773 -
774 - // Slice items array to hold only items for the current page.
775 - $this->items = array_slice( $this->items, ( ( $current_page - 1 ) * $per_page ), $per_page );
776 -
777 - // Register pagination options and calculation results.
778 - $this->set_pagination_args( array(
779 - 'total_items' => $total_items, // Total number of records/items
780 - 'per_page' => $per_page, // Number of items per page
781 - 'total_pages' => ceil( $total_items / $per_page ), // Total number of pages
782 - ) );
783 - }
784 -
785 -} // class TablePress_All_Tables_List_Table