, is_header: bool}> */ private array $rows = []; /** * Cells for the active row. * * @var array */ private array $current_row = []; /** * Whether the active row is a header row. * * @var bool */ private bool $current_row_is_header = false; /** * Start a new row. * * @param bool $is_header Whether the row starts in a header context. * * @return void */ public function start_row( bool $is_header = false ): void { if ( ! empty( $this->current_row ) ) { $this->finish_row(); } $this->current_row = []; $this->current_row_is_header = $is_header; } /** * Append a cell to the active row. * * @param WpHtmlApiLineBuffer $cell Cell content buffer. * @param bool $is_header Whether the cell came from a TH element. * * @return void */ public function append_table_cell( WpHtmlApiLineBuffer $cell, bool $is_header = false ): void { $this->current_row[] = $cell; $this->current_row_is_header = $this->current_row_is_header || $is_header; } /** * Finish the active row. * * @return void */ public function finish_row(): void { if ( empty( $this->current_row ) ) { $this->current_row_is_header = false; return; } $this->rows[] = [ 'cells' => $this->current_row, 'is_header' => $this->current_row_is_header, ]; $this->current_row = []; $this->current_row_is_header = false; } /** * Flush the table into markdown. * * @param WpHtmlApiRendererOptions $options Renderer options. * * @return string */ public function flush( WpHtmlApiRendererOptions $options ): string { $this->finish_row(); if ( empty( $this->rows ) ) { return ''; } $soft_limit = $options->soft_line_wrap; $options->soft_line_wrap = PHP_INT_MAX; $rows = []; foreach ( $this->rows as $row ) { $cells = []; foreach ( $row['cells'] as $cell ) { $cells[] = $this->normalize_cell_markdown( $cell->flush( $options ) ); } $rows[] = [ 'cells' => $cells, 'is_header' => $row['is_header'], ]; } $options->soft_line_wrap = $soft_limit; $header_row = $rows[0]['cells']; $body_rows = array_slice( $rows, 1 ); if ( empty( $rows[0]['is_header'] ) ) { $header_row = $rows[0]['cells']; } $column_count = count( $header_row ); foreach ( $body_rows as $row ) { $column_count = max( $column_count, count( $row['cells'] ) ); } if ( $column_count < 1 ) { return ''; } $header_row = array_pad( $header_row, $column_count, '' ); $lines = []; $lines[] = '| ' . implode( ' | ', $header_row ) . ' |'; $lines[] = '| ' . implode( ' | ', array_fill( 0, $column_count, '---' ) ) . ' |'; foreach ( $body_rows as $row ) { $lines[] = '| ' . implode( ' | ', array_pad( $row['cells'], $column_count, '' ) ) . ' |'; } return implode( "\n", $lines ); } /** * Normalize rendered cell markdown for pipe-table output. * * @param string $markdown Cell markdown. * * @return string */ private function normalize_cell_markdown( string $markdown ): string { $markdown = trim( $markdown ); $markdown = wp_strip_all_tags( $markdown ); $markdown = preg_replace( "/\r\n?/", "\n", $markdown ); $markdown = preg_replace( "/\n+/", ' ', $markdown ); $markdown = preg_replace( '/\s+/', ' ', $markdown ); $markdown = str_replace( '|', '\\|', $markdown ); return trim( $markdown ); } /** * Determine whether the table is empty. * * @return bool */ public function is_empty(): bool { if ( ! empty( $this->current_row ) ) { return false; } return empty( $this->rows ); } }