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

379 lines 12.1 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\Core\Database;
9 use Yatra\Providers\AppServiceProvider;
10 use Yatra\Providers\RouteServiceProvider;
11 use Yatra\Providers\AdminServiceProvider;
12 use Yatra\Providers\FrontendAssetsProvider;
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\Admin\StatsUsage')) {
79 \Yatra\Admin\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
113 $this->loadTextDomain();
114
115 } catch (\Throwable $e) {
116 error_log('Yatra plugin initialization error: ' . $e->getMessage() . ' in ' . $e->getFile() . ':' . $e->getLine());
117
118 // Show admin notice if in admin area
119 if (is_admin()) {
120 add_action('admin_notices', function() use ($e) {
121 echo '<div class="notice notice-error"><p><strong>Yatra:</strong> ' .
122 esc_html($e->getMessage()) . '</p></div>';
123 });
124 }
125
126 return;
127 }
128
129 $this->initialized = true;
130 }
131
132 /**
133 * Load helper functions
134 */
135 private function loadHelperFunctions(): void
136 {
137 $helpersPath = YATRA_PLUGIN_PATH . 'includes/helpers.php';
138 if (file_exists($helpersPath)) {
139 require_once $helpersPath;
140 }
141
142 $seoHelperPath = YATRA_PLUGIN_PATH . 'includes/seo-helper.php';
143 if (file_exists($seoHelperPath)) {
144 require_once $seoHelperPath;
145 }
146 }
147
148 /**
149 * Register and boot service providers.
150 *
151 * Each provider is instantiated once. The same instance is used for both
152 * register() and boot() so that any hooks added during register() remain
153 * attached to the object that boot() later acts on.
154 */
155 private function registerServiceProviders(): void
156 {
157 $providerClasses = [];
158
159 // Core providers — always loaded
160 if (class_exists('Yatra\Providers\AppServiceProvider')) {
161 $providerClasses[] = 'Yatra\Providers\AppServiceProvider';
162 }
163
164 if (class_exists('Yatra\Providers\RouteServiceProvider')) {
165 $providerClasses[] = 'Yatra\Providers\RouteServiceProvider';
166 }
167
168 // Admin-only providers
169 if (is_admin() && class_exists('Yatra\Providers\AdminServiceProvider')) {
170 $providerClasses[] = 'Yatra\Providers\AdminServiceProvider';
171 }
172
173 // Frontend-only providers
174 if (!is_admin() && class_exists('Yatra\Providers\FrontendAssetsProvider')) {
175 $providerClasses[] = 'Yatra\Providers\FrontendAssetsProvider';
176 }
177
178 // Shortcode provider (frontend + admin)
179 if (class_exists('Yatra\Providers\ShortcodeServiceProvider')) {
180 $providerClasses[] = 'Yatra\Providers\ShortcodeServiceProvider';
181 }
182
183 // Block provider (Gutenberg)
184 if (class_exists('Yatra\Providers\BlockServiceProvider')) {
185 $providerClasses[] = 'Yatra\Providers\BlockServiceProvider';
186 }
187
188 // Instantiate and register all providers, keeping a map of the instances
189 // so boot() runs on the exact same object that register() did.
190 $instances = [];
191
192 foreach ($providerClasses as $class) {
193 try {
194 $instance = new $class($this->container);
195 if (method_exists($instance, 'register')) {
196 $instance->register();
197 }
198 $instances[$class] = $instance;
199 } catch (\Throwable $e) {
200 error_log("Yatra: Failed to register provider {$class}: " . $e->getMessage());
201 continue;
202 }
203 }
204
205 // Boot each successfully registered provider
206 foreach ($instances as $class => $instance) {
207 try {
208 if (method_exists($instance, 'boot')) {
209 $instance->boot();
210 }
211 } catch (\Throwable $e) {
212 error_log("Yatra: Failed to boot provider {$class}: " . $e->getMessage());
213 continue;
214 }
215 }
216 }
217
218 /**
219 * Initialize Action Scheduler
220 */
221 private function initializeActionScheduler(): void
222 {
223 $actionSchedulerPath = YATRA_PLUGIN_PATH . 'vendor/woocommerce/action-scheduler/action-scheduler.php';
224 if (file_exists($actionSchedulerPath)) {
225 require_once $actionSchedulerPath;
226 }
227 }
228
229 /**
230 * Initialize core components
231 */
232 private function initializeCore(): void
233 {
234 // Check and create database tables if they don't exist
235 $this->ensureDatabaseTables();
236 }
237
238 /**
239 * Setup WordPress hooks
240 */
241 private function setupWordPressHooks(): void
242 {
243 // Register activation/deactivation hooks
244 register_activation_hook(YATRA_PLUGIN_FILE, [$this, 'activate']);
245 register_deactivation_hook(YATRA_PLUGIN_FILE, [$this, 'deactivate']);
246
247 // Check for plugin upgrades
248 add_action('admin_init', [$this, 'upgrade']);
249 }
250
251 /**
252 * Ensure database tables exist
253 */
254 private function ensureDatabaseTables(): void
255 {
256 // Register migration routes
257 add_action('rest_api_init', function() {
258 // Temporarily manually require migration files until autoloader is fixed
259 $migrationFiles = [
260 __DIR__ . '/Migrations/MigrationController.php',
261 __DIR__ . '/Migrations/MigrationProgress.php',
262 __DIR__ . '/Migrations/MigrationDetector.php',
263 ];
264
265 foreach ($migrationFiles as $file) {
266 if (file_exists($file)) {
267 require_once $file;
268 }
269 }
270
271 if (class_exists('\Yatra\Migration\MigrationController')) {
272 $migrationController = new \Yatra\Migration\MigrationController();
273 $migrationController->registerRoutes();
274 }
275 });
276
277 // Register Action Scheduler hook for background migration processing
278 add_action('yatra_migrate_data_type', function($dataType, $force = false) {
279 if (class_exists('\Yatra\Migration\MigrationProgress')) {
280 $migrationService = new \Yatra\Migration\MigrationProgress();
281 $result = $migrationService->processMigration($dataType, (bool) $force);
282
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 }
289 }
290 }, 10, 2);
291
292 // Register background hook for all data types migration via cron
293 add_action('yatra_migration_background_run', function($force = false) {
294 if (class_exists('\Yatra\Migration\MigrationProgress')) {
295 $migrationService = new \Yatra\Migration\MigrationProgress();
296 $migrationService->migrateAllDirect((bool) $force);
297 }
298 }, 10, 1);
299 }
300
301 /**
302 * Plugin activation
303 */
304 public function activate(): void
305 {
306 // Run centralized installer for all one-time actions (tables + settings)
307 \Yatra\Services\InstallerService::install();
308
309 // Set default options (only version tracking - other defaults handled by InstallerService)
310 if (get_option('yatra_version') === false) {
311 add_option('yatra_version', YATRA_VERSION);
312 }
313
314 // Set up setup wizard redirect for first-time activation
315 if (get_option('yatra_setup_wizard_ran') !== '1') {
316 set_transient('yatra_setup_wizard_redirect', 1, 30);
317 }
318
319 // Flush rewrite rules
320 flush_rewrite_rules();
321 }
322
323 /**
324 * Plugin upgrade logic
325 */
326 public function upgrade(): void
327 {
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);
333 }
334
335 \Yatra\Services\InstallerService::maybeBackfillEmailTemplateDefaults();
336 \Yatra\Services\InstallerService::maybeNormalizeMigratedCouponDiscountStatuses();
337 }
338
339 /**
340 * Plugin deactivation
341 */
342 public function deactivate(): void
343 {
344 // Clean up if needed
345 flush_rewrite_rules();
346 }
347
348 /**
349 * Load plugin text domain
350 */
351 public function loadTextDomain(): void
352 {
353 $locale = determine_locale();
354
355 // Unload any existing text domain
356 unload_textdomain('yatra');
357
358 // Load from WordPress languages directory first (where Loco Translate saves files)
359 load_textdomain('yatra', WP_LANG_DIR . '/plugins/yatra-' . $locale . '.mo');
360
361 // Also check loco subdirectory
362 if (file_exists(WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo')) {
363 load_textdomain('yatra', WP_LANG_DIR . '/loco/plugins/yatra-' . $locale . '.mo');
364 }
365
366 // Load from plugin directory (fallback)
367 load_plugin_textdomain('yatra', false, 'i18n/languages');
368 }
369
370 /**
371 * Get container instance
372 */
373 public function getContainer(): Container
374 {
375 return $this->container;
376 }
377 }
378
379