PluginProbe
Posts Table with Search & Sort / 1.0.5
Posts Table with Search & Sort v1.0.5
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 1.3.8 All 39 releases
posts-data-table / posts-data-table.php

posts-data-table.php in Posts Table with Search & Sort 1.0.5, at posts-data-table.php

373 lines 15.7 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * The main plugin file for Posts Table with Search & Sort.
4 *
5 * @package Posts_Data_Table
6 * @author Andrew Keith <andy@barn2.co.uk>
7 * @license GPL-2.0+
8 * @link http://barn2.co.uk
9 * @copyright 2016 Barn2 Media
10 *
11 * @wordpress-plugin
12 * Plugin Name: Posts Table with Search & Sort
13 * Description: This plugin provides a shortcode to show a list of your site's posts in a searchable and sortable table.
14 * Version: 1.0.5
15 * Author: Barn2 Media
16 * Author URI: http://barn2.co.uk
17 * Text Domain: posts-data-table
18 * Domain Path: /languages
19 * License: GPL-2.0+
20 * License URI: http://www.gnu.org/licenses/gpl-2.0.txt
21 */
22
23 // Prevent direct file access
24 if ( ! defined ( 'ABSPATH' ) ) {
25 exit;
26 }
27
28 // Current version of this plugin
29 define( 'POSTS_DATA_TABLE_VERSION', '1.0.5' );
30
31 class Posts_Data_Table_Plugin {
32
33 private $shortcode = 'posts_data_table';
34
35 private $shortcode_defaults = array(
36 'columns' => 'title,content,date,author,category',
37 'rows_per_page' => 20,
38 'sort_by' => 'date',
39 'sort_order' => '',
40 'category' => '',
41 'search_on_click' => true,
42 'wrap' => true,
43 'content_length' => 15,
44 'scroll_offset' => 15
45 );
46
47 private $table_count = 1;
48
49 public function __construct() {
50 add_action( 'plugins_loaded', array( $this, 'init' ) );
51 add_filter( 'plugin_action_links_' . plugin_basename( __FILE__ ), array( $this, 'add_plugin_settings_link' ) );
52 }
53
54 public function init() {
55 // Don't init plugin if Pro version exists
56 if ( !class_exists( 'Posts_Table_Pro_Plugin' ) ) {
57 // Load the text domain - should go on 'plugins_loaded' hook
58 $this->load_textdomain();
59
60 // Register shortcode
61 add_shortcode( $this->shortcode, array( $this, 'shortcode' ) );
62
63 // Register styles and scripts
64 add_action( 'wp_enqueue_scripts', array( $this, 'register_styles' ) );
65 add_action( 'wp_enqueue_scripts', array( $this, 'register_scripts' ) );
66 }
67 }
68
69 public function load_textdomain() {
70 load_plugin_textdomain( 'posts-data-table', false, dirname( plugin_basename( __FILE__ ) ) . '/languages' );
71 }
72
73 public function register_styles() {
74 wp_enqueue_style( 'jquery-data-tables', plugins_url( 'assets/css/datatables.min.css', __FILE__ ), array(), '1.10.12' );
75 wp_enqueue_style( 'posts-data-table', plugins_url( 'assets/css/posts-data-table.min.css', __FILE__ ), array( 'jquery-data-tables' ), POSTS_DATA_TABLE_VERSION );
76 //wp_enqueue_style( 'posts-data-table', plugins_url( 'assets/css/posts-data-table.css', __FILE__ ), array( 'jquery-data-tables' ), POSTS_DATA_TABLE_VERSION );
77 }
78
79 public function register_scripts() {
80 wp_enqueue_script( 'jquery-data-tables', plugins_url( 'assets/js/datatables.min.js', __FILE__ ), array( 'jquery' ), '1.10.12', true );
81 wp_enqueue_script( 'posts-data-table', plugins_url( 'assets/js/posts-data-table.min.js', __FILE__ ), array( 'jquery-data-tables' ), POSTS_DATA_TABLE_VERSION, true );
82 //wp_enqueue_script( 'posts-data-table', plugins_url( 'assets/js/posts-data-table.js', __FILE__ ), array( 'jquery-data-tables' ), POSTS_DATA_TABLE_VERSION, true );
83
84 $locale = get_locale();
85 $supported_locales = $this->get_supported_locales();
86
87 // Add language file to script if locale is supported (English file is not added as this is the default language)
88 if ( array_key_exists( $locale, $supported_locales ) ) {
89 wp_localize_script( 'posts-data-table', 'posts_data_table', array(
90 'langurl' => $supported_locales[$locale]
91 ) );
92 }
93 }
94
95 public function add_plugin_settings_link( $links ) {
96 $links[] = sprintf( '<a href="%1$s" target="_blank">%2$s</a>', esc_url( 'https://barn2.co.uk/wordpress-products/posts-table-pro/'), __( 'Pro Version', 'posts-data-table' ) );
97 return $links;
98 }
99
100 /**
101 * Handles our posts data table shortcode.
102 *
103 * @param array $atts The attributes passed in to the shortcode
104 * @param string $content The content passed to the shortcode (not used)
105 * @return string The shortcode output
106 */
107 public function shortcode( $atts, $content = '' ) {
108 $atts = shortcode_atts( $this->shortcode_defaults, $atts, $this->shortcode );
109 return $this->get_posts_data_table( $atts );
110 }
111
112 /**
113 * Returns an array of locales supported by the plugin.
114 * The array returned uses the locale as the array key mapped to the URL of the corresponding translation file.
115 *
116 * @return array The supported locales
117 */
118 private function get_supported_locales() {
119 $lang_file_base_url = plugins_url( 'languages/data-tables/', __FILE__ );
120
121 return array(
122 'es_ES' => $lang_file_base_url . 'Spanish.json',
123 'fr_FR' => $lang_file_base_url . 'French.json',
124 'de_DE' => $lang_file_base_url . 'German.json',
125 );
126 }
127
128 /**
129 * Retrieves a data table containing a list of posts based on the specified arguments.
130 *
131 * @param array $args An array of options used to display the posts table
132 * @return string The posts table HTML output
133 */
134 private function get_posts_data_table( $args ) {
135
136 if ( empty( $args['columns'] ) ) {
137 $args['columns'] = $this->shortcode_defaults['columns'];
138 }
139
140 $args['rows_per_page'] = filter_var( $args['rows_per_page'], FILTER_VALIDATE_INT );
141 if ( ($args['rows_per_page'] < 1) || !$args['rows_per_page'] ) {
142 $args['rows_per_page'] = false;
143 }
144
145 if ( !in_array( $args['sort_by'], array('id', 'title', 'category', 'date', 'author', 'content') ) ) {
146 $args['sort_by'] = $this->shortcode_defaults['sort_by'];
147 }
148
149 if ( !in_array( $args['sort_order'], array('asc', 'desc') ) ) {
150 $args['sort_order'] = $this->shortcode_defaults['sort_order'];
151 }
152
153 // Set default sort direction
154 if ( !$args['sort_order'] ) {
155 if ( $args['sort_by'] === 'date' ) {
156 $args['sort_order'] = 'desc';
157 } else {
158 $args['sort_order'] = 'asc';
159 }
160 }
161
162 $args['search_on_click'] = filter_var( $args['search_on_click'], FILTER_VALIDATE_BOOLEAN );
163 $args['wrap'] = filter_var( $args['wrap'], FILTER_VALIDATE_BOOLEAN );
164 $args['content_length'] = filter_var( $args['content_length'], FILTER_VALIDATE_INT );
165 $args['scroll_offset'] = filter_var( $args['scroll_offset'], FILTER_VALIDATE_INT );
166
167 $date_format = 'Y/m/d';
168 $output = $table_head = $table_body = $body_row_fmt = '';
169
170 // Start building the args needed for our posts query
171 $post_args = array(
172 'post_type' => 'post',
173 'posts_per_page' => -1,
174 'post_status' => 'publish',
175 'suppress_filters' => false // Ensure WPML filters run on this query
176 );
177
178 if ( $args['category'] ) {
179 $category = get_category_by_slug( $args['category'] );
180
181 if ( $category ) {
182 $post_args['category_name'] = $category->slug;
183 }
184 }
185
186 // Get all published posts in the current language
187 $all_posts_curr_lang = get_posts( $post_args );
188
189 if ( is_array( $all_posts_curr_lang ) && $all_posts_curr_lang ) { // if we have posts
190
191 /**
192 * Define an array of all possible columns and their default heading, priority, and column width.
193 *
194 * Priority values are used to determine visiblity at small screen sizes (1 = highest priority, 6 = lowest priority).
195 * Column widths are automatically calculated by DataTables, but can be overridden by using filter 'posts_data_table_column_defaults'.
196 */
197 $column_defaults = array(
198 'id' => array(
199 'heading' => __('ID', 'posts-data-table'),
200 'priority' => 3,
201 'width' => ''
202 ),
203 'title' => array(
204 'heading' => __('Title', 'posts-data-table'),
205 'priority' => 1,
206 'width' => ''
207 ),
208 'category' => array(
209 'heading' => __('Categories', 'posts-data-table'),
210 'priority' => 6,
211 'width' => ''
212 ),
213 'date' => array(
214 'heading' => __('Date', 'posts-data-table'),
215 'priority' => 2,
216 'width' => ''
217 ),
218 'author' => array(
219 'heading' => __('Author', 'posts-data-table'),
220 'priority' => 4,
221 'width' => ''
222 ),
223 'content' => array(
224 'heading' => __('Content', 'posts-data-table'),
225 'priority' => 5,
226 'width' => ''
227 ),
228 );
229
230 $all_columns = array_keys( $column_defaults );
231
232 // Allow users to override defaults
233 $column_defaults = apply_filters( 'posts_data_table_column_defaults', $column_defaults );
234 $column_defaults = apply_filters( 'posts_data_table_column_defaults_' . $this->table_count, $column_defaults );
235
236 // Get the columns to be used in this table
237 $columns = array_map( 'trim', explode( ',', strtolower( $args['columns'] ) ) );
238
239 // If none of the user-specfied columns are valid, use the default columns instead
240 if ( !array_intersect( $all_columns, $columns ) ) {
241 $columns = explode( ',', $this->shortcode_defaults['columns'] );
242 }
243
244 // Build table header
245 $heading_fmt = '<th data-name="%1$s" data-priority="%2$u" data-width="%3$s">%4$s</th>';
246 $cell_fmt = '<td>%s</td>';
247
248 foreach( $columns as $column ) {
249
250 if ( array_key_exists( $column, $column_defaults ) ) { // Double-check column name is valid
251
252 // Add heading to table
253 $table_head .= sprintf( $heading_fmt, $column, $column_defaults[$column]['priority'], $column_defaults[$column]['width'], $column_defaults[$column]['heading'] );
254
255 // Add placeholder to table body format string so that content for this column is included in table output
256 $body_row_fmt .= sprintf($cell_fmt, '{' . $column . '}');
257 }
258 }
259
260 $sort_column = $args['sort_by'];
261 $sort_index = array_search( $sort_column, $columns );
262
263 if ( $sort_index === false && array_key_exists( $sort_column, $column_defaults ) ) {
264 // Sort column is not in list of displayed columns so we'll add it as a hidden column at end of table
265 $table_head .= sprintf( '<th data-name="%1$s" data-visible="false">%2$s</th>', $sort_column, $column_defaults[$sort_column]['heading'] );
266
267 // Make sure data for this column is included in table content
268 $body_row_fmt .= sprintf($cell_fmt, $sort_column);
269
270 // Set the sort column index to be this hidden column
271 $sort_index = count($columns);
272 }
273
274 $table_head = sprintf( '<thead><tr>%s</tr></thead>', $table_head );
275 // end table header
276
277 // Build table body
278 $body_row_fmt = '<tr>' . $body_row_fmt . '</tr>';
279
280 // Loop through posts and add a row for each
281 foreach ( (array) $all_posts_curr_lang as $_post ) {
282 setup_postdata( $_post );
283
284 // Format title
285 $title = sprintf( '<a href="%1$s">%2$s</a>', get_permalink($_post), get_the_title( $_post ) );
286
287 // Format author
288 $author = sprintf(
289 '<a href="%1$s" title="%2$s" rel="author">%3$s</a>',
290 esc_url( get_author_posts_url( $_post->post_author ) ),
291 esc_attr( sprintf( __( 'Posts by %s' ), get_the_author() ) ),
292 get_the_author()
293 );
294
295 $post_data_trans = array(
296 '{id}' => $_post->ID,
297 '{title}' => $title,
298 '{category}' => get_the_category_list( ', ', '', $_post->ID ),
299 '{date}' => get_the_date( $date_format, $_post ),
300 '{author}' => $author,
301 '{content}' => $this->get_post_content( $args['content_length'] )
302 );
303
304 $table_body .= strtr( $body_row_fmt, $post_data_trans );
305
306 } // foreach post
307
308 wp_reset_postdata();
309
310 $table_body = sprintf( '<tbody>%s</tbody>', $table_body );
311 // end table body
312
313 $paging_attr = 'false';
314 if ( ( $args['rows_per_page'] > 1 ) && ( $args['rows_per_page'] < count($all_posts_curr_lang) ) ) {
315 $paging_attr = 'true';
316 }
317
318 $order_attr = ( $sort_index === false ) ? '' : sprintf( '[[%u, "%s"]]', $sort_index, $args['sort_order'] );
319 $offset_attr = ( $args['scroll_offset'] === false ) ? 'false' : $args['scroll_offset'];
320
321 $table_class = 'posts-data-table';
322 if ( !$args['wrap'] ) {
323 $table_class .= ' nowrap';
324 }
325
326 $output = sprintf(
327 '<table '
328 . 'id="posts-table-%1$u" '
329 . 'class="%2$s" '
330 . 'data-page-length="%3$u" '
331 . 'data-paging="%4$s" '
332 . 'data-order=\'%5$s\' '
333 . 'data-click-filter="%6$s" '
334 . 'data-scroll-offset="%7$s" '
335 . 'cellspacing="0" width="100%%">'
336 . '%8$s%9$s' .
337 '</table>',
338 $this->table_count,
339 esc_attr( $table_class ),
340 esc_attr( $args['rows_per_page'] ),
341 esc_attr( $paging_attr ),
342 esc_attr( $order_attr ),
343 ( $args['search_on_click'] ? 'true' : 'false' ),
344 esc_attr( $offset_attr ),
345 $table_head,
346 $table_body
347 );
348
349 $this->table_count++;
350 } // if posts found
351
352 return $output;
353 } // get_comments_list
354
355 /**
356 * Retrieve the post content, truncated to the number of words specified by $num_words.
357 *
358 * Must be called with the Loop or a secondary loop after a call to setup_postdata().
359 *
360 * @param int $num_words The number of words to trim the content to
361 * @return string The (truncated) post content
362 */
363 private function get_post_content( $num_words = 15 ) {
364 $text = get_the_content('');
365 $text = strip_shortcodes( $text );
366 $text = apply_filters( 'the_content', $text );
367 $text = wp_trim_words( $text, $num_words, ' &hellip;' );
368 return $text;
369 }
370
371 } // end class
372
373 $posts_data_table = new Posts_Data_Table_Plugin();