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 / Services / BlockDataService.php

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

405 lines 13.1 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\Services;
6
7 use Yatra\Shortcodes\ActivityShortcode;
8 use Yatra\Shortcodes\DestinationShortcode;
9
10 /**
11 * Block Data Service
12 *
13 * Shared service for rendering blocks and shortcodes
14 * Provides reusable data fetching and template rendering logic
15 *
16 * @package Yatra\Services
17 * @since 3.0.0
18 */
19 class BlockDataService
20 {
21 /** Max grid columns for tour / activity / destination listing blocks (matches block editor RangeControl). */
22 private const LISTING_COLUMNS_MAX = 6;
23
24 /**
25 * Defaults aligned with each block's block.json (REST and ServerSideRender rely on full merge).
26 *
27 * @return array<string, mixed>
28 */
29 private static function defaultTourBlockAttributes(): array
30 {
31 return [
32 'order' => 'desc',
33 'featured' => false,
34 'per_page' => 10,
35 'columns' => 3,
36 'title' => 'Our Trips',
37 'show_pagination' => true,
38 ];
39 }
40
41 /**
42 * @return array<string, mixed>
43 */
44 private static function defaultActivityBlockAttributes(): array
45 {
46 return [
47 'order' => 'asc',
48 'columns' => 3,
49 'per_page' => 10,
50 'title' => 'Activity Listings',
51 'show_pagination' => true,
52 ];
53 }
54
55 /**
56 * @return array<string, mixed>
57 */
58 private static function defaultDestinationBlockAttributes(): array
59 {
60 return [
61 'order' => 'asc',
62 'columns' => 3,
63 'per_page' => 10,
64 'title' => 'Destination Showcase',
65 'show_pagination' => true,
66 ];
67 }
68
69 /**
70 * Coerce REST/block booleans and legacy string values.
71 *
72 * @param mixed $value
73 */
74 private static function coerceToBool($value, bool $default): bool
75 {
76 if ($value === null || $value === '') {
77 return $default;
78 }
79 if (is_bool($value)) {
80 return $value;
81 }
82 if (is_int($value) || is_float($value)) {
83 return (bool) $value;
84 }
85 $s = strtolower((string) $value);
86
87 return in_array($s, ['1', 'true', 'yes', 'on'], true);
88 }
89
90 /**
91 * Normalize trip/tour attributes in place (shortcode extras like category are preserved).
92 *
93 * @param array<string, mixed> $atts
94 */
95 private static function normalizeTripShortcodeAttributes(array &$atts): void
96 {
97 $order = strtolower((string) ($atts['order'] ?? 'desc'));
98 $atts['order'] = in_array($order, ['asc', 'desc'], true) ? $order : 'desc';
99
100 $atts['featured'] = self::coerceToBool($atts['featured'] ?? false, false) ? '1' : '0';
101
102 $perPage = (int) ($atts['per_page'] ?? 10);
103 if ($perPage === -1) {
104 $perPage = 10;
105 }
106 $atts['per_page'] = (string) max(1, min(100, $perPage));
107
108 $cols = (int) ($atts['columns'] ?? 3);
109 $atts['columns'] = (string) max(1, min(self::LISTING_COLUMNS_MAX, $cols));
110
111 $atts['title'] = sanitize_text_field((string) ($atts['title'] ?? 'Our Trips'));
112
113 $atts['show_pagination'] = self::coerceToBool($atts['show_pagination'] ?? true, true) ? 'yes' : 'no';
114 }
115
116 /**
117 * Render trip/tour - Shared method for both blocks and shortcodes
118 *
119 * @param array $attributes Block or shortcode attributes
120 * @return string Rendered HTML
121 */
122 public static function renderTrip(array $attributes): string
123 {
124 try {
125 $atts = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultTourBlockAttributes());
126 self::normalizeTripShortcodeAttributes($atts);
127
128 // Get trips using Yatra's service
129 $trips_data = self::getTrips($atts);
130
131 $per_page = max(1, (int) ($atts['per_page'] ?? 10));
132 $atts['per_page'] = $per_page;
133
134 // Prepare data for template
135 $data = [
136 'trips' => [
137 'trips' => $trips_data['trips'] ?? [],
138 'max_pages' => $trips_data['max_pages'] ?? 1,
139 'current_page' => $trips_data['current_page'] ?? 1,
140 'total_found' => $trips_data['total_found'] ?? 0,
141 'per_page' => $per_page
142 ],
143 'atts' => $atts,
144 'current_page' => $trips_data['current_page'] ?? 1,
145 'max_pages' => $trips_data['max_pages'] ?? 1,
146 'total_found' => $trips_data['total_found'] ?? 0,
147 'per_page' => $per_page
148 ];
149
150 // Enqueue assets
151 self::enqueueTripAssets();
152
153 // Load template
154 $result = self::loadTemplate('shortcodes/trip.php', $data);
155
156
157 return $result;
158 } catch (\Exception $e) {
159
160 return '<div class="yatra-error">Trip rendering failed</div>';
161 } catch (\Error $e) {
162
163 return '<div class="yatra-error">Trip rendering failed</div>';
164 }
165 }
166
167 /**
168 * Render trip/tour block - Backward compatibility method
169 *
170 * @param array $attributes Block attributes
171 * @return string Rendered HTML
172 */
173 public static function renderTripBlock(array $attributes): string
174 {
175 return self::renderTrip($attributes);
176 }
177
178 /**
179 * Enqueue trip assets
180 */
181 private static function enqueueTripAssets(): void
182 {
183 wp_enqueue_style('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/css/shortcodes/trip-shortcode.css', array(), '3.0.2.4');
184 wp_enqueue_script('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/js/trip-shortcode.js', array('jquery'), '3.0.2.4', true);
185
186 // Localize script for AJAX
187 wp_localize_script('yatra-trip-shortcode', 'yatraTripShortcode', [
188 'ajaxurl' => admin_url('admin-ajax.php'),
189 'nonce' => wp_create_nonce('yatra_trip_shortcode_nonce')
190 ]);
191 }
192
193 /**
194 * Load template file
195 */
196 private static function loadTemplate(string $template_path, array $data = []): string
197 {
198 $full_path = \YATRA_PLUGIN_PATH . 'templates/' . $template_path;
199
200 if (!file_exists($full_path)) {
201 if (defined('WP_DEBUG') && WP_DEBUG) {
202 return sprintf(
203 '<div class="yatra-error">Template not found: %s</div>',
204 esc_html($full_path)
205 );
206 }
207 return '';
208 }
209
210 // Extract data to make variables available in template
211 if (!empty($data)) {
212 extract($data);
213 }
214
215 ob_start();
216 include $full_path;
217 return ob_get_clean();
218 }
219
220 /**
221 * Get trips data - copied from TripShortcode
222 */
223 private static function getTrips(array $atts): array
224 {
225 try {
226 $tripService = new \Yatra\Services\TripService();
227
228 // Get current page from query string or attributes (for AJAX)
229 $current_page = isset($atts['current_page']) ? (int) $atts['current_page'] : (isset($_GET['trip_page']) ? (int) $_GET['trip_page'] : 1);
230 $per_page = max(1, (int) ($atts['per_page'] ?? 10));
231 $offset = ($current_page - 1) * $per_page;
232
233 $order = strtolower((string) ($atts['order'] ?? 'desc'));
234
235 // Start with very basic arguments to ensure we get trips
236 $args = [
237 'limit' => $per_page,
238 'offset' => $offset,
239 'order_by' => 'created_at',
240 'order' => $order === 'asc' ? 'ASC' : 'DESC',
241 ];
242
243 // Add featured filter if requested
244 $featured = (string) ($atts['featured'] ?? '0');
245 if ($featured === '1') {
246 $args['where']['is_featured'] = 1;
247 }
248
249 // Get total count for pagination
250 $count_args = $args;
251 unset($count_args['limit']);
252 unset($count_args['offset']);
253 $total_trips = $tripService->count($count_args);
254
255 // Get trips using the service
256 $trips_data = $tripService->getActiveTrips($args);
257
258
259
260 $trips = [];
261 foreach ($trips_data as $tripData) {
262 // Convert to Trip model
263 $trip = \Yatra\Models\Trip::fromStdClass($tripData);
264
265 // Add basic data needed for the card
266 // Note: reviews are loaded elsewhere; bookings_count is attached below
267 $trip->reviews = [];
268
269 $trips[] = $trip;
270 }
271
272 // Attach bookings_count (computed from bookings table) for just these trips
273 $tripIds = array_map(static function ($t) {
274 return isset($t->id) ? (int) $t->id : 0;
275 }, $trips);
276 $tripIds = array_values(array_filter($tripIds));
277 if (!empty($tripIds)) {
278 $bookingsCountMap = $tripService->getBookingsCountMap($tripIds);
279 foreach ($trips as $t) {
280 $tId = isset($t->id) ? (int) $t->id : 0;
281 if ($tId > 0) {
282 $t->bookings_count = (int) ($bookingsCountMap[$tId] ?? 0);
283 }
284 }
285 }
286
287 // Calculate pagination data
288 $max_pages = $per_page > 0 ? ceil($total_trips / $per_page) : 1;
289
290 return [
291 'trips' => $trips,
292 'max_pages' => $max_pages,
293 'current_page' => $current_page,
294 'total_found' => $total_trips,
295 'debug_info' => [
296 'args_used' => $args,
297 'raw_count' => count($trips_data)
298 ]
299 ];
300
301 } catch (\Exception $e) {
302
303
304 return [
305 'trips' => [],
306 'max_pages' => 1,
307 'current_page' => 1,
308 'total_found' => 0
309 ];
310 }
311 }
312
313 /**
314 * Render activity block or shortcode
315 *
316 * @param array $attributes Block or shortcode attributes
317 * @return string Rendered HTML
318 */
319 public static function renderActivityBlock(array $attributes): string
320 {
321 // Create shortcode instance to reuse its logic
322 $shortcode = new ActivityShortcode();
323
324 $merged = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultActivityBlockAttributes());
325
326 // Use shortcode's render method
327 return $shortcode->render(self::mapActivityAttributes($merged));
328 }
329
330 /**
331 * Render destination block or shortcode
332 *
333 * @param array $attributes Block or shortcode attributes
334 * @return string Rendered HTML
335 */
336 public static function renderDestinationBlock(array $attributes): string
337 {
338 // Create shortcode instance to reuse its logic
339 $shortcode = new DestinationShortcode();
340
341 $merged = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultDestinationBlockAttributes());
342
343 // Use shortcode's render method
344 return $shortcode->render(self::mapDestinationAttributes($merged));
345 }
346
347 /**
348 * Map activity block attributes to shortcode format (full set for shortcode_atts merge).
349 *
350 * @param array<string, mixed> $attributes Merged with defaults
351 * @return array<string, string>
352 */
353 private static function mapActivityAttributes(array $attributes): array
354 {
355 $order = strtolower((string) ($attributes['order'] ?? 'asc'));
356 $order = in_array($order, ['asc', 'desc'], true) ? $order : 'asc';
357
358 $perPage = (int) ($attributes['per_page'] ?? 10);
359 if ($perPage === -1) {
360 $perPage = 10;
361 }
362 $perPage = max(1, min(100, $perPage));
363
364 $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3)));
365
366 $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true);
367
368 return [
369 'order' => $order,
370 'per_page' => (string) $perPage,
371 'columns' => (string) $cols,
372 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Activity Listings')),
373 'show_pagination' => $showPag ? 'yes' : 'no',
374 ];
375 }
376
377 /**
378 * @param array<string, mixed> $attributes Merged with defaults
379 * @return array<string, string>
380 */
381 private static function mapDestinationAttributes(array $attributes): array
382 {
383 $order = strtolower((string) ($attributes['order'] ?? 'asc'));
384 $order = in_array($order, ['asc', 'desc'], true) ? $order : 'asc';
385
386 $perPage = (int) ($attributes['per_page'] ?? 10);
387 if ($perPage === -1) {
388 $perPage = 10;
389 }
390 $perPage = max(1, min(100, $perPage));
391
392 $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3)));
393
394 $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true);
395
396 return [
397 'order' => $order,
398 'per_page' => (string) $perPage,
399 'columns' => (string) $cols,
400 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Destination Showcase')),
401 'show_pagination' => $showPag ? 'yes' : 'no',
402 ];
403 }
404 }
405