PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.2.9
Yatra – Travel Booking & Tour Operator Software v3.0.2.9
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
yatra / includes / incompatible-pro-guard.php

incompatible-pro-guard.php in Yatra – Travel Booking & Tour Operator Software 3.0.2.9, at includes/incompatible-pro-guard.php

335 lines 10.5 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Yatra Pro &lt; 3.0 is incompatible with Yatra Free 3.0+ (removed / renamed classes such as Yatra_Form).
4 * When both are active, old Pro can fatal before Free runs if Pro loads first in the active-plugins list.
5 *
6 * This file:
7 * 1. Reorders active plugins so yatra/yatra.php loads before yatra-pro/yatra-pro.php when both are active.
8 * 2. Deactivates old Pro (version &lt; 3.0.0) when Free 3.0+ is running, and stores an admin notice.
9 *
10 * @package Yatra
11 */
12
13 declare(strict_types=1);
14
15 if (!defined('ABSPATH')) {
16 exit;
17 }
18
19 /**
20 * Minimum Yatra Pro version that works with Yatra Free 3.0.x.
21 */
22 function yatra_get_minimum_compatible_pro_version(): string
23 {
24 return '3.0.0';
25 }
26
27 /**
28 * Where customers download Yatra Pro (account / downloads).
29 */
30 function yatra_get_compatible_pro_account_url(): string
31 {
32 return 'https://store.mantrabrain.com/account';
33 }
34
35 /**
36 * Normalize plugin header versions for comparison. PHP's version_compare treats "3.0" as older than "3.0.0",
37 * so Pro 3.0 was incorrectly flagged as incompatible with minimum 3.0.0.
38 *
39 * @param string $version Raw Version header value.
40 */
41 function yatra_normalize_version_for_compare(string $version): string
42 {
43 $version = trim($version);
44 if ($version === '') {
45 return '0.0.0';
46 }
47
48 if (preg_match('/^(\d+(?:\.\d+)*)/', $version, $m)) {
49 $parts = array_map('intval', explode('.', $m[1]));
50 while (count($parts) < 3) {
51 $parts[] = 0;
52 }
53
54 return implode('.', array_slice($parts, 0, 3));
55 }
56
57 return $version;
58 }
59
60 /**
61 * Whether installed Yatra Pro version meets the minimum for Yatra Free 3.0+.
62 */
63 function yatra_is_pro_version_compatible(string $pro_version): bool
64 {
65 $pro = yatra_normalize_version_for_compare($pro_version);
66 $min = yatra_normalize_version_for_compare(yatra_get_minimum_compatible_pro_version());
67
68 return version_compare($pro, $min, '>=');
69 }
70
71 /**
72 * Put Yatra Free and Yatra Pro at the start of the active list, in that order, so Free always boots before Pro.
73 *
74 * @return bool True if the option was updated.
75 */
76 function yatra_normalize_yatra_plugins_active_order(): bool
77 {
78 if (!function_exists('get_option') || !function_exists('update_option')) {
79 return false;
80 }
81
82 $active = get_option('active_plugins', []);
83 if (!is_array($active) || $active === []) {
84 return false;
85 }
86
87 $free = 'yatra/yatra.php';
88 $pro = 'yatra-pro/yatra-pro.php';
89
90 $has_free = in_array($free, $active, true);
91 $has_pro = in_array($pro, $active, true);
92
93 if (!$has_free || !$has_pro) {
94 return false;
95 }
96
97 $rest = array_values(array_diff($active, [$free, $pro]));
98 $merged = array_merge([$free, $pro], $rest);
99
100 if ($merged === array_values($active)) {
101 return false;
102 }
103
104 update_option('active_plugins', $merged);
105
106 return true;
107 }
108
109 /**
110 * If Yatra Free 3.0+ is active and an old Yatra Pro (&lt; 3.0.0) is active, deactivate Pro and queue an admin notice.
111 */
112 function yatra_deactivate_incompatible_old_pro(): void
113 {
114 if (!defined('YATRA_VERSION')) {
115 return;
116 }
117
118 if (version_compare(YATRA_VERSION, '3.0.0', '<')) {
119 return;
120 }
121
122 if (!function_exists('get_plugin_data')) {
123 require_once ABSPATH . 'wp-admin/includes/plugin.php';
124 }
125
126 $pro_file = WP_PLUGIN_DIR . '/yatra-pro/yatra-pro.php';
127 if (!is_readable($pro_file)) {
128 return;
129 }
130
131 $data = get_plugin_data($pro_file, false, false);
132 $pro_version = isset($data['Version']) ? trim((string) $data['Version']) : '0';
133
134 if ($pro_version === '' || yatra_is_pro_version_compatible($pro_version)) {
135 return;
136 }
137
138 if (!function_exists('is_plugin_active')) {
139 require_once ABSPATH . 'wp-admin/includes/plugin.php';
140 }
141
142 if (!is_plugin_active('yatra-pro/yatra-pro.php')) {
143 return;
144 }
145
146 deactivate_plugins('yatra-pro/yatra-pro.php', true);
147
148 set_transient(
149 'yatra_admin_notice_incompatible_pro_deactivated',
150 [
151 'pro_version' => $pro_version,
152 'min_required' => yatra_get_minimum_compatible_pro_version(),
153 ],
154 WEEK_IN_SECONDS
155 );
156 }
157
158 /**
159 * Run guard once this file is loaded (yatra.php included after constants).
160 */
161 function yatra_run_incompatible_pro_guard(): void
162 {
163 yatra_normalize_yatra_plugins_active_order();
164 yatra_deactivate_incompatible_old_pro();
165 }
166
167 /**
168 * Admin notice after we deactivated incompatible Pro.
169 */
170 function yatra_admin_notice_incompatible_pro_deactivated(): void
171 {
172 if (!is_admin() || !current_user_can('activate_plugins')) {
173 return;
174 }
175
176 $payload = get_transient('yatra_admin_notice_incompatible_pro_deactivated');
177 if (!is_array($payload)) {
178 return;
179 }
180
181 $pro_v = isset($payload['pro_version']) ? sanitize_text_field((string) $payload['pro_version']) : '';
182 $min_v = isset($payload['min_required']) ? sanitize_text_field((string) $payload['min_required']) : yatra_get_minimum_compatible_pro_version();
183
184 $dismiss_url = wp_nonce_url(
185 add_query_arg('yatra_dismiss_pro_notice', '1'),
186 'yatra_dismiss_pro_notice'
187 );
188
189 ?>
190 <div class="notice notice-error is-dismissible" data-yatra-pro-notice="1">
191 <p>
192 <strong><?php esc_html_e('Yatra Pro was deactivated', 'yatra'); ?></strong>
193 </p>
194 <p>
195 <?php
196 printf(
197 /* translators: 1: detected Yatra Pro version, 2: minimum required Pro version, 3: current Yatra Free version */
198 esc_html__(
199 'Your site had Yatra Pro %1$s active together with Yatra %3$s. Pro versions older than %2$s are not compatible with Yatra 3.0 and were causing fatal errors (missing classes such as Yatra_Form). Yatra Pro has been deactivated automatically.',
200 'yatra'
201 ),
202 esc_html($pro_v !== '' ? $pro_v : '?'),
203 esc_html($min_v),
204 esc_html(defined('YATRA_VERSION') ? YATRA_VERSION : '3.0')
205 );
206 ?>
207 </p>
208 <p>
209 <?php
210 $account_url = yatra_get_compatible_pro_account_url();
211 printf(
212 /* translators: 1: minimum Yatra Pro version, 2: HTML link to MantraBrain store account */
213 wp_kses_post(
214 __('Please download and install <strong>Yatra Pro %1$s or newer</strong> from your MantraBrain store account: %2$s to use Pro features with this version of Yatra.', 'yatra')
215 ),
216 esc_html($min_v),
217 sprintf(
218 '<a href="%1$s" target="_blank" rel="noopener noreferrer">%2$s</a>',
219 esc_url($account_url),
220 esc_html($account_url)
221 )
222 );
223 ?>
224 </p>
225 <p>
226 <a href="<?php echo esc_url($dismiss_url); ?>" class="button">
227 <?php esc_html_e('Dismiss this notice', 'yatra'); ?>
228 </a>
229 </p>
230 </div>
231 <?php
232 }
233
234 /**
235 * Dismiss the notice (clears transient).
236 */
237 function yatra_handle_dismiss_incompatible_pro_notice(): void
238 {
239 if (!is_admin() || !isset($_GET['yatra_dismiss_pro_notice']) || !current_user_can('activate_plugins')) {
240 return;
241 }
242
243 if (!isset($_GET['_wpnonce']) || !wp_verify_nonce(sanitize_text_field(wp_unslash($_GET['_wpnonce'])), 'yatra_dismiss_pro_notice')) {
244 return;
245 }
246
247 delete_transient('yatra_admin_notice_incompatible_pro_deactivated');
248 wp_safe_redirect(remove_query_arg(['yatra_dismiss_pro_notice', '_wpnonce']));
249 exit;
250 }
251
252 /**
253 * Remove the "Pro was deactivated" notice once installed Yatra Pro meets the minimum (e.g. header "3.0" vs minimum "3.0.0").
254 */
255 function yatra_clear_stale_pro_incompatible_notice(): void
256 {
257 if (!is_admin()) {
258 return;
259 }
260
261 if (!get_transient('yatra_admin_notice_incompatible_pro_deactivated')) {
262 return;
263 }
264
265 if (!function_exists('get_plugin_data')) {
266 require_once ABSPATH . 'wp-admin/includes/plugin.php';
267 }
268
269 $pro_file = WP_PLUGIN_DIR . '/yatra-pro/yatra-pro.php';
270 if (!is_readable($pro_file)) {
271 return;
272 }
273
274 $data = get_plugin_data($pro_file, false, false);
275 $v = isset($data['Version']) ? trim((string) $data['Version']) : '0';
276
277 if ($v !== '' && yatra_is_pro_version_compatible($v)) {
278 delete_transient('yatra_admin_notice_incompatible_pro_deactivated');
279 }
280 }
281
282 add_action('admin_init', 'yatra_clear_stale_pro_incompatible_notice', 0);
283 add_action('admin_notices', 'yatra_admin_notice_incompatible_pro_deactivated', 1);
284 add_action('admin_init', 'yatra_handle_dismiss_incompatible_pro_notice', 1);
285
286 /**
287 * After Free is installed/updated via the dashboard, normalize load order before the next request hits plugins.
288 */
289 function yatra_on_upgrader_process_complete($upgrader, array $hook_extra): void
290 {
291 if (!isset($hook_extra['plugin']) || $hook_extra['plugin'] !== 'yatra/yatra.php') {
292 return;
293 }
294 yatra_normalize_yatra_plugins_active_order();
295 yatra_deactivate_incompatible_old_pro();
296 }
297
298 add_action('upgrader_process_complete', 'yatra_on_upgrader_process_complete', 10, 2);
299
300 /**
301 * On Plugins → Installed Plugins, show a row warning under Yatra Pro if the installed package is &lt; 3.0 (cannot be safely activated with Yatra 3.0 Free).
302 *
303 * @param string $plugin_file Relative plugin path.
304 * @param array<string, mixed> $plugin_data Headers from the plugin file.
305 */
306 function yatra_plugin_row_old_pro_warning(string $plugin_file, array $plugin_data): void
307 {
308 if (!defined('YATRA_VERSION') || version_compare(YATRA_VERSION, '3.0.0', '<')) {
309 return;
310 }
311
312 $v = isset($plugin_data['Version']) ? trim((string) $plugin_data['Version']) : '0';
313 if ($v === '' || yatra_is_pro_version_compatible($v)) {
314 return;
315 }
316
317 $account_url = yatra_get_compatible_pro_account_url();
318 $msg = sprintf(
319 /* translators: 1: minimum Yatra Pro version, 2: account URL */
320 esc_html__(
321 'This Yatra Pro version is not compatible with Yatra 3.0. Activating it will cause a fatal error. Install Yatra Pro %1$s or newer from your MantraBrain store account (%2$s) before activating.',
322 'yatra'
323 ),
324 esc_html(yatra_get_minimum_compatible_pro_version()),
325 esc_html($account_url)
326 );
327
328 printf(
329 '<tr class="plugin-update-tr active yatra-pro-incompatible-row"><td colspan="4" class="plugin-update colspanchange"><div class="update-message notice inline notice-error notice-alt"><p>%s</p></div></td></tr>',
330 $msg
331 );
332 }
333
334 add_action('after_plugin_row_yatra-pro/yatra-pro.php', 'yatra_plugin_row_old_pro_warning', 10, 2);
335