'
',
'table' => sprintf(
'
',
esc_attr( $class_tb )
),
'header' => $this->html_header( $data['header'] ?? [] ),
'body' => $this->html_body( $data['body'] ?? [] ),
'footer' => $this->html_footer( $data['footer'] ?? '' ),
'table-end' => '
',
'wrap-end' => '
',
];
return Template::combine_components( $section );
}
/**
* Render the HTML table header.
*
* @param array $data
*
* @return string
*/
public function html_header( array $data = [] ): string {
$html_th = '';
foreach ( $data as $item ) {
$html_th .= $this->html_header_sort( $item );
}
$section = [
'wrapper' => '',
'tr' => '',
'ths' => $html_th,
'tr_end' => '
',
'wrapper_end' => '',
];
return Template::combine_components( $section );
}
/**
* Render a single sortable/non-sortable column header.
*
* Mirrors WordPress WP_List_Table column headers, replacing the
* default .sorting-indicator pseudo-element icon with lp-icon carets.
*
* Expected item keys:
* - class : CSS class(es) for the .
* - title : Column title.
* - sortable : Whether the column supports sorting.
* - sort_url : URL to use when the header is clicked (required when sortable).
* - sorted : Whether this column is the currently sorted one.
* - sort_order : Current sort order, 'asc' or 'desc' (default 'asc').
*
* @param array $item
*
* @return string
*/
public function html_header_sort( array $item = [] ): string {
$classes = array_filter( [ (string) ( $item['class'] ?? '' ) ] );
$sortable = ! empty( $item['sortable'] );
$sorted = $sortable && ! empty( $item['sorted'] );
$order = $sorted ? strtolower( (string) ( $item['sort_order'] ?? 'asc' ) ) : '';
if ( ! in_array( $order, [ 'asc', 'desc' ], true ) ) {
$order = 'asc';
}
if ( $sortable ) {
$classes[] = $sorted ? 'sorted' : 'sortable';
if ( $sorted ) {
$classes[] = $order;
}
}
$title = wp_kses_post( $item['title'] ?? '' );
$class = implode( ' ', $classes );
if ( ! $sortable ) {
return sprintf(
' | %s | ',
esc_attr( $class ),
$title
);
}
$up_active = $sorted && 'asc' === $order ? ' is-active' : '';
$down_active = $sorted && 'desc' === $order ? ' is-active' : '';
$sort_url = $item['sort_url'] ?? '#';
return sprintf(
'
%s
| ',
esc_attr( $class ),
esc_url( $sort_url ),
$title,
esc_attr( $up_active ),
esc_attr( $down_active )
);
}
/**
* Render the HTML table body.
*
* @param array $data
*
* @return string
*/
public function html_body( array $data = [] ): string {
$html_tr = '';
// Allow callers to pass fully prepared rows HTML.
if ( isset( $data['rows_html'] ) && is_string( $data['rows_html'] ) ) {
$html_tr = $data['rows_html'];
} else {
foreach ( $data as $item_tr ) {
$html_tr .= '';
foreach ( $item_tr as $item_td ) {
$html_td = sprintf(
'| %s | ',
wp_kses_post( $item_td )
);
$html_tr .= $html_td;
}
$html_tr .= '
';
}
}
$section = [
'wrapper' => '',
'trs' => $html_tr,
'wrapper_end' => '',
];
return Template::combine_components( $section );
}
/**
* Render the HTML table footer.
*
* @param string $footer_html
*
* @return string
*/
public function html_footer( string $footer_html = '' ): string {
if ( '' === trim( $footer_html ) ) {
return '';
}
$html_td = sprintf(
'%s | ',
wp_kses_post( $footer_html )
);
$section = [
'wrapper' => '',
'tr' => '',
'tds' => $html_td,
'tr_end' => '
',
'wrapper_end' => '',
];
return Template::combine_components( $section );
}
/**
* Render the HTML info page query.
*
* @param array $data
*
* @return string
*/
public function html_page_result( array $data = [] ): string {
$total_rows = $data['total_rows'] ?? 0;
$paged = $data['paged'] ?? 1;
$per_page = $data['per_page'] ?? 1;
$item_name = $data['item_name'] ?? _n( 'item', 'items', $total_rows, 'learnpress' );
$from = ( $paged - 1 ) * $per_page + 1;
$to = $from + $per_page - 1;
$to = min( $to, $total_rows );
if ( $total_rows < 1 ) {
$from = 0;
}
$format = __( 'Displaying {{from}} to {{to}} of {{total}} {{item_name}}.', 'learnpress' );
$format = apply_filters(
'learnpress/table/list-page-result',
$format,
$data
);
$output = str_replace(
array( '{{from}}', '{{to}}', '{{total}}', '{{item_name}}' ),
array(
$from,
$to,
$total_rows,
$item_name,
),
$format
);
return wp_kses_post( $output );
}
}