You can use this function, which you’d add to the theme’s functions.php
file, to update the average post rating which is saved in a private meta named _avg_rating
(but you can of course rename it) — private meta has their name starting with an underscore (_
):
function update_post_avg_rating( $comment_id, $post_id = 0 ) {
if ( ! $post_id ) {
if ( ! $comment = get_comment( $comment_id ) ) {
return false;
}
$post_id = $comment->comment_post_ID;
}
// Retrieve the ID of all rating comments in post $post_id.
$ids = get_comments( [
'meta_key' => 'rating',
'post_id' => $post_id,
'fields' => 'ids',
'status' => 'all',
] );
// Calculate the average rating (using a custom MySQL query).
$avg = 0;
if ( ! empty( $ids ) ) {
global $wpdb;
$avg = $wpdb->get_var( "
SELECT AVG(meta_value + 0) FROM {$wpdb->prefix}commentmeta
WHERE meta_key = 'rating'
AND comment_id IN (" . implode( ',', $ids ) . ")
" );
}
// Update the average rating.
update_post_meta( $post_id, '_avg_rating', $avg );
}
Then call the function after you saved the post rating, like so:
function save_comment_meta_phone( $comment_id ) {
if ( ! empty( $_POST['rating'] ) ) {
$rating = sanitize_text_field( $_POST['rating'] );
// Save the post rating.
add_comment_meta( $comment_id, 'rating', $rating );
// Then update the average rating.
update_post_avg_rating( $comment_id );
}
}
Btw, you may want to rename the save_comment_meta_phone()
function to save_comment_meta_rating
?.. (just a suggestion)
And in the update_post_avg_rating()
code, in the get_comments()
call, you can set the status
to approve
if you want to include only approved post ratings.
UPDATE
Removed, but you can always view the answer’s revisions.
UPDATE #2
Removed, but you can always view the answer’s revisions.
UPDATE #3
Hopefully these help you in using the _avg_rating
meta:
-
To show the average rating of an individual post, you can use
get_post_meta()
like so:$avg_rating = get_post_meta( get_the_ID(), '_avg_rating', true ); $avg_rating = $avg_rating ? number_format_i18n( $avg_rating, 1 ) : 0; echo $avg_rating;
-
To sort posts by the
_avg_rating
meta, while still including posts that do not have the_avg_rating
meta, you can use keyedmeta_query
like so:$q = new WP_Query( array( 'post_type' => 'post', 'meta_query' => array( 'relation' => 'OR', 'avg_rating_clause' => array( 'key' => '_avg_rating', 'compare' => 'EXISTS', 'type' => 'DECIMAL', ), 'avg_rating_clause2' => array( 'key' => '_avg_rating', 'compare' => 'NOT EXISTS', 'type' => 'DECIMAL', ), ), 'orderby' => array( 'avg_rating_clause2' => 'DESC', 'date' => 'DESC', ), //... ) ); // Sample for displaying the posts. if ( $q->have_posts() ) { while ( $q->have_posts() ) { $q->the_post(); $avg_rating = get_post_meta( get_the_ID(), '_avg_rating', true ); $avg_rating = $avg_rating ? number_format_i18n( $avg_rating, 1 ) : 0; the_title( '<h2>', ' (Avg. Rating: ' . $avg_rating . ')</h2>' ); } }
See here for more details on the
meta_query
.