PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.9
Yatra – Travel Booking & Tour Operator Software v3.0.2.9
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 2.0.10 All 83 releases
yatra / app / Shortcodes / ActivityShortcode.php

ActivityShortcode.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.9, at app/Shortcodes/ActivityShortcode.php

365 lines 13.6 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\Shortcodes;
6
7 use Yatra\Services\SettingsService;
8
9 /**
10 * Activity Shortcode
11 *
12 * Displays activity listings with associated trips using trip-listing-card.php template
13 */
14 class ActivityShortcode extends BaseShortcode
15 {
16 public function __construct()
17 {
18 parent::__construct('yatra_activity', [
19 'order' => 'desc',
20 'per_page' => '10',
21 'columns' => '3',
22 'show_trip_count' => 'yes',
23 'show_description' => 'yes',
24 'show_image' => 'yes',
25 'show_pagination' => 'yes', // Default to show pagination like trip shortcode
26 'activity' => '', // Specific activity slug(s), comma separated
27 'hide_empty' => 'yes',
28 'title' => 'Activity Listings'
29 ]);
30 }
31
32 /**
33 * Render the activity shortcode content
34 */
35 protected function renderContent(array $atts): string
36 {
37 $atts = shortcode_atts($this->default_attributes, $atts, $this->tag);
38
39 // Extract per_page from attributes (only per_page parameter)
40 $per_page = 10; // default
41 if (!empty($atts['per_page']) && is_numeric($atts['per_page'])) {
42 $per_page = (int) $atts['per_page'];
43 }
44 $atts['per_page'] = $per_page;
45
46 // Get activities using Yatra's service
47 $activities_data = $this->getActivities($atts);
48
49 // Prepare data for template
50 $data = [
51 'activities' => $activities_data['activities'] ?? [],
52 'atts' => $atts,
53 'current_page' => $activities_data['current_page'] ?? 1,
54 'max_pages' => $activities_data['max_pages'] ?? 1,
55 'total_found' => $activities_data['total_found'] ?? 0,
56 'per_page' => $per_page
57 ];
58
59 // Enqueue shortcode-specific CSS
60 wp_enqueue_style(
61 'yatra-activity-shortcode',
62 YATRA_PLUGIN_URL . 'assets/css/shortcodes/activity-shortcode.css',
63 [],
64 YATRA_VERSION
65 );
66
67 // Enqueue shortcode-specific JavaScript
68 wp_enqueue_script(
69 'yatra-activity-shortcode',
70 YATRA_PLUGIN_URL . 'assets/js/activity-shortcode.js',
71 ['jquery'],
72 YATRA_VERSION,
73 true
74 );
75
76 // Pass data to JavaScript
77 wp_localize_script('yatra-activity-shortcode', 'yatraActivityShortcode', [
78 'ajaxurl' => admin_url('admin-ajax.php'),
79 'nonce' => wp_create_nonce('yatra_activity_shortcode_nonce')
80 ]);
81
82 return $this->loadTemplate('shortcodes/activity.php', $data);
83 }
84
85 /**
86 * Get activities using Yatra's service
87 */
88 public function getActivities(array $atts): array
89 {
90 try {
91 $activityService = new \Yatra\Services\ActivityService();
92
93 // Get current page from query string or attributes (for AJAX)
94 $current_page = isset($atts['current_page']) ? (int) $atts['current_page'] : (isset($_GET['activity_page']) ? (int) $_GET['activity_page'] : 1);
95 // Enhanced per_page handling with validation and debugging
96
97 $per_page = (int) $atts['per_page'];
98
99
100 // Validate per_page to prevent issues
101 $per_page = max(1, min($per_page, 100)); // Between 1 and 100 items
102 $offset = ($current_page - 1) * $per_page;
103
104 // Start with very basic arguments to ensure we get activities
105 $args = [
106 'limit' => $per_page,
107 'offset' => $offset,
108 'order_by' => 'name',
109 'order' => $atts['order'] === 'asc' ? 'ASC' : 'DESC'
110 ];
111
112 // Filter by specific activities if provided
113 if (!empty($atts['activity'])) {
114 $args['where']['slug'] = explode(',', $atts['activity']);
115 }
116
117 // Get total count for pagination
118 $count_args = $args;
119 unset($count_args['limit']);
120 unset($count_args['offset']);
121 $total_activities = $activityService->count($count_args);
122
123 // Try using the base repository method to bypass status filtering
124 $result = $activityService->getAll($args);
125
126
127
128 $activities = [];
129
130 foreach ($result as $activityData) {
131
132
133 // Get real trip data for this activity using classification tables
134 global $wpdb;
135
136 $tripClassificationsTable = \Yatra\Database\Tables\TripClassificationsTable::getTableName();
137 $tripsTable = \Yatra\Database\Tables\TripsTable::getTableName();
138
139 // Get trip IDs for this activity
140 $trip_ids = $wpdb->get_col($wpdb->prepare(
141 "SELECT tc.trip_id
142 FROM {$tripClassificationsTable} tc
143 INNER JOIN {$tripsTable} t ON tc.trip_id = t.id
144 WHERE tc.classification_id = %d
145 AND tc.classification_type = 'activity'
146 AND t.status = 'publish'",
147 $activityData->id
148 ));
149
150 $trip_count = count($trip_ids);
151
152 // Get actual trips
153 $trips = [];
154 if (!empty($trip_ids)) {
155 $placeholders = implode(',', array_fill(0, count($trip_ids), '%d'));
156 $trips = $wpdb->get_results($wpdb->prepare(
157 "SELECT * FROM {$tripsTable}
158 WHERE id IN ({$placeholders})
159 AND status = 'publish'
160 ORDER BY created_at DESC
161 LIMIT 6",
162 ...$trip_ids
163 ));
164 }
165
166 // Calculate pricing from real trips
167 $min_price = null;
168 $max_price = null;
169 $durations = [];
170 $group_sizes = [];
171 $difficulties = [];
172
173 // Calculate rating from reviews table directly
174 $total_rating_sum = 0;
175 $total_review_count = 0;
176
177 if (!empty($trip_ids)) {
178 $reviewsTable = \Yatra\Database\Tables\ReviewsTable::getTableName();
179 $placeholders = implode(',', array_fill(0, count($trip_ids), '%d'));
180
181 $reviews = $wpdb->get_results($wpdb->prepare(
182 "SELECT rating, COUNT(*) as review_count
183 FROM {$reviewsTable}
184 WHERE trip_id IN ({$placeholders})
185 AND status = 'approved'",
186 ...$trip_ids
187 ));
188
189
190 foreach ($reviews as $review) {
191 $total_rating_sum += $review->rating * $review->review_count;
192 $total_review_count += $review->review_count;
193
194 }
195 }
196
197 // Calculate average rating only for trips that actually have reviews
198 // Trips with no reviews are excluded from the average (not treated as 0 rating)
199 $avg_rating = $total_review_count > 0 ? $total_rating_sum / $total_review_count : 0;
200
201 foreach ($trips as $trip) {
202 // Debug: Log all trip data to see what fields exist
203
204
205 // Get pricing via centralized TripPricingService
206 $effective = \Yatra\Services\TripPricingService::getEffectivePrice($trip);
207 if ($effective > 0) {
208 if ($min_price === null || $effective < $min_price) {
209 $min_price = $effective;
210 }
211 if ($max_price === null || $effective > $max_price) {
212 $max_price = $effective;
213 }
214 }
215
216 // Get duration
217 if (!empty($trip->duration)) {
218 $durations[] = $trip->duration;
219 }
220
221 // Get group size
222 if (!empty($trip->max_group_size)) {
223 $group_sizes[] = $trip->max_group_size;
224 }
225
226 // Get difficulty
227 if (!empty($trip->difficulty)) {
228 $difficulties[] = $trip->difficulty;
229 }
230 }
231
232 // Calculate averages
233 $final_avg_rating = $avg_rating; // Already calculated correctly above
234 $avg_duration = !empty($durations) ? array_sum($durations) / count($durations) : 0;
235 $avg_group_size = !empty($group_sizes) ? round(array_sum($group_sizes) / count($group_sizes)) : 0;
236
237
238
239 $activities[] = [
240 'term' => $activityData,
241 'trips' => $trips,
242 'trip_count' => $trip_count,
243 'description' => $activityData->description ?? '',
244 'image' => $this->getActivityImage($activityData),
245 'link' => $this->getActivityLink($activityData),
246 'min_price' => $min_price,
247 'max_price' => $max_price,
248 'avg_rating' => $final_avg_rating,
249 'rating_count' => $total_review_count,
250 'avg_duration' => $avg_duration,
251 'avg_group_size' => $avg_group_size,
252 'difficulty' => !empty($difficulties) ? $this->getMostCommonDifficulty($difficulties) : null
253 ];
254 }
255
256 // Filter out empty activities if requested
257 if ($atts['hide_empty'] === 'yes') {
258 $activities = array_filter($activities, function($activity) {
259 return !empty($activity['term']->name) && !empty($activity['term']->slug);
260 });
261 }
262
263 // Calculate pagination data
264 $max_pages = $per_page > 0 ? ceil($total_activities / $per_page) : 1;
265
266
267
268 return [
269 'activities' => $activities,
270 'current_page' => $current_page,
271 'max_pages' => $max_pages,
272 'total_found' => $total_activities,
273 'per_page' => $per_page
274 ];
275
276 } catch (\Exception $e) {
277
278 return [];
279 }
280 }
281
282 /**
283 * Get the most common difficulty from an array of difficulties
284 */
285 private function getMostCommonDifficulty(array $difficulties): string
286 {
287 if (empty($difficulties)) {
288 return 'Moderate';
289 }
290
291 $counts = array_count_values($difficulties);
292 arsort($counts);
293 return array_key_first($counts);
294 }
295
296
297 /**
298 * Get activity image
299 */
300 private function getActivityImage($activity): string
301 {
302 // Check for activity image in metadata
303 if (isset($activity->image) && !empty($activity->image)) {
304 return $activity->image;
305 }
306
307 // Check for activity icon in metadata
308 if (isset($activity->icon) && !empty($activity->icon)) {
309 $icon_data = maybe_unserialize($activity->icon);
310 if (is_array($icon_data) && isset($icon_data['type']) && $icon_data['type'] === 'image') {
311 return is_numeric($icon_data['value']) ? wp_get_attachment_url($icon_data['value']) : $icon_data['value'];
312 }
313 }
314
315 // Check for activity thumbnail/featured image
316 if (isset($activity->thumbnail) && !empty($activity->thumbnail)) {
317 return is_numeric($activity->thumbnail) ? wp_get_attachment_url($activity->thumbnail) : $activity->thumbnail;
318 }
319
320 // Check for activity banner
321 if (isset($activity->banner) && !empty($activity->banner)) {
322 return $activity->banner;
323 }
324
325 // Check for metadata with image
326 if (isset($activity->metadata) && !empty($activity->metadata)) {
327 $metadata = maybe_unserialize($activity->metadata);
328 if (is_array($metadata)) {
329 // Check for various image fields in metadata
330 $image_fields = ['image', 'thumbnail', 'banner', 'featured_image', 'cover_image'];
331 foreach ($image_fields as $field) {
332 if (isset($metadata[$field]) && !empty($metadata[$field])) {
333 return is_numeric($metadata[$field]) ? wp_get_attachment_url($metadata[$field]) : $metadata[$field];
334 }
335 }
336 }
337 }
338
339 // Fallback to placeholder
340 $fallback_url = YATRA_PLUGIN_URL . 'assets/images/placeholder.png';
341
342
343
344 return $fallback_url;
345 }
346
347 /**
348 * Get activity link
349 */
350 private function getActivityLink($activity): string
351 {
352 if (isset($activity->slug)) {
353 // Use permalink helper so global base + plain permalinks are respected
354 if (function_exists('yatra_get_activity_permalink')) {
355 return yatra_get_activity_permalink($activity);
356 }
357
358 $base = SettingsService::getString('activity_base', 'activity');
359 return home_url('/' . $base . '/' . $activity->slug . '/');
360 }
361
362 return '#'; // Fallback
363 }
364 }
365