PluginProbe
Related Posts Thumbnails Plugin for WordPress / trunk
Related Posts Thumbnails Plugin for WordPress vtrunk
5.0.1 1.9.2 2.0.0 2.0.1 2.0.2 2.0.3 2.1.0 2.2.0 3.0.0 3.0.1 3.0.2 4.0.0 4.0.1 4.1.0 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.3.3 5.0.0 trunk 1.0 1.1 1.1.1 All 57 releases
related-posts-thumbnails / related-posts-thumbnails.php

related-posts-thumbnails.php in Related Posts Thumbnails Plugin for WordPress trunk, at related-posts-thumbnails.php

2,165 lines 76.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Plugin Name: Related Posts Thumbnails
4 * Plugin URI: https://wpbrigade.com/wordpress/plugins/related-posts/?utm_source=related-posts-lite&utm_medium=plugin-uri&utm_campaign=pro-upgrade-rp
5 * Description: Showing related posts thumbnails under the posts.
6 * Version: 5.0.1
7 * Author: WPBrigade
8 * Author URI: https://WPBrigade.com/?utm_source=related-posts-lite&utm_medium=author-link&utm_campaign=pro-upgrade-rp
9 * GitHub Plugin URI: https://github.com/WPBrigade/related-posts-thumbnails
10 */
11
12 /*
13 Copyright 2010 - 2026 WPBrigade.com
14
15 This product was first developed by Maria I Shaldybina and later on maintained and developed by Adnan (WPBrigade.com)
16
17 This program is free software; you can redistribute it and/or modify
18 it under the terms of the GNU General Public License as published by
19 the Free Software Foundation; either version 2 of the License, or
20 (at your option) any later version.
21
22 This program is distributed in the hope that it will be useful,
23 but WITHOUT ANY WARRANTY; without even the implied warranty of
24 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
25 GNU General Public License for more details.
26 */
27
28
29 if ( ! defined( 'ABSPATH' ) ) {
30 exit;
31 }
32
33 if ( ! function_exists( 'rpt_wpb92640233' ) ) {
34 /**
35 * Create a helper function for easy SDK access.
36 *
37 * @return mixed
38 */
39 function rpt_wpb92640233() {
40 global $rpt_wpb92640233;
41
42 if ( ! isset( $rpt_wpb92640233 ) || ! is_array( $rpt_wpb92640233 ) ) {
43 require_once __DIR__ . '/lib/wpb-sdk/start.php';
44
45 /**
46 * Initialize WPB SDK.
47 *
48 * @phpstan-ignore-next-line
49 */
50 $rpt_wpb92640233 = wpb_sdk_dynamic_init(
51 array(
52 'id' => '3',
53 'slug' => 'related-posts-thumbnails',
54 'type' => 'plugin',
55 'plugin_file' => __FILE__,
56 'sdk_views_dir' => __DIR__ . '/lib/wpb-sdk/views',
57 'public_key' => '1|4aOA8EuyIN4pi2miMvC23LLpnHbBZFNki9R9pVmwd673d3c8',
58 'secret_key' => 'sk_b36c525848fee035',
59 'is_premium' => false,
60 'has_addons' => false,
61 'has_paid_plans' => false,
62 'optin_user_meta' => array(
63 'token' => '_rpt_verification_token',
64 'email_verified' => '_rpt_email_verified',
65 ),
66 'optin' => array(
67 'option_name' => '_rpt_optin',
68 'settings_page' => 'related-posts-thumbnails',
69 'optin_page' => 'rpt-optin',
70 'logo_path' => 'assets/images/rpt-brand.svg',
71 'verify_query_args' => array(
72 'related-posts-thumbnails_optin_verify',
73 'rpt_optin_verify',
74 ),
75 'ajax_prefix' => 'rpt',
76 'product_name' => 'Related Posts Thumbnails',
77 ),
78 'telemetry' => array(
79 'optout_submit_key' => 'rpt-submit-optout',
80 ),
81 'menu' => array(
82 'slug' => 'related-posts-thumbnails',
83 'account' => false,
84 'support' => false,
85 ),
86 'settings' => array(
87 '_rpt_optin' => '',
88 'wpb_sdk_related-posts-thumbnails' => '',
89 'wpb_sdk_related-posts-thumbnails_fallback_verify_token' => '',
90 'wpb_sdk_related-posts-thumbnails_initial_log_sent' => '',
91 'relpoststh_default_image' => false,
92 'rpt_active_time' => false,
93 'relpoststh_single_only' => false,
94 'relpoststh_mobile_view' => false,
95 'relpoststh_post_types' => false,
96 'relpoststh_onlywiththumbs' => false,
97 'relpoststh_output_style' => false,
98 'relpoststh_cleanhtml' => false,
99 'relpoststh_column' => false,
100 'relpoststh_column_t' => false,
101 'relpoststh_column_m' => false,
102 'relpoststh_image_size' => false,
103 'relpoststh_auto' => false,
104 'relpoststh_top_text' => false,
105 'relpoststh_number' => false,
106 'relpoststh_relation' => false,
107 'relpoststh_poststhname' => false,
108 'relpoststh_background' => false,
109 'relpoststh_hoverbackground' => false,
110 'relpoststh_bordercolor' => false,
111 'relpoststh_fontcolor' => false,
112 'relpoststh_fontsize' => false,
113 'relpoststh_fontfamily' => false,
114 'relpoststh_textlength' => false,
115 'relpoststh_excerptlength' => false,
116 'relpoststh_thsource' => false,
117 'relpoststh_customfield' => false,
118 'relpoststh_theme_resize_url' => false,
119 'relpoststh_customwidth' => false,
120 'relpoststh_customheight' => false,
121 'relpoststh_textblockheight' => false,
122 'rpt_post_sort' => false,
123 'relpoststh_categories' => false,
124 'relpoststh_categoriesall' => false,
125 'relpoststh_show_categoriesall' => false,
126 'relpoststh_show_categories' => false,
127 'relpoststh_devmode' => false,
128 'relpoststh_startdate' => false,
129 'relpoststh_custom_taxonomies' => false,
130 'relpoststh_show_taxonomy' => false,
131 'relpoststh_title_tag' => false,
132 ),
133 )
134 );
135 }
136
137 return $rpt_wpb92640233;
138 }
139
140 rpt_wpb92640233();
141 do_action( 'rpt_wpb92640233_loaded' );
142 }
143
144 if ( ! function_exists( 'rpt_response_is_image_content_type' ) ) {
145 /**
146 * Whether an HTTP response reports an image content type.
147 *
148 * @param array $response Remote response.
149 * @return bool
150 * @since 5.0.0
151 */
152 function rpt_response_is_image_content_type( $response ) {
153 $content_type = wp_remote_retrieve_header( $response, 'content-type' );
154
155 if ( is_array( $content_type ) ) {
156 $content_type = reset( $content_type );
157 }
158
159 $content_type = strtolower( trim( (string) $content_type ) );
160
161 if ( false !== strpos( $content_type, ';' ) ) {
162 $content_type = trim( strstr( $content_type, ';', true ) );
163 }
164
165 return 0 === strpos( $content_type, 'image/' );
166 }
167 }
168
169 if ( ! function_exists( 'rpt_remote_image_url_is_accessible' ) ) {
170 /**
171 * Whether a remote image URL responds with a reachable image.
172 *
173 * @param string $url Sanitized image URL.
174 * @return bool
175 * @since 5.0.0
176 */
177 function rpt_remote_image_url_is_accessible( $url ) {
178 $request_args = array(
179 'timeout' => 8,
180 'redirection' => 5,
181 );
182
183 $response = wp_remote_head( $url, $request_args );
184
185 if ( ! is_wp_error( $response ) ) {
186 $code = (int) wp_remote_retrieve_response_code( $response );
187
188 if ( $code >= 200 && $code < 400 && rpt_remote_image_response_is_valid( $url, $response ) ) {
189 return true;
190 }
191 }
192
193 $response = wp_remote_get( $url, $request_args );
194
195 if ( is_wp_error( $response ) ) {
196 return false;
197 }
198
199 $code = (int) wp_remote_retrieve_response_code( $response );
200
201 return $code >= 200 && $code < 400 && rpt_remote_image_response_is_valid( $url, $response );
202 }
203 }
204
205 if ( ! function_exists( 'rpt_remote_image_response_is_valid' ) ) {
206 /**
207 * Whether a successful HTTP response looks like an image.
208 *
209 * @param string $url Image URL.
210 * @param array $response Remote response.
211 * @return bool
212 * @since 5.0.0
213 */
214 function rpt_remote_image_response_is_valid( $url, $response ) {
215 if ( rpt_response_is_image_content_type( $response ) ) {
216 return true;
217 }
218
219 $path = (string) wp_parse_url( $url, PHP_URL_PATH );
220 $ext = strtolower( pathinfo( $path, PATHINFO_EXTENSION ) );
221
222 return in_array( $ext, array( 'jpg', 'jpeg', 'png', 'gif', 'webp', 'svg', 'avif', 'bmp', 'ico' ), true );
223 }
224 }
225
226 if ( ! function_exists( 'rpt_is_valid_remote_image_url' ) ) {
227 /**
228 * Whether a URL points to an accessible remote image.
229 *
230 * @param string $url Image URL.
231 * @return bool
232 * @since 5.0.0
233 */
234 function rpt_is_valid_remote_image_url( $url ) {
235 $url = trim( (string) $url );
236
237 if ( '' === $url ) {
238 return false;
239 }
240
241 $scheme = strtolower( (string) wp_parse_url( $url, PHP_URL_SCHEME ) );
242
243 if ( ! in_array( $scheme, array( 'http', 'https' ), true ) ) {
244 return false;
245 }
246
247 $sanitized_url = esc_url_raw( $url );
248
249 if ( empty( $sanitized_url ) || ! filter_var( $sanitized_url, FILTER_VALIDATE_URL ) ) {
250 return false;
251 }
252
253 if ( function_exists( 'wp_http_validate_url' ) && ! wp_http_validate_url( $sanitized_url ) ) {
254 return false;
255 }
256
257 return rpt_remote_image_url_is_accessible( $sanitized_url );
258 }
259 }
260
261 require_once plugin_dir_path( __FILE__ ) . 'inc/rpt-cache.php';
262
263 class RelatedPostsThumbnails
264 {
265 /* Default values.
266 * PHP 8.0 compatible
267 * */
268 public $single_only = '1';
269 public $auto = '1';
270 public $author_related = '0';
271 public $top_text = '';
272 public $number = 3;
273 public $relation = 'categories';
274 public $poststhname = 'thumbnail';
275 public $background = '#ffffff';
276 public $hoverbackground = '#eeeeee';
277 public $border_color = '#dddddd';
278 public $font_color = '#333333';
279 public $font_family = 'Arial';
280 public $font_size = '12';
281 public $text_length = '100';
282 public $excerpt_length = '0';
283 public $custom_field = '';
284 public $custom_height = '100';
285 public $custom_width = '100';
286 public $text_block_height = '75';
287 public $thsource = 'post-thumbnails';
288 public $categories_all = '1';
289 public $devmode = '0';
290 public $format = 'j F, Y';
291 public $output_style = 'div';
292 public $post_types = array('post');
293 public $custom_taxonomies = array();
294 public $default_image = '';
295 public $default_image_type = 'image';
296 public $column = '3';
297 public $column_t = '2';
298 public $column_m = '2';
299 public $size = '1/1';
300 public $wp_version = '';
301 public $relpoststh_column = "3";
302 public $relpoststh_column_t = "2";
303 public $relpoststh_column_m = "2";
304 public $relpoststh_image_size = "1/1";
305
306 protected $wp_kses_rp_args = array('h1' => array(), 'h2' => array(), 'h3' => array(), 'h4' => array(), 'h5' => array(), 'h6' => array(), 'strong' => array());
307 protected static $instance = null;
308
309 /**
310 * Function Constructor
311 */
312 function __construct()
313 {
314
315 $this->constant();
316 $this->default_image = esc_url(plugins_url('img/default.png', __FILE__));
317 $this->column = '3';
318 $this->size = '1/1';
319
320 add_action('admin_enqueue_scripts', array($this, 'admin_scripts'));
321
322 // Compatibility for old default image path.
323 if ($this->is_old_default_img())
324 update_option('relpoststh_default_image', $this->default_image);
325
326 add_action( 'init', array( $this, 'rpt_register_content_hooks' ) );
327
328 add_action('admin_menu', array($this, 'admin_menu'));
329
330 $this->wp_version = get_bloginfo('version');
331
332 add_action('admin_init', array($this, 'redirect_optin'));
333 add_action('admin_init', array($this, 'review_notice'));
334 add_action('amp_post_template_css',array( $this, 'rpt_ampforwp_add_custom_css'));
335
336 add_shortcode('related-posts-thumbnails', array($this, 'related_posts_shortcode'));
337
338 add_filter('plugin_action_links_' . plugin_basename(__FILE__), array($this, 'filter_plugin_action_links'));
339 add_action('init', array($this, 'textdomain'), 0);
340
341 add_action( 'save_post', array( $this, 'rpt_invalidate_post_cache_on_save' ) );
342 add_action( 'wp_trash_post', array( $this, 'rpt_invalidate_post_cache_on_delete' ) );
343 add_action( 'before_delete_post', array( $this, 'rpt_invalidate_post_cache_on_delete' ) );
344 add_action( 'admin_init', 'rpt_batch_delete_cache_meta' );
345 add_action( 'admin_bar_menu', array( $this, 'rpt_admin_bar_cache_purge' ), 100 );
346 add_action( 'admin_post_rpt_purge_cache', array( $this, 'rpt_handle_admin_purge_cache' ) );
347 add_action( 'admin_notices', array( $this, 'rpt_cache_purge_admin_notice' ) );
348
349 add_action( 'user_register', 'rpt_flush_multiple_publishers_cache' );
350 add_action( 'deleted_user', 'rpt_flush_multiple_publishers_cache' );
351 add_action( 'set_user_role', 'rpt_flush_multiple_publishers_cache' );
352 add_action( 'add_user_role', 'rpt_flush_multiple_publishers_cache' );
353 add_action( 'remove_user_role', 'rpt_flush_multiple_publishers_cache' );
354
355 }
356
357 /**
358 * Load Languages
359 *
360 * @since 4.1.1
361 * @version 5.0.0
362 */
363 public function textdomain() {
364
365 // Explicitly load .mo from plugin's locale/ folder (avoids path/cache issues on Windows).
366 $locale = determine_locale();
367 $mofile = plugin_dir_path( __FILE__ ) . 'locale/related-posts-thumbnails-' . $locale . '.mo';
368 if ( file_exists( $mofile ) ) {
369 load_textdomain( 'related-posts-thumbnails', $mofile, $locale );
370 }
371 $this->top_text = '<h3>' . esc_html__( 'Related posts:', 'related-posts-thumbnails' ) . '</h3>';
372 }
373
374 /**
375 * Show Opt-in Page.
376 */
377 function render_optin()
378 {
379 if ( function_exists( 'wpb_sdk_render_optin_form' ) ) {
380 wpb_sdk_render_optin_form( 'related-posts-thumbnails' );
381 }
382 }
383
384 /**
385 * Redirect first-time admins to the opt-in screen; skip opt-in page when already opted in.
386 *
387 * @return void
388 */
389 public function redirect_optin()
390 {
391 if ( ! current_user_can( 'manage_options' ) ) {
392 return;
393 }
394
395 $page = isset( $_GET['page'] ) ? sanitize_text_field( wp_unslash( (string) $_GET['page'] ) ) : '';
396 $decision = function_exists( 'wpb_sdk_get_optin_decision' )
397 ? wpb_sdk_get_optin_decision( 'related-posts-thumbnails' )
398 : (string) get_option( '_rpt_optin', '' );
399
400 if (
401 $page
402 && in_array( $page, array( 'related-posts-thumbnails', 'rpt' ), true )
403 && '' === $decision
404 ) {
405 $page_redirect = 'rpt' === $page ? 'rpt' : 'related-posts-thumbnails';
406 wp_safe_redirect(
407 admin_url( 'admin.php?page=rpt-optin&redirect-page=' . rawurlencode( $page_redirect ) )
408 );
409 exit;
410 }
411
412 if (
413 (
414 function_exists( 'wpb_sdk_should_redirect_from_optin_page' )
415 ? wpb_sdk_should_redirect_from_optin_page( 'related-posts-thumbnails' )
416 : ( 'yes' === $decision )
417 )
418 && 'rpt-optin' === $page
419 ) {
420 wp_safe_redirect( admin_url( 'admin.php?page=related-posts-thumbnails' ) );
421 exit;
422 }
423 }
424
425 /**
426 * Action link on plugin page
427 *
428 * @param array $actions
429 * @return array
430 *
431 * @access public
432 * @return array
433 * @since 2.1.4
434 */
435 public function filter_plugin_action_links($actions_links)
436 {
437 $settings_link = '<a href="' . esc_url(admin_url('admin.php?page=related-posts-thumbnails')) . '">' . esc_html__('Settings', 'related-posts-thumbnails') . '</a>';
438 array_unshift($actions_links, $settings_link);
439
440 return $actions_links;
441 }
442
443
444 /**
445 * Prevent related posts on editor screen (builders).
446 *
447 * @return bool $return
448 */
449 function prevent_on_editors()
450 {
451 $return = false;
452 $prevent_on_edit = apply_filters('rpt_prevent_on_edit', array('divi' => false,));
453
454 foreach ($prevent_on_edit as $key => $value) {
455 switch ($key) {
456 case 'divi':
457 if ($value && isset($_GET['et_fb'])) {
458 $return = true;
459 }
460 break;
461 }
462 }
463
464 return $return;
465 }
466
467 /**
468 * callback for shortcode related_posts_shortcode
469 *
470 * @param array $atts attributes of shortcode
471 * @version 1.9.0
472 */
473 function related_posts_shortcode($atts)
474 {
475
476 $atts = shortcode_atts(array(
477 'posts_number' => '3',
478 'posts_sort' => 'random',
479 'main_title' => '',
480 'exclude_post' => ''),
481 $atts, 'related-posts-thumbnails'
482 );
483
484 $number = $atts['posts_number'];
485
486 if ($atts['posts_sort'] == 'random') {
487 $sort = 'rand()';
488 } elseif ($atts['posts_sort'] == 'latest') {
489 $sort = 'post_date';
490 }
491
492 //sanitization through regex expression to know if a string is consisting of numeric values.
493 $regex = '/^\d+(?:,\d+)*$/';
494 $excluded_posts_array = preg_match($regex, $atts['exclude_post']) ? $atts['exclude_post'] : array();
495
496 if (!is_numeric($number)) {
497 $number = 3;
498 }
499
500 $main_title = str_replace('_', ' ', $atts['main_title']);
501
502 return $this->get_thumbnails(true, $number, $sort, $main_title, $excluded_posts_array);
503
504 }
505
506 /**
507 * Function to enqueue admin styles and scripts.
508 *
509 * @param $page
510 * @return void
511 * @since 1.7.0
512 * @version 1.9.0
513 *
514 */
515 function admin_scripts($page)
516 {
517 if ('toplevel_page_related-posts-thumbnails' === $page) {
518 wp_enqueue_media();
519 wp_enqueue_style('rpt_admin_css', plugins_url('assets/css/admin.css', __FILE__), false, RELATED_POSTS_THUMBNAILS_VERSION);
520 wp_enqueue_style('jquery-ui', 'https://code.jquery.com/ui/1.11.2/themes/smoothness/jquery-ui.css');
521 // Enqueue Chosen CSS
522 wp_enqueue_style('rpt-chosen', plugins_url('assets/css/chosen.min.css', __FILE__), array(), RELATED_POSTS_THUMBNAILS_VERSION);
523
524 // Enqueue jQuery (if not already included by WordPress)
525 if (!wp_script_is('jquery', 'enqueued')) {
526 wp_enqueue_script('jquery');
527 }
528
529 // Enqueue Chosen JS
530 wp_enqueue_script('rpt-chosen', plugins_url('assets/js/chosen.jquery.min.js', __FILE__), array('jquery'), RELATED_POSTS_THUMBNAILS_VERSION, true);
531
532 // Enqueue other scripts
533 wp_enqueue_style('wp-color-picker');
534 wp_enqueue_script('wp-color-picker-alpha', plugins_url('assets/js/wp-color-picker-alpha.js', __FILE__), array('wp-color-picker'), RELATED_POSTS_THUMBNAILS_VERSION, true);
535
536 wp_enqueue_script('rpt_admin_js', plugins_url('assets/js/admin.js', __FILE__),
537 array(
538 'jquery',
539 'wp-color-picker',
540 'jquery-ui-datepicker',
541 'rpt-chosen'
542 ), RELATED_POSTS_THUMBNAILS_VERSION
543 );
544 }
545 }
546
547 /**
548 * Function to add custom CSS for AMP pages.
549 *
550 * This function outputs custom CSS specific to AMP (Accelerated Mobile Pages).
551 * It is intended to be used in a WordPress theme or plugin for customizing the styles of AMP pages.
552 *
553 * @return void
554 * @since 4.2.0
555 */
556 public function rpt_ampforwp_add_custom_css() {
557 // inlcude the file
558 include_once RELATED_POSTS_THUMBNAILS_PLUGIN_DIR . '/inc/amp.php';
559 }
560 /**
561 * Function to define plugin Constants
562 *
563 * @return void
564 */
565 function constant()
566 {
567 define('RELATED_POSTS_THUMBNAILS_VERSION', '5.0.1');
568 define('RELATED_POSTS_THUMBNAILS_FEEDBACK_SERVER', 'https://wpbrigade.com/');
569 define('RELATED_POSTS_THUMBNAILS_PLUGIN_DIR', plugin_dir_path(__FILE__));
570 }
571
572 /**
573 * Check either to show notice or not.
574 *
575 * @since 1.8.2
576 */
577 public function review_notice()
578 {
579 $this->review_dismissal();
580 $this->review_prending();
581
582 $review_dismissal = get_option('rpt_review_dismiss');
583
584 if ('yes' == $review_dismissal) {
585 return;
586 }
587
588 $activation_time = get_option('rpt_active_time');
589
590 if (!$activation_time) {
591 $activation_time = time();
592 add_option('rpt_active_time', $activation_time);
593 }
594
595 // 1296000 = 15 Days in seconds.
596 if (time() - $activation_time > 1296000) {
597 add_action('admin_notices', array($this, 'review_notice_message'));
598 }
599 }
600
601 /**
602 * Show review Message After 15 days.
603 *
604 * @since 1.8.2
605 */
606 public function review_notice_message()
607 {
608 $scheme = (parse_url($_SERVER['REQUEST_URI'], PHP_URL_QUERY)) ? '&' : '?';
609 $url = $_SERVER['REQUEST_URI'] . $scheme . 'rpt_review_dismiss=yes';
610 $dismiss_url = wp_nonce_url($url, 'rpt-review-nonce');
611
612 $_later_link = $_SERVER['REQUEST_URI'] . $scheme . 'ssb_review_later=yes';
613 $later_url = wp_nonce_url($_later_link, 'rpt-review-nonce'); ?>
614
615 <style media="screen">
616 .rpt-review-notice {
617 padding: 15px 0;
618 background-color: #fff;
619 border-radius: 3px;
620 margin: 20px 20px 0 0;
621 border-left: 4px solid transparent;
622 }
623
624 .rpt-review-notice:after {
625 content: '';
626 display: table;
627 clear: both;
628 }
629
630 .rpt-review-thumbnail {
631 float: left;
632 line-height: 80px;
633 text-align: center;
634 width: 117px;
635 }
636
637 .rpt-review-thumbnail img {
638 width: 118px;
639 vertical-align: middle;
640 }
641
642 .rpt-review-text {
643 overflow: hidden;
644 }
645
646 .rpt-review-text h3 {
647 font-size: 24px;
648 margin: 0 0 5px;
649 font-weight: 400;
650 line-height: 1.3;
651 }
652
653 .rpt-review-text p {
654 font-size: 13px;
655 margin: 0 0 5px;
656 }
657
658 .rpt-review-ul {
659 margin: 0;
660 padding: 0;
661 }
662
663 .rpt-review-ul li {
664 display: inline-block;
665 margin-right: 15px;
666 }
667
668 .rpt-review-ul li a {
669 display: inline-block;
670 color: #10738B;
671 text-decoration: none;
672 padding-left: 26px;
673 position: relative;
674 }
675
676 .rpt-review-ul li a span {
677 position: absolute;
678 left: 0;
679 top: -2px;
680 }
681 </style>
682
683 <div class="rpt-review-notice">
684 <div class="rpt-review-thumbnail">
685 <img src="<?php echo plugins_url('assets/images/rpt-logo.png', __FILE__); ?>" alt="">
686 </div>
687 <div class="rpt-review-text">
688
689 <h3>
690 <?php _e('Leave A Review?', 'related-posts-thumbnails'); ?>
691 </h3>
692
693 <p>
694 <?php _e('We hope you\'ve enjoyed using Related Post Thumbnails! Would you consider leaving us a review on WordPress.org?', 'related-posts-thumbnails'); ?>
695 </p>
696
697 <ul class="rpt-review-ul">
698 <li>
699 <a href="https://wordpress.org/support/plugin/related-posts-thumbnails/reviews/?filter=5"
700 target="_blank"><span class="dashicons dashicons-external"></span>
701 <?php _e('Sure! I\'d love to!', 'related-posts-thumbnails'); ?>
702 </a>
703 </li>
704
705 <li>
706 <a href="<?php echo $dismiss_url; ?>">
707 <span class="dashicons dashicons-smiley"></span>
708 <?php _e('I\'ve already left a review', 'related-posts-thumbnails'); ?>
709 </a>
710 </li>
711
712 <li>
713 <a href="<?php echo $later_url; ?>">
714 <span class="dashicons dashicons-calendar-alt"></span>
715 <?php _e('Maybe Later', 'related-posts-thumbnails'); ?>
716 </a>
717 </li>
718
719 <li>
720 <a href="<?php echo $dismiss_url; ?>">
721 <span class="dashicons dashicons-dismiss"></span>
722 <?php _e('Never show again', 'related-posts-thumbnails'); ?>
723 </a>
724 </li>
725 </ul>
726 </div>
727 </div>
728
729 <?php
730 }
731
732 /**
733 * Set time to current so review notice will popup after 15 days
734 *
735 * @since 1.8.2
736 */
737 function review_prending()
738 {
739 // delete_site_option( 'rpt_review_dismiss' );
740 if (!is_admin() || !current_user_can('manage_options') || !isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['_wpnonce'])), 'rpt-review-nonce') || !isset($_GET['ssb_review_later'])) {
741
742 return;
743 }
744
745 // Reset Time to current time.
746 update_option('rpt_active_time', time());
747 }
748
749 /**
750 * Check and Dismiss review message.
751 *
752 * @since 1.8.2
753 */
754 private function review_dismissal()
755 {
756 //delete_option( 'rpt_review_dismiss' );
757 if (!is_admin() || !current_user_can('manage_options') || !isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_key(wp_unslash($_GET['_wpnonce'])), 'rpt-review-nonce') || !isset($_GET['rpt_review_dismiss'])) {
758
759 return;
760 }
761
762 add_option('rpt_review_dismiss', 'yes');
763 }
764
765 /**
766 * [is_old_default_img Check the compatibility for old default image path.]
767 *
768 * @return boolean Return true if path is old.
769 */
770 function is_old_default_img()
771 {
772 if (get_option('relpoststh_default_image') !== $this->default_image) {
773
774 $chunks = explode('/', get_option('relpoststh_default_image'));
775 if (in_array('related-posts-thumbnails', $chunks)) {
776 return true;
777 }
778 }
779 }
780
781 /**
782 * Get the configured default thumbnail URL based on the selected type.
783 *
784 * @return string Default image URL.
785 */
786 public function rpt_get_default_image_url() {
787 $type = get_option( 'relpoststh_default_image_type', $this->default_image_type );
788
789 if ( 'url' === $type ) {
790 $remote_url = get_option( 'relpoststh_default_image_url', '' );
791
792 if ( ! empty( $remote_url ) ) {
793 return esc_url( $remote_url );
794 }
795 }
796
797 return get_option( 'relpoststh_default_image', $this->default_image );
798 }
799
800 /**
801 * Automatically displaying related posts under post body
802 *
803 * @param $content
804 *
805 * @return void
806 */
807 function auto_show($content)
808 {
809 return $this->rpt_append_content_html( $content, $this->get_html( true ) );
810 }
811
812 /**
813 * Whether related output should be skipped for the current request.
814 *
815 * @return bool
816 * @since 5.0.0
817 */
818 private function rpt_should_skip_related_output() {
819 if ( $this->prevent_on_editors() ) {
820 return true;
821 }
822
823 if ( wp_is_mobile() && '1' === get_option( 'relpoststh_mobile_view', '0' ) ) {
824 return true;
825 }
826
827 return false;
828 }
829
830 /**
831 * Append related posts HTML to post content when markup exists.
832 *
833 * @param string $content Post content.
834 * @param string $html Related posts HTML.
835 * @return string
836 * @since 5.0.0
837 */
838 private function rpt_append_content_html( $content, $html ) {
839 if ( empty( $html ) ) {
840 return $content;
841 }
842
843 return $content . $html;
844 }
845
846 /**
847 * Register automatic and author-related content filters after WordPress is ready.
848 *
849 * @return void
850 * @since 5.0.0
851 */
852 public function rpt_register_content_hooks() {
853 $priority = (int) apply_filters( 'rpt_content_prioirty', 10 );
854
855 if ( get_option( 'relpoststh_auto', $this->auto ) && ! $this->rpt_is_author_related_enabled() && ! $this->rpt_should_skip_related_output() ) {
856 add_filter( 'the_content', array( $this, 'auto_show' ), $priority );
857 }
858
859 if ( $this->rpt_is_author_related_enabled() && ! $this->rpt_should_skip_related_output() ) {
860 add_filter( 'the_content', array( $this, 'rpt_author_related_show' ), $priority );
861 }
862 }
863
864 /**
865 * Whether author-related auto display is the active mode.
866 *
867 * @return bool
868 * @since 5.0.0
869 */
870 public function rpt_is_author_related_enabled() {
871 return '1' === get_option( 'relpoststh_author_related', $this->author_related ) && $this->rpt_has_multiple_publishers();
872 }
873
874 /**
875 * Whether the site has more than one user who can publish posts.
876 *
877 * @return bool
878 * @since 5.0.0
879 */
880 public function rpt_has_multiple_publishers() {
881 if ( ! did_action( 'init' ) ) {
882 return false;
883 }
884
885 static $request_cache = null;
886
887 if ( null !== $request_cache ) {
888 return $request_cache;
889 }
890
891 $stored = get_transient( RPT_MULTIPLE_PUBLISHERS_TRANSIENT );
892
893 if ( false !== $stored ) {
894 $request_cache = (bool) $stored;
895
896 return $request_cache;
897 }
898
899 $user_query = new WP_User_Query(
900 array(
901 'capability' => 'publish_posts',
902 'fields' => 'ID',
903 'number' => 2,
904 'count_total' => false,
905 )
906 );
907
908 $request_cache = count( $user_query->get_results() ) > 1;
909
910 set_transient( RPT_MULTIPLE_PUBLISHERS_TRANSIENT, $request_cache ? 1 : 0, DAY_IN_SECONDS );
911
912 return $request_cache;
913 }
914
915 /**
916 * Append author-related posts to post content, same placement as auto-append.
917 *
918 * @param string $content Post content.
919 * @return string
920 * @since 5.0.0
921 */
922 public function rpt_author_related_show( $content ) {
923 if ( ! $this->rpt_should_show_author_related() ) {
924 return $content;
925 }
926
927 return $this->rpt_append_content_html( $content, $this->rpt_get_author_related_html() );
928 }
929
930 /**
931 * Whether author-related posts should output on the current request.
932 *
933 * @return bool
934 * @since 5.0.0
935 */
936 public function rpt_should_show_author_related() {
937 if ( ! $this->rpt_is_author_related_enabled() ) {
938 return false;
939 }
940
941 if ( $this->prevent_on_editors() ) {
942 return false;
943 }
944
945 if ( wp_is_mobile() && '1' === get_option( 'relpoststh_mobile_view', '0' ) ) {
946 return false;
947 }
948
949 return $this->is_relpoststh_show();
950 }
951
952 /**
953 * Build related posts markup limited to the current post author.
954 *
955 * @return string
956 * @since 5.0.0
957 */
958 public function rpt_get_author_related_html() {
959 $post_id = get_the_ID();
960
961 if ( ! $post_id ) {
962 return '';
963 }
964
965 $author_id = (int) get_post_field( 'post_author', $post_id );
966 $author_id = (int) apply_filters( 'rpt_author_related_author_id', $author_id, $post_id );
967
968 if ( $author_id <= 0 ) {
969 return '';
970 }
971
972 $html = $this->get_thumbnails( true, '', '', '', '', $author_id );
973
974 if ( empty( $html ) ) {
975 return '';
976 }
977
978 return '<div class="relpost-author-related">' . $html . '</div>';
979 }
980
981 /**
982 * Getting related posts HTML
983 *
984 * @param boolean $show_top
985 *
986 */
987 function get_html($show_top = false)
988 {
989 if ($this->is_relpoststh_show()) {
990 return $this->get_thumbnails($show_top);
991 }
992
993 return '';
994 }
995
996 /**
997 * Query related post IDs for a source post.
998 *
999 * @param int $post_id Source post ID.
1000 * @param array<string, mixed> $query_args Query arguments.
1001 * @param string $debug Debug output passed by reference.
1002 * @return array<int>
1003 * @since 5.0.0
1004 */
1005 public function rpt_query_related_post_ids( $post_id, $query_args, &$debug = '' ) {
1006 $post_id = absint( $post_id );
1007
1008 if ( $post_id <= 0 ) {
1009 return array();
1010 }
1011
1012 $posts_number = absint( $query_args['posts_number'] ?? 0 );
1013 $sort_by = rpt_sanitize_related_sort_by( $query_args['sort_by'] ?? 'rand()' );
1014 $author_id = absint( $query_args['author_id'] ?? 0 );
1015 $exclude = $query_args['exclude'] ?? '';
1016
1017 if ( $posts_number <= 0 ) {
1018 return array();
1019 }
1020
1021 $relation = get_option( 'relpoststh_relation', $this->relation );
1022 $categories_show_all = get_option( 'relpoststh_show_categoriesall', get_option( 'relpoststh_categoriesall', $this->categories_all ) );
1023 $thsource = get_option( 'relpoststh_thsource', $this->thsource );
1024 $onlywiththumbs = ( current_theme_supports( 'post-thumbnails' ) && 'post-thumbnails' === $thsource )
1025 ? get_option( 'relpoststh_onlywiththumbs', false )
1026 : false;
1027
1028 global $wpdb;
1029
1030 $debug .= "Relation: $relation; All categories: $categories_show_all;";
1031 $use_filter = ( '1' !== $categories_show_all || 'no' !== $relation );
1032
1033 if ( $use_filter ) {
1034 $query_objects = "SELECT distinct object_id FROM $wpdb->term_relationships WHERE 1=1 ";
1035
1036 if ( 'no' !== $relation ) {
1037 if ( 'categories' === $relation ) {
1038 $taxonomy = array( 'category' );
1039 } elseif ( 'tags' === $relation ) {
1040 $taxonomy = array( 'post_tag' );
1041 } elseif ( 'custom' === $relation ) {
1042 $taxonomy = get_option( 'relpoststh_custom_taxonomies', $this->custom_taxonomies );
1043 } else {
1044 $taxonomy = array( 'category', 'post_tag' );
1045 }
1046
1047 $object_terms = wp_get_object_terms( $post_id, $taxonomy, array( 'fields' => 'ids' ) );
1048
1049 if ( empty( $object_terms ) || ! is_array( $object_terms ) ) {
1050 $debug .= __( 'No taxonomy terms to get posts;', 'related-posts-thumbnails' );
1051
1052 return array();
1053 }
1054
1055 $query = "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id in ('" . implode( "', '", $object_terms ) . "')";
1056 $object_taxonomy = $wpdb->get_results( $query );
1057 $object_taxonomy_a = array();
1058
1059 if ( count( $object_taxonomy ) > 0 ) {
1060 foreach ( $object_taxonomy as $item ) {
1061 $object_taxonomy_a[] = $item->term_taxonomy_id;
1062 }
1063 }
1064
1065 $query_objects .= " AND term_taxonomy_id IN ('" . implode( "', '", $object_taxonomy_a ) . "') ";
1066 }
1067
1068 if ( '1' !== $categories_show_all ) {
1069 $select_terms = get_option( 'relpoststh_show_categories', get_option( 'relpoststh_categories' ) );
1070
1071 if ( empty( $select_terms ) || ! is_array( $select_terms ) ) {
1072 $debug .= __( 'No categories were selected;', 'related-posts-thumbnails' );
1073
1074 return array();
1075 }
1076
1077 $query = "SELECT term_taxonomy_id FROM $wpdb->term_taxonomy WHERE term_id in ('" . implode( "', '", $select_terms ) . "')";
1078 $taxonomy = $wpdb->get_results( $query );
1079 $filter_taxonomy_a = array();
1080
1081 if ( count( $taxonomy ) > 0 ) {
1082 foreach ( $taxonomy as $item ) {
1083 $filter_taxonomy_a[] = $item->term_taxonomy_id;
1084 }
1085 }
1086
1087 if ( 'no' !== $relation ) {
1088 $query_objects .= " AND object_id IN (SELECT distinct object_id FROM $wpdb->term_relationships WHERE term_taxonomy_id IN ('" . implode( "', '", $filter_taxonomy_a ) . "') )";
1089 } else {
1090 $query_objects .= " AND term_taxonomy_id IN ('" . implode( "', '", $filter_taxonomy_a ) . "')";
1091 }
1092 }
1093
1094 $relationships = $wpdb->get_results( $query_objects );
1095 $related_objects = array();
1096
1097 if ( count( $relationships ) > 0 ) {
1098 foreach ( $relationships as $item ) {
1099 $related_objects[] = $item->object_id;
1100 }
1101 }
1102 }
1103
1104 $custom_relations = apply_filters( 'rpt_custom_relationship', array( get_post_type( $post_id ) ) );
1105
1106 if ( ! is_array( $custom_relations ) ) {
1107 $custom_relations = array( $custom_relations );
1108 }
1109
1110 $selected_post_type = '';
1111
1112 foreach ( $custom_relations as $checked_post_type ) {
1113 if ( in_array( $checked_post_type, get_post_types(), true ) ) {
1114 $selected_post_type .= "'" . esc_html( $checked_post_type ) . "',";
1115 }
1116 }
1117
1118 $checked_post_type = rtrim( $selected_post_type, ',' );
1119 $query = "SELECT ID FROM $wpdb->posts ";
1120 $where = ' WHERE post_type IN (' . $checked_post_type . ") AND post_status = 'publish' AND ID<>" . $post_id;
1121 $startdate = get_option( 'relpoststh_startdate' );
1122
1123 if ( ! empty( $startdate ) && preg_match( '/^\d\d\d\d-\d\d-\d\d$/', $startdate ) ) {
1124 $debug .= "Startdate: $startdate;";
1125 $where .= " AND post_date >= '" . $startdate . "'";
1126 }
1127
1128 if ( ! empty( $author_id ) ) {
1129 $where .= ' AND post_author = ' . $author_id;
1130 $debug .= 'Author filter: ' . $author_id . ';';
1131 }
1132
1133 if ( $use_filter ) {
1134 if ( empty( $related_objects ) ) {
1135 $debug .= __( 'No posts matching relationships criteria;', 'related-posts-thumbnails' );
1136
1137 return array();
1138 }
1139
1140 $where .= " AND ID IN ('" . implode( "', '", $related_objects ) . "')";
1141 }
1142
1143 $join = '';
1144
1145 if ( $onlywiththumbs ) {
1146 $debug .= 'Only with thumbnails;';
1147 $join = " INNER JOIN $wpdb->postmeta ON ($wpdb->posts.ID = $wpdb->postmeta.post_id)";
1148 $where .= " AND $wpdb->postmeta.meta_key = '_thumbnail_id'";
1149 }
1150
1151 $order_query = ' ORDER BY ' . $sort_by;
1152 $limit_order = $order_query . ' LIMIT ' . $posts_number;
1153 $random_posts = $wpdb->get_results( $query . $join . $where . $limit_order );
1154
1155 if ( ! is_array( $random_posts ) || count( $random_posts ) < 1 ) {
1156 $debug .= __( 'No posts matching relationships criteria;', 'related-posts-thumbnails' );
1157
1158 return array();
1159 }
1160
1161 $posts_in = array();
1162
1163 foreach ( $random_posts as $random_post ) {
1164 $posts_in[] = $random_post->ID;
1165 }
1166
1167 if ( ! empty( $exclude ) ) {
1168 if ( is_array( $exclude ) ) {
1169 $exclude_post_ids = array_map( 'absint', $exclude );
1170 } else {
1171 $exclude_post_ids = array_map( 'absint', explode( ',', (string) $exclude ) );
1172 }
1173
1174 $posts_in = array_values( array_diff( $posts_in, $exclude_post_ids ) );
1175 }
1176
1177 return $posts_in;
1178 }
1179
1180 /**
1181 * Function responsible for Thumbnail creation.
1182 *
1183 * @param boolean $show_top Position of the thumbnails.
1184 * @param string $posts_number Number of posts to display.
1185 * @param string $sort_by sort The thumbnails by some filter.
1186 * @param string $main_title Thumbnail title.
1187 * @param string $exclude post_ids To exclude from related posts thumbnails.
1188 * @param int $author_id Limit results to this post author when greater than zero.
1189 *
1190 * @return void
1191 * @version 4.3.0
1192 *
1193 * @since 1.0.0
1194 */
1195 function get_thumbnails($show_top = false, $posts_number = '', $sort_by = '', $main_title = '', $exclude = '', $author_id = 0)
1196 {
1197 $output = '';
1198 $debug = 'Developer mode initialization; Version: ;' . RELATED_POSTS_THUMBNAILS_VERSION;
1199 $time = microtime( true );
1200
1201 $amp_endpoint = (function_exists('is_amp_endpoint') && is_amp_endpoint()) ? true : false;
1202
1203 $show_category = get_option('relpoststh_show_taxonomy');
1204
1205 // Stop execution if RPT is disabled in AMP view
1206 if (($amp_endpoint) && ('disable' === apply_filters('rpth_amp', true))) {
1207
1208 $debug .= 'AMP view disabled';
1209 return $this->finish_process('', $debug, $time);
1210 }
1211
1212 $posts_number_opt = get_option('relpoststh_number', $this->number);
1213 $posts_number = !empty($posts_number) ? $posts_number : $posts_number_opt;
1214 $height = '';
1215 $width = '';
1216
1217 $sort_by_opt = get_option('rpt_post_sort') == 'latest' ? 'post_date DESC' : 'rand()';
1218 $sort_by = rpt_sanitize_related_sort_by( ! empty( $sort_by ) ? $sort_by : $sort_by_opt );
1219
1220 // rpt_content_align: add content allignment class; clases are: relpost-align-left, relpost-align-right and relpost-align-center
1221 $output = '<!-- relpost-thumb-wrapper -->';
1222 $output .= '<div class="relpost-thumb-wrapper">';
1223 $output .= '<!-- filter-class -->';
1224 $output .= '<div class="relpost-thumb-container' . apply_filters('rpt_content_align', '') . '">';
1225 $alt = '';
1226
1227 if ($posts_number <= 0) { // return nothing if this parameter was set to <= 0
1228 $output = '';
1229 return $this->finish_process($output, $debug . 'Posts number is 0;', $time);
1230 }
1231
1232 $id = get_the_ID();
1233 $poststhname = get_option('relpoststh_poststhname', $this->poststhname);
1234 $text_length = get_option('relpoststh_textlength', $this->text_length) ? get_option('relpoststh_textlength', $this->text_length) : 0;
1235 $excerpt_length = get_option('relpoststh_excerptlength', $this->excerpt_length) ? get_option('relpoststh_excerptlength', $this->text_length) : 0;
1236 $thsource = get_option('relpoststh_thsource', $this->thsource);
1237 $onlywiththumbs = ( current_theme_supports( 'post-thumbnails' ) && 'post-thumbnails' === $thsource )
1238 ? (bool) get_option( 'relpoststh_onlywiththumbs', false )
1239 : false;
1240 $post_type = get_post_type();
1241 $order_query = ' ORDER BY ' . $sort_by;
1242
1243 $query_args = array(
1244 'posts_number' => $posts_number,
1245 'sort_by' => $sort_by,
1246 'author_id' => absint( $author_id ),
1247 'exclude' => $exclude,
1248 );
1249
1250 $posts_in = false;
1251 $cache_context = '';
1252
1253 if ( rpt_is_related_cache_enabled() && $id ) {
1254 $cache_context = rpt_build_related_cache_context( $query_args );
1255 $cached_ids = rpt_get_cached_related_ids( $id, $cache_context );
1256
1257 if ( is_array( $cached_ids ) ) {
1258 $validation = rpt_validate_cached_related_ids( $cached_ids, $posts_number, $onlywiththumbs );
1259
1260 if ( ! $validation['requery'] ) {
1261 $posts_in = $validation['ids'];
1262 }
1263 }
1264 }
1265
1266 if ( false === $posts_in ) {
1267 $posts_in = $this->rpt_query_related_post_ids( $id, $query_args, $debug );
1268
1269 if ( empty( $posts_in ) ) {
1270 $output = '';
1271 return $this->finish_process( $output, $debug, $time );
1272 }
1273
1274 if ( rpt_is_related_cache_enabled() && $cache_context ) {
1275 rpt_set_cached_related_ids( $id, $cache_context, $posts_in );
1276 }
1277 }
1278
1279 /**
1280 *
1281 * Filter rpt_exclude_post to exclude post from RPT thumbnails
1282 *
1283 * @since 1.9.0
1284 * @version 4.3.0
1285 */
1286 $exclude_by_filter = apply_filters('rpt_exclude_post', '');
1287
1288 if ($exclude_by_filter !== '') {
1289 $regex = '/^\d+(?:,\d+)*$/';
1290 $exclude_by_filter = preg_match($regex, $exclude_by_filter) ? $exclude_by_filter : array();
1291 $exclude_by_filter_ids = explode(",", $exclude_by_filter);
1292 $posts_in = array_diff($posts_in, $exclude_by_filter_ids);
1293
1294 }
1295
1296 if ( empty( $posts_in ) ) {
1297 $output = '';
1298 return $this->finish_process( $output, $debug . 'No posts found after exclusions;', $time );
1299 }
1300
1301 global $wpdb;
1302
1303 $query = "SELECT ID, post_content, post_excerpt, post_title FROM $wpdb->posts WHERE ID IN ('" . implode("', '", $posts_in) . "') $order_query ";
1304 $posts = $wpdb->get_results($query);
1305
1306 if (!(is_array($posts) && count($posts) > 0)) { // no posts
1307 $debug .= 'No posts found;';
1308 $output = '';
1309 return $this->finish_process($output, $debug, $time);
1310 } else {
1311 $debug .= 'Found ' . count($posts) . ' posts;';
1312 RPT_Frontend_Assets::rpt_enqueue( $this );
1313 }
1314
1315 /* Calculating sizes */
1316 if ($thsource == 'custom-field') {
1317 $debug .= 'Custom sizes;';
1318 $width = get_option('relpoststh_customwidth', $this->custom_width);
1319 $height = get_option('relpoststh_customheight', $this->custom_height);
1320 } else {
1321 // post-thumbnails source
1322 if ($poststhname == 'thumbnail' || $poststhname == 'medium' || $poststhname == 'large') { // get thumbnail size for basic sizes
1323 $debug .= 'Basic sizes;';
1324 $width = get_option("{$poststhname}_size_w");
1325 $height = get_option("{$poststhname}_size_h");
1326 } elseif (current_theme_supports('post-thumbnails')) { // get sizes for theme supported thumbnails
1327 global $_wp_additional_image_sizes;
1328 if (isset($_wp_additional_image_sizes[$poststhname])) {
1329 $debug .= 'Additional sizes;';
1330 $width = $_wp_additional_image_sizes[$poststhname]['width'];
1331 $height = $_wp_additional_image_sizes[$poststhname]['height'];
1332 } else {
1333 $debug .= 'No additional sizes;';
1334 }
1335 }
1336 }
1337
1338 // displaying square if one size is not cropping
1339 if ($height == 9999) {
1340 $height = $width;
1341 }
1342
1343 if ($width == 9999) {
1344 $width = $height;
1345 }
1346 // theme is not supporting but settings were not changed
1347 if (empty($width)) {
1348 $debug .= 'Using default width;';
1349 $width = get_option('thumbnail_size_w');
1350 }
1351 if (empty($height)) {
1352 $debug .= 'Using default height;';
1353 $height = get_option('thumbnail_size_h');
1354 }
1355
1356 $debug .= 'Got sizes ' . $width . 'x' . $height . ';';
1357 $title_tag = apply_filters('relpoststh_title_tag', get_option( 'relpoststh_title_tag', 'h2' ) );
1358
1359 // rendering related posts HTML
1360 if ($show_top) {
1361 if (!empty($main_title)) {
1362
1363 $output .= '<' . esc_attr( $title_tag ) . ' class="relpoststh-block-title">' . esc_html( $main_title ) . '</' . esc_attr( $title_tag ) . '>';
1364 } else {
1365 $top_text = stripslashes(get_option('relpoststh_top_text', $this->top_text));
1366 $output .= stripslashes(apply_filters('rpt_top_text', $top_text));
1367 }
1368 }
1369
1370 $relpoststh_output_style = get_option('relpoststh_output_style', $this->output_style);
1371 $relpoststh_show_date = get_option('relpoststh_show_date', '0');
1372 $relpoststh_date_format = get_option('relpoststh_date_format', $this->format);
1373
1374 $relpoststh_cleanhtml = get_option('relpoststh_cleanhtml', 0);
1375 $text_height = get_option('relpoststh_textblockheight', $this->text_block_height);
1376 $column = get_option('relpoststh_column', $this->relpoststh_column) ?: "3";
1377 $column_t = get_option('relpoststh_column_t', $this->relpoststh_column_t) ?: "2";
1378 $column_m = get_option('relpoststh_column_m', $this->relpoststh_column_m) ?: "2";
1379 $relpoststh_image_size = get_option('relpoststh_image_size', $this->relpoststh_image_size) ?: "1/1";
1380
1381 $column_layout = '';
1382 if($column !== ''){
1383 $column_layout = "relpost-block-column-layout";
1384 }
1385
1386
1387 if ($relpoststh_output_style == 'list') {
1388 $output .= '<!-- related_posts_thumbnails -->';
1389 $output .= '<ul id="related_posts_thumbnails"';
1390 if (!$relpoststh_cleanhtml) {
1391 $output .= ' style="list-style-type:none; list-style-position: inside; padding: 0; margin:0"';
1392 }
1393 $output .= '>';
1394 } else {
1395
1396 $output .= '<div style="clear: both"></div>';
1397
1398 // $output .= '<!-- related-posts-nav -->';
1399 // $output .= '<ul class="related-posts-nav">'; //open blocks ul
1400
1401 $output .= '<div style="clear: both"></div>';
1402
1403 $output .= '<!-- relpost-block-container -->';
1404 $output .= '<div class="relpost-block-container ' . $column_layout . '" style="--relposth-columns: '. $column .';--relposth-columns_t: '. $column_t .'; --relposth-columns_m: '. $column_m .'">'; // open relpost-block-container div
1405 }
1406
1407 foreach ($posts as $post) {
1408 $image = '';
1409 $url = '';
1410 $alt = '';
1411 $category_list = '';
1412 $post_id = $post->ID;
1413 $taxonomies = get_object_taxonomies($post_type);
1414
1415 /**
1416 * Show the Categories names of a post in related post thumbnails.
1417 *
1418 * @since 2.2.0
1419 * @version 4.3.0
1420 */
1421 if ($show_category) {
1422 $category_list = $this->rpt_get_post_category_list( $show_category, $taxonomies, $post, $post_type );
1423 }
1424
1425 // Setting's option to show the first image of the article, if no featured image is set
1426 $articlefirstimage = get_option('relpoststh_articlefirstimage', '1');
1427 if ($thsource == 'custom-field') {
1428 $custom_field = get_option('relpoststh_customfield', $this->custom_field);
1429 $custom_field_meta = get_post_meta( $post_id, $custom_field );
1430 if (empty($custom_field)) {
1431 $debug .= 'No custom field specifield, using default thumbnail image;';
1432 $url = $this->default_image;
1433 } elseif (empty($custom_field_meta) && apply_filters('rpt_remove_empty_cfield', false)) {
1434 $debug .= 'Custom field meta is empty, using rpt_remove_empty_cfield filter;';
1435 continue;
1436 } elseif (empty($custom_field_meta)) {
1437 $debug .= 'Custom field meta is empty, using default thumbnail image;';
1438 $url = $this->default_image;
1439 } else {
1440 $debug .= 'Using custom field;';
1441
1442 /**
1443 * Fix the single URL or Image object.
1444 *
1445 * @since 2.0.3
1446 * @version 2.0.4
1447 */
1448 if (is_array($custom_field_meta) && isset($custom_field_meta[0])) {
1449 // If your post meta has an attachment ID instead of string URL.
1450 $url = wp_get_attachment_image_src($custom_field_meta[0]) ? wp_get_attachment_image_src($custom_field_meta[0])[0] : $this->default_image;
1451
1452 /**
1453 * Check if the custom field has string or int saved in it.
1454 * Upon this condition serve the image accordingly.
1455 *
1456 * @since 2.0.4
1457 */
1458 $url = isset($custom_field_meta[0]) && (int)$custom_field_meta[0] ? $url : $custom_field_meta[0];
1459 } else {
1460 $url = isset($custom_field_meta) && !empty($custom_field_meta) ? $custom_field_meta : $this->default_image;
1461 }
1462
1463 $theme_resize_url = get_option('relpoststh_theme_resize_url', '');
1464
1465 if (strpos($url, '/wp-content') !== false) {
1466 $url = substr($url, strpos($url, '/wp-content'));
1467 }
1468
1469 if (!empty($theme_resize_url)) {
1470 $url = $theme_resize_url . '?src=' . $url . '&w=' . $width . '&h=' . $height . '&zc=1&q=90';
1471 }
1472 }
1473 } else {
1474
1475 // using built in WordPress Thumbnails Feature
1476 if (current_theme_supports('post-thumbnails')) {
1477
1478 $post_thumbnail_id = get_post_thumbnail_id( $post_id );
1479 $debug .= 'Post-thumbnails enabled in theme;';
1480
1481 if (!(empty($post_thumbnail_id) || $post_thumbnail_id === false)) { // post has thumbnail
1482 $debug .= 'Post has thumbnail ' . $post_thumbnail_id . ';';
1483 $debug .= 'Postthname: ' . $poststhname . ';';
1484 $image = wp_get_attachment_image_src($post_thumbnail_id, $poststhname);
1485 $alt = get_post_meta($post_thumbnail_id, '_wp_attachment_image_alt', true);
1486 /**
1487 * Add the image check if found.
1488 *
1489 * @since 3.0.3
1490 */
1491 $url = !is_bool($image) && isset($image[0]) ? $image[0] : false;
1492 } else {
1493 $debug .= 'Post has no thumbnail;';
1494 }
1495
1496 }
1497
1498 }
1499
1500 if (strpos($url, '/') === 0) {
1501 $url = get_bloginfo('url') . $url;
1502 $debug .= 'Relative url: ' . $url . ';';
1503 }
1504
1505 // Get the first image from the post body if the option is enabled
1506 if ( empty($url) && $articlefirstimage === '1' ) {
1507 $debug .= 'Getting image from post body;';
1508 $wud = wp_upload_dir();
1509
1510 // search the first uploaded image in content
1511 preg_match_all('|<img.*?src=[\'"](' . $wud['baseurl'] . '.*?)[\'"].*?>|i', $post->post_content, $matches);
1512
1513 if (isset($matches) && isset($matches[1][0])) {
1514 $image = $matches[1][0];
1515 $html = $matches[0][0];
1516
1517 if (!empty($html)) {
1518 preg_match('/alt="([^"]*)"/i', $html, $array);
1519
1520 if (!empty($array) && is_array($array)) {
1521 $explode_tag = explode('"', $array[0]);
1522 $alt = $explode_tag[1];
1523 }
1524 }
1525
1526 } else {
1527 $debug .= 'No image was found;';
1528 }
1529
1530 if (strlen(trim($image)) > 0) {
1531
1532 $image_sizes = @getimagesize($image);
1533
1534 if ($image_sizes === false) {
1535 $debug .= 'Unable to determine parsed image size';
1536 }
1537
1538 if (($image_sizes !== false && isset($image_sizes[0])) && $image_sizes[0] == $width) {
1539 // if this image is the same size
1540 $debug .= 'Image used is the required size;';
1541 $url = $image;
1542 } elseif (apply_filters('rpt_prevent_img_size_check', false) && $image_sizes[0] < $width) {
1543 // if this image is smaller than required size
1544 $debug .= 'Image used is smaller than the required size, rpt_prevent_img_size_check filter is active;';
1545 $url = $image;
1546 } else {
1547 $debug .= 'Changing image according to Wordpress standards;';
1548 $url = $image;
1549 }
1550
1551 } else {
1552 $debug .= 'Found wrong formatted image: ' . $image . ';';
1553 }
1554 }
1555
1556 // parsed URL is empty or no image found
1557 if (empty($url)) {
1558 $debug .= 'Image URL: ' . $url . ';';
1559 $debug .= 'Image is empty or no file. Using default image;';
1560 $url = $this->rpt_get_default_image_url();
1561 }
1562
1563 $title = $this->process_text_cut($post->post_title, $text_length);
1564 $post_excerpt = (empty($post->post_excerpt)) ? $post->post_content : $post->post_excerpt;
1565 $excerpt = $this->process_text_cut($post_excerpt, $excerpt_length);
1566 $aria_label = 'aria-label="' . esc_attr($alt) . '"';
1567
1568 if (empty($alt)) {
1569 $alt = str_replace('"', '', $title);
1570 $aria_label = 'aria-hidden="true"';
1571 }
1572 if ( ! empty( $title) ) {
1573 $title = '<' . esc_attr( $title_tag ) . ' class="relpost_card_title">' . esc_html( $title ) . '</' . esc_attr( $title_tag ) . '>';
1574
1575 }
1576 if (!empty($excerpt)) {
1577 $excerpt = '<div class="relpost_card_exerpt">' . $excerpt . '</div>';
1578 }
1579
1580 $fontface = str_replace( '"', "'", stripslashes( get_option( 'relpoststh_fontfamily', $this->font_family ) ) );
1581 $debug .= 'Using title with size ' . $text_length . '. Using excerpt with size ' . $excerpt_length . ';';
1582 $after_content = apply_filters( 'rpth_after_content', '', $post );
1583
1584 $date_output = '';
1585
1586 /**
1587 * Get the date format from the settings.
1588 *
1589 * @since 1.9.3
1590 */
1591 if ('0' !== $relpoststh_show_date) {
1592 $date = get_the_date($relpoststh_date_format, $post_id );
1593 $date_output = '<span class="rpth_list_date">' . $date . '</span>';
1594 }
1595
1596 if ( $show_category ) {
1597 $category_list = $this->rpt_get_post_category_list( $show_category, $taxonomies, $post, $post_type );
1598 }
1599
1600 if ($relpoststh_output_style == 'list') {
1601 $link = get_permalink( $post_id );
1602 $output .= '<li ';
1603
1604 // if ( !$relpoststh_cleanhtml ) {
1605 // $output .= ' onmouseout="this.style.backgroundColor=\'' . get_option( 'relpoststh_background', $this->background ) . '\'"';
1606 // }
1607
1608 $output .= '>';
1609 $output .= '<a href="' . $link . '"><img class="relpost-post-image lazy-load" alt="' . esc_attr( $alt ) . '" data-src="' . esc_url( $url ) . '" width="' . esc_attr( $width ) . '" height="' . esc_attr( $height ) . '" ';
1610
1611 if ( $relpoststh_image_size ) {
1612 $output .= 'style="aspect-ratio:' . esc_attr( $relpoststh_image_size ) . '"';
1613 }
1614
1615 $output .= '/></a>';
1616
1617 if ($text_height != '0') {
1618 $output .= '<a href="' . $link . '" class="relpost_content"';
1619
1620 if (!$relpoststh_cleanhtml) {
1621 $output .= ' style="width: ' . $width . 'px;height: ' . $text_height . 'px; font-family: ' . $fontface . '; "';
1622 }
1623
1624
1625 // $output .= '><span class="rpth_list_content">' . $title . $excerpt . '</span>' . $date . '</a></li>';
1626 $output .= '><span class="rpth_list_content">' . $title . $excerpt . $date_output . $category_list . '</span>' . $after_content . '</a></li>';
1627 }
1628 } else {
1629 //if lazy-load is not activated
1630 $rpt_single_background = apply_filters('rpt-single-background', 'data-bg="' . esc_url( $url ) . '" style="background: transparent no-repeat scroll 0% 0%; width: ' . esc_attr( $width ) . 'px; height: ' . esc_attr( $height ) . 'px; aspect-ratio: ' . esc_attr( $relpoststh_image_size ) . ';"');
1631
1632 //if lazy-load is activated.
1633 $rpt_lazy_single_background = apply_filters('rpt-lazy-loading', false);
1634
1635 $rpt_anchor_attrs = array(
1636 'class' => '',
1637 'target' => false,
1638 );
1639
1640 /**
1641 * Filter to enhance the related post thumbnail anchor attribute such as open post in a new tab.
1642 *
1643 * @param int $post ->ID Current post ID.
1644 * @param array $rpt_anchor_attrs array of the attributes.
1645 *
1646 * @since 1.9.2
1647 */
1648 $rpt_anchor_attr_filter = (array)apply_filters('relpost_anchor_attr', $post_id, $rpt_anchor_attrs);
1649
1650 /**
1651 * Array Containing Allowed attributes.
1652 */
1653 $allowed_anchor_attrs = array('title', 'class', 'target');
1654
1655 // Pattern for data-* attribute.
1656 $data_attr_ptrn = "/data-/i";
1657
1658 $relpost_attributes = 'class="relpost-block-single';
1659
1660 // Attr sets for class including default class.
1661 if (array_key_exists('class', $rpt_anchor_attr_filter)) {
1662
1663 // Class attributes in string.
1664 $class_attrs_str = esc_attr(wp_unslash($rpt_anchor_attr_filter['class']));
1665 // Class attributes in array.
1666 $class_attrs = explode(" ", $class_attrs_str);
1667
1668 foreach ($class_attrs as $value) {
1669 if ('relpost-block-single' !== $value && !empty($value)) {
1670 $relpost_attributes .= ' ' . $value;
1671 }
1672 }
1673 }
1674 $relpost_attributes .= '" ';
1675
1676 foreach ($rpt_anchor_attr_filter as $rel_post_a_attr => $value) {
1677
1678 $value = esc_attr(wp_unslash($value));
1679 $rel_post_a_attr = esc_attr(wp_unslash($rel_post_a_attr));
1680
1681 if (false !== $value && !empty($value) && $rel_post_a_attr !== 'class' && (in_array($rel_post_a_attr, $allowed_anchor_attrs) || preg_match($data_attr_ptrn, $rel_post_a_attr))) {
1682 $relpost_attributes .= $rel_post_a_attr . '="' . $value . '"';
1683 }
1684 }
1685
1686 $output .= '<a href="' . get_permalink( $post_id ) . '"' . $relpost_attributes . '>';
1687
1688 $output .= '<div class="relpost-custom-block-single">';
1689 if ($rpt_lazy_single_background) {
1690 $output .= '<img loading="lazy" class="relpost-block-single-image" alt="' . esc_attr($alt) . '" src="' . esc_url($url) . '" style="aspect-ratio:'.$relpoststh_image_size.'" style="aspect-ratio:'.$relpoststh_image_size.'">' . $date_output . $category_list . '</img>';
1691 } else {
1692 $output .= '<div class="relpost-block-single-image rpt-lazyload" ' . $aria_label . ' role="img" ' . $rpt_single_background . '></div>';
1693 }
1694 $output .= '<div class="relpost-block-single-text" style="height: ' . ($text_height) . 'px;font-family: ' . $fontface . '; font-size: ' . get_option('relpoststh_fontsize', $this->font_size) . 'px; color: ' . get_option('relpoststh_fontcolor', $this->font_color) . ';">' . $title . $excerpt . $date_output . $category_list . '</div>';
1695 $output .= $after_content;
1696 // $output .= $date;
1697 $output .= '</div>';
1698 $output .= '</a>';
1699 }
1700
1701 } // end foreach
1702
1703 if ($relpoststh_output_style == 'list') {
1704 $output .= '</ul>';
1705 $output .= '<!-- close related_posts_thumbnails -->';
1706 } else {
1707 $output .= '</div>';
1708 $output .= '<!-- close relpost-block-container -->';
1709 // $output .= '</ul>';
1710 // $output .= '<!-- close related-posts-nav -->';
1711 }
1712
1713 $output .= '<div style="clear: both"></div>';
1714
1715 $output .= '</div>';
1716 $output .= '<!-- close filter class -->';
1717
1718 $output .= '</div>';
1719 $output .= '<!-- close relpost-thumb-wrapper -->';
1720
1721 return $this->finish_process($output, $debug, $time);
1722 }
1723
1724 /**
1725 * Show Related Post Categories.
1726 *
1727 * @param int $id The ID of post.
1728 *
1729 * @return string $category_list The structure of category list.
1730 *
1731 * @since 2.2.0
1732 */
1733 function relpoststh_category_list($id, $taxonomy, $post_type)
1734 {
1735
1736 $category_list_struct = '';
1737
1738 $category_list = $this->relpoststh_get_featured_category($id, $taxonomy, $post_type);
1739
1740 // Bail early if category list is not found.
1741 if (false === $category_list) {
1742 return $category_list_struct;
1743 }
1744
1745 /**
1746 * Modifiy the category listings.
1747 *
1748 * @param int $id The ID of post.
1749 * @return string $category_list The category list of current post at hand.
1750 * @return string $taxonomy The taxonomy of a post.
1751 *
1752 * @since 2.2.0
1753 * @version 4.3.0
1754 */
1755 $category_list = apply_filters('relpoststh_show_all_categories', $category_list, $id, $taxonomy, $post_type);
1756 $category_names = array();
1757
1758 if ( is_array( $category_list ) && ! empty( $category_list[0] ) ) {
1759 foreach ( $category_list[0] as $item ) {
1760 if ( isset( $item->name ) ) {
1761 $category_names[] = $item->name;
1762 }
1763 }
1764 } elseif ( ! empty( $category_list->name ) ) {
1765 $category_names[] = $category_list->name;
1766 }
1767
1768 $html = '';
1769
1770 if (!empty($category_names)) {
1771 $category_names = implode(', ', $category_names);
1772 $html .= '<div class="relpoststh_front_cat">';
1773 $html .= '<span>' . esc_html($category_names) . '</span>';
1774 $html .= '</div>';
1775 }
1776
1777 return $html;
1778 }
1779
1780 /**
1781 * Returns the featured category of a post based on YOAST SEO's meta-data.
1782 *
1783 * @param int $post_ID The post id.
1784 * @param int $taxonomy_name The taxonomy name.
1785 *
1786 * @return object
1787 * @since 2.2.0
1788 * @version 3.0.1
1789 */
1790 function relpoststh_get_featured_category($post_ID, $taxonomy_name = 'category', $post_type = 'post')
1791 {
1792
1793 // if the ID is not set, get the global ID.
1794 if (!is_numeric($post_ID)) {
1795 $post_ID = get_the_ID();
1796 }
1797
1798 $args = array(
1799 'post_type' => $post_type,
1800 );
1801
1802 $taxonomy_name = is_array($taxonomy_name) ? $taxonomy_name[0] : $taxonomy_name;
1803 $categories = wp_get_object_terms($post_ID, $taxonomy_name, $args);
1804
1805 if (!empty($categories) && is_wp_error($categories)) {
1806 return false;
1807 }
1808
1809 // get the yoast 'primary_category' from meta-data.
1810 $yoast_primary_category = get_post_meta($post_ID, '_yoast_wpseo_primary_' . $taxonomy_name, true);
1811
1812 if ($yoast_primary_category) {
1813
1814 // if meta-data exists, find the primary category.
1815 foreach ($categories as $category) {
1816
1817 if ($yoast_primary_category == $category->term_id) {
1818 return $category;
1819 }
1820 }
1821 }
1822
1823 // return the first category.
1824 if (isset($categories) && !empty($categories[0])) {
1825 return $categories[0];
1826 }
1827 }
1828
1829 // function is_url_404( $url ) {
1830 // $response = wp_remote_request( $url,
1831 // array(
1832 // 'method' => 'GET'
1833 // )
1834 // );
1835
1836 // return $response['response']['code'];
1837 // }
1838
1839 /**
1840 * This will add debugging information in HTML source
1841 *
1842 * @param $output
1843 * @param $debug
1844 * @param int $time time took to create the thumbnails
1845 *
1846 * @return $output debugged information
1847 */
1848 function finish_process($output, $debug, $time)
1849 {
1850
1851 $devmode = get_option('relpoststh_devmode', $this->devmode);
1852
1853 if ($devmode) {
1854 $time = microtime(true) - $time;
1855 $debug .= "Plugin execution time: $time sec;";
1856 $output .= '<!-- ' . $debug . ' -->';
1857 }
1858
1859 return $output;
1860 }
1861
1862 function process_text_cut($text, $length)
1863 {
1864
1865 if ($length == 0) {
1866 return '';
1867 } else {
1868 $text = strip_tags(strip_shortcodes($text));
1869
1870 if (function_exists('mb_strlen')) {
1871 return ((mb_strlen($text) > $length) ? mb_substr($text, 0, $length) . '...' : $text);
1872 } else {
1873 return ((strlen($text) > $length) ? substr($text, 0, $length) . '...' : $text);
1874 }
1875 }
1876 }
1877
1878 /**
1879 * Function to check th options to show the thumbnails according to the post types, categories etc.
1880 *
1881 * @return boolean
1882 */
1883 function is_relpoststh_show()
1884 {
1885 // Checking display options
1886 if (!is_single() && get_option('relpoststh_single_only', $this->single_only)) { // single only
1887 return false;
1888 }
1889 // Check post type
1890 $post_types = get_option('relpoststh_post_types', $this->post_types);
1891 $post_type = get_post_type();
1892
1893 if (!in_array($post_type, $post_types)) {
1894 return false;
1895 }
1896 // Check categories
1897 $id = get_the_ID();
1898 $categories_all = get_option('relpoststh_categoriesall', $this->categories_all);
1899
1900 if ($categories_all != '1') { // only specific categories were selected
1901
1902 $post_categories = wp_get_object_terms($id, array('category'), array('fields' => 'ids'));
1903 $relpoststh_categories = get_option('relpoststh_categories');
1904
1905 if (!is_array($relpoststh_categories) || !is_array($post_categories)) { // no categories were selcted or post doesn't belong to any
1906 return false;
1907 }
1908
1909 $common_categories = array_intersect($relpoststh_categories, $post_categories);
1910
1911 if (empty($common_categories)) { // post doesn't belong to specified categories
1912 return false;
1913 }
1914 }
1915
1916 return true;
1917 }
1918
1919 /**
1920 * Clear related ID cache when a post is saved.
1921 *
1922 * @param int $post_id Post ID.
1923 * @return void
1924 * @since 5.0.0
1925 */
1926 public function rpt_invalidate_post_cache_on_save( $post_id ) {
1927 if ( ! rpt_is_related_cache_enabled() ) {
1928 return;
1929 }
1930
1931 if ( wp_is_post_revision( $post_id ) || wp_is_post_autosave( $post_id ) ) {
1932 return;
1933 }
1934
1935 rpt_delete_post_related_cache( $post_id );
1936 }
1937
1938 /**
1939 * Clear related ID cache when a post is trashed or deleted.
1940 *
1941 * @param int $post_id Post ID.
1942 * @return void
1943 * @since 5.0.0
1944 */
1945 public function rpt_invalidate_post_cache_on_delete( $post_id ) {
1946 if ( ! rpt_is_related_cache_enabled() ) {
1947 return;
1948 }
1949
1950 rpt_delete_post_related_cache( $post_id );
1951 }
1952
1953 /**
1954 * Add purge cache link to the admin bar.
1955 *
1956 * @param WP_Admin_Bar $admin_bar Admin bar instance.
1957 * @return void
1958 * @since 5.0.0
1959 */
1960 public function rpt_admin_bar_cache_purge( $admin_bar ) {
1961 if ( ! is_user_logged_in() || ! current_user_can( 'manage_options' ) || ! rpt_is_related_cache_enabled() ) {
1962 return;
1963 }
1964
1965 $admin_bar->add_node(
1966 array(
1967 'id' => 'rpt-purge-cache',
1968 'title' => esc_html__( 'Purge RPT Cache', 'related-posts-thumbnails' ),
1969 'href' => wp_nonce_url(
1970 admin_url( 'admin-post.php?action=rpt_purge_cache' ),
1971 'rpt_purge_cache'
1972 ),
1973 )
1974 );
1975 }
1976
1977 /**
1978 * Handle admin bar cache purge requests.
1979 *
1980 * @return void
1981 * @since 5.0.0
1982 */
1983 public function rpt_handle_admin_purge_cache() {
1984 if ( ! current_user_can( 'manage_options' ) ) {
1985 wp_die( esc_html__( 'No access', 'related-posts-thumbnails' ) );
1986 }
1987
1988 check_admin_referer( 'rpt_purge_cache' );
1989
1990 rpt_purge_all_related_cache();
1991
1992 $redirect = wp_get_referer();
1993
1994 if ( ! $redirect ) {
1995 $redirect = admin_url( 'admin.php?page=related-posts-thumbnails' );
1996 }
1997
1998 wp_safe_redirect( add_query_arg( 'rpt_cache_purged', '1', $redirect ) );
1999 exit;
2000 }
2001
2002 /**
2003 * Show cache purge notices in admin.
2004 *
2005 * @return void
2006 * @since 5.0.0
2007 */
2008 public function rpt_cache_purge_admin_notice() {
2009 if ( ! current_user_can( 'manage_options' ) ) {
2010 return;
2011 }
2012
2013 if ( isset( $_GET['rpt_cache_purged'] ) && '1' === sanitize_text_field( wp_unslash( (string) $_GET['rpt_cache_purged'] ) ) ) {
2014 $pending = '1' === get_option( RPT_CACHE_PURGE_PENDING_OPTION, '0' );
2015 $message = $pending
2016 ? esc_html__( 'Related posts cache purge started. Cleanup will continue in the background.', 'related-posts-thumbnails' )
2017 : esc_html__( 'Related posts cache purged successfully.', 'related-posts-thumbnails' );
2018
2019 echo '<div class="notice notice-success is-dismissible"><p>' . $message . '</p></div>';
2020 }
2021 }
2022
2023 /**
2024 * Admin Menu page
2025 *
2026 * @return void
2027 */
2028 function admin_menu()
2029 {
2030 add_menu_page(__('Related Posts Thumbnails', 'related-posts-thumbnails'), __('Related Posts', 'related-posts-thumbnails'), 'administrator', 'related-posts-thumbnails', array($this, 'admin_interface'), 'dashicons-screenoptions');
2031 add_submenu_page(
2032 'related-posts-thumbnails',
2033 __( 'Activate', 'related-posts-thumbnails' ),
2034 ' ',
2035 'manage_options',
2036 'rpt-optin',
2037 array( $this, 'render_optin' )
2038 );
2039 }
2040
2041 /**
2042 * Retrieves the category list for a post based on provided conditions.
2043 *
2044 * @param bool $show_category Whether to show categories.
2045 * @param array $taxonomies Array of taxonomies.
2046 * @param WP_Post|int $post Post object or post ID.
2047 * @param string $post_type The type of the post.
2048 *
2049 * @since 4.3.0
2050 * @return array|string Category list array or empty string.
2051 */
2052 private function rpt_get_post_category_list( $show_category, $taxonomies, $post, $post_type ) {
2053 // Ensure $post is a valid post ID or object
2054 $post_id = is_object( $post ) && isset( $post->ID) ? $post->ID : ( is_numeric( $post ) ? intval( $post ) : 0 );
2055
2056 if ( ! $show_category || $post_id === 0 ) {
2057 return '';
2058 }
2059
2060 if ( is_array( $taxonomies ) && isset( $taxonomies[0] ) ) {
2061 return $this->relpoststh_category_list( $post_id, $taxonomies[0], $post_type );
2062 }
2063
2064 // Add missing return statement
2065 return '';
2066 }
2067
2068 /**
2069 * Related post thumbnail settings page load
2070 *
2071 * @return void
2072 */
2073 function admin_interface()
2074 {
2075 include_once RELATED_POSTS_THUMBNAILS_PLUGIN_DIR . '/inc/rpt-settings.php';
2076 }
2077
2078 /**
2079 * Category List in Settings
2080 *
2081 * @param $categoriesall
2082 * @param $categories
2083 * @param $selected_categories
2084 * @param $all_name
2085 * @param $specific_name
2086 */
2087 function display_categories_list($categoriesall, $categories, $selected_categories, $all_name, $specific_name)
2088 { ?>
2089 <input style="display:none" id="<?php echo esc_attr($all_name) . '_check'; ?>" class="select_all"
2090 type="checkbox" name="<?php echo esc_attr($all_name); ?>" value="1" <?php
2091 if ($categoriesall == '1') {
2092 echo 'checked="checked"';
2093 } ?>
2094 />
2095 <label style="display:none" for="<?php echo esc_attr($all_name); ?>">
2096 <?php _e('All', 'related-posts-thumbnails'); ?>
2097 </label>
2098 <div class="select_specific" <?php echo esc_attr($specific_name);
2099 if ($categoriesall == '1'): ?>
2100 style="display:none"
2101 <?php endif; ?> >
2102 </div>
2103 <select class="chosen-select <?php echo esc_attr($all_name); ?>"
2104 data-placeholder="<?php _e('Select Categories', 'related-posts-thumbnails'); ?>"
2105 id="<?php echo esc_attr($all_name); ?>" name="<?php echo esc_attr($specific_name); ?>[]" multiple>
2106 <option value="0" <?php if ($categoriesall == '1') {
2107 echo 'selected="selected"';
2108 } ?>><?php _e('All', 'related-posts-thumbnails'); ?></option>
2109 <?php foreach ($categories as $category): ?>
2110 <option value="<?php echo esc_attr($category->cat_ID); ?>" <?php
2111 if ($categoriesall !== '1' && in_array($category->cat_ID, (array)$selected_categories)) {
2112 echo 'selected="selected"';
2113 }
2114 ?>><?php echo esc_html($category->cat_name); ?></option>
2115 <?php endforeach; ?>
2116 </select>
2117 <?php }
2118
2119 /**
2120 * Main Instance
2121 *
2122 * @return Main instance
2123 * @see related_posts_thumbnails_loader()
2124 * @since 2.0.1
2125 * @static
2126 */
2127 public static function instance()
2128 {
2129
2130 if (is_null(self::$instance)) {
2131 self::$instance = new self();
2132 }
2133 return self::$instance;
2134 }
2135 }
2136
2137 /**
2138 * Returns the main instance of WP to prevent the need to use globals.
2139 *
2140 * @return RelatedPostsThumbnails instance
2141 * @since 2.0.1
2142 */
2143 if (!function_exists('related_posts_thumbnails_loader')) {
2144 function related_posts_thumbnails_loader()
2145 {
2146 return RelatedPostsThumbnails::instance();
2147 }
2148 }
2149
2150 // Call the function.
2151 global $related_posts_thumbnails;
2152 $related_posts_thumbnails = related_posts_thumbnails_loader();
2153
2154
2155 // Include frontend assets handler.
2156 include_once plugin_dir_path( __FILE__ ) . 'inc/rpt-assets.php';
2157 RPT_Frontend_Assets::rpt_init( __FILE__ );
2158
2159 // Include Widget File.
2160 include_once plugin_dir_path(__FILE__) . 'inc/rpt-widget.php';
2161 // Include Blocks File.
2162 include_once plugin_dir_path(__FILE__) . 'inc/rpt-blocks.php';
2163
2164 ?>
2165