PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 6.1.4
WP Popular Posts v6.1.4
4.0.8 4.0.9 4.1.0 4.1.1 4.1.2 4.2.0 4.2.1 4.2.2 5.0.0 5.0.1 5.0.2 5.1.0 5.2.0 5.2.1 5.2.2 5.2.3 5.2.4 5.3.0 5.3.1 5.3.2 5.3.3 5.3.4 5.3.5 5.3.6 5.4.0 5.4.1 5.4.2 5.5.0 5.5.1 6.0.0 6.0.1 6.0.2 6.0.3 6.0.4 6.0.5 6.1.0 6.1.1 6.1.2 6.1.3 6.1.4 6.2.0 6.2.1 6.3.0 6.3.1 6.3.2 6.3.3 6.3.4 6.4.0 6.4.1 6.4.2 7.0.0 7.0.1 7.1.0 7.2.0 7.3.0 7.3.1 7.3.2 7.3.3 7.3.4 7.3.5 7.3.6 7.3.7 7.3.8 7.4.0 trunk 2.3.7 3.0.0 3.0.1 3.0.2 3.0.3 3.1.0 3.1.1 3.2.0 3.2.1 3.2.2 3.2.3 3.3.0 3.3.1 3.3.2 3.3.3 3.3.4 4.0.0 4.0.1 4.0.10 4.0.11 4.0.12 4.0.13 4.0.2 4.0.3 4.0.5 4.0.6
wordpress-popular-posts / src / Output.php
wordpress-popular-posts / src Last commit date
Activation 2 years ago Admin 2 years ago Block 2 years ago Container 2 years ago Front 2 years ago Rest 2 years ago Traits 2 years ago Widget 2 years ago Bootstrap.php 2 years ago Cache.php 2 years ago Helper.php 2 years ago I18N.php 2 years ago Image.php 2 years ago Output.php 2 years ago Query.php 2 years ago Settings.php 2 years ago Themer.php 2 years ago Translate.php 2 years ago WordPressPopularPosts.php 2 years ago deprecated.php 2 years ago template-tags.php 2 years ago
Output.php
1036 lines
1 <?php
2 /**
3 * This class formats the HTML output of every popular posts listing.
4 *
5 *
6 * @package WordPressPopularPosts
7 * @author Hector Cabrera <me@cabrerahector.com>
8 */
9
10 namespace WordPressPopularPosts;
11
12 class Output {
13
14 /**
15 * Popular posts data.
16 *
17 * @since 4.0.0
18 * @var string
19 */
20 private $data;
21
22 /**
23 * HTML output.
24 *
25 * @since 4.0.0
26 * @var string
27 */
28 private $output;
29
30 /**
31 * Widget / shortcode settings.
32 *
33 * @since 4.0.0
34 * @var array
35 */
36 private $public_options = [];
37
38 /**
39 * Administrative settings.
40 *
41 * @since 2.3.3
42 * @var array
43 */
44 private $admin_options = [];
45
46 /**
47 * Default excerpt 'more' string.
48 *
49 * @since 4.2.1
50 * @var string
51 */
52 private $more;
53
54 /**
55 * Image object
56 *
57 * @since 4.0.2
58 * @var WordPressPopularPosts\Image
59 */
60 private $thumbnail;
61
62 /**
63 * Translate object.
64 *
65 * @var \WordPressPopularPosts\Translate $translate
66 * @access private
67 */
68 private $translate;
69
70 /**
71 * Themer object.
72 *
73 * @var \WordPressPopularPosts\Themer $themer
74 * @access private
75 */
76 private $themer;
77
78 /**
79 * WordPress Date format.
80 *
81 * @var string
82 * @access private
83 */
84 private $wp_date_format;
85
86 /**
87 * Constructor.
88 *
89 * @since 4.0.0
90 * @param array $public_options
91 * @param array $admin_options
92 * @param WordPressPopularPosts\Image $thumbnail
93 * @param WordPressPopularPosts\Translate $translate
94 * @param WordPressPopularPosts\Themer $themer
95 */
96 public function __construct(array $public_options, array $admin_options, Image $thumbnail, Translate $translate, Themer $themer)
97 {
98 $this->public_options = $public_options;
99 $this->admin_options = $admin_options;
100 $this->thumbnail = $thumbnail;
101 $this->translate = $translate;
102 $this->themer = $themer;
103
104 $this->more = '...';
105
106 $this->wp_date_format = get_option('date_format');
107
108 if ( ! $this->wp_date_format ) {
109 $this->wp_date_format = 'F j, Y';
110 }
111 }
112
113 /**
114 * Sets data.
115 *
116 * @since 5.0.0
117 * @param array
118 */
119 public function set_data(array $data = [])
120 {
121 $this->data = $data;
122 }
123
124 /**
125 * Sets public options.
126 *
127 * @since 5.0.0
128 * @param array
129 */
130 public function set_public_options(array $public_options = [])
131 {
132 $this->public_options = Helper::merge_array_r(
133 Settings::get('widget_options'),
134 $public_options
135 );
136 }
137
138 /**
139 * Output the HTML.
140 *
141 * @since 4.0.0
142 */
143 public function output()
144 {
145 echo $this->get_output(); // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- At this point everything has been escaped / sanitized already
146 }
147
148 /**
149 * Return the HTML.
150 *
151 * @since 4.0.0
152 * @return string
153 */
154 public function get_output()
155 {
156 $this->output = ( WP_DEBUG ? "\n" . '<!-- WordPress Popular Posts v' . WPP_VERSION . ( $this->admin_options['tools']['cache']['active'] ? ' - cached' : '' ) . ' -->' . "\n" : '' ) . $this->output;
157
158 // Attempt to close open tags
159 $this->output = force_balance_tags($this->output);
160
161 // Remove empty tags
162 $clean_html = '';
163 $html = '<!DOCTYPE html><html><head><meta charset="UTF-8" /></head><body>' . trim($this->output) . '</body></html>';
164
165 $dom = new \DOMDocument();
166 $dom->loadHTML($html);
167 $xpath = new \DOMXPath($dom);
168
169 while ( ($node_list = $xpath->query('//*[not(*) and not(@*) and not(text()[normalize-space()])]')) && $node_list->length ) {
170 foreach ($node_list as $node) {
171 $node->parentNode->removeChild($node);
172 }
173 }
174
175 $body = $dom->getElementsByTagName('body')->item(0);
176
177 foreach( $body->childNodes as $node ) {
178 $clean_html .= $dom->saveHTML($node);
179 }
180
181 $this->output = trim($clean_html);
182
183 return $this->output;
184 }
185
186 /**
187 * Build the HTML output.
188 *
189 * @since 4.0.0
190 */
191 public function build_output()
192 {
193 // Got some posts, format 'em!
194 if ( ! empty($this->data) ) {
195
196 $this->output = '';
197
198 // Allow WP themers / coders access to raw data
199 // so they can build their own output
200 if ( has_filter('wpp_custom_html') ) {
201 $this->output .= apply_filters('wpp_custom_html', $this->data, $this->public_options);
202 return;
203 }
204
205 if (
206 isset($this->public_options['theme']['name'])
207 && $this->public_options['theme']['name']
208 ) {
209 $this->output .= '<div class="popular-posts-sr">';
210
211 if ( @file_exists(get_stylesheet_directory() . '/wordpress-popular-posts/themes/' . $this->public_options['theme']['name'] . '/style.css') ) {
212 $theme_stylesheet = get_stylesheet_directory() . '/wordpress-popular-posts/themes/' . $this->public_options['theme']['name'] . '/style.css';
213 } else {
214 $theme_stylesheet = $this->themer->get_theme($this->public_options['theme']['name'])['path'] . '/style.css';
215 }
216
217 $theme_css_rules = wp_strip_all_tags(file_get_contents($theme_stylesheet), true);
218 $additional_styles = '';
219
220 if ( has_filter('wpp_additional_theme_styles') ) {
221 $additional_styles = wp_strip_all_tags(apply_filters('wpp_additional_theme_styles', '', $this->public_options['theme']['name']), true);
222
223 if ( $additional_styles ) {
224 $additional_styles = ' /* additional rules */ ' . $additional_styles;
225 }
226 }
227
228 $this->output .= '<style>' . $theme_css_rules . $additional_styles . '</style>';
229 }
230
231 /* Open HTML wrapper */
232 // Output a custom wrapper
233 if (
234 isset($this->public_options['markup']['custom_html'])
235 && $this->public_options['markup']['custom_html']
236 && isset($this->public_options['markup']['wpp-start'])
237 && isset($this->public_options['markup']['wpp-end'])
238 ){
239 $this->output .= "\n" . htmlspecialchars_decode($this->public_options['markup']['wpp-start'], ENT_QUOTES) . "\n";
240 }
241 // Output the default wrapper
242 else {
243
244 $classes = 'wpp-list';
245
246 if ( $this->public_options['thumbnail']['active'] ) {
247 $classes .= ' wpp-list-with-thumbnails';
248 }
249
250 $this->output .= "\n<ul class=\"{$classes}\">\n";
251
252 }
253
254 $position = 0;
255
256 // Format each post
257 foreach( $this->data as $post_object ) {
258 $position++;
259 $this->output .= $this->render_post($post_object, $position);
260 }
261
262 /* Close HTML wrapper */
263 // Output a custom wrapper
264 if (
265 isset($this->public_options['markup']['custom_html'])
266 && $this->public_options['markup']['custom_html']
267 && isset($this->public_options['markup']['wpp-start'])
268 && isset($this->public_options['markup']['wpp-end'])
269 ){
270 $this->output .= "\n" . htmlspecialchars_decode($this->public_options['markup']['wpp-end'], ENT_QUOTES) . "\n";
271 }
272 // Output default wrapper
273 else {
274 $this->output .= '</ul>' . "\n";
275 }
276
277 if (
278 isset($this->public_options['theme']['name'])
279 && $this->public_options['theme']['name']
280 ) {
281 $this->output .= '</div>';
282 }
283
284 }
285 // Got nothing to show, give 'em the old "Sorry. No data so far." message!
286 else {
287 $this->output = apply_filters('wpp_no_data', '<p class="wpp-no-data">' . __('Sorry. No data so far.', 'wordpress-popular-posts') . '</p>');
288 }
289 }
290
291 /**
292 * Build the HTML markup for a single post.
293 *
294 * @since 4.0.0
295 * @access private
296 * @param object $post_object
297 * @param integer $position
298 * @return string
299 */
300 private function render_post(\stdClass $post_object, int $position = 1)
301 {
302 $is_single = $this->is_single();
303 $post = '';
304 $post_id = $post_object->id;
305 $trid = $this->translate->get_object_id(
306 $post_object->id,
307 get_post_type($post_object->id)
308 );
309
310 if ( $post_id != $trid ) {
311 $post_id = $trid;
312 }
313
314 $is_current_post = ( $is_single && ($is_single == $post_id || $is_single == $post_object->id) ) ? true : false;
315
316 // Permalink
317 $permalink = esc_url($this->get_permalink($post_object, $post_id));
318
319 // Post title (and title attribute)
320 $post_title_attr = esc_attr(wp_strip_all_tags($this->get_title($post_object, $post_id)));
321 $post_title = $this->get_title($post_object, $post_id);
322
323 if ( $this->public_options['shorten_title']['active'] ) {
324 $length = ( filter_var($this->public_options['shorten_title']['length'], FILTER_VALIDATE_INT) && $this->public_options['shorten_title']['length'] > 0 )
325 ? $this->public_options['shorten_title']['length']
326 : 25;
327
328 $more = $this->public_options['shorten_title']['words'] ? ' ' . $this->more : $this->more;
329 $more = apply_filters('wpp_title_more', $more);
330 $post_title = Helper::truncate($post_title, $length, $this->public_options['shorten_title']['words'], $more);
331 }
332
333 // Thumbnail
334 $post_thumbnail = $this->get_thumbnail($post_id);
335
336 // Post excerpt
337 $post_excerpt = $this->get_excerpt($post_object, $post_id);
338
339 // Post rating
340 $post_rating = $this->get_rating($post_object);
341
342 /**
343 * Post meta
344 */
345
346 // Post date
347 $post_date = $this->get_date($post_object);
348
349 // Post taxonomies
350 $post_taxonomies = $this->get_taxonomies($post_id);
351
352 // Post author
353 $post_author = $this->get_author($post_object, $post_id);
354
355 // Post views count
356 $post_views = $this->get_pageviews($post_object);
357
358 // Post comments count
359 $post_comments = $this->get_comments($post_object);
360
361 // Post meta
362 $meta_arr = $this->get_metadata(
363 $post_object,
364 $post_id,
365 $post_date,
366 $post_taxonomies,
367 $post_author,
368 $post_views,
369 $post_comments
370 );
371
372 if (
373 is_array($meta_arr)
374 && ! empty($meta_arr)
375 && 'views' == $this->public_options['order_by']
376 ) {
377 $keys = ['views', 'comments', 'author', 'date', 'taxonomy'];
378 $new_meta_arr = [];
379
380 foreach($keys as $key) {
381 if ( isset($meta_arr[$key])) {
382 $new_meta_arr[$key] = $meta_arr[$key];
383 }
384 }
385
386 if ( ! empty($new_meta_arr) ) {
387 $meta_arr = $new_meta_arr;
388 }
389 }
390
391 $post_meta_separator = esc_html(apply_filters('wpp_post_meta_separator', ' | '));
392 $post_meta = join($post_meta_separator, $meta_arr);
393
394 $prettify_numbers = apply_filters('wpp_pretiffy_numbers', true);
395
396 // Build custom HTML output
397 if ( $this->public_options['markup']['custom_html'] ) {
398 $data = [
399 'id' => $post_id,
400 'is_current_post' => $is_current_post,
401 'title' => '<a href="' . $permalink . '" ' . ($post_title_attr !== $post_title ? 'title="' . $post_title_attr . '" ' : '' ) . 'class="wpp-post-title" target="' . esc_attr($this->admin_options['tools']['link']['target']) . '">' . $post_title . '</a>',
402 'title_attr' => $post_title_attr,
403 'summary' => $post_excerpt,
404 'stats' => $post_meta,
405 'img' => ( ! empty($post_thumbnail) ) ? '<a href="' . $permalink . '" ' . ($post_title_attr !== $post_title ? 'title="' . $post_title_attr . '" ' : '' ) . 'target="' . esc_attr($this->admin_options['tools']['link']['target']) . '">' . $post_thumbnail . '</a>' : '',
406 'img_no_link' => $post_thumbnail,
407 'url' => $permalink,
408 'text_title' => $post_title,
409 'taxonomy' => $post_taxonomies,
410 'taxonomy_copy' => isset($meta_arr['taxonomy']) ? $meta_arr['taxonomy'] : null,
411 'author' => ( ! empty($post_author) ) ? '<a href="' . esc_url(get_author_posts_url($post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid )) . '">' . esc_html($post_author) . '</a>' : '',
412 'author_copy' => isset($meta_arr['author']) ? $meta_arr['author'] : null,
413 'author_name' => esc_html($post_author),
414 'author_url' => ( ! empty($post_author) ) ? esc_url(get_author_posts_url($post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid)) : '',
415 'views' => ( $this->public_options['order_by'] == 'views' || $this->public_options['order_by'] == 'comments' ) ? ($prettify_numbers ? Helper::prettify_number($post_views) : number_format_i18n($post_views)) : ($prettify_numbers ? Helper::prettify_number($post_views, 2) : number_format_i18n($post_views, 2)),
416 'views_copy' => isset($meta_arr['views']) ? $meta_arr['views'] : null,
417 'comments' => $prettify_numbers ? Helper::prettify_number($post_comments) : number_format_i18n($post_comments),
418 'comments_copy' => isset($meta_arr['comments']) ? $meta_arr['comments'] : null,
419 'date' => $post_date,
420 'date_copy' => isset($meta_arr['date']) ? $meta_arr['date'] : null,
421 'total_items' => count($this->data),
422 'item_position' => $position
423 ];
424 $post = $this->format_content(htmlspecialchars_decode($this->public_options['markup']['post-html'], ENT_QUOTES), $data, $this->public_options['rating']) . "\n";
425 } // Use the "stock" HTML output
426 else {
427 $wpp_post_class = [];
428
429 if ( $is_current_post ) {
430 $wpp_post_class[] = 'current';
431 }
432
433 // Allow themers / plugin developer
434 // to add custom classes to each post
435 $wpp_post_class = apply_filters('wpp_post_class', $wpp_post_class, $post_id);
436
437 $post_thumbnail = ( ! empty($post_thumbnail) )
438 ? "<a href=\"{$permalink}\" " . ($post_title_attr !== $post_title ? "title=\"{$post_title_attr}\" " : '') . 'target="' . esc_attr($this->admin_options['tools']['link']['target']) . "\">{$post_thumbnail}</a>\n"
439 : '';
440
441 $post_excerpt = ( ! empty($post_excerpt) )
442 ? " <span class=\"wpp-excerpt\">{$post_excerpt}</span>\n"
443 : '';
444
445 $post_meta = ( ! empty($post_meta) )
446 ? " <span class=\"wpp-meta post-stats\">{$post_meta}</span>\n"
447 : '';
448
449 $post_rating = ( ! empty($post_rating) )
450 ? " <span class=\"wpp-rating\">{$post_rating}</span>\n"
451 : '';
452
453 $post =
454 '<li' . ( ( is_array($wpp_post_class) && ! empty($wpp_post_class) ) ? ' class="' . esc_attr(implode(' ', $wpp_post_class)) . '"' : '') . ">\n"
455 . $post_thumbnail
456 . "<a href=\"{$permalink}\" " . ($post_title_attr !== $post_title ? "title=\"{$post_title_attr}\" " : '') . 'class="wpp-post-title" target="' . esc_attr($this->admin_options['tools']['link']['target']) . "\">{$post_title}</a>\n"
457 . $post_excerpt
458 . $post_meta
459 . $post_rating
460 . "</li>\n";
461 }
462
463 return apply_filters('wpp_post', $post, $post_object, $this->public_options);
464 }
465
466 /**
467 * Return the processed post/page title.
468 *
469 * @since 3.0.0
470 * @access private
471 * @param object $post_object
472 * @param integer $post_id
473 * @return string
474 */
475 private function get_title(\stdClass $post_object, int $post_id)
476 {
477 $title = '';
478
479 if ( $post_object->id != $post_id ) {
480 $title = get_the_title($post_id);
481 } else {
482 $title = $post_object->title;
483 }
484
485 // Run the_title filter so core/plugin title hooks can
486 // be applied to the post title
487 $title = apply_filters('the_title', $title, $post_object->id);
488
489 return apply_filters('wpp_the_title', $title, $post_object->id, $post_id);
490 }
491
492 /**
493 * Return the permalink.
494 *
495 * @since 4.0.12
496 * @access private
497 * @param object $post_object
498 * @param integer $post_id
499 * @return string
500 */
501 private function get_permalink(\stdClass $post_object, int $post_id) {
502 if ( $post_object->id != $post_id ) {
503 return get_permalink($post_id);
504 }
505
506 return get_permalink($post_object->id);
507 }
508
509 /**
510 * Return the processed thumbnail.
511 *
512 * @since 3.0.0
513 * @access private
514 * @param int $post_id
515 * @return string
516 */
517 private function get_thumbnail(int $post_id)
518 {
519 $thumbnail = '';
520
521 if ( $this->public_options['thumbnail']['active'] ) {
522 $thumbnail = $this->thumbnail->get(
523 $post_id,
524 [
525 $this->public_options['thumbnail']['width'],
526 $this->public_options['thumbnail']['height']
527 ],
528 $this->admin_options['tools']['thumbnail']['source'],
529 $this->public_options['thumbnail']['crop'],
530 $this->public_options['thumbnail']['build']
531 );
532 }
533
534 return $thumbnail;
535 }
536
537 /**
538 * Return post excerpt.
539 *
540 * @since 3.0.0
541 * @access private
542 * @param object $post_object
543 * @param integer $post_id
544 * @return string
545 */
546 private function get_excerpt(\stdClass $post_object, int $post_id)
547 {
548 $excerpt = '';
549
550 if ( $this->public_options['post-excerpt']['active'] ) {
551
552 if ( $post_object->id != $post_id ) {
553 $the_post = get_post($post_id);
554
555 $excerpt = ( empty($the_post->post_excerpt) )
556 ? $the_post->post_content
557 : $the_post->post_excerpt;
558 }
559 else {
560 $excerpt = ( empty($post_object->post_excerpt) )
561 ? $post_object->post_content
562 : $post_object->post_excerpt;
563 }
564
565 // remove caption tags
566 $excerpt = preg_replace('/\[caption.*\[\/caption\]/', '', $excerpt);
567
568 // remove Flash objects
569 $excerpt = preg_replace("/<object[0-9 a-z_?*=\":\-\/\.#\,\\n\\r\\t]+/smi", '', $excerpt);
570
571 // remove iframes
572 $excerpt = preg_replace('/<iframe.*?\/iframe>/i', '', $excerpt);
573
574 // remove WP shortcodes
575 $excerpt = strip_shortcodes($excerpt);
576
577 // remove style/script tags
578 $excerpt = preg_replace('@<(script|style)[^>]*?>.*?</\\1>@si', '', $excerpt);
579
580 // remove blocks that are not appropriate for the excerpt
581 $excerpt = excerpt_remove_blocks($excerpt);
582
583 // remove HTML tags if requested
584 if ( $this->public_options['post-excerpt']['keep_format'] ) {
585 $excerpt = wp_kses(
586 $excerpt,
587 [
588 'a' => [
589 'href' => [],
590 'title' => []
591 ],
592 'em' => [],
593 'strong' => []
594 ]
595 );
596 } else {
597 $excerpt = wp_kses($excerpt, []);
598
599 // remove URLs, too
600 $excerpt = preg_replace('_^(?:(?:https?|ftp)://)(?:\S+(?::\S*)?@)?(?:(?!10(?:\.\d{1,3}){3})(?!127(?:\.\d{1,3}){3})(?!169\.254(?:\.\d{1,3}){2})(?!192\.168(?:\.\d{1,3}){2})(?!172\.(?:1[6-9]|2\d|3[0-1])(?:\.\d{1,3}){2})(?:[1-9]\d?|1\d\d|2[01]\d|22[0-3])(?:\.(?:1?\d{1,2}|2[0-4]\d|25[0-5])){2}(?:\.(?:[1-9]\d?|1\d\d|2[0-4]\d|25[0-4]))|(?:(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)(?:\.(?:[a-z\x{00a1}-\x{ffff}0-9]+-?)*[a-z\x{00a1}-\x{ffff}0-9]+)*(?:\.(?:[a-z\x{00a1}-\x{ffff}]{2,})))(?::\d{2,5})?(?:/[^\s]*)?$_iuS', '', $excerpt);
601 }
602
603 // remove HTML comments
604 $excerpt = preg_replace('/<!--.*?-->/ms', '', $excerpt);
605
606 // remove extra whitespaces
607 $excerpt = preg_replace('/\s\s+/', ' ', $excerpt);
608
609 $excerpt = trim($excerpt);
610
611 }
612
613 // Balance tags, if needed
614 if ( '' !== $excerpt ) {
615
616 $more = $this->public_options['post-excerpt']['words'] ? ' ' . $this->more : $this->more;
617 $more = apply_filters('wpp_excerpt_more', $more);
618 $excerpt = Helper::truncate($excerpt, $this->public_options['post-excerpt']['length'], $this->public_options['post-excerpt']['words'], $more);
619
620 if ( $this->public_options['post-excerpt']['keep_format'] ) {
621 $excerpt = force_balance_tags($excerpt);
622 }
623 }
624
625 return $excerpt;
626 }
627
628 /**
629 * Return post rating.
630 *
631 * @since 3.0.0
632 * @access private
633 * @param object $post_object
634 * @return string
635 */
636 private function get_rating(\stdClass $post_object)
637 {
638 $rating = '';
639
640 if ( function_exists('the_ratings_results') && $this->public_options['rating'] ) {
641 $rating = the_ratings_results($post_object->id);
642 }
643
644 return $rating;
645 }
646
647 /**
648 * Get post date.
649 *
650 * @since 3.0.0
651 * @access private
652 * @param object $post_object
653 * @return string
654 */
655 private function get_date(\stdClass $post_object)
656 {
657 $date = '';
658
659 if ( $this->public_options['stats_tag']['date']['active'] ) {
660 if ( 'relative' == $this->public_options['stats_tag']['date']['format'] ) {
661 $date = sprintf(
662 __('%s ago', 'wordpress-popular-posts'),
663 human_time_diff(
664 strtotime($post_object->date),
665 current_time('timestamp')
666 )
667 );
668 } else {
669 $date = date_i18n(
670 ( 'wp_date_format' == $this->public_options['stats_tag']['date']['format'] ? $this->wp_date_format : $this->public_options['stats_tag']['date']['format'] ),
671 strtotime($post_object->date)
672 );
673 }
674 }
675
676 return apply_filters('wpp_the_date', $date, $post_object->id);
677 }
678
679 /**
680 * Get post taxonomies.
681 *
682 * @since 3.0.0
683 * @access private
684 * @param integer $post_id
685 * @return string
686 */
687 private function get_taxonomies(int $post_id)
688 {
689 $post_tax = '';
690
691 if (
692 (isset($this->public_options['stats_tag']['category']) && $this->public_options['stats_tag']['category'])
693 || $this->public_options['stats_tag']['taxonomy']['active']
694 ) {
695
696 $taxonomy = 'category';
697
698 if (
699 $this->public_options['stats_tag']['taxonomy']['active']
700 && ! empty($this->public_options['stats_tag']['taxonomy']['name'])
701 ) {
702 $taxonomy = $this->public_options['stats_tag']['taxonomy']['name'];
703 }
704
705 $terms = wp_get_post_terms($post_id, $taxonomy);
706
707 if ( ! is_wp_error($terms) ) {
708 // Usage: https://wordpress.stackexchange.com/a/46824
709 if ( has_filter('wpp_post_exclude_terms') ) {
710 $args = apply_filters('wpp_post_exclude_terms', []);
711 $terms = wp_list_filter($terms, $args, 'NOT');
712 }
713
714 $terms = apply_filters('wpp_post_terms', $terms);
715
716 if (
717 is_array($terms)
718 && ! empty($terms)
719 ) {
720 $taxonomy_separator = esc_html(apply_filters('wpp_taxonomy_separator', ', '));
721
722 // We're going to use the taxonomy slug as a CSS class so let's escape it just in case
723 $taxonomy = esc_attr($taxonomy);
724
725 foreach ($terms as $term) {
726 $term_link = get_term_link($term);
727
728 if ( is_wp_error($term_link) ) {
729 continue;
730 }
731
732 $term_link = esc_url($this->translate->url($term_link, $this->translate->get_current_language()));
733 $post_tax .= "<a href=\"{$term_link}\" class=\"wpp-taxonomy {$taxonomy} {$taxonomy}-{$term->term_id}\">" . esc_html($term->name) . '</a>' . $taxonomy_separator;
734 }
735 }
736 }
737
738 if ( '' != $post_tax ) {
739 $post_tax = rtrim($post_tax, $taxonomy_separator);
740 }
741
742 }
743
744 return $post_tax;
745 }
746
747 /**
748 * Get post author.
749 *
750 * @since 3.0.0
751 * @access private
752 * @param object $post_object
753 * @param integer $post_id
754 * @return string
755 */
756 private function get_author(\stdClass $post_object, int $post_id)
757 {
758 $author = ( $this->public_options['stats_tag']['author'] )
759 ? get_the_author_meta('display_name', $post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid)
760 : '';
761
762 return $author;
763 }
764
765 /**
766 * Return post views count.
767 *
768 * @since 3.0.0
769 * @access private
770 * @param object $post_object
771 * @return int|float
772 */
773 private function get_pageviews(\stdClass $post_object)
774 {
775 $pageviews = 0;
776
777 if (
778 (
779 $this->public_options['order_by'] == 'views'
780 || $this->public_options['order_by'] == 'avg'
781 || $this->public_options['stats_tag']['views']
782 )
783 && ( isset($post_object->pageviews) || isset($post_object->avg_views) )
784 ) {
785 $pageviews = ( $this->public_options['order_by'] == 'views' || $this->public_options['order_by'] == 'comments' )
786 ? $post_object->pageviews
787 : $post_object->avg_views;
788 }
789
790 return $pageviews;
791 }
792
793 /**
794 * Return post comment count.
795 *
796 * @since 3.0.0
797 * @access private
798 * @param object $post_object
799 * @return int
800 */
801 private function get_comments(\stdClass $post_object)
802 {
803 $comments = ( ( $this->public_options['order_by'] == 'comments' || $this->public_options['stats_tag']['comment_count'] ) && isset($post_object->comment_count) )
804 ? $post_object->comment_count
805 : 0;
806
807 return $comments;
808 }
809
810 /**
811 * Return post metadata.
812 *
813 * @since 3.0.0
814 * @access private
815 * @param object $post_object
816 * @param integer $post_id
817 * @return array
818 */
819 //private function get_metadata(\stdClass $post_object, $post_id)
820 private function get_metadata(\stdClass $post_object, int $post_id, string $date, string $post_tax, string $author, $pageviews, int $comments) /** @TODO: starting PHP 8.0 $pageviews can be declared as mixed $pageviews */
821 {
822 $stats = [];
823
824 $prettify_numbers = apply_filters('wpp_pretiffy_numbers', true);
825
826 // comments
827 if ( $this->public_options['stats_tag']['comment_count'] ) {
828 $comments_text = sprintf(
829 _n('%s comment', '%s comments', $comments, 'wordpress-popular-posts'),
830 $prettify_numbers ? Helper::prettify_number($comments) : number_format_i18n($comments)
831 );
832
833 $stats['comments'] = '<span class="wpp-comments">' . $comments_text . '</span>';
834 }
835
836 // views
837 if ( $this->public_options['stats_tag']['views'] ) {
838 if ( $this->public_options['order_by'] == 'avg' ) {
839 $views_text = sprintf(
840 _n('%s view per day', '%s views per day', $pageviews, 'wordpress-popular-posts'),
841 $prettify_numbers ? Helper::prettify_number($pageviews, 2) : number_format_i18n($pageviews, (fmod($pageviews, 1) !== 0.0 ? 2 : 0))
842 );
843 }
844 else {
845 $views_text = sprintf(
846 _n('%s view', '%s views', $pageviews, 'wordpress-popular-posts'),
847 $prettify_numbers ? Helper::prettify_number($pageviews) : number_format_i18n($pageviews)
848 );
849 }
850
851 $stats['views'] = '<span class="wpp-views">' . $views_text . '</span>';
852 }
853
854 // author
855 if ( $this->public_options['stats_tag']['author'] ) {
856 $author_url = get_author_posts_url($post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid);
857 $display_name = '<a href="' . esc_url($this->translate->url($author_url, $this->translate->get_current_language())) . '">' . esc_html($author) . '</a>';
858 $stats['author'] = '<span class="wpp-author">' . sprintf(__('by %s', 'wordpress-popular-posts'), $display_name) . '</span>';
859 }
860
861 // date
862 if ( $this->public_options['stats_tag']['date']['active'] ) {
863 $stats['date'] = '<span class="wpp-date">' . ( 'relative' == $this->public_options['stats_tag']['date']['format'] ? sprintf(__('posted %s', 'wordpress-popular-posts'), $date) : sprintf(__('posted on %s', 'wordpress-popular-posts'), $date) ) . '</span>';
864 }
865
866 // taxonomy
867 if ( ($this->public_options['stats_tag']['category'] || $this->public_options['stats_tag']['taxonomy']['active']) && $post_tax != '' ) {
868 $stats['taxonomy'] = '<span class="wpp-category">' . sprintf(__('under %s', 'wordpress-popular-posts'), $post_tax) . '</span>';
869 }
870
871 return $stats;
872 }
873
874 /**
875 * Parse content tags.
876 *
877 * @since 1.4.6
878 * @access private
879 * @param string HTML string with content tags
880 * @param array Post data
881 * @param bool Used to display post rating (if functionality is available)
882 * @return string
883 */
884 private function format_content(string $string, array $data, bool $rating) {
885
886 if ( empty($string) || ( empty($data) || ! is_array($data) ) ) {
887 return false;
888 }
889
890 $params = [];
891 $pattern = '/\{(pid|current_class|excerpt|summary|meta|stats|title|title_attr|image|thumb|thumb_img|thumb_url|rating|score|url|text_title|author|author_copy|author_name|author_url|taxonomy|taxonomy_copy|category|category_copy|views|views_copy|comments|comments_copy|date|date_copy|total_items|item_position)\}/i';
892 preg_match_all($pattern, $string, $matches);
893
894 array_map('strtolower', $matches[0]);
895
896 if ( in_array('{pid}', $matches[0]) ) {
897 $string = str_replace('{pid}', $data['id'], $string);
898 }
899
900 if ( in_array('{current_class}', $matches[0]) ) {
901 $string = str_replace('{current_class}', ( $data['is_current_post'] ? 'current' : '' ), $string);
902 }
903
904 if ( in_array('{title}', $matches[0]) ) {
905 $string = str_replace('{title}', $data['title'], $string);
906 }
907
908 if ( in_array('{title_attr}', $matches[0]) ) {
909 $string = str_replace('{title_attr}', $data['title_attr'], $string);
910 }
911
912 if ( in_array('{meta}', $matches[0]) || in_array('{stats}', $matches[0]) ) {
913 $string = str_replace(['{meta}', '{stats}'], $data['stats'], $string);
914 }
915
916 if ( in_array('{excerpt}', $matches[0]) || in_array('{summary}', $matches[0]) ) {
917 $string = str_replace(['{excerpt}', '{summary}'], $data['summary'], $string);
918 }
919
920 if ( in_array('{image}', $matches[0]) || in_array('{thumb}', $matches[0]) ) {
921 $string = str_replace(['{image}', '{thumb}'], $data['img'], $string);
922 }
923
924 if ( in_array('{thumb_img}', $matches[0]) ) {
925 $string = str_replace('{thumb_img}', $data['img_no_link'], $string);
926 }
927
928 if ( in_array('{thumb_url}', $matches[0]) && ! empty($data['img_no_link']) ) {
929 $dom = new \DOMDocument();
930
931 if ( $dom->loadHTML($data['img_no_link']) ) {
932 $img_tag = $dom->getElementsByTagName('img');
933
934 if ( $img_tag->length ) {
935 foreach( $img_tag as $node ) {
936 if ( $node->hasAttribute('src') ) {
937 $src = $node->getAttribute('src');
938 $string = str_replace('{thumb_url}', $src, $string);
939 }
940 }
941 }
942 }
943 }
944
945 // WP-PostRatings check
946 if ( $rating ) {
947 if ( function_exists('the_ratings_results') && in_array('{rating}', $matches[0]) ) {
948 $string = str_replace('{rating}', the_ratings_results($data['id']), $string);
949 }
950
951 if ( function_exists('expand_ratings_template') && in_array('{score}', $matches[0]) ) {
952 $string = str_replace('{score}', expand_ratings_template('%RATINGS_SCORE%', $data['id']), $string);
953 // removing the redundant plus sign
954 $string = str_replace('+', '', $string);
955 }
956 }
957
958 if ( in_array('{url}', $matches[0]) ) {
959 $string = str_replace('{url}', $data['url'], $string);
960 }
961
962 if ( in_array('{text_title}', $matches[0]) ) {
963 $string = str_replace('{text_title}', $data['text_title'], $string);
964 }
965
966 if ( in_array('{author}', $matches[0]) ) {
967 $string = str_replace('{author}', $data['author'], $string);
968 }
969
970 if ( in_array('{author_copy}', $matches[0]) ) {
971 $string = str_replace('{author_copy}', $data['author_copy'], $string);
972 }
973
974 if ( in_array('{author_name}', $matches[0]) ) {
975 $string = str_replace('{author_name}', $data['author_name'], $string);
976 }
977
978 if ( in_array('{author_url}', $matches[0]) ) {
979 $string = str_replace('{author_url}', $data['author_url'], $string);
980 }
981
982 if ( in_array('{taxonomy}', $matches[0]) || in_array('{category}', $matches[0]) ) {
983 $string = str_replace(['{taxonomy}', '{category}'], $data['taxonomy'], $string);
984 }
985
986 if ( in_array('{taxonomy_copy}', $matches[0]) || in_array('{category_copy}', $matches[0]) ) {
987 $string = str_replace(['{taxonomy_copy}', '{category_copy}'], $data['taxonomy_copy'], $string);
988 }
989
990 if ( in_array('{views}', $matches[0]) ) {
991 $string = str_replace('{views}', $data['views'], $string);
992 }
993
994 if ( in_array('{views_copy}', $matches[0]) ) {
995 $string = str_replace('{views_copy}', $data['views_copy'], $string);
996 }
997
998 if ( in_array('{comments}', $matches[0]) ) {
999 $string = str_replace('{comments}', $data['comments'], $string);
1000 }
1001
1002 if ( in_array('{comments_copy}', $matches[0]) ) {
1003 $string = str_replace('{comments_copy}', $data['comments_copy'], $string);
1004 }
1005
1006 if ( in_array('{date}', $matches[0]) ) {
1007 $string = str_replace('{date}', $data['date'], $string);
1008 }
1009
1010 if ( in_array('{date_copy}', $matches[0]) ) {
1011 $string = str_replace('{date_copy}', $data['date_copy'], $string);
1012 }
1013
1014 if ( in_array('{total_items}', $matches[0]) ) {
1015 $string = str_replace('{total_items}', $data['total_items'], $string);
1016 }
1017
1018 if ( in_array('{item_position}', $matches[0]) ) {
1019 $string = str_replace('{item_position}', $data['item_position'], $string);
1020 }
1021
1022 return apply_filters('wpp_parse_custom_content_tags', $string, $data['id']);
1023 }
1024
1025 /**
1026 * Checks whether we're currently seeing a single post/page/CPT.
1027 *
1028 * @since 5.0.0
1029 * @return int
1030 */
1031 public function is_single()
1032 {
1033 return apply_filters('wpp_is_single', Helper::is_single());
1034 }
1035 }
1036