Plugin Directory

source: yet-another-related-posts-plugin/tags/5.30.3/classes/YARPP_Core.php

Last change on this file was 2905558, checked in by jeffparker, 2 years ago

tagging version 5.30.3

File size: 65.8 KB
Line 
1<?php
2
3/**
4 * @since 3.4 Put everything YARPP into an object, expected to be a singleton global $yarpp.
5 */
6class YARPP {
7
8        /**
9         * Here's a list of all the options YARPP uses (except version), as well as their default values,
10         * sans the yarpp_ prefix, split up into binary options and value options. These arrays are used in updating
11         * settings (yarpp_options.php) and other tasks.
12         */
13        public $default_options             = array();
14        public $pro_default_options         = array();
15        public $default_hidden_metaboxes    = array();
16        public $debug                       = false;
17        public $yarppPro                    = null;
18        public $generate_missing_thumbnails = null;
19        /**
20         * @var YARPP_Cache_Bypass
21         */
22        public $cache_bypass;
23        /**
24         * @var YARPP_Cache_Demo_Bypass
25         */
26        public $demo_cache_bypass;
27        /**
28         * @var YARPP_Cache
29         */
30        public $cache;
31        public $admin;
32        /**
33         * @var YARPP_DB_Schema
34         */
35        public $db_schema;
36
37        /**
38         * @var YARPP_Cache
39         */
40        private $active_cache;
41        private $storage_class;
42        private $default_dimensions = array(
43                'width'    => 120,
44                'height'   => 120,
45                'crop'     => false,
46                'size'     => '120x120',
47                '_default' => true,
48        );
49        /**
50         * @var bool Set to true while YARPP is rendering related posts (a very bad time to start looking for related
51         * content, and start infintely recursing !)
52         */
53        private $rendering_related_content;
54
55        public function __construct() {
56                $this->is_custom_template = false;
57                $this->load_default_options();
58                $this->yarppPro = $this->get_pro_options();
59
60                /* Loads the plugin's translated strings. */
61                load_plugin_textdomain( 'yet-another-related-posts-plugin', false, plugin_basename( YARPP_DIR ) . '/lang' );
62
63                /* Load cache object. */
64                $this->storage_class     = 'YARPP_Cache_' . ucfirst( YARPP_CACHE_TYPE );
65                $this->cache             = new $this->storage_class( $this );
66                $this->cache_bypass      = new YARPP_Cache_Bypass( $this );
67                $this->demo_cache_bypass = new YARPP_Cache_Demo_Bypass( $this );
68                $this->db_schema         = new YARPP_DB_Schema();
69                $this->db_options        = new YARPP_DB_Options();
70
71                register_activation_hook( __FILE__, array( $this, 'activate' ) );
72
73                /**
74                 * @since 3.2 Update cache on delete.
75                 */
76                add_action( 'delete_post', array( $this->cache, 'delete_post' ), 10, 1 );
77
78                /**
79                 * @since 3.5.3 Use transition_post_status instead of save_post hook.
80                 * @since 3.2.1 Handle post_status transitions.
81                 */
82                add_action( 'transition_post_status', array( $this->cache, 'transition_post_status' ), 10, 3 );
83
84                /**
85                 * Initializes yarpp rest routes
86                 */
87                if ( apply_filters( 'rest_enabled', true ) && class_exists( 'WP_REST_Controller' ) && class_exists( 'WP_REST_Posts_Controller' ) ) {
88                        include_once YARPP_DIR . '/classes/YARPP_Rest_Api.php';
89                        new YARPP_Rest_Api();
90                }
91
92                /* Automatic display hooks: */
93                /**
94                 * Allow filtering the priority of YARPP's placement.
95                 */
96                $content_priority     = apply_filters( 'yarpp_content_priority', 1200 );
97                $feed_priority        = apply_filters( 'yarpp_feed_priority', 600 );
98                $excerpt_rss_priority = apply_filters( 'yarpp_excerpt_rss_priority', 600 );
99
100                add_filter( 'the_content', array( $this, 'the_content' ), $content_priority );
101                add_action( 'bbp_template_after_single_topic', array( $this, 'add_to_bbpress' ) );
102                add_filter( 'the_content_feed', array( $this, 'the_content_feed' ), $feed_priority );
103                add_filter( 'the_excerpt_rss', array( $this, 'the_excerpt_rss' ), $excerpt_rss_priority );
104                add_action( 'wp_enqueue_scripts', array( $this, 'maybe_enqueue_thumbnails_stylesheet' ) );
105                add_filter( 'is_protected_meta', array( $this, 'is_protected_meta' ), 10, 3 );
106
107                /**
108                 * If we're using thumbnails, register yarpp-thumbnail size, if theme has not already.
109                 * Note: see FAQ in the readme if you would like to change the YARPP thumbnail size.
110                 * If theme has already yarpp-thumbnail size registered and we also try to register yarpp-thumbnail then it will throw a fatal error. So it is necessary to check if yarpp-thumbnail size is not registered.
111                 */
112                global $add_image_size_by_yarpp;
113
114                /**
115                 * Filters whether or not to register YARPP's image size "yarpp-thumbnail". Defaults to registering it
116                 * if it wasn't already by the theme or some other plugin. But if you don't want yarpp-thumbnail sizes being
117                 * generated at all, have it always return false.
118                 */
119                if ( apply_filters('yarpp_add_image_size', false === yarpp_get_image_sizes( 'yarpp-thumbnail' ) ) ) {
120                        $width  = 120;
121                        $height = 120;
122                        $crop   = true;
123                        add_image_size( 'yarpp-thumbnail', $width, $height, $crop );
124                        $add_image_size_by_yarpp = true;
125                } else {
126                        $add_image_size_by_yarpp = false;
127                }
128
129                if ( isset( $_REQUEST['yarpp_debug'] ) ) {
130                        $this->debug = true;
131                }
132
133                if ( ! $this->db_options->plugin_version_in_db() ) {
134                        $this->db_options->add_upgrade_flag();
135                }
136
137                /**
138                 * @since 3.4 Only load UI if we're in the admin.
139                 */
140                if ( is_admin() ) {
141                        require_once YARPP_DIR . '/classes/YARPP_Admin.php';
142                        $this->admin = new YARPP_Admin( $this );
143                        if ( ! defined( 'DOING_AJAX' ) ) {
144                                $this->enforce();
145                        }
146                }
147                $shortcode = new YARPP_Shortcode();
148                $shortcode->register();
149        }
150
151        /**
152         * Add yarpp_meta key to protected list.
153         *
154         * @since 5.19
155         *
156         * @param bool   $protected Whether the key is considered protected.
157         * @param string $meta_key  Metadata key.
158         * @param string $meta_type Type of object metadata is for. Accepts 'post', 'comment', 'term', 'user',
159         *                          or any other object type with an associated meta table.
160         */
161        public function is_protected_meta( $protected, $meta_key, $meta_type ) {
162                if ( 'yarpp_meta' === $meta_key ) {
163                        return true;
164                }
165                return $protected;
166        }
167
168        /**
169         * OPTIONS
170         */
171        private function load_pro_default_options() {
172                return array(
173                        'active'                  => '0',
174                        'aid'                     => null,
175                        'st'                      => null,
176                        'v'                       => null,
177                        'dpid'                    => null,
178                        'optin'                   => false,
179                        'auto_display_post_types' => array( 'post' ),
180                );
181        }
182
183        private function load_default_options() {
184                $this->default_options = array(
185                        'threshold'                           => 1,
186                        'limit'                               => 4,
187                        'excerpt_length'                      => 10,
188                        'recent'                              => false,
189                        'before_title'                        => '<li>',
190                        'after_title'                         => '</li>',
191                        'before_post'                         => ' <small>',
192                        'after_post'                          => '</small>',
193                        'before_related'                      => '<h3>' . __( 'Related posts:', 'yet-another-related-posts-plugin' ) . '</h3><ol>',
194                        'after_related'                       => '</ol>',
195                        'no_results'                          => '<p>' . __( 'No related posts.', 'yet-another-related-posts-plugin' ) . '</p>',
196                        'order'                               => 'score DESC',
197                        'rss_limit'                           => 3,
198                        'rss_excerpt_length'                  => 10,
199                        'rss_before_title'                    => '<li>',
200                        'rss_after_title'                     => '</li>',
201                        'rss_before_post'                     => ' <small>',
202                        'rss_after_post'                      => '</small>',
203                        'rss_before_related'                  => '<h3>' . __( 'Related posts:', 'yet-another-related-posts-plugin' ) . '</h3><ol>',
204                        'rss_after_related'                   => '</ol>',
205                        'rss_no_results'                      => '<p>' . __( 'No related posts.', 'yet-another-related-posts-plugin' ) . '</p>',
206                        'rss_order'                           => 'score DESC',
207                        'past_only'                           => false,
208                        'show_excerpt'                        => false,
209                        'rss_show_excerpt'                    => false,
210                        'template'                            => false,
211                        'rss_template'                        => false,
212                        'show_pass_post'                      => false,
213                        'cross_relate'                        => false,
214                        'include_sticky_posts'                => true,
215                        'generate_missing_thumbnails'         => false,
216                        'rss_display'                         => false,
217                        'rss_excerpt_display'                 => true,
218                        'promote_yarpp'                       => false,
219                        'rss_promote_yarpp'                   => false,
220                        'myisam_override'                     => false,
221                        'exclude'                             => '',
222                        'include_post_type'                   => get_post_types( array() ),
223                        'weight'                              => array(
224                                'title' => 0,
225                                'body'  => 0,
226                                'tax'   => array(
227                                        'category' => 1,
228                                        'post_tag' => 1,
229                                ),
230                        ),
231                        'require_tax'                         => array(),
232                        'optin'                               => false,
233                        'thumbnails_heading'                  => __( 'Related posts:', 'yet-another-related-posts-plugin' ),
234                        'thumbnails_default'                  => plugins_url( 'images/default.png', dirname( __FILE__ ) ),
235                        'rss_thumbnails_heading'              => __( 'Related posts:', 'yet-another-related-posts-plugin' ),
236                        'rss_thumbnails_default'              => plugins_url( 'images/default.png', dirname( __FILE__ ) ),
237                        'auto_display_archive'                => false,
238                        'auto_display_post_types'             => array( 'post' ),
239                        'pools'                               => array(),
240                        'manually_using_thumbnails'           => false,
241                        'rest_api_display'                    => true,
242                        'thumbnail_size_display'              => 0,
243                        'custom_theme_thumbnail_size_display' => 0,
244                        'thumbnail_size_feed_display'         => 0,
245                        'rest_api_client_side_caching'        => false,
246                        'yarpp_rest_api_cache_time'           => 15,
247                );
248        }
249
250        public function set_option( $options, $value = null ) {
251                $current_options = $this->get_option();
252
253                /* We can call yarpp_set_option(key,value) if we like. */
254                if ( ! is_array( $options ) ) {
255                        if ( isset( $value ) ) {
256                                $options = array( $options => $value );
257                        } else {
258                                return false;
259                        }
260                }
261
262                $new_options = array_merge( $current_options, $options );
263                $this->db_options->set_yarpp_options( $new_options );
264
265                // new in 3.1: clear cache when updating certain settings.
266                $clear_cache_options = array(
267                        'show_pass_post'       => 1,
268                        'recent'               => 1,
269                        'threshold'            => 1,
270                        'past_only'            => 1,
271                        'include_sticky_posts' => 1,
272                        'cross_relate'         => 1,
273                );
274
275                $relevant_options                = array_intersect_key( $options, $clear_cache_options );
276                $relevant_current_options        = array_intersect_key( $current_options, $clear_cache_options );
277                $new_options_which_require_flush = array_diff_assoc( $relevant_options, $relevant_current_options );
278
279                if ( count( $new_options_which_require_flush )
280                        || ( $new_options['limit'] > $current_options['limit'] )
281                        || ( $new_options['weight'] != $current_options['weight'] )
282                        || ( $new_options['exclude'] != $current_options['exclude'] )
283                        || ( $new_options['require_tax'] != $current_options['require_tax'] )
284                                                || ( $new_options['include_post_type'] != $current_options['include_post_type'] )
285                ) {
286                        $this->cache->flush();
287                }
288        }
289
290        /**
291         * @since 3.4b8 $option can be a path, of the query_str variety, i.e. "option[suboption][subsuboption]"
292         */
293        public function get_option( $option = null ) {
294                $options = $this->db_options->get_yarpp_options();
295
296                // ensure defaults if not set:
297                $options = array_merge( $this->default_options, $options );
298
299                if ( is_null( $option ) ) {
300                        return $options;
301                }
302
303                $optionpath    = array();
304                $parsed_option = array();
305                wp_parse_str( $option, $parsed_option );
306                $optionpath = $this->array_flatten( $parsed_option );
307
308                $current = $options;
309                foreach ( $optionpath as $optionpart ) {
310                        if ( ! is_array( $current ) || ! isset( $current[ $optionpart ] ) ) {
311                                return null;
312                        }
313                        $current = $current[ $optionpart ];
314                }
315
316                return $current;
317        }
318
319        private function get_pro_options() {
320                $current  = get_option( 'yarpp_pro' );
321                $defaults = $this->load_pro_default_options();
322
323                if ( $current ) {
324                        $out = array_merge( $defaults, $current );
325                        update_option( 'yarpp_pro', $out );
326                } else {
327                        $out = $defaults;
328                        add_option( 'yarpp_pro', $out );
329                }
330
331                return $out;
332        }
333
334        private function array_flatten( $array, $given = array() ) {
335                foreach ( $array as $key => $val ) {
336                        $given[] = $key;
337                        if ( is_array( $val ) ) {
338                                $given = $this->array_flatten( $val, $given );
339                        }
340                }
341                return $given;
342        }
343
344        /*
345         * INFRASTRUCTURE
346         */
347
348        /**
349         * @since 3.5.2 Function to enforce YARPP setup if not ready, activate; else upgrade.
350         */
351        public function enforce() {
352                if ( ! $this->enabled() ) {
353                        $this->activate(); // activate calls upgrade later, so it's covered.
354                } else {
355                        $this->upgrade();
356                }
357                if ( $this->get_option( 'optin' ) ) {
358                        $this->optin_ping();
359                }
360        }
361
362        public function enabled() {
363                if ( ! (bool) $this->cache->is_enabled() ) {
364                        return false;
365                } else {
366                        return $this->diagnostic_fulltext_indices();
367                }
368        }
369
370        public function activate() {
371                if ( (bool) $this->cache->is_enabled() === false ) {
372                        $this->cache->setup();
373                }
374
375                /* If we're not enabled, give up. */
376                if ( ! $this->enabled() ) {
377                        return false;
378                }
379
380                if ( ! $this->db_options->plugin_version_in_db() ) {
381                        $this->db_options->update_plugin_version_in_db();
382                        $this->version_info( true );
383                } else {
384                        $this->upgrade();
385                }
386
387                return true;
388        }
389
390        /**
391         * DIAGNOSTICS
392         *
393         * @since 4.0 Moved into separate functions. Note return value types can differ.
394         * @since 5.2.0 consider using $this->db_schema->posts_table_database_engine() or
395         *        $this->db_schema->database_supports_fulltext_indexes() instead
396         */
397        public function diagnostic_myisam_posts() {
398                $engine = $this->db_schema->posts_table_database_engine();
399                switch ( $engine ) {
400                        case 'MyISAM':
401                                return true;
402                        case null:
403                                return 'UNKNOWN';
404                        default:
405                                return $engine;
406                }
407        }
408
409        /**
410         * @deprecated in 5.14.0 we just always enable fulltext indexes, or keep checking for it, so this should never need
411         * to be called.
412         * @return bool
413         */
414        function diagnostic_fulltext_disabled() {
415                return $this->db_options->is_fulltext_disabled();
416        }
417
418        /**
419         * Attempts to add the fulltext indexes on the posts table.
420         *
421         * @since 5.1.8
422         * @deprecated use YARPP::enable_fulltext_titles() and YARPP::enable_fulltext_contents() instead
423         * @return bool
424         */
425        public function enable_fulltext() {
426                _deprecated_function( 'YARPP::enable_fulltext', '5.15.0' );
427                if ( ! $this->db_supports_fulltext() ) {
428                        return false;
429                }
430                if ( ! $this->enable_fulltext_titles() ) {
431                        return false;
432                }
433                if ( ! $this->enable_fulltext_contents() ) {
434                        return false;
435                }
436                return true;
437        }
438
439        protected function db_supports_fulltext() {
440                /*
441                 * If we haven't already re-attempted creating the database indexes and the database doesn't support adding
442                 * those indexes, disable it.
443                 */
444                if ( ! (bool) $this->get_option( YARPP_DB_Options::YARPP_MYISAM_OVERRIDE ) &&
445                        ! $this->db_schema->database_supports_fulltext_indexes() ) {
446                        $this->disable_fulltext();
447                        return false;
448                }
449                return true;
450        }
451        public function enable_fulltext_titles() {
452                if ( ! $this->db_schema->title_column_has_index() ) {
453                        if ( $this->db_schema->add_title_index() ) {
454                                $this->db_options->delete_fulltext_db_error_record();
455                        } else {
456                                $this->db_options->update_fulltext_db_record();
457                                $this->disable_fulltext();
458                                return false;
459                        }
460                }
461                return true;
462        }
463
464        public function enable_fulltext_contents() {
465                if ( ! $this->db_schema->content_column_has_index() ) {
466                        if ( $this->db_schema->add_content_index() ) {
467                                $this->db_options->delete_fulltext_db_error_record();
468                        } else {
469                                $this->disable_fulltext();
470                                $this->db_options->update_fulltext_db_record();
471                                return false;
472                        }
473                }
474                return true;
475        }
476
477        /**
478         * Stop considering post title and body in relatedness criteria.
479         */
480        public function disable_fulltext() {
481                if ( $this->db_options->is_fulltext_disabled() ) {
482                        return;
483                }
484
485                /* Remove title and body weights: */
486                $weight = $this->get_option( 'weight' );
487                unset( $weight['title'] );
488                unset( $weight['body'] );
489                $this->set_option( array( 'weight' => $weight ) );
490
491                /* cut threshold by half: */
492                $threshold = (float) $this->get_option( 'threshold' );
493                $this->set_option( array( 'threshold' => round( $threshold / 2 ) ) );
494        }
495
496        /**
497         * Returns true if we consider this to be a big database (based on posts records); false otherwise.
498         * Uses the constants YARPP_BIG_DB
499         *
500         * @return bool
501         */
502        public function diagnostic_big_db() {
503                global $wpdb;
504                if ( ! defined( 'YARPP_BIG_DB' ) ) {
505                        define( 'YARPP_BIG_DB', 5000 );
506                }
507                $sql = 'SELECT COUNT(*) FROM ' . $wpdb->posts;
508                // Note: count includes drafts, revisions, etc.
509                $posts_count = $wpdb->get_var( $sql );
510                return (int) $posts_count > YARPP_BIG_DB;
511        }
512
513        /**
514         * Try to retrieve fulltext index from database.
515         *
516         * @return bool
517         */
518        public function diagnostic_fulltext_indices() {
519                return $this->db_schema->title_column_has_index() && $this->db_schema->content_column_has_index();
520        }
521
522        public function diagnostic_hidden_metaboxes() {
523                global $wpdb;
524                $raw = $wpdb->get_var(
525                        "SELECT meta_value FROM $wpdb->usermeta " .
526                        "WHERE meta_key = 'metaboxhidden_settings_page_yarpp' " .
527                        'ORDER BY length(meta_value) ASC LIMIT 1'
528                );
529
530                if ( ! $raw ) {
531                        return $this->default_hidden_metaboxes;
532                }
533
534                $list = maybe_unserialize( $raw );
535                if ( ! is_array( $list ) ) {
536                        return $this->default_hidden_metaboxes;
537                }
538
539                return implode( '|', $list );
540        }
541
542        public function diagnostic_post_thumbnails() {
543                return current_theme_supports( 'post-thumbnails', 'post' );
544        }
545
546        public function diagnostic_custom_templates() {
547                return count( $this->get_templates() );
548        }
549
550        public function diagnostic_happy() {
551                $stats = $this->cache->stats();
552
553                if ( ! ( array_sum( $stats ) > 0 ) ) {
554                        return false;
555                }
556
557                $sum = array_sum( (array) array_map( 'array_product', array_map( null, array_values( $stats ), array_keys( $stats ) ) ) );
558                $avg = $sum / array_sum( $stats );
559
560                return ( $this->cache->cache_status() > 0.1 && $avg > 2 );
561        }
562
563        public function diagnostic_generate_thumbnails() {
564                if ( is_bool( $this->generate_missing_thumbnails ) ) {
565                        return $this->generate_missing_thumbnails;
566                }
567                return ( defined( 'YARPP_GENERATE_THUMBNAILS' ) && YARPP_GENERATE_THUMBNAILS ) || (bool) $this->get_option( 'generate_missing_thumbnails' );
568        }
569
570        public function diagnostic_using_thumbnails() {
571                if ( $this->get_option( 'manually_using_thumbnails' ) ) {
572                        return true;
573                }
574                if ( $this->get_option( 'template' ) === 'thumbnails' ) {
575                        return true;
576                }
577                if ( $this->get_option( 'rss_template' ) === 'thumbnails' && $this->get_option( 'rss_display' ) ) {
578                        return true;
579                }
580                return false;
581        }
582        public function get_thumbnail_option_name() {
583                if ( is_feed() ) {
584                        return 'thumbnail_size_feed_display';
585                }
586                $chosen_template = yarpp_get_option( 'template' );
587                // check if they're using a custom template
588                if ( 'thumbnails' === $chosen_template ) {
589                        return 'thumbnail_size_display';
590                }
591                return 'custom_theme_thumbnail_size_display';
592        }
593        public function thumbnail_dimensions() {
594                global $_wp_additional_image_sizes;
595                if ( ! isset( $_wp_additional_image_sizes['yarpp-thumbnail'] ) ) {
596                        return $this->default_dimensions;
597                }
598
599                // get user selected thumbnail size.
600                $dimensions = yarpp_get_thumbnail_image_dimensions( $this->get_thumbnail_option_name() );
601                if ( empty( $dimensions ) ) {
602                        $dimensions         = $_wp_additional_image_sizes['yarpp-thumbnail'];
603                        $dimensions['size'] = 'yarpp-thumbnail';
604                }
605
606                /* Ensure YARPP dimensions format: */
607                $dimensions['width']  = (int) $dimensions['width'];
608                $dimensions['height'] = (int) $dimensions['height'];
609                return $dimensions;
610        }
611
612        /**
613         * @deprecated 5.11.0
614         * @see \YARPP::maybe_enqueue_thumbnails_stylesheet
615         */
616        public function maybe_enqueue_thumbnails() {
617                _deprecated_function( 'YARPP::maybe_enqueue_thumbnails', '5.11.0', 'YARPP::maybe_enqueue_thumbnails_stylesheet' );
618                return $this->maybe_enqueue_thumbnails_stylesheet();
619        }
620
621        public function maybe_enqueue_thumbnails_stylesheet() {
622                if ( is_feed() ) {
623                        return;
624                }
625
626                $auto_display_post_types = $this->get_option( 'auto_display_post_types' );
627
628                /* If it's not an auto-display post type, return. */
629                if ( ! in_array( get_post_type(), $auto_display_post_types ) ) {
630                        return;
631                }
632
633                if ( ! is_singular() && ! ( $this->get_option( 'auto_display_archive' ) && ( is_archive() || is_home() ) ) ) {
634                        return;
635                }
636
637                if ( $this->get_option( 'template' ) !== 'thumbnails' ) {
638                        return;
639                }
640
641                $this->enqueue_thumbnails_stylesheet( $this->thumbnail_dimensions() );
642        }
643
644        /**
645         * @deprecated 5.11.0
646         * @see YARPP::enqueue_thumbnails_stylesheet()
647         * @param $dimensions
648         */
649        public function enqueue_thumbnails( $dimensions ) {
650                _deprecated_function( 'YARPP::enqueue_thumbnails', '5.11.0', 'YARPP::enqueue_thumbnails_stylesheet' );
651                return $this->enqueue_thumbnails_stylesheet( $dimensions );
652        }
653
654        /**
655         * @param $dimensions
656         */
657        public function enqueue_thumbnails_stylesheet( $dimensions ) {
658
659                wp_register_style( 'yarpp-thumbnails', plugins_url( '/style/styles_thumbnails.css', YARPP_MAIN_FILE ), array(), YARPP_VERSION );
660                /**
661                 * Filter to allow dequeing of styles_thumbnails.css.
662                 *
663                 * @param boolean default true
664                 */
665                $enqueue_yarpp_thumbnails = apply_filters( 'yarpp_enqueue_thumbnails_style', true );
666                if ( true === $enqueue_yarpp_thumbnails ) {
667                        $yarpp_custom_css = yarpp_thumbnail_inline_css( $dimensions );
668                        wp_enqueue_style( 'yarpp-thumbnails' );
669                        wp_add_inline_style( 'yarpp-thumbnails', $yarpp_custom_css );
670                }
671        }
672
673        /**
674         * Code based on Viper's Regenerate Thumbnails plugin '$dimensions' must be an array with size, crop, height, width attributes.
675         */
676        public function ensure_resized_post_thumbnail( $post_id, $dimensions ) {
677
678                $thumbnail_id = get_post_thumbnail_id( $post_id );
679                $downsized    = image_downsize( $thumbnail_id, $dimensions['size'] );
680
681                if ( $dimensions['crop'] && $downsized[1] && $downsized[2]
682                        && ( $downsized[1] != $dimensions['width'] || $downsized[2] != $dimensions['height'] )
683                ) {
684                        /*
685                         * We want to trigger re-computation of the thumbnail here.
686                        * (only if downsized width and height are specified, for Photon behavior)
687                        */
688                        $fullSizePath = get_attached_file( $thumbnail_id );
689                        if ( $fullSizePath !== false && file_exists( $fullSizePath ) ) {
690                                require_once ABSPATH . 'wp-admin/includes/image.php';
691                                $metadata = wp_generate_attachment_metadata( $thumbnail_id, $fullSizePath );
692                                if ( ! is_wp_error( $metadata ) ) {
693                                        wp_update_attachment_metadata( $thumbnail_id, $metadata );
694                                }
695                        }
696                }
697        }
698
699        private $templates = null;
700        /**
701         * Returns an Array of all the custom templates
702         *
703         * @return array
704         */
705        public function get_templates() {
706                if ( is_null( $this->templates ) ) {
707                        $this->templates = glob( STYLESHEETPATH . '/yarpp-template-*.php' );
708
709                        // if glob hits an error, it returns false.
710                        if ( $this->templates === false ) {
711                                $this->templates = array();
712                        }
713
714                        // get basenames only.
715                        $this->templates = (array) array_map( array( $this, 'get_template_data' ), $this->templates );
716                }
717                return (array) $this->templates;
718        }
719
720        /**
721         * Get all the available templates
722         *
723         * @since 5.27.2
724         * @return array
725         */
726        public function get_all_templates() {
727                $templates       = $this->get_templates();
728                $block_templates = array(
729                        esc_attr( 'builtin' )    => esc_html__( 'List', 'yet-another-related-posts-plugin' ),
730                        esc_attr( 'thumbnails' ) => esc_html__( 'Thumbnail', 'yet-another-related-posts-plugin' ),
731                );
732                foreach ( $templates as $template ) {
733                        $block_templates[ esc_attr( $template['basename'] ) ] = sprintf(
734                                /* translators: %s: yarpp template name */
735                                esc_html__( 'Custom: %s', 'yet-another-related-posts-plugin' ),
736                                $template['name']
737                        );
738                }
739
740                return $block_templates;
741        }
742
743        public function get_template_data( $file ) {
744                $headers          = array(
745                        'name'        => 'YARPP Template',
746                        'description' => 'Description',
747                        'author'      => 'Author',
748                        'uri'         => 'Author URI',
749                );
750                $data             = get_file_data( $file, $headers );
751                $data['file']     = $file;
752                $data['basename'] = basename( $file );
753
754                if ( empty( $data['name'] ) ) {
755                        $data['name'] = $data['basename'];
756                }
757
758                return $data;
759        }
760
761        /**
762         * UPGRADE ROUTINES
763         */
764
765        public function upgrade() {
766                $last_version = $this->db_options->plugin_version_in_db();
767
768                if ( version_compare( YARPP_VERSION, $last_version ) === 0 ) {
769                        return;
770                }
771                if ( $last_version && version_compare( '3.4b2', $last_version ) > 0 ) {
772                        $this->upgrade_3_4b2();
773                }
774                if ( $last_version && version_compare( '3.4b5', $last_version ) > 0 ) {
775                        $this->upgrade_3_4b5();
776                }
777                if ( $last_version && version_compare( '3.4b8', $last_version ) > 0 ) {
778                        $this->upgrade_3_4b8();
779                }
780                if ( $last_version && version_compare( '3.4.4b2', $last_version ) > 0 ) {
781                        $this->upgrade_3_4_4b2();
782                }
783                if ( $last_version && version_compare( '3.4.4b3', $last_version ) > 0 ) {
784                        $this->upgrade_3_4_4b3();
785                }
786                if ( $last_version && version_compare( '3.4.4b4', $last_version ) > 0 ) {
787                        $this->upgrade_3_4_4b4();
788                }
789                if ( $last_version && version_compare( '3.5.2b2', $last_version ) > 0 ) {
790                        $this->upgrade_3_5_2b2();
791                }
792                if ( $last_version && version_compare( '3.6b7', $last_version ) > 0 ) {
793                        $this->upgrade_3_6b7();
794                }
795                if ( $last_version && version_compare( '4.0.1', $last_version ) > 0 ) {
796                        $this->upgrade_4_0_1();
797                }
798
799                $this->cache->upgrade( $last_version );
800                /* flush cache in 3.4.1b5 as 3.4 messed up calculations. */
801                if ( $last_version && version_compare( '3.4.1b5', $last_version ) > 0 ) {
802                        $this->cache->flush();
803                }
804
805                $this->version_info( true );
806
807                $this->db_options->update_plugin_version_in_db();
808                $this->db_options->add_upgrade_flag();
809                $this->delete_transient( 'yarpp_optin' );
810        }
811
812        public function upgrade_3_4b2() {
813                global $wpdb;
814
815                $yarpp_3_3_options = array(
816                        'threshold'           => 4,
817                        'limit'               => 4,
818                        'template_file'       => '',
819                        'excerpt_length'      => 10,
820                        'recent_number'       => 12,
821                        'recent_units'        => 'month',
822                        'before_title'        => '<li>',
823                        'after_title'         => '</li>',
824                        'before_post'         => ' <small>',
825                        'after_post'          => '</small>',
826                        'before_related'      => '<h3>' . __( 'Related posts:', 'yet-another-related-posts-plugin' ) . '</h3><ol>',
827                        'after_related'       => '</ol>',
828                        'no_results'          => '<p>' . __( 'No related posts.', 'yet-another-related-posts-plugin' ) . '</p>',
829                        'order'               => 'score DESC',
830                        'rss_limit'           => 3,
831                        'rss_template_file'   => '',
832                        'rss_excerpt_length'  => 10,
833                        'rss_before_title'    => '<li>',
834                        'rss_after_title'     => '</li>',
835                        'rss_before_post'     => ' <small>',
836                        'rss_after_post'      => '</small>',
837                        'rss_before_related'  => '<h3>' . __( 'Related posts:', 'yet-another-related-posts-plugin' ) . '</h3><ol>',
838                        'rss_after_related'   => '</ol>',
839                        'rss_no_results'      => '<p>' . __( 'No related posts.', 'yet-another-related-posts-plugin' ) . '</p>',
840                        'rss_order'           => 'score DESC',
841                        'title'               => '2',
842                        'body'                => '2',
843                        'categories'          => '1',
844                        'tags'                => '2',
845                        'distags'             => '',
846                        'discats'             => '',
847                        'past_only'           => false,
848                        'show_excerpt'        => false,
849                        'recent_only'         => false,
850                        'use_template'        => false,
851                        'rss_show_excerpt'    => false,
852                        'rss_use_template'    => false,
853                        'show_pass_post'      => false,
854                        'cross_relate'        => false,
855                        'auto_display'        => true,
856                        'rss_display'         => false,
857                        'rss_excerpt_display' => true,
858                        'promote_yarpp'       => false,
859                        'rss_promote_yarpp'   => false,
860                );
861
862                $yarpp_options = array();
863                foreach ( $yarpp_3_3_options as $key => $default ) {
864                        $value = get_option( "yarpp_$key", null );
865                        if ( is_null( $value ) ) {
866                                continue;
867                        }
868
869                        if ( is_bool( $default ) ) {
870                                $yarpp_options[ $key ] = (bool) $value;
871                                continue;
872                        }
873
874                        // value options used to be stored with a bajillion slashes...
875                        $value = stripslashes( stripslashes( $value ) );
876                        // value options used to be stored with a blank space at the end... don't ask.
877                        $value = rtrim( $value, ' ' );
878
879                        if ( is_int( $default ) ) {
880                                $yarpp_options[ $key ] = absint( $value );
881                        } else {
882                                $yarpp_options[ $key ] = $value;
883                        }
884                }
885
886                // add the options directly first, then call set_option which will ensure defaults,
887                // in case any new options have been added.
888                update_option( 'yarpp', $yarpp_options );
889                $this->set_option( $yarpp_options );
890
891                $option_keys = array_keys( $yarpp_options );
892                // append some keys for options which are long deprecated:
893                $option_keys[] = 'ad_hoc_caching';
894                $option_keys[] = 'excerpt_len';
895                $option_keys[] = 'show_score';
896                if ( count( $option_keys ) ) {
897                        // This sanitization is sufficient because $option_keys are hardcoded above.
898                        $in = "('yarpp_" . join( "', 'yarpp_", $option_keys ) . "')";
899                        $wpdb->query( "DELETE FROM {$wpdb->options} WHERE option_name IN {$in}" );
900                }
901        }
902
903        public function upgrade_3_4b5() {
904                $options            = $this->get_option();
905                $options['exclude'] = array(
906                        'post_tag' => $options['distags'],
907                        'category' => $options['discats'],
908                );
909                unset( $options['distags'] );
910                unset( $options['discats'] );
911                update_option( 'yarpp', $options );
912        }
913
914        public function upgrade_3_4b8() {
915                $options           = $this->get_option();
916                $options['weight'] = array(
917                        'title' => (int) @$options['title'],
918                        'body'  => (int) @$options['body'],
919                        'tax'   => array(
920                                'post_tag' => (int) @$options['tags'],
921                                'category' => (int) @$options['categories'],
922                        ),
923                );
924
925                // ensure that we consider something.
926                if ( $options['weight']['title'] < 2
927                        && $options['weight']['body'] < 2
928                        && $options['weight']['tax']['post_tag'] < 2
929                        && $options['weight']['tax']['category'] < 2
930                ) {
931                        $options['weight'] = $this->default_options['weight'];
932                }
933
934                unset( $options['title'] );
935                unset( $options['body'] );
936                unset( $options['tags'] );
937                unset( $options['categories'] );
938
939                update_option( 'yarpp', $options );
940        }
941
942        public function upgrade_3_4_4b2() {
943                $options = $this->get_option();
944
945                // update weight values; split out tax weights into weight[tax] and require_tax
946                $weight_map = array(
947                        2 => 1,
948                        3 => YARPP_EXTRA_WEIGHT,
949                );
950
951                if ( (int) $options['weight']['title'] == 1 ) {
952                        unset( $options['weight']['title'] );
953                } else {
954                        $options['weight']['title'] = $weight_map[ (int) $options['weight']['title'] ];
955                }
956
957                if ( (int) $options['weight']['body'] == 1 ) {
958                        unset( $options['weight']['body'] );
959                } else {
960                        $options['weight']['body'] = $weight_map[ (int) $options['weight']['body'] ];
961                }
962
963                $options['require_tax'] = array();
964                foreach ( $options['weight']['tax'] as $tax => $value ) {
965                        if ( $value == 3 ) {
966                                $options['require_tax'][ $tax ] = 1;
967                        }
968                        if ( $value == 4 ) {
969                                $options['require_tax'][ $tax ] = 2;
970                        }
971
972                        if ( $value > 1 ) {
973                                $options['weight']['tax'][ $tax ] = 1;
974                        } else {
975                                unset( $options['weight']['tax'][ $tax ] );
976                        }
977                }
978
979                // consolidate excludes, using tt_ids.
980                $exclude_tt_ids = array();
981                if ( isset( $options['exclude'] ) && is_array( $options['exclude'] ) ) {
982                        foreach ( $options['exclude'] as $tax => $term_ids ) {
983                                if ( ! empty( $term_ids ) ) {
984                                        $lp_tmp         = wp_list_pluck( get_terms( $tax, array( 'include' => $term_ids ) ), 'term_taxonomy_id' );
985                                        $exclude_tt_ids = array_merge( $lp_tmp, $exclude_tt_ids );
986                                }
987                        }
988                }
989                $options['exclude'] = join( ',', $exclude_tt_ids );
990
991                update_option( 'yarpp', $options );
992        }
993
994        public function upgrade_3_4_4b3() {
995                $options = $this->get_option();
996
997                $options['template']     = ( $options['use_template'] ) ? $options['template_file'] : false;
998                $options['rss_template'] = ( $options['rss_use_template'] ) ? $options['rss_template_file'] : false;
999
1000                unset( $options['use_template'] );
1001                unset( $options['template_file'] );
1002                unset( $options['rss_use_template'] );
1003                unset( $options['rss_template_file'] );
1004
1005                update_option( 'yarpp', $options );
1006        }
1007
1008        public function upgrade_3_4_4b4() {
1009                $options = $this->get_option();
1010
1011                $options['recent'] = ( $options['recent_only'] ) ? $options['recent_number'] . ' ' . $options['recent_units'] : false;
1012
1013                unset( $options['recent_only'] );
1014                unset( $options['recent_number'] );
1015                unset( $options['recent_units'] );
1016
1017                update_option( 'yarpp', $options );
1018        }
1019
1020        public function upgrade_3_5_2b2() {
1021                // fixing the effects of a previous bug affecting non-MyISAM users
1022                if ( is_null( $this->get_option( 'weight' ) ) || ! is_array( $this->get_option( 'weight' ) ) ) {
1023                        $weight = $this->default_options['weight'];
1024
1025                        // if we're still not using MyISAM
1026                        if ( ! $this->get_option( YARPP_DB_Options::YARPP_MYISAM_OVERRIDE ) &&
1027                                 ! $this->db_schema->database_supports_fulltext_indexes() ) {
1028                                unset( $weight['title'] );
1029                                unset( $weight['body'] );
1030                        }
1031
1032                        $this->set_option( array( 'weight' => $weight ) );
1033                }
1034        }
1035
1036        public function upgrade_3_6b7() {
1037                // migrate auto_display setting to auto_display_post_types
1038                $options = $this->get_option();
1039
1040                $options['auto_display_post_types'] = ( $options['auto_display'] ) ? array( 'post' ) : array();
1041
1042                unset( $options['auto_display'] );
1043
1044                update_option( 'yarpp', $options );
1045        }
1046
1047        public function upgrade_4_0_1() {
1048                delete_transient( 'yarpp_version_info' );
1049        }
1050
1051        public function upgrade_4_2() {
1052                $this->load_pro_default_options();
1053                $new = array_merge( $this->pro_default_options, $this->yarppPro );
1054                update_option( 'yarpp_pro', $new );
1055        }
1056
1057        /**
1058         * UTILITIES
1059         */
1060        private $current_post;
1061        private $current_query;
1062        private $current_pagenow;
1063        // so we can return to normal later.
1064        public function save_post_context() {
1065                global $wp_query, $pagenow, $post;
1066
1067                $this->current_query   = $wp_query;
1068                $this->current_pagenow = $pagenow;
1069                $this->current_post    = $post;
1070        }
1071
1072        public function restore_post_context() {
1073                global $wp_query, $pagenow, $post;
1074
1075                $wp_query = $this->current_query;
1076                unset( $this->current_query );
1077
1078                $pagenow = $this->current_pagenow;
1079                unset( $this->current_pagenow );
1080
1081                if ( isset( $this->current_post ) ) {
1082                        $post = $this->current_post;
1083                        setup_postdata( $post );
1084                        unset( $this->current_post );
1085                }
1086        }
1087
1088        private $post_types = null;
1089
1090        /**
1091         * Gets all the post types YARPP can add related content to, and the post types YARPP can include in
1092         * "the pool"
1093         *
1094         * @param string $field 'objects', or any property on WP_Post_Type, like 'name'. Defaults to 'name'.
1095         *
1096         * @return array|null
1097         */
1098        public function get_post_types( $field = 'name' ) {
1099                if ( is_null( $this->post_types ) ) {
1100                        $this->post_types = get_post_types( array(), 'objects' );
1101                        $this->post_types = array_filter( $this->post_types, array( $this, 'post_type_filter' ) );
1102                }
1103
1104                if ( $field === 'objects' ) {
1105                        return $this->post_types;
1106                }
1107
1108                return wp_list_pluck( $this->post_types, $field );
1109        }
1110
1111        /**
1112         * Gets the post types to use for the current YARPP query
1113         *
1114         * @param string|WP_Post $reference_ID
1115         * @param array          $args
1116         * @return string[]
1117         */
1118        public function get_query_post_types( $reference_ID = null, $args = array() ) {
1119                $include_post_type = yarpp_get_option( 'include_post_type' );
1120                $include_post_type = wp_parse_list( $include_post_type );
1121                if ( isset( $args['post_type'] ) ) {
1122                        $post_types = wp_parse_list( $args['post_type'] );
1123                } elseif ( ! $this->get_option( 'cross_relate' ) ) {
1124                        $current_post_type = get_post_type( $reference_ID );
1125                        $post_types        = array( $current_post_type );
1126                        if ( ! in_array( $current_post_type, $include_post_type ) ) {
1127                                $post_types = array( '' );
1128                        }
1129                } elseif ( ! empty( $include_post_type ) ) {
1130                        $post_types = $include_post_type;
1131                } elseif ( $this->get_option( 'cross_relate' ) ) {
1132                        $post_types = $this->get_post_types();
1133                } else {
1134                        $post_types = array( get_post_type( $reference_ID ) );
1135                }
1136                return apply_filters(
1137                        'yarpp_map_post_types',
1138                        $post_types,
1139                        is_array( $args ) && isset( $args['domain'] ) ? $args['domain'] : null
1140                );
1141        }
1142
1143        private function post_type_filter( $post_type ) {
1144                // Remove blacklisted post types.
1145                if ( class_exists( 'bbPress' ) && in_array(
1146                        $post_type->name,
1147                        array(
1148                                'forum', // bbPress forums (ie, group of topics).
1149                                'reply', // bbPress replies to topics
1150                        )
1151                ) ) {
1152                        return false;
1153                }
1154                if ( $post_type->public ) {
1155                        return true;
1156                }
1157                if ( isset( $post_type->yarpp_support ) ) {
1158                        return $post_type->yarpp_support;
1159                }
1160                return false;
1161        }
1162
1163        private $taxonomies = null;
1164        function get_taxonomies( $field = false ) {
1165                if ( is_null( $this->taxonomies ) ) {
1166                        $this->taxonomies = get_taxonomies( array(), 'objects' );
1167                        $this->taxonomies = array_filter( $this->taxonomies, array( $this, 'taxonomy_filter' ) );
1168                }
1169
1170                if ( $field ) {
1171                        return wp_list_pluck( $this->taxonomies, $field );
1172                }
1173
1174                return $this->taxonomies;
1175        }
1176
1177        private function taxonomy_filter( $taxonomy ) {
1178                if ( ! count( array_intersect( $taxonomy->object_type, $this->get_post_types() ) ) ) {
1179                        return false;
1180                }
1181
1182                // if yarpp_support is set, follow that; otherwise include if show_ui is true.
1183                if ( isset( $taxonomy->yarpp_support ) ) {
1184                        return $taxonomy->yarpp_support;
1185                }
1186
1187                return $taxonomy->show_ui;
1188        }
1189
1190        /**
1191         * Gather optin data.
1192         *
1193         * @return array
1194         */
1195        public function optin_data() {
1196                global $wpdb;
1197
1198                $comments = wp_count_comments();
1199                $users    = $wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $wpdb->users ); // count_users();
1200                $posts    = $wpdb->get_var( 'SELECT COUNT(ID) FROM ' . $wpdb->posts . " WHERE post_type = 'post' AND comment_count > 0" );
1201                $settings = $this->get_option();
1202
1203                $collect = array_flip(
1204                        array(
1205                                'threshold',
1206                                'limit',
1207                                'excerpt_length',
1208                                'recent',
1209                                'rss_limit',
1210                                'rss_excerpt_length',
1211                                'past_only',
1212                                'show_excerpt',
1213                                'rss_show_excerpt',
1214                                'template',
1215                                'rss_template',
1216                                'show_pass_post',
1217                                'cross_relate',
1218                                'generate_missing_thumbnails',
1219                                'include_sticky_posts',
1220                                'rss_display',
1221                                'rss_excerpt_display',
1222                                'promote_yarpp',
1223                                'rss_promote_yarpp',
1224                                'myisam_override',
1225                                'weight',
1226                                'require_tax',
1227                                'auto_display_archive',
1228                                'exclude',
1229                                'include_post_type',
1230                        )
1231                );
1232
1233                $check_changed = array(
1234                        'before_title',
1235                        'after_title',
1236                        'before_post',
1237                        'after_post',
1238                        'after_related',
1239                        'no_results',
1240                        'order',
1241                        'rss_before_title',
1242                        'rss_after_title',
1243                        'rss_before_post',
1244                        'rss_after_post',
1245                        'rss_after_related',
1246                        'rss_no_results',
1247                        'rss_order',
1248                        'exclude',
1249                        'thumbnails_heading',
1250                        'thumbnails_default',
1251                        'rss_thumbnails_heading',
1252                        'rss_thumbnails_default',
1253                );
1254
1255                $data = array(
1256                        'versions'    => array(
1257                                'yarpp' => YARPP_VERSION,
1258                                'wp'    => get_bloginfo( 'version' ),
1259                                'php'   => phpversion(),
1260                        ),
1261                        'yarpp'       => array(
1262                                'settings'     => array_intersect_key( $settings, $collect ),
1263                                'cache_engine' => YARPP_CACHE_TYPE,
1264                        ),
1265                        'diagnostics' => array(
1266                                'myisam_posts'        => $this->diagnostic_myisam_posts(),
1267                                'fulltext_indices'    => $this->diagnostic_fulltext_indices(),
1268                                'hidden_metaboxes'    => $this->diagnostic_hidden_metaboxes(),
1269                                'post_thumbnails'     => $this->diagnostic_post_thumbnails(),
1270                                'happy'               => $this->diagnostic_happy(),
1271                                'using_thumbnails'    => $this->diagnostic_using_thumbnails(),
1272                                'generate_thumbnails' => $this->diagnostic_generate_thumbnails(),
1273                        ),
1274                        'stats'       => array(
1275                                'counts'   => array(),
1276                                'terms'    => array(),
1277                                'comments' => array(
1278                                        'moderated' => $comments->moderated,
1279                                        'approved'  => $comments->approved,
1280                                        'total'     => $comments->total_comments,
1281                                        'posts'     => $posts,
1282                                ),
1283                                'users'    => $users,
1284                        ),
1285                        'locale'      => get_bloginfo( 'language' ),
1286                        'url'         => get_bloginfo( 'url' ),
1287                        'plugins'     => array(
1288                                'active'   => implode( '|', get_option( 'active_plugins', array() ) ),
1289                                'sitewide' => implode( '|', array_keys( get_site_option( 'active_sitewide_plugins', array() ) ) ),
1290                        ),
1291                        'pools'       => $settings['pools'],
1292                );
1293
1294                $data['yarpp']['settings']['auto_display_post_types'] = implode( '|', $settings['auto_display_post_types'] );
1295
1296                $changed = array();
1297                foreach ( $check_changed as $key ) {
1298                        if ( $this->default_options[ $key ] !== $settings[ $key ] ) {
1299                                $changed[] = $key;
1300                        }
1301                }
1302
1303                foreach ( array( 'before_related', 'rss_before_related' ) as $key ) {
1304                        if ( $settings[ $key ] !== '<p>' . __( 'Related posts:', 'yet-another-related-posts-plugin' ) . '</p><ol>'
1305                                && $settings[ $key ] !== $this->default_options[ $key ]
1306                        ) {
1307                                $changed[] = $key;
1308                        }
1309                }
1310
1311                $data['yarpp']['changed_settings'] = implode( '|', $changed );
1312
1313                if ( method_exists( $this->cache, 'cache_status' ) ) {
1314                        $data['yarpp']['cache_status'] = $this->cache->cache_status();
1315                }
1316
1317                if ( method_exists( $this->cache, 'stats' ) ) {
1318                        $stats     = $this->cache->stats();
1319                        $flattened = array();
1320
1321                        foreach ( $stats as $key => $value ) {
1322                                $flattened[] = "$key:$value";
1323                        }
1324                        $data['yarpp']['stats'] = implode( '|', $flattened );
1325                }
1326
1327                if ( method_exists( $wpdb, 'db_version' ) ) {
1328                        $data['versions']['mysql'] = preg_replace( '/[^0-9.].*/', '', $wpdb->db_version() );
1329                }
1330
1331                $counts = array();
1332                foreach ( get_post_types( array( 'public' => true ) ) as $post_type ) {
1333                        $counts[ $post_type ] = wp_count_posts( $post_type );
1334                }
1335
1336                $data['stats']['counts'] = wp_list_pluck( $counts, 'publish' );
1337
1338                foreach ( get_taxonomies( array( 'public' => true ) ) as $taxonomy ) {
1339                        $data['stats']['terms'][ $taxonomy ] = wp_count_terms( $taxonomy );
1340                }
1341
1342                if ( is_multisite() ) {
1343                        $data['multisite'] = array(
1344                                'url'   => network_site_url(),
1345                                'users' => get_user_count(),
1346                                'sites' => get_blog_count(),
1347                        );
1348                }
1349
1350                return $data;
1351        }
1352
1353        public function pretty_echo( $data ) {
1354                echo '<pre>';
1355                $formatted = print_r( $data, true );
1356                $formatted = str_replace( array( 'Array', '(', ')', "\n    " ), array( '', '', '', "\n" ), $formatted );
1357                echo preg_replace( "/\n\s*\n/u", "\n", $formatted );
1358                echo '</pre>';
1359        }
1360
1361        /**
1362         * CORE LOOKUP + DISPLAY FUNCTIONS
1363         */
1364        protected function display_basic() {
1365                /* if it's not an auto-display post type, return */
1366                if ( ! in_array( get_post_type(), $this->get_option( 'auto_display_post_types' ) ) ) {
1367                        return null;
1368                }
1369
1370                if ( ! is_singular() && ! ( $this->get_option( 'auto_display_archive' ) && ( is_archive() || is_home() ) ) ) {
1371                        return null;
1372                }
1373                // If we're only viewing a single post with page breaks, only show YARPP its the last page.
1374                global $page, $pages;
1375                if ( is_singular() && is_int( $page ) && is_array( $pages ) && $page < count( $pages ) ) {
1376                        return null;
1377                }
1378
1379                return $this->display_related(
1380                        null,
1381                        array(
1382                                'domain' => 'website',
1383                        ),
1384                        false
1385                );
1386        }
1387
1388        public function display_pro( $domain ) {
1389                if ( ( is_archive() || is_home() || $domain !== 'website' ) ) {
1390                        return null;
1391                }
1392                if ( ! in_array( get_post_type(), $this->yarppPro['auto_display_post_types'] ) ) {
1393                        return null;
1394                }
1395                if ( ! ( isset( $this->yarppPro['active'] ) && $this->yarppPro['active'] ) ) {
1396                        return null;
1397                }
1398                if ( ! ( isset( $this->yarppPro['aid'] ) && isset( $this->yarppPro['v'] ) ) ||
1399                        ! ( $this->yarppPro['aid'] && $this->yarppPro['v'] ) ) {
1400                        return null;
1401                }
1402
1403                $output = null;
1404                $aid    = $this->yarppPro['aid'];
1405                $v      = $this->yarppPro['v'];
1406                $dpid   = ( isset( $this->yarppPro['dpid'] ) ) ? $this->yarppPro['dpid'] : null;
1407                $ru     = 'http://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
1408                $ssp    = ( $dpid ) ? '_ssp' : null;
1409
1410                ob_start();
1411                include YARPP_DIR . '/includes/phtmls/yarpp_pro_tag' . $ssp . '.phtml';
1412                $output .= ob_get_contents();
1413                ob_end_clean();
1414
1415                return $output;
1416        }
1417
1418        /**
1419         * Display related posts
1420         *
1421         * @since 2.1 The domain global refers to {website, widget, rss, metabox}
1422         * @since 3.0 New query-based approach: EXTREMELY HACKY!
1423         *
1424         * @param integer $reference_ID
1425         * @param array   $args see readme.txt's installation tab's  "YARPP functions()" section
1426         * @param bool    $echo
1427         * @return string
1428         */
1429        public function display_related( $reference_ID = null, $args = array(), $echo = true ) {
1430                // Avoid infinite recursion here.
1431                if ( $this->do_not_query_for_related() ) {
1432                        return false;
1433                }
1434                $this->parse_json_arg($args, 'weight');
1435                $this->parse_json_arg($args, 'require_tax');
1436                // Custom templates require .php extension.
1437                if ( isset( $args['template'] ) && $args['template'] ) {
1438                        // Normalize parameter.
1439                        if ( ( strpos( $args['template'], 'yarpp-template-' ) === 0 ) && ( strpos( $args['template'], '.php' ) === false ) ) {
1440                                $args['template'] .= '.php';
1441                        }
1442                }
1443                wp_register_style( 'yarppRelatedCss', plugins_url( '/style/related.css', YARPP_MAIN_FILE ), array(), YARPP_VERSION );
1444                /**
1445                 * Filter to allow dequeing of related.css.
1446                 *
1447                 * @param boolean default true
1448                 */
1449                $enqueue_related_style = apply_filters( 'yarpp_enqueue_related_style', true );
1450                if ( true === $enqueue_related_style ) {
1451                        wp_enqueue_style( 'yarppRelatedCss' );
1452                }
1453
1454                if ( is_numeric( $reference_ID ) ) {
1455                        $reference_ID = (int) $reference_ID;
1456                } else {
1457                        $reference_ID = get_the_ID();
1458                }
1459
1460                /**
1461                 * @since 3.5.3 don't compute on revisions.
1462                 */
1463                if ( $the_post = wp_is_post_revision( $reference_ID ) ) {
1464                        $reference_ID = $the_post;
1465                }
1466
1467                $this->setup_active_cache( $args );
1468
1469                $options = array(
1470                        'limit',
1471                        'order',
1472                        'optin',
1473                );
1474
1475                extract( $this->parse_args( $args, $options ) );
1476
1477                $cache_status = $this->active_cache->enforce( $reference_ID, false, $args );
1478                if ( $cache_status === YARPP_DONT_RUN ) {
1479                        return;
1480                }
1481                if ( $cache_status !== YARPP_NO_RELATED ) {
1482                        $this->active_cache->begin_yarpp_time( $reference_ID, $args );
1483                }
1484
1485                $this->save_post_context();
1486
1487                global $wp_query;
1488                $wp_query = new WP_Query();
1489
1490                if ( $cache_status !== YARPP_NO_RELATED ) {
1491                        $orders = explode( ' ', $order );
1492                        $wp_query->query(
1493                                array(
1494                                        'p'         => $reference_ID,
1495                                        'orderby'   => $orders[0],
1496                                        'order'     => $orders[1],
1497                                        'showposts' => $limit,
1498                                        'post_type' => $this->get_query_post_types( $reference_ID, $args ),
1499                                )
1500                        );
1501                }
1502
1503                $this->prep_query( $this->current_query->is_feed );
1504
1505                $wp_query->posts = apply_filters(
1506                        'yarpp_results',
1507                        $wp_query->posts,
1508                        array(
1509                                'function'   => 'display_related',
1510                                'args'       => $args,
1511                                'related_ID' => $reference_ID,
1512                        )
1513                );
1514
1515                $related_query = $wp_query; // backwards compatibility
1516
1517                if ( $cache_status !== YARPP_NO_RELATED ) {
1518                        $this->active_cache->end_yarpp_time();
1519                }
1520                if ( isset( $args['generate_missing_thumbnails'] ) ) {
1521                        $this->generate_missing_thumbnails = $args['generate_missing_thumbnails'];
1522                }
1523                // Be careful to avoid infinite recursion, because those templates might show each related posts' body or
1524                // excerpt, which would trigger finding its related posts, which would show its related posts body or excerpt...
1525                $this->rendering_related_content = true;
1526
1527                $output = $this->get_template_content($reference_ID, $args);
1528
1529                $this->rendering_related_content = false;
1530
1531                unset( $related_query );
1532                $this->restore_post_context();
1533
1534                if ( $echo ) {
1535                        echo $output;
1536                }
1537                return $output;
1538        }
1539
1540        /**
1541         * Handles in case JSON was provided for this argument.
1542         *
1543         * If the argument specified is a string, it is expected to be a string of JSON, otherwise an error is logged.
1544         *
1545         * Nothing is returned, modifies the $args passed in.
1546         *
1547         * @param array  $args
1548         * @param string $key
1549         *
1550         * @return null but modifies the $args array provided
1551         */
1552        protected function parse_json_arg( &$args, $key ) {
1553                if ( isset( $args[$key] ) && ! empty( $args[$key] ) && is_string($args[$key]) ) {
1554                        $decoded_json = json_decode( $args[$key], true );
1555                        if ( json_last_error() === JSON_ERROR_NONE ) {
1556                                $args[$key] = $decoded_json;
1557                        } else {
1558                                error_log(sprintf('Error parsing JSON in YARPP argument "%s". JSON was "%s" and JSON error was "%s"', $key, $args[$key], function_exists('json_last_error_msg') ? json_last_error_msg() : json_last_error()));
1559                        }
1560                }
1561        }
1562        /**
1563         * Returns the YARPP template html data.
1564         *
1565         * @param int   $reference_ID reference id.
1566         * @param array $args see readme.txt installation tab's  "YARPP functions()" section.
1567         * @param bool  $is_demo whether to add yarpp-demo-related class to div or not.
1568         * @return string return html data.
1569         */
1570        protected function get_template_content( $reference_ID = null, $args = array(), $is_demo = false ) {
1571                // make $related_query available to custom templates. It may be in use by old custom templates
1572                global $wp_query;
1573                $related_query = $wp_query;
1574                $related_count = $wp_query->post_count;
1575
1576                $options = array(
1577                        'domain',
1578                        'template',
1579                        'promote_yarpp',
1580                        'extra_css_class',
1581                );
1582
1583                extract( $this->parse_args( $args, $options ) );
1584
1585                // CSS class "yarpp-related" exists for backwards compatibility in-case older custom themes are dependent on it.
1586                $output = "<div class='yarpp yarpp-related";
1587
1588                if ( $is_demo ) {
1589                        $output .= ' yarpp-demo-related';
1590                }
1591
1592                // Add CSS class to identify domain.
1593                if ( isset( $domain ) && $domain ) {
1594                        $domain  = esc_attr($domain);
1595                        $output .= " yarpp-related-{$domain}";
1596                }
1597
1598                // Add CSS class to identify no results.
1599                if ( $related_count < 1 ) {
1600                        $output .= ' yarpp-related-none';
1601                }
1602
1603                // Add CSS class to identify template.
1604                if ( isset( $template ) && $template ) {
1605                        // Normalize "thumbnail" and "thumbnails" to reference the same inbuilt template
1606                        if ( $template === 'thumbnail' ) {
1607                                $template = 'thumbnails';
1608                        }
1609                        // Sanitize template name; remove file extension if exists
1610                        if ( strpos( $template, '.php' ) ) {
1611                                $template_css_class_suffix = preg_replace( '/' . preg_quote( '.php', '/' ) . '$/', '', $template );
1612                        } else {
1613                                $template_css_class_suffix = $template;
1614                        }
1615                        $output .= " yarpp-template-$template_css_class_suffix";
1616                } else {
1617                        // fallback to default template ("list")
1618                        $output .= ' yarpp-template-list';
1619                }
1620
1621                // Add any extra CSS classes specified (blocks)
1622                if ( isset( $extra_css_class ) && $extra_css_class ) {
1623                        $output .= " $extra_css_class";
1624                }
1625
1626                $output .= "'>\n";
1627
1628                // avoid any monkeying around where someone could trya custom template like a template name like
1629                // "yarpp-template-;../../wp-config.php". YARPP custom templates are only supported in the theme's root folder.
1630                $template = str_replace( '/', '', $template );
1631                if ( $domain === 'metabox' ) {
1632                        include YARPP_DIR . '/includes/template_metabox.php';
1633                } elseif ( (bool) $template && $template === 'thumbnails' ) {
1634                        include YARPP_DIR . '/includes/template_thumbnails.php';
1635                } elseif ( (bool) $template && $template === 'list' ) {
1636                        include YARPP_DIR . '/includes/template_builtin.php';
1637                } elseif ( (bool) $template ) {
1638                        $named_properly  = strpos( $template, 'yarpp-template-' ) === 0;
1639                        $template_exists = file_exists( STYLESHEETPATH . '/' . $template );
1640                        if ( $named_properly && $template_exists ) {
1641                                global $post;
1642                                add_action( 'begin_fetch_post_thumbnail_html', array( $this, 'maybe_regenerate_thumbnails' ), 10, 3 );
1643                                ob_start();
1644                                include STYLESHEETPATH . '/' . $template;
1645                                $output .= ob_get_contents();
1646                                remove_action( 'begin_fetch_post_thumbnail_html', array( $this, 'maybe_regenerate_thumbnails' ), 10 );
1647                                ob_end_clean();
1648                        } else {
1649                                error_log( 'YARPP Plugin: Could not load template "' . $template . '". ' . ( $named_properly ? 'It is named properly.' : 'It is NOT named properly' ) . ' ' . ( $template_exists ? 'It exists' : 'It does NOT exist' ) . '. Falling back to default template.' );
1650                                include YARPP_DIR . '/includes/template_builtin.php';
1651                        }
1652                } elseif ( $domain === 'widget' ) {
1653                        include YARPP_DIR . '/includes/template_widget.php';
1654                } else {
1655                        include YARPP_DIR . '/includes/template_builtin.php';
1656                }
1657
1658                $output = trim( $output ) . "\n";
1659
1660                if ( $related_count > 0 && $promote_yarpp && $domain != 'metabox' ) {
1661                        $output .=
1662                                '<p>' .
1663                                        sprintf(
1664                                                __(
1665                                                        "Powered by <a href='%s' title='WordPress Related Posts' target='_blank'>YARPP</a>.",
1666                                                        'yet-another-related-posts-plugin'
1667                                                ),
1668                                                'https://yarpp.com'
1669                                        ) .
1670                                "</p>\n";
1671                }
1672
1673                $output .= "</div>\n";
1674
1675                return $output;
1676        }
1677
1678        /**
1679         * @param (int)   $reference_ID
1680         * @param (array) $args see readme.txt installation tab's  "YARPP functions()" section
1681         */
1682        public function get_related( $reference_ID = null, $args = array() ) {
1683                // Avoid infinite recursion here.
1684                if ( $this->do_not_query_for_related() ) {
1685                        return false;
1686                }
1687
1688                if ( is_numeric( $reference_ID ) ) {
1689                        $reference_ID = (int) $reference_ID;
1690                } else {
1691                        $reference_ID = get_the_ID();
1692                }
1693
1694                /**
1695                 * @since 3.5.3: don't compute on revisions.
1696                 */
1697                if ( $the_post = wp_is_post_revision( $reference_ID ) ) {
1698                        $reference_ID = $the_post;
1699                }
1700
1701                $this->setup_active_cache( $args );
1702
1703                $options = array( 'limit', 'order' );
1704                extract( $this->parse_args( $args, $options ) );
1705
1706                $cache_status = $this->active_cache->enforce( $reference_ID, false, $args );
1707                if ( in_array( $cache_status, array( YARPP_DONT_RUN, YARPP_NO_RELATED ), true ) ) {
1708                        return array();
1709                }
1710
1711                /* Get ready for YARPP TIME! */
1712                $this->active_cache->begin_yarpp_time( $reference_ID, $args );
1713
1714                $related_query = new WP_Query();
1715                $orders        = explode( ' ', $order );
1716                $related_query->query(
1717                        array(
1718                                'p'         => $reference_ID,
1719                                'orderby'   => $orders[0],
1720                                'order'     => $orders[1],
1721                                'showposts' => $limit,
1722                                'post_type' => $this->get_query_post_types( $reference_ID, $args ),
1723                        )
1724                );
1725
1726                $related_query->posts = apply_filters(
1727                        'yarpp_results',
1728                        $related_query->posts,
1729                        array(
1730                                'function'   => 'get_related',
1731                                'args'       => $args,
1732                                'related_ID' => $reference_ID,
1733                        )
1734                );
1735
1736                $this->active_cache->end_yarpp_time();
1737                return $related_query->posts;
1738        }
1739
1740        /**
1741         * @param (int)   $reference_ID
1742         * @param (array) $args see readme.txt installation tab's  "YARPP functions()" section
1743         */
1744        public function related_exist( $reference_ID = null, $args = array() ) {
1745                // Avoid infinite recursion here.
1746                if ( $this->do_not_query_for_related() ) {
1747                        return false;
1748                }
1749
1750                if ( is_numeric( $reference_ID ) ) {
1751                        $reference_ID = (int) $reference_ID;
1752                } else {
1753                        $reference_ID = get_the_ID();
1754                }
1755
1756                /** @since 3.5.3: don't compute on revisions */
1757                if ( $the_post = wp_is_post_revision( $reference_ID ) ) {
1758                        $reference_ID = $the_post;
1759                }
1760
1761                $this->setup_active_cache( $args );
1762
1763                $cache_status = $this->active_cache->enforce( $reference_ID, false, $args );
1764
1765                if ( in_array( $cache_status, array( YARPP_DONT_RUN, YARPP_NO_RELATED ), true ) ) {
1766                        return false;
1767                }
1768
1769                /* Get ready for YARPP TIME! */
1770                $this->active_cache->begin_yarpp_time( $reference_ID, $args );
1771                $related_query = new WP_Query();
1772                $related_query->query(
1773                        array(
1774                                'p'         => $reference_ID,
1775                                'showposts' => 1,
1776                                'post_type' => $this->get_query_post_types( $reference_ID, $args ),
1777                        )
1778                );
1779
1780                $related_query->posts = apply_filters(
1781                        'yarpp_results',
1782                        $related_query->posts,
1783                        array(
1784                                'function'   => 'related_exist',
1785                                'args'       => $args,
1786                                'related_ID' => $reference_ID,
1787                        )
1788                );
1789
1790                $return = $related_query->have_posts();
1791                unset( $related_query );
1792
1793                $this->active_cache->end_yarpp_time();
1794                return $return;
1795        }
1796
1797        /**
1798         * @param array $args
1799         * @param bool  $echo
1800         * @return string
1801         */
1802        public function display_demo_related( $args = array(), $echo = true ) {
1803                // If YARPP cache is already finding the current post's content, don't ask it to do it again.
1804                // Avoid infinite recursion here.
1805                if ( $this->demo_cache_bypass->demo_time ) {
1806                        return false;
1807                }
1808
1809                $options = array(
1810                        'domain',
1811                        'limit',
1812                        'order',
1813                        'size',
1814                );
1815                extract( $this->parse_args( $args, $options ) );
1816                $this->demo_cache_bypass->begin_demo_time( $limit, $order, $size );
1817
1818                global $wp_query;
1819                $wp_query = new WP_Query();
1820
1821                $wp_query->query( array(
1822                        'showposts' => $limit,
1823                        'ignore_sticky_posts' => true
1824                ) );
1825
1826                $this->prep_query( $domain === 'rss' );
1827
1828                $output = $this->get_template_content(null, $args, true);
1829
1830                $this->demo_cache_bypass->end_demo_time();
1831
1832                if ( $echo ) {
1833                        echo $output;
1834                }
1835                return $output;
1836        }
1837
1838        /**
1839         * Create an array whose keys come from $options, and whose values are either their values in $args or the option's
1840         * default value.
1841         * Any keys from $args that aren't in $options are ignored and not included in the returned result.
1842         *
1843         * @param array $args inputted arguments
1844         * @param array $options names of arguments to consider
1845         *
1846         * @return array with all the keys from the list of $options, with their values
1847         * from $args or the options' default values.
1848         */
1849        public function parse_args( $args, $options ) {
1850                $options_with_rss_variants = array(
1851                        'limit',
1852                        'template',
1853                        'excerpt_length',
1854                        'before_title',
1855                        'after_title',
1856                        'before_post',
1857                        'after_post',
1858                        'before_related',
1859                        'after_related',
1860                        'no_results',
1861                        'order',
1862                        'promote_yarpp',
1863                        'thumbnails_heading',
1864                        'thumbnails_default',
1865                );
1866
1867                if ( ! isset( $args['domain'] ) ) {
1868                        $args['domain'] = 'website';
1869                }
1870
1871                $r = array();
1872                foreach ( $options as $option ) {
1873                        if ( $args['domain'] === 'rss'
1874                                && in_array( $option, $options_with_rss_variants )
1875                        ) {
1876                                $default = $this->get_option( 'rss_' . $option );
1877                        } else {
1878                                $default = $this->get_option( $option );
1879                        }
1880
1881                        if ( isset( $args[ $option ] ) && $args[ $option ] !== $default ) {
1882                                $r[ $option ] = $args[ $option ];
1883                        } else {
1884                                $r[ $option ] = $default;
1885                        }
1886
1887                        if ( $option === 'weight' && ! isset( $r[ $option ]['tax'] ) ) {
1888                                $r[ $option ]['tax'] = array();
1889                        }
1890                }
1891                return $r;
1892        }
1893
1894        private function setup_active_cache( $args ) {
1895                /* the options which the main sql query cares about: */
1896                $magic_options = array(
1897                        'limit',
1898                        'threshold',
1899                        'show_pass_post',
1900                        'past_only',
1901                        'weight',
1902                        'exclude',
1903                        'require_tax',
1904                        'recent',
1905                );
1906
1907                $defaults = $this->get_option();
1908                foreach ( $magic_options as $option ) {
1909                        if ( ! isset( $args[ $option ] ) ) {
1910                                continue;
1911                        }
1912
1913                        /*
1914                         * limit is a little different... if it's less than what we cache, let it go.
1915                         */
1916                        if ( $option === 'limit' && $args[ $option ] <= max( $defaults['limit'], $defaults['rss_limit'] ) ) {
1917                                continue;
1918                        }
1919
1920                        if ( $args[ $option ] !== $defaults[ $option ] ) {
1921                                $this->active_cache = $this->cache_bypass;
1922                                return;
1923                        }
1924                }
1925
1926                $this->active_cache = $this->cache;
1927        }
1928
1929        private function prep_query( $is_feed = false ) {
1930                global $wp_query;
1931                $wp_query->in_the_loop = true;
1932                $wp_query->is_feed     = $is_feed;
1933
1934                /*
1935                 * Make sure we get the right is_single value (see http://wordpress.org/support/topic/288230)
1936                 */
1937                $wp_query->is_single = false;
1938        }
1939
1940        /**
1941         * We're regenerating thumbnails when get_the_post_thumbnail is called
1942         * directly from one of our custom templates because many folks have already
1943         * coded their custom templates but may also want them to automatically regenerate thumbnails..
1944         *
1945         * @since 5.22.1
1946         *
1947         * @param int          $post_id           The post ID.
1948         * @param int          $post_thumbnail_id The post thumbnail ID.
1949         * @param string|int[] $size              Requested image size. Can be any registered image size name, or
1950         *                                        an array of width and height values in pixels (in that order).
1951         */
1952        public function maybe_regenerate_thumbnails( $post_id, $post_thumbnail_id, $size ) {
1953                $dimensions = $this->thumbnail_dimensions();
1954                if ( $this->diagnostic_generate_thumbnails() ) {
1955                        $this->ensure_resized_post_thumbnail( $post_id, $dimensions );
1956                }
1957        }
1958
1959        /**
1960         * Return true if user disabled the YARPP related post for the current post, false otherwise.
1961         *
1962         * @return bool
1963         */
1964        public function yarpp_disabled_for_this_post() {
1965                global $post;
1966
1967                if ( $post instanceof WP_Post ) {
1968                        $yarpp_meta = get_post_meta( $post->ID, 'yarpp_meta', true );
1969                        if ( isset( $yarpp_meta['yarpp_display_for_this_post'] ) && 0 === (int) $yarpp_meta['yarpp_display_for_this_post'] ) {
1970                                return true;
1971                        }
1972                }
1973                return false;
1974        }
1975
1976        /**
1977         * Return true if Automatic Display should be disabled
1978         *
1979         * @return bool
1980         * @since 5.24.0
1981         */
1982        public function is_noyarpp( $content ) {
1983                /*
1984                 * Before automatically adding YARPP's related content onto a post's content, checks the value of the
1985                 * "yarpp_meta" postmeta's key "yarpp_display_for_this_post", and whether the post's content contains
1986                 * the magic comment "<!--noyarpp-->"`. If either one of those is true `$noyarpp` will be true, otherwise false.
1987                 */
1988                $noyarpp = $this->yarpp_disabled_for_this_post();   // post meta flag.
1989                if ( strpos( $content, '<!--noyarpp-->' ) !== false ) {
1990                        $noyarpp = true;    // does content includes <!--noyarpp--> ?
1991                }
1992                /**
1993                 * Filters whether or not to disable adding YARPP's related posts on the current post.
1994                 *
1995                 * Note: the global `$post` will be populated with the current post, if needed.
1996                 *
1997                 * @param bool $noyarpp true indicates that YARPP should be disabled on the post; false indicates it should be shown.
1998                 * @param string $content post's content
1999                 * @since 5.24.0
2000                 */
2001                $noyarpp = apply_filters( 'noyarpp', $noyarpp, $content );
2002
2003                return $noyarpp;
2004        }
2005
2006        /**
2007         * DEFAULT CONTENT FILTERS
2008         */
2009        public function the_content( $content ) {
2010                // Avoid infinite recursion.
2011                if ( is_feed() || $this->do_not_query_for_related() ) {
2012                        return $content;
2013                }
2014
2015                // Disable Automatic Display?
2016                if ( true === $this->is_noyarpp( $content ) ) {
2017                        return $content;
2018                }
2019
2020                $content .= $this->display_basic();
2021                $content .= $this->display_pro( 'website' );
2022                return $content;
2023        }
2024
2025        public function the_content_feed( $content ) {
2026                if ( ! $this->get_option( 'rss_display' ) ) {
2027                        return $content;
2028                }
2029
2030                // Disable Automatic Display?
2031                if ( true === $this->is_noyarpp( $content ) ) {
2032                        return $content;
2033                }
2034
2035                return $content . $this->display_related(
2036                        null,
2037                        array(
2038                                'domain' => 'rss',
2039                        ),
2040                        false
2041                );
2042        }
2043
2044        public function the_excerpt_rss( $content ) {
2045                if ( ! $this->get_option( 'rss_excerpt_display' ) || ! $this->get_option( 'rss_display' ) ) {
2046                        return $content;
2047                }
2048
2049                // Disable Automatic Display?
2050                if ( true === $this->is_noyarpp( $content ) ) {
2051                        return $content;
2052                }
2053
2054                return $content . $this->clean_pre( $this->display_related( null, array( 'domain' => 'rss' ), false ) );
2055        }
2056
2057        /*
2058         * UTILS
2059         */
2060
2061        /**
2062         * @since 3.3  Use PHP serialized format instead of JSON.
2063         */
2064        public function version_info( $enforce_cache = false ) {
2065                if ( ! $enforce_cache && false !== ( $result = $this->get_transient( 'yarpp_version_info' ) ) ) {
2066                        return $result;
2067                }
2068
2069                $version = YARPP_VERSION;
2070                $remote  = wp_remote_post( "https://yarpp.org/checkversion.php?format=php&version={$version}", array ( 'sslverify' => false ) );
2071
2072                if ( is_wp_error( $remote ) || wp_remote_retrieve_response_code( $remote ) != 200 || ! isset( $remote['body'] ) || ! is_array( $remote['body'] ) ) {
2073                        $this->set_transient( 'yarpp_version_info', null, 60 * 60 );
2074                        return false;
2075                }
2076
2077                if ( $result = @unserialize( $remote['body'] ) ) {
2078                        $this->set_transient( 'yarpp_version_info', $result, 60 * 60 * 24 );
2079                }
2080
2081                return $result;
2082        }
2083
2084        /**
2085         * @since 4.0 Optional data collection (default off)
2086         */
2087        public function optin_ping() {
2088                if ( $this->get_transient( 'yarpp_optin' ) ) {
2089                        return true;
2090                }
2091
2092                $remote = wp_remote_post( 'https://yarpp.org/optin/2/', array( 'body' => $this->optin_data(), 'sslverify' => false ) );
2093
2094                if ( is_wp_error( $remote )
2095                        || wp_remote_retrieve_response_code( $remote ) != 200
2096                        || ! isset( $remote['body'] )
2097                        || $remote['body'] !== 'ok'
2098                ) {
2099                        /* try again later */
2100                        $this->set_transient( 'yarpp_optin', null, 60 * 60 );
2101                        return false;
2102                }
2103
2104                $this->set_transient( 'yarpp_optin', null, 60 * 60 * 24 * 7 );
2105
2106                return true;
2107        }
2108
2109        /**
2110         * A version of the transient functions which is unaffected by caching plugin behavior.
2111         * We want to control the lifetime of data.
2112         *
2113         * @param int $transient
2114         * @return bool
2115         */
2116        private function get_transient( $transient ) {
2117                $transient_timeout = $transient . '_timeout';
2118
2119                if ( intval( get_option( $transient_timeout ) ) < time() ) {
2120                        delete_option( $transient_timeout );
2121                        return false; // timed out.
2122                }
2123
2124                return get_option( $transient, true ); // still ok.
2125        }
2126
2127        private function set_transient( $transient, $data = null, $expiration = 0 ) {
2128                $transient_timeout = $transient . '_timeout';
2129
2130                if ( get_option( $transient_timeout ) === false ) {
2131
2132                        add_option( $transient_timeout, time() + $expiration, '', 'no' );
2133                        if ( ! is_null( $data ) ) {
2134                                add_option( $transient, $data, '', 'no' );
2135                        }
2136                } else {
2137
2138                        update_option( $transient_timeout, time() + $expiration );
2139                        if ( ! is_null( $data ) ) {
2140                                update_option( $transient, $data );
2141                        }
2142                }
2143
2144                $this->kick_other_caches();
2145        }
2146
2147        private function delete_transient( $transient ) {
2148                delete_option( $transient );
2149                delete_option( $transient . '_timeout' );
2150        }
2151
2152        /**
2153         * @since 4.0.4  Helper function to force other caching systems which are too aggressive.
2154         * <cough>DB Cache Reloaded (Fix)</cough> to flush when YARPP transients are set.
2155         */
2156        private function kick_other_caches() {
2157                if ( class_exists( 'DBCacheReloaded' ) ) {
2158                        global $wp_db_cache_reloaded;
2159                        if ( is_object( $wp_db_cache_reloaded ) && is_a( $wp_db_cache_reloaded, 'DBCacheReloaded' ) ) {
2160                                // if DBCR offered a more granualar way of just flushing options, I'd love that.
2161                                $wp_db_cache_reloaded->dbcr_clear();
2162                        }
2163                }
2164        }
2165
2166        /**
2167         * @since 3.5.2  Clean_pre is deprecated in WP 3.4, so implement here.
2168         */
2169        function clean_pre( $text ) {
2170                $text = str_replace( array( '<br />', '<br/>', '<br>' ), array( '', '', '' ), $text );
2171                $text = str_replace( '<p>', "\n", $text );
2172                $text = str_replace( '</p>', '', $text );
2173                return $text;
2174        }
2175
2176        /**
2177         * Gets the list of valid interval units used by YARPP and MySQL interval statements.
2178         *
2179         * @return array keys are valid values for recent units, and for MySQL interval
2180         * (see https://www.mysqltutorial.org/mysql-interval/), values are translated strings
2181         */
2182        public function recent_units() {
2183                return array(
2184                        'day'   => __( 'day(s)', 'yet-another-related-posts-plugin' ),
2185                        'week'  => __( 'week(s)', 'yet-another-related-posts-plugin' ),
2186                        'month' => __( 'month(s)', 'yet-another-related-posts-plugin' ),
2187                );
2188        }
2189
2190        /**
2191         * Adds YARPP's content to bbPress topics.
2192         */
2193        public function add_to_bbpress() {
2194                echo $this->display_basic();
2195        }
2196
2197        /**
2198         * Checks if it's an appropriate time to look for related posts, or if we should skip that.
2199         *
2200         * There are two contrary indicators:
2201         * 1. if the active cache is currently discovering post keywords. Finding related posts at this time causes
2202         * infinite recursion because: in order to discover keywords, you need to get the post's FILTERED content, which
2203         * would trigger adding related content to the post's body, which requires discovering its keywords, etc.
2204         * 2. if YARPP is currently adding related content. Finding related posts at this time can cause infinite recursion
2205         * because: the template file might show a posts't content or excerpt, which would cause adding related content
2206         * to that post body or excerpt, which would start adding related content to it too, etc.    *
2207         *
2208         * @return bool
2209         */
2210        protected function do_not_query_for_related() {
2211                return $this->rendering_related_content ||
2212                           ( $this->active_cache instanceof YARPP_Cache && $this->active_cache->discovering_keywords() );
2213        }
2214}
Note: See TracBrowser for help on using the repository browser.