PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.3
Yatra – Travel Booking & Tour Operator Software v3.0.3
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 / Repositories / SampleDataRepository.php

SampleDataRepository.php in Yatra – Travel Booking & Tour Operator Software 3.0.3, at app/Repositories/SampleDataRepository.php

797 lines 31.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 namespace Yatra\Repositories;
4
5 use Yatra\Database\Tables\TripsTable;
6 use Yatra\Database\Tables\ClassificationsTable;
7 use Yatra\Database\Tables\TripClassificationsTable;
8 use Yatra\Database\Tables\DiscountsTable;
9 use Yatra\Database\Tables\TripAvailabilityDatesTable;
10 use Yatra\Database\Tables\TripAvailabilityRulesTable;
11 use Yatra\Database\Tables\TripItineraryDaysTable;
12 use Yatra\Database\Tables\TripItineraryDayEntryTable;
13 use Yatra\Database\Tables\TripContentTable;
14
15 /**
16 * Sample Data Repository
17 *
18 * Handles database operations for sample data import.
19 * Inserts data into all required tables matching the exact structure
20 * that the real UI/API/Service layer uses.
21 */
22 class SampleDataRepository
23 {
24 private $wpdb;
25
26 private $trips_table;
27 private $classifications_table;
28 private $trip_classifications_table;
29 private $discounts_table;
30 private $availability_dates_table;
31 private $availability_rules_table;
32 private $itinerary_days_table;
33 private $itinerary_entries_table;
34 private $trip_content_table;
35
36 /**
37 * Tracks inserted classification type:slug => id mapping.
38 * Uses composite key to avoid slug collisions across types.
39 */
40 private $classification_ids = [];
41
42 /**
43 * Simple slug => id mapping (last wins) for backward compat.
44 */
45 private $slug_to_id = [];
46
47 public function __construct()
48 {
49 global $wpdb;
50 $this->wpdb = $wpdb;
51
52 $this->trips_table = TripsTable::getTableName();
53 $this->classifications_table = ClassificationsTable::getTableName();
54 $this->trip_classifications_table = TripClassificationsTable::getTableName();
55 $this->discounts_table = DiscountsTable::getTableName();
56 $this->availability_dates_table = TripAvailabilityDatesTable::getTableName();
57 $this->availability_rules_table = TripAvailabilityRulesTable::getTableName();
58 $this->itinerary_days_table = TripItineraryDaysTable::getTableName();
59 $this->itinerary_entries_table = TripItineraryDayEntryTable::getTableName();
60 $this->trip_content_table = TripContentTable::getTableName();
61 }
62
63 /**
64 * Get sample data directory path
65 */
66 private function get_sample_data_dir()
67 {
68 return YATRA_ABSPATH . 'sample-data/';
69 }
70
71 /**
72 * Read JSON file
73 */
74 private function read_json_file($filename)
75 {
76 $file_path = $this->get_sample_data_dir() . $filename;
77
78 if (!file_exists($file_path)) {
79 return [];
80 }
81
82 $json_content = file_get_contents($file_path);
83 $data = json_decode($json_content, true);
84
85 if (json_last_error() !== JSON_ERROR_NONE) {
86 return [];
87 }
88
89 return $data;
90 }
91
92 /**
93 * Get all sample data from JSON files
94 */
95 public function get_all_sample_data()
96 {
97 return [
98 'categories' => $this->read_json_file('categories.json'),
99 'activities' => $this->read_json_file('activities.json'),
100 'destinations' => $this->read_json_file('destinations.json'),
101 'difficulty_levels' => $this->read_json_file('difficulty-levels.json'),
102 'attributes' => $this->read_json_file('attributes.json'),
103 'item_types' => $this->read_json_file('item-types.json'),
104 'traveler_categories' => $this->read_json_file('traveler-categories.json'),
105 'items' => $this->read_json_file('items.json'),
106 'discounts' => $this->read_json_file('discounts.json'),
107 'trips' => $this->read_json_file('trips.json'),
108 'trip_classifications' => $this->read_json_file('trip-classifications.json'),
109 'availability_dates' => $this->read_json_file('availability-dates.json'),
110 'availability_rules' => $this->read_json_file('availability-rules.json'),
111 'itinerary_days' => $this->read_json_file('itinerary-days.json'),
112 'itinerary_entries' => $this->read_json_file('itinerary-entries.json'),
113 ];
114 }
115
116 /**
117 * Get the tracked classification IDs (slug => id)
118 */
119 public function get_classification_ids()
120 {
121 return $this->classification_ids;
122 }
123
124 /**
125 * Insert classifications and track their IDs by slug.
126 * Returns the count of inserted records.
127 */
128 public function insert_classifications($data)
129 {
130 $inserted = 0;
131 $now = current_time('mysql');
132 $uid = get_current_user_id();
133
134 foreach ($data as $item) {
135 // Track the slug before inserting
136 $slug = $item['slug'] ?? '';
137
138 // Set defaults for required fields
139 $item['created_at'] = $item['created_at'] ?? $now;
140 $item['updated_at'] = $item['updated_at'] ?? $now;
141 $item['created_by'] = $item['created_by'] ?? $uid;
142 $item['updated_by'] = $item['updated_by'] ?? $uid;
143 $item['parent_id'] = $item['parent_id'] ?? null;
144 $item['level'] = $item['level'] ?? 0;
145 $item['sorting'] = $item['sorting'] ?? 0;
146 $item['is_featured'] = $item['is_featured'] ?? 0;
147
148 // Convert metadata to JSON if it's an array
149 if (isset($item['metadata']) && is_array($item['metadata'])) {
150 $item['metadata'] = json_encode($item['metadata']);
151 }
152
153 $result = $this->wpdb->insert($this->classifications_table, $item);
154
155 if ($result && $this->wpdb->insert_id) {
156 $inserted++;
157 $id = $this->wpdb->insert_id;
158 $type = $item['type'] ?? '';
159 // Track by composite key (type:slug) and simple slug
160 if ($slug) {
161 $this->classification_ids[$type . ':' . $slug] = $id;
162 $this->slug_to_id[$slug] = $id;
163 }
164 } else {
165 }
166 }
167
168 return $inserted;
169 }
170
171 /**
172 * Insert items (type='item') with parent_id resolved from item_type slugs.
173 * Items use parent_slug to reference their item_type.
174 */
175 public function insert_items($data)
176 {
177 $inserted = 0;
178 $now = current_time('mysql');
179 $uid = get_current_user_id();
180
181 foreach ($data as $item) {
182 $slug = $item['slug'] ?? '';
183 $parent_slug = $item['parent_slug'] ?? '';
184 unset($item['parent_slug']);
185
186 // Resolve parent_id from the item_type slug using composite key
187 $parent_key = 'item_type:' . $parent_slug;
188 if ($parent_slug && isset($this->classification_ids[$parent_key])) {
189 $item['parent_id'] = $this->classification_ids[$parent_key];
190 } else {
191 $item['parent_id'] = null;
192 if ($parent_slug) {
193 }
194 }
195
196 $item['created_at'] = $item['created_at'] ?? $now;
197 $item['updated_at'] = $item['updated_at'] ?? $now;
198 $item['created_by'] = $item['created_by'] ?? $uid;
199 $item['updated_by'] = $item['updated_by'] ?? $uid;
200 $item['level'] = $item['level'] ?? 0;
201 $item['sorting'] = $item['sorting'] ?? 0;
202 $item['is_featured'] = $item['is_featured'] ?? 0;
203
204 if (isset($item['metadata']) && is_array($item['metadata'])) {
205 $item['metadata'] = json_encode($item['metadata']);
206 }
207
208 $result = $this->wpdb->insert($this->classifications_table, $item);
209
210 if ($result && $this->wpdb->insert_id) {
211 $inserted++;
212 $id = $this->wpdb->insert_id;
213 if ($slug) {
214 $this->classification_ids['item:' . $slug] = $id;
215 $this->slug_to_id[$slug] = $id;
216 }
217 }
218 }
219
220 return $inserted;
221 }
222
223 /**
224 * Insert trip-classification pivot records.
225 * Links trips to their categories, activities, destinations, difficulty, traveler_types.
226 */
227 public function insert_trip_classifications($data, $trip_ids)
228 {
229 $inserted = 0;
230 $now = current_time('mysql');
231
232 foreach ($data as $mapping) {
233 $trip_slug = $mapping['trip_slug'] ?? '';
234 if (!isset($trip_ids[$trip_slug])) {
235 continue;
236 }
237 $trip_id = $trip_ids[$trip_slug];
238
239 $classifications = $mapping['classifications'] ?? [];
240
241 // Track index per classification type so first of each type gets 'primary'
242 // This matches how TripRepository::saveDestinations/saveActivities works
243 $type_counters = [];
244
245 foreach ($classifications as $classification) {
246 $cls_slug = $classification['slug'] ?? '';
247 $cls_type = $classification['type'] ?? '';
248
249 if (!$cls_slug || !$cls_type) {
250 continue;
251 }
252
253 // Look up the classification ID using composite key (type:slug)
254 $composite_key = $cls_type . ':' . $cls_slug;
255 if (!isset($this->classification_ids[$composite_key])) {
256 // Try to find it in DB if not tracked (might already exist)
257 $existing = $this->wpdb->get_var($this->wpdb->prepare(
258 "SELECT id FROM {$this->classifications_table} WHERE slug = %s AND type = %s LIMIT 1",
259 $cls_slug, $cls_type
260 ));
261 if ($existing) {
262 $this->classification_ids[$composite_key] = (int) $existing;
263 } else {
264 continue;
265 }
266 }
267
268 $classification_id = $this->classification_ids[$composite_key];
269
270 // Per-type index for relationship_type and sort_order
271 if (!isset($type_counters[$cls_type])) {
272 $type_counters[$cls_type] = 0;
273 }
274 $type_index = $type_counters[$cls_type];
275 $type_counters[$cls_type]++;
276
277 $metadata_json = null;
278 if ($cls_type === 'attribute') {
279 if (!empty($classification['metadata']) && is_array($classification['metadata'])) {
280 $metadata_json = wp_json_encode($classification['metadata']);
281 } elseif (array_key_exists('value', $classification) || !empty($classification['field_type'])) {
282 $metadata_json = wp_json_encode([
283 'field_type' => $classification['field_type'] ?? 'text_field',
284 'value' => $classification['value'] ?? '',
285 ]);
286 }
287 } elseif (!empty($classification['metadata'])) {
288 $meta = $classification['metadata'];
289 $metadata_json = is_string($meta) ? $meta : wp_json_encode($meta);
290 }
291
292 $result = $this->wpdb->insert(
293 $this->trip_classifications_table,
294 [
295 'trip_id' => $trip_id,
296 'classification_id' => $classification_id,
297 'classification_type' => $cls_type,
298 'relationship_type' => $type_index === 0 ? 'primary' : 'secondary',
299 'metadata' => $metadata_json,
300 'sort_order' => $type_index,
301 'is_featured' => $type_index === 0 ? 1 : 0,
302 'is_active' => 1,
303 'created_at' => $now,
304 'updated_at' => $now,
305 ],
306 ['%d', '%d', '%s', '%s', '%s', '%d', '%d', '%d', '%s', '%s']
307 );
308
309 if ($result) {
310 $inserted++;
311 }
312 }
313 }
314
315 return $inserted;
316 }
317
318 /**
319 * Insert discounts
320 */
321 public function insert_discounts($data)
322 {
323 $inserted = 0;
324 $now = current_time('mysql');
325 $future = date('Y-m-d H:i:s', strtotime('+6 months'));
326 $uid = get_current_user_id();
327
328 foreach ($data as $item) {
329 $item['created_at'] = $item['created_at'] ?? $now;
330 $item['updated_at'] = $item['updated_at'] ?? $now;
331 $item['created_by'] = $item['created_by'] ?? $uid;
332 $item['updated_by'] = $item['updated_by'] ?? $uid;
333 $item['usage_count'] = $item['usage_count'] ?? 0;
334 $item['usage_limit_per_customer'] = $item['usage_limit_per_customer'] ?? 0;
335 $item['applicable_to'] = $item['applicable_to'] ?? 'all';
336 $item['first_time_customer_only'] = $item['first_time_customer_only'] ?? 0;
337 $item['is_group_discount'] = $item['is_group_discount'] ?? 0;
338 $item['discount_mode'] = $item['discount_mode'] ?? 'both';
339 $item['valid_from'] = $item['valid_from'] ?? $now;
340 $item['expiry_date'] = $item['expiry_date'] ?? $future;
341
342 $result = $this->wpdb->insert($this->discounts_table, $item);
343 if ($result) {
344 $inserted++;
345 }
346 }
347
348 return $inserted;
349 }
350
351 /**
352 * Insert trips. Returns slug => id mapping.
353 */
354 public function insert_trips($data)
355 {
356 $trip_ids = [];
357 $now = current_time('mysql');
358 $uid = get_current_user_id();
359
360 foreach ($data as $item) {
361 $trip_slug = $item['slug'];
362
363 $item['created_at'] = $item['created_at'] ?? $now;
364 $item['updated_at'] = $item['updated_at'] ?? $now;
365 $item['created_by'] = $item['created_by'] ?? $uid;
366 $item['updated_by'] = $item['updated_by'] ?? $uid;
367
368 // Resolve price_types: convert traveler_category slugs to category_id
369 // and map field names (price→original_price, sale_price→discounted_price)
370 if (!empty($item['price_types'])) {
371 $price_types_raw = $item['price_types'];
372
373 // Decode if it's a JSON string
374 if (is_string($price_types_raw)) {
375 $price_types_raw = json_decode($price_types_raw, true);
376 }
377
378 if (is_array($price_types_raw) && !empty($price_types_raw)) {
379 $resolved_price_types = [];
380 foreach ($price_types_raw as $pt) {
381 $resolved = [];
382
383 // Resolve traveler_category slug to numeric category_id
384 // Composite key uses 'traveler_type:' (matches type field in classifications table)
385 if (isset($pt['traveler_category'])) {
386 $slug = $pt['traveler_category'];
387 $composite_key = 'traveler_type:' . $slug;
388 if (isset($this->classification_ids[$composite_key])) {
389 $resolved['category_id'] = $this->classification_ids[$composite_key];
390 } elseif (isset($this->slug_to_id[$slug])) {
391 $resolved['category_id'] = $this->slug_to_id[$slug];
392 } else {
393 // Keep slug as label fallback
394 $resolved['category_id'] = null;
395 $resolved['label'] = ucfirst(str_replace('-', ' ', $slug));
396 }
397 } elseif (isset($pt['category_id'])) {
398 $resolved['category_id'] = $pt['category_id'];
399 }
400
401 // Map field names: price → original_price, sale_price → discounted_price
402 $resolved['original_price'] = (float) ($pt['original_price'] ?? $pt['price'] ?? 0);
403 $resolved['discounted_price'] = (float) ($pt['discounted_price'] ?? $pt['sale_price'] ?? 0);
404
405 if (isset($resolved['label'])) {
406 // Keep label for fallback display
407 }
408
409 $resolved_price_types[] = $resolved;
410 }
411
412 $item['price_types'] = wp_json_encode($resolved_price_types);
413
414 // Auto-set pricing_type to traveler_based when price_types exist
415 if (empty($item['pricing_type']) || $item['pricing_type'] === 'regular') {
416 $item['pricing_type'] = 'traveler_based';
417 }
418 } else {
419 $item['price_types'] = null;
420 }
421 }
422
423 // Ensure other JSON fields are properly encoded
424 foreach (['included_items', 'excluded_items', 'frontend_tabs', 'custom_fields'] as $jsonField) {
425 if (isset($item[$jsonField]) && is_array($item[$jsonField])) {
426 $item[$jsonField] = wp_json_encode($item[$jsonField]);
427 }
428 }
429
430 $result = $this->wpdb->insert($this->trips_table, $item);
431
432 if ($result && $this->wpdb->insert_id) {
433 $trip_ids[$trip_slug] = $this->wpdb->insert_id;
434 } else {
435 }
436 }
437
438 return $trip_ids;
439 }
440
441 /**
442 * Insert availability dates
443 */
444 public function insert_availability_dates($data, $trip_ids)
445 {
446 $inserted = 0;
447
448 foreach ($data as $item) {
449 $trip_slug = $item['trip_slug'];
450 unset($item['trip_slug']);
451
452 if (!isset($trip_ids[$trip_slug])) {
453 continue;
454 }
455 $item['trip_id'] = $trip_ids[$trip_slug];
456
457 if (empty($item['return_date']) && !empty($item['arrival_date'])) {
458 $item['return_date'] = $item['arrival_date'];
459 }
460
461 $result = $this->wpdb->insert($this->availability_dates_table, $item);
462 if ($result) {
463 $inserted++;
464 }
465 }
466
467 return $inserted;
468 }
469
470 /**
471 * Insert availability rules
472 */
473 public function insert_availability_rules($data, $trip_ids)
474 {
475 $inserted = 0;
476
477 foreach ($data as $item) {
478 $trip_slug = $item['trip_slug'];
479 unset($item['trip_slug']);
480
481 if (!isset($trip_ids[$trip_slug])) {
482 continue;
483 }
484 $item['trip_id'] = $trip_ids[$trip_slug];
485
486 // Convert arrays to JSON
487 if (isset($item['days_of_week']) && is_array($item['days_of_week'])) {
488 $item['days_of_week'] = json_encode($item['days_of_week']);
489 }
490 if (isset($item['recurrence_pattern']) && is_array($item['recurrence_pattern'])) {
491 $item['recurrence_pattern'] = json_encode($item['recurrence_pattern']);
492 }
493
494 $result = $this->wpdb->insert($this->availability_rules_table, $item);
495 if ($result) {
496 $inserted++;
497 }
498 }
499
500 return $inserted;
501 }
502
503 /**
504 * Insert itinerary days. Returns composite key => day_id mapping.
505 */
506 public function insert_itinerary_days($data, $trip_ids)
507 {
508 $day_ids = [];
509 $now = current_time('mysql');
510 $uid = get_current_user_id();
511
512 foreach ($data as $item) {
513 $trip_slug = $item['trip_slug'];
514 unset($item['trip_slug']);
515
516 if (!isset($trip_ids[$trip_slug])) {
517 continue;
518 }
519 $item['trip_id'] = $trip_ids[$trip_slug];
520 $item['created_at'] = $item['created_at'] ?? $now;
521 $item['updated_at'] = $item['updated_at'] ?? $now;
522 $item['created_by'] = $item['created_by'] ?? $uid;
523 $item['updated_by'] = $item['updated_by'] ?? $uid;
524
525 $result = $this->wpdb->insert($this->itinerary_days_table, $item);
526
527 if ($result && $this->wpdb->insert_id) {
528 $key = $trip_slug . '_day_' . $item['day_number'];
529 $day_ids[$key] = $this->wpdb->insert_id;
530 }
531 }
532
533 return $day_ids;
534 }
535
536 /**
537 * Insert itinerary entries with proper item_type_id and item_id resolution.
538 * Uses item_type slug from JSON to look up real classification IDs.
539 */
540 public function insert_itinerary_entries($data, $trip_ids, $day_ids)
541 {
542 $inserted = 0;
543 $now = current_time('mysql');
544 $uid = get_current_user_id();
545
546 // Build a map of item_type slug => {id, name, icon} from classifications
547 $item_type_map = $this->build_item_type_map();
548 // Build a map of item slug => {id, name, icon, parent_id} from classifications
549 $item_map = $this->build_item_map();
550
551 foreach ($data as $item) {
552 $trip_slug = $item['trip_slug'];
553 $day_number = $item['day_number'];
554 unset($item['trip_slug'], $item['day_number']);
555
556 if (!isset($trip_ids[$trip_slug])) {
557 continue;
558 }
559 $day_key = $trip_slug . '_day_' . $day_number;
560 if (!isset($day_ids[$day_key])) {
561 continue;
562 }
563
564 $item['trip_id'] = $trip_ids[$trip_slug];
565 $item['day_id'] = $day_ids[$day_key];
566
567 // Resolve item_type field to real item_type_id, item_name, item_icon
568 // Note: item_type is also a real DB column (varchar(50)) so we keep it
569 $item_type_slug = $item['item_type'] ?? null;
570 if ($item_type_slug && isset($item_type_map[$item_type_slug])) {
571 $typeInfo = $item_type_map[$item_type_slug];
572 $item['item_type_id'] = $typeInfo['id'];
573 $item['item_name'] = $item['item_name'] ?? $typeInfo['name'];
574 $item['item_icon'] = $item['item_icon'] ?? $typeInfo['icon'];
575
576 // Try to find a matching item for this item_type
577 $matched_item = $this->find_best_item_match($item_type_slug, $item['title'] ?? '', $item_map);
578 if ($matched_item) {
579 $item['item_id'] = $matched_item['id'];
580 $item['item_name'] = $matched_item['name'];
581 $item['item_icon'] = $matched_item['icon'] ?: ($item['item_icon'] ?? null);
582 }
583 }
584
585 $item['created_at'] = $item['created_at'] ?? $now;
586 $item['updated_at'] = $item['updated_at'] ?? $now;
587 $item['created_by'] = $item['created_by'] ?? $uid;
588 $item['updated_by'] = $item['updated_by'] ?? $uid;
589
590 // Convert JSON fields if arrays
591 foreach (['included_items', 'excluded_items', 'gallery'] as $jsonField) {
592 if (isset($item[$jsonField]) && is_array($item[$jsonField])) {
593 $item[$jsonField] = json_encode($item[$jsonField]);
594 }
595 }
596
597 $result = $this->wpdb->insert($this->itinerary_entries_table, $item);
598 if ($result) {
599 $inserted++;
600 } else {
601 }
602 }
603
604 return $inserted;
605 }
606
607 /**
608 * Build item_type slug => info map from DB
609 */
610 private function build_item_type_map()
611 {
612 $map = [];
613 $rows = $this->wpdb->get_results(
614 "SELECT id, slug, name, icon FROM {$this->classifications_table} WHERE type = 'item_type'"
615 );
616 foreach ($rows as $row) {
617 $map[$row->slug] = [
618 'id' => (int) $row->id,
619 'name' => $row->name,
620 'icon' => $row->icon,
621 ];
622 }
623 return $map;
624 }
625
626 /**
627 * Build item slug => info map from DB (type='item')
628 */
629 private function build_item_map()
630 {
631 $map = [];
632 $rows = $this->wpdb->get_results(
633 "SELECT id, slug, name, icon, parent_id FROM {$this->classifications_table} WHERE type = 'item'"
634 );
635 foreach ($rows as $row) {
636 $map[$row->slug] = [
637 'id' => (int) $row->id,
638 'name' => $row->name,
639 'icon' => $row->icon,
640 'parent_id' => (int) $row->parent_id,
641 ];
642 }
643 return $map;
644 }
645
646 /**
647 * Find the best matching item for an itinerary entry based on item_type and title
648 */
649 private function find_best_item_match($item_type_slug, $entry_title, $item_map)
650 {
651 // Get the item_type_id for this slug using composite key
652 $item_type_id = $this->classification_ids['item_type:' . $item_type_slug] ?? null;
653 if (!$item_type_id) {
654 return null;
655 }
656
657 // Filter items that belong to this item_type (via parent_id)
658 $candidates = [];
659 foreach ($item_map as $slug => $info) {
660 if ($info['parent_id'] === $item_type_id) {
661 $candidates[$slug] = $info;
662 }
663 }
664
665 if (empty($candidates)) {
666 return null;
667 }
668
669 // Simple keyword matching
670 $title_lower = strtolower($entry_title);
671 foreach ($candidates as $slug => $info) {
672 $name_lower = strtolower($info['name']);
673 $slug_words = explode('-', $slug);
674
675 // Check if any word from slug appears in the entry title
676 foreach ($slug_words as $word) {
677 if (strlen($word) > 2 && strpos($title_lower, $word) !== false) {
678 return $info;
679 }
680 }
681 // Check if item name appears in title
682 if (strpos($title_lower, $name_lower) !== false) {
683 return $info;
684 }
685 }
686
687 // Return first candidate as fallback
688 return reset($candidates);
689 }
690
691 /**
692 * Cleanup all sample data
693 */
694 public function cleanup_sample_data()
695 {
696 $results = [];
697
698 // Get trip IDs first for cleaning pivot tables
699 $trip_slugs = [
700 'swiss-alps-mountain-trek', 'maldives-beach-escape', 'kyoto-cultural-journey',
701 'serengeti-wildlife-safari', 'paris-city-explorer', 'bali-island-adventure',
702 'iceland-northern-lights', 'new-zealand-adventure', 'peru-machu-picchu-trek',
703 'norway-fjords-cruise', 'grand-canyon-day-tour', 'paris-city-highlights-tour',
704 'nyc-helicopter-liberty-tour', 'tokyo-cultural-food-tour'
705 ];
706 $slugs_string = "'" . implode("','", $trip_slugs) . "'";
707
708 // Get trip IDs before deleting
709 $trip_ids = $this->wpdb->get_col(
710 "SELECT id FROM {$this->trips_table} WHERE slug IN ({$slugs_string})"
711 );
712
713 if (!empty($trip_ids)) {
714 $trip_ids_string = implode(',', array_map('intval', $trip_ids));
715
716 // Clean pivot table
717 $this->wpdb->query(
718 "DELETE FROM {$this->trip_classifications_table} WHERE trip_id IN ({$trip_ids_string})"
719 );
720
721 // Clean itinerary entries
722 $this->wpdb->query(
723 "DELETE FROM {$this->itinerary_entries_table} WHERE trip_id IN ({$trip_ids_string})"
724 );
725
726 // Clean itinerary days
727 $this->wpdb->query(
728 "DELETE FROM {$this->itinerary_days_table} WHERE trip_id IN ({$trip_ids_string})"
729 );
730
731 // Clean availability dates
732 $this->wpdb->query(
733 "DELETE FROM {$this->availability_dates_table} WHERE trip_id IN ({$trip_ids_string})"
734 );
735
736 // Clean availability rules
737 $this->wpdb->query(
738 "DELETE FROM {$this->availability_rules_table} WHERE trip_id IN ({$trip_ids_string})"
739 );
740
741 // Clean trip content
742 $this->wpdb->query(
743 "DELETE FROM {$this->trip_content_table} WHERE trip_id IN ({$trip_ids_string})"
744 );
745 }
746
747 // Delete trips
748 $result = $this->wpdb->query(
749 "DELETE FROM {$this->trips_table} WHERE slug IN ({$slugs_string})"
750 );
751 $results['trips'] = $result !== false;
752
753 // All classification slugs including items
754 $classification_slugs = [
755 'adventure-tours', 'beach-island', 'cultural-tours', 'wildlife-safari',
756 'city-tours', 'trekking-hiking', 'cruise-tours', 'food-wine',
757 'hiking', 'snorkeling', 'city-walking-tour', 'wildlife-viewing',
758 'kayaking', 'photography', 'camping', 'rock-climbing', 'cycling', 'cooking-class',
759 'swiss-alps', 'maldives', 'kyoto-japan', 'serengeti-tanzania', 'paris-france',
760 'bali-indonesia', 'iceland', 'new-zealand', 'peru', 'norway',
761 'easy', 'moderate', 'challenging', 'difficult', 'extreme', 'expert',
762 'group-size', 'age-restriction', 'fitness-level', 'accommodation-type',
763 'meal-plan', 'transportation', 'guide-language', 'season',
764 'accommodation', 'activity', 'meal', 'sightseeing', 'free-time',
765 'adult', 'child', 'infant', 'student', 'senior', 'group-leader', 'family', 'solo-traveler',
766 'mountain-hut', '5-star-hotel', 'beach-resort', 'safari-lodge', 'tented-camp',
767 'guided-hiking', 'snorkeling-trip', 'temple-visit', 'game-drive',
768 'city-walking-tour-item', 'cooking-class-item',
769 'breakfast', 'lunch', 'dinner', 'welcome-dinner',
770 'airport-transfer', 'coach-transfer', 'boat-transfer',
771 'landmark-visit', 'scenic-viewpoint',
772 'rest-and-explore', 'shopping-time'
773 ];
774
775 $class_slugs_string = "'" . implode("','", $classification_slugs) . "'";
776 $result = $this->wpdb->query(
777 "DELETE FROM {$this->classifications_table} WHERE slug IN ({$class_slugs_string})"
778 );
779 $results['classifications'] = $result !== false;
780
781 // Clean discounts
782 $discount_codes = ['SUMMER2024', 'EARLYBIRD', 'GROUP10', 'WELCOME50',
783 'FAMILY20', 'LASTMINUTE', 'LOYAL100', 'WINTER2024'];
784 $codes_string = "'" . implode("','", $discount_codes) . "'";
785 $result = $this->wpdb->query(
786 "DELETE FROM {$this->discounts_table} WHERE code IN ({$codes_string})"
787 );
788 $results['discounts'] = $result !== false;
789
790 // Clear import flags
791 delete_option('yatra_sample_data_imported');
792 delete_option('yatra_sample_data_import_date');
793
794 return $results;
795 }
796 }
797