PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
3.0.16 3.0.15 3.0.14 3.0.14.1 3.0.14.2 3.0.12 3.0.13 3.0.11 3.0.10 3.0.9 3.0.8 3.0.7 3.0.6 3.0.5 3.0.5.1 3.0.4 3.0.3 3.0.2.9 3.0.2.7 3.0.2.8 3.0.2.6 trunk 1.0.0 2.0.0 2.0.1 All 84 releases
yatra / templates / partials / single-trip / reviews.php

reviews.php in Yatra – Travel Booking & Tour Operator Software 3.0.16, at templates/partials/single-trip/reviews.php

323 lines 19.4 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 if (!defined('ABSPATH')) {
3 exit;
4 }
5
6 // Reviews Section
7 // Expected variables: $trip
8 ?>
9 <!-- Reviews: full width within unified trip container (same max-width + padding as .yatra-trip-container) -->
10 <?php // Structured data for reviews is emitted as JSON-LD (Product.review[]) in
11 // SEOService. The old itemtype="Review" here made the whole list a single
12 // Review with no author/itemReviewed, which Google flagged. ?>
13 <section class="yatra-reviews-section" id="reviews">
14 <div class="yatra-reviews-section-container">
15 <div class="yatra-reviews-header">
16 <h2 class="yatra-reviews-section-title">
17 <?php echo yatra_svg_icon('star', 'yatra-reviews-section-icon'); ?>
18 <?php echo esc_html__('Reviews', 'yatra'); ?>
19 </h2>
20 </div>
21
22 <?php
23 // Use dynamic reviews from database (via SingleTripController)
24 $display_reviews = !empty($trip->reviews) && is_array($trip->reviews) ? $trip->reviews : [];
25
26 // Total approved count and average come from SQL on the Trip model (list may be capped at N rows).
27 $total_reviews = (int) ($trip->review_count ?? 0);
28 if ($total_reviews < 1) {
29 $total_reviews = count($display_reviews);
30 }
31 $avg_rating = (isset($trip->average_rating) && (float) $trip->average_rating > 0)
32 ? (float) $trip->average_rating
33 : 0.0;
34
35 // Rating distribution: prefer full aggregate from Trip (accurate when review list is limited).
36 $rating_distribution = [5 => 0, 4 => 0, 3 => 0, 2 => 0, 1 => 0];
37 $dist = $trip->rating_distribution ?? null;
38 if (is_array($dist) && $dist !== [] && ($trip->review_count ?? 0) > 0) {
39 foreach ([5, 4, 3, 2, 1] as $star) {
40 $rating_distribution[$star] = (int) ($dist[$star] ?? $dist[(string) $star] ?? 0);
41 }
42 } else {
43 foreach ($display_reviews as $review) {
44 $review_rating = (int) (is_object($review) ? ($review->rating ?? 0) : ($review['rating'] ?? 0));
45 if ($review_rating >= 1 && $review_rating <= 5) {
46 $rating_distribution[$review_rating]++;
47 }
48 }
49 }
50
51 // If we have reviews, calculate average from them
52 if ($total_reviews > 0 && $avg_rating == 0) {
53 $total_rating = 0;
54 foreach ($display_reviews as $review) {
55 $total_rating += (int) (is_object($review) ? ($review->rating ?? 0) : ($review['rating'] ?? 0));
56 }
57 $avg_rating = round($total_rating / $total_reviews, 1);
58 }
59 ?>
60
61 <div class="yatra-reviews-container">
62 <!-- Left: Overall Rating Summary -->
63 <div class="yatra-reviews-summary">
64 <div class="yatra-overall-rating">
65 <div class="yatra-overall-rating-score">
66 <span class="yatra-rating-big"><?php echo esc_html(number_format($avg_rating, 1)); ?></span>
67 <span class="yatra-rating-max">/5</span>
68 </div>
69 <div class="yatra-overall-stars">
70 <?php
71 // Same helper as the confirmation page and listing cards, so a
72 // rating never renders differently on two screens.
73 $star_parts = yatra_rating_star_parts($avg_rating);
74 $full_stars = $star_parts['full'];
75 $has_half = $star_parts['half'];
76 for ($i = 1; $i <= 5; $i++):
77 if ($i <= $full_stars):
78 ?>
79 <span class="yatra-star-icon filled">�
80 </span>
81 <?php elseif ($i == $full_stars + 1 && $has_half): ?>
82 <span class="yatra-star-icon half">�
83 </span>
84 <?php else: ?>
85 <span class="yatra-star-icon">�
86 </span>
87 <?php endif; endfor; ?>
88 </div>
89 <p class="yatra-reviews-based-on">
90 <?php
91 /* translators: %s: formatted total number of reviews. */
92 echo esc_html(sprintf(_n('based on %s review', 'based on %s reviews', $total_reviews, 'yatra'), number_format($total_reviews)));
93 ?>
94 </p>
95 </div>
96
97 <div class="yatra-rating-distribution">
98 <h4 class="yatra-rating-distribution-title"><?php echo esc_html__('Rating breakdown', 'yatra'); ?></h4>
99 <?php for ($star = 5; $star >= 1; $star--):
100 $count = $rating_distribution[$star];
101 $percentage = $total_reviews > 0 ? ($count / $total_reviews) * 100 : 0;
102 ?>
103 <div class="yatra-rating-row">
104 <span class="yatra-rating-star-label">
105 <?php for ($s = 1; $s <= 5; $s++): ?>
106 <span class="yatra-breakdown-star <?php echo $s <= $star ? 'filled' : ''; ?>">�
107 </span>
108 <?php endfor; ?>
109 </span>
110 <div class="yatra-rating-bar">
111 <div class="yatra-rating-bar-fill" style="width: <?php echo esc_attr($percentage); ?>%"></div>
112 </div>
113 <span class="yatra-rating-count"><?php echo esc_html($count); ?></span>
114 </div>
115 <?php endfor; ?>
116 </div>
117 </div>
118
119 <!-- Right: Reviews List -->
120 <div class="yatra-reviews-list">
121 <?php if (!empty($display_reviews)): ?>
122 <!-- Sort & Filter Toolbar -->
123 <div class="yatra-reviews-toolbar">
124 <div class="yatra-reviews-sort">
125 <span class="yatra-sort-label"><?php echo esc_html__('Sort by:', 'yatra'); ?></span>
126 <select class="yatra-sort-select" id="review-sort">
127 <option value="newest"><?php echo esc_html__('Newest first', 'yatra'); ?></option>
128 <option value="highest"><?php echo esc_html__('Highest rated', 'yatra'); ?></option>
129 <option value="lowest"><?php echo esc_html__('Lowest rated', 'yatra'); ?></option>
130 </select>
131 </div>
132 </div>
133 <!-- Reviews -->
134 <div class="yatra-reviews-items">
135 <?php foreach ($display_reviews as $review):
136 $review_rating = is_object($review) ? ($review->rating ?? 5) : ($review['rating'] ?? 5);
137 $review_title = is_object($review) ? ($review->title ?? '') : ($review['title'] ?? '');
138 $review_content = is_object($review) ? ($review->content ?? '') : ($review['content'] ?? '');
139 $review_author = is_object($review) ? ($review->author_name ?? __('Anonymous', 'yatra')) : ($review['author_name'] ?? __('Anonymous', 'yatra'));
140 $review_location = is_object($review) ? ($review->author_location ?? '') : ($review['author_location'] ?? '');
141 $review_date = is_object($review) ? ($review->created_at ?? '') : ($review['created_at'] ?? '');
142 $review_user_id = is_object($review) ? ($review->user_id ?? 0) : ($review['user_id'] ?? 0);
143 $is_verified = $review_user_id > 0;
144 $author_initial = strtoupper(substr($review_author, 0, 1));
145 $avatar_colors = ['#ef4444', '#f97316', '#eab308', '#22c55e', '#3b82f6', '#8b5cf6', '#ec4899'];
146 $avatar_color = $avatar_colors[ord($author_initial) % count($avatar_colors)];
147 ?>
148 <div class="yatra-review-item">
149 <div class="yatra-review-header">
150 <div class="yatra-review-header-left">
151 <div class="yatra-review-avatar" style="background: linear-gradient(135deg, <?php echo esc_attr($avatar_color); ?> 0%, <?php echo esc_attr($avatar_color); ?>dd 100%);">
152 <?php echo esc_html($author_initial); ?>
153 </div>
154 <div class="yatra-review-author-info">
155 <div class="yatra-review-author-top">
156 <span class="yatra-review-author-name"><?php echo esc_html($review_author); ?></span>
157 <?php if ($is_verified): ?>
158 <span class="yatra-verified-badge">
159 <svg class="yatra-icon-xs" width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5">
160 <path d="M20 6L9 17l-5-5"/>
161 </svg>
162 <?php echo esc_html__('Verified', 'yatra'); ?>
163 </span>
164 <?php endif; ?>
165 </div>
166 <div class="yatra-review-meta">
167 <?php if ($review_date): ?>
168 <span class="yatra-review-date"><?php echo esc_html(date_i18n('F j, Y', strtotime($review_date))); ?></span>
169 <?php endif; ?>
170 <?php if ($review_location): ?>
171 <span class="yatra-review-author-location">• <?php echo esc_html($review_location); ?></span>
172 <?php endif; ?>
173 </div>
174 </div>
175 </div>
176 <div class="yatra-review-stars">
177 <?php for ($i = 1; $i <= 5; $i++): ?>
178 <span class="yatra-star-sm <?php echo $i <= $review_rating ? 'filled' : ''; ?>">�
179 </span>
180 <?php endfor; ?>
181 </div>
182 </div>
183 <div class="yatra-review-body">
184 <?php if ($review_title): ?>
185 <h4 class="yatra-review-title"><?php echo esc_html($review_title); ?></h4>
186 <?php endif; ?>
187 <p class="yatra-review-content"><?php echo esc_html($review_content); ?></p>
188 </div>
189 </div>
190 <?php endforeach; ?>
191 </div>
192
193 <!-- Load More -->
194 <?php if ($total_reviews > 3): ?>
195 <div class="yatra-reviews-load-more">
196 <button class="yatra-load-more-btn" type="button">
197 <?php echo esc_html__('Show more reviews', 'yatra'); ?>
198 </button>
199 </div>
200 <?php endif; ?>
201 <?php else: ?>
202 <div class="yatra-no-reviews-message">
203 <div class="yatra-no-reviews-icon">
204 <?php echo yatra_svg_icon('message-circle', 'yatra-icon-lg'); ?>
205 </div>
206 <p><?php echo esc_html__('No reviews yet. Be the first to review this trip!', 'yatra'); ?></p>
207 </div>
208 <?php endif; ?>
209 </div>
210 </div>
211
212 <!-- Review Form -->
213 <?php
214 $can_review = yatra_can_review((int) $trip->id);
215 $require_booking = yatra_setting_enabled('require_booking_to_review');
216 $minimum_rating = (int) yatra_get_setting('minimum_rating', 1);
217
218 // Check for existing review that can be edited
219 $existing_review = null;
220 $can_edit_review = false;
221 $edit_time_remaining = '';
222
223 if (is_user_logged_in()) {
224 $existing_review = yatra_get_user_review((int) $trip->id);
225 if ($existing_review) {
226 $can_edit_review = yatra_can_edit_review($existing_review);
227 if ($can_edit_review) {
228 $edit_time_remaining = yatra_get_review_edit_time_remaining($existing_review);
229 }
230 }
231 }
232 ?>
233 <div class="yatra-review-form-section">
234 <?php if ($existing_review && $can_edit_review): ?>
235 <h3 class="yatra-review-form-title"><?php echo esc_html__('Edit Your Review', 'yatra'); ?></h3>
236 <div class="yatra-review-edit-notice">
237 <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24">
238 <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M12 8v4l3 3m6-3a9 9 0 11-18 0 9 9 0 0118 0z"/>
239 </svg>
240 <p><?php
241 /* translators: %s: remaining edit time (e.g. "12 minutes"). */
242 echo esc_html(sprintf(__('You can edit your review for %s more.', 'yatra'), $edit_time_remaining));
243 ?></p>
244 </div>
245 <?php else: ?>
246 <h3 class="yatra-review-form-title"><?php echo esc_html__('Write a Review', 'yatra'); ?></h3>
247 <?php endif; ?>
248
249 <?php if (!is_user_logged_in()): ?>
250 <div class="yatra-review-login-notice">
251 <p><?php echo esc_html__('Please', 'yatra'); ?> <a href="<?php echo esc_url(wp_login_url(get_permalink())); ?>"><?php echo esc_html__('log in', 'yatra'); ?></a> <?php echo esc_html__('to write a review.', 'yatra'); ?></p>
252 </div>
253 <?php elseif (!$can_review && $require_booking): ?>
254 <div class="yatra-review-booking-notice">
255 <p><?php echo esc_html__('Only customers who have booked this trip can leave a review.', 'yatra'); ?></p>
256 </div>
257 <?php elseif ($existing_review && !$can_edit_review): ?>
258 <div class="yatra-review-already-notice">
259 <?php if (isset($existing_review->status) && $existing_review->status === 'approved'): ?>
260 <p><?php echo esc_html__('Thank you! Your review has been approved and published.', 'yatra'); ?></p>
261 <?php else: ?>
262 <p><?php echo esc_html__('You have already reviewed this trip.', 'yatra'); ?></p>
263 <?php endif; ?>
264 </div>
265 <?php elseif ($can_review || ($existing_review && $can_edit_review)): ?>
266 <form class="yatra-review-form" id="yatra-review-form" method="post">
267 <?php wp_nonce_field('yatra_submit_review', 'yatra_review_nonce'); ?>
268 <input type="hidden" name="trip_id" value="<?php echo esc_attr($trip->id); ?>">
269 <?php if ($existing_review && $can_edit_review): ?>
270 <input type="hidden" name="review_id" value="<?php echo esc_attr($existing_review->id); ?>">
271 <input type="hidden" name="action_type" value="edit">
272 <?php endif; ?>
273
274 <!-- Rating -->
275 <div class="yatra-form-field yatra-rating-field">
276 <label class="yatra-form-label"><?php echo esc_html__('Your Rating', 'yatra'); ?> <span class="yatra-required">*</span></label>
277 <div class="yatra-star-rating-input" data-min-rating="<?php echo esc_attr($minimum_rating); ?>">
278 <?php
279 $selected_rating = $existing_review ? (int) $existing_review->rating : 5;
280 for ($i = 1; $i <= 5; $i++):
281 ?>
282 <input type="radio" name="rating" id="rating-<?php echo $i; ?>" value="<?php echo $i; ?>" <?php echo $i === $selected_rating ? 'checked' : ''; ?> <?php echo $i < $minimum_rating ? 'disabled' : ''; ?>>
283 <label for="rating-<?php echo $i; ?>" class="yatra-star-label" title="<?php echo esc_attr(sprintf(__('%d star', 'yatra'), $i)); ?>">�
284 </label>
285 <?php endfor; ?>
286 </div>
287 <?php if ($minimum_rating > 1): ?>
288 <p class="yatra-field-hint"><?php
289 /* translators: %d: minimum allowed star rating. */
290 echo esc_html(sprintf(__('Minimum rating: %d star(s)', 'yatra'), $minimum_rating));
291 ?></p>
292 <?php endif; ?>
293 </div>
294
295 <!-- Title -->
296 <div class="yatra-form-field">
297 <label for="review-title" class="yatra-form-label"><?php echo esc_html__('Review Title', 'yatra'); ?></label>
298 <input type="text" id="review-title" name="title" class="yatra-form-input" placeholder="<?php echo esc_attr__('Summarize your experience', 'yatra'); ?>" maxlength="100" value="<?php echo $existing_review ? esc_attr($existing_review->title ?? '') : ''; ?>">
299 </div>
300
301 <!-- Review Content -->
302 <div class="yatra-form-field">
303 <label for="review-content" class="yatra-form-label"><?php echo esc_html__('Your Review', 'yatra'); ?> <span class="yatra-required">*</span></label>
304 <textarea id="review-content" name="content" class="yatra-form-textarea" rows="5" placeholder="<?php echo esc_attr__('Share your experience with this trip...', 'yatra'); ?>" required minlength="20"><?php echo $existing_review ? esc_textarea($existing_review->content ?? '') : ''; ?></textarea>
305 <p class="yatra-field-hint"><?php echo esc_html__('Minimum 20 characters', 'yatra'); ?></p>
306 </div>
307
308 <!-- Submit Button -->
309 <div class="yatra-form-field">
310 <button type="submit" class="yatra-review-submit-btn">
311 <?php echo yatra_svg_icon('check', 'yatra-icon-sm'); ?>
312 <?php echo $existing_review && $can_edit_review ? esc_html__('Update Review', 'yatra') : esc_html__('Submit Review', 'yatra'); ?>
313 </button>
314 <?php if (yatra_setting_enabled('enable_review_moderation')): ?>
315 <p class="yatra-review-moderation-notice"><?php echo esc_html__('Your review will be published after moderation.', 'yatra'); ?></p>
316 <?php endif; ?>
317 </div>
318 </form>
319 <?php endif; ?>
320 </div>
321 </div>
322 </section>
323