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/Bootstrap.php +55 -36 3.0.2.6 → 3.0.16 View file →
@@ -4,13 +4,13 @@
4 4
5 5 namespace Yatra;
6 6
7 7 use Yatra\Core\Container;
8 -use Yatra\Core\Database;
9 8 use Yatra\Providers\AppServiceProvider;
10 9 use Yatra\Providers\RouteServiceProvider;
11 10 use Yatra\Providers\AdminServiceProvider;
12 11 use Yatra\Providers\FrontendAssetsProvider;
12 +use Yatra\Compatibility\Compatibility;
13 13 use Yatra\Providers\BlockServiceProvider;
14 14
15 15 /**
16 16 * Main Bootstrap class for Yatra plugin
@@ -74,10 +74,10 @@
74 74 if (class_exists('\Yatra\Services\NoticeService')) {
75 75 \Yatra\Services\NoticeService::init();
76 76 }
77 77
78 - if (class_exists('\Yatra\Admin\StatsUsage')) {
79 - \Yatra\Admin\StatsUsage::instance()->init();
78 + if (class_exists('\Yatra\Services\StatsUsage')) {
79 + \Yatra\Services\StatsUsage::instance()->init();
80 80 }
81 81
82 82 // Initialize Dynamic Pricing Service
83 83 // DISABLED: Automatic dynamic pricing was adding 15% markup for trips with ≤5 spots
@@ -108,14 +108,18 @@
108 108
109 109 // Set up WordPress hooks
110 110 $this->setupWordPressHooks();
111 111
112 - // Load text domain
113 - $this->loadTextDomain();
112 + // Load text domain on `init` — calling load_(plugin_)textdomain before `init`
113 + // triggers WP 6.7+ _doing_it_wrong notices (and Loco's "premature text domain"
114 + // warning). Use priority 1 so it runs before code that translates on `init`.
115 + if (did_action('init')) {
116 + $this->loadTextDomain();
117 + } else {
118 + add_action('init', [$this, 'loadTextDomain'], 1);
119 + }
114 120
115 121 } catch (\Throwable $e) {
116 - error_log('Yatra plugin initialization error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
117 -
118 122 // Show admin notice if in admin area
119 123 if (is_admin()) {
120 124 add_action('admin_notices', function() use ($e) {
121 125 echo '<div class="notice notice-error"><p><strong>Yatra:</strong> ' .
@@ -153,8 +157,17 @@
153 157 * attached to the object that boot() later acts on.
154 158 */
155 159 private function registerServiceProviders(): void
156 160 {
161 + // Register third-party compatibility hooks (Elementor, etc.)
162 + // Must run on `plugins_loaded` so that other plugins (Elementor, etc.) are
163 + // guaranteed to have loaded their classes before we check class_exists().
164 + // Calling Compatibility::register() directly here runs before plugins_loaded
165 + // and class_exists('\Elementor\Plugin') will always be false at that point.
166 + if (!is_admin() && class_exists('Yatra\\Compatibility\\Compatibility')) {
167 + add_action('plugins_loaded', ['Yatra\\Compatibility\\Compatibility', 'register'], 20);
168 + }
169 +
157 170 $providerClasses = [];
158 171
159 172 // Core providers — always loaded
160 173 if (class_exists('Yatra\Providers\AppServiceProvider')) {
@@ -196,9 +209,8 @@
196 209 $instance->register();
197 210 }
198 211 $instances[$class] = $instance;
199 212 } catch (\Throwable $e) {
200 - error_log("Yatra: Failed to register provider {$class}: " . $e->getMessage());
201 213 continue;
202 214 }
203 215 }
204 216
@@ -208,9 +220,8 @@
208 220 if (method_exists($instance, 'boot')) {
209 221 $instance->boot();
210 222 }
211 223 } catch (\Throwable $e) {
212 - error_log("Yatra: Failed to boot provider {$class}: " . $e->getMessage());
213 224 continue;
214 225 }
215 226 }
216 227 }
@@ -242,11 +253,29 @@
242 253 {
243 254 // Register activation/deactivation hooks
244 255 register_activation_hook(YATRA_PLUGIN_FILE, [$this, 'activate']);
245 256 register_deactivation_hook(YATRA_PLUGIN_FILE, [$this, 'deactivate']);
246 -
247 - // Check for plugin upgrades
248 - add_action('admin_init', [$this, 'upgrade']);
257 +
258 + if (class_exists(\Yatra\Upgrades\FreeUpgradeRunner::class)) {
259 + \Yatra\Upgrades\FreeUpgradeRunner::register();
260 + }
261 +
262 + // On user registration, link any guest bookings made under
263 + // the same email. Otherwise a customer who booked as guest
264 + // first and then created an account would lose visibility of
265 + // that earlier booking from My Account (the rows live with
266 + // user_id=0 and the customer page filters by user_id).
267 + if (class_exists('\\Yatra\\Services\\CustomerService')) {
268 + add_action('user_register', static function ($user_id): void {
269 + try {
270 + (new \Yatra\Services\CustomerService())->linkGuestBookingsToUser((int) $user_id);
271 + } catch (\Throwable $e) {
272 + // Never block registration on a reconciliation
273 + // failure. The booking remains accessible via the
274 + // confirmation email link either way.
275 + }
276 + }, 20, 1);
277 + }
249 278 }
250 279
251 280 /**
252 281 * Ensure database tables exist
@@ -279,14 +308,9 @@
279 308 if (class_exists('\Yatra\Migration\MigrationProgress')) {
280 309 $migrationService = new \Yatra\Migration\MigrationProgress();
281 310 $result = $migrationService->processMigration($dataType, (bool) $force);
282 311
283 - // Log result for debugging
284 - if (isset($result['success']) && $result['success']) {
285 - error_log("Yatra Migration completed for {$dataType}: migrated={$result['migrated']}, skipped={$result['skipped']}, failed={$result['failed']}");
286 - } else {
287 - error_log("Yatra Migration failed for {$dataType}: " . ($result['error'] ?? 'Unknown error'));
288 - }
312 +
289 313 }
290 314 }, 10, 2);
291 315
292 316 // Register background hook for all data types migration via cron
@@ -320,28 +344,20 @@
320 344 flush_rewrite_rules();
321 345 }
322 346
323 347 /**
324 - * Plugin upgrade logic
348 + * Plugin deactivation
325 349 */
326 - public function upgrade(): void
350 + public function deactivate(): void
327 351 {
328 - $current_version = get_option('yatra_version', '1.0.0');
329 -
330 - if (version_compare($current_version, YATRA_VERSION, '<')) {
331 - Database::createTables();
332 - update_option('yatra_version', YATRA_VERSION);
352 + // Clear the booking maintenance sweeps so a deactivated plugin leaves no
353 + // orphan events behind in WP-Cron. They are re-scheduled on `init` when
354 + // the plugin is active again; the expiry activation floor is an option,
355 + // so it survives and still protects pre-existing bookings.
356 + foreach (['yatra_booking_expiry', 'yatra_booking_reminder', 'yatra_booking_completion'] as $hook) {
357 + wp_clear_scheduled_hook($hook);
333 358 }
334 359
335 - \Yatra\Services\InstallerService::maybeBackfillEmailTemplateDefaults();
336 - \Yatra\Services\InstallerService::maybeNormalizeMigratedCouponDiscountStatuses();
337 - }
338 -
339 - /**
340 - * Plugin deactivation
341 - */
342 - public function deactivate(): void
343 - {
344 360 // Clean up if needed
345 361 flush_rewrite_rules();
346 362 }
347 363
@@ -362,10 +378,13 @@
362 378 if (file_exists(WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo')) {
363 379 load_textdomain('yatra', WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo');
364 380 }
365 381
366 - // Load from plugin directory (fallback)
367 - load_plugin_textdomain('yatra', false, 'i18n/languages');
382 + // Load from the plugin's own i18n/languages folder (fallback). The 3rd
383 + // arg is relative to WP_PLUGIN_DIR, so it MUST include the plugin folder
384 + // name — a bare 'i18n/languages' resolves to wp-content/plugins/i18n/
385 + // languages (which doesn't exist), so bundled translations never load.
386 + load_plugin_textdomain('yatra', false, dirname(YATRA_PLUGIN_BASENAME) . '/i18n/languages');
368 387 }
369 388
370 389 /**
371 390 * Get container instance