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 | classes/class-view.php +215 -78 2.4.2 → 3.4 View file →
@@ -7,8 +7,10 @@
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 /**
@@ -26,41 +28,31 @@
26 28 *
27 29 * @since 1.0.0
28 30 * @var array<string, mixed>
29 31 */
30 - protected $data = array();
32 + protected array $data = array();
31 33
32 34 /**
33 35 * Number of screen columns for post boxes.
34 36 *
35 37 * @since 1.0.0
36 - * @var int
37 38 */
38 - protected $screen_columns = 0;
39 + protected int $screen_columns = 0;
39 40
40 41 /**
41 42 * User action for this screen.
42 43 *
43 44 * @since 1.0.0
44 - * @var string
45 45 */
46 - protected $action = '';
46 + protected string $action = '';
47 47
48 48 /**
49 - * Instance of the Admin Page Helper Class, with necessary functions.
50 - *
51 - * @since 1.0.0
52 - * @var TablePress_Admin_Page
53 - */
54 - protected $admin_page;
55 -
56 - /**
57 49 * List of text boxes (similar to post boxes, but just with text and without extra functionality).
58 50 *
59 51 * @since 1.0.0
60 52 * @var array<string, array<string, array<string, mixed>>>
61 53 */
62 - protected $textboxes = array();
54 + protected array $textboxes = array();
63 55
64 56 /**
65 57 * List of messages that are to be displayed as boxes below the page title.
66 58 *
@@ -66,9 +58,9 @@
66 58 *
67 59 * @since 1.0.0
68 60 * @var string[]
69 61 */
70 - protected $header_messages = array();
62 + protected array $header_messages = array();
71 63
72 64 /**
73 65 * Whether there are post boxes registered for this screen,
74 66 * is automatically set to true, when a meta box is added.
@@ -73,11 +65,10 @@
73 65 * Whether there are post boxes registered for this screen,
74 66 * is automatically set to true, when a meta box is added.
75 67 *
76 68 * @since 1.0.0
77 - * @var bool
78 69 */
79 - protected $has_meta_boxes = false;
70 + protected bool $has_meta_boxes = false;
80 71
81 72 /**
82 73 * List of WP feature pointers for this view.
83 74 *
@@ -83,12 +74,12 @@
83 74 *
84 75 * @since 1.0.0
85 76 * @var string[]
86 77 */
87 - protected $wp_pointers = array();
78 + protected array $wp_pointers = array();
88 79
89 80 /**
90 - * Initialize the View class, by setting the correct screen columns and adding help texts.
81 + * Initializes the View class, by setting the correct screen columns and adding help texts.
91 82 *
92 83 * @since 1.0.0
93 84 */
94 85 public function __construct() {
@@ -93,19 +84,23 @@
93 84 */
94 85 public function __construct() {
95 86 $screen = get_current_screen();
96 87 if ( 0 !== $this->screen_columns ) {
97 - $screen->add_option( 'layout_columns', array( 'max' => $this->screen_columns ) );
88 + $screen->add_option( 'layout_columns', array( 'max' => $this->screen_columns ) ); // @phpstan-ignore method.nonObject
98 89 }
99 90 // Enable two column layout.
100 - add_filter( "get_user_option_screen_layout_{$screen->id}", array( $this, 'set_current_screen_layout_columns' ) );
91 + add_filter( "get_user_option_screen_layout_{$screen->id}", array( $this, 'set_current_screen_layout_columns' ) ); // @phpstan-ignore property.nonObject
101 92
93 + /* translators: %1$s: URL to TablePress website, %2$s: URL to WordPress Plugin Directory */
102 94 $common_content = '<p>' . sprintf( __( 'More information about TablePress can be found on the <a href="%1$s">plugin website</a> or on its page in the <a href="%2$s">WordPress Plugin Directory</a>.', 'tablepress' ), 'https://tablepress.org/', 'https://wordpress.org/plugins/tablepress/' ) . '</p>';
103 - $common_content .= '<p>' . sprintf( __( 'For technical information, please see the <a href="%s">Documentation</a>.', 'tablepress' ), 'https://tablepress.org/documentation/' ) . ' ' . sprintf( __( 'Common questions are answered in the <a href="%s">FAQ</a>.', 'tablepress' ), 'https://tablepress.org/faq/' ) . '</p>';
95 + /* translators: %s: URL to Documentation page */
96 + $common_content .= '<p>' . sprintf( __( 'For technical information, please see the <a href="%s">Documentation</a>.', 'tablepress' ), 'https://tablepress.org/documentation/' ) . ' ';
97 + /* translators: %s: URL to FAQ page */
98 + $common_content .= sprintf( __( 'Common questions are answered in the <a href="%s">FAQ</a>.', 'tablepress' ), 'https://tablepress.org/faq/' ) . '</p>';
104 99
105 100 if ( tb_tp_fs()->is_free_plan() ) {
106 101 $common_content .= '<p>'
107 - . sprintf( __( '<a href="%1$s">Support</a> is provided through the <a href="%2$s">WordPress Support Forums</a>.', 'tablepress' ), 'https://tablepress.org/support/', 'https://wordpress.org/tags/tablepress' )
102 + . sprintf( __( '<a href="%1$s">Support</a> is provided through the <a href="%2$s">WordPress Support Forums</a>.', 'tablepress' ), 'https://tablepress.org/support/', 'https://wordpress.org/support/plugin/tablepress/' )
108 103 . ' '
109 104 . sprintf( __( 'Before asking for support, please carefully read the <a href="%s">Frequently Asked Questions</a>, where you will find answers to the most common questions, and search through the forums.', 'tablepress' ), 'https://tablepress.org/faq/' )
110 105 . '</p>';
111 106 $common_content .= '<p><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=help-tab' ) . '</strong></p>';
@@ -110,15 +105,15 @@
110 105 . '</p>';
111 106 $common_content .= '<p><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=help-tab' ) . '</strong></p>';
112 107 }
113 108
114 - $screen->add_help_tab( array(
109 + $screen->add_help_tab( array( // @phpstan-ignore method.nonObject
115 110 'id' => 'tablepress-help', // This should be unique for the screen.
116 111 'title' => __( 'TablePress Help', 'tablepress' ),
117 112 'content' => '<p>' . $this->help_tab_content() . '</p>' . $common_content,
118 113 ) );
119 114 // "Sidebar" in the help tab.
120 - $screen->set_help_sidebar(
115 + $screen->set_help_sidebar( // @phpstan-ignore method.nonObject
121 116 '<p><strong>' . __( 'For more information:', 'tablepress' ) . '</strong></p>'
122 117 . '<p><a href="https://tablepress.org/">TablePress Website</a></p>'
123 118 . '<p><a href="https://tablepress.org/faq/">TablePress FAQ</a></p>'
124 119 . '<p><a href="https://tablepress.org/documentation/">TablePress Documentation</a></p>'
@@ -126,28 +121,32 @@
126 121 );
127 122 }
128 123
129 124 /**
130 - * Change the value of the user option "screen_layout_{$screen->id}" through a filter.
125 + * Changes the value of the user option "screen_layout_{$screen->id}" through a filter.
131 126 *
132 127 * @since 1.0.0
133 128 *
134 - * @param int|false $result Current value of the user option.
129 + * @param string|int|false $result Current value of the user option.
135 130 * @return int New value for the user option.
136 131 */
137 - public function set_current_screen_layout_columns( /* int|false */ $result ): int {
132 + public function set_current_screen_layout_columns( /* string|int|false */ $result ): int {
138 133 if ( false === $result ) {
139 134 // The user option does not yet exist.
140 - $result = $this->screen_columns;
141 - } elseif ( $result > $this->screen_columns ) {
135 + return $this->screen_columns;
136 + }
137 +
138 + $result = (int) $result;
139 + if ( $result > $this->screen_columns ) {
142 140 // The value of the user option is bigger than what is possible on this screen (e.g. because the number of columns was reduced in an update).
143 141 $result = $this->screen_columns;
144 142 }
143 +
145 144 return $result;
146 145 }
147 146
148 147 /**
149 - * Set up the view with data and do things that are necessary for all views.
148 + * Sets up the view with data and do things that are necessary for all views.
150 149 *
151 150 * @since 1.0.0
152 151 *
153 152 * @param string $action Action for this view.
@@ -161,19 +160,16 @@
161 160
162 161 // Set page title.
163 162 $GLOBALS['title'] = sprintf( __( '%1$s &lsaquo; %2$s', 'tablepress' ), $this->data['view_actions'][ $this->action ]['page_title'], 'TablePress' ); // phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
164 163
165 - // Admin page helpers, like script/style loading, could be moved to view.
166 - $this->admin_page = TablePress::load_class( 'TablePress_Admin_Page', 'class-admin-page-helper.php', 'classes' );
167 - $this->admin_page->enqueue_style( 'common' );
164 + add_filter( 'admin_footer_text', array( $this, 'add_admin_footer_text' ) );
165 +
166 + TablePress::enqueue_style( 'common', array( 'wp-components' ) );
168 167 // RTL styles for the admin interface.
169 168 if ( is_rtl() ) {
170 - $this->admin_page->enqueue_style( 'common-rtl', array( 'tablepress-common' ) );
169 + TablePress::enqueue_style( 'common-rtl', array( 'tablepress-common' ) );
171 170 }
172 - $this->admin_page->enqueue_script( 'common', array( 'jquery-core', 'postbox' ) );
173 171
174 - $this->admin_page->add_admin_footer_text();
175 -
176 172 // Initialize WP feature pointers for TablePress.
177 173 $this->_init_wp_pointers();
178 174
179 175 // Necessary fields for all views.
@@ -182,9 +178,9 @@
182 178 $this->add_text_box( 'action_field', array( $this, 'action_field' ), 'header', false );
183 179 }
184 180
185 181 /**
186 - * Register a header message for the view.
182 + * Registers a header message for the view.
187 183 *
188 184 * @since 1.0.0
189 185 *
190 186 * @param string $text Text for the header message.
@@ -190,9 +186,9 @@
190 186 * @param string $text Text for the header message.
191 187 * @param string $css_class Optional. Additional CSS class for the header message.
192 188 * @param string $title Optional. Text for the header title.
193 189 */
194 - protected function add_header_message( string $text, string $css_class = 'notice-success', string $title = '' ): void {
190 + protected function add_header_message( string $text, string $css_class = 'is-success notice-success', string $title = '' ): void {
195 191 if ( ! str_contains( $css_class, 'not-dismissible' ) ) {
196 192 $css_class .= ' is-dismissible';
197 193 }
198 194 if ( '' !== $title ) {
@@ -201,13 +197,13 @@
201 197 // Wrap the message text in HTML <p> tags if it does not already start with one (potentially with attributes), indicating custom message HTML.
202 198 if ( '' !== $text && ! str_starts_with( $text, '<p' ) ) {
203 199 $text = "<p>{$text}</p>";
204 200 }
205 - $this->header_messages[] = "<div class=\"notice {$css_class}\">{$title}{$text}</div>\n";
201 + $this->header_messages[] = "<div class=\"notice components-notice {$css_class}\"><div class=\"components-notice__content\">{$title}{$text}</div></div>\n";
206 202 }
207 203
208 204 /**
209 - * Process header action messages, i.e. check if a message should be added to the page.
205 + * Processes header action messages, i.e. check if a message should be added to the page.
210 206 *
211 207 * @since 1.0.0
212 208 *
213 209 * @param array<string, string> $action_messages Action messages for the screen.
@@ -213,9 +209,9 @@
213 209 * @param array<string, string> $action_messages Action messages for the screen.
214 210 */
215 211 protected function process_action_messages( array $action_messages ): void {
216 212 if ( $this->data['message'] && isset( $action_messages[ $this->data['message'] ] ) ) {
217 - $class = ( str_starts_with( $this->data['message'], 'error' ) ) ? 'notice-error' : 'notice-success';
213 + $class = ( str_starts_with( $this->data['message'], 'error' ) ) ? 'is-error notice-error' : 'is-success notice-success';
218 214
219 215 if ( '' !== $this->data['error_details'] ) {
220 216 $this->data['error_details'] = '</p><p>' . sprintf( __( 'Error code: %s', 'tablepress' ), '<code>' . esc_html( $this->data['error_details'] ) . '</code>' );
221 217 }
@@ -224,9 +220,9 @@
224 220 }
225 221 }
226 222
227 223 /**
228 - * Register a text box for the view.
224 + * Registers a text box for the view.
229 225 *
230 226 * @since 1.0.0
231 227 *
232 228 * @param string $id Unique HTML ID for the text box container (only visible with $wrap = true).
@@ -248,9 +244,9 @@
248 244 );
249 245 }
250 246
251 247 /**
252 - * Register a post meta box for the view, that is drag/droppable with WordPress functionality.
248 + * Registers a post meta box for the view, that is drag/droppable with WordPress functionality.
253 249 *
254 250 * @since 1.0.0
255 251 *
256 252 * @param string $id Unique ID for the meta box.
@@ -265,9 +261,9 @@
265 261 add_meta_box( "tablepress_{$this->action}-{$id}", $title, $callback, null, $context, $priority, $callback_args );
266 262 }
267 263
268 264 /**
269 - * Render all text boxes for the given context.
265 + * Renders all text boxes for the given context.
270 266 *
271 267 * @since 1.0.0
272 268 *
273 269 * @param string $context Context (normal, side, additional, header, submit) for which registered text boxes shall be rendered.
@@ -288,9 +284,9 @@
288 284 }
289 285 }
290 286
291 287 /**
292 - * Render all post meta boxes for the given context, if there are post meta boxes.
288 + * Renders all post meta boxes for the given context, if there are post meta boxes.
293 289 *
294 290 * @since 1.0.0
295 291 *
296 292 * @param string $context Context (normal, side, additional) for which registered post meta boxes shall be rendered.
@@ -296,14 +292,14 @@
296 292 * @param string $context Context (normal, side, additional) for which registered post meta boxes shall be rendered.
297 293 */
298 294 protected function do_meta_boxes( string $context ): void {
299 295 if ( $this->has_meta_boxes ) {
300 - do_meta_boxes( get_current_screen(), $context, $this->data ); // @phpstan-ignore-line
296 + do_meta_boxes( get_current_screen(), $context, $this->data ); // @phpstan-ignore argument.type
301 297 }
302 298 }
303 299
304 300 /**
305 - * Print hidden fields with nonces for post meta box AJAX handling, if there are post meta boxes on the screen.
301 + * Prints hidden fields with nonces for post meta box AJAX handling, if there are post meta boxes on the screen.
306 302 *
307 303 * The check is possible as this function is executed after post meta boxes have to be registered.
308 304 *
309 305 * @since 1.0.0
@@ -321,9 +317,9 @@
321 317 echo "\n";
322 318 }
323 319
324 320 /**
325 - * Print hidden field with a nonce for the screen's action, to be transmitted in HTTP requests.
321 + * Prints hidden field with a nonce for the screen's action, to be transmitted in HTTP requests.
326 322 *
327 323 * @since 1.0.0
328 324 *
329 325 * @param array<string, mixed> $data Data for this screen.
@@ -334,9 +330,9 @@
334 330 echo "\n";
335 331 }
336 332
337 333 /**
338 - * Print hidden field with the screen action.
334 + * Prints hidden field with the screen action.
339 335 *
340 336 * @since 1.0.0
341 337 *
342 338 * @param array<string, mixed> $data Data for this screen.
@@ -346,9 +342,9 @@
346 342 echo "<input type=\"hidden\" name=\"action\" value=\"tablepress_{$this->action}\">\n";
347 343 }
348 344
349 345 /**
350 - * Render the current view.
346 + * Renders the current view.
351 347 *
352 348 * @since 1.0.0
353 349 */
354 350 public function render(): void {
@@ -358,8 +354,9 @@
358 354 $this->print_nav_tab_menu();
359 355 ?>
360 356 <div id="tablepress-body">
361 357 <hr class="wp-header-end">
358 + <script>document.querySelectorAll('.notice:has(~#tablepress-page)').forEach(e=>document.querySelector('.wp-header-end').after(e));</script>
362 359 <?php
363 360 // Print all header messages.
364 361 foreach ( $this->header_messages as $message ) {
365 362 echo $message;
@@ -402,23 +399,39 @@
402 399 <?php
403 400 }
404 401
405 402 /**
406 - * Render the navigation menu with links to the possible actions, highlighting the current one.
403 + * Renders the navigation menu with links to the possible actions, highlighting the current one.
407 404 *
408 405 * @since 1.0.0
409 406 */
410 407 protected function print_nav_tab_menu(): void {
408 + $milestone_period_ended = ( strtotime( '2026-10-10' ) < strtotime( 'today' ) );
409 + $name = __( 'TablePress', 'tablepress' );
410 + $filename = 'admin/img/tablepress.svg';
411 411 ?>
412 412 <div id="tablepress-header" class="header">
413 - <h1 class="name"><img src="<?php echo plugins_url( 'admin/img/tablepress-icon.png', TABLEPRESS__FILE__ ); ?>" class="tablepress-icon" alt="<?php esc_attr_e( 'TablePress plugin logo', 'tablepress' ); ?>"><?php _e( 'TablePress', 'tablepress' ); ?></h1>
414 - <?php if ( ! TABLEPRESS_IS_PLAYGROUND_PREVIEW && tb_tp_fs()->is_free_plan() ) : ?>
415 - <div class="buttons">
416 - <a href="https://tablepress.org/premium/?utm_source=plugin&utm_medium=button&utm_content=upgrade-button" class="tablepress-button">
417 - <span><?php _e( 'Upgrade to Premium', 'tablepress' ); ?></span>
418 - <span class="dashicons dashicons-arrow-right-alt"></span>
419 - </a>
420 - </div>
413 + <h1 class="name">
414 + <img src="<?php echo plugins_url( $filename, TABLEPRESS__FILE__ ); ?>" alt="<?php esc_attr_e( 'TablePress plugin logo', 'tablepress' ); ?>">
415 + <span class="screen-reader-text"><?php echo $name; ?></span>
416 + </h1>
417 + <?php if ( 'list' !== $this->action || ! $this->data['messages']['plugin_update'] || $milestone_period_ended ) : ?>
418 + <?php if ( ! TABLEPRESS_IS_PLAYGROUND_PREVIEW && tb_tp_fs()->is_free_plan() ) : ?>
419 + <div class="buttons">
420 + <a href="<?php echo $milestone_period_ended ? esc_url( tb_tp_fs()->pricing_url( WP_FS__PERIOD_ANNUALLY, false ) ) : 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=header&utm_campaign=upgrade-message340&utm_content=button'; ?>" class="tablepress-button">
421 + <span>
422 + <?php
423 + if ( $milestone_period_ended ) {
424 + _e( 'Upgrade to Premium', 'tablepress' );
425 + } else {
426 + echo in_array( get_user_locale(), array( 'de_DE', 'de_AT', 'de_CH' ), true ) ? 'Premium: Spare jetzt 25&#8239;%' : 'Premium: Get 25% off now';
427 + }
428 + ?>
429 + </span>
430 + <span class="dashicons dashicons-arrow-right-alt"></span>
431 + </a>
432 + </div>
433 + <?php endif; ?>
421 434 <?php endif; ?>
422 435 </div>
423 436 <nav id="tablepress-nav">
424 437 <ul class="nav-menu">
@@ -451,26 +464,30 @@
451 464 * @param array<string, mixed> $box Information about the text box.
452 465 */
453 466 public function textbox_no_javascript( array $data, array $box ): void {
454 467 ?>
455 - <div class="notice notice-error notice-alt notice-large hide-if-js">
456 - <h3><em>
457 - <?php _e( 'Attention: Unfortunately, there is a problem!', 'tablepress' ); ?>
458 - </em></h3>
459 - <p style="font-size:14px">
460 - <strong><?php _e( 'This screen requires JavaScript. Please enable JavaScript in your browser settings.', 'tablepress' ); ?></strong><br>
461 - <?php _e( 'For help, please follow <a href="https://www.enable-javascript.com/">the instructions on how to enable JavaScript in your browser</a>.', 'tablepress' ); ?>
462 - </p>
463 - <p>
464 - <?php echo '<a href="' . esc_url( TablePress::url( array( 'action' => 'list' ) ) ) . '">' . __( 'Back to the List of Tables', 'tablepress' ) . '</a>'; ?>
465 - </p>
468 + <div class="notice components-notice is-error notice-error hide-if-js">
469 + <div class="components-notice__content">
470 + <h3><em>
471 + <?php _e( 'Attention: Unfortunately, there is a problem!', 'tablepress' ); ?>
472 + </em></h3>
473 + <p style="font-size:14px">
474 + <strong><?php _e( 'This screen requires JavaScript. Please enable JavaScript in your browser settings.', 'tablepress' ); ?></strong><br>
475 + <?php _e( 'For help, please follow <a href="https://www.enable-javascript.com/">the instructions on how to enable JavaScript in your browser</a>.', 'tablepress' ); ?>
476 + </p>
477 + <p>
478 + <?php echo '<a href="' . esc_url( TablePress::url( array( 'action' => 'list' ) ) ) . '">' . __( 'Back to the List of Tables', 'tablepress' ) . '</a>'; ?>
479 + </p>
480 + </div>
466 481 </div>
467 482 <?php
468 483 }
469 484
470 485 /**
471 - * Print a submit button (only done when function is used as a callback for a text box).
486 + * Prints a submit button (only done when function is used as a callback for a text box).
472 487 *
488 + * This method is soft-deprecated. It's no longer used in TablePress, but e.g. in the "TablePress Debug Extension".
489 + *
473 490 * @since 1.0.0
474 491 *
475 492 * @param array<string, mixed> $data Data for this screen.
476 493 * @param array<string, mixed> $box Information about the text box.
@@ -475,17 +492,55 @@
475 492 * @param array<string, mixed> $data Data for this screen.
476 493 * @param array<string, mixed> $box Information about the text box.
477 494 */
478 495 protected function textbox_submit_button( array $data, array $box ): void {
479 - $caption = $data['submit_button_caption'] ?? __( 'Save Changes', 'tablepress' );
480 496 ?>
481 - <p class="submit"><input type="submit" value="<?php echo esc_attr( $caption ); ?>" class="button button-primary button-large"></p>
497 + <p class="submit"><input type="submit" class="components-button is-primary button-save-changes" value="<?php esc_attr_e( 'Save Changes', 'tablepress' ); ?>"></p>
482 498 <?php
483 499 }
484 500
485 501 /**
486 - * Return the content for the help tab for this screen.
502 + * Returns a safe JSON representation of a variable for printing inside of JavaScript code.
487 503 *
504 + * @since 2.0.0
505 + *
506 + * @param mixed $data Variable to convert to JSON.
507 + * @return string Safe JSON representation of a variable for printing inside of JavaScript code.
508 + */
509 + public function convert_to_json_parse_output( /* string|array|bool|int|float|null */ $data ): string {
510 + $json = wp_json_encode( $data, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES );
511 + if ( false === $json ) {
512 + // JSON encoding failed, return an error object. Use a prefixed "_error" key to avoid conflicts with intentionally added "error" keys.
513 + $json = '{ "_error": "The data could not be encoded to JSON!" }';
514 + }
515 + // Print the JSON data inside a `JSON.parse()` call in JS for speed gains, with necessary escaping of `\` and `'`.
516 + $json = str_replace( array( '\\', "'" ), array( '\\\\', "\'" ), $json );
517 + return "JSON.parse( '{$json}' )";
518 + }
519 +
520 + /**
521 + * Prints JavaScript variables for the screen.
522 + *
523 + * @since 3.1.0
524 + *
525 + * @param string $variable Name of the JavaScript variable.
526 + * @param array<string, mixed> $data Information about the text box.
527 + */
528 + protected function print_script_data_json( string $variable, array $data ): void {
529 + echo "<script>\n";
530 + echo "window.tp = window.tp || {};\n";
531 + echo "tp.{$variable} = {\n";
532 + foreach ( $data as $key => $value ) {
533 + $value = $this->convert_to_json_parse_output( $value );
534 + echo "\t{$key}: {$value},\n";
535 + }
536 + echo "};\n";
537 + echo "</script>\n";
538 + }
539 +
540 + /**
541 + * Returns the content for the help tab for this screen.
542 + *
488 543 * Has to be implemented for every view that is visible in the WP Dashboard!
489 544 *
490 545 * @since 1.0.0
491 546 *
@@ -496,12 +551,38 @@
496 551 return '';
497 552 }
498 553
499 554 /**
500 - * Initialize the WP feature pointers for TablePress.
555 + * Adds a TablePress "Thank You" message to the admin footer content.
501 556 *
502 557 * @since 1.0.0
558 + * @since 3.3.0 This method was moved from the now-removed `TablePress_Admin_Page` class.
559 + *
560 + * @param string $content Current admin footer content.
561 + * @return string New admin footer content.
503 562 */
563 + public function add_admin_footer_text( /* string */ $content ): string {
564 + // Don't use a type hint in the method declaration as many WordPress plugins use the `admin_footer_text` filter without returning a string.
565 +
566 + // Protect against other plugins not returning a string in their filter callbacks.
567 + if ( ! is_string( $content ) ) { // @phpstan-ignore function.alreadyNarrowedType (The `is_string()` check is needed as the input is coming from a filter hook.)
568 + $content = '';
569 + }
570 +
571 + /* translators: %s: URL to TablePress website */
572 + $content .= ' &bull; ' . sprintf( __( 'Thank you for using <a href="%s">TablePress</a>.', 'tablepress' ), 'https://tablepress.org/' );
573 + if ( tb_tp_fs()->is_free_plan() ) {
574 + /* translators: %s: URL to TablePress premium features */
575 + $content .= ' ' . sprintf( __( 'Take a look at the <a href="%s">Premium features</a>!', 'tablepress' ), 'https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=admin-footer' );
576 + }
577 + return $content;
578 + }
579 +
580 + /**
581 + * Initializes the WP feature pointers for TablePress.
582 + *
583 + * @since 1.0.0
584 + */
504 585 protected function _init_wp_pointers(): void {
505 586 // Check if there are WP pointers for this view.
506 587 if ( empty( $this->wp_pointers ) ) {
507 588 return;
@@ -512,9 +593,9 @@
512 593
513 594 $pointers_on_page = false;
514 595 foreach ( array_diff( $this->wp_pointers, $dismissed ) as $pointer ) {
515 596 // Bind pointer print function.
516 - add_action( "admin_footer-{$GLOBALS['hook_suffix']}", array( $this, 'wp_pointer_' . $pointer ) ); // @phpstan-ignore-line
597 + add_action( "admin_footer-{$GLOBALS['hook_suffix']}", array( $this, 'wp_pointer_' . $pointer ) ); // @phpstan-ignore argument.type
517 598 $pointers_on_page = true;
518 599 }
519 600
520 601 if ( $pointers_on_page ) {
@@ -520,7 +601,63 @@
520 601 if ( $pointers_on_page ) {
521 602 wp_enqueue_style( 'wp-pointer' );
522 603 wp_enqueue_script( 'wp-pointer' );
523 604 }
605 + }
606 +
607 + /**
608 + * Prints the JavaScript code for a WP feature pointer.
609 + *
610 + * @since 1.0.0
611 + * @since 3.3.0 This method was moved from the now-removed `TablePress_Admin_Page` class.
612 + *
613 + * @param string $pointer_id The pointer ID.
614 + * @param string $selector The HTML elements, on which the pointer should be attached.
615 + * @param array<string, mixed> $args Arguments to be passed to the pointer JS (see wp-pointer.js).
616 + */
617 + public function print_wp_pointer_js( string $pointer_id, string $selector, array $args ): void {
618 + if ( empty( $pointer_id ) || empty( $selector ) || empty( $args['content'] ) ) {
619 + return;
620 + }
621 +
622 + $keyboard_shortcut = '';
623 + if ( 'tp33_edit_quick_navigation' === $pointer_id ) {
624 + $keyboard_shortcut = <<<JS
625 + content: options.content.replace( /%metaKey%/g, window?.navigator?.platform?.includes( 'Mac' ) ? wp.i18n._x( '⌘', 'keyboard shortcut modifier key on a Mac keyboard', 'tablepress' ) : wp.i18n._x( 'Ctrl+', 'keyboard shortcut modifier key on a non-Mac keyboard', 'tablepress' ) ),\n
626 + JS;
627 + }
628 +
629 + /*
630 + * Print JS code for the feature pointers, extended with event handling for opened/closed "Screen Options", so that pointers can
631 + * be repositioned. 210 ms is slightly slower than jQuery's "fast" value, to allow all elements to reach their original position.
632 + */
633 + ?>
634 +<script>
635 +( ( $ ) => {
636 + let options = <?php echo wp_json_encode( $args, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); ?>;
637 + if ( ! options ) {
638 + return;
639 + }
640 +
641 + options = {
642 + ...options,
643 + <?php echo $keyboard_shortcut; ?>
644 + close() {
645 + $.post( ajaxurl, {
646 + pointer: '<?php echo $pointer_id; ?>',
647 + action: 'dismiss-wp-pointer'
648 + } );
649 + $( this ).pointer( { 'disabled': true } );
650 + },
651 + };
652 +
653 + $( () => setTimeout( () => $( '<?php echo $selector; ?>' ).pointer( options ).pointer( 'open' ), 1 ) );
654 +
655 + $( document ).on( 'screen:options:open screen:options:close', () => {
656 + setTimeout( () => $( '<?php echo $selector; ?>' ).pointer( 'reposition' ), 210 );
657 + } );
658 +} )( jQuery );
659 +</script>
660 + <?php
524 661 }
525 662
526 663 } // class TablePress_View