PluginProbe ʕ •ᴥ•ʔ
Post Views Counter / 1.7.2
Post Views Counter v1.7.2
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 5 months ago class-columns.php 5 months ago class-counter.php 5 months ago class-crawler-detect.php 5 months ago class-cron.php 5 months ago class-dashboard.php 5 months ago class-frontend.php 5 months ago class-functions.php 5 months ago class-import.php 5 months ago class-integration-gutenberg.php 5 months ago class-integrations.php 5 months ago class-query.php 5 months ago class-settings-api.php 5 months ago class-settings-display.php 5 months ago class-settings-general.php 5 months ago class-settings-integrations.php 5 months ago class-settings-other.php 5 months ago class-settings-reports.php 5 months ago class-settings.php 5 months ago class-toolbar.php 5 months ago class-update.php 5 months ago class-widgets.php 5 months ago functions.php 5 months ago
functions.php
867 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 $query = apply_filters( 'pvc_get_views_query_sql', $query, $args, $views_query );
473
474 // get cached data
475 $post_views = wp_cache_get( md5( $query ), 'pvc-get_views' );
476
477 // cached data not found?
478 if ( $post_views === false ) {
479 if ( $args['fields'] === 'date=>views' && ! empty( $range ) ) {
480 $results = $wpdb->get_results( $query );
481
482 if ( ! empty( $results ) ) {
483 foreach ( $results as $row ) {
484 $range[$row->period] = (int) $row->post_views;
485 }
486 }
487
488 $post_views = $range;
489 } else
490 $post_views = (int) $wpdb->get_var( $query );
491
492 // set the cache expiration, 5 minutes by default
493 $expire = absint( apply_filters( 'pvc_object_cache_expire', 300 ) );
494
495 wp_cache_add( md5( $query ), $post_views, 'pvc-get_views', $expire );
496 }
497
498 return apply_filters( 'pvc_get_views', $post_views );
499 }
500 }
501
502 /**
503 * Display post views for a given post.
504 *
505 * @param int $post_id
506 * @param bool $display
507 *
508 * @return string|void
509 */
510 if ( ! function_exists( 'pvc_post_views' ) ) {
511 function pvc_post_views( $post_id = 0, $display = true, $period = '' ) {
512 // get all data
513 $post_id = (int) ( empty( $post_id ) ? get_the_ID() : $post_id );
514
515 // get display options
516 $options = Post_Views_Counter()->options['display'];
517
518 // get post views
519 $views = pvc_get_post_views( $post_id, $period !== '' ? $period : $options['display_period'] );
520
521 // use number format?
522 $views = $options['use_format'] ? number_format_i18n( $views ) : $views;
523
524 // container class
525 $class = apply_filters( 'pvc_post_views_class', 'post-views content-post post-' . $post_id . ' entry-meta', $post_id );
526
527 // dynamic loading?
528 $class .= $options['dynamic_loading'] === true ? ' load-dynamic' : ' load-static';
529
530 // prepare display
531 $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 );
532
533 // add dashicons class if needed
534 $icon_class = strpos( $options['icon_class'], 'dashicons' ) === false ? $options['icon_class'] : 'dashicons ' . $options['icon_class'];
535
536 // prepare icon output
537 $icon = apply_filters( 'pvc_post_views_icon', '<span class="post-views-icon ' . esc_attr( $icon_class ) . '"></span> ', $post_id );
538
539 // final views
540 $views = apply_filters( 'pvc_post_views_number_format', $views, $post_id );
541
542 $html = apply_filters(
543 'pvc_post_views_html',
544 '<div class="' . esc_attr( $class ) . '">
545 ' . ( $options['display_style']['icon'] ? $icon : '' )
546 . ( $options['display_style']['text'] ? '<span class="post-views-label">' . esc_html( $label ) . '</span> ' : '' )
547 . '<span class="post-views-count">' . $views . '</span>
548 </div>',
549 $post_id,
550 $views,
551 $label,
552 $icon
553 );
554
555 if ( $display )
556 echo $html;
557 else
558 return $html;
559 }
560 }
561
562 /**
563 * Get most viewed posts.
564 *
565 * @param array $args
566 *
567 * @return array
568 */
569 if ( ! function_exists( 'pvc_get_most_viewed_posts' ) ) {
570 function pvc_get_most_viewed_posts( $args = [] ) {
571 $args = array_merge(
572 [
573 'posts_per_page' => 10,
574 'order' => 'desc',
575 'post_type' => [ 'post' ],
576 'post_status' => [ 'publish' ],
577 'fields' => 'all',
578 'period' => 'total'
579 ],
580 $args
581 );
582
583 if ( ( is_array( $args['post_type'] ) && in_array( 'attachment', $args['post_type'], true ) ) || ( is_string( $args['post_type'] ) && $args['post_type'] === 'attachment' ) )
584 $args['post_status'][] = 'inherit';
585
586 $args = apply_filters( 'pvc_get_most_viewed_posts_args', $args );
587
588 // force to use filters
589 $args['suppress_filters'] = false;
590
591 // force to use post views as order
592 $args['orderby'] = 'post_views';
593
594 return apply_filters( 'pvc_get_most_viewed_posts', get_posts( $args ), $args );
595 }
596 }
597
598 /**
599 * Display a list of most viewed posts.
600 *
601 * @param array $args
602 * @param bool $display
603 *
604 * @return void|string
605 */
606 if ( ! function_exists( 'pvc_most_viewed_posts' ) ) {
607 function pvc_most_viewed_posts( $args = [], $display = true ) {
608 $defaults = [
609 'number_of_posts' => 5,
610 'post_type' => [ 'post' ],
611 'order' => 'desc',
612 'thumbnail_size' => 'thumbnail',
613 'list_type' => 'unordered',
614 'show_post_views' => true,
615 'show_post_thumbnail' => false,
616 'show_post_author' => false,
617 'show_post_excerpt' => false,
618 'no_posts_message' => __( 'No most viewed posts found.', 'post-views-counter' ),
619 'item_before' => '',
620 'item_after' => '',
621 'period' => 'total'
622 ];
623
624 $args = apply_filters( 'pvc_most_viewed_posts_args', wp_parse_args( $args, $defaults ) );
625
626 // get periods
627 $periods = apply_filters( 'pvc_display_period_options', [ 'total' => __( 'Total Views', 'post-views-counter' ) ] );
628
629 // sanitize arguments
630 $args['show_post_views'] = (bool) $args['show_post_views'];
631 $args['show_post_thumbnail'] = (bool) $args['show_post_thumbnail'];
632 $args['show_post_author'] = (bool) $args['show_post_author'];
633 $args['show_post_excerpt'] = (bool) $args['show_post_excerpt'];
634 $args['period'] = isset( $args['period'] ) && array_key_exists( $args['period'], $periods ) ? $args['period'] : $defaults['period'];
635 $args['post_type'] = isset( $args['post_type'] ) ? $args['post_type'] : $defaults['post_type'];
636
637 // no post types?
638 if ( empty( $args['post_type'] ) )
639 $html = $args['no_posts_message'];
640 else {
641 // get posts
642 $posts = pvc_get_most_viewed_posts( [
643 'posts_per_page' => isset( $args['number_of_posts'] ) ? (int) $args['number_of_posts'] : $defaults['number_of_posts'],
644 'order' => isset( $args['order'] ) ? $args['order'] : $defaults['order'],
645 'post_type' => $args['post_type'],
646 'period' => $args['period']
647 ] );
648
649 if ( ! empty( $posts ) ) {
650 $html = ( $args['list_type'] === 'unordered' ? '<ul>' : '<ol>' );
651
652 foreach ( $posts as $post ) {
653 setup_postdata( $post );
654
655 $html .= '<li>';
656 $html .= apply_filters( 'pvc_most_viewed_posts_item_before', $args['item_before'], $post );
657
658 if ( $args['show_post_thumbnail'] && has_post_thumbnail( $post->ID ) ) {
659 $html .= '<span class="post-thumbnail">' . get_the_post_thumbnail( $post->ID, $args['thumbnail_size'] ) . '</span>';
660 }
661
662 $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>' : '' );
663
664 if ( $args['show_post_excerpt'] ) {
665 $excerpt = '';
666
667 if ( empty( $post->post_excerpt ) )
668 $text = $post->post_content;
669 else
670 $text = $post->post_excerpt;
671
672 if ( ! empty( $text ) )
673 $excerpt = wp_trim_words( str_replace( ']]>', ']]&gt;', strip_shortcodes( $text ) ), apply_filters( 'excerpt_length', 55 ), apply_filters( 'excerpt_more', ' ' . '[&hellip;]' ) );
674
675 if ( ! empty( $excerpt ) )
676 $html .= '<div class="post-excerpt">' . esc_html( $excerpt ) . '</div>';
677 }
678
679 $html .= apply_filters( 'pvc_most_viewed_posts_item_after', $args['item_after'], $post );
680 $html .= '</li>';
681 }
682
683 wp_reset_postdata();
684
685 $html .= ( $args['list_type'] === 'unordered' ? '</ul>' : '</ol>' );
686 } else
687 $html = $args['no_posts_message'];
688 }
689
690 $html = apply_filters( 'pvc_most_viewed_posts_html', $html, $args );
691
692 if ( $display )
693 echo $html;
694 else
695 return $html;
696 }
697 }
698
699 /**
700 * Update total number of post views for a post.
701 *
702 * @global object $wpdb
703 *
704 * @param int $post_id
705 * @param int $post_views
706 *
707 * @return bool|int
708 */
709 function pvc_update_post_views( $post_id = 0, $post_views = 0 ) {
710 global $wpdb;
711
712 // cast post ID
713 $post_id = (int) $post_id;
714
715 // get post
716 $post = get_post( $post_id );
717
718 // check if post exists
719 if ( empty( $post ) )
720 return false;
721
722 // cast number of views
723 $post_views = (int) $post_views;
724 $post_views = $post_views < 0 ? 0 : $post_views;
725
726 // change post views?
727 $post_views = apply_filters( 'pvc_update_post_views_count', $post_views, $post_id );
728
729 // insert or update database post views count
730 $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 ) );
731
732 // query fails only if it returns false
733 return apply_filters( 'pvc_update_post_views', $post_id );
734 }
735
736 /**
737 * View post manually function.
738 *
739 * By default this function has limitations. It works properly only between
740 * wp_loaded (minimum priority 10) and wp_head (maximum priority 6) actions and
741 * it can handle only one function execution per site request.
742 *
743 * To bypass these limitations there is a $bypass_content argument. It requires
744 * JavaScript or REST API as counter mode but it extends the ability to use
745 * pvc_view_post up to wp_print_footer_scripts (maximum priority 10) action. It
746 * also bypass one function execution limitation to allow multiple function
747 * calls during one site request. This also includes the correct saving of
748 * cookies.
749 *
750 * @since 1.2.0
751 *
752 * @param int $post_id
753 * @param bool $bypass_content
754 *
755 * @return bool
756 */
757 function pvc_view_post( $post_id = 0, $bypass_content = false ) {
758 // no post id?
759 if ( empty( $post_id ) ) {
760 // get current id
761 $post_id = get_the_ID();
762 } else {
763 // cast post id
764 $post_id = (int) $post_id;
765 }
766
767 // get post
768 $post = get_post( $post_id );
769
770 // invalid post?
771 if ( ! is_a( $post, 'WP_Post' ) )
772 return false;
773
774 // get main instance
775 $pvc = Post_Views_Counter();
776
777 if ( $bypass_content )
778 $pvc->counter->add_to_queue( $post_id );
779 else
780 $pvc->counter->check_post( $post_id );
781
782 return true;
783 }
784
785 /**
786 * Convert string to date.
787 *
788 * @param string $period
789 * @return DateTiem object
790 */
791 if ( ! function_exists( 'pvc_period2date' ) ) {
792 function pvc_period2date( $period ) {
793 $datetime = false;
794
795 // check requested period by string length
796 $length = is_string( $period ) ? strlen( $period ) : 0;
797
798 if ( $length ) {
799 switch ( $length ) {
800 // day
801 case 8:
802 $datetime = date_create_from_format( 'Ymd' , $period );
803 break;
804
805 // week
806 case 7:
807 // get year and week from string
808 $period_year = (int) substr( $period, 0, -3 );
809 $period_week = (int) substr( $period, 4, -1 );
810
811 $datetime = new DateTime();
812 $datetime->setISODate( $period_year, $period_week );
813 break;
814
815 // month
816 case 6:
817 $datetime = date_create_from_format( 'Ym' , $period );
818 break;
819 // year
820 case 4:
821 $datetime = date_create_from_format( 'Y' , $period );
822 break;
823
824 default:
825 $datetime = new DateTime();
826 }
827 }
828
829 return apply_filters( 'pvc_period2date', $datetime, $period );
830 }
831 }
832
833 /**
834 * Convert period to timestamp.
835 *
836 * @param string $period
837 * @return int
838 */
839 if ( ! function_exists( 'pvc_period2timestamp' ) ) {
840 function pvc_period2timestamp( $period ) {
841 $period = preg_replace( '/[^a-z0-9_|]/', '', $period );
842
843 // default time
844 $timestamp = current_time( 'timestamp', false );
845
846 // whitelisted period?
847 if ( in_array( $period, [ 'this_week', 'this_year', 'this_month' ], true ) ) {
848 $timestamp = current_time( 'timestamp', false );
849 // backward compatibility
850 } else if ( preg_match( '/^([0-9]{2}\|[0-9]{4})$/', $period ) === 1 ) {
851 // month|year
852 $date = explode( '|', $period, 2 );
853
854 // get timestamp
855 $timestamp = strtotime( (string) $date[1] . '-' . (string) $date[0] . '-13' );
856 } else {
857 // convert string to DateTime()
858 $d = pvc_period2date( $period );
859
860 if ( $d ) {
861 $timestamp = $d->getTimestamp();
862 }
863 }
864
865 return $timestamp;
866 }
867 }