PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.5.7
Post Views Counter v1.5.7
1.7.13 1.7.12 1.7.11 trunk 1.0.0 1.0.1 1.0.10 1.0.11 1.0.12 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.0.9 1.1.0 1.1.1 1.1.2 1.1.3 1.1.4 1.2.0 1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3 1.3.1 1.3.10 1.3.11 1.3.12 1.3.13 1.3.2 1.3.2.1 1.3.3 1.3.4 1.3.5 1.3.6 1.3.7 1.3.8 1.3.9 1.4 1.4.1 1.4.2 1.4.3 1.4.4 1.4.5 1.4.6 1.4.7 1.4.8 1.5.0 1.5.1 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.7.0 1.7.1 1.7.10 1.7.2 1.7.3 1.7.4 1.7.5 1.7.6 1.7.7 1.7.8 1.7.9
post-views-counter / includes / functions.php
post-views-counter / includes Last commit date
class-admin.php 8 months ago class-columns.php 8 months ago class-counter.php 8 months ago class-crawler-detect.php 8 months ago class-cron.php 8 months ago class-dashboard.php 8 months ago class-frontend.php 8 months ago class-functions.php 8 months ago class-query.php 8 months ago class-settings-api.php 8 months ago class-settings.php 8 months ago class-update.php 8 months ago class-widgets.php 8 months ago functions.php 8 months ago
functions.php
865 lines
1 <?php
2 /**
3 * Post Views Counter pluggable template functions
4 *
5 * Override any of those functions by copying it to your theme or replace it via plugin
6 *
7 * @author Digital Factory
8 * @package Post Views Counter
9 * @since 1.0.0
10 */
11 // exit if accessed directly
12 if ( ! defined( 'ABSPATH' ) )
13 exit;
14
15 /**
16 * Get post views for a post or array of posts.
17 *
18 * @global object $wpdb
19 *
20 * @param int|array $post_id
21 * @param string $period
22 *
23 * @return int
24 */
25 if ( ! function_exists( 'pvc_get_post_views' ) ) {
26 function pvc_get_post_views( $post_id = 0, $period = 'total' ) {
27 global $wpdb;
28
29 // sanitize period
30 $period = sanitize_key( $period );
31
32 if ( empty( $post_id ) )
33 $post_id = get_the_ID();
34
35 if ( is_array( $post_id ) ) {
36 $numbers = array_filter( array_unique( array_map( 'intval', $post_id ) ) );
37 $post_id = implode( ',', $numbers );
38 } else if ( $post_id === 'all' ) {
39 $numbers = [];
40 } else {
41 $post_id = (int) $post_id;
42 $numbers = [ $post_id ];
43 }
44
45 // set where clause
46 $where = [ 'type' => 'type = 4' ];
47
48 // update where clause
49 $where = apply_filters( 'pvc_get_post_views_period_where', $where, $period, $post_id );
50
51 // updated where clause
52 $_where = [];
53
54 // sanitize where clause
55 foreach ( $where as $index => $value ) {
56 if ( $index === 'type' || $index === 'content' )
57 $_where[$index] = preg_replace( '/[^0-9]/', '', $value );
58 elseif ( $index === 'period' ) {
59 $values = preg_match_all( '/\d+/', $value, $matches );
60
61 // any values?
62 if ( $values !== false && $values > 0 )
63 $_where['period'] = $matches[0];
64 }
65 }
66
67 // get current number of ids
68 $ids_count = count( $numbers );
69
70 $where_clause = '';
71
72 // add post ids if needed
73 if ( $ids_count ) {
74 $where_clause .= " WHERE id IN (" . implode( ',', array_fill( 0, $ids_count, '%d' ) ) . ") AND";
75 } else {
76 $where_clause .= " WHERE";
77 }
78
79 // validate where clause
80 foreach( $_where as $index => $value ) {
81 if ( $index === 'type' ) {
82 $where_clause .= ' type = %d';
83 $numbers[] = (int) $value;
84 } elseif ( $index === 'content' ) {
85 $where_clause .= ' AND content = %d';
86 $numbers[] = (int) $value;
87 } elseif ( $index === 'period' ) {
88 $nop = count( $_where['period'] );
89
90 if ( $nop === 1 ) {
91 $where_clause .= ' AND CAST( period AS SIGNED ) = %d';
92 $numbers[] = (int) $_where['period'][0];
93 } elseif ( $nop === 2 ) {
94 $where_clause .= ' AND CAST( period AS SIGNED ) <= %d AND CAST( period AS SIGNED ) >= %d';
95 $numbers[] = (int) $_where['period'][0];
96 $numbers[] = (int) $_where['period'][1];
97 }
98 }
99 }
100
101 // prepare query
102 $query = $wpdb->prepare( "SELECT SUM(count) AS views FROM " . $wpdb->prefix . "post_views" . $where_clause, $numbers );
103
104 // calculate query hash
105 $query_hash = md5( $query );
106
107 // get cached data
108 $post_views = wp_cache_get( $query_hash, 'pvc-get_post_views' );
109
110 // cached data not found?
111 if ( $post_views === false ) {
112 // get post views
113 $post_views = (int) $wpdb->get_var( $query );
114
115 // set the cache expiration, 5 minutes by default
116 $expire = absint( apply_filters( 'pvc_object_cache_expire', 300 ) );
117
118 // add cached post views
119 wp_cache_add( $query_hash, $post_views, 'pvc-get_post_views', $expire );
120 }
121
122 return (int) apply_filters( 'pvc_get_post_views', $post_views, $post_id, $period );
123 }
124 }
125
126 /**
127 * Get views query.
128 *
129 * @global object $wpdb
130 *
131 * @param array $args
132 *
133 * @return int|array
134 */
135 if ( ! function_exists( 'pvc_get_views' ) ) {
136 function pvc_get_views( $args = [] ) {
137 global $wpdb;
138
139 $range = [];
140 $defaults = [
141 'fields' => 'views',
142 'post_id' => '',
143 'post_type' => '',
144 'views_query' => [
145 'year' => '',
146 'month' => '',
147 'week' => '',
148 'day' => '',
149 'after' => '', // string or array
150 'before' => '', // string or array
151 'inclusive' => true
152 ]
153 ];
154
155 // merge default options with new arguments
156 $args = array_merge( $defaults, $args );
157
158 // check views query
159 if ( ! is_array( $args['views_query'] ) )
160 $args['views_query'] = $defaults['views_query'];
161
162 // merge views query too
163 $args['views_query'] = array_merge( $defaults['views_query'], $args['views_query'] );
164
165 // filter arguments
166 $args = apply_filters( 'pvc_get_views_args', $args );
167
168 // check post types
169 if ( is_string( $args['post_type'] ) )
170 $args['post_type'] = [ $args['post_type'] ];
171 elseif ( ! is_array( $args['post_type'] ) )
172 $args['post_type'] = [];
173
174 // get number of post types
175 $post_types_count = count( $args['post_type'] );
176
177 // check post ids
178 if ( is_array( $args['post_id'] ) && ! empty( $args['post_id'] ) )
179 $args['post_id'] = array_filter( array_unique( array_map( 'intval', $args['post_id'] ) ) );
180 elseif ( is_string( $args['post_id'] ) || is_numeric( $args['post_id'] ) ) {
181 $post_id = (int) $args['post_id'];
182
183 if ( $post_id === 0 )
184 $args['post_id'] = [];
185 else
186 $args['post_id'] = [ $post_id ];
187 } else
188 $args['post_id'] = [];
189
190 // get number of post ids
191 $post_ids_count = count( $args['post_id'] );
192
193 // placeholder for empty query data
194 $query_data = [ 1 ];
195
196 // set query data
197 if ( $post_ids_count === 0 && $post_types_count === 0 )
198 $query_data = [ 1 ];
199 elseif ( $post_ids_count === 0 )
200 $query_data = array_merge( $query_data, array_values( $args['post_type'] ) );
201 elseif ( $post_types_count === 0 )
202 $query_data = array_merge( $query_data, array_values( $args['post_id'] ) );
203 else
204 $query_data = array_merge( $query_data, array_values( $args['post_id'] ), array_values( $args['post_type'] ) );
205
206 // set where clause
207 $where = apply_filters( 'pvc_get_views_period_where', [], $args );
208
209 // check fields
210 if ( ! in_array( $args['fields'], [ 'views', 'date=>views' ], true ) )
211 $args['fields'] = $defaults['fields'];
212
213 $query_chunks = [];
214 $views_query = '';
215
216 // views query after/before parameters work only when fields == views
217 if ( $args['fields'] === 'views' ) {
218 // check views query inclusive
219 if ( ! isset( $args['views_query']['inclusive'] ) )
220 $args['views_query']['inclusive'] = $defaults['views_query']['inclusive'];
221 else
222 $args['views_query']['inclusive'] = (bool) $args['views_query']['inclusive'];
223
224 // check after and before dates
225 foreach ( [ 'after' => '>', 'before' => '<' ] as $date => $type ) {
226 $year_ = null;
227 $month_ = null;
228 $week_ = null;
229 $day_ = null;
230
231 // check views query date
232 if ( ! empty( $args['views_query'][$date] ) ) {
233 // is it a date array?
234 if ( is_array( $args['views_query'][$date] ) ) {
235 // check views query $date date year
236 if ( ! empty( $args['views_query'][$date]['year'] ) )
237 $year_ = str_pad( (int) $args['views_query'][$date]['year'], 4, 0, STR_PAD_LEFT );
238
239 // check views query date month
240 if ( ! empty( $args['views_query'][$date]['month'] ) )
241 $month_ = str_pad( (int) $args['views_query'][$date]['month'], 2, 0, STR_PAD_LEFT );
242
243 // check views query date week
244 if ( ! empty( $args['views_query'][$date]['week'] ) )
245 $week_ = str_pad( (int) $args['views_query'][$date]['week'], 2, 0, STR_PAD_LEFT );
246
247 // check views query date day
248 if ( ! empty( $args['views_query'][$date]['day'] ) )
249 $day_ = str_pad( (int) $args['views_query'][$date]['day'], 2, 0, STR_PAD_LEFT );
250 // is it a date string?
251 } elseif ( is_string( $args['views_query'][$date] ) ) {
252 $time_ = strtotime( $args['views_query'][$date] );
253
254 // valid datetime?
255 if ( $time_ !== false ) {
256 // week does not exists here, string dates are always treated as year + month + day
257 list( $day_, $month_, $year_ ) = explode( ' ', date( "d m Y", $time_ ) );
258 }
259 }
260
261 // valid date?
262 if ( ! ( $year_ === null && $month_ === null && $week_ === null && $day_ === null ) ) {
263 $query_chunks[] = [
264 'year' => $year_,
265 'month' => $month_,
266 'day' => $day_,
267 'week' => $week_,
268 'type' => $type . ( $args['views_query']['inclusive'] ? '=' : '' )
269 ];
270 }
271 }
272 }
273
274 if ( ! empty( $query_chunks ) ) {
275 $valid_dates = true;
276
277 // after and before?
278 if ( count( $query_chunks ) === 2 ) {
279 // before and after dates should be the same
280 foreach ( [ 'year', 'month', 'day', 'week' ] as $date_type ) {
281 if ( ! ( ( $query_chunks[0][$date_type] !== null && $query_chunks[1][$date_type] !== null ) || ( $query_chunks[0][$date_type] === null && $query_chunks[1][$date_type] === null ) ) )
282 $valid_dates = false;
283 }
284 }
285
286 if ( $valid_dates ) {
287 foreach ( $query_chunks as $chunk ) {
288 // year
289 if ( isset( $chunk['year'] ) ) {
290 // year, week
291 if ( isset( $chunk['week'] ) ) {
292 $where['type'] = 'pvc.type = 1';
293 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['year'] . $chunk['week'] );
294 }
295 // year, month
296 elseif ( isset( $chunk['month'] ) ) {
297 // year, month, day
298 if ( isset( $chunk['day'] ) ) {
299 $where['type'] = 'pvc.type = 0';
300 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['year'] . $chunk['month'] . $chunk['day'] );
301 }
302 // year, month
303 else {
304 $where['type'] = 'pvc.type = 2';
305 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['year'] . $chunk['month'] );
306 }
307 // year
308 } else {
309 $where['type'] = 'pvc.type = 3';
310 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['year'] );
311 }
312 // month
313 } elseif ( isset( $chunk['month'] ) ) {
314 // month, day
315 if ( isset( $chunk['day'] ) ) {
316 $where['type'] = 'pvc.type = 0';
317 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 4 ) AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['month'] . $chunk['day'] );
318 // month
319 } else {
320 $where['type'] = 'pvc.type = 2';
321 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['month'] );
322 }
323 // week
324 } elseif ( isset( $chunk['week'] ) ) {
325 $where['type'] = 'pvc.type = 1';
326 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['week'] );
327 }
328 // day
329 elseif ( isset( $chunk['day'] ) ) {
330 $where['type'] = 'pvc.type = 0';
331 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) " . $chunk['type'] . " " . (int) ( $chunk['day'] );
332 }
333 }
334 }
335 }
336 }
337
338 $special_views_query = ( $views_query !== '' );
339
340 if ( $args['fields'] === 'date=>views' || $views_query === '' ) {
341 // check views query year
342 if ( ! empty( $args['views_query']['year'] ) )
343 $year = str_pad( (int) $args['views_query']['year'], 4, 0, STR_PAD_LEFT );
344
345 // check views query month
346 if ( ! empty( $args['views_query']['month'] ) )
347 $month = str_pad( (int) $args['views_query']['month'], 2, 0, STR_PAD_LEFT );
348
349 // check views query week
350 if ( ! empty( $args['views_query']['week'] ) )
351 $week = str_pad( (int) $args['views_query']['week'], 2, 0, STR_PAD_LEFT );
352
353 // check views query day
354 if ( ! empty( $args['views_query']['day'] ) )
355 $day = str_pad( (int) $args['views_query']['day'], 2, 0, STR_PAD_LEFT );
356
357 // year
358 if ( isset( $year ) ) {
359 // year, week
360 if ( isset( $week ) ) {
361 if ( $args['fields'] === 'date=>views' ) {
362 // create date based on week number
363 $date = new DateTime( $year . 'W' . $week );
364
365 // get monday
366 $monday = $date->format( 'd' );
367
368 // get month of monday
369 $monday_month = $date->format( 'm' );
370
371 // prepare range
372 for( $i = 1; $i <= 6; $i++ ) {
373 $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
374
375 $date->modify( '+1days' );
376 }
377
378 $range[(string) ( $date->format( 'Y' ) . $date->format( 'm' ) . $date->format( 'd' ) )] = 0;
379
380 // get month of sunday
381 $sunday_month = $date->format( 'm' );
382
383 $where['type'] = 'pvc.type = 0';
384 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year . $monday_month . $monday ) . " AND CAST( pvc.period AS SIGNED ) <= " . (int) ( $date->format( 'Y' ) . $sunday_month . $date->format( 'd' ) );
385 } else {
386 $where['type'] = 'pvc.type = 1';
387 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int) ( $year . $week );
388 }
389 // year, month
390 } elseif ( isset( $month ) ) {
391 // year, month, day
392 if ( isset( $day ) ) {
393 if ( $args['fields'] === 'date=>views' )
394 // prepare range
395 $range[(string) ( $year . $month . $day )] = 0;
396
397 $where['type'] = 'pvc.type = 0';
398 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int) ( $year . $month . $day );
399 // year, month
400 } else {
401 if ( $args['fields'] === 'date=>views' ) {
402 // create date
403 $date = new DateTime( $year . '-' . $month . '-01' );
404
405 // get last day
406 $last = $date->format( 't' );
407
408 // prepare range
409 for( $i = 1; $i <= $last; $i++ ) {
410 $range[(string) ( $year . $month . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
411 }
412
413 $where['type'] = 'pvc.type = 0';
414 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year . $month ) . "01 AND CAST( pvc.period AS SIGNED ) <= " . (int) ( $year . $month . $last );
415 } else {
416 $where['type'] = 'pvc.type = 2';
417 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int) ( $year . $month );
418 }
419 }
420 // year
421 } else {
422 if ( $args['fields'] === 'date=>views' ) {
423 // prepare range
424 for( $i = 1; $i <= 12; $i++ ) {
425 $range[(string) ( $year . str_pad( $i, 2, 0, STR_PAD_LEFT ) )] = 0;
426 }
427
428 // create date
429 $date = new DateTime( $year . '-12-01' );
430
431 $where['type'] = 'pvc.type = 2';
432 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) >= " . (int) ( $year ) . "01 AND CAST( pvc.period AS SIGNED ) <= " . (int) ( $year ) . "12";
433 } else {
434 $where['type'] = 'pvc.type = 3';
435 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( pvc.period AS SIGNED ) = " . (int) ( $year );
436 }
437 }
438 // month
439 } elseif ( isset( $month ) ) {
440 // month, day
441 if ( isset( $day ) ) {
442 $where['type'] = 'pvc.type = 0';
443 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 4 ) AS SIGNED ) = " . (int) ( $month . $day );
444 // month
445 } else {
446 $where['type'] = 'pvc.type = 2';
447 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) = " . (int) ( $month );
448 }
449 // week
450 } elseif ( isset( $week ) ) {
451 $where['type'] = 'pvc.type = 1';
452 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) = " . (int) ( $week );
453 // day
454 } elseif ( isset( $day ) ) {
455 $where['type'] = 'pvc.type = 0';
456 $views_query .= ' AND ' . implode( ' AND ', $where ) . " AND CAST( RIGHT( pvc.period, 2 ) AS SIGNED ) = " . (int) ( $day );
457 }
458 }
459
460 // update where clause
461 $where['type'] = [ 'pvc.type = 4' ];
462
463 $query = $wpdb->prepare(
464 "SELECT " . ( $args['fields'] === 'date=>views' ? 'pvc.period, ' : '' ) . "SUM( COALESCE( pvc.count, 0 ) ) AS post_views
465 FROM " . $wpdb->prefix . "posts wpp
466 LEFT JOIN " . $wpdb->prefix . "post_views pvc ON pvc.id = wpp.ID AND 1 = %d" . ( $views_query !== '' ? ' ' . $views_query : ' AND ' . implode( ' AND ', $where ) ) . ( ! empty( $args['post_id'] ) ? ' AND pvc.id IN (' . implode( ',', array_fill( 0, $post_ids_count, '%d' ) ) . ')' : '' ) . "
467 " . ( ! empty( $args['post_type'] ) ? 'WHERE wpp.post_type IN (' . implode( ',', array_fill( 0, $post_types_count, '%s' ) ) . ')' : '' ) . "
468 " . ( $views_query !== '' && $special_views_query === false ? 'GROUP BY pvc.period HAVING post_views > 0' : '' ),
469 $query_data
470 );
471
472 // get cached data
473 $post_views = wp_cache_get( md5( $query ), 'pvc-get_views' );
474
475 // cached data not found?
476 if ( $post_views === false ) {
477 if ( $args['fields'] === 'date=>views' && ! empty( $range ) ) {
478 $results = $wpdb->get_results( $query );
479
480 if ( ! empty( $results ) ) {
481 foreach ( $results as $row ) {
482 $range[$row->period] = (int) $row->post_views;
483 }
484 }
485
486 $post_views = $range;
487 } else
488 $post_views = (int) $wpdb->get_var( $query );
489
490 // set the cache expiration, 5 minutes by default
491 $expire = absint( apply_filters( 'pvc_object_cache_expire', 300 ) );
492
493 wp_cache_add( md5( $query ), $post_views, 'pvc-get_views', $expire );
494 }
495
496 return apply_filters( 'pvc_get_views', $post_views );
497 }
498 }
499
500 /**
501 * Display post views for a given post.
502 *
503 * @param int $post_id
504 * @param bool $display
505 *
506 * @return string|void
507 */
508 if ( ! function_exists( 'pvc_post_views' ) ) {
509 function pvc_post_views( $post_id = 0, $display = true, $period = '' ) {
510 // get all data
511 $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
512
513 // get display options
514 $options = Post_Views_Counter()->options['display'];
515
516 // get post views
517 $views = pvc_get_post_views( $post_id, $period !== '' ? $period : $options['display_period'] );
518
519 // use number format?
520 $views = $options['use_format'] ? number_format_i18n( $views ) : $views;
521
522 // container class
523 $class = apply_filters( 'pvc_post_views_class', 'post-views content-post post-' . $post_id . ' entry-meta', $post_id );
524
525 // dynamic loading?
526 $class .= $options['dynamic_loading'] === true ? ' load-dynamic' : ' load-static';
527
528 // prepare display
529 $label = apply_filters( 'pvc_post_views_label', ( function_exists( 'icl_t' ) ? icl_t( 'Post Views Counter', 'Post Views Label', $options['label'] ) : $options['label'] ), $post_id );
530
531 // add dashicons class if needed
532 $icon_class = strpos( $options['icon_class'], 'dashicons' ) === false ? $options['icon_class'] : 'dashicons ' . $options['icon_class'];
533
534 // prepare icon output
535 $icon = apply_filters( 'pvc_post_views_icon', '<span class="post-views-icon ' . esc_attr( $icon_class ) . '"></span> ', $post_id );
536
537 // final views
538 $views = apply_filters( 'pvc_post_views_number_format', $views, $post_id );
539
540 $html = apply_filters(
541 'pvc_post_views_html',
542 '<div class="' . esc_attr( $class ) . '">
543 ' . ( $options['display_style']['icon'] ? $icon : '' )
544 . ( $options['display_style']['text'] ? '<span class="post-views-label">' . esc_html( $label ) . '</span> ' : '' )
545 . '<span class="post-views-count">' . $views . '</span>
546 </div>',
547 $post_id,
548 $views,
549 $label,
550 $icon
551 );
552
553 if ( $display )
554 echo $html;
555 else
556 return $html;
557 }
558 }
559
560 /**
561 * Get most viewed posts.
562 *
563 * @param array $args
564 *
565 * @return array
566 */
567 if ( ! function_exists( 'pvc_get_most_viewed_posts' ) ) {
568 function pvc_get_most_viewed_posts( $args = [] ) {
569 $args = array_merge(
570 [
571 'posts_per_page' => 10,
572 'order' => 'desc',
573 'post_type' => [ 'post' ],
574 'post_status' => [ 'publish' ],
575 'fields' => 'all',
576 'period' => 'total'
577 ],
578 $args
579 );
580
581 if ( ( is_array( $args['post_type'] ) && in_array( 'attachment', $args['post_type'], true ) ) || ( is_string( $args['post_type'] ) && $args['post_type'] === 'attachment' ) )
582 $args['post_status'][] = 'inherit';
583
584 $args = apply_filters( 'pvc_get_most_viewed_posts_args', $args );
585
586 // force to use filters
587 $args['suppress_filters'] = false;
588
589 // force to use post views as order
590 $args['orderby'] = 'post_views';
591
592 return apply_filters( 'pvc_get_most_viewed_posts', get_posts( $args ), $args );
593 }
594 }
595
596 /**
597 * Display a list of most viewed posts.
598 *
599 * @param array $args
600 * @param bool $display
601 *
602 * @return void|string
603 */
604 if ( ! function_exists( 'pvc_most_viewed_posts' ) ) {
605 function pvc_most_viewed_posts( $args = [], $display = true ) {
606 $defaults = [
607 'number_of_posts' => 5,
608 'post_type' => [ 'post' ],
609 'order' => 'desc',
610 'thumbnail_size' => 'thumbnail',
611 'list_type' => 'unordered',
612 'show_post_views' => true,
613 'show_post_thumbnail' => false,
614 'show_post_author' => false,
615 'show_post_excerpt' => false,
616 'no_posts_message' => __( 'No most viewed posts found.', 'post-views-counter' ),
617 'item_before' => '',
618 'item_after' => '',
619 'period' => 'total'
620 ];
621
622 $args = apply_filters( 'pvc_most_viewed_posts_args', wp_parse_args( $args, $defaults ) );
623
624 // get periods
625 $periods = apply_filters( 'pvc_display_period_options', [ 'total' => __( 'Total Views', 'post-views-counter' ) ] );
626
627 // sanitize arguments
628 $args['show_post_views'] = (bool) $args['show_post_views'];
629 $args['show_post_thumbnail'] = (bool) $args['show_post_thumbnail'];
630 $args['show_post_author'] = (bool) $args['show_post_author'];
631 $args['show_post_excerpt'] = (bool) $args['show_post_excerpt'];
632 $args['period'] = isset( $args['period'] ) && array_key_exists( $args['period'], $periods ) ? $args['period'] : $defaults['period'];
633 $args['post_type'] = isset( $args['post_type'] ) ? $args['post_type'] : $defaults['post_type'];
634
635 // no post types?
636 if ( empty( $args['post_type'] ) )
637 $html = $args['no_posts_message'];
638 else {
639 // get posts
640 $posts = pvc_get_most_viewed_posts( [
641 'posts_per_page' => isset( $args['number_of_posts'] ) ? (int) $args['number_of_posts'] : $defaults['number_of_posts'],
642 'order' => isset( $args['order'] ) ? $args['order'] : $defaults['order'],
643 'post_type' => $args['post_type'],
644 'period' => $args['period']
645 ] );
646
647 if ( ! empty( $posts ) ) {
648 $html = ( $args['list_type'] === 'unordered' ? '<ul>' : '<ol>' );
649
650 foreach ( $posts as $post ) {
651 setup_postdata( $post );
652
653 $html .= '<li>';
654 $html .= apply_filters( 'pvc_most_viewed_posts_item_before', $args['item_before'], $post );
655
656 if ( $args['show_post_thumbnail'] && has_post_thumbnail( $post->ID ) ) {
657 $html .= '<span class="post-thumbnail">' . get_the_post_thumbnail( $post->ID, $args['thumbnail_size'] ) . '</span>';
658 }
659
660 $html .= '<a class="post-title" href="' . get_permalink( $post->ID ) . '">' . get_the_title( $post->ID ) . '</a>' . ( $args['show_post_author'] ? ' <span class="author">(' . get_the_author_meta( 'display_name', $post->post_author ) . ')</span> ' : '' ) . ( $args['show_post_views'] ? ' <span class="count">(' . number_format_i18n( (int) ( property_exists( $post, 'post_views' ) ? $post->post_views : pvc_get_post_views( $post->ID, $args['period'] ) ) ) . ')</span>' : '' );
661
662 if ( $args['show_post_excerpt'] ) {
663 $excerpt = '';
664
665 if ( empty( $post->post_excerpt ) )
666 $text = $post->post_content;
667 else
668 $text = $post->post_excerpt;
669
670 if ( ! empty( $text ) )
671 $excerpt = wp_trim_words( str_replace( ']]>', ']]&gt;', strip_shortcodes( $text ) ), apply_filters( 'excerpt_length', 55 ), apply_filters( 'excerpt_more', ' ' . '[&hellip;]' ) );
672
673 if ( ! empty( $excerpt ) )
674 $html .= '<div class="post-excerpt">' . esc_html( $excerpt ) . '</div>';
675 }
676
677 $html .= apply_filters( 'pvc_most_viewed_posts_item_after', $args['item_after'], $post );
678 $html .= '</li>';
679 }
680
681 wp_reset_postdata();
682
683 $html .= ( $args['list_type'] === 'unordered' ? '</ul>' : '</ol>' );
684 } else
685 $html = $args['no_posts_message'];
686 }
687
688 $html = apply_filters( 'pvc_most_viewed_posts_html', $html, $args );
689
690 if ( $display )
691 echo $html;
692 else
693 return $html;
694 }
695 }
696
697 /**
698 * Update total number of post views for a post.
699 *
700 * @global object $wpdb
701 *
702 * @param int $post_id
703 * @param int $post_views
704 *
705 * @return bool|int
706 */
707 function pvc_update_post_views( $post_id = 0, $post_views = 0 ) {
708 global $wpdb;
709
710 // cast post ID
711 $post_id = (int) $post_id;
712
713 // get post
714 $post = get_post( $post_id );
715
716 // check if post exists
717 if ( empty( $post ) )
718 return false;
719
720 // cast number of views
721 $post_views = (int) $post_views;
722 $post_views = $post_views < 0 ? 0 : $post_views;
723
724 // change post views?
725 $post_views = apply_filters( 'pvc_update_post_views_count', $post_views, $post_id );
726
727 // insert or update database post views count
728 $wpdb->query( $wpdb->prepare( "INSERT INTO " . $wpdb->prefix . "post_views (id, type, period, count) VALUES (%d, %d, %s, %d) ON DUPLICATE KEY UPDATE count = %d", $post_id, 4, 'total', $post_views, $post_views ) );
729
730 // query fails only if it returns false
731 return apply_filters( 'pvc_update_post_views', $post_id );
732 }
733
734 /**
735 * View post manually function.
736 *
737 * By default this function has limitations. It works properly only between
738 * wp_loaded (minimum priority 10) and wp_head (maximum priority 6) actions and
739 * it can handle only one function execution per site request.
740 *
741 * To bypass these limitations there is a $bypass_content argument. It requires
742 * JavaScript or REST API as counter mode but it extends the ability to use
743 * pvc_view_post up to wp_print_footer_scripts (maximum priority 10) action. It
744 * also bypass one function execution limitation to allow multiple function
745 * calls during one site request. This also includes the correct saving of
746 * cookies.
747 *
748 * @since 1.2.0
749 *
750 * @param int $post_id
751 * @param bool $bypass_content
752 *
753 * @return bool
754 */
755 function pvc_view_post( $post_id = 0, $bypass_content = false ) {
756 // no post id?
757 if ( empty( $post_id ) ) {
758 // get current id
759 $post_id = get_the_ID();
760 } else {
761 // cast post id
762 $post_id = (int) $post_id;
763 }
764
765 // get post
766 $post = get_post( $post_id );
767
768 // invalid post?
769 if ( ! is_a( $post, 'WP_Post' ) )
770 return false;
771
772 // get main instance
773 $pvc = Post_Views_Counter();
774
775 if ( $bypass_content )
776 $pvc->counter->add_to_queue( $post_id );
777 else
778 $pvc->counter->check_post( $post_id );
779
780 return true;
781 }
782
783 /**
784 * Convert string to date.
785 *
786 * @param string $period
787 * @return DateTiem object
788 */
789 if ( ! function_exists( 'pvc_period2date' ) ) {
790 function pvc_period2date( $period ) {
791 $datetime = false;
792
793 // check requested period by string length
794 $length = is_string( $period ) ? strlen( $period ) : 0;
795
796 if ( $length ) {
797 switch ( $length ) {
798 // day
799 case 8:
800 $datetime = date_create_from_format( 'Ymd' , $period );
801 break;
802
803 // week
804 case 7:
805 // get year and week from string
806 $period_year = (int) substr( $period, 0, -3 );
807 $period_week = (int) substr( $period, 4, -1 );
808
809 $datetime = new DateTime();
810 $datetime->setISODate( $period_year, $period_week );
811 break;
812
813 // month
814 case 6:
815 $datetime = date_create_from_format( 'Ym' , $period );
816 break;
817 // year
818 case 4:
819 $datetime = date_create_from_format( 'Y' , $period );
820 break;
821
822 default:
823 $datetime = new DateTime();
824 }
825 }
826
827 return apply_filters( 'pvc_period2date', $datetime, $period );
828 }
829 }
830
831 /**
832 * Convert period to timestamp.
833 *
834 * @param string $period
835 * @return int
836 */
837 if ( ! function_exists( 'pvc_period2timestamp' ) ) {
838 function pvc_period2timestamp( $period ) {
839 $period = preg_replace( '/[^a-z0-9_|]/', '', $period );
840
841 // default time
842 $timestamp = current_time( 'timestamp', false );
843
844 // whitelisted period?
845 if ( in_array( $period, [ 'this_week', 'this_year', 'this_month' ], true ) ) {
846 $timestamp = current_time( 'timestamp', false );
847 // backward compatibility
848 } else if ( preg_match( '/^([0-9]{2}\|[0-9]{4})$/', $period ) === 1 ) {
849 // month|year
850 $date = explode( '|', $period, 2 );
851
852 // get timestamp
853 $timestamp = strtotime( (string) $date[1] . '-' . (string) $date[0] . '-13' );
854 } else {
855 // convert string to DateTime()
856 $d = pvc_period2date( $period );
857
858 if ( $d ) {
859 $timestamp = $d->getTimestamp();
860 }
861 }
862
863 return $timestamp;
864 }
865 }