PluginProbe
TablePress – Tables in WordPress made easy / 3.0
TablePress – Tables in WordPress made easy v3.0
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 2.4.4 All 44 releases
← All changes | controllers/controller-frontend.php +65 -165 trunk3.0 View file →
@@ -21,15 +21,8 @@
21 21 */
22 22 class TablePress_Frontend_Controller extends TablePress_Controller {
23 23
24 24 /**
25 - * Whether to use the legacy CSS loading method of enqueuing all CSS files on all pages.
26 - *
27 - * @since 3.0.1
28 - */
29 - public bool $use_legacy_css_loading = false;
30 -
31 - /**
32 25 * File name of the admin screens' parent page in the admin menu.
33 26 *
34 27 * @since 1.0.0
35 28 */
@@ -58,9 +51,9 @@
58 51 */
59 52 protected array $datatables_datetime_formats = array();
60 53
61 54 /**
62 - * Initiates Frontend functionality.
55 + * Initiate Frontend functionality.
63 56 *
64 57 * @since 1.0.0
65 58 */
66 59 public function __construct() {
@@ -75,26 +68,8 @@
75 68 */
76 69 $this->parent_page = apply_filters( 'tablepress_admin_menu_parent_page', TablePress::$model_options->get( 'admin_menu_parent_page' ) );
77 70 $this->is_top_level_page = in_array( $this->parent_page, array( 'top', 'middle', 'bottom' ), true );
78 71
79 - /**
80 - * Filters whether TablePress should load its frontend CSS files on all pages.
81 - * For block themes, the default behavior is to only load the CSS files when a table is encountered on the page.
82 - * If Elementor is active, the CSS is also loaded on the editor page.
83 - *
84 - * @since 3.0.1
85 - *
86 - * @param bool $use_legacy_css_loading Whether TablePress should load its frontend CSS files on all pages.
87 - */
88 - $this->use_legacy_css_loading = apply_filters( 'tablepress_frontend_legacy_css_loading', ! wp_is_block_theme() || ( isset( $_GET['elementor-preview'] ) && is_plugin_active( 'elementor/elementor.php' ) ) );
89 -
90 - if ( $this->use_legacy_css_loading ) {
91 - add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_css' ) );
92 - }
93 -
94 - // Register a placeholder script handle so that plugins can properly declare it as a dependency, even before the actual script is enqueued in `enqueue_datatables_files()`.
95 - wp_register_script( 'tablepress-datatables', '', array(), TablePress::version, array( 'in_footer' => true ) );
96 -
97 72 add_action( 'wp_print_footer_scripts', array( $this, 'add_datatables_calls' ), 9 ); // Priority 9 so that this runs before `_wp_footer_scripts()`.
98 73
99 74 // Register TablePress Shortcodes. Priority 20 is kept for backwards-compatibility purposes.
100 75 add_action( 'init', array( $this, 'init_shortcodes' ), 20 );
@@ -118,12 +93,15 @@
118 93
119 94 /**
120 95 * Register the tablepress/table block and its dependencies.
121 96 */
122 - wp_register_block_metadata_collection(
123 - TABLEPRESS_ABSPATH . 'blocks',
124 - TABLEPRESS_ABSPATH . 'blocks/blocks-manifest.php',
125 - );
97 + if ( function_exists( 'wp_register_block_metadata_collection' ) ) {
98 + // wp_register_block_metadata_collection() is only available since WP 6.7.
99 + wp_register_block_metadata_collection(
100 + TABLEPRESS_ABSPATH . 'blocks',
101 + TABLEPRESS_ABSPATH . 'blocks/blocks-manifest.php',
102 + );
103 + }
126 104 register_block_type_from_metadata(
127 105 TABLEPRESS_ABSPATH . 'blocks/table/block.json',
128 106 array(
129 107 'render_callback' => array( $this, 'table_block_render_callback' ),
@@ -128,18 +106,12 @@
128 106 array(
129 107 'render_callback' => array( $this, 'table_block_render_callback' ),
130 108 ),
131 109 );
132 -
133 - /**
134 - * Register the TablePress Elementor widgets.
135 - */
136 - add_action( 'elementor/widgets/register', array( $this, 'register_elementor_widgets' ) );
137 - add_action( 'elementor/editor/after_enqueue_styles', array( $this, 'enqueue_elementor_editor_styles' ), 10, 0 );
138 110 }
139 111
140 112 /**
141 - * Registers TablePress Shortcodes.
113 + * Register TablePress Shortcodes.
142 114 *
143 115 * @since 1.0.0
144 116 */
145 117 public function init_shortcodes(): void {
@@ -147,20 +119,18 @@
147 119 add_shortcode( TablePress::$shortcode_info, array( $this, 'shortcode_table_info' ) );
148 120 }
149 121
150 122 /**
151 - * Checks if the CSS files for TablePress default CSS and "Custom CSS" should be loaded.
123 + * Enqueues CSS files for TablePress default CSS and "Custom CSS" (if desired).
152 124 *
153 125 * This function is only called when a [table /] Shortcode or "TablePress Table" block is evaluated, so that CSS files are only loaded when needed.
154 126 *
155 - * @since 3.0.0
127 + * If styles have not been printed to the page (in the `<head>`), the TablePress CSS files will be enqueued.
128 + * If styles have already been printed to the page, the TablePress CSS files will be printed right away (likely in the `<body`>).
129 + *
130 + * @since 1.0.0
156 131 */
157 - public function maybe_enqueue_css(): void {
158 - // Bail early if the legacy CSS loading mechanism is used, as the files will then have been enqueued already.
159 - if ( $this->use_legacy_css_loading && ! doing_action( 'enqueue_block_assets' ) ) {
160 - return;
161 - }
162 -
132 + public function enqueue_css(): void {
163 133 /*
164 134 * Bail early if the function is called from some action hook outside of the normal rendering process.
165 135 * These are often used by e.g. SEO plugins that render the content in additional contexts, e.g. to get an excerpt via an output buffer.
166 136 * In these cases, we don't want to enqueue the CSS, as it would likely not be printed on the page.
@@ -175,20 +145,8 @@
175 145 return;
176 146 }
177 147 $css_enqueued = true;
178 148
179 - $this->enqueue_css();
180 - }
181 -
182 - /**
183 - * Enqueues CSS files for TablePress default CSS and "Custom CSS" (if desired).
184 - *
185 - * If styles have not been printed to the page (in the `<head>`), the TablePress CSS files will be enqueued.
186 - * If styles have already been printed to the page, the TablePress CSS files will be printed right away (likely in the `<body`>).
187 - *
188 - * @since 1.0.0
189 - */
190 - public function enqueue_css(): void {
191 149 /**
192 150 * Filters whether the TablePress Default CSS code shall be loaded.
193 151 *
194 152 * @since 1.0.0
@@ -323,15 +281,13 @@
323 281 * @param string[] $dependencies The dependencies for the DataTables JS library.
324 282 */
325 283 $dependencies = apply_filters( 'tablepress_datatables_js_dependencies', $dependencies );
326 284
327 - // De-register the placeholder script handle and enqueue the actual script, so that the dependencies are correct.
328 - wp_deregister_script( 'tablepress-datatables' );
329 - wp_enqueue_script( 'tablepress-datatables', $js_url, $dependencies, TablePress::version, array( 'in_footer' => true ) );
285 + wp_enqueue_script( 'tablepress-datatables', $js_url, $dependencies, TablePress::version, true );
330 286 }
331 287
332 288 /**
333 - * Adds the JavaScript code for the invocation of the DataTables JS library.
289 + * Add JS code for invocation of DataTables JS library.
334 290 *
335 291 * @since 1.0.0
336 292 */
337 293 public function add_datatables_calls(): void {
@@ -340,13 +296,15 @@
340 296 if ( $datatables_calls_printed ) {
341 297 return;
342 298 }
343 299
344 - // Bail early if there are no TablePress tables on the page.
345 300 if ( empty( $this->shown_tables ) ) {
301 + // There are no tables with activated DataTables on the page that is currently rendered.
346 302 return;
347 303 }
348 304
305 + $this->enqueue_datatables_files();
306 +
349 307 /*
350 308 * Don't add the DataTables function calls in the scope of the block editor iframe.
351 309 * This is necessary for non-block themes, for others, the repeated execution check above is sufficient.
352 310 */
@@ -356,31 +314,20 @@
356 314 return;
357 315 }
358 316 }
359 317
360 - // Filter out all tables that use DataTables.
361 - $shown_tables_with_datatables = array();
362 - foreach ( $this->shown_tables as $table_id => $table_store ) {
363 - if ( ! empty( $table_store['instances'] ) ) {
364 - $shown_tables_with_datatables[ (string) $table_id ] = $table_store;
365 - }
366 - }
367 -
368 - // Bail early if there are no tables with activated DataTables on the page.
369 - if ( empty( $shown_tables_with_datatables ) ) {
370 - return;
371 - }
372 -
373 - $this->enqueue_datatables_files();
374 -
375 318 // Storage for the DataTables language strings.
376 319 $datatables_language = array();
377 320 // Generate the specific JS commands, depending on chosen features on the "Edit" screen and the Shortcode parameters.
378 321 $commands = array();
379 322
380 - foreach ( $shown_tables_with_datatables as $table_id => $table_store ) {
323 + foreach ( $this->shown_tables as $table_id => $table_store ) {
381 324 $table_id = (string) $table_id; // Ensure that the table ID is a string, as it comes from an array key where numeric strings are converted to integers.
382 325
326 + if ( empty( $table_store['instances'] ) ) {
327 + continue;
328 + }
329 +
383 330 foreach ( $table_store['instances'] as $html_id => $js_options ) {
384 331 $parameters = array();
385 332
386 333 // Settle dependencies/conflicts between certain features.
@@ -557,21 +504,22 @@
557 504 } // foreach table instance
558 505 } // foreach table ID
559 506
560 507 // DataTables language/translation handling.
561 - $datatables_language_command = wp_json_encode( $datatables_language, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT );
562 - $datatables_language_command = "var DT_language={$datatables_language_command};\n";
508 + if ( ! empty( $datatables_language ) ) {
509 + $datatables_language_command = wp_json_encode( $datatables_language, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_FORCE_OBJECT );
510 + $datatables_language_command = "var DT_language={$datatables_language_command};\n";
511 + } else {
512 + $datatables_language_command = '';
513 + }
563 514
564 515 // DataTables datetime format string handling.
565 516 if ( ! empty( $this->datatables_datetime_formats ) ) {
566 - // Create a command like `DataTable.datetime("MM/DD/YYYY");DataTable.datetime("DD.MM.YYYY");`.
517 + // Create a command like `DataTable.datetime('MM/DD/YYYY');DataTable.datetime('DD.MM.YYYY');`.
567 518 $datatables_datetime_command = implode(
568 519 '',
569 520 array_map(
570 - static function ( string $datetime_format ): string {
571 - $datetime_format = wp_json_encode( $datetime_format, JSON_HEX_TAG | JSON_UNESCAPED_SLASHES );
572 - return "DataTable.datetime({$datetime_format});";
573 - },
521 + static fn( string $datetime_format ): string => "DataTable.datetime('{$datetime_format}');",
574 522 $this->datatables_datetime_formats,
575 523 )
576 524 ) . "\n";
577 525 } else {
@@ -625,18 +573,20 @@
625 573 $datatables_calls_printed = true;
626 574 }
627 575
628 576 /**
629 - * Handles the Shortcode [table id=<ID> /].
577 + * Handle Shortcode [table id=<ID> /].
630 578 *
631 579 * @since 1.0.0
632 580 *
633 - * @param array<string, mixed> $shortcode_atts List of attributes that where included in the Shortcode.
581 + * @param array<string, mixed>|string $shortcode_atts List of attributes that where included in the Shortcode. An empty string for empty Shortcodes like [table] or [table /].
634 582 * @return string Resulting HTML code for the table with the ID <ID>.
635 583 */
636 - public function shortcode_table( array $shortcode_atts ): string {
637 - $this->maybe_enqueue_css();
584 + public function shortcode_table( /* array|string */ $shortcode_atts ): string {
585 + $shortcode_atts = (array) $shortcode_atts;
638 586
587 + $this->enqueue_css();
588 +
639 589 $_render = TablePress::load_class( 'TablePress_Render', 'class-render.php', 'classes' );
640 590
641 591 $default_shortcode_atts = $_render->get_default_render_options();
642 592 /**
@@ -704,26 +654,19 @@
704 654 $message = apply_filters( 'tablepress_table_corrupted_message', $message, $table_id, $table['json_error'] );
705 655 return $message;
706 656 }
707 657
708 - if ( ! is_null( $shortcode_atts['datatables_custom_commands'] ) ) {
709 - /**
710 - * Filters whether the "datatables_custom_commands" Shortcode parameter is disabled.
711 - *
712 - * By default, the "datatables_custom_commands" Shortcode parameter is disabled for security reasons.
713 - *
714 - * @since 1.0.0
715 - *
716 - * @param bool $disable Whether to disable the "datatables_custom_commands" Shortcode parameter. Default true.
717 - */
718 - if ( apply_filters( 'tablepress_disable_custom_commands_shortcode_parameter', true ) ) {
719 - $shortcode_atts['datatables_custom_commands'] = null;
720 - } else {
721 - // Convert the HTML entity `&amp;` back to `&` manually, as entities in Shortcodes in normal text paragraphs are sometimes double-encoded.
722 - $shortcode_atts['datatables_custom_commands'] = str_replace( '&amp;', '&', $shortcode_atts['datatables_custom_commands'] );
723 - // Convert HTML entities like `&lt;`, `&lsqb;`, `&#91;`, and `&amp;` back to their respective characters.
724 - $shortcode_atts['datatables_custom_commands'] = html_entity_decode( $shortcode_atts['datatables_custom_commands'], ENT_QUOTES | ENT_HTML5, get_option( 'blog_charset' ) );
725 - }
658 + /**
659 + * Filters whether the "datatables_custom_commands" Shortcode parameter is disabled.
660 + *
661 + * By default, the "datatables_custom_commands" Shortcode parameter is disabled for security reasons.
662 + *
663 + * @since 1.0.0
664 + *
665 + * @param bool $disable Whether to disable the "datatables_custom_commands" Shortcode parameter. Default true.
666 + */
667 + if ( ! is_null( $shortcode_atts['datatables_custom_commands'] ) && apply_filters( 'tablepress_disable_custom_commands_shortcode_parameter', true ) ) {
668 + $shortcode_atts['datatables_custom_commands'] = null;
726 669 }
727 670
728 671 // Determine options to use (if set in Shortcode, use those, otherwise use stored options, from the "Edit" screen).
729 672 $render_options = array();
@@ -899,9 +842,9 @@
899 842 }
900 843
901 844 // Maybe print a list of used render options.
902 845 if ( $render_options['shortcode_debug'] && is_user_logged_in() ) {
903 - $output .= '<pre>' . esc_html( wp_json_encode( $render_options, JSON_PRETTY_PRINT | JSON_UNESCAPED_SLASHES ) ) . '</pre>'; // @phpstan-ignore argument.type
846 + $output .= '<pre>' . var_export( $render_options, true ) . '</pre>'; // phpcs:ignore WordPress.PHP.DevelopmentFunctions.error_log_var_export
904 847 }
905 848
906 849 return $output;
907 850 }
@@ -906,16 +849,18 @@
906 849 return $output;
907 850 }
908 851
909 852 /**
910 - * Handles the Shortcode [table-info id=<ID> field=<name> /].
853 + * Handle Shortcode [table-info id=<ID> field=<name> /].
911 854 *
912 855 * @since 1.0.0
913 856 *
914 - * @param array<string, mixed> $shortcode_atts List of attributes that where included in the Shortcode.
857 + * @param array<string, mixed>|string $shortcode_atts List of attributes that where included in the Shortcode. An empty string for empty Shortcodes like [table] or [table /].
915 858 * @return string Text that replaces the Shortcode (error message or asked-for information).
916 859 */
917 - public function shortcode_table_info( array $shortcode_atts ): string {
860 + public function shortcode_table_info( /* array|string */ $shortcode_atts ): string {
861 + $shortcode_atts = (array) $shortcode_atts;
862 +
918 863 // Parse Shortcode attributes, only allow those that are specified.
919 864 $default_shortcode_atts = array(
920 865 'id' => '',
921 866 'field' => '',
@@ -977,15 +922,8 @@
977 922 switch ( $field ) {
978 923 case 'name':
979 924 case 'description':
980 925 $output = $table[ $field ];
981 - // Replace any & with &amp; that is not already an encoded entity (from function htmlentities2 in WP 2.8).
982 - // A complete htmlentities2() or htmlspecialchars() would encode <HTML> tags, which we don't want.
983 - $output = (string) preg_replace( '/&(?![A-Za-z]{0,4}\w{2,3};|#[0-9]{2,4};)/', '&amp;', $output );
984 - /** This filter is documented in classes/class-render.php */
985 - if ( apply_filters( 'tablepress_apply_nl2br', true, $table_id ) ) {
986 - $output = nl2br( $output );
987 - }
988 926 break;
989 927 case 'last_modified':
990 928 switch ( $format ) {
991 929 case 'raw':
@@ -1063,9 +1001,9 @@
1063 1001 return $output;
1064 1002 }
1065 1003
1066 1004 /**
1067 - * Expands the WP Search to also find posts and pages that have a search term in a table that is shown in them.
1005 + * Expand WP Search to also find posts and pages that have a search term in a table that is shown in them.
1068 1006 *
1069 1007 * This is done by looping through all search terms and TablePress tables and searching there for the search term,
1070 1008 * saving all tables's IDs that have a search term and then expanding the WP query to search for posts or pages that have the
1071 1009 * Shortcode for one of these tables in their content.
@@ -1101,10 +1039,8 @@
1101 1039 $table_ids = TablePress::$model_table->load_all( true, false );
1102 1040 // Array of all search words that were found, and the table IDs where they were found.
1103 1041 $query_result = array();
1104 1042
1105 - $fn_stripos = function_exists( 'mb_stripos' ) ? 'mb_stripos' : 'stripos';
1106 -
1107 1043 foreach ( $table_ids as $table_id ) {
1108 1044 // Load table, with table data, options, and visibility settings.
1109 1045 $table = TablePress::$model_table->load( $table_id, true, true );
1110 1046
@@ -1118,10 +1054,10 @@
1118 1054 continue;
1119 1055 }
1120 1056
1121 1057 foreach ( $search_terms as $search_term ) {
1122 - if ( ( $table['options']['print_name'] && false !== $fn_stripos( $table['name'], (string) $search_term ) )
1123 - || ( $table['options']['print_description'] && false !== $fn_stripos( $table['description'], (string) $search_term ) ) ) {
1058 + if ( ( $table['options']['print_name'] && false !== stripos( $table['name'], (string) $search_term ) )
1059 + || ( $table['options']['print_description'] && false !== stripos( $table['description'], (string) $search_term ) ) ) {
1124 1060 // Found the search term in the name or description (and they are shown).
1125 1061 $query_result[ $search_term ][] = $table_id; // Add table ID to result list.
1126 1062 // No need to continue searching this search term in this table.
1127 1063 continue;
@@ -1138,9 +1074,9 @@
1138 1074 // Column is hidden, so don't search in it.
1139 1075 continue;
1140 1076 }
1141 1077 // @todo Cells are not evaluated here, so math formulas are searched.
1142 - if ( false !== $fn_stripos( $table_cell, (string) $search_term ) ) {
1078 + if ( false !== stripos( $table_cell, (string) $search_term ) ) {
1143 1079 // Found the search term in the cell content.
1144 1080 $query_result[ $search_term ][] = $table_id; // Add table ID to result list
1145 1081 // No need to continue searching this search term in this table.
1146 1082 continue 3;
@@ -1182,51 +1118,15 @@
1182 1118 if ( '' === $block_attributes['id'] ) {
1183 1119 return '';
1184 1120 }
1185 1121
1186 - $render_attributes = shortcode_parse_atts( $block_attributes['parameters'] );
1122 + if ( '' !== trim( $block_attributes['parameters'] ) ) {
1123 + $render_attributes = shortcode_parse_atts( $block_attributes['parameters'] );
1124 + } else {
1125 + $render_attributes = array();
1126 + }
1187 1127 $render_attributes['id'] = $block_attributes['id'];
1188 1128
1189 1129 return $this->shortcode_table( $render_attributes );
1190 - }
1191 -
1192 - /**
1193 - * Registers the TablePress Elementor widgets.
1194 - *
1195 - * @since 3.1.0
1196 - *
1197 - * @param \Elementor\Widgets_Manager $widgets_manager Elementor widgets manager.
1198 - */
1199 - public function register_elementor_widgets( \Elementor\Widgets_Manager $widgets_manager ): void {
1200 - TablePress::load_file( 'class-elementor-widget-table.php', 'classes' );
1201 - $widgets_manager->register( new TablePress\Elementor\TablePressTableWidget() ); // @phpstan-ignore method.notFound (Elementor methods are not in the stubs.)
1202 - }
1203 -
1204 - /**
1205 - * Enqueues the TablePress Elementor Editor CSS styles.
1206 - *
1207 - * @since 3.1.0
1208 - */
1209 - public function enqueue_elementor_editor_styles(): void {
1210 - $svg_url = plugins_url( 'admin/img/tablepress-editor-button.svg', TABLEPRESS__FILE__ );
1211 - wp_register_style( 'tablepress-elementor', false ); // phpcs:ignore WordPress.WP.EnqueuedResourceParameters.MissingVersion
1212 - wp_add_inline_style(
1213 - 'tablepress-elementor',
1214 - <<<CSS
1215 - .elementor-panel .elementor-element .icon:has(> .tablepress-elementor-icon) {
1216 - height: 43.5px;
1217 - }
1218 - .tablepress-elementor-icon {
1219 - display: inline-block;
1220 - height: 28px;
1221 - width: 28px;
1222 - background-image: url({$svg_url});
1223 - background-repeat: no-repeat;
1224 - background-position: center;
1225 - background-size: 28px auto;
1226 - }
1227 - CSS
1228 - );
1229 - wp_enqueue_style( 'tablepress-elementor' );
1230 1130 }
1231 1131
1232 1132 } // class TablePress_Frontend_Controller