PluginProbe
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables / 2.2.7
TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables v2.2.7
2.3.0 2.2.14 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 / Elementor / TablekitWidget.php

TablekitWidget.php in TableKit – WordPress Table Builder for Data Tables, WooCommerce Product Tables & Post Tables 2.2.7, at includes/Elementor/TablekitWidget.php

331 lines 9.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 /**
4 * Elementor widget for TableKit tables.
5 *
6 * @package TableKit
7 */
8
9 use TableBuilder\Shortcode\ShortcodeUtils;
10
11 if (! defined('ABSPATH')) {
12 exit;
13 }
14
15 class TableKit_Elementor_Widget extends \Elementor\Widget_Base
16 {
17 private const ALL_BLOCKS = '';
18
19 private static bool $global_styles_printed = false;
20 private static array $printed_block_styles = [];
21 private static array $printed_block_scripts = [];
22 private static ?array $table_options_cache = null;
23
24 // -------------------------------------------------------------------------
25 // Identity
26 // -------------------------------------------------------------------------
27
28 public function get_name(): string
29 {
30 return 'tablekit_table';
31 }
32
33 public function get_title(): string
34 {
35 return __('TableKit', 'tablekit');
36 }
37
38 public function get_icon(): string
39 {
40 return 'eicon-table';
41 }
42
43 public function get_categories(): array
44 {
45 return ['general'];
46 }
47
48 public function get_keywords(): array
49 {
50 return ['table', 'tablekit', 'data', 'grid'];
51 }
52
53 public function is_reload_preview_required(): bool
54 {
55 return true;
56 }
57
58 // -------------------------------------------------------------------------
59 // Controls
60 // -------------------------------------------------------------------------
61
62 protected function register_controls(): void
63 {
64 $this->start_controls_section(
65 'tablekit_table_section',
66 [
67 'label' => __('Table', 'tablekit'),
68 'tab' => \Elementor\Controls_Manager::TAB_CONTENT,
69 ]
70 );
71
72 $this->add_control(
73 'table_id',
74 [
75 'label' => __('Select Table', 'tablekit'),
76 'type' => \Elementor\Controls_Manager::SELECT2,
77 'options' => $this->get_table_options(),
78 'default' => '',
79 'render_type' => 'template',
80 'label_block' => true,
81 'description' => __('Create and manage tables under TableKit → Tables in the WP admin.', 'tablekit'),
82 ]
83 );
84
85 $this->add_control(
86 'block_index',
87 [
88 'label' => __('Select Block', 'tablekit'),
89 'type' => \Elementor\Controls_Manager::SELECT,
90 'options' => ['' => __('— All Blocks —', 'tablekit')],
91 'default' => self::ALL_BLOCKS,
92 'render_type' => 'template',
93 'label_block' => true,
94 'description' => __('Choose a specific block to display. Or select — All Blocks — to show all blocks.', 'tablekit'),
95 ]
96 );
97
98 $this->end_controls_section();
99 }
100
101 // -------------------------------------------------------------------------
102 // Rendering
103 // -------------------------------------------------------------------------
104
105 protected function render(): void
106 {
107 $settings = $this->get_settings_for_display();
108 $raw_id = $settings['table_id'] ?? 0;
109
110 if (is_array($raw_id)) {
111 $raw_id = reset($raw_id);
112 }
113
114 $table_id = absint($raw_id);
115
116 if (empty($table_id)) {
117 $this->render_placeholder(__('Select a table to display.', 'tablekit'));
118 return;
119 }
120
121 $post = get_post($table_id);
122
123 if (! $post) {
124 $this->render_placeholder(__('Table not found.', 'tablekit'));
125 return;
126 }
127
128 if (class_exists('\\TableBuilder\\Config\\Blocks')) {
129 \TableBuilder\Config\Blocks::instance()->enqueue_block_assets();
130 }
131
132 $all_blocks = parse_blocks($post->post_content);
133 $table_blocks = $this->filter_table_blocks($all_blocks);
134 $block_index = $settings['block_index'] ?? self::ALL_BLOCKS;
135 $blocks_to_render = $all_blocks;
136
137 if (self::ALL_BLOCKS !== $block_index && '' !== $block_index) {
138 $index = (int) $block_index;
139 if (isset($table_blocks[$index])) {
140 $blocks_to_render = array($table_blocks[$index]);
141 }
142 }
143
144 $block_names = $this->collect_block_names($blocks_to_render);
145
146 $this->print_shared_styles($block_names);
147 $this->print_table_styles($table_id, $post->post_content);
148
149 echo '<div class="tablekit-elementor-wrap">';
150 foreach ($blocks_to_render as $block) {
151 echo (new WP_Block($block))->render();
152 }
153 echo '</div>';
154
155 $this->print_block_scripts($block_names);
156
157 if (class_exists('\\TableBuilder\\Shortcode\\ShortcodeUtils')) {
158 echo \TableBuilder\Shortcode\ShortcodeUtils::get_elementor_init_script();
159 }
160 }
161
162 protected function content_template(): void {}
163
164 // -------------------------------------------------------------------------
165 // Private helpers
166 // -------------------------------------------------------------------------
167
168 private function render_placeholder(string $message): void
169 {
170 echo '<div class="tablekit-el-placeholder" style="padding:1.5em;border:1px dashed #ccc;text-align:center;color:#999;">'
171 . '<span class="eicon-table" style="font-size:2em;display:block;margin-bottom:.5em;opacity:.35;"></span>'
172 . '<p style="margin:0;">' . esc_html($message) . '</p>'
173 . '</div>';
174 }
175
176 private function filter_table_blocks(array $blocks): array
177 {
178 return ShortcodeUtils::filter_table_blocks($blocks);
179 }
180
181 /**
182 * Print shared CSS once per page load.
183 */
184 private function print_shared_styles(array $block_names): void
185 {
186 $css = '';
187
188 if (! self::$global_styles_printed) {
189 foreach (['global.css', 'components.css'] as $filename) {
190 $path = TABLE_BUILDER_BLOCK_PLUGIN_DIR . 'build/tablebuilder/' . $filename;
191 if (file_exists($path)) {
192 $css .= file_get_contents($path) . "\n"; // phpcs:ignore
193 }
194 }
195
196 $css .= $this->get_registered_style_css('tablebuilder/table-builder');
197 self::$global_styles_printed = true;
198 self::$printed_block_styles['tablebuilder/table-builder'] = true;
199 }
200
201 foreach ($block_names as $name) {
202 if (isset(self::$printed_block_styles[$name])) {
203 continue;
204 }
205 $css .= $this->get_registered_style_css($name);
206 self::$printed_block_styles[$name] = true;
207 }
208
209 if ('' !== trim($css)) {
210 echo '<style id="tablekit-shared-styles">' . $css . '</style>'; // phpcs:ignore
211 }
212 }
213
214 /**
215 * Print per-table dynamic CSS. Unique ID per table so multiple widgets coexist.
216 */
217 private function print_table_styles(int $table_id, string $post_content): void
218 {
219 if (! class_exists('\\TableBuilder\\Shortcode\\Shortcode')) {
220 return;
221 }
222
223 $shortcode = \TableBuilder\Shortcode\Shortcode::instance();
224
225 if (! $shortcode || ! method_exists($shortcode, 'collect_blocks_css_from_content')) {
226 return;
227 }
228
229 $css = $shortcode->collect_blocks_css_from_content($post_content);
230
231 if ('' !== trim($css)) {
232 echo '<style id="tablekit-el-css-' . esc_attr((string) $table_id) . '">' . $css . '</style>'; // phpcs:ignore
233 }
234 }
235
236 /**
237 * Enqueue + immediately print block view-scripts inline.
238 * Required for the editor iframe where wp_footer never fires.
239 */
240 private function print_block_scripts(array $block_names): void
241 {
242 // FIX 8: only print once per full or partial render cycle
243 static $printed = [];
244
245 foreach (array_unique(array_merge(['tablebuilder/table-builder'], $block_names)) as $name) {
246 $handle = \TableBuilder\Shortcode\ShortcodeUtils::get_block_asset_handle($name, 'viewScript');
247 if (isset($printed[$handle])) {
248 continue;
249 }
250 wp_enqueue_script($handle);
251 wp_print_scripts($handle);
252 $printed[$handle] = true;
253 }
254 }
255
256 /**
257 * Read the CSS file of a registered WP stylesheet handle.
258 */
259 private function get_registered_style_css(string $block_name): string
260 {
261 $handle = \TableBuilder\Shortcode\ShortcodeUtils::get_block_asset_handle($block_name, 'style');
262 $style = wp_styles()->query($handle, 'registered');
263
264 if (! $style || empty($style->src)) {
265 return '';
266 }
267
268 $path = str_replace(content_url(), WP_CONTENT_DIR, (string) $style->src);
269 $path = (string) strtok($path, '?');
270
271 if (! file_exists($path)) {
272 return '';
273 }
274
275 return file_get_contents($path) . "\n"; // phpcs:ignore
276 }
277
278 /**
279 * Recursively collect unique block names from a block tree.
280 */
281 private function collect_block_names(array $blocks): array
282 {
283 $all = ShortcodeUtils::collect_blocks_recursive(
284 $blocks,
285 static fn(array $block): bool => is_string($block['blockName'] ?? null) && '' !== $block['blockName']
286 );
287
288 return array_values(array_unique(array_column($all, 'blockName')));
289 }
290
291 /**
292 * Build the SELECT2 options array for the table picker control.
293 */
294 private function get_table_options(): array
295 {
296 if (is_array(self::$table_options_cache)) {
297 return self::$table_options_cache;
298 }
299
300 $options = ['' => __('-- Select a Table --', 'tablekit')];
301
302 $tables = get_posts(
303 [
304 'post_type' => 'tablekit_table',
305 'post_status' => 'publish',
306 'posts_per_page' => -1,
307 'orderby' => 'title',
308 'order' => 'ASC',
309 ]
310 );
311
312 foreach ($tables as $table) {
313 $options[(string) $table->ID] = esc_html($table->post_title);
314 }
315
316 if (class_exists('\\TableBuilder\\Config\\CPT\\TableCPT')) {
317 $inline = \TableBuilder\Config\CPT\TableCPT::instance()->get_inline_table_source_options();
318 foreach ($inline as $id => $label) {
319 $key = (string) $id;
320 if (! isset($options[$key])) {
321 $options[$key] = esc_html($label);
322 }
323 }
324 }
325
326 self::$table_options_cache = $options;
327
328 return $options;
329 }
330 }
331