PluginProbe ʕ •ᴥ•ʔ
WP Popular Posts / 6.2.1
WP Popular Posts v6.2.1
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
1058 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(mb_convert_encoding($html, 'HTML-ENTITIES', 'UTF-8'), LIBXML_NOERROR | LIBXML_NOWARNING | LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
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 // Sanitize HTML
184 $allowed_tags = wp_kses_allowed_html('post');
185
186 if ( isset($allowed_tags['form']) ) {
187 unset($allowed_tags['form']);
188 }
189
190 if (
191 isset($this->public_options['theme']['name'])
192 && $this->public_options['theme']['name']
193 ) {
194 $allowed_tags['style'] = [
195 'id' => 1,
196 'nonce' => 1,
197 ];
198 }
199
200 $allowed_tags['img']['decoding'] = true;
201 $allowed_tags['img']['srcset'] = true;
202
203 $this->output = wp_kses($this->output, $allowed_tags);
204
205 return $this->output;
206 }
207
208 /**
209 * Build the HTML output.
210 *
211 * @since 4.0.0
212 */
213 public function build_output()
214 {
215 // Got some posts, format 'em!
216 if ( ! empty($this->data) ) {
217
218 $this->output = '';
219
220 // Allow WP themers / coders access to raw data
221 // so they can build their own output
222 if ( has_filter('wpp_custom_html') ) {
223 $this->output .= apply_filters('wpp_custom_html', $this->data, $this->public_options);
224 return;
225 }
226
227 if (
228 isset($this->public_options['theme']['name'])
229 && $this->public_options['theme']['name']
230 ) {
231 $this->output .= '<div class="popular-posts-sr">';
232
233 if ( @file_exists(get_stylesheet_directory() . '/wordpress-popular-posts/themes/' . $this->public_options['theme']['name'] . '/style.css') ) {
234 $theme_stylesheet = get_stylesheet_directory() . '/wordpress-popular-posts/themes/' . $this->public_options['theme']['name'] . '/style.css';
235 } else {
236 $theme_stylesheet = $this->themer->get_theme($this->public_options['theme']['name'])['path'] . '/style.css';
237 }
238
239 $theme_css_rules = wp_strip_all_tags(file_get_contents($theme_stylesheet), true);
240 $additional_styles = '';
241
242 if ( has_filter('wpp_additional_theme_styles') ) {
243 $additional_styles = wp_strip_all_tags(apply_filters('wpp_additional_theme_styles', '', $this->public_options['theme']['name']), true);
244
245 if ( $additional_styles ) {
246 $additional_styles = ' /* additional rules */ ' . $additional_styles;
247 }
248 }
249
250 $this->output .= '<style>' . $theme_css_rules . $additional_styles . '</style>';
251 }
252
253 /* Open HTML wrapper */
254 // Output a custom wrapper
255 if (
256 isset($this->public_options['markup']['custom_html'])
257 && $this->public_options['markup']['custom_html']
258 && isset($this->public_options['markup']['wpp-start'])
259 && isset($this->public_options['markup']['wpp-end'])
260 ){
261 $this->output .= "\n" . htmlspecialchars_decode($this->public_options['markup']['wpp-start'], ENT_QUOTES) . "\n";
262 }
263 // Output the default wrapper
264 else {
265
266 $classes = 'wpp-list';
267
268 if ( $this->public_options['thumbnail']['active'] ) {
269 $classes .= ' wpp-list-with-thumbnails';
270 }
271
272 $this->output .= "\n<ul class=\"{$classes}\">\n";
273
274 }
275
276 $position = 0;
277
278 // Format each post
279 foreach( $this->data as $post_object ) {
280 $position++;
281 $this->output .= $this->render_post($post_object, $position);
282 }
283
284 /* Close HTML wrapper */
285 // Output a custom wrapper
286 if (
287 isset($this->public_options['markup']['custom_html'])
288 && $this->public_options['markup']['custom_html']
289 && isset($this->public_options['markup']['wpp-start'])
290 && isset($this->public_options['markup']['wpp-end'])
291 ){
292 $this->output .= "\n" . htmlspecialchars_decode($this->public_options['markup']['wpp-end'], ENT_QUOTES) . "\n";
293 }
294 // Output default wrapper
295 else {
296 $this->output .= '</ul>' . "\n";
297 }
298
299 if (
300 isset($this->public_options['theme']['name'])
301 && $this->public_options['theme']['name']
302 ) {
303 $this->output .= '</div>';
304 }
305
306 }
307 // Got nothing to show, give 'em the old "Sorry. No data so far." message!
308 else {
309 $this->output = apply_filters('wpp_no_data', '<p class="wpp-no-data">' . __('Sorry. No data so far.', 'wordpress-popular-posts') . '</p>');
310 }
311 }
312
313 /**
314 * Build the HTML markup for a single post.
315 *
316 * @since 4.0.0
317 * @access private
318 * @param object $post_object
319 * @param integer $position
320 * @return string
321 */
322 private function render_post(\stdClass $post_object, int $position = 1)
323 {
324 $is_single = $this->is_single();
325 $post = '';
326 $post_id = $post_object->id;
327 $trid = $this->translate->get_object_id(
328 $post_object->id,
329 get_post_type($post_object->id)
330 );
331
332 if ( $post_id != $trid ) {
333 $post_id = $trid;
334 }
335
336 $is_current_post = ( $is_single && ($is_single == $post_id || $is_single == $post_object->id) ) ? true : false;
337
338 // Permalink
339 $permalink = esc_url($this->get_permalink($post_object, $post_id));
340
341 // Post title (and title attribute)
342 $post_title_attr = esc_attr(wp_strip_all_tags($this->get_title($post_object, $post_id)));
343 $post_title = $this->get_title($post_object, $post_id);
344
345 if ( $this->public_options['shorten_title']['active'] ) {
346 $length = ( filter_var($this->public_options['shorten_title']['length'], FILTER_VALIDATE_INT) && $this->public_options['shorten_title']['length'] > 0 )
347 ? $this->public_options['shorten_title']['length']
348 : 25;
349
350 $more = $this->public_options['shorten_title']['words'] ? ' ' . $this->more : $this->more;
351 $more = apply_filters('wpp_title_more', $more);
352 $post_title = Helper::truncate($post_title, $length, $this->public_options['shorten_title']['words'], $more);
353 }
354
355 // Thumbnail
356 $post_thumbnail = $this->get_thumbnail($post_id);
357
358 // Post excerpt
359 $post_excerpt = $this->get_excerpt($post_object, $post_id);
360
361 // Post rating
362 $post_rating = $this->get_rating($post_object);
363
364 /**
365 * Post meta
366 */
367
368 // Post date
369 $post_date = $this->get_date($post_object);
370
371 // Post taxonomies
372 $post_taxonomies = $this->get_taxonomies($post_id);
373
374 // Post author
375 $post_author = $this->get_author($post_object, $post_id);
376
377 // Post views count
378 $post_views = $this->get_pageviews($post_object);
379
380 // Post comments count
381 $post_comments = $this->get_comments($post_object);
382
383 // Post meta
384 $meta_arr = $this->get_metadata(
385 $post_object,
386 $post_id,
387 $post_date,
388 $post_taxonomies,
389 $post_author,
390 $post_views,
391 $post_comments
392 );
393
394 if (
395 is_array($meta_arr)
396 && ! empty($meta_arr)
397 && 'views' == $this->public_options['order_by']
398 ) {
399 $keys = ['views', 'comments', 'author', 'date', 'taxonomy'];
400 $new_meta_arr = [];
401
402 foreach($keys as $key) {
403 if ( isset($meta_arr[$key])) {
404 $new_meta_arr[$key] = $meta_arr[$key];
405 }
406 }
407
408 if ( ! empty($new_meta_arr) ) {
409 $meta_arr = $new_meta_arr;
410 }
411 }
412
413 $post_meta_separator = esc_html(apply_filters('wpp_post_meta_separator', ' | '));
414 $post_meta = join($post_meta_separator, $meta_arr);
415
416 $prettify_numbers = apply_filters('wpp_pretiffy_numbers', true);
417
418 // Build custom HTML output
419 if ( $this->public_options['markup']['custom_html'] ) {
420 $data = [
421 'id' => $post_id,
422 'is_current_post' => $is_current_post,
423 '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>',
424 'title_attr' => $post_title_attr,
425 'summary' => $post_excerpt,
426 'stats' => $post_meta,
427 '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>' : '',
428 'img_no_link' => $post_thumbnail,
429 'url' => $permalink,
430 'text_title' => $post_title,
431 'taxonomy' => $post_taxonomies,
432 'taxonomy_copy' => isset($meta_arr['taxonomy']) ? $meta_arr['taxonomy'] : null,
433 '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>' : '',
434 'author_copy' => isset($meta_arr['author']) ? $meta_arr['author'] : null,
435 'author_name' => esc_html($post_author),
436 '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)) : '',
437 '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)),
438 'views_copy' => isset($meta_arr['views']) ? $meta_arr['views'] : null,
439 'comments' => $prettify_numbers ? Helper::prettify_number($post_comments) : number_format_i18n($post_comments),
440 'comments_copy' => isset($meta_arr['comments']) ? $meta_arr['comments'] : null,
441 'date' => $post_date,
442 'date_copy' => isset($meta_arr['date']) ? $meta_arr['date'] : null,
443 'total_items' => count($this->data),
444 'item_position' => $position
445 ];
446 $post = $this->format_content(htmlspecialchars_decode($this->public_options['markup']['post-html'], ENT_QUOTES), $data, $this->public_options['rating']) . "\n";
447 } // Use the "stock" HTML output
448 else {
449 $wpp_post_class = [];
450
451 if ( $is_current_post ) {
452 $wpp_post_class[] = 'current';
453 }
454
455 // Allow themers / plugin developer
456 // to add custom classes to each post
457 $wpp_post_class = apply_filters('wpp_post_class', $wpp_post_class, $post_id);
458
459 $post_thumbnail = ( ! empty($post_thumbnail) )
460 ? "<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"
461 : '';
462
463 $post_excerpt = ( ! empty($post_excerpt) )
464 ? " <span class=\"wpp-excerpt\">{$post_excerpt}</span>\n"
465 : '';
466
467 $post_meta = ( ! empty($post_meta) )
468 ? " <span class=\"wpp-meta post-stats\">{$post_meta}</span>\n"
469 : '';
470
471 $post_rating = ( ! empty($post_rating) )
472 ? " <span class=\"wpp-rating\">{$post_rating}</span>\n"
473 : '';
474
475 $post =
476 '<li' . ( ( is_array($wpp_post_class) && ! empty($wpp_post_class) ) ? ' class="' . esc_attr(implode(' ', $wpp_post_class)) . '"' : '') . ">\n"
477 . $post_thumbnail
478 . "<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"
479 . $post_excerpt
480 . $post_meta
481 . $post_rating
482 . "</li>\n";
483 }
484
485 return apply_filters('wpp_post', $post, $post_object, $this->public_options);
486 }
487
488 /**
489 * Return the processed post/page title.
490 *
491 * @since 3.0.0
492 * @access private
493 * @param object $post_object
494 * @param integer $post_id
495 * @return string
496 */
497 private function get_title(\stdClass $post_object, int $post_id)
498 {
499 $title = '';
500
501 if ( $post_object->id != $post_id ) {
502 $title = get_the_title($post_id);
503 } else {
504 $title = $post_object->title;
505 }
506
507 // Run the_title filter so core/plugin title hooks can
508 // be applied to the post title
509 $title = apply_filters('the_title', $title, $post_object->id);
510
511 return apply_filters('wpp_the_title', $title, $post_object->id, $post_id);
512 }
513
514 /**
515 * Return the permalink.
516 *
517 * @since 4.0.12
518 * @access private
519 * @param object $post_object
520 * @param integer $post_id
521 * @return string
522 */
523 private function get_permalink(\stdClass $post_object, int $post_id) {
524 if ( $post_object->id != $post_id ) {
525 return get_permalink($post_id);
526 }
527
528 return get_permalink($post_object->id);
529 }
530
531 /**
532 * Return the processed thumbnail.
533 *
534 * @since 3.0.0
535 * @access private
536 * @param int $post_id
537 * @return string
538 */
539 private function get_thumbnail(int $post_id)
540 {
541 $thumbnail = '';
542
543 if ( $this->public_options['thumbnail']['active'] ) {
544 $thumbnail = $this->thumbnail->get(
545 $post_id,
546 [
547 $this->public_options['thumbnail']['width'],
548 $this->public_options['thumbnail']['height']
549 ],
550 $this->admin_options['tools']['thumbnail']['source'],
551 $this->public_options['thumbnail']['crop'],
552 $this->public_options['thumbnail']['build']
553 );
554 }
555
556 return $thumbnail;
557 }
558
559 /**
560 * Return post excerpt.
561 *
562 * @since 3.0.0
563 * @access private
564 * @param object $post_object
565 * @param integer $post_id
566 * @return string
567 */
568 private function get_excerpt(\stdClass $post_object, int $post_id)
569 {
570 $excerpt = '';
571
572 if ( $this->public_options['post-excerpt']['active'] ) {
573
574 if ( $post_object->id != $post_id ) {
575 $the_post = get_post($post_id);
576
577 $excerpt = ( empty($the_post->post_excerpt) )
578 ? $the_post->post_content
579 : $the_post->post_excerpt;
580 }
581 else {
582 $excerpt = ( empty($post_object->post_excerpt) )
583 ? $post_object->post_content
584 : $post_object->post_excerpt;
585 }
586
587 // remove caption tags
588 $excerpt = preg_replace('/\[caption.*\[\/caption\]/', '', $excerpt);
589
590 // remove Flash objects
591 $excerpt = preg_replace("/<object[0-9 a-z_?*=\":\-\/\.#\,\\n\\r\\t]+/smi", '', $excerpt);
592
593 // remove iframes
594 $excerpt = preg_replace('/<iframe.*?\/iframe>/i', '', $excerpt);
595
596 // remove WP shortcodes
597 $excerpt = strip_shortcodes($excerpt);
598
599 // remove style/script tags
600 $excerpt = preg_replace('@<(script|style)[^>]*?>.*?</\\1>@si', '', $excerpt);
601
602 // remove blocks that are not appropriate for the excerpt
603 $excerpt = excerpt_remove_blocks($excerpt);
604
605 // remove HTML tags if requested
606 if ( $this->public_options['post-excerpt']['keep_format'] ) {
607 $excerpt = wp_kses(
608 $excerpt,
609 [
610 'a' => [
611 'href' => [],
612 'title' => []
613 ],
614 'em' => [],
615 'strong' => []
616 ]
617 );
618 } else {
619 $excerpt = wp_kses($excerpt, []);
620
621 // remove URLs, too
622 $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);
623 }
624
625 // remove HTML comments
626 $excerpt = preg_replace('/<!--.*?-->/ms', '', $excerpt);
627
628 // remove extra whitespaces
629 $excerpt = preg_replace('/\s\s+/', ' ', $excerpt);
630
631 $excerpt = trim($excerpt);
632
633 }
634
635 // Balance tags, if needed
636 if ( '' !== $excerpt ) {
637
638 $more = $this->public_options['post-excerpt']['words'] ? ' ' . $this->more : $this->more;
639 $more = apply_filters('wpp_excerpt_more', $more);
640 $excerpt = Helper::truncate($excerpt, $this->public_options['post-excerpt']['length'], $this->public_options['post-excerpt']['words'], $more);
641
642 if ( $this->public_options['post-excerpt']['keep_format'] ) {
643 $excerpt = force_balance_tags($excerpt);
644 }
645 }
646
647 return $excerpt;
648 }
649
650 /**
651 * Return post rating.
652 *
653 * @since 3.0.0
654 * @access private
655 * @param object $post_object
656 * @return string
657 */
658 private function get_rating(\stdClass $post_object)
659 {
660 $rating = '';
661
662 if ( function_exists('the_ratings_results') && $this->public_options['rating'] ) {
663 $rating = the_ratings_results($post_object->id);
664 }
665
666 return $rating;
667 }
668
669 /**
670 * Get post date.
671 *
672 * @since 3.0.0
673 * @access private
674 * @param object $post_object
675 * @return string
676 */
677 private function get_date(\stdClass $post_object)
678 {
679 $date = '';
680
681 if ( $this->public_options['stats_tag']['date']['active'] ) {
682 if ( 'relative' == $this->public_options['stats_tag']['date']['format'] ) {
683 $date = sprintf(
684 __('%s ago', 'wordpress-popular-posts'),
685 human_time_diff(
686 strtotime($post_object->date),
687 current_time('timestamp')
688 )
689 );
690 } else {
691 $date = date_i18n(
692 ( 'wp_date_format' == $this->public_options['stats_tag']['date']['format'] ? $this->wp_date_format : $this->public_options['stats_tag']['date']['format'] ),
693 strtotime($post_object->date)
694 );
695 }
696 }
697
698 return apply_filters('wpp_the_date', $date, $post_object->id);
699 }
700
701 /**
702 * Get post taxonomies.
703 *
704 * @since 3.0.0
705 * @access private
706 * @param integer $post_id
707 * @return string
708 */
709 private function get_taxonomies(int $post_id)
710 {
711 $post_tax = '';
712
713 if (
714 (isset($this->public_options['stats_tag']['category']) && $this->public_options['stats_tag']['category'])
715 || $this->public_options['stats_tag']['taxonomy']['active']
716 ) {
717
718 $taxonomy = 'category';
719
720 if (
721 $this->public_options['stats_tag']['taxonomy']['active']
722 && ! empty($this->public_options['stats_tag']['taxonomy']['name'])
723 ) {
724 $taxonomy = $this->public_options['stats_tag']['taxonomy']['name'];
725 }
726
727 $terms = wp_get_post_terms($post_id, $taxonomy);
728
729 if ( ! is_wp_error($terms) ) {
730 // Usage: https://wordpress.stackexchange.com/a/46824
731 if ( has_filter('wpp_post_exclude_terms') ) {
732 $args = apply_filters('wpp_post_exclude_terms', []);
733 $terms = wp_list_filter($terms, $args, 'NOT');
734 }
735
736 $terms = apply_filters('wpp_post_terms', $terms);
737
738 if (
739 is_array($terms)
740 && ! empty($terms)
741 ) {
742 $taxonomy_separator = esc_html(apply_filters('wpp_taxonomy_separator', ', '));
743
744 // We're going to use the taxonomy slug as a CSS class so let's escape it just in case
745 $taxonomy = esc_attr($taxonomy);
746
747 foreach ($terms as $term) {
748 $term_link = get_term_link($term);
749
750 if ( is_wp_error($term_link) ) {
751 continue;
752 }
753
754 $term_link = esc_url($this->translate->url($term_link, $this->translate->get_current_language()));
755 $post_tax .= "<a href=\"{$term_link}\" class=\"wpp-taxonomy {$taxonomy} {$taxonomy}-{$term->term_id}\">" . esc_html($term->name) . '</a>' . $taxonomy_separator;
756 }
757 }
758 }
759
760 if ( '' != $post_tax ) {
761 $post_tax = rtrim($post_tax, $taxonomy_separator);
762 }
763
764 }
765
766 return $post_tax;
767 }
768
769 /**
770 * Get post author.
771 *
772 * @since 3.0.0
773 * @access private
774 * @param object $post_object
775 * @param integer $post_id
776 * @return string
777 */
778 private function get_author(\stdClass $post_object, int $post_id)
779 {
780 $author = ( $this->public_options['stats_tag']['author'] )
781 ? get_the_author_meta('display_name', $post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid)
782 : '';
783
784 return $author;
785 }
786
787 /**
788 * Return post views count.
789 *
790 * @since 3.0.0
791 * @access private
792 * @param object $post_object
793 * @return int|float
794 */
795 private function get_pageviews(\stdClass $post_object)
796 {
797 $pageviews = 0;
798
799 if (
800 (
801 $this->public_options['order_by'] == 'views'
802 || $this->public_options['order_by'] == 'avg'
803 || $this->public_options['stats_tag']['views']
804 )
805 && ( isset($post_object->pageviews) || isset($post_object->avg_views) )
806 ) {
807 $pageviews = ( $this->public_options['order_by'] == 'views' || $this->public_options['order_by'] == 'comments' )
808 ? $post_object->pageviews
809 : $post_object->avg_views;
810 }
811
812 return $pageviews;
813 }
814
815 /**
816 * Return post comment count.
817 *
818 * @since 3.0.0
819 * @access private
820 * @param object $post_object
821 * @return int
822 */
823 private function get_comments(\stdClass $post_object)
824 {
825 $comments = ( ( $this->public_options['order_by'] == 'comments' || $this->public_options['stats_tag']['comment_count'] ) && isset($post_object->comment_count) )
826 ? $post_object->comment_count
827 : 0;
828
829 return $comments;
830 }
831
832 /**
833 * Return post metadata.
834 *
835 * @since 3.0.0
836 * @access private
837 * @param object $post_object
838 * @param integer $post_id
839 * @return array
840 */
841 //private function get_metadata(\stdClass $post_object, $post_id)
842 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 */
843 {
844 $stats = [];
845
846 $prettify_numbers = apply_filters('wpp_pretiffy_numbers', true);
847
848 // comments
849 if ( $this->public_options['stats_tag']['comment_count'] ) {
850 $comments_text = sprintf(
851 _n('%s comment', '%s comments', $comments, 'wordpress-popular-posts'),
852 $prettify_numbers ? Helper::prettify_number($comments) : number_format_i18n($comments)
853 );
854
855 $stats['comments'] = '<span class="wpp-comments">' . $comments_text . '</span>';
856 }
857
858 // views
859 if ( $this->public_options['stats_tag']['views'] ) {
860 if ( $this->public_options['order_by'] == 'avg' ) {
861 $views_text = sprintf(
862 _n('%s view per day', '%s views per day', $pageviews, 'wordpress-popular-posts'),
863 $prettify_numbers ? Helper::prettify_number($pageviews, 2) : number_format_i18n($pageviews, (fmod($pageviews, 1) !== 0.0 ? 2 : 0))
864 );
865 }
866 else {
867 $views_text = sprintf(
868 _n('%s view', '%s views', $pageviews, 'wordpress-popular-posts'),
869 $prettify_numbers ? Helper::prettify_number($pageviews) : number_format_i18n($pageviews)
870 );
871 }
872
873 $stats['views'] = '<span class="wpp-views">' . $views_text . '</span>';
874 }
875
876 // author
877 if ( $this->public_options['stats_tag']['author'] ) {
878 $author_url = get_author_posts_url($post_object->uid != $post_id ? get_post_field('post_author', $post_id) : $post_object->uid);
879 $display_name = '<a href="' . esc_url($this->translate->url($author_url, $this->translate->get_current_language())) . '">' . esc_html($author) . '</a>';
880 $stats['author'] = '<span class="wpp-author">' . sprintf(__('by %s', 'wordpress-popular-posts'), $display_name) . '</span>';
881 }
882
883 // date
884 if ( $this->public_options['stats_tag']['date']['active'] ) {
885 $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>';
886 }
887
888 // taxonomy
889 if ( ($this->public_options['stats_tag']['category'] || $this->public_options['stats_tag']['taxonomy']['active']) && $post_tax != '' ) {
890 $stats['taxonomy'] = '<span class="wpp-category">' . sprintf(__('under %s', 'wordpress-popular-posts'), $post_tax) . '</span>';
891 }
892
893 return $stats;
894 }
895
896 /**
897 * Parse content tags.
898 *
899 * @since 1.4.6
900 * @access private
901 * @param string HTML string with content tags
902 * @param array Post data
903 * @param bool Used to display post rating (if functionality is available)
904 * @return string
905 */
906 private function format_content(string $string, array $data, bool $rating) {
907
908 if ( empty($string) || ( empty($data) || ! is_array($data) ) ) {
909 return false;
910 }
911
912 $params = [];
913 $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';
914 preg_match_all($pattern, $string, $matches);
915
916 array_map('strtolower', $matches[0]);
917
918 if ( in_array('{pid}', $matches[0]) ) {
919 $string = str_replace('{pid}', $data['id'], $string);
920 }
921
922 if ( in_array('{current_class}', $matches[0]) ) {
923 $string = str_replace('{current_class}', ( $data['is_current_post'] ? 'current' : '' ), $string);
924 }
925
926 if ( in_array('{title}', $matches[0]) ) {
927 $string = str_replace('{title}', $data['title'], $string);
928 }
929
930 if ( in_array('{title_attr}', $matches[0]) ) {
931 $string = str_replace('{title_attr}', $data['title_attr'], $string);
932 }
933
934 if ( in_array('{meta}', $matches[0]) || in_array('{stats}', $matches[0]) ) {
935 $string = str_replace(['{meta}', '{stats}'], $data['stats'], $string);
936 }
937
938 if ( in_array('{excerpt}', $matches[0]) || in_array('{summary}', $matches[0]) ) {
939 $string = str_replace(['{excerpt}', '{summary}'], $data['summary'], $string);
940 }
941
942 if ( in_array('{image}', $matches[0]) || in_array('{thumb}', $matches[0]) ) {
943 $string = str_replace(['{image}', '{thumb}'], $data['img'], $string);
944 }
945
946 if ( in_array('{thumb_img}', $matches[0]) ) {
947 $string = str_replace('{thumb_img}', $data['img_no_link'], $string);
948 }
949
950 if ( in_array('{thumb_url}', $matches[0]) && ! empty($data['img_no_link']) ) {
951 $dom = new \DOMDocument();
952
953 if ( $dom->loadHTML($data['img_no_link']) ) {
954 $img_tag = $dom->getElementsByTagName('img');
955
956 if ( $img_tag->length ) {
957 foreach( $img_tag as $node ) {
958 if ( $node->hasAttribute('src') ) {
959 $src = $node->getAttribute('src');
960 $string = str_replace('{thumb_url}', $src, $string);
961 }
962 }
963 }
964 }
965 }
966
967 // WP-PostRatings check
968 if ( $rating ) {
969 if ( function_exists('the_ratings_results') && in_array('{rating}', $matches[0]) ) {
970 $string = str_replace('{rating}', the_ratings_results($data['id']), $string);
971 }
972
973 if ( function_exists('expand_ratings_template') && in_array('{score}', $matches[0]) ) {
974 $string = str_replace('{score}', expand_ratings_template('%RATINGS_SCORE%', $data['id']), $string);
975 // removing the redundant plus sign
976 $string = str_replace('+', '', $string);
977 }
978 }
979
980 if ( in_array('{url}', $matches[0]) ) {
981 $string = str_replace('{url}', $data['url'], $string);
982 }
983
984 if ( in_array('{text_title}', $matches[0]) ) {
985 $string = str_replace('{text_title}', $data['text_title'], $string);
986 }
987
988 if ( in_array('{author}', $matches[0]) ) {
989 $string = str_replace('{author}', $data['author'], $string);
990 }
991
992 if ( in_array('{author_copy}', $matches[0]) ) {
993 $string = str_replace('{author_copy}', $data['author_copy'], $string);
994 }
995
996 if ( in_array('{author_name}', $matches[0]) ) {
997 $string = str_replace('{author_name}', $data['author_name'], $string);
998 }
999
1000 if ( in_array('{author_url}', $matches[0]) ) {
1001 $string = str_replace('{author_url}', $data['author_url'], $string);
1002 }
1003
1004 if ( in_array('{taxonomy}', $matches[0]) || in_array('{category}', $matches[0]) ) {
1005 $string = str_replace(['{taxonomy}', '{category}'], $data['taxonomy'], $string);
1006 }
1007
1008 if ( in_array('{taxonomy_copy}', $matches[0]) || in_array('{category_copy}', $matches[0]) ) {
1009 $string = str_replace(['{taxonomy_copy}', '{category_copy}'], $data['taxonomy_copy'], $string);
1010 }
1011
1012 if ( in_array('{views}', $matches[0]) ) {
1013 $string = str_replace('{views}', $data['views'], $string);
1014 }
1015
1016 if ( in_array('{views_copy}', $matches[0]) ) {
1017 $string = str_replace('{views_copy}', $data['views_copy'], $string);
1018 }
1019
1020 if ( in_array('{comments}', $matches[0]) ) {
1021 $string = str_replace('{comments}', $data['comments'], $string);
1022 }
1023
1024 if ( in_array('{comments_copy}', $matches[0]) ) {
1025 $string = str_replace('{comments_copy}', $data['comments_copy'], $string);
1026 }
1027
1028 if ( in_array('{date}', $matches[0]) ) {
1029 $string = str_replace('{date}', $data['date'], $string);
1030 }
1031
1032 if ( in_array('{date_copy}', $matches[0]) ) {
1033 $string = str_replace('{date_copy}', $data['date_copy'], $string);
1034 }
1035
1036 if ( in_array('{total_items}', $matches[0]) ) {
1037 $string = str_replace('{total_items}', $data['total_items'], $string);
1038 }
1039
1040 if ( in_array('{item_position}', $matches[0]) ) {
1041 $string = str_replace('{item_position}', $data['item_position'], $string);
1042 }
1043
1044 return apply_filters('wpp_parse_custom_content_tags', $string, $data['id']);
1045 }
1046
1047 /**
1048 * Checks whether we're currently seeing a single post/page/CPT.
1049 *
1050 * @since 5.0.0
1051 * @return int
1052 */
1053 public function is_single()
1054 {
1055 return apply_filters('wpp_is_single', Helper::is_single());
1056 }
1057 }
1058