PluginProbe
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables / 2.2.13
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables v2.2.13
2.2.13 2.2.12 2.2.11 2.2.10 2.2.9 2.2.8 2.2.7 2.2.6 2.2.5 2.2.4 2.2.3 trunk 1.0.0 1.0.1 2.0.0 2.0.1 2.1.0 2.1.1 2.1.2 2.2.0 2.2.1 2.2.2
table-builder-block / includes / Render / BlockRenderer.php

BlockRenderer.php in TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables 2.2.13, at includes/Render/BlockRenderer.php

179 lines 7.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Server-side rendering for the table-builder block and its rows/cells
4 *
5 * @package TableKit
6 */
7
8 namespace TableBuilder\Render;
9
10 defined( 'ABSPATH' ) || exit;
11
12 /**
13 * Renders table-builder block markup in PHP (used by the shortcode and
14 * dynamic-block rendering paths).
15 */
16 class BlockRenderer {
17
18 /**
19 * Renders static table-builder block structure in PHP.
20 *
21 * @param array $attributes Block attributes.
22 * @param array $row_blocks Parsed row inner blocks to render as tbody content.
23 * @param string $tbody_content Pre-rendered tbody HTML; used instead of $row_blocks when given.
24 * @return string Rendered block HTML.
25 */
26 public static function render_table_builder( array $attributes = array(), array $row_blocks = array(), string $tbody_content = '' ): string {
27 $caption = $attributes['caption'] ?? '';
28 $headers = is_array( $attributes['headers'] ?? null ) ? $attributes['headers'] : array();
29 $footers = is_array( $attributes['footers'] ?? null ) ? $attributes['footers'] : array();
30 $has_header = ! empty( $attributes['hasHeader'] );
31 $has_footer = ! empty( $attributes['hasFooter'] );
32 $show_caption = ! empty( $attributes['showCaption'] );
33 $is_empty = ! empty( $attributes['isEmpty'] );
34 $block_class = trim( (string) ( $attributes['blockClass'] ?? '' ) );
35 $block_id = (string) ( $attributes['blockID'] ?? '' );
36 $col_widths = is_array( $attributes['columnWidths'] ?? null ) ? $attributes['columnWidths'] : array();
37
38 $settings = array(
39 'enableSorting' => ! empty( $attributes['enableSorting'] ),
40 'tableConditionalFormat' => is_array( $attributes['tableConditionalFormat'] ?? null ) ? $attributes['tableConditionalFormat'] : array(),
41 'mergeTableCell' => $attributes['mergeTableCell'] ?? array(),
42 'freezeSettings' => $attributes['freezeSettings'] ?? array(),
43 'blockClass' => $block_class,
44 'enableFreeze' => ! empty( $attributes['enableFreeze'] ),
45 'columnWidths' => $col_widths,
46 'rowHeights' => is_array( $attributes['rowHeights'] ?? null ) ? $attributes['rowHeights'] : array(),
47 'headerHeight' => absint( $attributes['headerHeight'] ?? 0 ),
48 'resizerEnabled' => isset( $attributes['resizerEnabled'] ) ? (bool) $attributes['resizerEnabled'] : true,
49 'mobileBreakpoint' => absint( $attributes['responsiveBreakpoint'] ?? 768 ),
50 );
51
52 $figure_classes = trim( 'wp-block-tablebuilder-table-builder table-builder-block ' . $block_class );
53 $figure_id = ! empty( $block_id ) ? 'block-' . sanitize_html_class( $block_id ) : '';
54
55 $has_widths = ! empty( $col_widths ) && array_sum( array_map( 'floatval', $col_widths ) ) > 0;
56 $table_style = $has_widths ? 'table-layout:fixed;width:100%;' : '';
57
58 $rendered_tbody = '';
59 if ( ! empty( $tbody_content ) ) {
60 $rendered_tbody = wp_kses_post( $tbody_content );
61 } elseif ( ! empty( $row_blocks ) ) {
62 $rendered_tbody = self::render_table_rows( $row_blocks );
63 }
64
65 ob_start();
66 ?>
67 <figure class="<?php echo esc_attr( $figure_classes ); ?>" data-block="tablebuilder/table-builder" data-settings="<?php echo esc_attr( wp_json_encode( $settings ) ); ?>"<?php echo ! empty( $figure_id ) ? ' id="' . esc_attr( $figure_id ) . '"' : ''; ?>>
68 <?php if ( ! $is_empty ) : ?>
69 <table class="gkit-table"<?php echo ! empty( $table_style ) ? ' style="' . esc_attr( $table_style ) . '"' : ''; ?>>
70 <?php if ( $has_header ) : ?>
71 <thead class="gkit-table__header">
72 <tr>
73 <?php foreach ( $headers as $index => $header ) : ?>
74 <?php $col_style = self::get_column_style( $col_widths, $index ); ?>
75 <th class="gkit-table__header-content"<?php echo ! empty( $col_style ) ? ' style="' . esc_attr( $col_style ) . '"' : ''; ?>>
76 <div><?php echo wp_kses_post( $header['title'] ?? '' ); ?></div>
77 </th>
78 <?php endforeach; ?>
79 </tr>
80 </thead>
81 <?php endif; ?>
82
83 <tbody class="gkit-table__body"><?php echo $rendered_tbody; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- built above via wp_kses_post() or from esc_attr()-escaped attributes plus core's render_block(). ?></tbody>
84
85 <?php if ( $has_footer ) : ?>
86 <tfoot class="gkit-table__footer">
87 <tr>
88 <?php foreach ( $footers as $index => $footer ) : ?>
89 <?php $col_style = self::get_column_style( $col_widths, $index ); ?>
90 <td class="gkit-table__footer-content"<?php echo ! empty( $col_style ) ? ' style="' . esc_attr( $col_style ) . '"' : ''; ?>>
91 <div><?php echo wp_kses_post( $footer['title'] ?? '' ); ?></div>
92 </td>
93 <?php endforeach; ?>
94 </tr>
95 </tfoot>
96 <?php endif; ?>
97 </table>
98
99 <?php if ( $show_caption ) : ?>
100 <figcaption class="gkit-table__caption"><?php echo wp_kses_post( $caption ); ?></figcaption>
101 <?php endif; ?>
102 <?php endif; ?>
103 </figure>
104 <?php
105
106 return (string) ob_get_clean();
107 }
108
109 /**
110 * Renders row and cell inner blocks for tbody markup.
111 *
112 * @param array $row_blocks Parsed "tablebuilder/table-builder-row" inner blocks.
113 * @return string Rendered <tr> markup.
114 */
115 private static function render_table_rows( array $row_blocks ): string {
116 $output = '';
117
118 foreach ( $row_blocks as $row_block ) {
119 if ( ( $row_block['blockName'] ?? '' ) !== 'tablebuilder/table-builder-row' ) {
120 continue;
121 }
122
123 $row_class = trim( 'wp-block-tablebuilder-table-builder-row gkit-table__body-row ' . ( $row_block['attrs']['blockClass'] ?? '' ) );
124 $output .= '<tr class="' . esc_attr( $row_class ) . '">';
125
126 foreach ( $row_block['innerBlocks'] ?? array() as $item_block ) {
127 if ( ( $item_block['blockName'] ?? '' ) !== 'tablebuilder/table-builder-item' ) {
128 continue;
129 }
130
131 $item_class = trim( 'wp-block-tablebuilder-table-builder-item gkit-table__body-content ' . ( $item_block['attrs']['blockClass'] ?? '' ) );
132 $item_markup = self::render_nested_inner_blocks( $item_block['innerBlocks'] ?? array() );
133 $output .= '<td class="' . esc_attr( $item_class ) . '"><div>' . $item_markup . '</div></td>';
134 }
135
136 $output .= '</tr>';
137 }
138
139 return $output;
140 }
141
142 /**
143 * Renders nested inner blocks of a cell.
144 *
145 * @param array $blocks Parsed inner blocks to render via core's render_block().
146 * @return string Combined rendered HTML.
147 */
148 private static function render_nested_inner_blocks( array $blocks ): string {
149 $output = '';
150
151 foreach ( $blocks as $inner ) {
152 $output .= render_block( $inner );
153 }
154
155 return $output;
156 }
157
158 /**
159 * Converts stored column widths into percentages for saved frontend parity.
160 *
161 * @param array $column_widths Stored column width values, keyed by column index.
162 * @param int $index Column index to compute the style for.
163 * @return string An inline "width:N%;" style, or an empty string if not applicable.
164 */
165 private static function get_column_style( array $column_widths, int $index ): string {
166 if ( empty( $column_widths[ $index ] ) ) {
167 return '';
168 }
169
170 $total_width = array_sum( array_map( 'floatval', $column_widths ) );
171 if ( $total_width <= 0 ) {
172 return '';
173 }
174
175 $percentage = ( (float) $column_widths[ $index ] / $total_width ) * 100;
176 return 'width:' . round( $percentage, 4 ) . '%;';
177 }
178 }
179