PluginProbe
Tableberg – Simple Gutenberg Table Block / 1.2.0
Tableberg – Simple Gutenberg Table Block v1.2.0
1.2.0 1.1.5 1.1.4 1.1.3 1.1.2 1.1.1 1.1.0 1.0.5 1.0.4 1.0.3 1.0.2 1.0.1 trunk 0.0.2 0.2.1 0.3.2 0.3.3 0.4.1 0.5.0 0.5.1 0.5.2 0.5.3 0.5.4 0.5.5 0.5.6 All 43 releases
← All changes | renderer/Table/TableRenderer.php +122 -28 1.1.2 → 1.2.0 View file →
@@ -69,8 +69,19 @@
69 69 );
70 70 $stickyHeader = !empty($stickySettings['stickyHeader']);
71 71 $stickyFirstCol = !empty($stickySettings['stickyFirstCol']);
72 72
73 + // Row-only/column-only is Pro-owned. Free's empty default preserves
74 + // the attribute without enabling its editor or frontend behavior.
75 + $innerBorderType = apply_filters(
76 + 'tableberg/inner_border_type',
77 + '',
78 + $attrs->attrs
79 + );
80 + if (!in_array($innerBorderType, ['row', 'col'], true)) {
81 + $innerBorderType = '';
82 + }
83 +
73 84 $caption = $attrs->table->caption;
74 85 $tableWidth = trim($attrs->table->tableWidth->asAttr());
75 86 $tableAlignment = $attrs->table->tableAlignment->asAttr();
76 87 $cellSpacingHorizontal = trim($attrs->table->cellSpacing->horizontal->asAttr());
@@ -79,8 +90,24 @@
79 90 $tableBorderRight = trim($attrs->table->tableBorder->right->asAttr());
80 91 $tableBorderBottom = trim($attrs->table->tableBorder->bottom->asAttr());
81 92 $tableBorderLeft = trim($attrs->table->tableBorder->left->asAttr());
82 93 $fixedColumnWidths = $attrs->table->fixedColumnWidths->value();
94 + $tableRadius = [
95 + 'topLeft' => $attrs->cellDefaults->styles->borderRadius->topLeft->asAttr(),
96 + 'topRight' => $attrs->cellDefaults->styles->borderRadius->topRight->asAttr(),
97 + 'bottomRight' => $attrs->cellDefaults->styles->borderRadius->bottomRight->asAttr(),
98 + 'bottomLeft' => $attrs->cellDefaults->styles->borderRadius->bottomLeft->asAttr(),
99 + ];
100 + $isZeroRadius = function ($value) {
101 + $trimmed = trim((string) $value);
102 + return $trimmed === '' || preg_match('/^0(?:\.0+)?[a-z%]*$/i', $trimmed) === 1;
103 + };
104 + $hasRoundedCorners = count(array_filter(
105 + $tableRadius,
106 + function ($value) use ($isZeroRadius) {
107 + return !$isZeroRadius($value);
108 + }
109 + )) > 0;
83 110
84 111 $isHorizontalSpacingZero = $cellSpacingHorizontal === '0';
85 112 $isVerticalSpacingZero = $cellSpacingVertical === '0';
86 113 $hasCellSpacing = !$isHorizontalSpacingZero || !$isVerticalSpacingZero;
@@ -104,11 +131,19 @@
104 131 $canApplyCustomWidth,
105 132 $tableAlignment
106 133 );
107 134
108 - $tableStyles = [
109 - 'border-collapse: ' . ($hasCellSpacing ? 'separate' : 'collapse'),
110 - ];
135 + $tableStyles = array_merge(
136 + // Table-wide typography, inherited by everything in the cells that
137 + // does not set its own.
138 + $attrs->table->typography->asStyles(),
139 + [
140 + 'border-collapse: ' . ($hasCellSpacing ? 'separate' : 'collapse'),
141 + // Neutralize theme-level table borders. Tableberg owns its
142 + // borders through the table/cell controls and rounded wrapper.
143 + 'border: 0',
144 + ]
145 + );
111 146
112 147 if ($hasCellSpacing) {
113 148 $tableStyles[] = "border-spacing: {$cellSpacingHorizontal} {$cellSpacingVertical}";
114 149 }
@@ -119,21 +154,21 @@
119 154 } else {
120 155 $tableStyles[] = 'width: 100%';
121 156 }
122 157
123 - if ($tableBorderTop !== '') {
158 + if (!$hasRoundedCorners && $tableBorderTop !== '') {
124 159 $tableStyles[] = "border-top: {$tableBorderTop}";
125 160 }
126 161
127 - if ($tableBorderRight !== '') {
162 + if (!$hasRoundedCorners && $tableBorderRight !== '') {
128 163 $tableStyles[] = "border-right: {$tableBorderRight}";
129 164 }
130 165
131 - if ($tableBorderBottom !== '') {
166 + if (!$hasRoundedCorners && $tableBorderBottom !== '') {
132 167 $tableStyles[] = "border-bottom: {$tableBorderBottom}";
133 168 }
134 169
135 - if ($tableBorderLeft !== '') {
170 + if (!$hasRoundedCorners && $tableBorderLeft !== '') {
136 171 $tableStyles[] = "border-left: {$tableBorderLeft}";
137 172 }
138 173
139 174 $tableStyleAttr = "style='" . implode('; ', $tableStyles) . ";'";
@@ -244,13 +279,18 @@
244 279 'bottomLeft' => $attrs->cellDefaults->styles->borderRadius->bottomLeft->asAttr(),
245 280 ],
246 281 ];
247 282
248 - // The table border radius rounds the whole table's outer corners.
249 - // border-radius on collapsed-border tables/cells is ignored by
250 - // browsers, so it is rendered on the wrapper (with overflow:hidden)
251 - // and removed from the individual cells here.
252 - $tableRadius = $globalCellStyles['borderRadius'];
283 + // A collapsed table cannot reliably round its own explicit border.
284 + // The wrapper owns only the table border and clips the cell grid to
285 + // it. Cell borders stay on cells; copying them to the wrapper would
286 + // add an outline that the user did not configure as a table border.
287 + $tableOuterBorder = [
288 + 'top' => $tableBorderTop,
289 + 'right' => $tableBorderRight,
290 + 'bottom' => $tableBorderBottom,
291 + 'left' => $tableBorderLeft,
292 + ];
253 293 $globalCellStyles['borderRadius'] = [
254 294 'topLeft' => '',
255 295 'topRight' => '',
256 296 'bottomRight' => '',
@@ -269,8 +309,32 @@
269 309 $rowBackgroundColor = isset($rowStyles['backgroundColor']) && is_string($rowStyles['backgroundColor'])
270 310 ? $rowStyles['backgroundColor']
271 311 : '';
272 312
313 + $cellStylesForRow = $globalCellStyles;
314 +
315 + // Header/footer/even/odd are table-wide defaults, resolved per
316 + // row here the same way `cell/index.tsx`'s
317 + // `useRowBackgroundStyleKey` does in the editor — header/footer
318 + // don't consume a slot in the even/odd count.
319 + $isHeaderRow = $headerEnabled && $row === 0;
320 + $isFooterRow = $footerEnabled && $rows > 0 && $row === $rows - 1;
321 +
322 + if ($isHeaderRow) {
323 + $rowPositionBackground = $attrs->cellDefaults->styles->headerBackgroundColor->asAttr();
324 + } elseif ($isFooterRow) {
325 + $rowPositionBackground = $attrs->cellDefaults->styles->footerBackgroundColor->asAttr();
326 + } else {
327 + $dataRowPosition = $headerEnabled ? $row - 1 : $row;
328 + $rowPositionBackground = ($dataRowPosition % 2 === 0)
329 + ? $attrs->cellDefaults->styles->oddRowBackgroundColor->asAttr()
330 + : $attrs->cellDefaults->styles->evenRowBackgroundColor->asAttr();
331 + }
332 +
333 + if ($rowPositionBackground !== '') {
334 + $cellStylesForRow['backgroundColor'] = $rowPositionBackground;
335 + }
336 +
273 337 // A row with its own background would otherwise never show
274 338 // through: every cell paints its own background over the
275 339 // `<tr>`'s, and cells fall back to the table-wide default
276 340 // whenever they carry no colour of their own. So for this row's
@@ -275,9 +339,8 @@
275 339 // `<tr>`'s, and cells fall back to the table-wide default
276 340 // whenever they carry no colour of their own. So for this row's
277 341 // cells, that fallback is cleared — a cell/column colour on top
278 342 // of it (applied below by the pro filter) still wins either way.
279 - $cellStylesForRow = $globalCellStyles;
280 343 if ($rowBackgroundColor !== '') {
281 344 $cellStylesForRow['backgroundColor'] = '';
282 345 }
283 346
@@ -345,9 +408,12 @@
345 408 $stickyHeader,
346 409 $stickyFirstCol,
347 410 $this->getCellClassName($cell),
348 411 $cell instanceof CellData ? $cell->attrs : [],
349 - $this->isCellEmpty($cell)
412 + $this->isCellEmpty($cell),
413 + $innerBorderType,
414 + $rows,
415 + $cols
350 416 )
351 417 );
352 418 }
353 419
@@ -355,8 +421,17 @@
355 421 if ($rowBackgroundColor !== '') {
356 422 $rowStyleParts[] = 'background-color:' . esc_attr($rowBackgroundColor);
357 423 }
358 424
425 + // Inherited by everything in the row's cells that has no colour
426 + // of its own.
427 + $rowTextColor = isset($rowStyles['textColor']) && is_string($rowStyles['textColor'])
428 + ? $rowStyles['textColor']
429 + : '';
430 + if ($rowTextColor !== '') {
431 + $rowStyleParts[] = 'color:' . esc_attr($rowTextColor);
432 + }
433 +
359 434 $rowBorder = isset($rowStyles['border']) && is_array($rowStyles['border'])
360 435 ? $rowStyles['border']
361 436 : [];
362 437 foreach (['top', 'right', 'bottom', 'left'] as $side) {
@@ -385,27 +460,29 @@
385 460 'sortable' => $sortType,
386 461 ];
387 462 }
388 463
389 - $columnsJson = json_encode($columnsData);
464 + $columnsJson = wp_json_encode($columnsData);
390 465 if (!is_string($columnsJson)) {
391 466 $columnsJson = '{}';
392 467 }
468 + $columnsJson = esc_attr($columnsJson);
393 469
394 - $paginationJson = json_encode($paginationConfig);
470 + $paginationJson = wp_json_encode($paginationConfig);
395 471 if (!is_string($paginationJson)) {
396 472 $paginationJson = '{}';
397 473 }
474 + $paginationJson = esc_attr($paginationJson);
398 475
476 + $searchPlaceholderAttr = esc_attr($searchPlaceholder);
477 + $searchPositionAttr = esc_attr($searchPosition);
478 + $searchHighlightColorAttr = esc_attr($searchHighlightColor);
479 +
399 480 $wrapperClass = trim("tableberg-table-wrapper {$wrapperAlignmentClass}");
400 481
401 - // Round the whole table's outer corners by clipping the wrapper.
482 + // Round the whole table's outer corners on the wrapper.
402 483 // Zero radii are skipped so a table without any actual rounding does
403 484 // not carry pointless border-radius declarations.
404 - $isZeroRadius = function ($value) {
405 - $trimmed = trim((string) $value);
406 - return $trimmed === '' || preg_match('/^0(?:\.0+)?[a-z%]*$/i', $trimmed) === 1;
407 - };
408 485 $wrapperStyles = [];
409 486 if (!$isZeroRadius($tableRadius['topLeft'])) {
410 487 $wrapperStyles[] = 'border-top-left-radius:' . $tableRadius['topLeft'];
411 488 }
@@ -418,8 +495,24 @@
418 495 if (!$isZeroRadius($tableRadius['bottomLeft'])) {
419 496 $wrapperStyles[] = 'border-bottom-left-radius:' . $tableRadius['bottomLeft'];
420 497 }
421 498
499 + if (!empty($wrapperStyles)) {
500 + if ($tableOuterBorder['top'] !== '') {
501 + $wrapperStyles[] = 'border-top:' . $tableOuterBorder['top'];
502 + }
503 + if ($tableOuterBorder['right'] !== '') {
504 + $wrapperStyles[] = 'border-right:' . $tableOuterBorder['right'];
505 + }
506 + if ($tableOuterBorder['bottom'] !== '') {
507 + $wrapperStyles[] = 'border-bottom:' . $tableOuterBorder['bottom'];
508 + }
509 + if ($tableOuterBorder['left'] !== '') {
510 + $wrapperStyles[] = 'border-left:' . $tableOuterBorder['left'];
511 + }
512 + $wrapperStyles[] = 'box-sizing:border-box';
513 + }
514 +
422 515 // A table wider than its wrapper must scroll inside the wrapper
423 516 // instead of pushing the whole page sideways, so the wrapper is a
424 517 // scroll container by default.
425 518 //
@@ -431,10 +524,8 @@
431 524 // scrolling wins and the header sticks within the wrapper.
432 525 //
433 526 // A rounded wrapper always needs the clip, so it opts in regardless.
434 527 $pageStickyHeader = $stickyHeader && !$stickyFirstCol;
435 - $hasRoundedCorners = !empty($wrapperStyles);
436 -
437 528 if ($hasRoundedCorners || !$pageStickyHeader) {
438 529 // `auto`, not `hidden`: both clip to the rounded corners, but
439 530 // `hidden` would also swallow a table wider than the wrapper.
440 531 // Inline, so it also wins over the `.tableberg-scroll-x` rule.
@@ -494,11 +585,11 @@
494 585 data-tableberg-sortable='$sortingBoolAsStr'
495 586 data-tableberg-columns='$columnsJson'
496 587 data-tableberg-pagination='$paginationJson'
497 588 data-tableberg-search-enabled='$searchEnabledAsStr'
498 - data-tableberg-search-placeholder='$searchPlaceholder'
499 - data-tableberg-search-position='$searchPosition'
500 - data-tableberg-search-highlight-color='$searchHighlightColor'
589 + data-tableberg-search-placeholder='$searchPlaceholderAttr'
590 + data-tableberg-search-position='$searchPositionAttr'
591 + data-tableberg-search-highlight-color='$searchHighlightColorAttr'
501 592 data-tableberg-header='$headerBoolAsStr'
502 593 data-tableberg-footer='$footerBoolAsStr'
503 594 {$responsiveDataAttrs}
504 595 >
@@ -570,8 +661,11 @@
570 661 $mobileMaxWidth = max(1, (int) $mobile->maxWidth->value());
571 662 $tabletStackCount = max(1, (int) $tablet->stackCount->value());
572 663 $mobileStackCount = max(1, (int) $mobile->stackCount->value());
573 664
665 + $tabletRepeatFirstCol = $tablet->repeatFirstCol->asAttr();
666 + $mobileRepeatFirstCol = $mobile->repeatFirstCol->asAttr();
667 +
574 668 return "
575 669 data-tableberg-responsive='true'
576 670 data-tableberg-rows='{$rows}'
577 671 data-tableberg-cols='{$cols}'
@@ -579,15 +673,15 @@
579 673 data-tableberg-tablet-width='{$tabletMaxWidth}'
580 674 data-tableberg-tablet-mode='{$tablet->mode->asAttr()}'
581 675 data-tableberg-tablet-transpose='{$tablet->transpose->asAttr()}'
582 676 data-tableberg-tablet-count='{$tabletStackCount}'
583 - data-tableberg-tablet-repeat-first-col='{$tablet->repeatFirstCol->asAttr()}'
677 + data-tableberg-tablet-repeat-first-col='{$tabletRepeatFirstCol}'
584 678 data-tableberg-mobile-enabled='{$mobile->enabled->asAttr()}'
585 679 data-tableberg-mobile-width='{$mobileMaxWidth}'
586 680 data-tableberg-mobile-mode='{$mobile->mode->asAttr()}'
587 681 data-tableberg-mobile-transpose='{$mobile->transpose->asAttr()}'
588 682 data-tableberg-mobile-count='{$mobileStackCount}'
589 - data-tableberg-mobile-repeat-first-col='{$mobile->repeatFirstCol->asAttr()}'
683 + data-tableberg-mobile-repeat-first-col='{$mobileRepeatFirstCol}'
590 684 ";
591 685 }
592 686
593 687 private function getCell($row, $col, $cells) {