| @@ -52,13 +52,9 @@ | ||
| 52 | 52 | public function html_header( array $data = [] ): string { |
| 53 | 53 | $html_th = ''; |
| 54 | 54 | |
| 55 | 55 | foreach ( $data as $item ) { |
| 56 | - $html_th .= sprintf( | |
| 57 | - '<th class="%s">%s</th>', | |
| 58 | - esc_attr( $item['class'] ?? '' ), | |
| 59 | - wp_kses_post( $item['title'] ?? '' ) | |
| 60 | - ); | |
| 56 | + $html_th .= $this->html_header_sort( $item ); | |
| 61 | 57 | } |
| 62 | 58 | |
| 63 | 59 | $section = [ |
| 64 | 60 | 'wrapper' => '<thead>', |
| @@ -68,8 +64,75 @@ | ||
| 68 | 64 | 'wrapper_end' => '</thead>', |
| 69 | 65 | ]; |
| 70 | 66 | |
| 71 | 67 | return Template::combine_components( $section ); |
| 68 | + } | |
| 69 | + | |
| 70 | + /** | |
| 71 | + * Render a single sortable/non-sortable column header. | |
| 72 | + * | |
| 73 | + * Mirrors WordPress WP_List_Table column headers, replacing the | |
| 74 | + * default .sorting-indicator pseudo-element icon with lp-icon carets. | |
| 75 | + * | |
| 76 | + * Expected item keys: | |
| 77 | + * - class : CSS class(es) for the <th>. | |
| 78 | + * - title : Column title. | |
| 79 | + * - sortable : Whether the column supports sorting. | |
| 80 | + * - sort_url : URL to use when the header is clicked (required when sortable). | |
| 81 | + * - sorted : Whether this column is the currently sorted one. | |
| 82 | + * - sort_order : Current sort order, 'asc' or 'desc' (default 'asc'). | |
| 83 | + * | |
| 84 | + * @param array $item | |
| 85 | + * | |
| 86 | + * @return string | |
| 87 | + */ | |
| 88 | + public function html_header_sort( array $item = [] ): string { | |
| 89 | + $classes = array_filter( [ (string) ( $item['class'] ?? '' ) ] ); | |
| 90 | + $sortable = ! empty( $item['sortable'] ); | |
| 91 | + $sorted = $sortable && ! empty( $item['sorted'] ); | |
| 92 | + $order = $sorted ? strtolower( (string) ( $item['sort_order'] ?? 'asc' ) ) : ''; | |
| 93 | + if ( ! in_array( $order, [ 'asc', 'desc' ], true ) ) { | |
| 94 | + $order = 'asc'; | |
| 95 | + } | |
| 96 | + | |
| 97 | + if ( $sortable ) { | |
| 98 | + $classes[] = $sorted ? 'sorted' : 'sortable'; | |
| 99 | + if ( $sorted ) { | |
| 100 | + $classes[] = $order; | |
| 101 | + } | |
| 102 | + } | |
| 103 | + | |
| 104 | + $title = wp_kses_post( $item['title'] ?? '' ); | |
| 105 | + $class = implode( ' ', $classes ); | |
| 106 | + | |
| 107 | + if ( ! $sortable ) { | |
| 108 | + return sprintf( | |
| 109 | + '<th scope="col" class="%s">%s</th>', | |
| 110 | + esc_attr( $class ), | |
| 111 | + $title | |
| 112 | + ); | |
| 113 | + } | |
| 114 | + | |
| 115 | + $up_active = $sorted && 'asc' === $order ? ' is-active' : ''; | |
| 116 | + $down_active = $sorted && 'desc' === $order ? ' is-active' : ''; | |
| 117 | + $sort_url = $item['sort_url'] ?? '#'; | |
| 118 | + | |
| 119 | + return sprintf( | |
| 120 | + '<th scope="col" class="%s"> | |
| 121 | + <a href="%s"> | |
| 122 | + <span>%s</span> | |
| 123 | + <span class="sorting-indicator"> | |
| 124 | + <i class="lp-icon-caret-up%4$s"></i> | |
| 125 | + <i class="lp-icon-caret-down%5$s"></i> | |
| 126 | + </span> | |
| 127 | + </a> | |
| 128 | + </th>', | |
| 129 | + esc_attr( $class ), | |
| 130 | + esc_url( $sort_url ), | |
| 131 | + $title, | |
| 132 | + esc_attr( $up_active ), | |
| 133 | + esc_attr( $down_active ) | |
| 134 | + ); | |
| 72 | 135 | } |
| 73 | 136 | |
| 74 | 137 | /** |
| 75 | 138 | * Render the HTML table body. |