PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.8
Yatra – Travel Booking & Tour Operator Software v3.0.2.8
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.8, at app/Shortcodes/ActivityShortcode.php

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