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
tablepress / views / view-edit.php

view-edit.php in TablePress – Tables in WordPress made easy 3.4, at views/view-edit.php

498 lines 20.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Edit Table View
4 *
5 * @package TablePress
6 * @subpackage Views
7 * @author Tobias Bäthge
8 * @since 1.0.0
9 */
10
11 declare(strict_types=1);
12
13 // Prohibit direct script loading.
14 defined( 'ABSPATH' ) || die( 'No direct script access allowed!' );
15
16 /**
17 * Edit Table View class
18 *
19 * @package TablePress
20 * @subpackage Views
21 * @author Tobias Bäthge
22 * @since 1.0.0
23 */
24 class TablePress_Edit_View extends TablePress_View {
25
26 /**
27 * List of WP feature pointers for this view.
28 *
29 * @since 2.0.0
30 * @var string[]
31 */
32 protected array $wp_pointers = array( 'tp34_edit_toolbar', 'tp33_edit_quick_navigation' );
33
34 /**
35 * Sets up the view with data and do things that are specific for this view.
36 *
37 * @since 1.0.0
38 *
39 * @param string $action Action for this view.
40 * @param array<string, mixed> $data Data for this view.
41 */
42 #[\Override]
43 public function setup( /* string */ $action, array $data ) /* : void */ {
44 // Don't use type hints in the method declaration to prevent PHP errors, as the method is inherited.
45
46 parent::setup( $action, $data );
47
48 TablePress::enqueue_script( 'common', array( 'jquery-core', 'postbox' ) );
49
50 $this->add_text_box( 'no-javascript', array( $this, 'textbox_no_javascript' ), 'header' );
51
52 if ( isset( $data['table']['is_corrupted'] ) && $data['table']['is_corrupted'] ) {
53 $this->add_text_box( 'table-corrupted', array( $this, 'textbox_corrupted_table' ), 'header' );
54 return;
55 }
56
57 $this->process_action_messages( array(
58 'success_add' => __( 'The table was added successfully.', 'tablepress' ),
59 'success_copy' => _n( 'The table was copied successfully.', 'The tables were copied successfully.', 1, 'tablepress' ) . ' ' . sprintf( __( 'You are now seeing the copied table, which has the table ID &#8220;%s&#8221;.', 'tablepress' ), esc_html( $data['table']['id'] ) ),
60 'success_import' => __( 'The table was imported successfully.', 'tablepress' ),
61 'error_delete' => __( 'Error: The table could not be deleted.', 'tablepress' ),
62 ) );
63
64 // For the Advanced Editor.
65 wp_enqueue_style( 'wp-jquery-ui-dialog' );
66 wp_enqueue_style( 'editor-buttons' );
67 wp_enqueue_script( 'wpdialogs' );
68 // For the "Insert Image" dialog.
69 add_filter( 'media_view_strings', array( $this, 'change_media_view_strings' ) );
70 wp_enqueue_media();
71 // For the "Insert Link" dialog.
72 wp_enqueue_script( 'wplink' );
73
74 TablePress::enqueue_style( 'jspreadsheet' );
75 TablePress::enqueue_style( 'jsuites', array( 'tablepress-jspreadsheet' ) );
76 TablePress::enqueue_style( 'edit', array( 'tablepress-jspreadsheet', 'tablepress-jsuites' ) );
77 if ( ! TABLEPRESS_IS_PLAYGROUND_PREVIEW && tb_tp_fs()->is_free_plan() ) {
78 TablePress::enqueue_style( 'edit-features', array( 'tablepress-edit' ) );
79 }
80 TablePress::enqueue_script( 'jspreadsheet' );
81 TablePress::enqueue_script( 'jsuites', array( 'tablepress-jspreadsheet' ) );
82 TablePress::enqueue_script( 'edit', array( 'tablepress-jspreadsheet', 'tablepress-jsuites', 'jquery-core' ) );
83
84 $this->add_text_box( 'head', array( $this, 'textbox_head' ), 'normal' );
85 $this->add_text_box( 'header-bar', array( $this, 'textbox_header_bar' ), 'normal' );
86 $this->add_meta_box( 'table-information', __( 'Table Information', 'tablepress' ), array( $this, 'postbox_table_information' ), 'normal' );
87 $this->add_meta_box( 'table-data', __( 'Table Content', 'tablepress' ), array( $this, 'postbox_table_data' ), 'normal' );
88 $this->add_meta_box( 'table-options', __( 'Table Options', 'tablepress' ), array( $this, 'postbox_table_options' ), 'normal' );
89 $this->add_meta_box( 'datatables-features', __( 'Table Features for Site Visitors', 'tablepress' ), array( $this, 'postbox_datatables_features' ), 'normal' );
90 $this->add_text_box( 'hidden-containers', array( $this, 'textbox_hidden_containers' ), 'additional' );
91
92 add_filter( 'screen_settings', array( $this, 'add_screen_options_output' ), 10, 2 );
93 }
94
95 /**
96 * Changes the Media View string "Insert into post" to "Insert into Table".
97 *
98 * @since 1.0.0
99 *
100 * @param array<string, string> $strings Current set of Media View strings.
101 * @return array<string, string> Changed Media View strings.
102 */
103 public function change_media_view_strings( array $strings ): array {
104 $strings['insertIntoPost'] = __( 'Insert into Table', 'tablepress' );
105 return $strings;
106 }
107
108 /**
109 * Adds custom screen options to the screen.
110 *
111 * @since 2.1.0
112 *
113 * @param string $screen_settings Screen settings.
114 * @param WP_Screen $screen WP_Screen object.
115 * @return string Extended Screen settings.
116 */
117 public function add_screen_options_output( /* string */ $screen_settings, WP_Screen $screen ): string {
118 // Don't use a type hint for the `$screen_settings` argument as many WordPress plugins seem to be returning `null` in their filter hook handlers.
119
120 // Protect against other plugins not returning a string for the `$screen_settings` argument.
121 if ( ! is_string( $screen_settings ) ) { // @phpstan-ignore function.alreadyNarrowedType (The `is_string()` check is needed as the input is coming from a filter hook.)
122 $screen_settings = '';
123 }
124
125 $screen_settings = '<fieldset id="tablepress-screen-options" class="screen-options">';
126 $screen_settings .= '<legend>' . __( 'Table editor settings', 'tablepress' ) . '</legend>';
127 $screen_settings .= '<p>' . __( 'Adjust the default size of the table cells in the table editor below.', 'tablepress' ) . ' ' . __( 'Cells with many lines of text will expand to their full height when they are edited.', 'tablepress' ) . '</p>';
128 $screen_settings .= '<p><em>' . __( 'Please note: These settings only influence the table editor view on this screen, but not the table that the site visitor sees!', 'tablepress' ) . '</em></p>';
129 $screen_settings .= '<div>';
130 $screen_settings .= '<label for="table_editor_column_width">' . __( 'Default column width:', 'tablepress' ) . '</label> ';
131 $input = '<input type="number" id="table_editor_column_width" class="small-text" value="' . esc_attr( TablePress::$model_options->get( 'table_editor_column_width' ) ) . '" min="30" max="9999">';
132 /* translators: %s: Input field for the number of pixels */
133 $screen_settings .= sprintf( __( '%s pixels', 'tablepress' ), $input );
134 $screen_settings .= '</div>';
135 $screen_settings .= '<div style="margin-top: 6px;">';
136 $screen_settings .= '<label for="table_editor_line_clamp">' . __( 'Maximum visible lines of text:', 'tablepress' ) . '</label> ';
137 $input = '<input type="number" id="table_editor_line_clamp" class="tiny-text" value="' . esc_attr( TablePress::$model_options->get( 'table_editor_line_clamp' ) ) . '" min="0" max="999">';
138 /* translators: %s: Input field for the number of lines */
139 $screen_settings .= sprintf( __( '%s lines', 'tablepress' ), $input );
140 $screen_settings .= '</div>';
141 $screen_settings .= '</fieldset>';
142 return $screen_settings;
143 }
144
145 /**
146 * Renders the current view.
147 *
148 * In comparison to the parent class method, this contains handling for the no-js case and adjusts the HTML code structure.
149 *
150 * @since 2.0.0
151 */
152 #[\Override]
153 public function render(): void {
154 $this->print_javascript_data();
155
156 ?>
157 <div id="tablepress-page" class="wrap">
158 <form>
159 <?php
160 $this->print_nav_tab_menu();
161 ?>
162 <div id="tablepress-body">
163 <hr class="wp-header-end">
164 <script>document.querySelectorAll('.notice:has(~#tablepress-page)').forEach(e=>document.querySelector('.wp-header-end').after(e));</script>
165 <?php
166 // Print all header messages.
167 foreach ( $this->header_messages as $message ) {
168 echo $message;
169 }
170
171 $this->do_text_boxes( 'header' );
172 ?>
173 <div id="poststuff" class="hide-if-no-js">
174 <div id="post-body" class="metabox-holder columns-1">
175 <div id="postbox-container-2" class="postbox-container">
176 <?php
177 $this->do_text_boxes( 'normal' );
178 $this->do_meta_boxes( 'normal' );
179
180 $this->do_text_boxes( 'additional' );
181 $this->do_meta_boxes( 'additional' );
182
183 $this->do_text_boxes( 'submit' );
184
185 $this->do_text_boxes( 'side' );
186 $this->do_meta_boxes( 'side' );
187 ?>
188 </div>
189 </div>
190 <br class="clear">
191 </div>
192 </form>
193 </div>
194 </div>
195 <?php
196 }
197
198 /**
199 * Overrides parent class method, as the nonces for this view are generated in the JS code.
200 *
201 * @since 1.0.0
202 *
203 * @param array<string, mixed> $data Data for this screen.
204 * @param array<string, mixed> $box Information about the text box.
205 */
206 #[\Override]
207 protected function action_nonce_field( array $data, array $box ): void {
208 // Intentionally left empty. Nonces for this view are generated in `print_javascript_data()`.
209 }
210
211 /**
212 * Prints the table data for use in JS code and the main React container.
213 *
214 * @since 3.0.0
215 */
216 public function print_javascript_data(): void {
217 echo "<script>\n";
218 echo "window.tp = window.tp || {};\n";
219
220 echo "tp.nonces = {\n";
221 echo "\tedit_table: '" . wp_create_nonce( TablePress::nonce( $this->action, $this->data['table']['id'] ) ) . "',\n";
222 echo "\tpreview_table: '" . wp_create_nonce( TablePress::nonce( 'preview_table', $this->data['table']['id'] ) ) . "',\n";
223 echo "\tcopy_table: '" . wp_create_nonce( TablePress::nonce( 'copy_table', $this->data['table']['id'] ) ) . "',\n";
224 echo "\tdelete_table: '" . wp_create_nonce( TablePress::nonce( 'delete_table', $this->data['table']['id'] ) ) . "',\n";
225 echo "\tscreen_options: '" . wp_create_nonce( TablePress::nonce( 'screen_options' ) ) . "',\n";
226 echo "};\n";
227
228 echo "tp.table = {\n";
229 echo "\tid: '{$this->data['table']['id']}',\n";
230 echo "\tshortcode: '" . esc_js( TablePress::$shortcode ) . "',\n";
231
232 // Add the table meta data.
233 $this->data['table']['meta'] = array(
234 'id' => $this->data['table']['id'],
235 'name' => $this->data['table']['name'],
236 'description' => $this->data['table']['description'],
237 'lastModified' => TablePress::format_datetime( $this->data['table']['last_modified'] ),
238 'lastEditor' => TablePress::get_user_display_name( $this->data['table']['options']['last_editor'] ),
239 );
240
241 // JSON-encode array items separately to save some PHP memory.
242 foreach ( array( 'meta', 'data', 'options', 'visibility' ) as $item ) {
243 $json = $this->convert_to_json_parse_output( $this->data['table'][ $item ] );
244 echo "\t{$item}: {$json},\n";
245 }
246 echo "};\n";
247
248 echo "tp.screenOptions = {\n";
249 echo "\ttable_editor_column_width: " . absint( TablePress::$model_options->get( 'table_editor_column_width' ) ) . ",\n";
250 echo "\tshowCustomCommands: " . ( current_user_can( 'unfiltered_html' ) ? 'true' : 'false' ) . ",\n";
251 echo "\toptionsUrl: '" . TablePress::url( array( 'action' => 'options' ) ) . "',\n";
252 echo "\tcurrentUserCanEditTableId: " . ( current_user_can( 'tablepress_edit_table_id', $this->data['table']['id'] ) ? 'true' : 'false' ) . ",\n";
253 echo "\tcurrentUserCanCopyTable: " . ( current_user_can( 'tablepress_copy_table', $this->data['table']['id'] ) ? 'true' : 'false' ) . ",\n";
254 echo "\tcurrentUserCanDeleteTable: " . ( current_user_can( 'tablepress_delete_table', $this->data['table']['id'] ) ? 'true' : 'false' ) . ",\n";
255 echo "\tcurrentUserCanExportTable: " . ( current_user_can( 'tablepress_export_table', $this->data['table']['id'] ) ? 'true' : 'false' ) . ",\n";
256 echo "\tcurrentUserCanPreviewTable: " . ( current_user_can( 'tablepress_preview_table', $this->data['table']['id'] ) ? 'true' : 'false' ) . ",\n";
257 echo "\tcopyUrl: '" . str_replace( '&amp;', '&', TablePress::url( array( 'action' => 'copy_table', 'item' => $this->data['table']['id'], 'return' => 'edit' ), true, 'admin-post.php' ) ) . "',\n";
258 echo "\tdeleteUrl: '" . str_replace( '&amp;', '&', TablePress::url( array( 'action' => 'delete_table', 'item' => $this->data['table']['id'], 'return' => 'edit', 'return_item' => $this->data['table']['id'] ), true, 'admin-post.php' ) ) . "',\n";
259 echo "\texportUrl: '" . str_replace( '&amp;', '&', TablePress::url( array( 'action' => 'export', 'table_id' => $this->data['table']['id'] ) ) ) . "',\n";
260 echo "\tpreviewUrl: '" . str_replace( '&amp;', '&', TablePress::url( array( 'action' => 'preview_table', 'item' => $this->data['table']['id'], 'return' => 'edit', 'return_item' => $this->data['table']['id'] ), true, 'admin-post.php' ) ) . "',\n";
261 echo "};\n";
262
263 echo "</script>\n";
264
265 echo '<div id="tablepress-edit-screen"></div>'; // React container.
266 }
267
268 /**
269 * Prints the content of the "Table Information" post meta box.
270 *
271 * @since 1.0.0
272 *
273 * @param array<string, mixed> $data Data for this screen.
274 * @param array<string, mixed> $box Information about the meta box.
275 */
276 public function postbox_table_information( array $data, array $box ): void {
277 echo '<div id="tablepress-table-information-section"></div>';
278
279 if ( ! TABLEPRESS_IS_PLAYGROUND_PREVIEW && tb_tp_fs()->is_free_plan() ) :
280 ?>
281 <div class="postbox premium-features">
282 <div>
283 <div>
284 <div class="postbox-header">
285 <h2><span class="dashicons dashicons-lightbulb"></span> <?php _e( 'TablePress has more to offer!', 'tablepress' ); ?></h2>
286 </div>
287 <div class="inside">
288 <?php
289 TablePress::load_modules_data();
290 $random_module_slug = array_rand( TablePress::$modules );
291 $feature_module = TablePress::$modules[ $random_module_slug ];
292 $module_url = esc_url( "https://tablepress.org/modules/{$random_module_slug}/?utm_source=plugin&utm_medium=textlink&utm_content=edit-screen" );
293
294 echo '<strong>' . __( 'Supercharge your tables with exceptional features:', 'tablepress' ) . '</strong>';
295 echo '<h3><a href="' . $module_url . '">' . $feature_module['name'] . '</a></h3>';
296 echo '<span>' . $feature_module['description'] . ' <a href="' . $module_url . '">' . __( 'Read more!', 'tablepress' ) . '</a></span>';
297 ?>
298 </div>
299 </div>
300 <div class="buttons">
301 <a href="https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=edit-screen" class="tablepress-button">
302 <span><?php _e( 'Compare the TablePress premium versions', 'tablepress' ); ?></span>
303 <span class="dashicons dashicons-arrow-right-alt"></span>
304 </a>
305 </div>
306 </div>
307 </div>
308 <?php
309 endif;
310 }
311
312 /**
313 * Prints the content of the "Table Content" post meta box.
314 *
315 * @since 1.0.0
316 *
317 * @param array<string, mixed> $data Data for this screen.
318 * @param array<string, mixed> $box Information about the meta box.
319 */
320 public function postbox_table_data( array $data, array $box ): void {
321 echo '<div id="tablepress-table-editor-toolbar-section"></div>';
322 $css_variables = '--table-editor-line-clamp:' . absint( TablePress::$model_options->get( 'table_editor_line_clamp' ) ) . ';';
323 $css_variables = esc_attr( $css_variables );
324 echo "<div id=\"table-editor\" style=\"{$css_variables}\"></div>";
325 }
326
327 /**
328 * Prints the container for the sticky "Header Bar".
329 *
330 * @since 3.3.0
331 *
332 * @param array<string, mixed> $data Data for this screen.
333 * @param array<string, mixed> $box Information about the text box.
334 */
335 public function textbox_header_bar( array $data, array $box ): void {
336 echo '<div id="tablepress-header-bar-section" class="section-has-react-loading-text">';
337 echo '</div>';
338 }
339
340 /**
341 * Prints the hidden containers for the Preview.
342 *
343 * @since 1.0.0
344 *
345 * @param array<string, mixed> $data Data for this screen.
346 * @param array<string, mixed> $box Information about the text box.
347 */
348 public function textbox_hidden_containers( array $data, array $box ): void {
349 ?>
350 <div id="tablepress-table-preview-section"></div>
351 <div class="hidden-container">
352 <div id="advanced-editor">
353 <label id="advanced-editor-label" for="advanced-editor-content" class="screen-reader-text"><?php esc_html_e( 'Advanced Editor', 'tablepress' ); ?></label>
354 <?php
355 $wp_editor_options = array(
356 'textarea_rows' => 10,
357 'tinymce' => false,
358 'quicktags' => array(
359 'buttons' => 'strong,em,link,del,ins,img,code,spell,close',
360 ),
361 );
362 wp_editor( '', 'advanced-editor-content', $wp_editor_options );
363 ?>
364 </div>
365 <textarea id="textarea-insert-helper" class="hidden"></textarea>
366 </div>
367 <?php
368 }
369
370 /**
371 * Prints the content of the "Table Options" post meta box.
372 *
373 * @since 1.0.0
374 *
375 * @param array<string, mixed> $data Data for this screen.
376 * @param array<string, mixed> $box Information about the meta box.
377 */
378 public function postbox_table_options( array $data, array $box ): void {
379 echo '<div id="tablepress-table-options-section"></div>';
380 }
381
382 /**
383 * Prints the content of the "Table Features for Site Visitors" post meta box.
384 *
385 * @since 1.0.0
386 *
387 * @param array<string, mixed> $data Data for this screen.
388 * @param array<string, mixed> $box Information about the meta box.
389 */
390 public function postbox_datatables_features( array $data, array $box ): void {
391 echo '<div id="tablepress-datatables-features-section"></div>';
392 }
393
394 /**
395 * Prints a notification about a corrupted table.
396 *
397 * @since 1.4.0
398 *
399 * @param array<string, mixed> $data Data for this screen.
400 * @param array<string, mixed> $box Information about the text box.
401 */
402 public function textbox_corrupted_table( array $data, array $box ): void {
403 ?>
404 <div class="notice components-notice is-error notice-error">
405 <div class="components-notice__content">
406 <h3><em>
407 <?php _e( 'Attention: Unfortunately, an error occurred.', 'tablepress' ); ?>
408 </em></h3>
409 <p>
410 <?php
411 /* translators: %1$s: Table name, %2$s: Table ID */
412 printf( __( 'The internal data of table &#8220;%1$s&#8221; (ID %2$s) is corrupted.', 'tablepress' ), esc_html( $data['table']['name'] ), esc_html( $data['table']['id'] ) );
413 echo ' ';
414 /* translators: %s: Error message */
415 printf( __( 'The following error was registered: %s.', 'tablepress' ), '<code>' . esc_html( $data['table']['json_error'] ) . '</code>' );
416 ?>
417 </p>
418 <p>
419 <?php
420 _e( 'Because of this error, the table can not be edited at this time, to prevent possible further data loss.', 'tablepress' );
421 echo ' ';
422 /* translators: %s: URL to TablePress FAQ page */
423 printf( __( 'Please see the <a href="%s">TablePress FAQ page</a> for further instructions.', 'tablepress' ), 'https://tablepress.org/faq/corrupted-tables/' );
424 ?>
425 </p>
426 <p>
427 <?php echo '<a href="' . esc_url( TablePress::url( array( 'action' => 'list' ) ) ) . '" class="components-button is-secondary is-compact">' . __( 'Back to the List of Tables', 'tablepress' ) . '</a>'; ?>
428 </p>
429 </div>
430 </div>
431 <?php
432 }
433
434 /**
435 * Prints the screen head text.
436 *
437 * @since 1.0.0
438 *
439 * @param array<string, mixed> $data Data for this screen.
440 * @param array<string, mixed> $box Information about the text box.
441 */
442 public function textbox_head( array $data, array $box ): void {
443 echo '<p>';
444 _e( 'To edit the content or modify the structure of this table, use the input fields and buttons below.', 'tablepress' );
445 echo ' ';
446 // Show the instructions string depending on whether the Block Editor is used on the site or not.
447 if ( 'block' === $data['site_used_editor'] ) {
448 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' ) );
449 } elseif ( 'elementor' === $data['site_used_editor'] ) {
450 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' ) );
451 } else {
452 _e( 'To insert a table into a post or page, paste its Shortcode at the desired place in the editor.', 'tablepress' );
453 }
454 echo '</p>';
455 }
456
457 /**
458 * Sets the content for the WP feature pointer about the Table Editor Toolbar on the "Edit" screen.
459 *
460 * @since 3.4.0
461 */
462 public function wp_pointer_tp34_edit_toolbar(): void {
463 $content = '<h3>' . __( 'TablePress feature: Toolbar', 'tablepress' ) . '</h3>';
464 $content .= '<p style="text-wrap:balance">' . __( 'Adding links or images or modifying the structure of your tables is very easy with the sticky Table Editor Toolbar!', 'tablepress' ) . '</p>';
465
466 $this->print_wp_pointer_js(
467 'tp34_edit_toolbar',
468 '#tablepress-table-editor-toolbar-section > div > div > div:first-child',
469 array(
470 'content' => $content,
471 'position' => array( 'edge' => is_rtl() ? 'right' : 'left', 'align' => 'center' ),
472 'pointerWidth' => 290,
473 ),
474 );
475 }
476
477 /**
478 * Sets the content for the WP feature pointer about the Quick Navigation on the "Edit" screen.
479 *
480 * @since 3.3.0
481 */
482 public function wp_pointer_tp33_edit_quick_navigation(): void {
483 $content = '<h3>' . __( 'TablePress feature: Quick Navigation', 'tablepress' ) . '</h3>';
484 $content .= '<p style="text-wrap:balance">' . __( 'You can quickly navigate between different sections of the table editor using the Quick Navigation menu.', 'tablepress' ) . ' ' . __( 'Just click the logo or use the <kbd>%metaKey%J</kbd> keyboard shortcut!', 'tablepress' ) . '</p>';
485
486 $this->print_wp_pointer_js(
487 'tp33_edit_quick_navigation',
488 '#tablepress-header-bar-section',
489 array(
490 'content' => $content,
491 'position' => array( 'edge' => 'top', 'align' => is_rtl() ? 'right+16' : 'left-16' ),
492 'pointerWidth' => 330,
493 ),
494 );
495 }
496
497 } // class TablePress_Edit_View
498