| @@ -104,19 +104,15 @@ | ||
| 104 | 104 | case 'top': |
| 105 | 105 | $position = 3; // Position of Dashboard + 1. |
| 106 | 106 | break; |
| 107 | 107 | case 'bottom': |
| 108 | - $position = isset( $GLOBALS['_wp_last_utility_menu'] ) ? ++$GLOBALS['_wp_last_utility_menu'] : 80; | |
| 108 | + $position = ( ++$GLOBALS['_wp_last_utility_menu'] ); | |
| 109 | 109 | break; |
| 110 | 110 | case 'middle': |
| 111 | 111 | default: |
| 112 | - $position = isset( $GLOBALS['_wp_last_object_menu'] ) ? ++$GLOBALS['_wp_last_object_menu'] : 25; | |
| 112 | + $position = ( ++$GLOBALS['_wp_last_object_menu'] ); | |
| 113 | 113 | break; |
| 114 | 114 | } |
| 115 | - // Prevent overwriting existing menu entries. | |
| 116 | - while ( isset( $GLOBALS['menu'][ $position ] ) ) { | |
| 117 | - ++$position; | |
| 118 | - } | |
| 119 | 115 | add_menu_page( 'TablePress', $admin_menu_entry_name, $min_access_cap, 'tablepress', $callback, $icon_url, $position ); // @phpstan-ignore-line |
| 120 | 116 | foreach ( $this->view_actions as $action => $entry ) { |
| 121 | 117 | if ( ! $entry['show_entry'] ) { |
| 122 | 118 | continue; |
| @@ -224,18 +220,12 @@ | ||
| 224 | 220 | $table_ids = TablePress::$model_table->load_all( false ); |
| 225 | 221 | foreach ( $table_ids as $table_id ) { |
| 226 | 222 | // Load table, without table data, options, and visibility settings. |
| 227 | 223 | $table = TablePress::$model_table->load( $table_id, false, false ); |
| 228 | - | |
| 229 | - // Skip tables that could not be loaded. | |
| 230 | - if ( is_wp_error( $table ) ) { | |
| 231 | - continue; | |
| 224 | + if ( '' === trim( $table['name'] ) ) { // @phpstan-ignore-line | |
| 225 | + $table['name'] = __( '(no name)', 'tablepress' ); // @phpstan-ignore-line | |
| 232 | 226 | } |
| 233 | - | |
| 234 | - if ( '' === trim( $table['name'] ) ) { | |
| 235 | - $table['name'] = __( '(no name)', 'tablepress' ); | |
| 236 | - } | |
| 237 | - $tables[ $table_id ] = esc_html( $table['name'] ); | |
| 227 | + $tables[ $table_id ] = esc_html( $table['name'] ); // @phpstan-ignore-line | |
| 238 | 228 | } |
| 239 | 229 | |
| 240 | 230 | /** |
| 241 | 231 | * Filters the list of table IDs and names that is passed to the block editor, and is then used in the dropdown of the TablePress table block. |
| @@ -245,26 +235,26 @@ | ||
| 245 | 235 | * @param array<string, string> $tables List of table names, the table ID is the array key. |
| 246 | 236 | */ |
| 247 | 237 | $tables = apply_filters( 'tablepress_block_editor_tables_list', $tables ); |
| 248 | 238 | |
| 249 | - $tables = wp_json_encode( $tables, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); | |
| 239 | + $tables = wp_json_encode( $tables, TABLEPRESS_JSON_OPTIONS ); | |
| 250 | 240 | if ( false === $tables ) { |
| 251 | 241 | // JSON encoding failed, return an error object. Use a prefixed "_error" key to avoid conflicts with intentionally added "error" keys. |
| 252 | 242 | $tables = '{ "_error": "The data could not be encoded to JSON!" }'; |
| 253 | 243 | } |
| 254 | - // Print the JSON data inside a `JSON.parse()` call in JS for speed gains, with necessary escaping of `\` and `'`. | |
| 255 | - $tables = str_replace( array( '\\', "'" ), array( '\\\\', "\'" ), $tables ); | |
| 244 | + // Print them inside a `JSON.parse()` call in JS for speed gains, with necessary escaping of `</script>`, `'`, and `\`. | |
| 245 | + $tables = str_replace( array( '</script>', '\\', "'" ), array( '<\/script>', '\\\\', "\'" ), $tables ); | |
| 256 | 246 | |
| 257 | 247 | $shortcode = esc_js( TablePress::$shortcode ); |
| 258 | 248 | |
| 259 | 249 | $template = TablePress::$model_table->get_table_template(); |
| 260 | - $template = wp_json_encode( $template['options'], JSON_HEX_TAG | JSON_UNESCAPED_SLASHES ); | |
| 250 | + $template = wp_json_encode( $template['options'], TABLEPRESS_JSON_OPTIONS ); | |
| 261 | 251 | if ( false === $template ) { |
| 262 | 252 | // JSON encoding failed, return an error object. Use a prefixed "_error" key to avoid conflicts with intentionally added "error" keys. |
| 263 | 253 | $template = '{ "_error": "The data could not be encoded to JSON!" }'; |
| 264 | 254 | } |
| 265 | - // Print the JSON data inside a `JSON.parse()` call in JS for speed gains, with necessary escaping of `\` and `'`. | |
| 266 | - $template = str_replace( array( '\\', "'" ), array( '\\\\', "\'" ), $template ); | |
| 255 | + // Print them inside a `JSON.parse()` call in JS for speed gains, with necessary escaping of `</script>`, `'`, and `\`. | |
| 256 | + $template = str_replace( array( '</script>', '\\', "'" ), array( '<\/script>', '\\\\', "\'" ), $template ); | |
| 267 | 257 | |
| 268 | 258 | /** |
| 269 | 259 | * Filters whether the table block preview should be loaded via a <ServerSideRender> in the block editor. |
| 270 | 260 | * |
| @@ -400,9 +390,9 @@ | ||
| 400 | 390 | * @return string[] Extended list of links to print in the "Plugin" column on the Plugins page. |
| 401 | 391 | */ |
| 402 | 392 | public function add_plugin_action_links( array $links ): array { |
| 403 | 393 | if ( current_user_can( 'tablepress_list_tables' ) ) { |
| 404 | - $links[] = '<a href="' . esc_url( TablePress::url() ) . '">' . __( 'Plugin page', 'tablepress' ) . '</a>'; | |
| 394 | + $links[] = '<a href="' . TablePress::url() . '">' . __( 'Plugin page', 'tablepress' ) . '</a>'; | |
| 405 | 395 | } |
| 406 | 396 | return $links; |
| 407 | 397 | } |
| 408 | 398 | |
| @@ -419,9 +409,9 @@ | ||
| 419 | 409 | if ( TABLEPRESS_BASENAME === $file ) { |
| 420 | 410 | $links[] = '<a href="https://tablepress.org/faq/" title="' . esc_attr__( 'Frequently Asked Questions', 'tablepress' ) . '">' . __( 'FAQ', 'tablepress' ) . '</a>'; |
| 421 | 411 | $links[] = '<a href="https://tablepress.org/documentation/">' . __( 'Documentation', 'tablepress' ) . '</a>'; |
| 422 | 412 | $links[] = '<a href="https://tablepress.org/support/">' . __( 'Support', 'tablepress' ) . '</a>'; |
| 423 | - if ( ! TABLEPRESS_IS_PLAYGROUND_PREVIEW && tb_tp_fs()->is_free_plan() ) { | |
| 413 | + if ( tb_tp_fs()->is_free_plan() ) { | |
| 424 | 414 | $links[] = '<a href="https://tablepress.org/premium/?utm_source=plugin&utm_medium=textlink&utm_content=plugins-screen" title="' . esc_attr__( 'Check out the Premium version of TablePress!', 'tablepress' ) . '"><strong>' . __( 'Go Premium', 'tablepress' ) . '</strong></a>'; |
| 425 | 415 | } |
| 426 | 416 | } |
| 427 | 417 | return $links; |
| @@ -443,9 +433,9 @@ | ||
| 443 | 433 | } |
| 444 | 434 | } |
| 445 | 435 | |
| 446 | 436 | // Check if action is a supported action, and whether the user is allowed to access this screen. |
| 447 | - if ( ! isset( $this->view_actions[ $action ] ) || ! current_user_can( $this->view_actions[ $action ]['required_cap'] ) ) { // @phpstan-ignore-line (The array value for the capability is always a string.) | |
| 437 | + if ( ! isset( $this->view_actions[ $action ] ) || ! current_user_can( $this->view_actions[ $action ]['required_cap'] ) ) { // @phpstan-ignore-line | |
| 448 | 438 | wp_die( __( 'Sorry, you are not allowed to access this page.', 'default' ), 403 ); |
| 449 | 439 | } |
| 450 | 440 | |
| 451 | 441 | // Don't load TablePress assets on the Freemius opt-in/activation screen. |
| @@ -477,16 +467,17 @@ | ||
| 477 | 467 | case 'list': |
| 478 | 468 | $data['table_id'] = ( ! empty( $_GET['table_id'] ) ) ? $_GET['table_id'] : false; |
| 479 | 469 | // Prime the post meta cache for cached loading of last_editor. |
| 480 | 470 | $data['table_ids'] = TablePress::$model_table->load_all( true ); |
| 481 | - $data['messages']['donation_nag'] = $this->maybe_show_donation_message(); | |
| 482 | - $data['messages']['first_visit'] = ! $data['messages']['donation_nag'] && TablePress::$model_options->get( 'message_first_visit' ); | |
| 483 | - $data['messages']['plugin_update'] = TablePress::$model_options->get( 'message_plugin_update' ); | |
| 484 | - $data['messages']['superseded_extensions'] = TablePress::$model_options->get( 'message_superseded_extensions' ); | |
| 471 | + $data['messages']['donation_message'] = $this->maybe_show_donation_message(); | |
| 472 | + $data['messages']['first_visit'] = ! $data['messages']['donation_message'] && TablePress::$model_options->get( 'message_first_visit' ); | |
| 473 | + $data['messages']['plugin_update_message'] = TablePress::$model_options->get( 'message_plugin_update' ); | |
| 485 | 474 | $data['table_count'] = count( $data['table_ids'] ); |
| 486 | 475 | break; |
| 487 | 476 | case 'about': |
| 488 | 477 | $data['first_activation'] = TablePress::$model_options->get( 'first_activation' ); |
| 478 | + $exporter = TablePress::load_class( 'TablePress_Export', 'class-export.php', 'classes' ); | |
| 479 | + $data['zip_support_available'] = $exporter->zip_support_available; | |
| 489 | 480 | break; |
| 490 | 481 | case 'options': |
| 491 | 482 | /* |
| 492 | 483 | * Maybe try saving "Custom CSS" to a file: |
| @@ -541,15 +532,9 @@ | ||
| 541 | 532 | continue; |
| 542 | 533 | } |
| 543 | 534 | // Load table, without table data, options, and visibility settings. |
| 544 | 535 | $table = TablePress::$model_table->load( $table_id, false, false ); |
| 545 | - | |
| 546 | - // Skip tables that could not be loaded. | |
| 547 | - if ( is_wp_error( $table ) ) { | |
| 548 | - continue; | |
| 549 | - } | |
| 550 | - | |
| 551 | - $data['tables'][ $table['id'] ] = $table['name']; | |
| 536 | + $data['tables'][ $table['id'] ] = $table['name']; // @phpstan-ignore-line | |
| 552 | 537 | } |
| 553 | 538 | $data['tables_count'] = TablePress::$model_table->count_tables(); |
| 554 | 539 | $data['export_ids'] = ( ! empty( $_GET['table_id'] ) ) ? explode( ',', $_GET['table_id'] ) : array(); |
| 555 | 540 | $exporter = TablePress::load_class( 'TablePress_Export', 'class-export.php', 'classes' ); |
| @@ -568,19 +553,14 @@ | ||
| 568 | 553 | continue; |
| 569 | 554 | } |
| 570 | 555 | // Load table, without table data, options, and visibility settings. |
| 571 | 556 | $table = TablePress::$model_table->load( $table_id, false, false ); |
| 572 | - | |
| 573 | - // Skip tables that could not be loaded. | |
| 574 | - if ( is_wp_error( $table ) ) { | |
| 575 | - continue; | |
| 576 | - } | |
| 577 | - | |
| 578 | - $data['tables'][ $table['id'] ] = $table['name']; | |
| 557 | + $data['tables'][ $table['id'] ] = $table['name']; // @phpstan-ignore-line | |
| 579 | 558 | } |
| 580 | - $data['table_ids'] = $table_ids; // Backward compatibility for the retired "Table Auto Update" Extension, which still relies on this variable name. | |
| 559 | + $data['table_ids'] = $table_ids; // Backwards compatibility for the retired "Table Auto Update" Extension, which still relies on this variable name. | |
| 581 | 560 | $data['tables_count'] = TablePress::$model_table->count_tables(); |
| 582 | 561 | $importer = TablePress::load_class( 'TablePress_Import', 'class-import.php', 'classes' ); |
| 562 | + $data['zip_support_available'] = $importer->zip_support_available; | |
| 583 | 563 | $data['import_type'] = ( ! empty( $_GET['import_type'] ) ) ? $_GET['import_type'] : 'add'; |
| 584 | 564 | $data['import_existing_table'] = ( ! empty( $_GET['import_existing_table'] ) ) ? $_GET['import_existing_table'] : ''; |
| 585 | 565 | $data['import_source'] = ( ! empty( $_GET['import_source'] ) ) ? $_GET['import_source'] : 'file-upload'; |
| 586 | 566 | $data['import_url'] = ( ! empty( $_GET['import_url'] ) ) ? wp_unslash( $_GET['import_url'] ) : 'https://'; |
| @@ -769,9 +749,9 @@ | ||
| 769 | 749 | } |
| 770 | 750 | break; |
| 771 | 751 | } |
| 772 | 752 | |
| 773 | - if ( 0 !== count( $no_success ) ) { // @todo maybe pass this information to the view? | |
| 753 | + if ( 0 !== count( $no_success ) ) { // @TODO: maybe pass this information to the view? | |
| 774 | 754 | $message = "error_{$bulk_action}_not_all_tables"; |
| 775 | 755 | } else { |
| 776 | 756 | $plural = ( count( $tables ) > 1 ) ? '_plural' : ''; |
| 777 | 757 | $message = "success_{$bulk_action}{$plural}"; |
| @@ -809,9 +789,9 @@ | ||
| 809 | 789 | } |
| 810 | 790 | |
| 811 | 791 | $add_table = wp_unslash( $_POST['table'] ); |
| 812 | 792 | |
| 813 | - // Perform confidence checks of posted data. | |
| 793 | + // Perform sanity checks of posted data. | |
| 814 | 794 | $name = ( isset( $add_table['name'] ) ) ? $add_table['name'] : ''; |
| 815 | 795 | $description = ( isset( $add_table['description'] ) ) ? $add_table['description'] : ''; |
| 816 | 796 | if ( ! isset( $add_table['rows'], $add_table['columns'] ) ) { |
| 817 | 797 | TablePress::redirect( array( 'action' => 'add', 'message' => 'error_add', 'error_details' => 'The HTTP POST data does not contain the table size.' ) ); |
| @@ -1114,15 +1094,8 @@ | ||
| 1114 | 1094 | TablePress::redirect( array( 'action' => 'import', 'message' => 'error_import', 'error_details' => 'You do not have the required access rights.' ) ); |
| 1115 | 1095 | } |
| 1116 | 1096 | } |
| 1117 | 1097 | |
| 1118 | - // For security reasons, the "url" source is only available admins and editors via a custom capability. | |
| 1119 | - if ( 'url' === $import_config['source'] ) { | |
| 1120 | - if ( ! current_user_can( 'tablepress_import_tables_url' ) ) { | |
| 1121 | - TablePress::redirect( array( 'action' => 'import', 'message' => 'error_import', 'error_details' => 'You do not have the required access rights.' ) ); | |
| 1122 | - } | |
| 1123 | - } | |
| 1124 | - | |
| 1125 | 1098 | // Move file upload data to the main import configuration. |
| 1126 | 1099 | $import_config['file-upload'] = $_FILES['import_file_upload'] ?? null; |
| 1127 | 1100 | |
| 1128 | 1101 | // Check if the source data for the chosen import source is defined. |
| @@ -1159,9 +1132,9 @@ | ||
| 1159 | 1132 | $redirect_parameters['error_details'] = TablePress::get_wp_error_string( $import ); |
| 1160 | 1133 | } elseif ( 0 < count( $import['errors'] ) ) { |
| 1161 | 1134 | $wp_error_strings = array(); |
| 1162 | 1135 | foreach ( $import['errors'] as $file ) { |
| 1163 | - $wp_error_strings[] = TablePress::get_wp_error_string( $file->error ); | |
| 1136 | + $wp_error_strings[] = TablePress::get_wp_error_string( $file['error'] ); | |
| 1164 | 1137 | } |
| 1165 | 1138 | $redirect_parameters['error_details'] = implode( ', ', $wp_error_strings ); |
| 1166 | 1139 | } |
| 1167 | 1140 | TablePress::redirect( $redirect_parameters ); |
| @@ -1321,14 +1294,13 @@ | ||
| 1321 | 1294 | $render_options = shortcode_atts( $default_render_options, $table['options'] ); |
| 1322 | 1295 | /** This filter is documented in controllers/controller-frontend.php */ |
| 1323 | 1296 | $render_options = apply_filters( 'tablepress_shortcode_table_shortcode_atts', $render_options ); |
| 1324 | 1297 | $render_options['html_id'] = "tablepress-{$table['id']}"; |
| 1325 | - $render_options['block_preview'] = true; | |
| 1326 | 1298 | $_render->set_input( $table, $render_options ); |
| 1327 | 1299 | $view_data = array( |
| 1328 | 1300 | 'table_id' => $table_id, |
| 1329 | 1301 | 'head_html' => $_render->get_preview_css(), |
| 1330 | - 'body_html' => $_render->get_output( 'html' ), | |
| 1302 | + 'body_html' => $_render->get_output(), | |
| 1331 | 1303 | 'site_uses_block_editor' => TablePress::site_uses_block_editor(), |
| 1332 | 1304 | ); |
| 1333 | 1305 | |
| 1334 | 1306 | $custom_css = TablePress::$model_options->get( 'custom_css' ); |
| @@ -1392,9 +1364,9 @@ | ||
| 1392 | 1364 | |
| 1393 | 1365 | TablePress::$model_table->destroy(); |
| 1394 | 1366 | TablePress::$model_options->destroy(); |
| 1395 | 1367 | |
| 1396 | - $output = '<strong>' . __( 'TablePress was uninstalled successfully.', 'tablepress' ) . '</strong><br><br>'; | |
| 1368 | + $output = '<strong>' . __( 'TablePress was uninstalled successfully.', 'tablepress' ) . '</strong><br /><br />'; | |
| 1397 | 1369 | $output .= __( 'All tables, data, and options were deleted.', 'tablepress' ); |
| 1398 | 1370 | if ( is_multisite() ) { |
| 1399 | 1371 | $output .= ' ' . __( 'You may now ask the network admin to delete the plugin’s folder <code>tablepress</code> from the server, if no other site in the network uses it.', 'tablepress' ); |
| 1400 | 1372 | } else { |