Version Description
Download this release
Release Info
Developer | mitchoyoshitaka |
Plugin | Yet Another Related Posts Plugin (YARPP) |
Version | 1.5 |
Comparing to | |
See all releases |
Code changes from version 1.1 to 1.5
- includes.php +114 -0
- magic.php +160 -0
- options.css +28 -0
- options.php +113 -0
- readme.txt +37 -37
- related-functions.php +35 -0
- yarpp.php +10 -336
includes.php
ADDED
@@ -0,0 +1,114 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// here's a list of all the options YARPP uses (except version), as well as their default values, sans the yarpp_ prefix, split up into binary options and value options. These arrays are used in updating settings (options.php) and other tasks.
|
4 |
+
$yarpp_value_options = array('threshold' => 5,
|
5 |
+
'limit' => 5,
|
6 |
+
'excerpt_length' => 10,
|
7 |
+
'before_title' => '<li>',
|
8 |
+
'after_title' => '</li>',
|
9 |
+
'before_post' => '<small>',
|
10 |
+
'after_post' => '</small>',
|
11 |
+
'before_related' => '<p>Related posts:<ol>',
|
12 |
+
'after_related' => '</ol></p>',
|
13 |
+
'no_results' => '<p>No related posts.</p>');
|
14 |
+
$yarpp_binary_options = array('past_only' => true,
|
15 |
+
'show_score' => true,
|
16 |
+
'show_excerpt' => false,
|
17 |
+
'show_pass_post' => false,
|
18 |
+
'cross_relate' => false,
|
19 |
+
'auto_display' => true);
|
20 |
+
|
21 |
+
function yarpp_enabled() {
|
22 |
+
global $wpdb;
|
23 |
+
$indexdata = $wpdb->get_results("show index from $wpdb->posts");
|
24 |
+
foreach ($indexdata as $index) {
|
25 |
+
if ($index->Key_name == 'post_related') return 1;
|
26 |
+
}
|
27 |
+
return 0;
|
28 |
+
}
|
29 |
+
|
30 |
+
function yarpp_activate() {
|
31 |
+
global $yarpp_version, $wpdb, $yarpp_binary_options, $yarpp_value_options;
|
32 |
+
$yarpp_options = array_merge($yarpp_binary_options, $yarpp_value_options);
|
33 |
+
foreach (array_keys($yarpp_options) as $option) {
|
34 |
+
add_option('yarpp_'.$option,$yarpp_options[$option]);
|
35 |
+
}
|
36 |
+
if (!yarpp_enabled()) {
|
37 |
+
$wpdb->query("ALTER TABLE $wpdb->posts ADD FULLTEXT `post_related` ( `post_name` , `post_content` )");
|
38 |
+
}
|
39 |
+
add_option('yarpp_version',1.5);
|
40 |
+
return 1;
|
41 |
+
}
|
42 |
+
|
43 |
+
function yarpp_upgrade_check() {
|
44 |
+
if (get_option('threshold') and get_option('limit') and get_option('len')) {
|
45 |
+
yarpp_activate(); // just to make sure, in case the plugin was just replaced and not deactivated / activated
|
46 |
+
echo '<div id="message" class="updated fade" style="background-color: rgb(207, 235, 247);"><h3>An important message from YARPP:</h3><p>Thank you for upgrading to YARPP 1.5. YARPP 1.5 adds "simple installation" which automagically prints a simple related posts display at the end of each single entry (permalink) page without tinkering with any theme files. As a previous YARPP user, you probably have already edited your theme files to your liking, so this "automatic display" feature has been turned off.</p><p>If you would like to use "automatic display," remove <code>related_posts</code> from your <code>single.php</code> file and turn on automatic display in the YARPP options. Make sure to adjust the new prefix and suffix preferences to your liking as well.</p><p>For more information, check out the <a href="http://mitcho.com/code/yarpp/">YARPP documentation</a>. (This message will not be displayed again.)</p></div>';
|
47 |
+
yarpp_upgrade_one_five();
|
48 |
+
}
|
49 |
+
}
|
50 |
+
|
51 |
+
function yarpp_admin_menu() {
|
52 |
+
if (function_exists('add_submenu_page')) add_submenu_page('options-general.php', __('Related Posts (YARPP)'), __('Related Posts (YARPP)'), 8, 'yarpp/options.php');
|
53 |
+
}
|
54 |
+
|
55 |
+
function yarpp_default($content) {
|
56 |
+
global $wpdb, $post, $user_level;
|
57 |
+
if (get_option('yarpp_auto_display') and is_single()) {
|
58 |
+
return $content."\n\n".yarpp_related(array('post'),array(),false);
|
59 |
+
} else {
|
60 |
+
return $content;
|
61 |
+
}
|
62 |
+
}
|
63 |
+
|
64 |
+
|
65 |
+
|
66 |
+
/* apply_filters_without() is a dirty, dirty HACK.
|
67 |
+
It is used here to avoid a loop in apply_filters('the_content') > yarpp_default() > yarpp_related() > current_post_keywords() > apply_filters('the_content'). The code is straight up stolen from wp-includes/plugin.php and, with the exception of the single hack line below, should match what happens in plugin.php . */
|
68 |
+
function apply_filters_without($tag, $string, $without) {
|
69 |
+
global $wp_filter, $merged_filters;
|
70 |
+
|
71 |
+
if ( !isset( $merged_filters[ $tag ] ) )
|
72 |
+
merge_filters($tag);
|
73 |
+
|
74 |
+
if ( !isset($wp_filter[$tag]) )
|
75 |
+
return $string;
|
76 |
+
|
77 |
+
reset( $wp_filter[ $tag ] );
|
78 |
+
|
79 |
+
$args = func_get_args();
|
80 |
+
|
81 |
+
do{
|
82 |
+
foreach( (array) current($wp_filter[$tag]) as $the_ )
|
83 |
+
if ( !is_null($the_['function']) and $the_['function'] != $without ){ //HACK!
|
84 |
+
$args[1] = $string;
|
85 |
+
$string = call_user_func_array($the_['function'], array_slice($args, 1, (int) $the_['accepted_args']));
|
86 |
+
}
|
87 |
+
|
88 |
+
} while ( next($wp_filter[$tag]) !== false );
|
89 |
+
|
90 |
+
return $string;
|
91 |
+
}
|
92 |
+
|
93 |
+
// upgrade to 1.5!
|
94 |
+
function yarpp_upgrade_one_five() {
|
95 |
+
global $wpdb;
|
96 |
+
$migrate_options = array('past_only','show_score','show_excerpt','show_pass_post','cross_relate','limit','threshold','before_title','after_title','before_post','after_post');
|
97 |
+
foreach ($migrate_options as $option) {
|
98 |
+
if (get_option($option)) {
|
99 |
+
update_option('yarpp_'.$option,get_option($option));
|
100 |
+
delete_option($option);
|
101 |
+
}
|
102 |
+
}
|
103 |
+
// len is one option where we actually change the name of the option
|
104 |
+
update_option('yarpp_excerpt_length',get_option('len'));
|
105 |
+
delete_option('len');
|
106 |
+
|
107 |
+
// override these defaults for those who upgrade from < 1.5
|
108 |
+
update_option('yarpp_auto_display',false);
|
109 |
+
update_option('yarpp_before_related','');
|
110 |
+
update_option('yarpp_after_related','');
|
111 |
+
unset($yarpp_version);
|
112 |
+
}
|
113 |
+
|
114 |
+
?>
|
magic.php
ADDED
@@ -0,0 +1,160 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// current_post_keywords()
|
4 |
+
// This function was more or less completely written by Peter Bowyer
|
5 |
+
/**
|
6 |
+
* Builds a word frequency list from the Wordpress post, and returns a string
|
7 |
+
* to be used in matching against the MySQL full-text index.
|
8 |
+
*
|
9 |
+
* @param integer $num_to_ret The number of words to use when matching against
|
10 |
+
* the database.
|
11 |
+
* @return string The words
|
12 |
+
*/
|
13 |
+
function current_post_keywords($num_to_ret = 20) {
|
14 |
+
global $post;
|
15 |
+
// An array of weightings, to make adjusting them easier.
|
16 |
+
$w = array(
|
17 |
+
'title' => 2,
|
18 |
+
'name' => 2,
|
19 |
+
'content' => 1,
|
20 |
+
'cat_name' => 3
|
21 |
+
);
|
22 |
+
|
23 |
+
/*
|
24 |
+
Thanks to http://www.eatdrinksleepmovabletype.com/tutorials/building_a_weighted_keyword_list/
|
25 |
+
for the basics for this code. It saved me much typing (or thinking) :)
|
26 |
+
*/
|
27 |
+
|
28 |
+
// This needs experimenting with. I've given post title and url a double
|
29 |
+
// weighting, changing this may give you better results
|
30 |
+
$string = str_repeat($post->post_title, $w['title'].' ').
|
31 |
+
str_repeat(str_replace('-', ' ', $post->post_name).' ', $w['name']).
|
32 |
+
str_repeat(strip_tags(apply_filters_without('the_content',$post->post_content,'yarpp_default')), $w['content'].' ');//mitcho: strip_tags
|
33 |
+
|
34 |
+
// Cat names don't help with the current query: the category names of other
|
35 |
+
// posts aren't retrieved by the query to be matched against (and can't be
|
36 |
+
// indexed)
|
37 |
+
// But I've left this in just in case...
|
38 |
+
$post_categories = get_the_category();
|
39 |
+
foreach ($post_categories as $cat) {
|
40 |
+
$string .= str_repeat($cat->cat_name.' ', $w['cat_name']);
|
41 |
+
}
|
42 |
+
|
43 |
+
// Remove punctuation.
|
44 |
+
$wordlist = preg_split('/\s*[\s+\.|\?|,|(|)|\-+|\'|\"|=|;|×|\$|\/|:|{|}]\s*/i', strtolower($string));
|
45 |
+
|
46 |
+
// Build an array of the unique words and number of times they occur.
|
47 |
+
$a = array_count_values($wordlist);
|
48 |
+
|
49 |
+
//Remove words that don't matter--"stop words."
|
50 |
+
$overusedwords = array( '', 'a', 'an', 'the', 'and', 'of', 'i', 'to', 'is', 'in', 'with', 'for', 'as', 'that', 'on', 'at', 'this', 'my', 'was', 'our', 'it', 'you', 'we', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '10', 'about', 'after', 'all', 'almost', 'along', 'also', 'amp', 'another', 'any', 'are', 'area', 'around', 'available', 'back', 'be', 'because', 'been', 'being', 'best', 'better', 'big', 'bit', 'both', 'but', 'by', 'c', 'came', 'can', 'capable', 'control', 'could', 'course', 'd', 'dan', 'day', 'decided', 'did', 'didn', 'different', 'div', 'do', 'doesn', 'don', 'down', 'drive', 'e', 'each', 'easily', 'easy', 'edition', 'end', 'enough', 'even', 'every', 'example', 'few', 'find', 'first', 'found', 'from', 'get', 'go', 'going', 'good', 'got', 'gt', 'had', 'hard', 'has', 'have', 'he', 'her', 'here', 'how', 'if', 'into', 'isn', 'just', 'know', 'last', 'left', 'li', 'like', 'little', 'll', 'long', 'look', 'lot', 'lt', 'm', 'made', 'make', 'many', 'mb', 'me', 'menu', 'might', 'mm', 'more', 'most', 'much', 'name', 'nbsp', 'need', 'new', 'no', 'not', 'now', 'number', 'off', 'old', 'one', 'only', 'or', 'original', 'other', 'out', 'over', 'part', 'place', 'point', 'pretty', 'probably', 'problem', 'put', 'quite', 'quot', 'r', 're', 'really', 'results', 'right', 's', 'same', 'saw', 'see', 'set', 'several', 'she', 'sherree', 'should', 'since', 'size', 'small', 'so', 'some', 'something', 'special', 'still', 'stuff', 'such', 'sure', 'system', 't', 'take', 'than', 'their', 'them', 'then', 'there', 'these', 'they', 'thing', 'things', 'think', 'those', 'though', 'through', 'time', 'today', 'together', 'too', 'took', 'two', 'up', 'us', 'use', 'used', 'using', 've', 'very', 'want', 'way', 'well', 'went', 'were', 'what', 'when', 'where', 'which', 'while', 'white', 'who', 'will', 'would', 'your');
|
51 |
+
|
52 |
+
// Remove the stop words from the list.
|
53 |
+
foreach ($overusedwords as $word) {
|
54 |
+
unset($a[$word]);
|
55 |
+
}
|
56 |
+
arsort($a, SORT_NUMERIC);
|
57 |
+
|
58 |
+
$num_words = count($a);
|
59 |
+
$num_to_ret = $num_words > $num_to_ret ? $num_to_ret : $num_words;
|
60 |
+
|
61 |
+
$outwords = array_slice($a, 0, $num_to_ret);
|
62 |
+
return implode(' ', array_keys($outwords));
|
63 |
+
|
64 |
+
}
|
65 |
+
|
66 |
+
function yarpp_related($type,$args,$echo = true) {
|
67 |
+
global $wpdb, $post, $user_level;
|
68 |
+
get_currentuserinfo();
|
69 |
+
|
70 |
+
// if cross_relate is set, override the type argument and make sure both matches are accepted in the sql query
|
71 |
+
if (get_option('yarpp_cross_relate')) $type = array('post','page');
|
72 |
+
|
73 |
+
// Get option values from the options page--this can be overwritten: see readme
|
74 |
+
$options = array('limit','threshold','before_title','after_title','show_excerpt','excerpt_length','before_post','after_post','show_pass_post','past_only','show_score');
|
75 |
+
$optvals = array();
|
76 |
+
foreach (array_keys($options) as $index) {
|
77 |
+
if (isset($args[$index+1])) {
|
78 |
+
$optvals[$options[$index]] = stripslashes($args[$index+1]);
|
79 |
+
} else {
|
80 |
+
$optvals[$options[$index]] = stripslashes(get_option('yarpp_'.$options[$index]));
|
81 |
+
}
|
82 |
+
}
|
83 |
+
extract($optvals);
|
84 |
+
|
85 |
+
// Fetch keywords
|
86 |
+
$terms = current_post_keywords();
|
87 |
+
|
88 |
+
// Make sure the post is not from the future
|
89 |
+
$time_difference = get_settings('gmt_offset');
|
90 |
+
$now = gmdate("Y-m-d H:i:s",(time()+($time_difference*3600)));
|
91 |
+
|
92 |
+
// Primary SQL query
|
93 |
+
|
94 |
+
$sql = "SELECT ID, post_title, post_content,"
|
95 |
+
. "MATCH (post_name, post_content) "
|
96 |
+
. "AGAINST ('$terms') AS score "
|
97 |
+
. "FROM $wpdb->posts WHERE "
|
98 |
+
. "post_type IN ('".implode("', '",$type)."') "
|
99 |
+
. "AND MATCH (post_name, post_content) AGAINST ('$terms') >= $threshold "
|
100 |
+
. "AND (post_status IN ( 'publish', 'static' ) && ID != '$post->ID') ";
|
101 |
+
if (past_only) { $sql .= "AND post_date <= '$now' "; }
|
102 |
+
if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
|
103 |
+
$sql .= "ORDER BY score DESC LIMIT $limit";
|
104 |
+
$results = $wpdb->get_results($sql);
|
105 |
+
$output = '';
|
106 |
+
if ($results) {
|
107 |
+
foreach ($results as $result) {
|
108 |
+
$title = stripslashes(apply_filters('the_title', $result->post_title));
|
109 |
+
$permalink = get_permalink($result->ID);
|
110 |
+
$post_content = strip_tags($result->post_content);
|
111 |
+
$post_content = stripslashes($post_content);
|
112 |
+
$output .= $before_title .'<a href="'. $permalink .'" rel="bookmark" title="Permanent Link: ' . $title . '">' . $title . (($show_score and $user_level >= 8)? ' ('.round($result->score,3).')':'') . '</a>' . $after_title;
|
113 |
+
if ($show_excerpt) {
|
114 |
+
$ze = substr($post_content, 0, $excerpt_length);
|
115 |
+
$ze = substr($ze, 0, strrpos($ze,' '));
|
116 |
+
$ze .= '...';
|
117 |
+
$output .= $before_post . $ze . $after_post;
|
118 |
+
}
|
119 |
+
}
|
120 |
+
$output = get_option('yarpp_before_related').$output.get_option('yarpp_after_related');
|
121 |
+
} else {
|
122 |
+
$output = get_option('yarpp_no_results');
|
123 |
+
}
|
124 |
+
if ($echo) echo $output; else return $output;
|
125 |
+
}
|
126 |
+
|
127 |
+
function yarpp_related_exist($type,$args) {
|
128 |
+
global $wpdb, $post;
|
129 |
+
|
130 |
+
if (get_option('yarpp_cross_relate')) $type = array('post','page');
|
131 |
+
|
132 |
+
$options = array('threshold','show_pass_post','past_only');
|
133 |
+
$optvals = array();
|
134 |
+
foreach (array_keys($options) as $index) {
|
135 |
+
if (isset($args[$index+1])) {
|
136 |
+
$optvals[$options[$index]] = stripslashes($args[$index+1]);
|
137 |
+
} else {
|
138 |
+
$optvals[$options[$index]] = stripslashes(get_option('yarpp_'.$options[$index]));
|
139 |
+
}
|
140 |
+
}
|
141 |
+
extract($optvals);
|
142 |
+
|
143 |
+
$terms = current_post_keywords();
|
144 |
+
|
145 |
+
$time_difference = get_settings('gmt_offset');
|
146 |
+
$now = gmdate("Y-m-d H:i:s",(time()+($time_difference*3600)));
|
147 |
+
|
148 |
+
$sql = "SELECT COUNT(*) as count "
|
149 |
+
. "FROM $wpdb->posts WHERE "
|
150 |
+
. "post_type IN ('".implode("', '",$type)."') "
|
151 |
+
. "AND MATCH (post_name, post_content) AGAINST ('$terms') >= $threshold "
|
152 |
+
. "AND (post_status IN ( 'publish', 'static' ) && ID != '$post->ID') ";
|
153 |
+
if (past_only) { $sql .= "AND post_date <= '$now' "; }
|
154 |
+
if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
|
155 |
+
|
156 |
+
$result = $wpdb->get_var($sql);
|
157 |
+
return $result > 0 ? true: false;
|
158 |
+
}
|
159 |
+
|
160 |
+
?>
|
options.css
ADDED
@@ -0,0 +1,28 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
a.info{
|
2 |
+
position:relative;
|
3 |
+
z-index:24;
|
4 |
+
}
|
5 |
+
|
6 |
+
a.info:hover {
|
7 |
+
z-index:25;
|
8 |
+
text-decoration:none;
|
9 |
+
}
|
10 |
+
|
11 |
+
a.info span {display: none;}
|
12 |
+
|
13 |
+
a.info:hover span {
|
14 |
+
display:block;
|
15 |
+
position:absolute;
|
16 |
+
top:1em;
|
17 |
+
left:0;
|
18 |
+
width:350px;
|
19 |
+
border:1px solid #000;
|
20 |
+
background-color:#ccc;
|
21 |
+
color:#000;
|
22 |
+
padding:4px;
|
23 |
+
}
|
24 |
+
|
25 |
+
span.new {
|
26 |
+
color: red;
|
27 |
+
size: 80%;
|
28 |
+
}
|
options.php
ADDED
@@ -0,0 +1,113 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
// Begin Related Posts Options
|
3 |
+
|
4 |
+
global $yarpp_value_options, $yarpp_binary_options;
|
5 |
+
if (!yarpp_enabled()) {
|
6 |
+
echo '<div class="updated">';
|
7 |
+
if (yarpp_activate()) echo 'The YARPP database had an error but has been fixed.';
|
8 |
+
echo '</div>';
|
9 |
+
}
|
10 |
+
|
11 |
+
if (isset($_POST['update_yarpp'])) {
|
12 |
+
foreach (array_keys($yarpp_value_options) as $option) {
|
13 |
+
update_option('yarpp_'.$option,$_POST[$option]);
|
14 |
+
}
|
15 |
+
foreach (array_keys($yarpp_binary_options) as $option) {
|
16 |
+
(isset($_POST[$option])) ? update_option('yarpp_'.$option,true) : update_option('yarpp_'.$option,false);
|
17 |
+
}
|
18 |
+
echo '<div id="message" class="updated fade" style="background-color: rgb(207, 235, 247);"><p>Options saved!</p></div>';
|
19 |
+
}
|
20 |
+
|
21 |
+
function checkbox($option,$desc,$tr="<tr>
|
22 |
+
<td width='33%' scope='row' colspan='2'>",$inputplus = '') {
|
23 |
+
echo " $tr<label for='$option'>$desc</label></td>
|
24 |
+
<td>
|
25 |
+
<input $inputplus type='checkbox' name='$option' value='true'". ((get_option('yarpp_'.$option)) ? ' checked="checked"': '' )." />
|
26 |
+
</td>
|
27 |
+
</tr>";
|
28 |
+
}
|
29 |
+
function textbox($option,$desc,$size=2,$tr="<tr>
|
30 |
+
<td width='33%' scope='row' colspan='2'>") {
|
31 |
+
echo " $tr<label for='$option'>$desc</label></td>
|
32 |
+
<td><input name='$option' type='text' id='$option' value='".htmlspecialchars(stripslashes(get_option('yarpp_'.$option)))."' size='$size' /></td>
|
33 |
+
</tr>";
|
34 |
+
}
|
35 |
+
|
36 |
+
?>
|
37 |
+
|
38 |
+
<script type="text/javascript">
|
39 |
+
var css=document.createElement("link");
|
40 |
+
css.setAttribute("rel", "stylesheet");
|
41 |
+
css.setAttribute("type", "text/css");
|
42 |
+
css.setAttribute("href", "../wp-content/plugins/yarpp/options.css");
|
43 |
+
document.getElementsByTagName("head")[0].appendChild(css);
|
44 |
+
</script>
|
45 |
+
|
46 |
+
<div class="wrap">
|
47 |
+
<h2>Yet Another Related Posts Plugin Options <small><?php echo get_option('yarpp_version'); ?></small></h2>
|
48 |
+
<p><small>by <a href="http://mitcho.com/code/">mitcho (Michael 芳貴 Erlewine)</a> and based on the fabulous work of <a href="http://peter.mapledesign.co.uk/weblog/archives/wordpress-related-posts-plugin">Peter Bower</a>, <a href="http://wasabi.pbwiki.com/Related%20Entries">Alexander Malov & Mike Lu</a>. If you appreciate this plugin, please consider <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=mitcho%40mitcho%2ecom&item_name=mitcho%2ecom%2fcode%3a%20donate%20to%20Michael%20Yoshitaka%20Erlewine&no_shipping=0&no_note=1&tax=0¤cy_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8">donating to the author, mitcho</a>.</small></p>
|
49 |
+
<form method="post">
|
50 |
+
<fieldset class="options">
|
51 |
+
<h3>"Relatedness" options</h3>
|
52 |
+
<p>YARPP is different than the <a href="http://wasabi.pbwiki.com/Related%20Entries">previous plugins it is based on</a> as it limits the related posts list by (1) a maximum number and (2) a <em>match threshold</em>. <a href="#" class='info'>more><span>The higher the match threshold, the more restrictive, and you get less related posts overall. The default match threshold is 5. If you want to find an appropriate match threshhold, I recommend you turn on the "show admins the match scores" setting below. That way, you can see what kinds of related posts are being picked up and with what kind of match scores, and determine an appropriate threshold for your site.</span></a></p>
|
53 |
+
|
54 |
+
<table class="optiontable editform" width="100%" scope="row">
|
55 |
+
<?php textbox('limit','Maximum number of related posts:')?>
|
56 |
+
<?php textbox('threshold','Match threshold:')?>
|
57 |
+
<?php checkbox('cross_relate',"Cross-relate posts and pages? <a href='#' class='info'>more><span>When the \"Cross-relate posts and pages\" option is selected, the <code>related_posts()</code>, <code>related_pagaes()</code>, and <code>related_entries()</code> all will give the same output, returning both related pages and posts.</span></a>"); ?>
|
58 |
+
|
59 |
+
</table>
|
60 |
+
<h3>Display options</h3>
|
61 |
+
<table class="optiontable editform" width="100%" scope="row">
|
62 |
+
<?php checkbox('auto_display',"Automatically display related posts? <span class='red'>NEW!</span> <a href='#' class='info'>more><span>This option automatically displays related posts right after the content on single entry pages. If this option is off, you will need to manually insert <code>related_posts()</code> or variants into your theme files.</span></a>"); ?>
|
63 |
+
<tr>
|
64 |
+
<td colspan='2'><label for="before_related">Before</label> / <label for="after_related">after related entries </label>:</td>
|
65 |
+
<td><input name="before_related" type="text" id="before_related" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_before_related'))); ?>" size="10" /> / <input name="after_related" type="text" id="after_related" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_after_related'))); ?>" size="10" /><em><small> For example: <ol></ol> or <div></div></small></em>
|
66 |
+
</td>
|
67 |
+
</tr>
|
68 |
+
<tr>
|
69 |
+
<td colspan='2'><label for="before_title">Before</label> / <label for="after_title">after each post </label>:</td>
|
70 |
+
<td><input name="before_title" type="text" id="before_title" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_before_title'))); ?>" size="10" /> / <input name="after_title" type="text" id="after_title" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_after_title'))); ?>" size="10" /><em><small> For example: <li></li> or <dl></dl></small></em>
|
71 |
+
</td>
|
72 |
+
</tr>
|
73 |
+
<?php checkbox('show_excerpt',"Show excerpt?","<tr>
|
74 |
+
<td colspan='2'>",' onclick="javascript:excerpt()"'); ?>
|
75 |
+
<?php textbox('excerpt_length','Excerpt length (No. of words):',null,"<tr name='excerpted'>
|
76 |
+
<td style='background-color: gray; width: .3px;'> </td><td>")?>
|
77 |
+
|
78 |
+
<tr name="excerpted">
|
79 |
+
<td style='background-color: gray; width: 3px;'> </td><td><label for="before_post">Before</label> / <label for="after_post">After</label> (Excerpt):</td>
|
80 |
+
<td><input name="before_post" type="text" id="before_post" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_before_post'))); ?>" size="10" /> / <input name="after_post" type="text" id="after_post" value="<?php echo htmlspecialchars(stripslashes(get_option('yarpp_after_post'))); ?>" size="10" /><em><small> For example: <li></li> or <dl></dl></small></em>
|
81 |
+
</td>
|
82 |
+
</tr>
|
83 |
+
|
84 |
+
<?php textbox('no_results','Default display if no results:','40')?>
|
85 |
+
<?php checkbox('show_past_post',"Show password protected posts?"); ?>
|
86 |
+
<?php checkbox('past_only',"Show only previous posts?"); ?>
|
87 |
+
<?php checkbox('show_score',"Show admins (user level > 8) the match scores?"); ?>
|
88 |
+
</table>
|
89 |
+
</fieldset>
|
90 |
+
|
91 |
+
<div class="submit"><input type="submit" name="update_yarpp" value="<?php _e('Save!', 'update_yarpp') ?>" style="font-weight:bold;" /></div>
|
92 |
+
|
93 |
+
</form>
|
94 |
+
|
95 |
+
</div>
|
96 |
+
<script language="javascript">
|
97 |
+
function excerpt() {
|
98 |
+
if (!document.getElementsByName('show_excerpt')[0].checked) {
|
99 |
+
document.getElementsByName('excerpted')[0].style.display = 'none';
|
100 |
+
document.getElementsByName('excerpted')[1].style.display = 'none';
|
101 |
+
} else {
|
102 |
+
document.getElementsByName('excerpted')[0].style.display = 'table-row';
|
103 |
+
document.getElementsByName('excerpted')[1].style.display = 'table-row';
|
104 |
+
}
|
105 |
+
}
|
106 |
+
excerpt();
|
107 |
+
</script>
|
108 |
+
|
109 |
+
<?php
|
110 |
+
|
111 |
+
// End Related Posts Options
|
112 |
+
|
113 |
+
?>
|
readme.txt
CHANGED
@@ -2,73 +2,73 @@
|
|
2 |
Contributors: mitchoyoshitaka
|
3 |
Author: mitcho (Michael Yoshitaka Erlewine)
|
4 |
Author URI: http://mitcho.com/
|
5 |
-
Plugin URI: http://mitcho.com/code/
|
6 |
-
Donate link:
|
7 |
Tags: related, posts, post, pages, page
|
8 |
Requires at least: 2.1
|
9 |
Tested up to: 2.3.2
|
10 |
-
Stable tag: 1.
|
11 |
|
12 |
Returns a list of the related entries based on keyword matches, limited by a certain relatedness threshold. Like the tried and true Related Posts plugins�just better!
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
-
Yet Another Related Posts Plugin (YARPP)
|
17 |
|
18 |
-
1. *Limiting by a threshold*: Peter Bowyer did the great work of making the algorithm use MySQL's [fulltext search](dev.mysql.com/doc/en/Fulltext_Search.html) score to identify related posts. But it
|
19 |
2. *Related posts and pages*: **New in 1.1!** Puts you in control of pulling up related posts, pages, or both.
|
20 |
-
3. *
|
21 |
4. *Miscellany*: a nicer options screen, displaying the fulltext match score on output for admins, an option to allow related posts from the future, a couple bug fixes, etc.
|
22 |
|
23 |
== Installation ==
|
24 |
|
25 |
-
|
26 |
|
27 |
-
|
28 |
|
29 |
-
|
30 |
|
31 |
-
|
32 |
|
33 |
-
|
34 |
|
35 |
-
|
36 |
|
37 |
-
|
38 |
|
39 |
-
|
40 |
|
41 |
-
|
42 |
|
43 |
-
|
|
|
|
|
|
|
|
|
44 |
|
45 |
-
|
46 |
|
47 |
-
|
48 |
|
49 |
-
|
50 |
|
51 |
-
|
52 |
-
>`<p>Related posts:`
|
53 |
-
>`<ol>`
|
54 |
-
>`<?php related_posts();?>`
|
55 |
-
>`</ol>`
|
56 |
-
>`</p>`
|
57 |
-
>`<?php else: ?>`
|
58 |
-
>`<p>No related posts.</p>`
|
59 |
-
>`<?php endif; ?>`
|
60 |
|
61 |
-
|
62 |
-
|
63 |
-
== Coming soon (probably) ==
|
64 |
|
65 |
1. Incorporation of tags and categories in the algorithm. I've gotten the code working, but I still need to think about what the most natural algorithm would be for weighing these factors against the mysql fulltext score currently used (and works pretty well, I must say).
|
66 |
-
2.
|
67 |
-
3. Um, something else! Let me know if you have any suggestions for improvement. ^^
|
68 |
|
69 |
== Version log ==
|
70 |
-
1.0 Initial upload
|
71 |
-
|
72 |
-
1.0.1 Bugfix: 1.0 assumed you had Markdown installed
|
73 |
|
74 |
-
1.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2 |
Contributors: mitchoyoshitaka
|
3 |
Author: mitcho (Michael Yoshitaka Erlewine)
|
4 |
Author URI: http://mitcho.com/
|
5 |
+
Plugin URI: http://mitcho.com/code/yarpp/
|
6 |
+
Donate link: https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=mitcho%40mitcho%2ecom&item_name=mitcho%2ecom%2fcode%3a%20donate%20to%20Michael%20Yoshitaka%20Erlewine&no_shipping=0&no_note=1&tax=0¤cy_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8
|
7 |
Tags: related, posts, post, pages, page
|
8 |
Requires at least: 2.1
|
9 |
Tested up to: 2.3.2
|
10 |
+
Stable tag: 1.5
|
11 |
|
12 |
Returns a list of the related entries based on keyword matches, limited by a certain relatedness threshold. Like the tried and true Related Posts plugins�just better!
|
13 |
|
14 |
== Description ==
|
15 |
|
16 |
+
Yet Another Related Posts Plugin (YARPP) gives you a list of posts and/or pages related to the current entry, introducing the reader to other relevant content on your site. YARPP is based on the work of [Peter Bowyer](http://peter.mapledesign.co.uk/weblog/archives/wordpress-related-posts-plugin), [Alexander Malov, and Mike Lu](http://wasabi.pbwiki.com/Related%20Entries). Key features include:
|
17 |
|
18 |
+
1. *Limiting by a threshold*: Peter Bowyer did the great work of making the algorithm use MySQL's [fulltext search](dev.mysql.com/doc/en/Fulltext_Search.html) score to identify related posts. But it just displayed, for example, the top 5 most "relevant" entries, even if some of them weren't at all relevant. Now you can set a threshold limit for relevance, and you get more related posts if there are more related posts and less if there are less. Ha!
|
19 |
2. *Related posts and pages*: **New in 1.1!** Puts you in control of pulling up related posts, pages, or both.
|
20 |
+
3. *Simple installation*: **New in 1.5!** Automatically displays related posts after content on single entry pages without any theme tinkering.
|
21 |
4. *Miscellany*: a nicer options screen, displaying the fulltext match score on output for admins, an option to allow related posts from the future, a couple bug fixes, etc.
|
22 |
|
23 |
== Installation ==
|
24 |
|
25 |
+
*Auto display*
|
26 |
|
27 |
+
With YARPP 1.5, you can just put the `yarpp` directory in your `/wp-content/plugins/` directory, activate the plugin, and you're set! You'll see related posts in single entry (permalink) pages. If all your pages say "no related posts," see the FAQ.
|
28 |
|
29 |
+
*Manual installation*
|
30 |
|
31 |
+
If you would like to put the related posts display in another part of your theme, or display them in pages other than single entry pages, turn off "auto display" in the YARPP Options, then drop `related_posts()`, `related_pages()`, or `related_entries()` (see below) in your [WP loop](http://codex.wordpress.org/The_Loop). Change any options in the Related Posts (YARPP) Options pane in Admin > Plugins. See Examples in Other Notes for sample code you can drop into your theme.
|
32 |
|
33 |
+
There're also `related_posts_exist()`, `related_pages_exist()`, and `related_entries_exist()` functions, which return a boolean as expected.
|
34 |
|
35 |
+
*The "related" functions*
|
36 |
|
37 |
+
By default, `related_posts()` gives you back posts only, `related_pages()` gives you pages, and there's `related_entries()` gives you posts and pages. When the "cross-relate posts and pages" option is checked in the YARPP options panel, `related_posts()`, `related_pages()`, and `related_entries()` will give you exactly the same output.
|
38 |
|
39 |
+
== FAQ ==
|
40 |
|
41 |
+
*Every page just says "no related posts"! What's up with that?*
|
42 |
|
43 |
+
Most likely you have "no related posts" right now as the default "match threshold" is too high. Here's what I recommend to find an appropriate match threshold:
|
44 |
+
1. lower your match threshold in the YARPP prefs to something ridiculously low, like 1 or 0.5.
|
45 |
+
2. Make sure the last option "show admins the match scores" is on.
|
46 |
+
3. Most likely the really low threshold will pull up many posts that aren't actually related (false positives), so look at some of your posts' related posts and their match scores.
|
47 |
+
4. This will help you find an appropriate threshold. You want it lower than what you have now, but high enough so it doesn't have many false positives. Set this new match threshold in the Options.
|
48 |
|
49 |
+
*Why doesn't YARPP use tags to find related posts?*
|
50 |
|
51 |
+
YARPP currently doesn't use tags to compare posts--it uses the actual content of the posts. Tag comparison as part of the "relatedness algorithm" will come soon but, in the mean time, I've found the current algorithm to work very well for many situations.
|
52 |
|
53 |
+
*Things are weird after I upgraded. Ack!*
|
54 |
|
55 |
+
I highly recommend you disactivate YARPP, replace it with the new one, and then reactivate it.
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
56 |
|
57 |
+
== Coming soon ==
|
|
|
|
|
58 |
|
59 |
1. Incorporation of tags and categories in the algorithm. I've gotten the code working, but I still need to think about what the most natural algorithm would be for weighing these factors against the mysql fulltext score currently used (and works pretty well, I must say).
|
60 |
+
2. Um, something else! Let me know if you have any suggestions for improvement. ^^
|
|
|
61 |
|
62 |
== Version log ==
|
|
|
|
|
|
|
63 |
|
64 |
+
* 1.0
|
65 |
+
* Initial upload
|
66 |
+
* 1.0.1
|
67 |
+
* Bugfix: 1.0 assumed you had Markdown installed
|
68 |
+
* 1.1
|
69 |
+
* Related pages support!
|
70 |
+
* Also, uses `apply_filters` to apply whatever content text transformation you use (Wikipedia link, Markdown, etc.) before computing similarity.
|
71 |
+
* 1.5
|
72 |
+
* Simple installation: automatic display of a basic related posts install
|
73 |
+
* code and variable cleanup
|
74 |
+
* FAQ in the documentation
|
related-functions.php
ADDED
@@ -0,0 +1,35 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
<?php
|
2 |
+
|
3 |
+
// Here are the related_WHATEVER functions, as introduced in 1.1, which actually just use the yarpp_related and yarpp_related_exist functions.
|
4 |
+
|
5 |
+
function related_posts() {
|
6 |
+
$a = func_get_args();
|
7 |
+
return yarpp_related(array('post'),$a);
|
8 |
+
}
|
9 |
+
|
10 |
+
function related_pages() {
|
11 |
+
$a = func_get_args();
|
12 |
+
return yarpp_related(array('page'),$a);
|
13 |
+
}
|
14 |
+
|
15 |
+
function related_entries() {
|
16 |
+
$a = func_get_args();
|
17 |
+
return yarpp_related(array('page','post'),$a);
|
18 |
+
}
|
19 |
+
|
20 |
+
function related_posts_exist() {
|
21 |
+
$a = func_get_args();
|
22 |
+
return yarpp_related_exist(array('post'),$a);
|
23 |
+
}
|
24 |
+
|
25 |
+
function related_pages_exist() {
|
26 |
+
$a = func_get_args();
|
27 |
+
return yarpp_related_exist(array('page'),$a);
|
28 |
+
}
|
29 |
+
|
30 |
+
function related_entries_exist() {
|
31 |
+
$a = func_get_args();
|
32 |
+
return yarpp_related_exist(array('page','post'),$a);
|
33 |
+
}
|
34 |
+
|
35 |
+
?>
|
yarpp.php
CHANGED
@@ -1,345 +1,19 @@
|
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Yet Another Related Posts Plugin
|
4 |
-
Plugin URI: http://mitcho.com/code
|
5 |
Description: Returns a list of the related entries based on keyword matches, limited by a certain relatedness threshold. Like the tried and true Related Posts plugins—just better!
|
6 |
-
Version: 1.
|
7 |
-
Author:
|
8 |
*/
|
9 |
|
10 |
-
|
|
|
|
|
11 |
|
12 |
-
|
13 |
-
|
14 |
-
|
15 |
-
|
16 |
-
$indexdata = $wpdb->get_results("show index from $wpdb->posts");
|
17 |
-
foreach ($indexdata as $index) {
|
18 |
-
if ($index->Key_name == 'post_related') return 1;
|
19 |
-
}
|
20 |
-
return 0;
|
21 |
-
}
|
22 |
-
|
23 |
-
function yarpp_activate() {
|
24 |
-
global $wpdb;
|
25 |
-
add_option('cross_relate',false);
|
26 |
-
add_option('threshold',5);
|
27 |
-
add_option('limit',5);
|
28 |
-
add_option('lim',10);
|
29 |
-
add_option('show_score',true);
|
30 |
-
if (!yarpp_enabled()) {
|
31 |
-
$wpdb->query("ALTER TABLE $wpdb->posts ADD FULLTEXT `post_related` ( `post_name` , `post_content` )");
|
32 |
-
}
|
33 |
-
return 1;
|
34 |
-
}
|
35 |
-
|
36 |
-
// End setup
|
37 |
-
|
38 |
-
// Begin Related Posts
|
39 |
-
|
40 |
-
// This section was more or less completely written by
|
41 |
-
|
42 |
-
/**
|
43 |
-
* Builds a word frequency list from the Wordpress post, and returns a string
|
44 |
-
* to be used in matching against the MySQL full-text index.
|
45 |
-
*
|
46 |
-
* @param integer $num_to_ret The number of words to use when matching against
|
47 |
-
* the database.
|
48 |
-
* @return string The words
|
49 |
-
*/
|
50 |
-
function current_post_keywords($num_to_ret = 20) {
|
51 |
-
global $post;
|
52 |
-
// An array of weightings, to make adjusting them easier.
|
53 |
-
$w = array(
|
54 |
-
'title' => 2,
|
55 |
-
'name' => 2,
|
56 |
-
'content' => 1,
|
57 |
-
'cat_name' => 3
|
58 |
-
);
|
59 |
-
|
60 |
-
/*
|
61 |
-
Thanks to http://www.eatdrinksleepmovabletype.com/tutorials/building_a_weighted_keyword_list/
|
62 |
-
for the basics for this code. It saved me much typing (or thinking) :)
|
63 |
-
*/
|
64 |
-
|
65 |
-
// This needs experimenting with. I've given post title and url a double
|
66 |
-
// weighting, changing this may give you better results
|
67 |
-
$string = str_repeat($post->post_title, $w['title'].' ').
|
68 |
-
str_repeat(str_replace('-', ' ', $post->post_name).' ', $w['name']).
|
69 |
-
str_repeat(strip_tags(apply_filters('the_content',$post->post_content)), $w['content'].' ');//mitcho: strip_tags
|
70 |
-
|
71 |
-
// Cat names don't help with the current query: the category names of other
|
72 |
-
// posts aren't retrieved by the query to be matched against (and can't be
|
73 |
-
// indexed)
|
74 |
-
// But I've left this in just in case...
|
75 |
-
$post_categories = get_the_category();
|
76 |
-
foreach ($post_categories as $cat) {
|
77 |
-
$string .= str_repeat($cat->cat_name.' ', $w['cat_name']);
|
78 |
-
}
|
79 |
-
|
80 |
-
// Remove punctuation.
|
81 |
-
$wordlist = preg_split('/\s*[\s+\.|\?|,|(|)|\-+|\'|\"|=|;|×|\$|\/|:|{|}]\s*/i', strtolower($string));
|
82 |
-
|
83 |
-
// Build an array of the unique words and number of times they occur.
|
84 |
-
$a = array_count_values($wordlist);
|
85 |
-
|
86 |
-
//Remove words that don't matter--"stop words."
|
87 |
-
$overusedwords = array( '', 'a', 'an', 'the', 'and', 'of', 'i', 'to', 'is', 'in', 'with', 'for', 'as', 'that', 'on', 'at', 'this', 'my', 'was', 'our', 'it', 'you', 'we', '1', '2', '3', '4', '5', '6', '7', '8', '9', '0', '10', 'about', 'after', 'all', 'almost', 'along', 'also', 'amp', 'another', 'any', 'are', 'area', 'around', 'available', 'back', 'be', 'because', 'been', 'being', 'best', 'better', 'big', 'bit', 'both', 'but', 'by', 'c', 'came', 'can', 'capable', 'control', 'could', 'course', 'd', 'dan', 'day', 'decided', 'did', 'didn', 'different', 'div', 'do', 'doesn', 'don', 'down', 'drive', 'e', 'each', 'easily', 'easy', 'edition', 'end', 'enough', 'even', 'every', 'example', 'few', 'find', 'first', 'found', 'from', 'get', 'go', 'going', 'good', 'got', 'gt', 'had', 'hard', 'has', 'have', 'he', 'her', 'here', 'how', 'if', 'into', 'isn', 'just', 'know', 'last', 'left', 'li', 'like', 'little', 'll', 'long', 'look', 'lot', 'lt', 'm', 'made', 'make', 'many', 'mb', 'me', 'menu', 'might', 'mm', 'more', 'most', 'much', 'name', 'nbsp', 'need', 'new', 'no', 'not', 'now', 'number', 'off', 'old', 'one', 'only', 'or', 'original', 'other', 'out', 'over', 'part', 'place', 'point', 'pretty', 'probably', 'problem', 'put', 'quite', 'quot', 'r', 're', 'really', 'results', 'right', 's', 'same', 'saw', 'see', 'set', 'several', 'she', 'sherree', 'should', 'since', 'size', 'small', 'so', 'some', 'something', 'special', 'still', 'stuff', 'such', 'sure', 'system', 't', 'take', 'than', 'their', 'them', 'then', 'there', 'these', 'they', 'thing', 'things', 'think', 'those', 'though', 'through', 'time', 'today', 'together', 'too', 'took', 'two', 'up', 'us', 'use', 'used', 'using', 've', 'very', 'want', 'way', 'well', 'went', 'were', 'what', 'when', 'where', 'which', 'while', 'white', 'who', 'will', 'would', 'your');
|
88 |
-
|
89 |
-
// Remove the stop words from the list.
|
90 |
-
foreach ($overusedwords as $word) {
|
91 |
-
unset($a[$word]);
|
92 |
-
}
|
93 |
-
arsort($a, SORT_NUMERIC);
|
94 |
-
|
95 |
-
$num_words = count($a);
|
96 |
-
$num_to_ret = $num_words > $num_to_ret ? $num_to_ret : $num_words;
|
97 |
-
|
98 |
-
$outwords = array_slice($a, 0, $num_to_ret);
|
99 |
-
return implode(' ', array_keys($outwords));
|
100 |
-
|
101 |
-
}
|
102 |
-
|
103 |
-
// Here are the related_WHATEVER functions, as introduced in 1.1, which actually just use the yarpp_related and yarpp_related_exist functions.
|
104 |
-
|
105 |
-
function related_posts() {
|
106 |
-
$a = func_get_args();
|
107 |
-
return yarpp_related(array('post'),$a);
|
108 |
-
}
|
109 |
-
|
110 |
-
function related_pages() {
|
111 |
-
$a = func_get_args();
|
112 |
-
return yarpp_related(array('page'),$a);
|
113 |
-
}
|
114 |
-
|
115 |
-
function related_entries() {
|
116 |
-
$a = func_get_args();
|
117 |
-
return yarpp_related(array('page','post'),$a);
|
118 |
-
}
|
119 |
-
|
120 |
-
function related_posts_exist() {
|
121 |
-
$a = func_get_args();
|
122 |
-
return yarpp_related_exist(array('post'),$a);
|
123 |
-
}
|
124 |
-
|
125 |
-
function related_pages_exist() {
|
126 |
-
$a = func_get_args();
|
127 |
-
return yarpp_related_exist(array('page'),$a);
|
128 |
-
}
|
129 |
-
|
130 |
-
function related_entries_exist() {
|
131 |
-
$a = func_get_args();
|
132 |
-
return yarpp_related_exist(array('page','post'),$a);
|
133 |
-
}
|
134 |
-
|
135 |
-
function yarpp_related($type,$args) {
|
136 |
-
global $wpdb, $post, $user_level;
|
137 |
-
get_currentuserinfo();
|
138 |
-
|
139 |
-
// if cross_relate is set, override the type argument and make sure both matches are accepted in the sql query
|
140 |
-
if (get_option('cross_relate')) $type = array('post','page');
|
141 |
-
|
142 |
-
// Get option values from the options page--this can be overwritten: see readme
|
143 |
-
$options = array('limit','threshold','before_title','after_title','show_excerpt','len','before_post','after_post','show_pass_post','past_only','show_score');
|
144 |
-
$optvals = array();
|
145 |
-
foreach (array_keys($options) as $index) {
|
146 |
-
if (isset($args[$index+1])) {
|
147 |
-
$optvals[$options[$index]] = stripslashes($args[$index+1]);
|
148 |
-
} else {
|
149 |
-
$optvals[$options[$index]] = stripslashes(get_option($options[$index]));
|
150 |
-
}
|
151 |
-
}
|
152 |
-
extract($optvals);
|
153 |
-
|
154 |
-
// Fetch keywords
|
155 |
-
$terms = current_post_keywords();
|
156 |
-
|
157 |
-
// Make sure the post is not from the future
|
158 |
-
$time_difference = get_settings('gmt_offset');
|
159 |
-
$now = gmdate("Y-m-d H:i:s",(time()+($time_difference*3600)));
|
160 |
-
|
161 |
-
// Primary SQL query
|
162 |
-
|
163 |
-
$sql = "SELECT ID, post_title, post_content,"
|
164 |
-
. "MATCH (post_name, post_content) "
|
165 |
-
. "AGAINST ('$terms') AS score "
|
166 |
-
. "FROM $wpdb->posts WHERE "
|
167 |
-
. "post_type IN ('".implode("', '",$type)."') "
|
168 |
-
. "AND MATCH (post_name, post_content) AGAINST ('$terms') >= $threshold "
|
169 |
-
. "AND (post_status IN ( 'publish', 'static' ) && ID != '$post->ID') ";
|
170 |
-
if (past_only) { $sql .= "AND post_date <= '$now' "; }
|
171 |
-
if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
|
172 |
-
$sql .= "ORDER BY score DESC LIMIT $limit";
|
173 |
-
$results = $wpdb->get_results($sql);
|
174 |
-
$output = '';
|
175 |
-
if ($results) {
|
176 |
-
foreach ($results as $result) {
|
177 |
-
$title = stripslashes(apply_filters('the_title', $result->post_title));
|
178 |
-
$permalink = get_permalink($result->ID);
|
179 |
-
$post_content = strip_tags($result->post_content);
|
180 |
-
$post_content = stripslashes($post_content);
|
181 |
-
$output .= $before_title .'<a href="'. $permalink .'" rel="bookmark" title="Permanent Link: ' . $title . '">' . $title . (($show_score and $user_level >= 8)? ' ('.round($result->score,3).')':'') . '</a>' . $after_title;
|
182 |
-
if ($show_excerpt=='true') {
|
183 |
-
$ze = substr($post_content, 0, $len);
|
184 |
-
$ze = substr($ze, 0, strrpos($ze,''));
|
185 |
-
$ze = $ze . '...';
|
186 |
-
$output .= $before_post . $ze . $after_post;
|
187 |
-
}
|
188 |
-
}
|
189 |
-
echo $output;
|
190 |
-
} else {
|
191 |
-
echo $before_title.'No related posts'.$after_title;
|
192 |
-
}
|
193 |
-
}
|
194 |
-
|
195 |
-
function yarpp_related_exist($type,$args) {
|
196 |
-
global $wpdb, $post;
|
197 |
-
|
198 |
-
if (get_option('cross_relate')) $type = array('post','page');
|
199 |
-
|
200 |
-
$options = array('threshold','show_pass_post','past_only');
|
201 |
-
$optvals = array();
|
202 |
-
foreach (array_keys($options) as $index) {
|
203 |
-
if (isset($args[$index+1])) {
|
204 |
-
$optvals[$options[$index]] = stripslashes($args[$index+1]);
|
205 |
-
} else {
|
206 |
-
$optvals[$options[$index]] = stripslashes(get_option($options[$index]));
|
207 |
-
}
|
208 |
-
}
|
209 |
-
extract($optvals);
|
210 |
-
|
211 |
-
$terms = current_post_keywords();
|
212 |
-
|
213 |
-
$time_difference = get_settings('gmt_offset');
|
214 |
-
$now = gmdate("Y-m-d H:i:s",(time()+($time_difference*3600)));
|
215 |
-
|
216 |
-
$sql = "SELECT COUNT(*) as count "
|
217 |
-
. "FROM $wpdb->posts WHERE "
|
218 |
-
. "post_type IN ('".implode("', '",$type)."') "
|
219 |
-
. "AND MATCH (post_name, post_content) AGAINST ('$terms') >= $threshold "
|
220 |
-
. "AND (post_status IN ( 'publish', 'static' ) && ID != '$post->ID') ";
|
221 |
-
if (past_only) { $sql .= "AND post_date <= '$now' "; }
|
222 |
-
if ($show_pass_post=='false') { $sql .= "AND post_password ='' "; }
|
223 |
-
|
224 |
-
$result = $wpdb->get_var($sql);
|
225 |
-
return $result > 0 ? true: false;
|
226 |
-
}
|
227 |
-
|
228 |
-
// End Related Posts
|
229 |
-
|
230 |
-
// Begin Related Posts Options
|
231 |
-
|
232 |
-
function yarpp_subpanel() {
|
233 |
-
global $yarpp_version;
|
234 |
-
if (!yarpp_enabled()) {
|
235 |
-
echo '<div class="updated">';
|
236 |
-
if (yarpp_activate()) echo 'The YARPP database had an error but has been fixed.';
|
237 |
-
echo '</div>';
|
238 |
-
}
|
239 |
-
|
240 |
-
if (isset($_POST['update_yarpp'])) {
|
241 |
-
$valueoptions = array('limit','threshold','len','before_title','after_title','before_post','after_post');
|
242 |
-
foreach ($valueoptions as $option) {
|
243 |
-
update_option($option,$_POST[$option]);
|
244 |
-
}
|
245 |
-
$checkoptions = array('past_only','show_score','show_excerpt','show_pass_post','cross_relate');
|
246 |
-
foreach ($checkoptions as $option) {
|
247 |
-
(isset($_POST[$option])) ? update_option($option,true) : update_option($option,false);
|
248 |
-
}
|
249 |
-
?> <div class="updated">Options saved!</div><?php
|
250 |
-
}
|
251 |
-
|
252 |
-
function checkbox($option,$desc,$tr="<tr>
|
253 |
-
<td colspan='2'>",$inputplus = '') {
|
254 |
-
echo " $tr<label for='$option'>$desc</label></td>
|
255 |
-
<td>
|
256 |
-
<input $inputplus type='checkbox' name='$option' value='true'". ((get_option($option)) ? ' checked="checked"': '' )." />
|
257 |
-
</td>
|
258 |
-
</tr>";
|
259 |
-
}
|
260 |
-
function textbox($option,$desc,$size=2,$tr="<tr>
|
261 |
-
<td colspan='2'>") {
|
262 |
-
echo " $tr<label for='$option'>$desc</label></td>
|
263 |
-
<td><input name='$option' type='text' id='$option' value='".htmlspecialchars(stripslashes(get_option($option)))."' size='$size' /></td>
|
264 |
-
</tr>";
|
265 |
-
}
|
266 |
-
|
267 |
-
if (get_option('threshold') == '') update_option('threshold',5);
|
268 |
-
if (get_option('length') == '') update_option('length',5);
|
269 |
-
if (get_option('len') == '') update_option('len',10);
|
270 |
-
if (get_option('cross_relate') == '') update_option('cross_relate',false);
|
271 |
-
?>
|
272 |
-
|
273 |
-
<div class="wrap">
|
274 |
-
<h2>Yet Another Related Posts Plugin Options <small><?php echo $yarpp_version; ?></small></h2>
|
275 |
-
<p><small>by <a href="http://mitcho.com/code/">mitcho (Michael 芳貴 Erlewine)</a> and based on the fabulous work of <a href="http://peter.mapledesign.co.uk/weblog/archives/wordpress-related-posts-plugin">Peter Bower</a>, <a href="http://wasabi.pbwiki.com/Related%20Entries">Alexander Malov & Mike Lu</a>. If you appreciate this plugin, please consider <a href="https://www.paypal.com/cgi-bin/webscr?cmd=_xclick&business=mitcho%40mitcho%2ecom&item_name=mitcho%2ecom%2fcode%3a%20donate%20to%20Michael%20Yoshitaka%20Erlewine&no_shipping=0&no_note=1&tax=0¤cy_code=USD&lc=US&bn=PP%2dDonationsBF&charset=UTF%2d8">donating to the author, mitcho</a>.</small></p>
|
276 |
-
<form method="post">
|
277 |
-
<fieldset class="options">
|
278 |
-
<h3>"Relatedness" options</h3>
|
279 |
-
<p>YARPP is different than the <a href="http://wasabi.pbwiki.com/Related%20Entries">previous plugins it is based on</a> as it limits the related posts list by (1) a maximum number and (2) a <em>match threshold</em>. <a href="#" onclick="javascript:document.getElementById('yarpp_match_explanation').style.display = 'inline';this.style.display='none'" id="yarpp_match_explanation_trigger">Tell me more.</a></p>
|
280 |
-
|
281 |
-
<p id="yarpp_match_explanation" style="display:none;">The higher the match threshold, the more restrictive, and you get less related posts overall. The default match threshold is 5. If you want to find an appropriate match threshhold, I recommend you turn on the "show admins the match scores" setting below. That way, you can see what kinds of related posts are being picked up and with what kind of match scores, and determine an appropriate threshold for your site. <a href="#" onclick="javascript:document.getElementById('yarpp_match_explanation_trigger').style.display = 'inline';this.parentNode.style.display='none'" id="yarpp_match_explanation_trigger">Tell me less now.</a></p>
|
282 |
-
|
283 |
-
<table>
|
284 |
-
<?php textbox('limit','Maximum number of related posts:')?>
|
285 |
-
<?php textbox('threshold','Match threshold:')?>
|
286 |
-
<?php checkbox('cross_relate',"Cross-relate posts and pages? <a href='#' onclick=\"javascript:document.getElementById('yarpp_cross_relate_explanation').style.display = 'table-row';this.style.display='none'\" id='yarpp_cross_relate_explanation_trigger'>Tell me more.</a>"); ?>
|
287 |
-
<tr id="yarpp_cross_relate_explanation" style="display:none;"><td style='background-color: gray; width: 3px;'> </td><td colspan = '2'>When the "Cross-relate posts and pages" option is selected, the <code>related_posts()</code>, <code>related_pagaes()</code>, and <code>related_entries()</code> all will give the same output, returning both related pages and posts. <a href="#" onclick="javascript:document.getElementById('yarpp_cross_relate_explanation_trigger').style.display = 'inline';this.parentNode.parentNode.style.display='none'" id="yarpp_cross_relate_explanation_trigger">Tell me less now.</a></td></tr>
|
288 |
-
</table>
|
289 |
-
<h3>Display options</h3>
|
290 |
-
<table>
|
291 |
-
<tr>
|
292 |
-
<td colspan='2'><label for="before_title">Before</label> / <label for="after_title">After (Post Title) </label>:</td>
|
293 |
-
<td><input name="before_title" type="text" id="before_title" value="<?php echo htmlspecialchars(stripslashes(get_option('before_title'))); ?>" size="10" /> / <input name="after_title" type="text" id="after_title" value="<?php echo htmlspecialchars(stripslashes(get_option('after_title'))); ?>" size="10" /><em><small> For example: <li></li> or <dl></dl></small></em>
|
294 |
-
</td>
|
295 |
-
</tr>
|
296 |
-
<?php checkbox('show_excerpt',"Show excerpt?","<tr>
|
297 |
-
<td colspan='2'>",' onclick="javascript:excerpt()"'); ?>
|
298 |
-
<?php textbox('len','Excerpt length (No. of words):',null,"<tr name='excerpted'>
|
299 |
-
<td style='background-color: gray; width: .3px;'> </td><td>")?>
|
300 |
-
|
301 |
-
<tr name="excerpted">
|
302 |
-
<td style='background-color: gray; width: 3px;'> </td><td><label for="before_post">Before</label> / <label for="after_post">After</label> (Excerpt):</td>
|
303 |
-
<td><input name="before_post" type="text" id="before_post" value="<?php echo htmlspecialchars(stripslashes(get_option('before_post'))); ?>" size="10" /> / <input name="after_post" type="text" id="after_post" value="<?php echo htmlspecialchars(stripslashes(get_option('after_post'))); ?>" size="10" /><em><small> For example: <li></li> or <dl></dl></small></em>
|
304 |
-
</td>
|
305 |
-
</tr>
|
306 |
-
|
307 |
-
<?php checkbox('show_past_post',"Show password protected posts?"); ?>
|
308 |
-
<?php checkbox('past_only',"Show only previous posts?"); ?>
|
309 |
-
<?php checkbox('show_score',"Show admins (user level > 8) the match scores?"); ?>
|
310 |
-
</table>
|
311 |
-
</fieldset>
|
312 |
-
|
313 |
-
<div class="submit"><input type="submit" name="update_yarpp" value="<?php _e('Save!', 'update_yarpp') ?>" style="font-weight:bold;" /></div>
|
314 |
-
|
315 |
-
</form>
|
316 |
-
|
317 |
-
</div>
|
318 |
-
<script language="javascript">
|
319 |
-
function excerpt() {
|
320 |
-
if (!document.getElementsByName('show_excerpt')[0].checked) {
|
321 |
-
document.getElementsByName('excerpted')[0].style.display = 'none';
|
322 |
-
document.getElementsByName('excerpted')[1].style.display = 'none';
|
323 |
-
} else {
|
324 |
-
document.getElementsByName('excerpted')[0].style.display = 'table-row';
|
325 |
-
document.getElementsByName('excerpted')[1].style.display = 'table-row';
|
326 |
-
}
|
327 |
-
}
|
328 |
-
excerpt();
|
329 |
-
</script>
|
330 |
-
|
331 |
-
<?php }
|
332 |
-
|
333 |
-
// End Related Posts Options
|
334 |
-
|
335 |
-
function yarpp_admin_menu() {
|
336 |
-
if (function_exists('add_submenu_page')) {
|
337 |
-
add_submenu_page('plugins.php', __('Related Posts (YARPP) Options'), __('Related Posts (YARPP) Options'), 1, __FILE__, 'yarpp_subpanel');
|
338 |
-
}
|
339 |
-
}
|
340 |
-
|
341 |
-
// add_action('publish_post', 'find_keywords', 1);
|
342 |
-
add_action('admin_menu', 'yarpp_admin_menu');
|
343 |
-
register_activation_hook(__FILE__,'yarpp_activate' );
|
344 |
|
345 |
?>
|
1 |
<?php
|
2 |
/*
|
3 |
Plugin Name: Yet Another Related Posts Plugin
|
4 |
+
Plugin URI: http://mitcho.com/code/yarpp/
|
5 |
Description: Returns a list of the related entries based on keyword matches, limited by a certain relatedness threshold. Like the tried and true Related Posts plugins—just better!
|
6 |
+
Version: 1.5
|
7 |
+
Author: mitcho (Michael Yoshitaka Erlewine)
|
8 |
*/
|
9 |
|
10 |
+
require_once('includes.php');
|
11 |
+
require_once('magic.php');
|
12 |
+
require_once('related-functions.php');
|
13 |
|
14 |
+
add_action('admin_head','yarpp_admin_menu');
|
15 |
+
add_action('admin_print_scripts','yarpp_upgrade_check');
|
16 |
+
add_filter('the_content','yarpp_default');
|
17 |
+
register_activation_hook(__FILE__,'yarpp_activate');
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
18 |
|
19 |
?>
|