PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.4
Yatra – Travel Booking & Tour Operator Software v3.0.4
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 / Bootstrap.php

Bootstrap.php in Yatra – Travel Booking & Tour Operator Software 3.0.4, at app/Bootstrap.php

370 lines 11.9 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;
6
7 use Yatra\Core\Container;
8 use Yatra\Providers\AppServiceProvider;
9 use Yatra\Providers\RouteServiceProvider;
10 use Yatra\Providers\AdminServiceProvider;
11 use Yatra\Providers\FrontendAssetsProvider;
12 use Yatra\Compatibility\Compatibility;
13 use Yatra\Providers\BlockServiceProvider;
14
15 /**
16 * Main Bootstrap class for Yatra plugin
17 */
18 class Bootstrap
19 {
20
21 /**
22 * @var Container
23 */
24 private Container $container;
25
26 /**
27 * @var bool
28 */
29 private bool $initialized = false;
30
31 /**
32 * Bootstrap constructor
33 */
34 public function __construct()
35 {
36 $this->container = new Container();
37 }
38
39 /**
40 * Initialize the plugin
41 */
42 public function init(): void
43 {
44 if ($this->initialized) {
45 return;
46 }
47
48 try {
49 // Register service providers first
50 $this->registerServiceProviders();
51
52 // Load helper functions (must be loaded after autoloader)
53 $this->loadHelperFunctions();
54
55 // Initialize cache hooks
56 if (class_exists('\Yatra\Hooks\CacheHooks')) {
57 \Yatra\Hooks\CacheHooks::init();
58 }
59
60 if (class_exists('\Yatra\Hooks\AvailabilityInventoryHooks')) {
61 \Yatra\Hooks\AvailabilityInventoryHooks::init();
62 }
63
64 if (class_exists('\Yatra\Hooks\MigrationAdminNoticeHooks')) {
65 \Yatra\Hooks\MigrationAdminNoticeHooks::init();
66 }
67
68 // Initialize Setup Wizard Service
69 if (class_exists('\Yatra\Services\SetupWizardService')) {
70 \Yatra\Services\SetupWizardService::init();
71 }
72
73 // Centralized notices (React UI + WP admin notices)
74 if (class_exists('\Yatra\Services\NoticeService')) {
75 \Yatra\Services\NoticeService::init();
76 }
77
78 if (class_exists('\Yatra\Services\StatsUsage')) {
79 \Yatra\Services\StatsUsage::instance()->init();
80 }
81
82 // Initialize Dynamic Pricing Service
83 // DISABLED: Automatic dynamic pricing was adding 15% markup for trips with ≤5 spots
84 // if (class_exists('\Yatra\Services\DynamicPricingService')) {
85 // \Yatra\Services\DynamicPricingService::init();
86 // }
87
88 // Initialize SEO Manager
89 if (class_exists('\Yatra\Managers\SEOManager')) {
90 \Yatra\Managers\SEOManager::init();
91 }
92
93 // Register Setup Service activation hook
94 if (class_exists('\Yatra\Services\SetupService')) {
95 \Yatra\Services\SetupService::registerActivationHook();
96 }
97
98 // Initialize Action Scheduler
99 $this->initializeActionScheduler();
100
101 // Initialize REST API hooks
102 if (class_exists('\Yatra\Hooks\RestApiHooks')) {
103 \Yatra\Hooks\RestApiHooks::init();
104 }
105
106 // Initialize core components
107 $this->initializeCore();
108
109 // Set up WordPress hooks
110 $this->setupWordPressHooks();
111
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 }
120
121 } catch (\Throwable $e) {
122 // Show admin notice if in admin area
123 if (is_admin()) {
124 add_action('admin_notices', function() use ($e) {
125 echo '<div class="notice notice-error"><p><strong>Yatra:</strong> ' .
126 esc_html($e->getMessage()) . '</p></div>';
127 });
128 }
129
130 return;
131 }
132
133 $this->initialized = true;
134 }
135
136 /**
137 * Load helper functions
138 */
139 private function loadHelperFunctions(): void
140 {
141 $helpersPath = YATRA_PLUGIN_PATH . 'includes/helpers.php';
142 if (file_exists($helpersPath)) {
143 require_once $helpersPath;
144 }
145
146 $seoHelperPath = YATRA_PLUGIN_PATH . 'includes/seo-helper.php';
147 if (file_exists($seoHelperPath)) {
148 require_once $seoHelperPath;
149 }
150 }
151
152 /**
153 * Register and boot service providers.
154 *
155 * Each provider is instantiated once. The same instance is used for both
156 * register() and boot() so that any hooks added during register() remain
157 * attached to the object that boot() later acts on.
158 */
159 private function registerServiceProviders(): void
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
170 $providerClasses = [];
171
172 // Core providers — always loaded
173 if (class_exists('Yatra\Providers\AppServiceProvider')) {
174 $providerClasses[] = 'Yatra\Providers\AppServiceProvider';
175 }
176
177 if (class_exists('Yatra\Providers\RouteServiceProvider')) {
178 $providerClasses[] = 'Yatra\Providers\RouteServiceProvider';
179 }
180
181 // Admin-only providers
182 if (is_admin() && class_exists('Yatra\Providers\AdminServiceProvider')) {
183 $providerClasses[] = 'Yatra\Providers\AdminServiceProvider';
184 }
185
186 // Frontend-only providers
187 if (!is_admin() && class_exists('Yatra\Providers\FrontendAssetsProvider')) {
188 $providerClasses[] = 'Yatra\Providers\FrontendAssetsProvider';
189 }
190
191 // Shortcode provider (frontend + admin)
192 if (class_exists('Yatra\Providers\ShortcodeServiceProvider')) {
193 $providerClasses[] = 'Yatra\Providers\ShortcodeServiceProvider';
194 }
195
196 // Block provider (Gutenberg)
197 if (class_exists('Yatra\Providers\BlockServiceProvider')) {
198 $providerClasses[] = 'Yatra\Providers\BlockServiceProvider';
199 }
200
201 // Instantiate and register all providers, keeping a map of the instances
202 // so boot() runs on the exact same object that register() did.
203 $instances = [];
204
205 foreach ($providerClasses as $class) {
206 try {
207 $instance = new $class($this->container);
208 if (method_exists($instance, 'register')) {
209 $instance->register();
210 }
211 $instances[$class] = $instance;
212 } catch (\Throwable $e) {
213 continue;
214 }
215 }
216
217 // Boot each successfully registered provider
218 foreach ($instances as $class => $instance) {
219 try {
220 if (method_exists($instance, 'boot')) {
221 $instance->boot();
222 }
223 } catch (\Throwable $e) {
224 continue;
225 }
226 }
227 }
228
229 /**
230 * Initialize Action Scheduler
231 */
232 private function initializeActionScheduler(): void
233 {
234 $actionSchedulerPath = YATRA_PLUGIN_PATH . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
235 if (file_exists($actionSchedulerPath)) {
236 require_once $actionSchedulerPath;
237 }
238 }
239
240 /**
241 * Initialize core components
242 */
243 private function initializeCore(): void
244 {
245 // Check and create database tables if they don't exist
246 $this->ensureDatabaseTables();
247 }
248
249 /**
250 * Setup WordPress hooks
251 */
252 private function setupWordPressHooks(): void
253 {
254 // Register activation/deactivation hooks
255 register_activation_hook(YATRA_PLUGIN_FILE, [$this, 'activate']);
256 register_deactivation_hook(YATRA_PLUGIN_FILE, [$this, 'deactivate']);
257
258 if (class_exists(\Yatra\Upgrades\FreeUpgradeRunner::class)) {
259 \Yatra\Upgrades\FreeUpgradeRunner::register();
260 }
261 }
262
263 /**
264 * Ensure database tables exist
265 */
266 private function ensureDatabaseTables(): void
267 {
268 // Register migration routes
269 add_action('rest_api_init', function() {
270 // Temporarily manually require migration files until autoloader is fixed
271 $migrationFiles = [
272 __DIR__ . '/Migrations/MigrationController.php',
273 __DIR__ . '/Migrations/MigrationProgress.php',
274 __DIR__ . '/Migrations/MigrationDetector.php',
275 ];
276
277 foreach ($migrationFiles as $file) {
278 if (file_exists($file)) {
279 require_once $file;
280 }
281 }
282
283 if (class_exists('\Yatra\Migration\MigrationController')) {
284 $migrationController = new \Yatra\Migration\MigrationController();
285 $migrationController->registerRoutes();
286 }
287 });
288
289 // Register Action Scheduler hook for background migration processing
290 add_action('yatra_migrate_data_type', function($dataType, $force = false) {
291 if (class_exists('\Yatra\Migration\MigrationProgress')) {
292 $migrationService = new \Yatra\Migration\MigrationProgress();
293 $result = $migrationService->processMigration($dataType, (bool) $force);
294
295
296 }
297 }, 10, 2);
298
299 // Register background hook for all data types migration via cron
300 add_action('yatra_migration_background_run', function($force = false) {
301 if (class_exists('\Yatra\Migration\MigrationProgress')) {
302 $migrationService = new \Yatra\Migration\MigrationProgress();
303 $migrationService->migrateAllDirect((bool) $force);
304 }
305 }, 10, 1);
306 }
307
308 /**
309 * Plugin activation
310 */
311 public function activate(): void
312 {
313 // Run centralized installer for all one-time actions (tables + settings)
314 \Yatra\Services\InstallerService::install();
315
316 // Set default options (only version tracking - other defaults handled by InstallerService)
317 if (get_option('yatra_version') === false) {
318 add_option('yatra_version', YATRA_VERSION);
319 }
320
321 // Set up setup wizard redirect for first-time activation
322 if (get_option('yatra_setup_wizard_ran') !== '1') {
323 set_transient('yatra_setup_wizard_redirect', 1, 30);
324 }
325
326 // Flush rewrite rules
327 flush_rewrite_rules();
328 }
329
330 /**
331 * Plugin deactivation
332 */
333 public function deactivate(): void
334 {
335 // Clean up if needed
336 flush_rewrite_rules();
337 }
338
339 /**
340 * Load plugin text domain
341 */
342 public function loadTextDomain(): void
343 {
344 $locale = determine_locale();
345
346 // Unload any existing text domain
347 unload_textdomain('yatra');
348
349 // Load from WordPress languages directory first (where Loco Translate saves files)
350 load_textdomain('yatra', WP_LANG_DIR . '/plugins/yatra-' . $locale . '.mo');
351
352 // Also check loco subdirectory
353 if (file_exists(WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo')) {
354 load_textdomain('yatra', WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo');
355 }
356
357 // Load from plugin directory (fallback)
358 load_plugin_textdomain('yatra', false, 'i18n/languages');
359 }
360
361 /**
362 * Get container instance
363 */
364 public function getContainer(): Container
365 {
366 return $this->container;
367 }
368 }
369
370