PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.16
Yatra – Travel Booking & Tour Operator Software v3.0.16
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
← All changes | app/Core/Routing/PrettyRouteMatcher.php +43 -22 3.0.2.7 → 3.0.16 View file →
@@ -18,10 +18,26 @@
18 18 public static function match(string $path): ?array
19 19 {
20 20 $path = trim($path, '/');
21 21
22 + /**
23 + * Override pretty-path routing entirely (runs before built-in rules).
24 + * Return a route array shaped like handler data: keys include `type` (trip|taxonomy|listing|…),
25 + * and type-specific keys such as `slug`, `taxonomy_type`, `listing_type`, `base`, `paged`, etc.
26 + *
27 + * @param array<string,mixed>|null $route_data Resolved route or null to use core matching.
28 + * @param string $path Trimmed relative path ({@see UrlParser::getCleanRequestPath()} after `yatra_frontend_request_path`).
29 + */
30 + $override = apply_filters('yatra_pretty_route_match', null, $path);
31 + if (is_array($override) && isset($override['type']) && is_string($override['type']) && $override['type'] !== '') {
32 + return $override;
33 + }
34 +
35 + $pb = SettingsService::getPermalinkBases();
36 +
22 37 // 1. Email verification
23 - if (preg_match('/^yatra-verify-email\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
38 + $evQuoted = preg_quote($pb['email_verification_prefix'], '/');
39 + if (preg_match('/^' . $evQuoted . '\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
24 40 return [
25 41 'type' => 'email_verification',
26 42 'token' => $matches[1],
27 43 ];
@@ -26,18 +42,9 @@
26 42 'token' => $matches[1],
27 43 ];
28 44 }
29 45
30 - // 2. Dedicated login slug (rewrite: ^login/?$)
31 - if ($path === 'login') {
32 - return [
33 - 'type' => 'login',
34 - 'page' => 'main',
35 - 'base' => 'login',
36 - ];
37 - }
38 -
39 - // 3. Account page
46 + // 2. Account page
40 47 $account_base = SettingsService::getAccountBase();
41 48 $account_route = self::matchAccountRoute($path, $account_base);
42 49 if ($account_route !== null) {
43 50 return $account_route;
@@ -42,9 +49,9 @@
42 49 if ($account_route !== null) {
43 50 return $account_route;
44 51 }
45 52
46 - // 4. Trip archive pagination: {trip_base}/page/{n}
53 + // 3. Trip archive pagination: {trip_base}/page/{n}
47 54 $trip_base = SettingsService::getTripBase();
48 55 if (preg_match('/^' . preg_quote($trip_base, '/') . '\/page\/(\d+)\/?$/', $path, $matches)) {
49 56 return [
50 57 'type' => 'listing',
@@ -53,14 +60,25 @@
53 60 'paged' => max(1, (int) $matches[1]),
54 61 ];
55 62 }
56 63
64 + // Captured slug segments come in as URL-encoded UTF-8 when the request
65 + // path contains non-ASCII characters (e.g. Cyrillic "моя-семья"
66 + // arrives here as `%D0%BC%D0%BE%D1%8F-...`). The DB stores the raw
67 + // decoded slug, so we must decode + normalise once here before
68 + // returning the route data — otherwise downstream handlers query
69 + // `findBySlug('%D0%BC...')` and 404 every non-Latin URL. Mirrors WP
70 + // core's behaviour in `get_page_by_path`.
71 + $decodeSlug = static function (string $raw): string {
72 + return \Yatra\Helpers\SlugHelper::generate($raw);
73 + };
74 +
57 75 // 5. Single trip
58 76 if (preg_match('/^' . preg_quote($trip_base, '/') . '\/([^\/]+)\/?$/', $path, $matches)) {
59 77 if ($matches[1] !== 'page') {
60 78 return [
61 79 'type' => 'trip',
62 - 'slug' => $matches[1],
80 + 'slug' => $decodeSlug($matches[1]),
63 81 'base' => $trip_base,
64 82 ];
65 83 }
66 84 }
@@ -66,11 +84,11 @@
66 84 }
67 85
68 86 // 6. Taxonomy (pagination before single slug)
69 87 $bases = [
70 - 'destination' => SettingsService::getString('destination_base', 'destination'),
71 - 'activity' => SettingsService::getString('activity_base', 'activity'),
72 - 'category' => SettingsService::getString('trip_category_base', 'trip-category'),
88 + 'destination' => SettingsService::getDestinationBase(),
89 + 'activity' => SettingsService::getActivityBase(),
90 + 'category' => SettingsService::getTripCategoryBase(),
73 91 ];
74 92
75 93 foreach ($bases as $type => $base) {
76 94 if (preg_match('/^' . preg_quote($base, '/') . '\/([^\/]+)\/page\/(\d+)\/?$/', $path, $matches)) {
@@ -76,9 +94,9 @@
76 94 if (preg_match('/^' . preg_quote($base, '/') . '\/([^\/]+)\/page\/(\d+)\/?$/', $path, $matches)) {
77 95 return [
78 96 'type' => 'taxonomy',
79 97 'taxonomy_type' => $type,
80 - 'slug' => $matches[1],
98 + 'slug' => $decodeSlug($matches[1]),
81 99 'base' => $base,
82 100 'paged' => max(1, (int) $matches[2]),
83 101 ];
84 102 }
@@ -88,9 +106,9 @@
88 106 if (preg_match('/^' . preg_quote($base, '/') . '\/([^\/]+)\/?$/', $path, $matches)) {
89 107 return [
90 108 'type' => 'taxonomy',
91 109 'taxonomy_type' => $type,
92 - 'slug' => $matches[1],
110 + 'slug' => $decodeSlug($matches[1]),
93 111 'base' => $base,
94 112 ];
95 113 }
96 114 }
@@ -113,11 +131,12 @@
113 131 'base' => $trip_base,
114 132 ];
115 133 }
116 134
117 - // 8. Booking confirmation (pageless: /{booking_base}/confirmation/{ref}/ + legacy slug)
135 + // 8. Booking confirmation (pageless: /{booking_base}/{confirmation_segment}/{ref}/ + legacy slug)
118 136 $booking_base = SettingsService::getBookingBase();
119 - if (preg_match('/^' . preg_quote($booking_base, '/') . '\/confirmation\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
137 + $confirmSeg = preg_quote($pb['booking_flow_confirmation_segment'], '/');
138 + if (preg_match('/^' . preg_quote($booking_base, '/') . '\/' . $confirmSeg . '\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
120 139 return [
121 140 'type' => 'booking_confirmation',
122 141 'confirmation_id' => $matches[1],
123 142 ];
@@ -122,9 +141,10 @@
122 141 'confirmation_id' => $matches[1],
123 142 ];
124 143 }
125 144
126 - if (preg_match('/^booking-confirmation\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
145 + $legacyConfQuoted = preg_quote($pb['legacy_booking_confirmation_prefix'], '/');
146 + if (preg_match('/^' . $legacyConfQuoted . '\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
127 147 return [
128 148 'type' => 'booking_confirmation',
129 149 'confirmation_id' => $matches[1],
130 150 ];
@@ -130,9 +150,10 @@
130 150 ];
131 151 }
132 152
133 153 // 9. Remaining checkout (rewrite) and legacy checkout/ path
134 - if (preg_match('/^remaining-checkout\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
154 + $remQuoted = preg_quote($pb['remaining_checkout_prefix'], '/');
155 + if (preg_match('/^' . $remQuoted . '\/([a-zA-Z0-9_-]+)$/', $path, $matches)) {
135 156 return [
136 157 'type' => 'checkout',
137 158 'token' => $matches[1],
138 159 ];