Instantly share code, notes, and snippets.
Last active
January 4, 2016 03:49
-
Star
(1)
1
You must be signed in to star a gist -
Fork
(0)
0
You must be signed in to fork a gist
-
Save freekrai/8564097 to your computer and use it in GitHub Desktop.
Related Posts without a plugin.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<?php | |
class rs_related{ | |
private $stopwords = array(); | |
private $debug = false; | |
private $weight = array( | |
'body'=>1, | |
'title'=>2, | |
'tax'=>4, | |
); | |
public function __construct(){ | |
global $wpdb; | |
// we've already set up the FULLTEXT keys... | |
if ( !get_option('related_already') ){ | |
$wpdb->query("ALTER TABLE $wpdb->posts ADD FULLTEXT `related_text` (`post_title`,`post_content`)"); | |
$wpdb->query("ALTER TABLE $wpdb->posts ADD FULLTEXT `related_title` (`post_title`)"); | |
$wpdb->query("ALTER TABLE $wpdb->posts ADD FULLTEXT `related_content` (`post_content`)"); | |
add_option('related_already', 1); | |
} | |
$this->stopwords = $this->slugs_stop_words(); | |
} | |
/** | |
* Fetch related posts as an array. | |
* | |
* @access public | |
* @param int $postid (default: FALSE) The post ID for which you want the posts for | |
* @param int $limit (default: FALSE) Maximum posts to retreive | |
* @param boolean $strict_limit (default: TRUE) Setting to true will fetch exactly as per limit above | |
* @param boolean $weight (default: array) array to set weights for title,body and category | |
* @return array Array of Post IDs | |
*/ | |
public function get_related($postid = FALSE, $limit = FALSE, $strict_limit = TRUE, $weight = '') { | |
global $wpdb, $post, $single; | |
$post = (empty($postid)) ? get_post($postid) : $post; | |
if (empty($limit)) $limit = 5; | |
$limit = ($strict_limit) ? $limit : ($limit*3); | |
// if weight was passed... | |
if( $weight != '' && is_array($weight) ){ | |
foreach($weight as $k => $v ){ | |
$this->weight[$k] = $v; | |
} | |
} | |
$sql = $this->sql($postid,$limit,4, false, false, "12 month"); | |
$transient_label = md5($sql); | |
// return cached results if already stored and not expired... | |
if ( false === ( $results = get_transient($transient_label) ) ) { | |
$results = $wpdb->get_results( $sql ); | |
set_transient( $transient_label, $results, DAY_IN_SECONDS ); | |
} | |
return $results; | |
} | |
/** | |
* Build SQL query for related posts and return SQL statement... | |
* @access private | |
* @param int $reference_ID | |
* @param int $limit | |
* @param int $threshold | |
* @param bool $past_only | |
* @param bool $show_pass_post | |
* @param text $recent | |
*/ | |
private function sql($reference_ID,$limit = 5,$threshold = 4,$past_only = false,$show_pass_post = false,$recent = 0){ | |
global $wpdb, $post, $single; | |
$post = (empty($reference_ID)) ? get_post($reference_ID) : $post; | |
$weight = $this->weight; | |
$keywords = array( | |
'body'=>implode(' ', $this->get_keywords( $this->excerpt($post->ID,0,true) ) ), | |
'title'=>implode(' ', $this->get_keywords( $post->post_title ) ), | |
); | |
// SELECT | |
$newsql = "SELECT $reference_ID as reference_ID, ID, "; | |
$newsql .= 'ROUND(0'; | |
$newsql .= " + (MATCH (post_content) AGAINST ('".esc_sql($keywords['body'])."')) * ".absint($weight['body']); | |
$newsql .= " + (MATCH (post_title) AGAINST ('".esc_sql($keywords['title'])."')) * ".absint($weight['title']); | |
// Build tax criteria query parts based on the weights | |
// categories: | |
$newsql .= " + ".$this->tax_criteria($reference_ID, 'category')." * ".intval($weight['tax']); | |
// post tags: | |
$newsql .= " + ".$this->tax_criteria($reference_ID, 'post_tag')." * ".intval($weight['tax']); | |
$newsql .= ',1) as score'; | |
$newsql .= "\n from $wpdb->posts \n"; | |
$newsql .= "left join $wpdb->term_relationships as terms on ( terms.object_id = $wpdb->posts.ID ) \n"; | |
$newsql .= " where post_status in ( 'publish', 'static' ) and ID != '$reference_ID'"; | |
if ($past_only) $newsql .= " and post_date <= '$reference_post->post_date' "; | |
if (!$show_pass_post) $newsql .= " and post_password ='' "; | |
if ((bool) $recent) $newsql .= " and post_date > date_sub(now(), interval {$recent}) "; | |
$newsql .= " and post_type = 'post'"; | |
$newsql .= "\n group by ID \n"; | |
$safethreshold = number_format(max($threshold,0.1), 2, '.', ''); | |
$newsql .= " having score >= $safethreshold and ID != 0"; | |
$newsql .= " order by score desc limit $limit"; | |
$sql = $newsql; | |
if ($this->debug) echo "<!-- $sql -->"; | |
return $sql; | |
} | |
function excerpt($id,$excerpt_length=0,$use_excerpt = true) { | |
$content = $excerpt = ''; | |
if ($use_excerpt) $content = get_post($id)->post_excerpt; | |
if (''==$content) $content = get_post($id)->post_content; | |
$output = strip_tags(strip_shortcodes($content)); | |
if ($excerpt_length>0) { | |
$output = wp_trim_words($output,$excerpt_length); | |
} | |
return $output; | |
} | |
/** | |
* Get keywords from a string of text | |
* | |
* @param string $text String of text to pull keywords from | |
* @param int $word_count Maximum number of words to pull | |
* @return array $keywords The keywords we've found | |
*/ | |
public function get_keywords( $text, $word_count = 5 ) { | |
$keywords = array(); | |
$word_count = min( max( 1, intval($word_count) ), 100 ); | |
$text = strip_tags( $text ); | |
foreach( (array)explode( ' ', $text ) as $word ) { | |
// Strip characters we don't want | |
$word = trim( $word, '?.;,"' ); | |
if ( in_array( $word, $this->stopwords ) ) continue; | |
$keywords[] = $word; | |
if ( count( $keywords ) == $word_count ) break; | |
} | |
return $keywords; | |
} | |
private function tax_criteria($reference_ID, $taxonomy) { | |
$terms = get_the_terms($reference_ID, $taxonomy); | |
// if there are no terms of that tax | |
if (false === $terms) return '(1 = 0)'; | |
$tt_ids = wp_list_pluck($terms, 'term_taxonomy_id'); | |
return "count(distinct if( terms.term_taxonomy_id in (".join(',',$tt_ids)."), terms.term_taxonomy_id, null ))"; | |
} | |
function slugs_stop_words() { | |
return array ("a", "ice", "able", "teaspoon","taste","about", "above", "abroad", "according", "accordingly", "across", "actually", "adj", "after", "afterwards", "again", "against", "ago", "ahead", "ain't", "all", "allow", "allows", "almost", "alone", "along", "alongside", "already", "also", "although", "always", "am", "amid", "amidst", "among", "amongst", "an", "and", "another", "any", "anybody", "anyhow", "anyone", "anything", "anyway", "anyways", "anywhere", "apart", "appear", "appreciate", "appropriate", "are", "aren't", "around", "as", "a's", "aside", "ask", "asking", "associated", "at", "available", "away", "awfully", "b", "back", "backward", "backwards", "be", "became", "because", "become", "becomes", "becoming", "been", "before", "beforehand", "begin", "behind", "being", "believe", "below", "beside", "besides", "best", "better", "between", "beyond", "both", "brief", "but", "by", "c", "came", "can", "cannot", "cant", "can't", "caption", "cause", "causes", "certain", "certainly", "changes", "clearly", "c'mon", "co", "co.", "com", "come", "comes", "concerning", "consequently", "consider", "considering", "contain", "containing", "contains", "corresponding", "could", "couldn't", "course", "c's", "currently", "d", "dare", "daren't", "definitely", "described", "despite", "did", "didn't", "different", "directly", "do", "does", "doesn't", "doing", "done", "don't", "down", "downwards", "during", "e", "each", "edu", "eg", "eight", "eighty", "either", "else", "elsewhere", "end", "ending", "enough", "entirely", "especially", "et", "etc", "even", "ever", "evermore", "every", "everybody", "everyone", "everything", "everywhere", "ex", "exactly", "example", "except", "f", "fairly", "far", "farther", "few", "fewer", "fifth", "first", "five", "followed", "following", "follows", "for", "forever", "former", "formerly", "forth", "forward", "found", "four", "from", "further", "furthermore", "g", "get", "gets", "getting", "given", "gives", "go", "goes", "going", "gone", "got", "gotten", "greetings", "h", "had", "hadn't", "half", "happens", "hardly", "has", "hasn't", "have", "haven't", "having", "he", "he'd", "he'll", "hello", "help", "hence", "her", "here", "hereafter", "hereby", "herein", "here's", "hereupon", "hers", "herself", "he's", "hi", "him", "himself", "his", "hither", "hopefully", "how", "howbeit", "however", "hundred", "i", "i'd", "ie", "if", "ignored", "i'll", "i'm", "immediate", "in", "inasmuch", "inc", "inc.", "indeed", "indicate", "indicated", "indicates", "inner", "inside", "insofar", "instead", "into", "inward", "is", "isn't", "it", "it'd", "it'll", "its", "it's", "itself", "i've", "j", "just", "k", "keep", "keeps", "kept", "know", "known", "knows", "l", "last", "lately", "later", "latter", "latterly", "least", "less", "lest", "let", "let's", "like", "liked", "likely", "likewise", "little", "look", "looking", "looks", "low", "lower", "ltd", "m", "made", "mainly", "make", "makes", "many", "may", "maybe", "mayn't", "me", "mean", "meantime", "meanwhile", "merely", "might", "mightn't", "mine", "minus", "miss", "more", "moreover", "most", "mostly", "mr", "mrs", "much", "must", "mustn't", "my", "myself", "n", "name", "namely", "nd", "near", "nearly", "necessary", "need", "needn't", "needs", "neither", "never", "neverf", "neverless", "nevertheless", "new", "next", "nine", "ninety", "no", "nobody", "non", "none", "nonetheless", "noone", "no-one", "nor", "normally", "not", "nothing", "notwithstanding", "novel", "now", "nowhere", "o", "obviously", "of", "off", "often", "oh", "ok", "okay", "old", "on", "once", "one", "ones", "one's", "only", "onto", "opposite", "or", "other", "others", "otherwise", "ought", "oughtn't", "our", "ours", "ourselves", "out", "outside", "over", "overall", "own", "p", "particular", "particularly", "past", "per", "perhaps", "placed", "please", "plus", "possible", "presumably", "probably", "provided", "provides", "q", "que", "quite", "qv", "r", "rather", "rd", "re", "really", "reasonably", "recent", "recently", "regarding", "regardless", "regards", "relatively", "respectively", "right", "round", "s", "said", "same", "saw", "say", "saying", "says", "second", "secondly", "see", "seeing", "seem", "seemed", "seeming", "seems", "seen", "self", "selves", "sensible", "sent", "serious", "seriously", "seven", "several", "shall", "shan't", "she", "she'd", "she'll", "she's", "should", "shouldn't", "since", "six", "so", "some", "somebody", "someday", "somehow", "someone", "something", "sometime", "sometimes", "somewhat", "somewhere", "soon", "sorry", "specified", "specify", "specifying", "still", "sub", "such", "sup", "sure", "t", "take", "taken", "taking", "tell", "tends", "th", "than", "thank", "thanks", "thanx", "that", "that'll", "thats", "that's", "that've", "the", "their", "theirs", "them", "themselves", "then", "thence", "there", "thereafter", "thereby", "there'd", "therefore", "therein", "there'll", "there're", "theres", "there's", "thereupon", "there've", "these", "they", "they'd", "they'll", "they're", "they've", "thing", "things", "think", "third", "thirty", "this", "thorough", "thoroughly", "those", "though", "three", "through", "throughout", "thru", "thus", "till", "to", "together", "too", "took", "toward", "towards", "tried", "tries", "truly", "try", "trying", "t's", "twice", "two", "u", "un", "under", "underneath", "undoing", "unfortunately", "unless", "unlike", "unlikely", "until", "unto", "up", "upon", "upwards", "us", "use", "used", "useful", "uses", "using", "usually", "v", "value", "various", "versus", "very", "via", "viz", "vs", "w", "want", "wants", "was", "wasn't", "way", "we", "we'd", "welcome", "well", "we'll", "went", "were", "we're", "weren't", "we've", "what", "whatever", "what'll", "what's", "what've", "when", "whence", "whenever", "where", "whereafter", "whereas", "whereby", "wherein", "where's", "whereupon", "wherever", "whether", "which", "whichever", "while", "whilst", "whither", "who", "who'd", "whoever", "whole", "who'll", "whom", "whomever", "who's", "whose", "why", "will", "willing", "wish", "with", "within", "without", "wonder", "won't", "would", "wouldn't", "x", "y", "yes", "yet", "you", "you'd", "you'll", "your", "you're", "yours", "yourself", "yourselves", "you've", "z", "zero"); | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
got it...line 99, add "OR post_type = [CPT name]". Sorry to bother!