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 / Core / Modules / ModuleManager.php

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

438 lines 19.7 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\Core\Modules;
6
7 /**
8 * Module Manager
9 * Handles module definitions and persistence via wp_options
10 */
11 class ModuleManager
12 {
13 private const OPTION_KEY = 'yatra_modules';
14 private const DEFAULT_VIDEO_URL = 'https://youtu.be/cHmC-x7y0TQ';
15
16 /**
17 * Ensure option exists with defaults
18 */
19 public static function initializeDefaults(): void
20 {
21 if (get_option(self::OPTION_KEY) === false) {
22 $defaults = [];
23 $timestamp = current_time('mysql');
24
25 foreach (self::getDefaultModules() as $module) {
26 $defaults[$module['slug']] = [
27 'enabled' => !empty($module['enabled']),
28 'updated_at' => $timestamp,
29 ];
30 }
31
32 add_option(self::OPTION_KEY, $defaults);
33 }
34 }
35
36 /**
37 * Get default module definitions
38 */
39 public static function getDefaultModules(): array
40 {
41 $modules = [
42 [
43 'slug' => 'google_calendar',
44 'name' => __('Google Calendar Integration', 'yatra'),
45 'description' => __('Automatically sync bookings and departures to Google Calendar. Keep travelers informed with calendar invitations. Perfect integration for managing your travel schedule.', 'yatra'),
46 'category' => __('Integrations', 'yatra'),
47 'docs_url' => 'https://docs.yatra.com/modules/google-calendar',
48 'is_premium' => true,
49 'purchase_url' => 'https://wpyatra.com/pricing?module=google-calendar',
50 'is_core' => false,
51 'enabled' => false,
52 'tags' => ['integrations', 'calendar', 'automation'],
53 'video_url' => self::DEFAULT_VIDEO_URL,
54 'requires_pro' => true,
55 'settings_page' => 'yatra-google-calendar',
56 ],
57 [
58 'slug' => 'additional_services',
59 'name' => __('Additional Services', 'yatra'),
60 'description' => __('Offer optional add-ons like airport transfers, travel insurance, and equipment rental. Increase revenue per booking with valuable extras travelers want. Enhance complete trip experience for your customers.', 'yatra'),
61 'category' => __('Sales', 'yatra'),
62 'docs_url' => 'https://docs.yatra.com/modules/additional-services',
63 'is_premium' => true,
64 'purchase_url' => 'https://wpyatra.com/pricing?module=additional-services',
65 'is_core' => false,
66 'enabled' => false,
67 'tags' => ['upsell', 'services', 'add-ons', 'extras'],
68 'video_url' => self::DEFAULT_VIDEO_URL,
69 'requires_pro' => true,
70 'settings_page' => 'yatra-additional-services',
71 ],
72 [
73 'slug' => 'trip_consent',
74 'name' => __('Trip Consent', 'yatra'),
75 'description' => __('Collect digital consent forms and signatures from travelers before their trip. Includes liability waivers and health declarations. Ensure legal compliance and protect your business.', 'yatra'),
76 'category' => __('Operations', 'yatra'),
77 'docs_url' => 'https://docs.yatra.com/modules/trip-consent',
78 'is_premium' => true,
79 'purchase_url' => 'https://wpyatra.com/pricing?module=trip-consent',
80 'is_core' => false,
81 'enabled' => false,
82 'tags' => ['consent', 'waiver', 'signature', 'forms', 'legal'],
83 'video_url' => self::DEFAULT_VIDEO_URL,
84 'requires_pro' => true,
85 'settings_page' => 'yatra-trip-consent',
86 ],
87 [
88 'slug' => 'email_automation',
89 'name' => __('Email Automation', 'yatra'),
90 'description' => __('Adds the full automation template library (database), sequences, and send logs on the Email screen. Everyone already gets Delivery settings plus the four core customer templates (booking, payment, cancellation, reminder) without this module.', 'yatra'),
91 'category' => __('Marketing', 'yatra'),
92 'docs_url' => 'https://docs.yatra.com/modules/email-automation',
93 'is_premium' => true,
94 'purchase_url' => 'https://wpyatra.com/pricing?module=email-automation',
95 'is_core' => false,
96 'enabled' => false,
97 'tags' => ['email', 'automation', 'templates', 'marketing', 'notifications'],
98 'video_url' => self::DEFAULT_VIDEO_URL,
99 'requires_pro' => true,
100 'settings_page' => 'email-automation',
101 ],
102 [
103 'slug' => 'dynamic_form_field',
104 'name' => __('Dynamic Form Field', 'yatra'),
105 'description' => __('Customize booking form fields with drag-and-drop builder. Add custom fields for traveler information and emergency contacts. Create the perfect booking experience for your customers.', 'yatra'),
106 'category' => __('Bookings', 'yatra'),
107 'docs_url' => 'https://docs.yatra.com/modules/dynamic-form-field',
108 'is_premium' => true,
109 'purchase_url' => 'https://wpyatra.com/pricing?module=dynamic-form-field',
110 'is_core' => false,
111 'enabled' => false,
112 'tags' => ['form', 'booking', 'customization', 'fields', 'builder'],
113 'video_url' => self::DEFAULT_VIDEO_URL,
114 'requires_pro' => true,
115 'settings_page' => 'yatra-settings',
116 ],
117 [
118 'slug' => 'advanced_discount',
119 'name' => __('Advanced Discount', 'yatra'),
120 'description' => __('Create group discounts that auto-apply based on traveler count. Combine promo codes with group savings for maximum flexibility and conversion optimization.', 'yatra'),
121 'category' => __('Marketing', 'yatra'),
122 'docs_url' => 'https://docs.yatra.com/modules/advanced-discount',
123 'is_premium' => true,
124 'purchase_url' => 'https://wpyatra.com/pricing?module=advanced-discount',
125 'is_core' => false,
126 'enabled' => false,
127 'tags' => ['discount', 'group', 'promo', 'coupon', 'marketing'],
128 'video_url' => self::DEFAULT_VIDEO_URL,
129 'requires_pro' => true,
130 ],
131 [
132 'slug' => 'mailchimp',
133 'name' => __('Mailchimp Integration', 'yatra'),
134 'description' => __('Automatically sync customers to Mailchimp lists when they book. Add tags based on trips booked. Build targeted email campaigns and nurture leads effectively.', 'yatra'),
135 'category' => __('Marketing', 'yatra'),
136 'docs_url' => 'https://docs.yatra.com/modules/mailchimp',
137 'is_premium' => true,
138 'purchase_url' => 'https://wpyatra.com/pricing?module=mailchimp',
139 'is_core' => false,
140 'enabled' => false,
141 'tags' => ['email', 'marketing', 'mailchimp', 'automation', 'integration'],
142 'video_url' => self::DEFAULT_VIDEO_URL,
143 'requires_pro' => true,
144 'settings_page' => 'yatra-mailchimp',
145 ],
146 [
147 'slug' => 'facebook_pixel',
148 'name' => __('Facebook Pixel', 'yatra'),
149 'description' => __('Track booking conversions with Facebook Pixel. Retarget visitors who viewed trips. Optimize ad campaigns with accurate conversion data and build lookalike audiences.', 'yatra'),
150 'category' => __('Marketing', 'yatra'),
151 'docs_url' => 'https://docs.yatra.com/modules/facebook-pixel',
152 'is_premium' => true,
153 'purchase_url' => 'https://wpyatra.com/pricing?module=facebook-pixel',
154 'is_core' => false,
155 'enabled' => false,
156 'tags' => ['facebook', 'pixel', 'tracking', 'ads', 'retargeting', 'marketing'],
157 'video_url' => self::DEFAULT_VIDEO_URL,
158 'requires_pro' => true,
159 'settings_page' => 'yatra-facebook-pixel',
160 ],
161 [
162 'slug' => 'google_analytics',
163 'name' => __('Google Analytics 4 Enhanced', 'yatra'),
164 'description' => __('Enhanced e-commerce tracking for GA4. Track view_item, begin_checkout, and purchase events. Server-side tracking via Measurement Protocol for accurate conversion data.', 'yatra'),
165 'category' => __('Marketing', 'yatra'),
166 'docs_url' => 'https://docs.yatra.com/modules/google-analytics',
167 'is_premium' => true,
168 'purchase_url' => 'https://wpyatra.com/pricing?module=google-analytics',
169 'is_core' => false,
170 'enabled' => false,
171 'tags' => ['google', 'analytics', 'ga4', 'tracking', 'ecommerce', 'marketing'],
172 'video_url' => self::DEFAULT_VIDEO_URL,
173 'requires_pro' => true,
174 'settings_page' => 'yatra-google-analytics',
175 ],
176 [
177 'slug' => 'flexible_payments',
178 'name' => __('Flexible Payments', 'yatra'),
179 'description' => __('Enable deposit and partial payment options for bookings. Allow customers to pay a percentage upfront and the rest later. Perfect for high-value trips and improving conversion rates.', 'yatra'),
180 'category' => __('Payments', 'yatra'),
181 'docs_url' => 'https://docs.yatra.com/modules/flexible-payments',
182 'is_premium' => true,
183 'purchase_url' => 'https://wpyatra.com/pricing?module=flexible-payments',
184 'is_core' => false,
185 'enabled' => false,
186 'tags' => ['payments', 'deposit', 'partial', 'installments', 'booking'],
187 'video_url' => self::DEFAULT_VIDEO_URL,
188 'requires_pro' => true,
189 'settings_page' => 'yatra-settings',
190 ],
191 [
192 'slug' => 'scheduled_payments',
193 'name' => __('Scheduled Payments', 'yatra'),
194 'description' => __('Automatically schedule the remaining booking balance after a partial or deposit payment. Uses your payment gateway (e.g. Stripe) to invoice or charge on the dates you configure.', 'yatra'),
195 'category' => __('Payments', 'yatra'),
196 'docs_url' => 'https://docs.yatra.com/modules/scheduled-payments',
197 'is_premium' => true,
198 'purchase_url' => 'https://wpyatra.com/pricing?module=scheduled-payments',
199 'is_core' => false,
200 'enabled' => false,
201 'tags' => ['payments', 'installments', 'balance', 'stripe', 'automation'],
202 'video_url' => self::DEFAULT_VIDEO_URL,
203 'requires_pro' => true,
204 'settings_page' => 'yatra-settings',
205 ],
206 [
207 'slug' => 'dynamic_pricing',
208 'name' => __('Dynamic Pricing', 'yatra'),
209 'description' => __('Automatically adjust trip prices based on demand, seasonality, early bird discounts, and last-minute deals. Maximize revenue with intelligent pricing rules that respond to booking patterns.', 'yatra'),
210 'category' => __('Sales', 'yatra'),
211 'docs_url' => 'https://docs.yatra.com/modules/dynamic-pricing',
212 'is_premium' => true,
213 'purchase_url' => 'https://wpyatra.com/pricing?module=dynamic-pricing',
214 'is_core' => false,
215 'enabled' => false,
216 'tags' => ['pricing', 'revenue', 'automation', 'discounts', 'sales'],
217 'video_url' => self::DEFAULT_VIDEO_URL,
218 'requires_pro' => true,
219 'settings_page' => 'dynamic-pricing',
220 ],
221 [
222 'slug' => 'custom_landing_pages',
223 'name' => __('Custom Landing Pages', 'yatra'),
224 'description' => __('Point destinations, activities, and trip types to any WordPress page. Use your page builder and Yatra shortcodes on that page; catalog links and redirects use the page URL when the module is enabled.', 'yatra'),
225 'category' => __('Marketing', 'yatra'),
226 'docs_url' => 'https://docs.wpyatra.com/modules/custom-landing-pages',
227 'is_premium' => true,
228 'purchase_url' => 'https://wpyatra.com/pricing?module=custom-landing-pages',
229 'is_core' => false,
230 'enabled' => false,
231 'tags' => ['seo', 'landing', 'page-builder', 'destinations', 'taxonomy'],
232 'video_url' => self::DEFAULT_VIDEO_URL,
233 'requires_pro' => true,
234 'settings_page' => 'yatra-settings',
235 ],
236 [
237 'slug' => 'abandoned_booking_recovery',
238 'name' => __('Abandoned Booking Recovery', 'yatra'),
239 'description' => __('Recover lost sales by automatically tracking abandoned bookings and sending targeted email sequences. Win back customers who left before completing their purchase.', 'yatra'),
240 'category' => __('Marketing', 'yatra'),
241 'docs_url' => 'https://docs.yatra.com/modules/abandoned-booking-recovery',
242 'is_premium' => true,
243 'purchase_url' => 'https://wpyatra.com/pricing?module=abandoned-booking-recovery',
244 'is_core' => false,
245 'enabled' => false,
246 'tags' => ['recovery', 'email', 'automation', 'marketing', 'conversion'],
247 'video_url' => self::DEFAULT_VIDEO_URL,
248 'requires_pro' => true,
249 'settings_page' => 'abandoned-recovery',
250 ],
251 ];
252
253 return apply_filters('yatra_default_modules', $modules);
254 }
255
256 /**
257 * Get modules merged with stored option state
258 */
259 public static function getModules(): array
260 {
261 // Get enable/disable status ONLY from database
262 $stored_status = get_option(self::OPTION_KEY, []);
263 $stored_status = is_array($stored_status) ? $stored_status : [];
264
265 // Get module definitions ONLY from hardcoded array
266 $modules = self::getDefaultModules();
267
268 $result = [];
269 foreach ($modules as $module) {
270 $slug = $module['slug'];
271
272 // Get enable/disable status from database only
273 $enabled = isset($stored_status[$slug]['enabled'])
274 ? (bool) $stored_status[$slug]['enabled']
275 : (bool) ($module['enabled'] ?? false);
276
277 // Check if module is available (can be enabled)
278 $is_available = true;
279 if (!empty($module['requires_pro'])) {
280 $pro_active = apply_filters('yatra_is_pro_active', false);
281 if ($pro_active) {
282 // Check if this module is available in Pro
283 $available_modules = apply_filters('yatra_pro_available_modules', []);
284 $is_available = in_array($slug, $available_modules, true);
285 } else {
286 $is_available = false;
287 }
288 }
289
290 $result[] = array_merge($module, [
291 'enabled' => $enabled,
292 'updated_at' => $stored_status[$slug]['updated_at'] ?? null,
293 'is_available' => $is_available,
294 ]);
295 }
296
297 return $result;
298 }
299
300 /**
301 * Check if module is enabled
302 */
303 public static function isModuleEnabled(string $slug): bool
304 {
305 // Allow direct override for specific modules
306 $override = apply_filters('yatra_module_enabled_status', null, $slug);
307 if ($override !== null) {
308 return (bool) $override;
309 }
310
311 $modules = self::getModules();
312 foreach ($modules as $module) {
313 if ($module['slug'] === $slug) {
314 // Check if module requires Pro and if Pro is active
315 if (!empty($module['requires_pro'])) {
316 $pro_active = apply_filters('yatra_is_pro_active', false);
317 if (!$pro_active) {
318 return false;
319 }
320 }
321
322 return (bool) $module['enabled'];
323 }
324 }
325
326 return false;
327 }
328
329 /**
330 * Check if module is available (can be enabled)
331 */
332 public static function isModuleAvailable(string $slug): bool
333 {
334 // Allow direct override for specific modules
335 $override = apply_filters('yatra_module_is_available_' . $slug, null);
336 if ($override !== null) {
337 return (bool) $override;
338 }
339
340 $modules = self::getModules();
341 foreach ($modules as $module) {
342 if ($module['slug'] === $slug) {
343 // If module requires Pro, check if Pro is active
344 if (!empty($module['requires_pro'])) {
345 // Check if Pro is active
346 $pro_active = apply_filters('yatra_is_pro_active', false);
347 if (!$pro_active) {
348 return false;
349 }
350
351 // Check if this module is available in Pro
352 $available_modules = apply_filters('yatra_pro_available_modules', []);
353 return in_array($slug, $available_modules, true);
354 }
355
356 return true;
357 }
358 }
359
360 return false;
361 }
362
363 /**
364 * Update module enabled state
365 */
366 public static function setModuleStatus(string $slug, bool $enabled): array
367 {
368 $modules = get_option(self::OPTION_KEY, []);
369 $modules = is_array($modules) ? $modules : [];
370
371 $modules[$slug] = array_merge($modules[$slug] ?? [], [
372 'enabled' => $enabled,
373 'updated_at' => current_time('mysql'),
374 ]);
375
376 update_option(self::OPTION_KEY, $modules);
377
378 // Trigger module activation/deactivation hook
379 if ($enabled) {
380 do_action('yatra_module_active', $slug);
381 } else {
382 do_action('yatra_module_deactive', $slug);
383 }
384
385 return self::getModules();
386 }
387
388 /**
389 * Update multiple modules at once
390 *
391 * @param array<array{slug:string, enabled:bool}> $items
392 */
393 public static function setMultipleStatuses(array $items): array
394 {
395 if (empty($items)) {
396 return self::getModules();
397 }
398
399 $modules = get_option(self::OPTION_KEY, []);
400 $modules = is_array($modules) ? $modules : [];
401 $timestamp = current_time('mysql');
402
403 foreach ($items as $item) {
404 if (empty($item['slug'])) {
405 continue;
406 }
407
408 $slug = sanitize_key($item['slug']);
409 $enabled = (bool) ($item['enabled'] ?? false);
410
411 $modules[$slug] = array_merge($modules[$slug] ?? [], [
412 'enabled' => $enabled,
413 'updated_at' => $timestamp,
414 ]);
415 }
416
417 update_option(self::OPTION_KEY, $modules);
418
419 // Trigger module activation/deactivation hooks for bulk updates
420 foreach ($items as $item) {
421 if (empty($item['slug'])) {
422 continue;
423 }
424
425 $slug = sanitize_key($item['slug']);
426 $enabled = (bool) ($item['enabled'] ?? false);
427
428 if ($enabled) {
429 do_action('yatra_module_active', $slug);
430 } else {
431 do_action('yatra_module_deactive', $slug);
432 }
433 }
434
435 return self::getModules();
436 }
437 }
438