PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.6
Yatra – Travel Booking & Tour Operator Software v3.0.2.6
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 / app / Services / BlockDataService.php

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

407 lines 13.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\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 if (defined('WP_DEBUG') && WP_DEBUG) {
157 error_log('Yatra BlockDataService: Render successful, result length: ' . strlen($result));
158 }
159
160 return $result;
161 } catch (\Exception $e) {
162 // Return error message for debugging
163 if (defined('WP_DEBUG') && WP_DEBUG) {
164 error_log('Yatra BlockDataService Exception: ' . $e->getMessage());
165 error_log('Yatra BlockDataService Exception Trace: ' . $e->getTraceAsString());
166 return '<div class="yatra-error">Trip rendering error: ' . esc_html($e->getMessage()) . ' in ' . esc_html($e->getFile()) . ':' . esc_html($e->getLine()) . '</div>';
167 }
168 return '<div class="yatra-error">Trip rendering failed</div>';
169 } catch (\Error $e) {
170 // Catch fatal errors too
171 if (defined('WP_DEBUG') && WP_DEBUG) {
172 error_log('Yatra BlockDataService Error: ' . $e->getMessage());
173 error_log('Yatra BlockDataService Error Trace: ' . $e->getTraceAsString());
174 return '<div class="yatra-error">Trip rendering error: ' . esc_html($e->getMessage()) . ' in ' . esc_html($e->getFile()) . ':' . esc_html($e->getLine()) . '</div>';
175 }
176 return '<div class="yatra-error">Trip rendering failed</div>';
177 }
178 }
179
180 /**
181 * Render trip/tour block - Backward compatibility method
182 *
183 * @param array $attributes Block attributes
184 * @return string Rendered HTML
185 */
186 public static function renderTripBlock(array $attributes): string
187 {
188 return self::renderTrip($attributes);
189 }
190
191 /**
192 * Enqueue trip assets
193 */
194 private static function enqueueTripAssets(): void
195 {
196 wp_enqueue_style('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/css/shortcodes/trip-shortcode.css', array(), '3.0.2.4');
197 wp_enqueue_script('yatra-trip-shortcode', \YATRA_PLUGIN_URL . 'assets/js/trip-shortcode.js', array('jquery'), '3.0.2.4', true);
198
199 // Localize script for AJAX
200 wp_localize_script('yatra-trip-shortcode', 'yatraTripShortcode', [
201 'ajaxurl' => admin_url('admin-ajax.php'),
202 'nonce' => wp_create_nonce('yatra_trip_shortcode_nonce')
203 ]);
204 }
205
206 /**
207 * Load template file
208 */
209 private static function loadTemplate(string $template_path, array $data = []): string
210 {
211 $full_path = \YATRA_PLUGIN_PATH . 'templates/' . $template_path;
212
213 if (!file_exists($full_path)) {
214 if (defined('WP_DEBUG') && WP_DEBUG) {
215 return sprintf(
216 '<div class="yatra-error">Template not found: %s</div>',
217 esc_html($full_path)
218 );
219 }
220 return '';
221 }
222
223 // Extract data to make variables available in template
224 if (!empty($data)) {
225 extract($data);
226 }
227
228 ob_start();
229 include $full_path;
230 return ob_get_clean();
231 }
232
233 /**
234 * Get trips data - copied from TripShortcode
235 */
236 private static function getTrips(array $atts): array
237 {
238 try {
239 $tripService = new \Yatra\Services\TripService();
240
241 // Get current page from query string or attributes (for AJAX)
242 $current_page = isset($atts['current_page']) ? (int) $atts['current_page'] : (isset($_GET['trip_page']) ? (int) $_GET['trip_page'] : 1);
243 $per_page = max(1, (int) ($atts['per_page'] ?? 10));
244 $offset = ($current_page - 1) * $per_page;
245
246 $order = strtolower((string) ($atts['order'] ?? 'desc'));
247
248 // Start with very basic arguments to ensure we get trips
249 $args = [
250 'limit' => $per_page,
251 'offset' => $offset,
252 'order_by' => 'created_at',
253 'order' => $order === 'asc' ? 'ASC' : 'DESC',
254 ];
255
256 // Add featured filter if requested
257 $featured = (string) ($atts['featured'] ?? '0');
258 if ($featured === '1') {
259 $args['where']['is_featured'] = 1;
260 }
261
262 // Get total count for pagination
263 $count_args = $args;
264 unset($count_args['limit']);
265 unset($count_args['offset']);
266 $total_trips = $tripService->count($count_args);
267
268 // Get trips using the service
269 $trips_data = $tripService->getActiveTrips($args);
270
271
272
273 $trips = [];
274 foreach ($trips_data as $tripData) {
275 // Convert to Trip model
276 $trip = \Yatra\Models\Trip::fromStdClass($tripData);
277
278 // Add basic data needed for the card
279 // Note: bookings_count and reviews will be added later
280 // For now, we'll set default values to ensure basic functionality
281 $trip->bookings_count = 0;
282 $trip->reviews = [];
283
284 $trips[] = $trip;
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 if (defined('WP_DEBUG') && WP_DEBUG) {
303 error_log('Yatra BlockDataService Trip Error: ' . $e->getMessage());
304 }
305
306 return [
307 'trips' => [],
308 'max_pages' => 1,
309 'current_page' => 1,
310 'total_found' => 0
311 ];
312 }
313 }
314
315 /**
316 * Render activity block or shortcode
317 *
318 * @param array $attributes Block or shortcode attributes
319 * @return string Rendered HTML
320 */
321 public static function renderActivityBlock(array $attributes): string
322 {
323 // Create shortcode instance to reuse its logic
324 $shortcode = new ActivityShortcode();
325
326 $merged = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultActivityBlockAttributes());
327
328 // Use shortcode's render method
329 return $shortcode->render(self::mapActivityAttributes($merged));
330 }
331
332 /**
333 * Render destination block or shortcode
334 *
335 * @param array $attributes Block or shortcode attributes
336 * @return string Rendered HTML
337 */
338 public static function renderDestinationBlock(array $attributes): string
339 {
340 // Create shortcode instance to reuse its logic
341 $shortcode = new DestinationShortcode();
342
343 $merged = wp_parse_args(is_array($attributes) ? $attributes : [], self::defaultDestinationBlockAttributes());
344
345 // Use shortcode's render method
346 return $shortcode->render(self::mapDestinationAttributes($merged));
347 }
348
349 /**
350 * Map activity block attributes to shortcode format (full set for shortcode_atts merge).
351 *
352 * @param array<string, mixed> $attributes Merged with defaults
353 * @return array<string, string>
354 */
355 private static function mapActivityAttributes(array $attributes): array
356 {
357 $order = strtolower((string) ($attributes['order'] ?? 'asc'));
358 $order = in_array($order, ['asc', 'desc'], true) ? $order : 'asc';
359
360 $perPage = (int) ($attributes['per_page'] ?? 10);
361 if ($perPage === -1) {
362 $perPage = 10;
363 }
364 $perPage = max(1, min(100, $perPage));
365
366 $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3)));
367
368 $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true);
369
370 return [
371 'order' => $order,
372 'per_page' => (string) $perPage,
373 'columns' => (string) $cols,
374 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Activity Listings')),
375 'show_pagination' => $showPag ? 'yes' : 'no',
376 ];
377 }
378
379 /**
380 * @param array<string, mixed> $attributes Merged with defaults
381 * @return array<string, string>
382 */
383 private static function mapDestinationAttributes(array $attributes): array
384 {
385 $order = strtolower((string) ($attributes['order'] ?? 'asc'));
386 $order = in_array($order, ['asc', 'desc'], true) ? $order : 'asc';
387
388 $perPage = (int) ($attributes['per_page'] ?? 10);
389 if ($perPage === -1) {
390 $perPage = 10;
391 }
392 $perPage = max(1, min(100, $perPage));
393
394 $cols = max(1, min(self::LISTING_COLUMNS_MAX, (int) ($attributes['columns'] ?? 3)));
395
396 $showPag = self::coerceToBool($attributes['show_pagination'] ?? true, true);
397
398 return [
399 'order' => $order,
400 'per_page' => (string) $perPage,
401 'columns' => (string) $cols,
402 'title' => sanitize_text_field((string) ($attributes['title'] ?? 'Destination Showcase')),
403 'show_pagination' => $showPag ? 'yes' : 'no',
404 ];
405 }
406 }
407