can_use_premium_code(); } private function has_visible_border($border) { $trimmed_border = trim($border); if ($trimmed_border === '') { return false; } $parts = preg_split('/\s+/', $trimmed_border, 3); $width = $parts[0] ?? ''; $style = $parts[1] ?? ''; if ($width === 'none' || $width === 'hidden') { return false; } if (preg_match('/^0(?:\.0+)?(?:[a-z%]+)?$/i', $width) === 1) { return false; } if ($style === 'none' || $style === 'hidden') { return false; } return true; } public function render($attributes) { $attrs = TableAttrs::from_array($attributes); $isProActive = $this->is_pro_active(); $rows = $attrs->table->rows->value(); $cols = $attrs->table->cols->value(); $headerEnabled = $attrs->table->headerEnabled->value(); $footerEnabled = $attrs->table->footerEnabled->value(); $stickyHeader = $attrs->table->stickyHeader->value(); $caption = $attrs->table->caption; $tableWidth = trim($attrs->table->tableWidth->asAttr()); $tableAlignment = $attrs->table->tableAlignment->asAttr(); $cellSpacingHorizontal = trim($attrs->table->cellSpacing->horizontal->asAttr()); $cellSpacingVertical = trim($attrs->table->cellSpacing->vertical->asAttr()); $tableBorderTop = trim($attrs->table->tableBorder->top->asAttr()); $tableBorderRight = trim($attrs->table->tableBorder->right->asAttr()); $tableBorderBottom = trim($attrs->table->tableBorder->bottom->asAttr()); $tableBorderLeft = trim($attrs->table->tableBorder->left->asAttr()); $fixedColumnWidths = $attrs->table->fixedColumnWidths->value(); $isHorizontalSpacingZero = $cellSpacingHorizontal === '0'; $isVerticalSpacingZero = $cellSpacingVertical === '0'; $hasCellSpacing = !$isHorizontalSpacingZero || !$isVerticalSpacingZero; $isWideWidth = $tableWidth === 'wide'; $isFullWidth = $tableWidth === 'full'; $canApplyCustomWidth = $tableWidth !== '' && !$isWideWidth && !$isFullWidth && $tableWidth !== 'auto'; if (!$canApplyCustomWidth) { $tableWidth = ''; } $wrapperAlignmentClass = $this->getWrapperAlignmentClass( $isWideWidth, $isFullWidth, $canApplyCustomWidth, $tableAlignment ); $tableStyles = [ 'border-collapse: ' . ($hasCellSpacing ? 'separate' : 'collapse'), ]; if ($hasCellSpacing) { $tableStyles[] = "border-spacing: {$cellSpacingHorizontal} {$cellSpacingVertical}"; } if ($tableWidth !== '') { $tableStyles[] = "width: {$tableWidth}"; $tableStyles[] = "max-width: {$tableWidth}"; } else { $tableStyles[] = 'width: 100%'; } if ($tableBorderTop !== '') { $tableStyles[] = "border-top: {$tableBorderTop}"; } if ($tableBorderRight !== '') { $tableStyles[] = "border-right: {$tableBorderRight}"; } if ($tableBorderBottom !== '') { $tableStyles[] = "border-bottom: {$tableBorderBottom}"; } if ($tableBorderLeft !== '') { $tableStyles[] = "border-left: {$tableBorderLeft}"; } $tableStyleAttr = "style='" . implode('; ', $tableStyles) . ";'"; $tableClasses = ['wp-block-tableberg']; if ($this->has_visible_border($tableBorderTop)) { $tableClasses[] = 'tableberg-has-table-border-top'; } if ($this->has_visible_border($tableBorderRight)) { $tableClasses[] = 'tableberg-has-table-border-right'; } if ($this->has_visible_border($tableBorderBottom)) { $tableClasses[] = 'tableberg-has-table-border-bottom'; } if ($this->has_visible_border($tableBorderLeft)) { $tableClasses[] = 'tableberg-has-table-border-left'; } if ($hasCellSpacing) { $tableClasses[] = 'tableberg-has-cell-spacing'; if ($isHorizontalSpacingZero) { $tableClasses[] = 'tableberg-cell-spacing-horizontal-zero'; } if ($isVerticalSpacingZero) { $tableClasses[] = 'tableberg-cell-spacing-vertical-zero'; } } $tableClassAttr = implode(' ', $tableClasses); $sortableColumns = []; if ($isProActive) { foreach ($attrs->columns as $column => $columnConfig) { if ($columnConfig->sortable === null) { continue; } $sortableColumns[$column] = $columnConfig->sortable->asAttr(); } } $paginationPageSize = (int) $attrs->table->pagination->pageSize->value(); if ($paginationPageSize < 1) { $paginationPageSize = 1; } $paginationConfig = [ 'enabled' => $isProActive && $attrs->table->pagination->enabled->value(), 'pageSize' => $paginationPageSize, 'showPageNumbers' => $attrs->table->pagination->showPageNumbers->value(), 'showPrevNext' => $attrs->table->pagination->showPrevNext->value(), ]; $searchEnabledAsStr = ( $isProActive && $attrs->table->search->enabled->value() ) ? 'true' : 'false'; $searchPlaceholder = $isProActive ? $attrs->table->search->placeholder->asAttr() : ''; $searchPosition = $isProActive ? $attrs->table->search->position->asAttr() : 'left'; $searchHighlightColor = $isProActive ? $attrs->table->search->highlightColor->asAttr() : ''; $responsiveDataAttrs = $this->buildResponsiveDataAttrs($attrs, $rows, $cols); $globalCellStyles = [ 'padding' => [ 'top' => $attrs->cellDefaults->styles->padding->top->asAttr(), 'right' => $attrs->cellDefaults->styles->padding->right->asAttr(), 'bottom' => $attrs->cellDefaults->styles->padding->bottom->asAttr(), 'left' => $attrs->cellDefaults->styles->padding->left->asAttr(), ], 'orientation' => $attrs->cellDefaults->styles->orientation->asAttr(), 'elementGap' => $attrs->cellDefaults->styles->elementGap->asAttr(), 'wrap' => $attrs->cellDefaults->styles->wrap->asAttr(), 'verticalAlign' => $attrs->cellDefaults->styles->verticalAlign->asAttr(), 'backgroundColor' => $attrs->cellDefaults->styles->backgroundColor->asAttr(), 'border' => [ 'top' => $attrs->cellDefaults->styles->border->top->asAttr(), 'right' => $attrs->cellDefaults->styles->border->right->asAttr(), 'bottom' => $attrs->cellDefaults->styles->border->bottom->asAttr(), 'left' => $attrs->cellDefaults->styles->border->left->asAttr(), ], 'borderRadius' => [ 'topLeft' => $attrs->cellDefaults->styles->borderRadius->topLeft->asAttr(), 'topRight' => $attrs->cellDefaults->styles->borderRadius->topRight->asAttr(), 'bottomRight' => $attrs->cellDefaults->styles->borderRadius->bottomRight->asAttr(), 'bottomLeft' => $attrs->cellDefaults->styles->borderRadius->bottomLeft->asAttr(), ], ]; // The table border radius rounds the whole table's outer corners. // border-radius on collapsed-border tables/cells is ignored by // browsers, so it is rendered on the wrapper (with overflow:hidden) // and removed from the individual cells here. $tableRadius = $globalCellStyles['borderRadius']; $globalCellStyles['borderRadius'] = [ 'topLeft' => '', 'topRight' => '', 'bottomRight' => '', 'bottomLeft' => '', ]; $cellRenderer = new CellRenderer(); $hiddenBySpan = []; $rowsHtml = ''; for ($row = 0; $row < $rows; $row++) { $cellsHtml = ''; $rowHeight = $this->getRowHeight($row, $attrs->rows); for ($col = 0; $col < $cols; $col++) { if (isset($hiddenBySpan[$row][$col])) { continue; } $cell = $this->getCell($row, $col, $attrs->cells); $span = $this->getCellSpan($cell); $rowSpan = is_numeric($span['rowSpan']) ? (int) $span['rowSpan'] : 1; $colSpan = is_numeric($span['colSpan']) ? (int) $span['colSpan'] : 1; if ($rowSpan > 1 || $colSpan > 1) { for ($rowOffset = 0; $rowOffset < $rowSpan; $rowOffset++) { for ($colOffset = 0; $colOffset < $colSpan; $colOffset++) { if ($rowOffset === 0 && $colOffset === 0) { continue; } $hiddenRow = $row + $rowOffset; $hiddenCol = $col + $colOffset; $hiddenBySpan[$hiddenRow][$hiddenCol] = true; } } } $isHeaderRowCell = $headerEnabled && $row === 0; $isFooterCell = $footerEnabled && $rows > 0 && $row === $rows - 1; $tag = ($isHeaderRowCell || $isFooterCell) ? 'th' : 'td'; $sortableType = ( $isHeaderRowCell && array_key_exists($col, $sortableColumns) ) ? $sortableColumns[$col] : null; $columnWidth = null; if ($colSpan === 1) { if ($fixedColumnWidths && $cols > 0) { $columnWidth = (string) (100 / $cols) . '%'; } else { $columnWidth = $this->getColumnWidth( $col, $attrs->columns ); } } $cellsHtml .= $cellRenderer->render( CellRenderContext::create( $row, $col, $rowSpan, $colSpan, $tag, $globalCellStyles, $this->getCellElements($cell), $this->getCellStyleOverride($cell), $this->getCellRibbon($cell), $sortableType, $columnWidth, $rowHeight, $stickyHeader, $this->getCellClassName($cell) ) ); } $rowsHtml .= "