Howto sort posts by rating
-
Hi there,
yesterday i started working with the plugin and discovered that sorting posts by rating is not simply possible.
but i found a way to it by storing the average rating in the post_meta table.
for reference here is the sourcecode to what ive done:
disclaimer: the comment actions need some more investigation
first i copied the shortcode function “wpcr_avg_rating” to my template or plugin, trimmed it (as there is a lot unnecessary code) and seperated the calculation of the average rating from the rest:
// calculates average rating based on comment_meta 'rating' function myPlugin_calculate_avg_rating($post_id = false){ if ( !function_exists('wpcr_avg_rating') ) { return 0; } if ( !$post_id ) { $post_id = get_the_ID(); } $comments = get_approved_comments($post_id); $sum = 0; $avg = 0; $count_rated = 0; foreach ( $comments as $comment ) { $rating = get_comment_meta($comment->comment_ID, 'rating', true); if ( $rating ) { $sum = $sum + (int)$rating; $count_rated++; } } if ( $count_rated > 0 ) { $avg = $sum/$count_rated; } return $avg; } // add own rating avg function for better displaying function myPlugin_avg_rating($atts) { if ( !function_exists('wpcr_avg_rating') ) { return ''; } $a = shortcode_atts(array('title' => 'Rating',), $atts); // what is this good for? $output = ''; $post_id = get_the_ID(); $avg = myPlugin_calculate_avg_rating($post_id); // now stored to post $comment_count = wp_count_comments($post_id)->approved; $wpcr_options = get_option('wpcr_settings'); $tooltip_inline = $wpcr_options['tooltip_inline']; $avgrating_text = $wpcr_options['wpcravg_text']; $avg_text = $avgrating_text == '' ? __( 'Average', 'wp-post-comment-rating' ) : $avgrating_text; $avgText = __('average', 'wp-post-comment-rating'); $outOf = __('out of 5. Total', 'wp-post-comment-rating'); if ( $avg > 0 ) { if ( $tooltip_inline == 1 ) { $output = '<div class="wpcr_aggregate"><a class="wpcr_tooltip" title="'.$avgText.': '.round($avg,2).' '.$outOf.': '.$comment_count.'"><span class="wpcr_stars" title="">'.$avg_text.':</span>'; $output .= '<span class="wpcr_averageStars" id="'.$avg.'"></span></a></div>'; } if ( $tooltip_inline == 0 ) { $output = '<div class="wpcr_aggregate"><a class="wpcr_inline" title=""><span class="wpcr_stars" title="">'.$avg_text.':</span>'; $output .= '<span class="wpcr_averageStars" id="'.$avg.'"></span></a><span class="avg-inline">('.$avgText.': <strong> '.round($avg, 2).'</strong> '.$outOf.': '.$comment_count.')</span></div>'; } } return $output; }
after having the calculation seperated i add action hooks to everytime a comment gets posted/updated/approved/trashed or deleted
// add avg rating to post meta after a comment was written // sets post_meta '_wpcr_rating' when new approved comment is posted function myPlugin_comment_post($id, $approved){ myPlugin_post_meta_avg_rating(get_comment($id)->comment_post_ID); } add_action('comment_post', 'myPlugin_comment_post', 10, 2); // sets post_meta '_wpcr_rating' when wp_set_comment_status is called function myPlugin_wp_set_comment_status($id, $status){ myPlugin_post_meta_avg_rating(get_comment($id)->comment_post_ID); } add_action('wp_set_comment_status', 'myPlugin_wp_set_comment_status', 10, 2); // sets post_meta '_wpcr_rating' when approved or deleted function myPlugin_transition_comment_status($new_status, $old_status, $comment){ myPlugin_post_meta_avg_rating($comment->comment_post_ID); } add_action('transition_comment_status', 'myPlugin_transition_comment_status', 10, 3);
all three actions call the “myPlugin_post_meta_avg_rating” function which updates the post_meta field “_wpcr_rating”
// sets post_meta '_wpcr_rating' function myPlugin_post_meta_avg_rating($post_id){ $avg = myPlugin_calculate_avg_rating($post_id); if ( $avg > 0 ) { update_post_meta($post_id, '_wpcr_rating', $avg); } }
now every time a comment action happens the meta value of “_wpcr_rating” is updated.
its not neccesarry any more to calculate it on every page load so i made a final change to the shortcode function by reading the post_meta:
// add own rating avg function for better displaying function myPlugin_avg_rating($atts) { if ( !function_exists('wpcr_avg_rating') ) { return ''; } $a = shortcode_atts(array('title' => 'Rating',), $atts); // what is this good for? $output = ''; $post_id = get_the_ID(); $avg = get_post_meta($post_id, '_wpcr_rating', true); // $avg = myPlugin_calculate_avg_rating($post_id); // now stored to post $comment_count = wp_count_comments($post_id)->approved; $wpcr_options = get_option('wpcr_settings'); $tooltip_inline = $wpcr_options['tooltip_inline']; $avgrating_text = $wpcr_options['wpcravg_text']; $avg_text = $avgrating_text == '' ? __( 'Average', 'wp-post-comment-rating' ) : $avgrating_text; $avgText = __('average', 'wp-post-comment-rating'); $outOf = __('out of 5. Total', 'wp-post-comment-rating'); if ( $avg > 0 ) { if ( $tooltip_inline == 1 ) { $output = '<div class="wpcr_aggregate"><a class="wpcr_tooltip" title="'.$avgText.': '.round($avg,2).' '.$outOf.': '.$comment_count.'"><span class="wpcr_stars" title="">'.$avg_text.':</span>'; $output .= '<span class="wpcr_averageStars" id="'.$avg.'"></span></a></div>'; } if ( $tooltip_inline == 0 ) { $output = '<div class="wpcr_aggregate"><a class="wpcr_inline" title=""><span class="wpcr_stars" title="">'.$avg_text.':</span>'; $output .= '<span class="wpcr_averageStars" id="'.$avg.'"></span></a><span class="avg-inline">('.$avgText.': <strong> '.round($avg, 2).'</strong> '.$outOf.': '.$comment_count.')</span></div>'; } } return $output; }
also its now possible to manipulate an archive query with the ‘pre_get_posts’ action:
function myPlugin_pre_get_posts($query) { if ( !is_admin() && $query->is_main_query() && is_archive() && $query->get('post_type') === 'my_post_type' ) { $query->set('meta_key','_wpcr_rating'); $query->set('orderby','meta_value_num'); } } add_action('pre_get_posts', 'myPlugin_pre_get_posts', 10, 1);
of course one also can add it now to any WP_Query call.
maybe some of the enhancements also will make it into an update of the plugin?
- The topic ‘Howto sort posts by rating’ is closed to new replies.