PluginProbe
Yatra – Travel Booking & Tour Operator Software / trunk
Yatra – Travel Booking & Tour Operator Software vtrunk
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 2.0.10 2.0.11 All 82 releases
yatra / app / Core / Handlers / TaxonomyPageHandler.php

TaxonomyPageHandler.php in Yatra – Travel Booking & Tour Operator Software trunk, at app/Core/Handlers/TaxonomyPageHandler.php

219 lines 6.8 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace Yatra\Core\Handlers;
6
7 use Yatra\Database\Tables\ClassificationsTable;
8 use Yatra\Repositories\TripRepository;
9
10 /**
11 * Taxonomy Page Handler
12 *
13 * Handles single taxonomy page requests (destination, activity, category)
14 */
15 class TaxonomyPageHandler extends BasePageHandler
16 {
17 /**
18 * Handle taxonomy page request
19 *
20 * @param array $route_data Route data from RouteMatcher
21 * @return bool True if handled successfully
22 */
23 public function handle(array $route_data): bool
24 {
25 $taxonomy_type = $route_data['taxonomy_type'];
26 $slug = $route_data['slug'];
27 $base = $route_data['base'];
28
29 $taxonomy_data = $this->getTaxonomyData($taxonomy_type, $slug);
30
31 if (!$taxonomy_data) {
32 $this->set404();
33 return false;
34 }
35
36 $tripRepository = new TripRepository();
37 $filter_key = $this->getFilterKey($taxonomy_type);
38
39 $pageNum = !empty($route_data['paged']) ? max(1, (int) $route_data['paged']) : \yatra_get_archive_listing_paged();
40 $perPage = \yatra_get_posts_per_page();
41
42 $filters = [$filter_key => $slug];
43 // AND with complementary slug filters from the query string (same semantics as /trip/?destination=&activity=).
44 if ($taxonomy_type === 'destination' && !empty($_GET['activity']) && is_string($_GET['activity'])) {
45 $a = sanitize_text_field(wp_unslash($_GET['activity']));
46 if ($a !== '') {
47 $filters['activity'] = $a;
48 }
49 }
50 if ($taxonomy_type === 'activity' && !empty($_GET['destination']) && is_string($_GET['destination'])) {
51 $d = sanitize_text_field(wp_unslash($_GET['destination']));
52 if ($d !== '') {
53 $filters['destination'] = $d;
54 }
55 }
56 $sort = isset($_GET['sort']) ? sanitize_text_field(wp_unslash((string) $_GET['sort'])) : '';
57 $allowedSorts = ['most_popular', 'price_low', 'price_high', 'rating_high', 'duration_short', 'duration_long'];
58 if ($sort !== '' && in_array($sort, $allowedSorts, true)) {
59 $filters['sort'] = $sort;
60 }
61
62 $trips_data = $tripRepository->findWithFilters($filters, $pageNum, $perPage);
63
64 $taxonomy_data->trips_total = (int) ($trips_data['total'] ?? 0);
65 $taxonomy_data->trips_pages = (int) ($trips_data['pages'] ?? 1);
66 $taxonomy_data->trips_per_page = (int) ($trips_data['per_page'] ?? $perPage);
67 $taxonomy_data->trips_current_page = (int) ($trips_data['page'] ?? $pageNum);
68 $taxonomy_data->trips = $trips_data['trips'] ?? [];
69
70 $tripsWithReviews = [];
71 foreach ($taxonomy_data->trips as $trip) {
72 $trip->reviews = $this->getReviewsForTrip((int) $trip->id);
73 $trip->average_rating = $this->calculateAverageRating($trip->reviews);
74 $trip->review_count = count($trip->reviews);
75
76 $tripsWithReviews[] = $trip;
77 }
78
79 $taxonomy_data->trips = $tripsWithReviews;
80
81 // Configure $wp_query + virtual WP_Post so FSE block themes resolve an archive
82 // template (not 404.html) for taxonomy pages.
83 $this->setupPageEnvironment('archive', [
84 'title' => (string) ($taxonomy_data->name ?? $taxonomy_data->title ?? $slug),
85 'object_id' => (int) ($taxonomy_data->id ?? 0),
86 'post_type' => 'page',
87 'post_name' => $slug,
88 ]);
89
90 $this->setGlobal('yatra_taxonomy_data', $taxonomy_data);
91
92 $this->setQueryVars([
93 'yatra_taxonomy_type' => $taxonomy_data->type,
94 'yatra_taxonomy_slug' => $taxonomy_data->slug,
95 'yatra_taxonomy' => $taxonomy_data,
96 'yatra_page' => $base,
97 ]);
98
99 return $this->selectTemplate('single-taxonomy', null, 'taxonomy-' . $taxonomy_type);
100 }
101
102 /**
103 * Get taxonomy data by type and slug
104 *
105 * @param string $type Taxonomy type
106 * @param string $slug Taxonomy slug
107 * @return object|null Taxonomy data or null if not found
108 */
109 private function getTaxonomyData(string $type, string $slug): ?object
110 {
111 global $wpdb;
112
113 $table = ClassificationsTable::getTableName();
114
115 $sql = $wpdb->prepare(
116 "SELECT * FROM {$table} WHERE type = %s AND slug = %s AND status = 'publish' LIMIT 1",
117 $type,
118 $slug
119 );
120
121 $data = $wpdb->get_row($sql);
122
123 if ($data) {
124 if (isset($data->metadata) && is_string($data->metadata)) {
125 $data->metadata = maybe_unserialize($data->metadata);
126 }
127
128 if (isset($data->icon) && is_string($data->icon)) {
129 $data->icon = maybe_unserialize($data->icon);
130 }
131
132 if (isset($data->icon) && is_numeric($data->icon)) {
133 $data->icon = wp_get_attachment_url($data->icon);
134 }
135 }
136
137 return $data ?: null;
138 }
139
140 /**
141 * Get filter key for taxonomy type
142 *
143 * @param string $taxonomy_type Taxonomy type
144 * @return string Filter key for TripRepository
145 */
146 private function getFilterKey(string $taxonomy_type): string
147 {
148 switch ($taxonomy_type) {
149 case 'category':
150 return 'trip_category';
151 case 'activity':
152 return 'activity';
153 case 'destination':
154 return 'destination';
155 case 'difficulty':
156 return 'difficulty';
157 default:
158 return $taxonomy_type;
159 }
160 }
161
162 /**
163 * Get reviews for a specific trip (same as SingleTripController)
164 *
165 * @param int $trip_id Trip ID
166 * @return array Reviews
167 */
168 private function getReviewsForTrip(int $trip_id): array
169 {
170 global $wpdb;
171
172 $reviewsTable = \Yatra\Database\Tables\ReviewsTable::getTableName();
173
174 $table_exists = $wpdb->get_var(
175 $wpdb->prepare(
176 'SHOW TABLES LIKE %s',
177 $reviewsTable
178 )
179 );
180
181 if (!$table_exists) {
182 return [];
183 }
184
185 $sql = $wpdb->prepare(
186 "SELECT * FROM {$reviewsTable}
187 WHERE trip_id = %d
188 AND status = 'approved'
189 ORDER BY created_at DESC
190 LIMIT 10",
191 $trip_id
192 );
193
194 $reviews = $wpdb->get_results($sql);
195
196 return $reviews ?: [];
197 }
198
199 /**
200 * Calculate average rating from reviews (same as SingleTripController)
201 *
202 * @param array $reviews Reviews array
203 * @return float Average rating
204 */
205 private function calculateAverageRating(array $reviews): float
206 {
207 if (empty($reviews)) {
208 return 0.0;
209 }
210
211 $total = 0;
212 foreach ($reviews as $review) {
213 $total += (float) ($review->rating ?? 0);
214 }
215
216 return round($total / count($reviews), 1);
217 }
218 }
219