PluginProbe
Posts Table with Search & Sort / 1.1.3
Posts Table with Search & Sort v1.1.3
1.4.13 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2 1.3 1.3.1 1.3.1-v2 1.3.2 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 All 40 releases
posts-data-table / includes / class-posts-data-table-simple.php

class-posts-data-table-simple.php in Posts Table with Search & Sort 1.1.3, at includes/class-posts-data-table-simple.php

346 lines 11.1 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 // Prevent direct file access
3 if ( ! defined( 'ABSPATH' ) ) {
4 exit;
5 }
6
7 /**
8 * This class is responsible for generating a HTML table from a list of supplied attributes.
9 *
10 * @package Posts_Table_Search_And_Sort
11 * @author Barn2 Media <info@barn2.co.uk>
12 * @license GPL-3.0
13 * @link https://barn2.co.uk
14 * @copyright 2016-2018 Barn2 Media Ltd
15 */
16 class Posts_Data_Table_Simple {
17
18 /**
19 * The complete list of table attributes, and their defaults.
20 */
21 public static $default_args = array(
22 'columns' => 'title,content,date,author,category',
23 'rows_per_page' => 20,
24 'sort_by' => 'date',
25 'sort_order' => '',
26 'category' => '',
27 'tag' => '',
28 'author' => '',
29 'post_status' => '',
30 'date_format' => 'Y/m/d',
31 'search_on_click' => true,
32 'wrap' => true,
33 'content_length' => 15,
34 'scroll_offset' => 15
35 );
36 /**
37 * An array of all possible columns and their default heading, priority, and column width.
38 * Initialised once on construction.
39 */
40 private static $column_defaults = array();
41 private static $allowed_columns = array();
42 /**
43 * Stores the number of tables on this page. Used to generate the table ID.
44 */
45 private static $table_count = 1;
46
47 public function __construct() {
48 if ( empty( self::$column_defaults ) ) {
49 /**
50 * Priority values are used to determine visiblity at small screen sizes (1 = highest priority, 6 = lowest priority).
51 * Column widths are automatically calculated by DataTables, but can be overridden by using filter 'posts_data_table_column_defaults'.
52 */
53 self::$column_defaults = array(
54 'id' => array(
55 'heading' => __( 'ID', 'posts-data-table' ),
56 'priority' => 3,
57 'width' => ''
58 ),
59 'title' => array(
60 'heading' => __( 'Title', 'posts-data-table' ),
61 'priority' => 1,
62 'width' => ''
63 ),
64 'category' => array(
65 'heading' => __( 'Categories', 'posts-data-table' ),
66 'priority' => 6,
67 'width' => ''
68 ),
69 'tags' => array(
70 'heading' => __( 'Tags', 'posts-data-table' ),
71 'priority' => 7,
72 'width' => ''
73 ),
74 'date' => array(
75 'heading' => __( 'Date', 'posts-data-table' ),
76 'priority' => 2,
77 'width' => ''
78 ),
79 'author' => array(
80 'heading' => __( 'Author', 'posts-data-table' ),
81 'priority' => 4,
82 'width' => ''
83 ),
84 'content' => array(
85 'heading' => __( 'Content', 'posts-data-table' ),
86 'priority' => 5,
87 'width' => ''
88 )
89 );
90 }
91
92 if ( empty( self::$allowed_columns ) ) {
93 self::$allowed_columns = array_keys( self::$column_defaults );
94 }
95 }
96
97 /**
98 * Retrieves a data table containing a list of posts based on the specified arguments.
99 *
100 * @param array $args An array of options used to display the posts table
101 * @return string The posts table HTML output
102 */
103 public function get_table( $args ) {
104
105 $args = wp_parse_args( $args, self::$default_args );
106
107 if ( empty( $args['columns'] ) ) {
108 $args['columns'] = self::$default_args['columns'];
109 }
110
111 $args['rows_per_page'] = filter_var( $args['rows_per_page'], FILTER_VALIDATE_INT );
112
113 if ( ($args['rows_per_page'] < 1) || ! $args['rows_per_page'] ) {
114 $args['rows_per_page'] = false;
115 }
116
117 if ( ! in_array( $args['sort_by'], self::$allowed_columns ) ) {
118 $args['sort_by'] = self::$default_args['sort_by'];
119 }
120
121 if ( ! in_array( $args['sort_order'], array( 'asc', 'desc' ) ) ) {
122 $args['sort_order'] = self::$default_args['sort_order'];
123 }
124
125 // Set default sort direction
126 if ( ! $args['sort_order'] ) {
127 if ( $args['sort_by'] === 'date' ) {
128 $args['sort_order'] = 'desc';
129 } else {
130 $args['sort_order'] = 'asc';
131 }
132 }
133
134 $args['search_on_click'] = filter_var( $args['search_on_click'], FILTER_VALIDATE_BOOLEAN );
135 $args['wrap'] = filter_var( $args['wrap'], FILTER_VALIDATE_BOOLEAN );
136 $args['content_length'] = filter_var( $args['content_length'], FILTER_VALIDATE_INT );
137 $args['scroll_offset'] = filter_var( $args['scroll_offset'], FILTER_VALIDATE_INT );
138
139 if ( empty( $args['date_format'] ) ) {
140 $args['date_format'] = self::$default_args['date_format'];
141 }
142
143 $output = $table_head = $table_body = $body_row_fmt = '';
144
145 // Start building the args needed for our posts query
146 $post_args = array(
147 'post_type' => 'post',
148 'posts_per_page' => apply_filters( 'posts_data_table_post_limit', 1000 ),
149 'post_status' => 'publish',
150 'suppress_filters' => false // Ensure WPML filters run on this query
151 );
152
153 if ( ! empty( $args['category'] ) ) {
154 if ( is_numeric( $args['category'] ) ) {
155 $post_args['cat'] = $args['category'];
156 } else {
157 $category = get_category_by_slug( $args['category'] );
158
159 if ( $category ) {
160 $post_args['category_name'] = $category->slug;
161 }
162 }
163 }
164
165 if ( ! empty( $args['tag'] ) ) {
166 if ( is_numeric( $args['tag'] ) ) {
167 $post_args['tag_id'] = $args['tag'];
168 } else {
169 $post_args['tag'] = $args['tag'];
170 }
171 }
172
173 if ( ! empty( $args['author'] ) ) {
174 $author = $args['author'];
175
176 if ( is_numeric( $author ) || false !== strpos( $author, ',' ) ) {
177 $post_args['author'] = $author;
178 } else {
179 $post_args['author_name'] = $author;
180 }
181 }
182
183 if ( ! empty( $args['post_status'] ) ) {
184 $post_args['post_status'] = $args['post_status'];
185 }
186
187 // Get all published posts in the current language
188 $all_posts = get_posts( apply_filters( 'posts_data_table_query_args', $post_args, $args ) );
189
190 // Bail early if no posts found
191 if ( ! $all_posts || ! is_array( $all_posts ) ) {
192 return $output;
193 }
194
195 // Allow theme/plugins to override defaults
196 $column_defaults = apply_filters( 'posts_data_table_column_defaults_' . self::$table_count, apply_filters( 'posts_data_table_column_defaults', self::$column_defaults ) );
197
198 // Get the columns to be used in this table
199 $columns = array_filter( array_map( 'trim', explode( ',', strtolower( $args['columns'] ) ) ) );
200 $hidden_columns = array();
201
202 // If none of the user-specfied columns are valid, use the default columns instead
203 if ( ! array_intersect( self::$allowed_columns, $columns ) ) {
204 $columns = explode( ',', self::$default_args['columns'] );
205 }
206
207 // Set hidden columns and sort indexes
208 $table_sort_index = array_search( $args['sort_by'], $columns );
209 $date_sort_index = false;
210 $hidden_date = in_array( 'date', $columns ) || 'date' === $args['sort_by'];
211
212 if ( $hidden_date ) {
213 $hidden_columns[] = 'timestamp';
214 $date_sort_index = count( $columns );
215
216 // If we're sorting by date, make sure we use this hidden column for the initial table sort
217 if ( 'date' === $args['sort_by'] && false === $table_sort_index ) {
218 $table_sort_index = $date_sort_index;
219 }
220 }
221
222 if ( false === $table_sort_index ) {
223 // Sort column is not in list of displayed columns so we'll add it as a hidden column at end of table
224 $hidden_columns[] = $args['sort_by'];
225
226 // Set the table sort index to the index of the hidden sort column
227 $table_sort_index = $date_sort_index ? $date_sort_index + 1 : count( $columns );
228 }
229
230 // Build table header
231 $heading_fmt = '<th data-name="%1$s" data-priority="%2$u" data-width="%3$s"%5$s>%4$s</th>';
232 $cell_fmt = '<td>{%s}</td>';
233
234 foreach ( $columns as $column ) {
235 // Double-check column name is valid
236 if ( ! in_array( $column, self::$allowed_columns ) ) {
237 continue;
238 }
239
240 // Do we need to use custom data for ordering this column?
241 $order_data = '';
242
243 if ( 'date' === $column && false !== $date_sort_index ) {
244 $order_data = sprintf( ' data-order-data="%u"', $date_sort_index );
245 }
246
247 // Add heading to table
248 $table_head .= sprintf( $heading_fmt, $column, $column_defaults[$column]['priority'], $column_defaults[$column]['width'], $column_defaults[$column]['heading'], $order_data );
249
250 // Add placeholder to table body format string so that content for this column is included in table output
251 $body_row_fmt .= sprintf( $cell_fmt, $column );
252 }
253
254 foreach ( $hidden_columns as $column ) {
255 $table_head .= sprintf( '<th data-name="%s" data-visible="false"></th>', $column );
256
257 // Make sure data for the hidden column is included in table content
258 $body_row_fmt .= sprintf( $cell_fmt, $column );
259 }
260
261 $table_head = sprintf( '<thead><tr>%s</tr></thead>', $table_head );
262
263 // Build table body
264 $body_row_fmt = '<tr>' . $body_row_fmt . '</tr>';
265
266 // Loop through posts and add a row for each
267 foreach ( (array) $all_posts as $_post ) {
268 setup_postdata( $_post );
269
270 // Format title
271 $title = sprintf( '<a href="%1$s">%2$s</a>', get_permalink( $_post ), get_the_title( $_post ) );
272
273 // Format author
274 $author = sprintf(
275 '<a href="%1$s" title="%2$s" rel="author">%3$s</a>', esc_url( get_author_posts_url( $_post->post_author ) ), esc_attr( sprintf( __( 'Posts by %s', 'posts-data-table' ), get_the_author() ) ), get_the_author()
276 );
277
278 $post_data_trans = apply_filters( 'posts_data_table_row_data_format', array(
279 '{id}' => $_post->ID,
280 '{title}' => $title,
281 '{category}' => get_the_category_list( ', ', '', $_post->ID ),
282 '{tags}' => get_the_tag_list( '', ', ', '', $_post->ID ),
283 '{date}' => get_the_date( $args['date_format'], $_post ),
284 '{author}' => $author,
285 '{content}' => $this->get_post_content( $args['content_length'] ),
286 '{timestamp}' => $_post->post_date
287 ) );
288
289 $table_body .= strtr( $body_row_fmt, $post_data_trans );
290 } // foreach post
291
292 wp_reset_postdata();
293
294 $table_body = sprintf( '<tbody>%s</tbody>', $table_body );
295
296 $paging_attr = 'false';
297 if ( ( $args['rows_per_page'] > 1 ) && ( $args['rows_per_page'] < count( $all_posts ) ) ) {
298 $paging_attr = 'true';
299 }
300
301 // Order attribute should be escaped here rather than in sprintf below as we don't want to escape the double-quotes around "asc" or "desc"
302 $order_attr = ( $table_sort_index === false ) ? '' : sprintf( '[[%u, "%s"]]', esc_attr( $table_sort_index ), esc_attr( $args['sort_order'] ) );
303 $offset_attr = ( $args['scroll_offset'] === false ) ? 'false' : $args['scroll_offset'];
304
305 $table_class = 'posts-data-table';
306 if ( ! $args['wrap'] ) {
307 $table_class .= ' nowrap';
308 }
309
310 $output = sprintf(
311 '<table '
312 . 'id="posts-table-%1$u" '
313 . 'class="%2$s" '
314 . 'data-page-length="%3$u" '
315 . 'data-paging="%4$s" '
316 . 'data-order=\'%5$s\' '
317 . 'data-click-filter="%6$s" '
318 . 'data-scroll-offset="%7$s" '
319 . 'cellspacing="0" width="100%%">'
320 . '%8$s%9$s' .
321 '</table>', self::$table_count, esc_attr( $table_class ), esc_attr( $args['rows_per_page'] ), esc_attr( $paging_attr ), $order_attr, ( $args['search_on_click'] ? 'true' : 'false' ), esc_attr( $offset_attr ), $table_head, $table_body
322 );
323
324 // Increment the table count
325 self::$table_count ++;
326
327 return apply_filters( 'posts_data_table_html_output', $output, $args );
328 }
329
330 /**
331 * Retrieve the post content, truncated to the number of words specified by $num_words.
332 *
333 * Must be called with the Loop or a secondary loop after a call to setup_postdata().
334 *
335 * @param int $num_words The number of words to trim the content to
336 * @return string The (truncated) post content
337 */
338 private function get_post_content( $num_words = 15 ) {
339 $text = get_the_content( '' );
340 $text = strip_shortcodes( $text );
341 $text = apply_filters( 'the_content', $text );
342 $text = wp_trim_words( $text, $num_words, ' &hellip;' );
343 return $text;
344 }
345
346 }