public function tour()
useEffect(() => fetch( /api/tours/$tourId/reviews ) .then(res => res.json()) .then(data => setStats(data.stats); setReviews(data.reviews.data); ); , [tourId]);
public function markHelpful($userId)
public function user()
class PortaTourReview extends Model
return ( <div className="portatour-reviews"> <div className="reviews-header"> <h2>Customer Reviews</h2> <div className="rating-summary"> <span className="average">stats?.average_rating.toFixed(1)</span> <StarRating rating=stats?.average_rating /> <span>(stats?.total_reviews reviews)</span> </div> </div>
"@context": "https://schema.org", "@type": "Product", "name": "Paris Walking Tour", "aggregateRating": "@type": "AggregateRating", "ratingValue": "4.8", "reviewCount": "127" , "review": [ "@type": "Review", "author": "John Doe", "datePublished": "2025-03-10", "reviewRating": "@type": "Rating", "ratingValue": "5" , "reviewBody": "Amazing guide!" ] portatour reviews
</script> ✅ Verified purchase only (via booking ID) ✅ Star rating (1–5) + title + comment ✅ Image upload (max 5) ✅ Helpful button ✅ Admin approval workflow ✅ Average rating & breakdown ✅ Sort by newest / highest rated ✅ SEO structured data