PluginProbe
WebberZone Top 10 — Popular Posts / 4.5.1
WebberZone Top 10 — Popular Posts v4.5.1
4.5.1 4.5.0 4.4.3 4.4.2 4.4.1 4.4.0 4.3.4 4.3.3 4.3.2 4.3.1 4.3.0 trunk 1.0 1.0.1 1.1 1.2 1.3 1.4 1.4.1 1.5 1.5.1 1.5.2 1.5.3 1.6 1.6.1 All 117 releases
top-10 / includes / frontend / class-display.php

class-display.php in WebberZone Top 10 — Popular Posts 4.5.1, at includes/frontend/class-display.php

1,268 lines 38.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Display class.
4 *
5 * @package WebberZone\Top_Ten\Frontend
6 */
7
8 namespace WebberZone\Top_Ten\Frontend;
9
10 use WebberZone\Top_Ten\Database;
11 use WebberZone\Top_Ten\Util\Helpers;
12
13 if ( ! defined( 'WPINC' ) ) {
14 die;
15 }
16
17 /**
18 * Display class
19 *
20 * @since 3.3.0
21 */
22 class Display {
23
24 /**
25 * Constructor class.
26 *
27 * @since 3.3.0
28 */
29 public function __construct() {
30 }
31
32 /**
33 * Function to return formatted list of popular posts.
34 *
35 * @since 3.3.0
36 *
37 * @param mixed $args Arguments array.
38 * @return string HTML output of the popular posts.
39 */
40 public static function pop_posts( $args ) {
41 global $tptn_settings, $post;
42
43 $defaults = array(
44 'daily' => false,
45 'instance_id' => 1,
46 'is_widget' => false,
47 'is_shortcode' => false,
48 'is_manual' => false,
49 'is_block' => false,
50 'echo' => false,
51 'strict_limit' => false,
52 'heading' => 1,
53 'offset' => 0,
54 'extra_class' => '',
55 );
56
57 // Merge the $defaults array with the $tptn_settings array.
58 $defaults = array_merge( $defaults, \tptn_settings_defaults(), $tptn_settings );
59
60 // Parse incomming $args into an array and merge it with $defaults.
61 $args = wp_parse_args( $args, $defaults );
62
63 // Sanitize the attributes.
64 $args = Helpers::sanitize_args( $args );
65
66 // Short circuit flag.
67 $short_circuit = false;
68
69 /**
70 * Allow a short circuit flag to be set to exit at this stage. Set to true to exit.
71 *
72 * @since 4.0.0
73 *
74 * @param bool $short_circuit Short circuit filter.
75 * @param array $args Arguments array.
76 * @param \WP_Post $post Current Post object.
77 */
78 $short_circuit = apply_filters( 'get_tptn_short_circuit', $short_circuit, $args, $post );
79
80 if ( $short_circuit ) {
81 return ''; // Exit without adding popular posts.
82 }
83
84 $output = '';
85
86 /**
87 * Fires before the output processing begins.
88 *
89 * @since 3.1.0
90 *
91 * @param string $output Formatted list of top posts.
92 * @param array $args Array of arguments.
93 * @param \WP_Post $post Current Post object.
94 */
95 do_action( 'pre_tptn_pop_posts', $output, $args, $post );
96
97 // Check exclusions.
98 if ( self::exclude_on( $post, $args ) ) {
99 return '';
100 }
101
102 /**
103 * Pre-filter the popular posts output.
104 *
105 * Return a non-null value to short-circuit the default rendering, e.g. to
106 * replace it with a lazy load placeholder. Runs for all display methods.
107 *
108 * @since 4.4.0
109 *
110 * @param string|null $pre Pre-rendered output. Default null.
111 * @param array $args Fully parsed arguments array.
112 * @param \WP_Post|null $post Current post object.
113 */
114 $pre = apply_filters( 'tptn_pre_pop_posts', null, $args, $post );
115 if ( null !== $pre ) {
116 return (string) $pre;
117 }
118
119 // Check if the cache is enabled and if the output exists. If so, return the output.
120 if ( $args['cache'] ) {
121 $cache_name = \WebberZone\Top_Ten\Util\Cache::get_key( $args );
122
123 $output = get_transient( $cache_name );
124
125 if ( false !== $output ) {
126
127 /**
128 * Filter the output
129 *
130 * @since 1.9.8.5
131 *
132 * @param string $output Formatted list of top posts
133 * @param array $args Array of arguments
134 */
135 return apply_filters( 'tptn_pop_posts', $output, $args );
136 }
137 }
138
139 // Get thumbnail size.
140 list( $args['thumb_width'], $args['thumb_height'] ) = Media_Handler::get_thumb_size( $args['thumb_size'] );
141
142 // Retrieve the popular posts.
143 $results = self::get_posts( $args );
144
145 $counter = 0;
146
147 // Override tptn_styles if post_thumb_op is text_only.
148 $args['tptn_styles'] = ( 'text_only' === $args['post_thumb_op'] ) ? 'text_only' : $args['tptn_styles'];
149 $style_array = Styles_Handler::get_style( $args['tptn_styles'] );
150
151 $post_classes = array(
152 'main' => $args['daily'] ? 'tptn_posts_daily ' : 'tptn_posts ',
153 'widget' => $args['is_widget'] ? 'tptn_posts_widget tptn_posts_widget-' . $args['instance_id'] : '',
154 'shortcode' => $args['is_shortcode'] ? 'tptn_posts_shortcode' : '',
155 'block' => $args['is_block'] ? 'tptn_posts_block' : '',
156 'extra_class' => $args['extra_class'],
157 'style' => ! empty( $style_array['name'] ) ? str_replace( '-pro', '', 'tptn-' . $style_array['name'] ) : '',
158 );
159 $post_classes = join( ' ', $post_classes );
160
161 /**
162 * Filter the classes added to the div wrapper of the Top 10.
163 *
164 * @since 2.1.0
165 *
166 * @param string $post_classes Post classes string.
167 */
168 $post_classes = apply_filters( 'tptn_post_class', $post_classes );
169
170 $output .= '<div class="' . $post_classes . '">';
171
172 if ( $results ) {
173
174 $output .= self::heading_title( $args );
175
176 $output .= self::before_list( $args );
177
178 foreach ( $results as $result ) {
179 $switched_blog = false;
180 if ( is_multisite() && ! empty( $result->blog_id ) && (int) get_current_blog_id() !== (int) $result->blog_id ) {
181 add_action( 'switch_blog', 'wz_switch_site_rewrite' );
182 switch_to_blog( $result->blog_id );
183 $switched_blog = true;
184 }
185
186 // Store the count. We'll need this later.
187 $count = $args['daily'] ? 'daily' : 'total';
188 $visits = empty( $result->visits ) ? \WebberZone\Top_Ten\Counter::get_post_count_only( $result->ID, $count ) : (int) $result->visits;
189
190 $result = get_post( $result );
191
192 $output .= self::before_list_item( $args, $result );
193
194 $output .= self::list_link( $args, $result );
195
196 if ( $args['show_author'] ) {
197 $output .= self::get_the_author( $args, $result );
198 }
199
200 if ( $args['show_date'] ) {
201 $output .= '<span class="tptn_date"> ' . self::get_the_date( $args, $result ) . '</span> ';
202 }
203
204 if ( $args['show_excerpt'] ) {
205 $output .= '<span class="tptn_excerpt"> ' . self::get_the_excerpt( $result->ID, $args['excerpt_length'] ) . '</span>';
206 }
207
208 if ( $args['disp_list_count'] ) {
209
210 $output .= ' <span class="tptn_list_count">' . self::get_list_count( $args, $result, $visits ) . '</span>';
211 }
212
213 if ( ! empty( $args['show_ratings'] ) ) {
214 $output .= self::get_the_ratings( $args, $result );
215 }
216
217 $tptn_list = '';
218 /**
219 * Filter to add content to the end of each item in the list.
220 *
221 * @since 3.3.0
222 *
223 * @param string $tptn_list Empty string at the end of each list item.
224 * @param object $result Object of the current post result
225 * @param array $args Array of arguments
226 */
227 $output .= apply_filters( 'tptn_list', $tptn_list, $result, $args );
228
229 // Opening span created in tptn_list_link().
230 if ( 'inline' === $args['post_thumb_op'] || 'text_only' === $args['post_thumb_op'] ) {
231 $output .= '</span>';
232 }
233
234 $output .= self::after_list_item( $args, $result );
235
236 ++$counter;
237
238 if ( $counter === (int) $args['limit'] ) {
239 break; // End loop when popular posts limit is reached.
240 }
241
242 if ( $switched_blog ) {
243 restore_current_blog();
244 remove_action( 'switch_blog', 'wz_switch_site_rewrite' );
245 }
246 }
247 if ( $args['show_credit'] ) {
248
249 $output .= self::before_list_item( $args, $result );
250
251 $output .= sprintf(
252 /* translators: 1. Top 10 plugin page link, 2. Link attributes. */
253 __( 'Popular posts by <a href="%1$s" rel="nofollow" %2$s>Top 10 plugin</a>', 'top-10' ),
254 esc_url( 'https://webberzone.com/plugins/top-10/' ),
255 self::link_attributes( $args, $result )
256 );
257
258 $output .= self::after_list_item( $args, $result );
259 }
260
261 $output .= self::after_list( $args );
262
263 $clearfix = '<div class="tptn_clear"></div>';
264
265 /**
266 * Filter the clearfix div tag. This is included after the closing tag to clear any miscellaneous floating elements;
267 *
268 * @since 3.3.0
269 *
270 * @param string $clearfix Contains: <div style="clear:both"></div>
271 */
272 $output .= apply_filters( 'tptn_clearfix', $clearfix );
273
274 } else {
275 $output .= ( $args['blank_output'] ) ? '' : $args['blank_output_text'];
276 }
277 $output .= '</div>';
278
279 // Check if the cache is enabled and if the output exists. If so, return the output.
280 if ( $args['cache'] ) {
281 /**
282 * Filter the cache time which allows a function to override this
283 *
284 * @since 3.3.0
285 *
286 * @param int $cache_time Cache time in seconds
287 * @param array $args Array of all the arguments
288 */
289 $cache_time = apply_filters( 'tptn_cache_time', $args['cache_time'], $args );
290
291 $output .= "<br /><!-- Cached output. Cached time is {$cache_time} seconds -->";
292
293 set_transient( $cache_name, $output, $cache_time );
294 }
295
296 /**
297 * Filter already documented in top-10.php
298 */
299 return apply_filters( 'tptn_pop_posts', $output, $args );
300 }
301
302
303 /**
304 * Function to retrieve the popular posts.
305 *
306 * @since 3.3.0
307 *
308 * @param mixed $args Arguments list.
309 */
310 public static function get_pop_posts( $args = array() ) {
311 global $wpdb, $tptn_settings;
312
313 // Initialise some variables.
314 $fields = array();
315 $where = '';
316 $join = '';
317 $groupby = '';
318 $orderby = '';
319 $limits = '';
320
321 $defaults = array(
322 'daily' => false,
323 'strict_limit' => true,
324 'posts_only' => false,
325 'offset' => 0,
326 );
327
328 // Merge the $defaults array with the $tptn_settings array.
329 $defaults = array_merge( $defaults, \tptn_settings_defaults(), $tptn_settings );
330
331 // Parse incomming $args into an array and merge it with $defaults.
332 $args = wp_parse_args( $args, $defaults );
333
334 $table_name = Database::get_table( $args['daily'] );
335
336 $limit = ( $args['strict_limit'] ) ? $args['limit'] : ( $args['limit'] * 5 );
337 $offset = isset( $args['offset'] ) ? $args['offset'] : 0;
338
339 // If post_types is empty or contains a query string then use parse_str else consider it comma-separated.
340 if ( ! empty( $args['post_types'] ) && is_array( $args['post_types'] ) ) {
341 $post_types = $args['post_types'];
342 } elseif ( ! empty( $args['post_types'] ) && false === strpos( $args['post_types'], '=' ) ) {
343 $post_types = explode( ',', $args['post_types'] );
344 } else {
345 parse_str( $args['post_types'], $post_types ); // Save post types in $post_types variable.
346 }
347
348 // If post_types is empty or if we want all the post types.
349 if ( empty( $post_types ) || 'all' === $args['post_types'] ) {
350 $post_types = get_post_types(
351 array(
352 'public' => true,
353 )
354 );
355 }
356
357 $blog_id = get_current_blog_id();
358
359 $from_date = Helpers::get_from_date( null, $args['daily_range'], $args['hour_range'] );
360
361 /**
362 *
363 * We're going to create a mySQL query that is fully extendable which would look something like this:
364 * "SELECT $fields FROM $wpdb->posts $join WHERE 1=1 $where $groupby $orderby $limits"
365 */
366
367 // Fields to return.
368 $fields[] = "{$table_name}.postnumber";
369 $fields[] = ( $args['daily'] ) ? "SUM({$table_name}.cntaccess) as visits" : "{$table_name}.cntaccess as visits";
370 $fields[] = "{$wpdb->posts}.ID";
371
372 $fields = implode( ', ', $fields );
373
374 // Create the JOIN clause.
375 $join = " INNER JOIN {$wpdb->posts} ON {$table_name}.postnumber={$wpdb->posts}.ID ";
376
377 // Create the base WHERE clause.
378 $where .= $wpdb->prepare( " AND {$table_name}.blog_id = %d ", $blog_id ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
379 $where .= " AND ({$wpdb->posts}.post_status = 'publish' OR {$wpdb->posts}.post_status = 'inherit') "; // Show published posts and attachments.
380
381 if ( $args['daily'] ) {
382 $where .= $wpdb->prepare( " AND {$table_name}.dp_date >= %s ", $from_date ); // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
383 }
384
385 // Convert exclude post IDs string to array so it can be filtered.
386 $exclude_post_ids = explode( ',', $args['exclude_post_ids'] );
387
388 /** This filter is documented in class-top-ten-query.php */
389 $exclude_post_ids = apply_filters( 'tptn_exclude_post_ids', $exclude_post_ids );
390
391 // Convert it back to string.
392 $exclude_post_ids = implode( ',', array_filter( $exclude_post_ids ) );
393
394 if ( $exclude_post_ids ) { // phpcs:ignore WordPress.PHP.StrictComparisons.LooseComparison
395 $where .= " AND $wpdb->posts.ID NOT IN ({$exclude_post_ids}) ";
396 }
397 $where .= " AND $wpdb->posts.post_type IN ('" . join( "', '", $post_types ) . "') "; // Array of post types.
398
399 // How old should the posts be?
400 if ( $args['how_old'] ) {
401 $how_old_date = Helpers::get_from_date( null, $args['how_old'] + 1, 0 );
402
403 $where .= $wpdb->prepare( " AND $wpdb->posts.post_date > %s ", $how_old_date );
404 }
405
406 if ( isset( $args['include_cat_ids'] ) && ! empty( $args['include_cat_ids'] ) ) {
407 $include_cat_ids = $args['include_cat_ids'];
408
409 $where .= " AND $wpdb->posts.ID IN ( SELECT object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ($include_cat_ids) )";
410 }
411
412 // Create the base GROUP BY clause.
413 if ( $args['daily'] ) {
414 $groupby = ' postnumber ';
415 }
416
417 // Create the base ORDER BY clause.
418 $orderby = ' visits DESC ';
419
420 // Create the base LIMITS clause.
421 $limits .= $wpdb->prepare( ' LIMIT %d, %d ', $offset, $limit );
422
423 /**
424 * Filter the SELECT clause of the query.
425 *
426 * @param string $fields The SELECT clause of the query.
427 */
428 $fields = apply_filters( 'tptn_posts_fields', $fields );
429
430 /**
431 * Filter the JOIN clause of the query.
432 *
433 * @param string $join The JOIN clause of the query.
434 */
435 $join = apply_filters( 'tptn_posts_join', $join );
436
437 /**
438 * Filter the WHERE clause of the query.
439 *
440 * @param string $where The WHERE clause of the query.
441 */
442 $where = apply_filters( 'tptn_posts_where', $where );
443
444 /**
445 * Filter the GROUP BY clause of the query.
446 *
447 * @param string $groupby The GROUP BY clause of the query.
448 */
449 $groupby = apply_filters( 'tptn_posts_groupby', $groupby );
450
451 /**
452 * Filter the ORDER BY clause of the query.
453 *
454 * @param string $orderby The ORDER BY clause of the query.
455 */
456 $orderby = apply_filters( 'tptn_posts_orderby', $orderby );
457
458 /**
459 * Filter the LIMIT clause of the query.
460 *
461 * @param string $limits The LIMIT clause of the query.
462 */
463 $limits = apply_filters( 'tptn_posts_limits', $limits );
464
465 if ( ! empty( $groupby ) ) {
466 $groupby = " GROUP BY {$groupby} ";
467 }
468 if ( ! empty( $orderby ) ) {
469 $orderby = " ORDER BY {$orderby} ";
470 }
471
472 $sql = "SELECT DISTINCT $fields FROM {$table_name} $join WHERE 1=1 $where $groupby $orderby $limits";
473
474 if ( $args['posts_only'] ) { // Return the array of posts only if the variable is set.
475 $results = $wpdb->get_results( $sql, ARRAY_A ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
476
477 /**
478 * Filter the array of top post IDs.
479 *
480 * @since 1.9.8.5
481 *
482 * @param array $tptn_pop_posts_array Posts array.
483 * @param mixed $args Arguments list
484 */
485 return apply_filters( 'tptn_pop_posts_array', $results, $args );
486 }
487
488 $results = $wpdb->get_results( $sql ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.NotPrepared
489
490 /**
491 * Filter object containing post IDs of popular posts
492 *
493 * @since 2.1.0
494 *
495 * @param object $results Top 10 popular posts object
496 * @param mixed $args Arguments list
497 */
498 return apply_filters( 'get_tptn_pop_posts', $results, $args );
499 }
500
501
502 /**
503 * Function to echo popular posts.
504 *
505 * @since 3.3.0
506 *
507 * @param mixed $args Arguments list.
508 */
509 public function show_pop_posts( $args = null ) {
510 if ( is_array( $args ) ) {
511 $args['manual'] = 1;
512 } else {
513 $args .= '&is_manual=1';
514 }
515
516 echo $this->pop_posts( $args ); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
517 }
518
519
520 /**
521 * Function to show daily popular posts.
522 *
523 * @since 3.3.0
524 *
525 * @param mixed $args Arguments list.
526 */
527 public function show_daily_pop_posts( $args = null ) {
528 if ( is_array( $args ) || ! isset( $args ) ) {
529 $args['daily'] = 1;
530 } else {
531 $args .= '&daily=1';
532 }
533
534 $this->show_pop_posts( $args );
535 }
536
537 /**
538 * Retrieves an array of the popular posts.
539 *
540 * The defaults are as follows:
541 *
542 * @since 3.3.0
543 *
544 * @see Top_Ten_Query::prepare_query_args()
545 *
546 * @param array $args Optional. Arguments to retrieve posts. See WP_Query::parse_query() for all available arguments.
547 * @return \WP_Post[]|int[] Array of post objects or post IDs.
548 */
549 public static function get_posts( $args = array() ) {
550
551 $get_posts = new \Top_Ten_Query( $args );
552
553 // Apply PHP-side exclusions and limit the results.
554 $filtered_posts = self::filter_posts_by_exclusions( $get_posts->posts, $args );
555
556 /**
557 * Filter array of post IDs or objects.
558 *
559 * @since 3.0.0
560 *
561 * @param \WP_Post[]|int[] $filtered_posts Array of post objects or post IDs after filtering.
562 * @param array $args Arguments to retrieve posts.
563 */
564 return apply_filters( 'get_tptn_posts', $filtered_posts, $args );
565 }
566
567 /**
568 * Returns the link attributes.
569 *
570 * @since 3.3.0
571 *
572 * @param array $args Array of arguments.
573 * @param \WP_Post $result Result object.
574 * @return string Space separated list of link attributes
575 */
576 public static function link_attributes( $args, $result ) {
577
578 $rel_attribute = ( $args['link_nofollow'] ) ? ' rel="nofollow" ' : ' ';
579
580 $target_attribute = ( $args['link_new_window'] ) ? ' target="_blank" ' : ' ';
581
582 $link_attributes = array(
583 'rel_attribute' => $rel_attribute,
584 'target_attribute' => $target_attribute,
585 );
586
587 /**
588 * Filter the title of the popular posts list
589 *
590 * @since 3.3.0
591 *
592 * @param array $link_attributes Array of link attributes
593 * @param array $args Array of arguments
594 * @param \WP_Post $result Result object
595 */
596 $link_attributes = apply_filters( 'tptn_link_attributes', $link_attributes, $args, $result );
597
598 // Convert it to a string.
599 $link_attributes = implode( ' ', $link_attributes );
600
601 return $link_attributes;
602 }
603
604
605 /**
606 * Returns the heading of the popular posts.
607 *
608 * @since 3.3.0
609 *
610 * @param array $args Array of arguments.
611 * @return string Space separated list of link attributes
612 */
613 public static function heading_title( $args ) {
614
615 $title = '';
616
617 if ( $args['heading'] && ! $args['is_widget'] ) {
618 $title = $args['daily'] ? $args['title_daily'] : $args['title'];
619 }
620
621 /**
622 * Filter the title of the Top posts.
623 *
624 * @since 1.9.5
625 *
626 * @param string $title Title/heading of the popular posts list
627 * @param array $args Array of arguments
628 */
629 return apply_filters( 'tptn_heading_title', $title, $args );
630 }
631
632
633 /**
634 * Returns the opening tag of the popular posts list.
635 *
636 * @since 3.3.0
637 *
638 * @param array $args Array of arguments.
639 * @return string Space separated list of link attributes
640 */
641 public static function before_list( $args ) {
642
643 $before_list = $args['before_list'];
644
645 /**
646 * Filter the opening tag of the popular posts list
647 *
648 * @since 1.9.10.1
649 *
650 * @param string $before_list Opening tag set in the Settings Page
651 * @param array $args Array of arguments
652 */
653 return apply_filters( 'tptn_before_list', $before_list, $args );
654 }
655
656
657 /**
658 * Returns the closing tag of the popular posts list.
659 *
660 * @since 3.3.0
661 *
662 * @param array $args Array of arguments.
663 * @return string Space separated list of link attributes
664 */
665 public static function after_list( $args ) {
666
667 $after_list = $args['after_list'];
668
669 /**
670 * Filter the closing tag of the popular posts list
671 *
672 * @since 1.9.10.1
673 *
674 * @param string $after_list Closing tag set in the Settings Page
675 * @param array $args Array of arguments
676 */
677 return apply_filters( 'tptn_after_list', $after_list, $args );
678 }
679
680
681 /**
682 * Returns the opening tag of each list item.
683 *
684 * @since 3.3.0
685 *
686 * @param array $args Array of arguments.
687 * @param \WP_Post $result Object of the current post result.
688 * @return string Space separated list of link attributes
689 */
690 public static function before_list_item( $args, $result ) {
691
692 $before_list_item = $args['before_list_item'];
693
694 /**
695 * Filter the opening tag of each list item.
696 *
697 * @since 1.9.10.1
698 *
699 * @param string $before_list_item Tag before each list item. Can be defined in the Settings page.
700 * @param object $result Object of the current post result
701 * @param array $args Array of arguments
702 */
703 return apply_filters( 'tptn_before_list_item', $before_list_item, $result, $args );
704 }
705
706
707 /**
708 * Returns the closing tag of each list item.
709 *
710 * @since 3.3.0
711 *
712 * @param array $args Array of arguments.
713 * @param \WP_Post $result Object of the current post result.
714 * @return string Space separated list of link attributes
715 */
716 public static function after_list_item( $args, $result ) {
717
718 $after_list_item = $args['after_list_item'];
719
720 /**
721 * Filter the closing tag of each list item.
722 *
723 * @since 1.9.10.1
724 *
725 * @param string $after_list_item Tag after each list item. Can be defined in the Settings page.
726 * @param object $result Object of the current post result
727 * @param array $args Array of arguments
728 */
729 return apply_filters( 'tptn_after_list_item', $after_list_item, $result, $args ); // Pass the post object to the filter.
730 }
731
732
733 /**
734 * Returns the title of each list item.
735 *
736 * @since 3.3.0
737 *
738 * @param array $args Array of arguments.
739 * @param \WP_Post $result Object of the current post result.
740 * @return string Space separated list of link attributes
741 */
742 public static function get_the_title( $args, $result ) {
743
744 $title = Helpers::trim_char( get_the_title( $result->ID ), $args['title_length'] ); // Get the post title and crop it if needed.
745
746 /**
747 * Filter the post title of each list item.
748 *
749 * @since 2.0.0
750 *
751 * @param string $title Title of the post.
752 * @param object $result Object of the current post result
753 * @param array $args Array of arguments
754 */
755 return apply_filters( 'tptn_post_title', $title, $result, $args );
756 }
757
758
759 /**
760 * Returns the author of each list item.
761 *
762 * @since 3.3.0
763 *
764 * @param array $args Array of arguments.
765 * @param \WP_Post $result Object of the current post result.
766 * @return string Space separated list of link attributes
767 */
768 public static function get_the_author( $args, $result ) {
769
770 $author_info = get_userdata( (int) $result->post_author );
771 $author_link = ( false === $author_info ) ? '' : get_author_posts_url( $author_info->ID );
772 $author_name = ( false === $author_info ) ? '' : ucwords( trim( stripslashes( $author_info->display_name ), " \t\n\r\0\x0B" ) );
773
774 /**
775 * Filter the author name.
776 *
777 * @since 1.9.1
778 *
779 * @param string $author_name Proper name of the post author.
780 * @param object $author_info WP_User object of the post author
781 */
782 $author_name = apply_filters( 'tptn_author_name', $author_name, $author_info );
783
784 if ( ! empty( $author_name ) ) {
785 $tptn_author = '<span class="tptn_author"> ' . __( ' by ', 'top-10' ) . '<a href="' . $author_link . '">' . $author_name . '</a></span> ';
786 } else {
787 $tptn_author = '';
788 }
789
790 /**
791 * Filter the text with the author details.
792 *
793 * @since 2.0.0
794 *
795 * @param string $tptn_author Formatted string with author details and link
796 * @param object $author_info WP_User object of the post author
797 * @param object $result Object of the current post result
798 * @param array $args Array of arguments
799 */
800 return apply_filters( 'tptn_author', $tptn_author, $author_info, $result, $args );
801 }
802
803
804 /**
805 * Returns the formatted list item with link and and thumbnail for each list item.
806 *
807 * @since 3.3.0
808 *
809 * @param array $args Array of arguments.
810 * @param \WP_Post $result Object of the current post result.
811 * @return string Space separated list of link attributes
812 */
813 public static function list_link( $args, $result ) {
814
815 $output = '';
816 $title = self::get_the_title( $args, $result );
817 $link_attributes = self::link_attributes( $args, $result );
818
819 if ( 'after' === $args['post_thumb_op'] ) {
820 $output .= '<a href="' . get_permalink( $result->ID ) . '" ' . $link_attributes . ' class="tptn_link">'; // Add beginning of link.
821 $output .= '<span class="tptn_title">' . $title . '</span>'; // Add title if post thumbnail is to be displayed after.
822 $output .= '</a>'; // Close the link.
823 }
824
825 if ( 'inline' === $args['post_thumb_op'] || 'after' === $args['post_thumb_op'] || 'thumbs_only' === $args['post_thumb_op'] ) {
826 $output .= '<a href="' . get_permalink( $result->ID ) . '" ' . $link_attributes . ' class="tptn_link">'; // Add beginning of link.
827
828 if ( 'text_only' !== $args['tptn_styles'] ) {
829 $output .= Media_Handler::get_the_post_thumbnail(
830 array(
831 'post' => $result,
832 'size' => $args['thumb_size'],
833 'thumb_meta' => $args['thumb_meta'],
834 'thumb_html' => $args['thumb_html'],
835 'thumb_default' => $args['thumb_default'],
836 'thumb_default_show' => $args['thumb_default_show'],
837 'scan_images' => $args['scan_images'],
838 'class' => 'tptn_thumb',
839 )
840 );
841 }
842
843 $output .= '</a>'; // Close the link.
844 }
845
846 if ( 'inline' === $args['post_thumb_op'] || 'text_only' === $args['post_thumb_op'] ) {
847 $output .= '<span class="tptn_after_thumb">';
848 $output .= '<a href="' . get_permalink( $result->ID ) . '" ' . $link_attributes . ' class="tptn_link">'; // Add beginning of link.
849 $output .= '<span class="tptn_title">' . $title . '</span>'; // Add title when required by settings.
850 $output .= '</a>'; // Close the link.
851 }
852
853 /**
854 * Filter Formatted list item with link and and thumbnail.
855 *
856 * @since 3.3.0
857 *
858 * @param string $output Formatted list item with link and and thumbnail
859 * @param object $result Object of the current post result
860 * @param array $args Array of arguments
861 */
862 return apply_filters( 'tptn_list_link', $output, $result, $args );
863 }
864
865
866 /**
867 * Returns the title of each list item.
868 *
869 * @since 3.3.0
870 *
871 * @param array $args Array of arguments.
872 * @param \WP_Post $result Object of the current post result.
873 * @return string Formatted post date
874 */
875 public static function get_the_date( $args, $result ) {
876
877 $date = mysql2date( get_option( 'date_format', 'd/m/y' ), $result->post_date );
878
879 /**
880 * Filter the post title of each list item.
881 *
882 * @since 2.6.0
883 *
884 * @param string $date Title of the post.
885 * @param object $result Object of the current post result
886 * @param array $args Array of arguments
887 */
888 return apply_filters( 'tptn_date', $date, $result, $args );
889 }
890
891
892 /**
893 * Returns the title of each list item.
894 *
895 * @since 3.3.0
896 *
897 * @param array $args Array of arguments.
898 * @param \WP_Post $result Object of the current post result.
899 * @param int $visits Number of visits.
900 * @return string Formatted post date
901 */
902 public static function get_list_count( $args, $result, $visits ) {
903
904 $number_format_style = isset( $args['number_format_style'] ) ? $args['number_format_style'] : null;
905
906 $tptn_list_count = '(' . Helpers::number_format_i18n( $visits, 0, $number_format_style ) . ')';
907
908 /**
909 * Filter the formatted list count text.
910 *
911 * @since 2.1.0
912 *
913 * @param string $tptn_list_count Formatted list count
914 * @param int $visits Post count
915 * @param \WP_Post $result Post object
916 * @param array $args Array of arguments.
917 */
918 return apply_filters( 'tptn_list_count', $tptn_list_count, $visits, $result, $args );
919 }
920
921
922 /**
923 * Returns the WP-PostRatings rating of each list item.
924 *
925 * @since 4.4.0
926 *
927 * @param array $args Array of arguments. `show_ratings` can be `stars` (WP-PostRatings template) or `score` (average rating number).
928 * @param \WP_Post $result Object of the current post result.
929 * @return string Formatted rating markup. Empty string if WP-PostRatings is not active.
930 */
931 public static function get_the_ratings( $args, $result ) {
932
933 $ratings = '';
934
935 if ( 'score' === $args['show_ratings'] && function_exists( 'expand_ratings_template' ) ) {
936 $ratings = ' <span class="tptn_ratings">' . expand_ratings_template( '%RATINGS_AVERAGE%', $result->ID ) . '</span>';
937 } elseif ( function_exists( 'the_ratings_results' ) ) {
938 $ratings = ' <span class="tptn_ratings">' . the_ratings_results( $result->ID ) . '</span>';
939 }
940
941 /**
942 * Filter the WP-PostRatings rating markup of each list item.
943 *
944 * @since 4.4.0
945 *
946 * @param string $ratings Formatted rating markup. Empty string if WP-PostRatings is not active.
947 * @param \WP_Post $result Object of the current post result.
948 * @param array $args Array of arguments.
949 */
950 return apply_filters( 'tptn_ratings', $ratings, $result, $args );
951 }
952
953
954 /**
955 * Function to create an excerpt for the post.
956 *
957 * @since 3.3.0
958 * @since 4.0.0 Added $more_link_text parameter. $post parameter can now be a WP_Post instance.
959 *
960 * @param int|\WP_Post $post Post ID or WP_Post instance.
961 * @param int|string $excerpt_length Length of the excerpt in words.
962 * @param bool $use_excerpt Use excerpt instead of content.
963 * @param string|null $more_link_text Read More text. Pass null to use the default "(more&hellip;)" link. Default '' (no Read More link).
964 * @return string Post Excerpt
965 */
966 public static function get_the_excerpt( $post, $excerpt_length = 0, $use_excerpt = true, $more_link_text = '' ) {
967 $content = '';
968
969 $post = get_post( $post );
970 if ( empty( $post ) ) {
971 return '';
972 }
973 if ( $use_excerpt ) {
974 $content = $post->post_excerpt;
975 }
976 if ( empty( $content ) ) {
977 $content = $post->post_content;
978 }
979
980 $output = strip_shortcodes( $content );
981 $output = wp_strip_all_tags( $output, true );
982
983 /**
984 * Filters excerpt generated by CRP before it is trimmed.
985 *
986 * @since 4.0.0
987 *
988 * @param string $output Formatted excerpt.
989 * @param \WP_Post $post Source Post instance.
990 * @param int $excerpt_length Length of the excerpt.
991 * @param boolean $use_excerpt Use the excerpt?
992 * @param string $content Content that is used to create the excerpt.
993 */
994 $output = apply_filters( 'tptn_excerpt_pre_trim', $output, $post, $excerpt_length, $use_excerpt, $content );
995
996 /**
997 * Filters the Read More text of the CRP excerpt.
998 *
999 * @since 3.0.0
1000 *
1001 * @param string|null $more_link_text Read More text. Null uses the default "(more&hellip;)" link.
1002 * @param \WP_Post $post Source Post instance.
1003 */
1004 $more_link_text = apply_filters( 'tptn_excerpt_more_link_text', $more_link_text, $post );
1005
1006 if ( null === $more_link_text ) {
1007 $more_link_text = sprintf(
1008 '<span aria-label="%1$s">%2$s</span>',
1009 sprintf(
1010 /* translators: %s: Post title. */
1011 __( 'Continue reading %s', 'top-10' ),
1012 the_title_attribute(
1013 array(
1014 'echo' => false,
1015 'post' => $post,
1016 )
1017 )
1018 ),
1019 __( '(more&hellip;)', 'top-10' )
1020 );
1021 }
1022
1023 if ( ! empty( $more_link_text ) ) {
1024 $more_link_element = ' <a href="' . get_permalink( $post ) . "#more-{$post->ID}\" class=\"tptn_read_more_link\">$more_link_text</a>";
1025 } else {
1026 $more_link_element = '';
1027 }
1028
1029 /**
1030 * Filters the Read More link text of the CRP excerpt.
1031 *
1032 * @since 4.0.0
1033 *
1034 * @param string $more_link_element Read More link element.
1035 * @param string $more_link_text Read More text.
1036 * @param \WP_Post $post Source Post instance.
1037 */
1038 $more_link_element = apply_filters( 'tptn_excerpt_more_link', $more_link_element, $more_link_text, $post );
1039
1040 if ( $excerpt_length > 0 ) {
1041 $more_link_element = empty( $more_link_element ) ? null : $more_link_element;
1042
1043 $output = wp_trim_words( $output, $excerpt_length, $more_link_element );
1044 }
1045
1046 if ( post_password_required( $post ) ) {
1047 $output = __( 'There is no excerpt because this is a protected post.', 'top-10' );
1048 }
1049
1050 /**
1051 * Filters excerpt generated by CRP.
1052 *
1053 * @since 1.9.10.1
1054 * @since 4.0.0 Changed second parameter to WP_Post instance instead of ID.
1055 *
1056 * @param string $output Formatted excerpt.
1057 * @param \WP_Post $post Source Post instance.
1058 * @param int $excerpt_length Length of the excerpt.
1059 * @param boolean $use_excerpt Use the excerpt?
1060 */
1061 return apply_filters( 'tptn_excerpt', $output, $post, $excerpt_length, $use_excerpt );
1062 }
1063
1064 /**
1065 * Get the default thumbnail.
1066 *
1067 * @since 4.0.0
1068 *
1069 * @return string Default thumbnail.
1070 */
1071 public static function get_default_thumbnail() {
1072 return defined( 'TOP_TEN_DEFAULT_THUMBNAIL_URL' ) ? TOP_TEN_DEFAULT_THUMBNAIL_URL : TOP_TEN_PLUGIN_URL . 'default.png';
1073 }
1074
1075 /**
1076 * Processes exclusion settings to return if the popular posts should not be displayed on the current post.
1077 *
1078 * @since 3.3.0
1079 *
1080 * @param int|\WP_Post|null $post Post ID or post object. Defaults to global $post. Default null.
1081 * @param array $args Parameters in a query string format.
1082 * @return bool True if any exclusion setting is matched.
1083 */
1084 public static function exclude_on( $post = null, $args = array() ) {
1085 $post = get_post( $post );
1086 if ( ! $post ) {
1087 return false;
1088 }
1089
1090 // If this post ID is in the DO NOT DISPLAY list.
1091 $exclude_on_post_ids = isset( $args['exclude_on_post_ids'] ) ? $args['exclude_on_post_ids'] : \tptn_get_option( 'exclude_on_post_ids' );
1092 $exclude_on_post_ids = wp_parse_id_list( $exclude_on_post_ids );
1093 if ( in_array( (int) $post->ID, $exclude_on_post_ids, true ) ) {
1094 return true;
1095 }
1096
1097 // If this post type is in the DO NOT DISPLAY list.
1098 $exclude_on_post_types = isset( $args['exclude_on_post_types'] ) ? $args['exclude_on_post_types'] : \tptn_get_option( 'exclude_on_post_types' );
1099 $exclude_on_post_types = wp_parse_list( $exclude_on_post_types );
1100
1101 if ( in_array( $post->post_type, $exclude_on_post_types, true ) ) {
1102 return true;
1103 }
1104
1105 // If this post's category is in the DO NOT DISPLAY list.
1106 $exclude_on_categories = isset( $args['exclude_on_categories'] ) ? $args['exclude_on_categories'] : \tptn_get_option( 'exclude_on_categories' );
1107 $exclude_on_categories = wp_parse_id_list( $exclude_on_categories );
1108 $post_categories = get_the_terms( $post->ID, 'category' );
1109 $categories = array();
1110 if ( ! empty( $post_categories ) && ! is_wp_error( $post_categories ) ) {
1111 $categories = wp_list_pluck( $post_categories, 'term_taxonomy_id' );
1112 }
1113 if ( ! empty( array_intersect( $exclude_on_categories, $categories ) ) ) {
1114 return true;
1115 }
1116
1117 // If the DO NOT DISPLAY meta field is set.
1118 if ( ( isset( $args['is_shortcode'] ) && ! $args['is_shortcode'] ) &&
1119 ( isset( $args['is_manual'] ) && ! $args['is_manual'] ) &&
1120 ( isset( $args['is_block'] ) && ! $args['is_block'] ) ) {
1121 $tptn_post_meta = get_post_meta( $post->ID, 'tptn_post_meta', true );
1122
1123 if ( isset( $tptn_post_meta['disable_here'] ) ) {
1124 $disable_here = $tptn_post_meta['disable_here'];
1125 } else {
1126 $disable_here = 0;
1127 }
1128
1129 if ( $disable_here ) {
1130 return true;
1131 }
1132 }
1133
1134 return false;
1135 }
1136
1137 /**
1138 * Get static excluded post IDs that should affect caching.
1139 *
1140 * These are exclusions that are consistent across requests for the same configuration.
1141 *
1142 * @since 4.2.0
1143 *
1144 * @param array $args Arguments array.
1145 * @return array Array of post IDs to exclude statically.
1146 */
1147 public static function get_static_excluded_ids( $args ) {
1148 global $wpdb;
1149
1150 $exclude_post_ids = empty( $args['exclude_post_ids'] ) ? array() : wp_parse_id_list( $args['exclude_post_ids'] );
1151
1152 // Prepare the query to find all posts with 'exclude_this_post' set in the meta.
1153 $post_metas = $wpdb->get_results( // phpcs:ignore WordPress.DB.DirectDatabaseQuery
1154 $wpdb->prepare(
1155 "SELECT post_id, meta_value FROM {$wpdb->postmeta} WHERE meta_key = %s",
1156 'tptn_post_meta'
1157 ),
1158 ARRAY_A
1159 );
1160
1161 foreach ( $post_metas as $post_meta ) {
1162 $meta_value = maybe_unserialize( $post_meta['meta_value'] );
1163
1164 if ( $meta_value['exclude_this_post'] ) {
1165 $exclude_post_ids[] = (int) $post_meta['post_id'];
1166 }
1167 }
1168
1169 // Exclude page_on_front and page_for_posts.
1170 if ( 'page' === get_option( 'show_on_front' ) && \tptn_get_option( 'exclude_front' ) ) {
1171 $page_on_front = (int) get_option( 'page_on_front' );
1172 $page_for_posts = (int) get_option( 'page_for_posts' );
1173 if ( $page_on_front > 0 ) {
1174 $exclude_post_ids[] = $page_on_front;
1175 }
1176 if ( $page_for_posts > 0 ) {
1177 $exclude_post_ids[] = $page_for_posts;
1178 }
1179 }
1180
1181 /**
1182 * Filter static exclude post IDs array.
1183 *
1184 * @since 4.2.0
1185 *
1186 * @param array $exclude_post_ids Array of post IDs.
1187 * @param array $args Arguments array.
1188 */
1189 $exclude_post_ids = apply_filters( 'tptn_static_exclude_post_ids', $exclude_post_ids, $args );
1190
1191 /**
1192 * Filter exclude post IDs array for backward compatibility.
1193 *
1194 * @since 2.2.0
1195 * @since 3.0.0 Added $args
1196 *
1197 * @param array $exclude_post_ids Array of post IDs.
1198 * @param array $args Arguments array.
1199 */
1200 $exclude_post_ids = apply_filters( 'tptn_exclude_post_ids', $exclude_post_ids, $args );
1201
1202 return array_unique( $exclude_post_ids );
1203 }
1204
1205 /**
1206 * Get dynamic excluded post IDs that are per-request and should not affect caching.
1207 *
1208 * @since 4.2.0
1209 *
1210 * @param array $args Arguments array.
1211 * @return array Array of post IDs to exclude dynamically.
1212 */
1213 public static function get_dynamic_excluded_ids( $args ) {
1214 $exclude_post_ids = array();
1215
1216 if ( ! empty( $args['exclude_current_post'] ) ) {
1217 $exclude_post_ids[] = (int) get_the_ID();
1218 }
1219
1220 /**
1221 * Filter dynamic exclude post IDs array.
1222 *
1223 * @since 4.2.0
1224 *
1225 * @param array $exclude_post_ids Array of post IDs.
1226 * @param array $args Arguments array.
1227 */
1228 $exclude_post_ids = apply_filters( 'tptn_dynamic_exclude_post_ids', $exclude_post_ids, $args );
1229
1230 return array_unique( $exclude_post_ids );
1231 }
1232
1233 /**
1234 * Filter posts array by excluded IDs and return requested limit.
1235 *
1236 * @since 4.2.0
1237 *
1238 * @param \WP_Post[] $posts Array of post objects.
1239 * @param array $args Arguments array.
1240 * @return \WP_Post[] Filtered array of post objects.
1241 */
1242 protected static function filter_posts_by_exclusions( $posts, $args ): array {
1243 if ( empty( $posts ) ) {
1244 return $posts;
1245 }
1246
1247 $static_excluded_ids = self::get_static_excluded_ids( $args );
1248 $dynamic_excluded_ids = self::get_dynamic_excluded_ids( $args );
1249 $all_excluded_ids = array_unique( array_merge( $static_excluded_ids, $dynamic_excluded_ids ) );
1250
1251 if ( empty( $all_excluded_ids ) ) {
1252 return array_slice( $posts, 0, (int) $args['limit'] );
1253 }
1254
1255 // Filter posts by excluded IDs.
1256 $filtered_posts = array_filter(
1257 $posts,
1258 function ( $post ) use ( $all_excluded_ids ) {
1259 return ! in_array( $post->ID, $all_excluded_ids, true );
1260 }
1261 );
1262
1263 // Re-index array and slice to requested limit.
1264 $filtered_posts = array_values( $filtered_posts );
1265 return array_slice( $filtered_posts, 0, (int) $args['limit'] );
1266 }
1267 }
1268