- 1. Better query performance
- 2. Separation of logic and presentation
- 3. Flexible filtering conditions
- Practical WP_Query Examples
- Get posts with an average rating of 4.5 or higher
- Get posts with at least 20 votes
- Order posts by highest average rating
- Order posts by most total votes
- Get posts with average score ≥ 4.5 and at least 50 votes
- Conclusion
In the Init Review System plugin, each user-submitted rating is stored using three separate meta keys for each post:
_init_review_total: the total score accumulated from all votes_init_review_count: the number of valid votes_init_review_avg: the average score (rounded to 2 decimal places)
While this approach may seem redundant (since the average can be recalculated at any time), it brings three key advantages:
1. Better query performance
If we don’t store _init_review_avg directly, WordPress would need to fetch both _init_review_total and _init_review_count, then calculate the average in PHP. This makes it impossible to sort posts by average score using orderby in SQL. By saving the average score as a separate meta key, we allow WP_Query to sort results efficiently at the database level.
2. Separation of logic and presentation
Every time a new vote is submitted, the plugin updates all three values at once. This ensures that frontend rendering doesn’t have to compute the average repeatedly, which reduces processing overhead and rounding inconsistencies. It also improves compatibility with object caching and REST API caching.
3. Flexible filtering conditions
Storing all three values enables a wide range of queries — such as finding posts with at least 10 votes or with an average rating above 4.5. These are common requirements for building review listings, top charts, or content rankings.
Practical WP_Query Examples
Get posts with an average rating of 4.5 or higher
new WP_Query([
'post_type' => 'post',
'meta_query' => [
[
'key' => '_init_review_avg',
'value' => 4.5,
'type' => 'NUMERIC',
'compare' => '>=',
]
]
]);
Get posts with at least 20 votes
new WP_Query([
'post_type' => 'post',
'meta_query' => [
[
'key' => '_init_review_count',
'value' => 20,
'type' => 'NUMERIC',
'compare' => '>=',
]
]
]);
Order posts by highest average rating
new WP_Query([
'post_type' => 'post',
'meta_key' => '_init_review_avg',
'orderby' => 'meta_value_num',
'order' => 'DESC',
]);
Order posts by most total votes
new WP_Query([
'post_type' => 'post',
'meta_key' => '_init_review_count',
'orderby' => 'meta_value_num',
'order' => 'DESC',
]);
Get posts with average score ≥ 4.5 and at least 50 votes
new WP_Query([
'post_type' => 'post',
'meta_query' => [
'relation' => 'AND',
[
'key' => '_init_review_avg',
'value' => 4.5,
'type' => 'NUMERIC',
'compare' => '>=',
],
[
'key' => '_init_review_count',
'value' => 50,
'type' => 'NUMERIC',
'compare' => '>=',
]
],
'orderby' => 'meta_value_num',
'meta_key' => '_init_review_avg',
'order' => 'DESC',
]);
Conclusion
Storing _init_review_total, _init_review_count, and _init_review_avg independently gives the Init Review System plugin the best of both worlds: fast database queries and flexible rating logic. This design is practical, optimized, and production-ready for modern WordPress review systems.
Comments