How reviews are stored and read (provider model)

The problem this solves

Earlier versions inserted app reviews as bare WordPress comments with wp_insert_comment(). That call does not fire comment_post, the hook GeoDirectory and WooCommerce listen on to recompute their rating aggregates — so app reviews became orphans: stored, but invisible to native averages and to the website. The web and the app disagreed about a listing’s rating.

The provider model fixes this by making one rule absolute: core never touches review storage directly. It resolves exactly one provider per post and delegates every read and write to it. The provider knows the post type’s native store and writes through the native path (so aggregates recompute). The result is read/write symmetry — what the app shows and what the app saves are the same data the website shows and saves.


The pieces

mam-reviews-manager (core orchestrator)
  ├─ envelope: auth, rate-limit, photos, tips, payload decode   (ajax-handler.php)
  ├─ sections: reviews_header / reviews / add_review            (content-sections.php)
  └─ provider registry + resolution                            (class-mam-reviews-provider-registry.php)
        resolves ONE provider per post ↓
   ┌──────────────────┬──────────────────────┬─────────────────────┐
   ▼                  ▼                      ▼
 GD provider       Woo provider          Default provider
 (mam-geodirectory)(mam-woocommerce)     (mam-reviews-manager, built in)
 wp_geodir_post_review  comment_type 'review'  wp_comments + 'rating' meta
 + rating categories    + _wc_average_rating   single-star
 MULTI-CRITERIA         single-star
  • MAM_Reviews_Provider (interface-mam-reviews-provider.php) — the contract: supports(), get_criteria(), get_aggregates(), get_reviews(), get_user_review(), save_review(), get_all_reviews().
  • MAM_Reviews_Provider_Base (abstract-mam-reviews-provider-base.php) — shared helpers: the overall criterion, reviewer-name formatting, photo loading, the default get_all_reviews() loop. Concrete providers implement only the storage-specific reads and writes.
  • MAM_Reviews_Provider_Registry — collects providers from the mam_reviews_providers filter and resolves one per post.
  • mam_reviews_provider_for( int $post_id ): MAM_Reviews_Provider — the helper everything calls to get the owning provider.

Resolution

  1. Core resolves $post_type = get_post_type( $post_id ).
  2. It walks registered providers by descending priority.
  3. The first provider whose supports( $post_id, $post_type ) returns true wins.
  4. The default provider registers at priority 0 and supports everything — so there is always exactly one match.

Resolution is memoized per request per post id. Registration is lazy/booted once on first resolution, so sibling-plugin providers (loaded later) are all present.

Provider Registered by Priority Owns
mam_gd_reviews_provider mam-geodirectory 20 GD post types with ratings enabled
mam_wc_reviews_provider mam-woocommerce 20 product post type
mam_reviews_default_provider mam-reviews-manager 0 everything else (fallback)

To add your own (e.g. a bespoke post type), register on the filter — see Hook: mam_reviews_providers.


Where the rating data actually lives

If you’re building a feature that consumes ratings (recommendations, “my ratings”, analytics), prefer reading through the provider so you stay storage-agnostic:

$provider = mam_reviews_provider_for( $post_id );
$aggregates = $provider->get_aggregates( $post_id );   // average, count, distribution, per-criterion
$reviews    = $provider->get_reviews( $post_id );       // normalized list
$mine       = $provider->get_user_review( $post_id, $user_id );
$criteria   = $provider->get_criteria( $post_id );

If you need the raw native store directly, this is where each provider keeps it:

Store GeoDirectory WooCommerce Default
Per-review row wp_geodir_post_review (rating overall + serialized ratings multi-criteria) comment with comment_type = 'review' + rating comment meta comment + rating comment meta
Overall average geodir_get_post_rating() _wc_average_rating postmeta computed from rating meta
Count geodir_get_review_count_total() _wc_review_count postmeta count of rated comments
Distribution GeoDir_Comments::get_post_review_rating_counts() _wc_rating_count postmeta computed
Criteria config geodir_reviewrating_rating_categories() (Review Rating Manager) n/a n/a

The write path (why it stays native)

save_review() must write so native aggregates update. The providers do this by reconstructing the request the native handler expects and submitting through wp_new_comment() (which fires comment_post), not wp_insert_comment():

  • GeoDirectory populates $_REQUEST/$_POST['geodir_overallrating'], ['geodir_rating'] (multi-criteria), and ['comment_images'], sets the global $user_ID, guards pre_comment_approved / wp_is_comment_flood, then calls wp_new_comment() so GeoDir_Comments::save_rating() runs. It temporarily removes GeoDirectory’s Dynamic Emails comment_post action around the insert so app submissions don’t trigger the “your comment was approved” email, then restores it.
  • WooCommerce inserts a comment_type = 'review' comment with rating meta and lets WooCommerce recompute _wc_average_rating / _wc_review_count / _wc_rating_count.

Each provider also ships a backfill_orphans() routine; the one-time migration uses these to fold pre-existing orphaned app comments into the native stores.


Hooks to consume after a rating is recorded

Hook When Args
mam_reviews_review_submitted after any full review is saved $payload, $submission, $result
mam_reviews_swipe_submitted after a swipe rating $swipe, $result
mam_reviews_add_vendor_review after a shop_order review (vendor/tips) $payload

See the individual hook pages for contracts and examples.


Back-compat

The pre-refactor read filters (mam_reviews_get_reviews_for_post, mam_reviews_has_user_commented_on_post, mam_reviews_get_all_reviews_array, and the mam_content_section_* builders) are retained as thin shims that call the resolved provider, so existing external consumers keep working unchanged.



Metadata

Field Value
Article type Integration / Architecture
Plugin slug mam-reviews-manager
Applies to plugin version 26.23.0+
Category Extending MAM Suite
Audience PHP developer
Last verified 2026-06-04
Contents

    Need Support?

    Can't find the answer you're looking for? Don't worry we're here to help!