Yet Another Related Posts Plugin (YARPP) - Version 4.3.2

Version Description

  • Fix ksort error in YARPP_Cache.php (credit to Derrick Hammer/@pcfreak30)
  • Discontinuing the YARPP Pro service as of 12/31/2016
Download this release

Release Info

Developer jeffparker
Plugin Icon 128x128 Yet Another Related Posts Plugin (YARPP)
Version 4.3.2
Comparing to
See all releases

Code changes from version 4.3.1 to 4.3.2

Files changed (3) hide show
  1. classes/YARPP_Cache.php +376 -489
  2. readme.txt +10 -20
  3. yarpp.php +2 -2
classes/YARPP_Cache.php CHANGED
@@ -1,489 +1,376 @@
1
- <?php
2
-
3
- abstract class YARPP_Cache {
4
-
5
- protected $core;
6
- protected $yarpp_time = false;
7
- public $score_override = false;
8
- public $online_limit = false;
9
- public $last_sql;
10
-
11
- function __construct( &$core ) {
12
- $this->core = &$core;
13
- $this->name = __($this->name, 'yarpp');
14
- }
15
-
16
- function add_signature( $query ) {
17
- $query->yarpp_cache_type = $this->name;
18
- }
19
-
20
- /**
21
- * GENERAL CACHE CONTROL
22
- */
23
- public function is_yarpp_time() {
24
- return $this->yarpp_time;
25
- }
26
-
27
- public function flush() {
28
- }
29
-
30
- public function setup() {
31
- }
32
-
33
- public function upgrade( $last_version ) {
34
- }
35
-
36
- /*
37
- * POST CACHE CONTROL
38
- */
39
-
40
- /*
41
- * Note: return value changed in 3.4
42
- * return YARPP_NO_RELATED | YARPP_RELATED | YARPP_DONT_RUN | false if no good input
43
- */
44
- function enforce($reference_ID, $force = false) {
45
- /**
46
- * @since 3.5.3 Don't compute on revisions.
47
- * wp_is_post_revision will return the id of the revision parent instead.
48
- */
49
- if ($the_post = wp_is_post_revision($reference_ID)) $reference_ID = $the_post;
50
-
51
- if (!is_int($reference_ID)) return false;
52
-
53
- $status = $this->is_cached($reference_ID);
54
- $status = apply_filters('yarpp_cache_enforce_status', $status, $reference_ID);
55
-
56
- // There's a stop signal:
57
- if ($status === YARPP_DONT_RUN) return YARPP_DONT_RUN;
58
-
59
- // If not cached, process now:
60
- if ($status === YARPP_NOT_CACHED || $force) $status = $this->update((int) $reference_ID); // status now will be YARPP_NO_RELATED | YARPP_RELATED
61
-
62
- // There are no related posts
63
- if ($status === YARPP_NO_RELATED) return YARPP_NO_RELATED;
64
-
65
- // There are results
66
- return YARPP_RELATED;
67
- }
68
-
69
- /**
70
- * @param int $reference_ID
71
- * @return string YARPP_NO_RELATED | YARPP_RELATED | YARPP_NOT_CACHED
72
- */
73
- public function is_cached($reference_ID) {
74
- return YARPP_NOT_CACHED;
75
- }
76
-
77
- public function clear($reference_ID) {
78
- }
79
-
80
- /*
81
- * POST STATUS INTERACTIONS
82
- */
83
-
84
- /**
85
- * Clear the cache for this entry and for all posts which are "related" to it.
86
- * @since 3.2 This is called when a post is deleted.
87
- */
88
- function delete_post($post_ID) {
89
- // Clear the cache for this post.
90
- $this->clear((int) $post_ID);
91
-
92
- // Find all "peers" which list this post as a related post and clear their caches
93
- if ($peers = $this->related(null, (int) $post_ID)) $this->clear($peers);
94
- }
95
-
96
- /**
97
- * @since 3.2.1 Handle various post_status transitions
98
- */
99
- function transition_post_status( $new_status, $old_status, $post ) {
100
- $post_ID = $post->ID;
101
-
102
- /**
103
- * @since 3.4 Don't compute on revisions
104
- * @since 3.5 Compute on the parent instead
105
- */
106
- if ($the_post = wp_is_post_revision($post_ID)) $post_ID = $the_post;
107
-
108
- // Un-publish
109
- if ($old_status === 'publish' && $new_status !== 'publish') {
110
- // Find all "peers" which list this post as a related post and clear their caches
111
- if ($peers = $this->related(null, (int) $post_ID)) $this->clear($peers);
112
- }
113
-
114
- // Publish
115
- if ($old_status !== 'publish' && $new_status === 'publish') {
116
- /*
117
- * Find everything which is related to this post, and clear them,
118
- * so that this post might show up as related to them.
119
- */
120
- if ($related = $this->related($post_ID, null)) $this->clear($related);
121
- }
122
-
123
- /**
124
- * @since 3.4 Simply clear the cache on save; don't recompute.
125
- */
126
- $this->clear((int) $post_ID);
127
- }
128
-
129
- function set_score_override_flag($q) {
130
- if ($this->is_yarpp_time()) {
131
-
132
- $this->score_override = (isset($q->query_vars['orderby']) && $q->query_vars['orderby'] === 'score');
133
-
134
- if (!empty($q->query_vars['showposts'])) {
135
- $this->online_limit = $q->query_vars['showposts'];
136
- } else {
137
- $this->online_limit = false;
138
- }
139
-
140
- } else {
141
-
142
- $this->score_override = false;
143
- $this->online_limit = false;
144
-
145
- }
146
- }
147
-
148
- /**
149
- * SQL!
150
- */
151
-
152
- protected function sql($reference_ID = false, $args = array()) {
153
- global $wpdb, $post;
154
-
155
- if (is_object($post) && !$reference_ID) {
156
- $reference_ID = $post->ID;
157
- }
158
-
159
- if (!is_object($post) || $reference_ID != $post->ID) {
160
- $reference_post = get_post($reference_ID);
161
- } else {
162
- $reference_post = $post;
163
- }
164
-
165
- $options = array(
166
- 'threshold',
167
- 'show_pass_post',
168
- 'past_only',
169
- 'weight',
170
- 'require_tax',
171
- 'exclude',
172
- 'recent',
173
- 'limit'
174
- );
175
-
176
- extract($this->core->parse_args($args, $options));
177
-
178
- // The maximum number of items we'll ever want to cache
179
- $limit = max($limit, $this->core->get_option('rss_limit'));
180
-
181
- // Fetch keywords
182
- $keywords = $this->get_keywords($reference_ID);
183
-
184
- // SELECT
185
- $newsql = "SELECT $reference_ID as reference_ID, ID, "; //post_title, post_date, post_content, post_excerpt,
186
-
187
- $newsql .= 'ROUND(0';
188
-
189
- if (isset($weight['body']) && isset($weight['body']) && (int) $weight['body']) {
190
- $newsql .= " + (MATCH (post_content) AGAINST ('".esc_sql($keywords['body'])."')) * ".absint($weight['body']);
191
- }
192
-
193
- if (isset($weight['body']) && isset($weight['title']) && (int) $weight['title']) {
194
- $newsql .= " + (MATCH (post_title) AGAINST ('".esc_sql($keywords['title'])."')) * ".absint($weight['title']);
195
- }
196
-
197
- // Build tax criteria query parts based on the weights
198
- foreach ((array) $weight['tax'] as $tax => $tax_weight) {
199
- $newsql .= " + ".$this->tax_criteria($reference_ID, $tax)." * ".intval($tax_weight);
200
- }
201
-
202
- $newsql .= ',1) as score';
203
-
204
- $newsql .= "\n from $wpdb->posts \n";
205
-
206
- $exclude_tt_ids = wp_parse_id_list($exclude);
207
-
208
- if (count($exclude_tt_ids) || count((array) $weight['tax']) || count($require_tax)) {
209
- $newsql .= "left join $wpdb->term_relationships as terms on ( terms.object_id = $wpdb->posts.ID ) \n";
210
- }
211
-
212
- /*
213
- * Where
214
- */
215
-
216
- $newsql .= " where post_status in ( 'publish', 'static' ) and ID != '$reference_ID'";
217
-
218
- /**
219
- * @since 3.1.8 Revised $past_only option
220
- */
221
- if ($past_only) $newsql .= " and post_date <= '$reference_post->post_date' ";
222
- if (!$show_pass_post) $newsql .= " and post_password ='' ";
223
- if ((bool) $recent) $newsql .= " and post_date > date_sub(now(), interval {$recent}) ";
224
-
225
- $newsql .= " and post_type = 'post'";
226
-
227
- // GROUP BY
228
- $newsql .= "\n group by ID \n";
229
-
230
- // HAVING
231
- // number_format fix suggested by vkovalcik! :)
232
- $safethreshold = number_format(max($threshold,0.1), 2, '.', '');
233
-
234
- /**
235
- * @since 3.5.3: ID=0 is a special value; never save such a result.
236
- */
237
- $newsql .= " having score >= $safethreshold and ID != 0";
238
-
239
- if (count($exclude_tt_ids)) {
240
- $newsql .= " and bit_or(terms.term_taxonomy_id in (".join(',', $exclude_tt_ids).")) = 0";
241
- }
242
-
243
- foreach ((array) $require_tax as $tax => $number) {
244
- $newsql .= ' and '.$this->tax_criteria($reference_ID, $tax).' >= '.intval($number);
245
- }
246
-
247
- $newsql .= " order by score desc limit $limit";
248
-
249
- if (isset($args['post_type'])) {
250
- $post_types = (array) $args['post_type'];
251
- } else {
252
- $post_types = $this->core->get_post_types();
253
- }
254
-
255
- $queries = array();
256
- foreach ($post_types as $post_type) {
257
- $queries[] = '('.str_replace("post_type = 'post'", "post_type = '{$post_type}'", $newsql).')';
258
- }
259
-
260
- $sql = implode(' union ', $queries);
261
-
262
- if ($this->core->debug) echo "<!-- $sql -->";
263
-
264
- $this->last_sql = $sql;
265
-
266
- return $sql;
267
- }
268
-
269
- private function tax_criteria($reference_ID, $taxonomy) {
270
- $terms = get_the_terms($reference_ID, $taxonomy);
271
-
272
- // if there are no terms of that tax
273
- if (false === $terms) return '(1 = 0)';
274
-
275
- $tt_ids = wp_list_pluck($terms, 'term_taxonomy_id');
276
- return "count(distinct if( terms.term_taxonomy_id in (".join(',',$tt_ids)."), terms.term_taxonomy_id, null ))";
277
- }
278
-
279
- /*
280
- * KEYWORDS
281
- */
282
-
283
- /**
284
- * @param int $ID
285
- * @param string $type body | title | all
286
- * @return string|array depending on whether "all" were requested or not
287
- */
288
- public function get_keywords($ID, $type = 'all') {
289
- if (!$ID = absint($ID)) return false;
290
-
291
- $keywords = array(
292
- 'body' => $this->body_keywords($ID),
293
- 'title' => $this->title_keywords($ID)
294
- );
295
-
296
- if (empty($keywords)) return false;
297
-
298
- if ($type === 'all') return $keywords;
299
-
300
- return $keywords[$type];
301
- }
302
-
303
- protected function title_keywords($ID, $max = 20) {
304
- return apply_filters('yarpp_title_keywords', $this->extract_keywords(get_the_title($ID), $max, $ID), $max, $ID);
305
- }
306
-
307
- protected function body_keywords($ID, $max = 20) {
308
- $post = get_post($ID);
309
- if (empty($post)) return '';
310
-
311
- $content = $this->apply_filters_if_white('the_content', $post->post_content);
312
- return apply_filters('yarpp_body_keywords', $this->extract_keywords($content, $max, $ID), $max, $ID);
313
- }
314
-
315
- private function extract_keywords( $html, $max = 20, $ID = 0 ) {
316
-
317
- /**
318
- * @filter yarpp_extract_keywords
319
- *
320
- * Use this filter to override YARPP's built-in keyword computation
321
- * Return values should be a string of space-delimited words
322
- *
323
- * @param $keywords
324
- * @param $html unfiltered HTML content
325
- * @param (int) $max maximum number of keywords
326
- * @param (int) $ID
327
- */
328
- if ($keywords = apply_filters('yarpp_extract_keywords', false, $html, $max, $ID)) return $keywords;
329
-
330
- if (defined('WPLANG')) {
331
- switch ( substr(WPLANG, 0, 2) ) {
332
- case 'de':
333
- $lang = 'de_DE';
334
- break;
335
- case 'it':
336
- $lang = 'it_IT';
337
- break;
338
- case 'pl':
339
- $lang = 'pl_PL';
340
- break;
341
- case 'bg':
342
- $lang = 'bg_BG';
343
- break;
344
- case 'fr':
345
- $lang = 'fr_FR';
346
- break;
347
- case 'cs':
348
- $lang = 'cs_CZ';
349
- break;
350
- case 'nl':
351
- $lang = 'nl_NL';
352
- break;
353
- default:
354
- $lang = 'en_US';
355
- break;
356
- }
357
- }
358
- else {
359
- $lang = 'en_US';
360
- }
361
-
362
- $words_file = YARPP_DIR.'/lang/words-'.$lang.'.php';
363
- if (file_exists($words_file)) include($words_file);
364
- if (!isset($overusedwords)) $overusedwords = array();
365
-
366
- // strip tags and html entities
367
- $text = preg_replace('/&(#x[0-9a-f]+|#[0-9]+|[a-zA-Z]+);/', '', strip_tags($html) );
368
-
369
- // 3.2.2: ignore soft hyphens
370
- // Requires PHP 5: http://bugs.php.net/bug.php?id=25670
371
- $softhyphen = html_entity_decode('&#173;',ENT_NOQUOTES,'UTF-8');
372
- $text = str_replace($softhyphen, '', $text);
373
-
374
- $charset = get_option('blog_charset');
375
- if ( function_exists('mb_split') && !empty($charset) ) {
376
- mb_regex_encoding($charset);
377
- $wordlist = mb_split('\s*\W+\s*', mb_strtolower($text, $charset));
378
- } else
379
- $wordlist = preg_split('%\s*\W+\s*%', strtolower($text));
380
-
381
- // Build an array of the unique words and number of times they occur.
382
- $tokens = array_count_values($wordlist);
383
-
384
- // Remove the stop words from the list.
385
- $overusedwords = apply_filters( 'yarpp_keywords_overused_words', $overusedwords );
386
- if ( is_array($overusedwords) ) {
387
- foreach ($overusedwords as $word) {
388
- unset($tokens[$word]);
389
- }
390
- }
391
- // Remove words which are only a letter
392
- foreach (array_keys($tokens) as $word) {
393
- if ( function_exists('mb_strlen') )
394
- if (mb_strlen($word) < 2) unset($tokens[$word]);
395
- else
396
- if (strlen($word) < 2) unset($tokens[$word]);
397
- }
398
-
399
- arsort($tokens, SORT_NUMERIC);
400
-
401
- $types = array_keys($tokens);
402
-
403
- if (count($types) > $max)
404
- $types = array_slice($types, 0, $max);
405
- return implode(' ', $types);
406
- }
407
-
408
- /* new in 2.0! apply_filters_if_white (previously apply_filters_without) now has a blacklist.
409
- * It can be modified via the yarpp_blacklist and yarpp_blackmethods filters.
410
- */
411
- /* blacklisted so far:
412
- - diggZ-Et
413
- - reddZ-Et
414
- - dzoneZ-Et
415
- - WP-Syntax
416
- - Viper's Video Quicktags
417
- - WP-CodeBox
418
- - WP shortcodes
419
- - WP Greet Box
420
- - Jetpack ShareDaddy
421
- //- Tweet This - could not reproduce problem.
422
- */
423
- function white( $filter ) {
424
- static $blacklist, $blackmethods;
425
-
426
- if ( is_null($blacklist) || is_null($blackmethods) ) {
427
- $yarpp_blacklist = array('diggZEt_AddBut', 'reddZEt_AddBut', 'dzoneZEt_AddBut', 'wp_syntax_before_filter', 'wp_syntax_after_filter', 'wp_codebox_before_filter', 'wp_codebox_after_filter', 'do_shortcode', 'sharing_display', 'really_simple_share_content');//,'insert_tweet_this'
428
- $yarpp_blackmethods = array('addinlinejs', 'replacebbcode', 'filter_content');
429
-
430
- $blacklist = (array) apply_filters( 'yarpp_blacklist', $yarpp_blacklist );
431
- $blackmethods = (array) apply_filters( 'yarpp_blackmethods', $yarpp_blackmethods );
432
- }
433
-
434
- if ( is_array($filter) && is_a( $filter[0], 'YARPP' ) )
435
- return false;
436
- if ( is_array($filter) && in_array( $filter[1], $blackmethods ) )
437
- return false;
438
- return !in_array( $filter, $blacklist );
439
- }
440
-
441
- /* FYI, apply_filters_if_white was used here to avoid a loop in apply_filters('the_content') > YARPP::the_content() > YARPP::related() > YARPP_Cache::body_keywords() > apply_filters('the_content').*/
442
- function apply_filters_if_white($tag, $value) {
443
- global $wp_filter, $merged_filters, $wp_current_filter;
444
-
445
- $args = array();
446
-
447
- // Do 'all' actions first
448
- if ( isset($wp_filter['all']) ) {
449
- $wp_current_filter[] = $tag;
450
- $args = func_get_args();
451
- _wp_call_all_hook($args);
452
- }
453
-
454
- if ( !isset($wp_filter[$tag]) ) {
455
- if ( isset($wp_filter['all']) )
456
- array_pop($wp_current_filter);
457
- return $value;
458
- }
459
-
460
- if ( !isset($wp_filter['all']) )
461
- $wp_current_filter[] = $tag;
462
-
463
- // Sort
464
- if ( !isset( $merged_filters[ $tag ] ) ) {
465
- ksort($wp_filter[$tag]);
466
- $merged_filters[ $tag ] = true;
467
- }
468
-
469
- reset( $wp_filter[ $tag ] );
470
-
471
- if ( empty($args) )
472
- $args = func_get_args();
473
-
474
- do {
475
- foreach( (array) current($wp_filter[$tag]) as $the_ )
476
- if ( !is_null($the_['function'])
477
- and $this->white($the_['function'])){ // HACK
478
- $args[1] = $value;
479
- $value = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
480
- }
481
-
482
- } while ( next($wp_filter[$tag]) !== false );
483
-
484
- array_pop( $wp_current_filter );
485
-
486
- return $value;
487
- }
488
- }
489
-
1
+ <?php
2
+ abstract class YARPP_Cache {
3
+ protected $core;
4
+ protected $yarpp_time = false;
5
+ public $score_override = false;
6
+ public $online_limit = false;
7
+ public $last_sql;
8
+ function __construct( &$core ) {
9
+ $this->core = &$core;
10
+ $this->name = __($this->name, 'yarpp');
11
+ }
12
+
13
+ function add_signature( $query ) {
14
+ $query->yarpp_cache_type = $this->name;
15
+ }
16
+
17
+ /**
18
+ * GENERAL CACHE CONTROL
19
+ */
20
+ public function is_yarpp_time() {
21
+ return $this->yarpp_time;
22
+ }
23
+ public function flush() {
24
+ }
25
+
26
+ public function setup() {
27
+ }
28
+
29
+ public function upgrade( $last_version ) {
30
+ }
31
+
32
+ /*
33
+ * POST CACHE CONTROL
34
+ */
35
+ /*
36
+ * Note: return value changed in 3.4
37
+ * return YARPP_NO_RELATED | YARPP_RELATED | YARPP_DONT_RUN | false if no good input
38
+ */
39
+ function enforce($reference_ID, $force = false) {
40
+ /**
41
+ * @since 3.5.3 Don't compute on revisions.
42
+ * wp_is_post_revision will return the id of the revision parent instead.
43
+ */
44
+ if ($the_post = wp_is_post_revision($reference_ID)) $reference_ID = $the_post;
45
+ if (!is_int($reference_ID)) return false;
46
+
47
+ $status = $this->is_cached($reference_ID);
48
+ $status = apply_filters('yarpp_cache_enforce_status', $status, $reference_ID);
49
+
50
+ // There's a stop signal:
51
+ if ($status === YARPP_DONT_RUN) return YARPP_DONT_RUN;
52
+
53
+ // If not cached, process now:
54
+ if ($status === YARPP_NOT_CACHED || $force) $status = $this->update((int) $reference_ID); // status now will be YARPP_NO_RELATED | YARPP_RELATED
55
+ // There are no related posts
56
+ if ($status === YARPP_NO_RELATED) return YARPP_NO_RELATED;
57
+
58
+ // There are results
59
+ return YARPP_RELATED;
60
+ }
61
+
62
+ /**
63
+ * @param int $reference_ID
64
+ * @return string YARPP_NO_RELATED | YARPP_RELATED | YARPP_NOT_CACHED
65
+ */
66
+ public function is_cached($reference_ID) {
67
+ return YARPP_NOT_CACHED;
68
+ }
69
+ public function clear($reference_ID) {
70
+ }
71
+
72
+ /*
73
+ * POST STATUS INTERACTIONS
74
+ */
75
+ /**
76
+ * Clear the cache for this entry and for all posts which are "related" to it.
77
+ * @since 3.2 This is called when a post is deleted.
78
+ */
79
+ function delete_post($post_ID) {
80
+ // Clear the cache for this post.
81
+ $this->clear((int) $post_ID);
82
+
83
+ // Find all "peers" which list this post as a related post and clear their caches
84
+ if ($peers = $this->related(null, (int) $post_ID)) $this->clear($peers);
85
+ }
86
+
87
+ /**
88
+ * @since 3.2.1 Handle various post_status transitions
89
+ */
90
+ function transition_post_status( $new_status, $old_status, $post ) {
91
+ $post_ID = $post->ID;
92
+ /**
93
+ * @since 3.4 Don't compute on revisions
94
+ * @since 3.5 Compute on the parent instead
95
+ */
96
+ if ($the_post = wp_is_post_revision($post_ID)) $post_ID = $the_post;
97
+ // Un-publish
98
+ if ($old_status === 'publish' && $new_status !== 'publish') {
99
+ // Find all "peers" which list this post as a related post and clear their caches
100
+ if ($peers = $this->related(null, (int) $post_ID)) $this->clear($peers);
101
+ }
102
+
103
+ // Publish
104
+ if ($old_status !== 'publish' && $new_status === 'publish') {
105
+ /*
106
+ * Find everything which is related to this post, and clear them,
107
+ * so that this post might show up as related to them.
108
+ */
109
+ if ($related = $this->related($post_ID, null)) $this->clear($related);
110
+ }
111
+ /**
112
+ * @since 3.4 Simply clear the cache on save; don't recompute.
113
+ */
114
+ $this->clear((int) $post_ID);
115
+ }
116
+
117
+ function set_score_override_flag($q) {
118
+ if ($this->is_yarpp_time()) {
119
+ $this->score_override = (isset($q->query_vars['orderby']) && $q->query_vars['orderby'] === 'score');
120
+
121
+ if (!empty($q->query_vars['showposts'])) {
122
+ $this->online_limit = $q->query_vars['showposts'];
123
+ } else {
124
+ $this->online_limit = false;
125
+ }
126
+ } else {
127
+ $this->score_override = false;
128
+ $this->online_limit = false;
129
+ }
130
+ }
131
+ /**
132
+ * SQL!
133
+ */
134
+ protected function sql($reference_ID = false, $args = array()) {
135
+ global $wpdb, $post;
136
+
137
+ if (is_object($post) && !$reference_ID) {
138
+ $reference_ID = $post->ID;
139
+ }
140
+
141
+ if (!is_object($post) || $reference_ID != $post->ID) {
142
+ $reference_post = get_post($reference_ID);
143
+ } else {
144
+ $reference_post = $post;
145
+ }
146
+
147
+ $options = array(
148
+ 'threshold',
149
+ 'show_pass_post',
150
+ 'past_only',
151
+ 'weight',
152
+ 'require_tax',
153
+ 'exclude',
154
+ 'recent',
155
+ 'limit'
156
+ );
157
+ extract($this->core->parse_args($args, $options));
158
+ // The maximum number of items we'll ever want to cache
159
+ $limit = max($limit, $this->core->get_option('rss_limit'));
160
+
161
+ // Fetch keywords
162
+ $keywords = $this->get_keywords($reference_ID);
163
+
164
+ // SELECT
165
+ $newsql = "SELECT $reference_ID as reference_ID, ID, "; //post_title, post_date, post_content, post_excerpt,
166
+
167
+ $newsql .= 'ROUND(0';
168
+ if (isset($weight['body']) && isset($weight['body']) && (int) $weight['body']) {
169
+ $newsql .= " + (MATCH (post_content) AGAINST ('".esc_sql($keywords['body'])."')) * ".absint($weight['body']);
170
+ }
171
+ if (isset($weight['body']) && isset($weight['title']) && (int) $weight['title']) {
172
+ $newsql .= " + (MATCH (post_title) AGAINST ('".esc_sql($keywords['title'])."')) * ".absint($weight['title']);
173
+ }
174
+
175
+ // Build tax criteria query parts based on the weights
176
+ foreach ((array) $weight['tax'] as $tax => $tax_weight) {
177
+ $newsql .= " + ".$this->tax_criteria($reference_ID, $tax)." * ".intval($tax_weight);
178
+ }
179
+
180
+ $newsql .= ',1) as score';
181
+
182
+ $newsql .= "\n from $wpdb->posts \n";
183
+
184
+ $exclude_tt_ids = wp_parse_id_list($exclude);
185
+ if (count($exclude_tt_ids) || count((array) $weight['tax']) || count($require_tax)) {
186
+ $newsql .= "left join $wpdb->term_relationships as terms on ( terms.object_id = $wpdb->posts.ID ) \n";
187
+ }
188
+
189
+ /*
190
+ * Where
191
+ */
192
+
193
+ $newsql .= " where post_status in ( 'publish', 'static' ) and ID != '$reference_ID'";
194
+ /**
195
+ * @since 3.1.8 Revised $past_only option
196
+ */
197
+ if ($past_only) $newsql .= " and post_date <= '$reference_post->post_date' ";
198
+ if (!$show_pass_post) $newsql .= " and post_password ='' ";
199
+ if ((bool) $recent) $newsql .= " and post_date > date_sub(now(), interval {$recent}) ";
200
+
201
+ $newsql .= " and post_type = 'post'";
202
+
203
+ // GROUP BY
204
+ $newsql .= "\n group by ID \n";
205
+
206
+ // HAVING
207
+ // number_format fix suggested by vkovalcik! :)
208
+ $safethreshold = number_format(max($threshold,0.1), 2, '.', '');
209
+ /**
210
+ * @since 3.5.3: ID=0 is a special value; never save such a result.
211
+ */
212
+ $newsql .= " having score >= $safethreshold and ID != 0";
213
+ if (count($exclude_tt_ids)) {
214
+ $newsql .= " and bit_or(terms.term_taxonomy_id in (".join(',', $exclude_tt_ids).")) = 0";
215
+ }
216
+
217
+ foreach ((array) $require_tax as $tax => $number) {
218
+ $newsql .= ' and '.$this->tax_criteria($reference_ID, $tax).' >= '.intval($number);
219
+ }
220
+
221
+ $newsql .= " order by score desc limit $limit";
222
+
223
+ if (isset($args['post_type'])) {
224
+ $post_types = (array) $args['post_type'];
225
+ } else {
226
+ $post_types = $this->core->get_post_types();
227
+ }
228
+ $queries = array();
229
+ foreach ($post_types as $post_type) {
230
+ $queries[] = '('.str_replace("post_type = 'post'", "post_type = '{$post_type}'", $newsql).')';
231
+ }
232
+ $sql = implode(' union ', $queries);
233
+
234
+ if ($this->core->debug) echo "<!-- $sql -->";
235
+
236
+ $this->last_sql = $sql;
237
+
238
+ return $sql;
239
+ }
240
+
241
+ private function tax_criteria($reference_ID, $taxonomy) {
242
+ $terms = get_the_terms($reference_ID, $taxonomy);
243
+ // if there are no terms of that tax
244
+ if (false === $terms) return '(1 = 0)';
245
+
246
+ $tt_ids = wp_list_pluck($terms, 'term_taxonomy_id');
247
+ return "count(distinct if( terms.term_taxonomy_id in (".join(',',$tt_ids)."), terms.term_taxonomy_id, null ))";
248
+ }
249
+ /*
250
+ * KEYWORDS
251
+ */
252
+ /**
253
+ * @param int $ID
254
+ * @param string $type body | title | all
255
+ * @return string|array depending on whether "all" were requested or not
256
+ */
257
+ public function get_keywords($ID, $type = 'all') {
258
+ if (!$ID = absint($ID)) return false;
259
+ $keywords = array(
260
+ 'body' => $this->body_keywords($ID),
261
+ 'title' => $this->title_keywords($ID)
262
+ );
263
+ if (empty($keywords)) return false;
264
+
265
+ if ($type === 'all') return $keywords;
266
+ return $keywords[$type];
267
+ }
268
+
269
+ protected function title_keywords($ID, $max = 20) {
270
+ return apply_filters('yarpp_title_keywords', $this->extract_keywords(get_the_title($ID), $max, $ID), $max, $ID);
271
+ }
272
+ protected function body_keywords( $ID, $max = 20 ) {
273
+ global $wp_current_filter;
274
+ $filter_count = array_count_values( $wp_current_filter );
275
+ if ( $filter_count['the_content'] > 1 ) {
276
+ return '';
277
+ }
278
+ $post = get_post( $ID );
279
+ if ( empty( $post ) ) {
280
+ return '';
281
+ }
282
+ return apply_filters( 'yarpp_body_keywords', $this->extract_keywords( apply_filters( 'the_content', $post->post_content ), $max, $ID ), $max, $ID );
283
+ }
284
+
285
+ private function extract_keywords( $html, $max = 20, $ID = 0 ) {
286
+
287
+ /**
288
+ * @filter yarpp_extract_keywords
289
+ *
290
+ * Use this filter to override YARPP's built-in keyword computation
291
+ * Return values should be a string of space-delimited words
292
+ *
293
+ * @param $keywords
294
+ * @param $html unfiltered HTML content
295
+ * @param (int) $max maximum number of keywords
296
+ * @param (int) $ID
297
+ */
298
+ if ($keywords = apply_filters('yarpp_extract_keywords', false, $html, $max, $ID)) return $keywords;
299
+ if (defined('WPLANG')) {
300
+ switch ( substr(WPLANG, 0, 2) ) {
301
+ case 'de':
302
+ $lang = 'de_DE';
303
+ break;
304
+ case 'it':
305
+ $lang = 'it_IT';
306
+ break;
307
+ case 'pl':
308
+ $lang = 'pl_PL';
309
+ break;
310
+ case 'bg':
311
+ $lang = 'bg_BG';
312
+ break;
313
+ case 'fr':
314
+ $lang = 'fr_FR';
315
+ break;
316
+ case 'cs':
317
+ $lang = 'cs_CZ';
318
+ break;
319
+ case 'nl':
320
+ $lang = 'nl_NL';
321
+ break;
322
+ default:
323
+ $lang = 'en_US';
324
+ break;
325
+ }
326
+ }
327
+ else {
328
+ $lang = 'en_US';
329
+ }
330
+
331
+ $words_file = YARPP_DIR.'/lang/words-'.$lang.'.php';
332
+ if (file_exists($words_file)) include($words_file);
333
+ if (!isset($overusedwords)) $overusedwords = array();
334
+
335
+ // strip tags and html entities
336
+ $text = preg_replace('/&(#x[0-9a-f]+|#[0-9]+|[a-zA-Z]+);/', '', strip_tags($html) );
337
+
338
+ // 3.2.2: ignore soft hyphens
339
+ // Requires PHP 5: http://bugs.php.net/bug.php?id=25670
340
+ $softhyphen = html_entity_decode('&#173;',ENT_NOQUOTES,'UTF-8');
341
+ $text = str_replace($softhyphen, '', $text);
342
+
343
+ $charset = get_option('blog_charset');
344
+ if ( function_exists('mb_split') && !empty($charset) ) {
345
+ mb_regex_encoding($charset);
346
+ $wordlist = mb_split('\s*\W+\s*', mb_strtolower($text, $charset));
347
+ } else
348
+ $wordlist = preg_split('%\s*\W+\s*%', strtolower($text));
349
+
350
+ // Build an array of the unique words and number of times they occur.
351
+ $tokens = array_count_values($wordlist);
352
+
353
+ // Remove the stop words from the list.
354
+ $overusedwords = apply_filters( 'yarpp_keywords_overused_words', $overusedwords );
355
+ if ( is_array($overusedwords) ) {
356
+ foreach ($overusedwords as $word) {
357
+ unset($tokens[$word]);
358
+ }
359
+ }
360
+ // Remove words which are only a letter
361
+ foreach (array_keys($tokens) as $word) {
362
+ if ( function_exists('mb_strlen') )
363
+ if (mb_strlen($word) < 2) unset($tokens[$word]);
364
+ else
365
+ if (strlen($word) < 2) unset($tokens[$word]);
366
+ }
367
+
368
+ arsort($tokens, SORT_NUMERIC);
369
+
370
+ $types = array_keys($tokens);
371
+
372
+ if (count($types) > $max)
373
+ $types = array_slice($types, 0, $max);
374
+ return implode(' ', $types);
375
+ }
376
+ }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
readme.txt CHANGED
@@ -5,8 +5,8 @@ Author URI: http://www.yarpp.com/
5
  Plugin URI: http://www.yarpp.com/
6
  Tags: feeds, pages, posts, related, rss, yarpp, ads, multisite, multilingual, thumbnails, related posts, related content
7
  Requires at least: 3.3
8
- Tested up to: 4.4
9
- Stable tag: 4.3.1
10
  License: GPLv2 or later
11
 
12
  Display a list of related posts on your site based on a powerful unique algorithm. Earn money by including sponsored content!
@@ -15,18 +15,6 @@ Display a list of related posts on your site based on a powerful unique algorith
15
 
16
  Yet Another Related Posts Plugin (YARPP) displays pages, posts, and custom post types related to the current entry, introducing your readers to other relevant content on your site.
17
 
18
- Now you can mix and match **YARPP Basic** and **YARPP Pro** to get the best of both features, beneath articles or in the sidebar! Use the combination that works best for you.
19
-
20
- **YARPP Pro for Sponsored Content**
21
- -----------------------------------------
22
- * Create a **variety of native units**, including Content Recommendation or In Feed display
23
- * **Make money by displaying sponsored content**, at the bottom of your posts, in the sidebar, or both.
24
- * **Easily promote your product or service** on thousands of blogs and websites.
25
- * Advertisers are now able to bid by CPC and/or CPM
26
- * Support for more granular advertiser targeting such as IAB category and geo-targeting by DMA
27
-
28
- [Learn more about the new YARPP Pro enhancements!](http://www.yarpp.com)
29
-
30
  **YARPP Basic for Standard Features**
31
  -------------------------------------------
32
  * **Thumbnail or list view** of related content.
@@ -51,9 +39,9 @@ Make sure the "display related posts in feeds" option is turned on if you would
51
 
52
  = Widget =
53
 
54
- Related posts can also be displayed as a widget. Go to the Appearance > Widgets options page and add the "Related Posts (YARPP)" widget. Choose to display content from YARPP Basic or YARPP Pro. The widget will only be displayed on single entry (permalink) pages.
55
 
56
- The YARPP Basic widget can be used even if the "auto display" option is turned off. The YARPP Pro sidebar widget can be used even if you choose YARPP Basic to display related content at the bottom of your posts.
57
 
58
  = Custom display through templates =
59
 
@@ -63,7 +51,7 @@ YARPP allows the advanced user with knowledge of PHP to customize the display of
63
 
64
  **Common Questions about YARPP Basic**
65
 
66
- Below are Frequently Asked Questions about YARPP basic. For questions about the new YARPP Pro enhancements, please visit the [YARPP Pro FAQ](http://www.yarpp.com/faq).
67
 
68
  If your question isn't here, ask your own question at [the WordPress.org forums](http://wordpress.org/support/plugin/yet-another-related-posts-plugin).
69
 
@@ -73,7 +61,7 @@ Most likely you have "no related posts" right now because the default "match thr
73
 
74
  = How can I move the related posts display? =
75
 
76
- If you do not want to show the Related Posts display in its default position (right below the post content), first go to YARPP options and turn off the "automatically display" options in the "website" section. If you would like to instead display it in your sidebar and you have a widget-aware theme, YARPP provides a Related Posts widget which you can add under "Appearance" > "Widgets." (You can choose to display sidebar content from either YARPP Basic or YARPP Pro.)
77
 
78
  If you would like to add the Related Posts display elsewhere, edit your relevant theme file (most likely something like `single.php`) and add the PHP code `related_posts();` within [The Loop](http://codex.wordpress.org/The_Loop) where you want to display the related posts. (Make sure you don't add `echo related_posts();` or you may end up with duplicates in your related posts section.)
79
 
@@ -122,8 +110,6 @@ The default YARPP thumbnail size is 120px by 120px. The thumbnail size can be sp
122
 
123
  Each time you change YARPP's thumbnail dimensions like this, you will probably want to have WordPress regenerate appropriate sized thumbnails for all of your images. I highly recommend the [Regenerate Thumbnails](http://wordpress.org/extend/plugins/regenerate-thumbnails/) plugin for this purpose.
124
 
125
- Please note that, by enabling the YARPP Pro enhancements, you can customize the thumbnail display using the admin interface instead of through PHP code.
126
-
127
  = I'm using the Thumbnails display. Why aren't the right size thumbnails being served? =
128
 
129
  By default, if an appropriately sized thumbnail is not available in WordPress, a larger image will be served and will be made to fit in the thumbnail space via CSS. Sometimes this means images will be scaled down in a weird way, so it is not ideal. What you really want is for YARPP to serve appropriately-sized thumbnails.
@@ -297,6 +283,10 @@ YARPP is currently localized in the following languages:
297
 
298
  == Changelog ==
299
 
 
 
 
 
300
  = 4.3.1 =
301
  * Tested on WordPress 4.4.
302
  * Fix $lang missing error in YARPP_Cache.php
5
  Plugin URI: http://www.yarpp.com/
6
  Tags: feeds, pages, posts, related, rss, yarpp, ads, multisite, multilingual, thumbnails, related posts, related content
7
  Requires at least: 3.3
8
+ Tested up to: 4.7
9
+ Stable tag: 4.3.2
10
  License: GPLv2 or later
11
 
12
  Display a list of related posts on your site based on a powerful unique algorithm. Earn money by including sponsored content!
15
 
16
  Yet Another Related Posts Plugin (YARPP) displays pages, posts, and custom post types related to the current entry, introducing your readers to other relevant content on your site.
17
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  **YARPP Basic for Standard Features**
19
  -------------------------------------------
20
  * **Thumbnail or list view** of related content.
39
 
40
  = Widget =
41
 
42
+ Related posts can also be displayed as a widget. Go to the Appearance > Widgets options page and add the "Related Posts (YARPP)" widget. Choose to display content from YARPP Basic. The widget will only be displayed on single entry (permalink) pages.
43
 
44
+ The YARPP Basic widget can be used even if the "auto display" option is turned off.
45
 
46
  = Custom display through templates =
47
 
51
 
52
  **Common Questions about YARPP Basic**
53
 
54
+ Below are Frequently Asked Questions about YARPP basic.
55
 
56
  If your question isn't here, ask your own question at [the WordPress.org forums](http://wordpress.org/support/plugin/yet-another-related-posts-plugin).
57
 
61
 
62
  = How can I move the related posts display? =
63
 
64
+ If you do not want to show the Related Posts display in its default position (right below the post content), first go to YARPP options and turn off the "automatically display" options in the "website" section. If you would like to instead display it in your sidebar and you have a widget-aware theme, YARPP provides a Related Posts widget which you can add under "Appearance" > "Widgets."
65
 
66
  If you would like to add the Related Posts display elsewhere, edit your relevant theme file (most likely something like `single.php`) and add the PHP code `related_posts();` within [The Loop](http://codex.wordpress.org/The_Loop) where you want to display the related posts. (Make sure you don't add `echo related_posts();` or you may end up with duplicates in your related posts section.)
67
 
110
 
111
  Each time you change YARPP's thumbnail dimensions like this, you will probably want to have WordPress regenerate appropriate sized thumbnails for all of your images. I highly recommend the [Regenerate Thumbnails](http://wordpress.org/extend/plugins/regenerate-thumbnails/) plugin for this purpose.
112
 
 
 
113
  = I'm using the Thumbnails display. Why aren't the right size thumbnails being served? =
114
 
115
  By default, if an appropriately sized thumbnail is not available in WordPress, a larger image will be served and will be made to fit in the thumbnail space via CSS. Sometimes this means images will be scaled down in a weird way, so it is not ideal. What you really want is for YARPP to serve appropriately-sized thumbnails.
283
 
284
  == Changelog ==
285
 
286
+ = 4.3.2 =
287
+ * Fix ksort error in YARPP_Cache.php (credit to Derrick Hammer/@pcfreak30)
288
+ * Discontinuing the YARPP Pro service as of 12/31/2016
289
+
290
  = 4.3.1 =
291
  * Tested on WordPress 4.4.
292
  * Fix $lang missing error in YARPP_Cache.php
yarpp.php CHANGED
@@ -2,7 +2,7 @@
2
  /*----------------------------------------------------------------------------------------------------------------------
3
  Plugin Name: Yet Another Related Posts Plugin
4
  Description: Adds related posts to your site and in RSS feeds, based on a powerful, customizable algorithm. Enabling YARPP Pro gives you access to even more powerful features. <a href="http://www.yarpp.com" target="_blank">Find out more</a>.
5
- Version: 4.3.1
6
  Author: Adknowledge
7
  Author URI: http://www.yarpp.com/
8
  Plugin URI: http://www.yarpp.com/
@@ -14,7 +14,7 @@ if(!defined('WP_CONTENT_DIR')){
14
  define('WP_CONTENT_DIR', substr($tr,0,strrpos($tr,'/')));
15
  }
16
 
17
- define('YARPP_VERSION', '4.3.1');
18
  define('YARPP_DIR', dirname(__FILE__));
19
  define('YARPP_URL', plugins_url('',__FILE__));
20
  define('YARPP_NO_RELATED', ':(');
2
  /*----------------------------------------------------------------------------------------------------------------------
3
  Plugin Name: Yet Another Related Posts Plugin
4
  Description: Adds related posts to your site and in RSS feeds, based on a powerful, customizable algorithm. Enabling YARPP Pro gives you access to even more powerful features. <a href="http://www.yarpp.com" target="_blank">Find out more</a>.
5
+ Version: 4.3.2
6
  Author: Adknowledge
7
  Author URI: http://www.yarpp.com/
8
  Plugin URI: http://www.yarpp.com/
14
  define('WP_CONTENT_DIR', substr($tr,0,strrpos($tr,'/')));
15
  }
16
 
17
+ define('YARPP_VERSION', '4.3.2');
18
  define('YARPP_DIR', dirname(__FILE__));
19
  define('YARPP_URL', plugins_url('',__FILE__));
20
  define('YARPP_NO_RELATED', ':(');