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 / Bootstrap.php

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

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