_hook = 'efficientRelatedPosts'; $this->_file = plugin_basename( __FILE__ ); $this->_pageTitle = __( 'Efficient Related Posts', $this->_slug ); $this->_menuTitle = __( 'Related Posts', $this->_slug ); $this->_accessLevel = 'manage_options'; $this->_optionGroup = 'erp-options'; $this->_optionNames = array('erp'); $this->_optionCallbacks = array(); $this->_slug = 'efficient-related-posts'; $this->_paypalButtonId = '9996714'; /** * Add filters and actions */ add_action( 'save_post', array( $this, 'processPost' ) ); add_action( 'admin_init', array( $this, 'processPosts' ) ); add_action( 'permalink_structure_changed', array( $this, 'fixPermalinks' ) ); add_shortcode('relatedPosts', array($this, 'handleShortcodes')); register_activation_hook( __FILE__, array( $this, 'activate' ) ); add_filter( $this->_slug .'-opt-erp', array( $this, 'filterSettings' ) ); add_action( 'erp-show-related-posts', array( $this, 'relatedPosts' ) ); add_filter( 'erp-get-related-posts', array( $this, 'getRelatedPosts' ) ); } protected function _postSettingsInit() { if ( $this->_settings['erp']['auto_insert'] != 'no' ) { add_filter('the_content', array( $this, 'filterPostContent'), 99); } if ( $this->_settings['erp']['rss'] == 'yes' ) { add_filter('the_content', array( $this, 'filterPostContentRSS'), 1); } } public function addOptionsMetaBoxes() { add_meta_box( $this->_slug . '-general-settings', __('General Settings', $this->_slug), array($this, 'generalSettingsMetaBox'), 'xavisys-' . $this->_slug, 'main'); add_meta_box( $this->_slug . '-process-posts', __('Build Relations', $this->_slug), array($this, 'processPostsMetaBox'), 'xavisys-' . $this->_slug, 'main-2'); if (get_option('erp-processedPosts')) { add_meta_box( $this->_slug . '-continue-processing-posts', __('Continue Processing Posts/Pages', $this->_slug), array($this, 'continueProcessingPostsMetaBox'), 'xavisys-' . $this->_slug, 'main-2'); } } public function processPostsMetaBox() { ?>

_slug); ?>

_slug); ?>

_slug) ?>

    _settings['erp']['ignore_cats'], array(), $erpWalker); ?>
_slug); ?>
_slug); ?>
_slug);?> _settings['erp']['auto_insert']) ?>>
_settings['erp']['auto_insert']) ?>>
_settings['erp']['auto_insert']) ?>>
_settings['erp']['auto_insert']) ?>>
_settings['erp']['auto_insert']) ?>>

_settings['erp']['rss']) ?>>
processAllPosts($_POST['erp']); $timeend = explode(' ',microtime()); $timeend = $timeend[1] + $timeend[0]; $timetotal = $timeend-$timestart; $r = ( function_exists('number_format_i18n') ) ? number_format_i18n($timetotal, 1) : number_format($timetotal, 1); $notice = sprintf(_n( 'Processed %d post.', 'Processed %d posts.', count($processed)), count($processed) ); $notice .= '
'; $notice .= sprintf(_n( 'Process took %s second.', 'Process took %s seconds.', $r), $r); $notice = str_replace( "'", "\'", "

$notice

" ); add_action('admin_notices', create_function( '', "echo '$notice';" ) ); } } public function filterPostContent($content) { // We don't want to filter if this is a feed or if settings tell us not to if ( ( $this->_settings['erp']['auto_insert'] == 'all' || ( $this->_settings['erp']['auto_insert'] == 'posts' && !is_page() ) || ( $this->_settings['erp']['auto_insert'] == 'single-all' && is_singular() && !is_attachment() && !is_home() ) || ( $this->_settings['erp']['auto_insert'] == 'single' && is_single() ) ) && !is_feed() ) { $content .= $this->getRelatedPosts(); } return $content; } public function filterPostContentRSS($content) { if ( $this->_settings['erp']['rss'] == 'yes' && is_feed() ) { $content .= $this->getRelatedPosts(); } return $content; } /** * @param [optional]$args Array of arguments containing any of the following: * [num_to_display] - Number of Posts to display * [no_rp_text] - Text to display if there are no related posts * [title] - Title for related posts list, empty for none */ public function getRelatedPosts( $args = array() ) { global $post; $output = ''; $settings = wp_parse_args($args, $this->_settings['erp']); $relatedPosts = get_post_meta($post->ID, '_efficient_related_posts', true); if ( empty($relatedPosts) || $settings['num_to_display'] == 0 ){ /** * @todo The before and after setting should apply to this too */ $output .= "
  • {$settings['no_rp_text']}
  • "; } else { $relatedPosts = array_slice($relatedPosts, 0, $settings['num_to_display']); foreach ( $relatedPosts as $p ) { /** * Handle IDs for backwards compat */ if ( ctype_digit($p) ) { $related_post = get_post($p); $p = array( 'ID' => $related_post->ID, 'post_title' => $related_post->post_title, 'permalink' => get_permalink($related_post->ID), 'post_thumbnail' => $related_post->post_thumbnail ); } $link = "".wptexturize($p['post_title']).''; if($p['post_thumbnail'] != ''){ $link = "" . $p['post_thumbnail'] . '' . $link; } /** * @todo Make a before and after setting for this */ $output .= "
  • {$link}
  • "; } } /** * @todo Make a before and after setting for this */ $output = ""; if ( !empty($settings['title']) ) { $output = "

    {$settings['title']}

    {$output}"; } return $output; } /** * @param [optional]$args See efficientRelatedPosts::getRelatedPosts */ public function relatedPosts( $args = array() ) { echo $this->getRelatedPosts($args); } private function _getPostIDs(&$p, $key) { $p = absint($p['ID']); } private function _findRelations($post, $processRelated = false, $postIds = null) { // Try to increase the time limit set_time_limit(60); global $wpdb; $now = current_time('mysql', 1); $post = get_post($post); $tags = wp_get_post_tags($post->ID); if ( !empty($tags) ) { $tagList = array(); foreach ( $tags as $t ) { $tagList[] = $t->term_id; } $tagList = implode(',', $tagList); if ( !empty($postIds) ) { // Make sure each element is an integer and filter out any 0s array_walk($postIds, array($this, '_getPostIDs')); $postIds = array_diff(array_unique((array) $postIds), array('','0')); } if ( !empty($postIds) ) { // If it's still not empty, make a SQL WHERE clause $postIds = 'p.ID IN (' . implode(',', $postIds) . ') AND'; } else { // If it's empty, make sure it's a string so we don't get notices $postIds = ''; } $q = <<term_taxonomy} t_t, {$wpdb->term_relationships} t_r, {$wpdb->posts} p WHERE {$postIds} t_t.taxonomy ='post_tag' AND t_t.term_taxonomy_id = t_r.term_taxonomy_id AND t_r.object_id = p.ID AND (t_t.term_id IN ({$tagList})) AND p.ID != {$post->ID} AND p.post_status = 'publish' AND p.post_date_gmt < '{$now}' GROUP BY t_r.object_id ORDER BY matches DESC, p.post_date_gmt DESC QUERY; $related_posts = $wpdb->get_results($q); $allRelatedPosts = array(); $relatedPostsToStore = array(); $threshold = ''; if ($related_posts) { foreach ($related_posts as $related_post ){ $overlap = array_intersect(wp_get_post_categories($related_post->ID), $this->_settings['erp']['ignore_cats']); $allRelatedPosts[] = $related_post; if ( empty($overlap) && count($relatedPostsToStore) < $this->_settings['erp']['max_relations_stored'] ) { $threshold = $related_post->matches; //unset($related_post->matches); $related_post->permalink = get_permalink($related_post->ID); if ( function_exists('get_the_post_thumbnail') ) { $related_post->post_thumbnail = get_the_post_thumbnail($related_post->ID); } $relatedPostsToStore[] = (array)$related_post; } } } if (!add_post_meta($post->ID, '_efficient_related_posts', $relatedPostsToStore, true)) { update_post_meta($post->ID, '_efficient_related_posts', $relatedPostsToStore); } /** * The threshold is the lowest number of matches in the related posts * that we store. We use this to see if we need to process an old post. */ if (!add_post_meta($post->ID, '_relation_threshold', $threshold, true)) { update_post_meta($post->ID, '_relation_threshold', $threshold); } if ($processRelated) { foreach ( $allRelatedPosts as $p ) { $threshold = get_post_meta($p->ID, '_relation_threshold', true); if ( empty($threshold) || $threshold <= $p->matches ) { // Get the current related posts $relatedPosts = get_post_meta($p->ID, '_efficient_related_posts', true); $relatedPosts[] = array('ID'=>$post->ID,'post_title'=>$post->post_title); // Find the relations, but limit the posts that are checked to save memory/time $this->_findRelations( $p->ID, false, $relatedPosts ); } } } } } public function processPost( $a ) { $a = get_post( $a ); // Don't Process revisions if ( $a->post_type == 'revision' ) { return; } $this->_findRelations( $a, true ); } public function processAllPosts( $args = array() ) { //set_time_limit(600); global $wpdb; $defaults = array( 'drafts' => false, 'pending' => false, 'scheduled' => false, 'continue' => false ); $args = wp_parse_args((array) $args, $defaults); $statuses = array('publish'); if ( $args['drafts'] == 'true' ) { $statuses[] = 'draft'; } if ( $args['scheduled'] == 'true' ) { $statuses[] = 'future'; } if ( $args['pending'] == 'true' ) { $statuses[] = 'pending'; } $q = "SELECT `ID` FROM `{$wpdb->posts}` WHERE `post_status` IN ('%s')"; if ( $args['continue'] ) { $this->_processedPosts = get_option('erp-processedPosts'); if ( !empty($this->_processedPosts) && is_array($this->_processedPosts) ) { $q .= ' && `ID` NOT IN (' . implode(',', $this->_processedPosts) . ')'; } else { $this->_processedPosts = array(); } } $q = sprintf( $q, implode("','", $statuses)); $postIDs = $wpdb->get_col( $q ); foreach ($postIDs as $pid) { $this->_findRelations( $pid ); $this->_processedPosts[] = $pid; update_option('erp-processedPosts', $this->_processedPosts); if (memory_get_usage() >= .8 * get_memory_limit()) { break; } } delete_option('erp-processedPosts'); return $postIDs; } public function fixPermalinks(){ global $wpdb; $query = <<postmeta}` WHERE `meta_key`='_efficient_related_posts' QUERY; $relatedPostMeta = $wpdb->get_results($query); foreach ($relatedPostMeta as $relatedPosts) { $relatedPosts->meta_value = maybe_unserialize($relatedPosts->meta_value); foreach ($relatedPosts->meta_value as &$relatedPost) { $relatedPost['permalink'] = get_permalink($relatedPost['ID']); } $relatedPosts->meta_value = maybe_serialize( stripslashes_deep($relatedPosts->meta_value) ); $data = array( 'meta_value' => $relatedPosts->meta_value); $where = array( 'meta_key' => $relatedPosts->meta_key, 'post_id' => $relatedPosts->post_id ); $wpdb->update( $wpdb->postmeta, $data, $where ); wp_cache_delete($relatedPosts->post_id, 'post_meta'); } } public function activate() { $this->processAllPosts(); } /** * Replace our shortCode with the list of related posts * * @param array $attr - array of attributes from the shortCode * @param string $content - Content of the shortCode * @return string - formatted XHTML replacement for the shortCode */ public function handleShortcodes($attr, $content = '') { if ( !empty($content) && empty($attr['title']) ) { $attr['title'] = $content; } $attr = shortcode_atts($this->_settings['erp'], $attr); return $this->getRelatedPosts($attr); } public function filterSettings($settings) { $defaults = array( 'title' => __("Related Posts:", $this->_slug), 'no_rp_text' => __("No Related Posts", $this->_slug), 'ignore_cats' => array(), 'max_relations_stored' => 10, 'num_to_display' => 5, 'auto_insert' => 'no', 'rss' => 'no' ); $settings = wp_parse_args($settings, $defaults); if ( !is_array($settings['ignore_cats']) ) { $settings['ignore_cats'] = preg_split('/\s*,\s*/', trim($settings['ignore_cats']), -1, PREG_SPLIT_NO_EMPTY); } $settings['max_relations_stored'] = intval($settings['max_relations_stored']); $settings['num_to_display'] = intval($settings['num_to_display']); return $settings; } } /** * Our custom Walker because Walker_Category_Checklist doesn't let you use your own field name */ class Walker_Category_Checklist_ERP extends Walker { var $tree_type = 'category'; var $db_fields = array ('parent' => 'parent', 'id' => 'term_id'); //TODO: decouple this function start_lvl(&$output, $depth, $args) { $indent = str_repeat("\t", $depth); $output .= "$indent\n"; } function start_el(&$output, $category, $depth, $args) { extract($args); $class = in_array( $category->term_id, $popular_cats ) ? ' class="popular-category"' : ''; $output .= "\n
  • " . ''; } function end_el(&$output, $category, $depth, $args) { $output .= "
  • \n"; } } /** * Helper functions */ /** * @param [optional]$args See efficientRelatedPosts::getRelatedPosts */ function wp_related_posts( $args = array() ) { _deprecated_function( __FUNCTION__, '0.3.5', '"erp-show-related-posts" action' ); // Instantiate our class $efficientRelatedPosts = efficientRelatedPosts::getInstance(); $efficientRelatedPosts->relatedPosts($args); } /** * @param [optional]$args See efficientRelatedPosts::getRelatedPosts */ function wp_get_related_posts( $args = array() ) { _deprecated_function( __FUNCTION__, '0.3.5', '"erp-get-related-posts" filter' ); // Instantiate our class $efficientRelatedPosts = efficientRelatedPosts::getInstance(); return $efficientRelatedPosts->getRelatedPosts($args); } if ( !function_exists('get_memory_limit') ) { function get_memory_limit() { $limit = ini_get('memory_limit'); $symbol = array('B', 'K', 'M', 'G'); $numLimit = (int) $limit; $units = str_replace($numLimit, '', $limit); if ( empty($units) ) { return $numLimit; } else { return $numLimit * pow(1024, array_search(strtoupper($units[0]), $symbol)); } } } // Instantiate our class $efficientRelatedPosts = efficientRelatedPosts::getInstance();