PluginProbe
Yatra – Travel Booking & Tour Operator Software / 3.0.17
Yatra – Travel Booking & Tour Operator Software v3.0.17
3.0.17 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 All 85 releases
← All changes | uninstall.php +189 -20 2.0.0 → 3.0.17 View file →
@@ -1,30 +1,199 @@
1 1 <?php
2 +/**
3 + * Runs when Yatra is deleted from the Plugins screen.
4 + *
5 + * Deleting a plugin is not the same as deactivating it, and WordPress only
6 + * loads this one file — the plugin itself is never bootstrapped, so nothing
7 + * here may assume an autoloader, a class or a helper exists.
8 + *
9 + * Nothing is removed unless the operator has switched on
10 + * "Delete all data on uninstall" (Yatra → Settings → Uninstall). Left off,
11 + * which is the default, every table and option survives so the plugin can be
12 + * reinstalled with its bookings and customers intact.
13 + *
14 + * @package Yatra
15 + */
2 16
17 +defined('WP_UNINSTALL_PLUGIN') || exit;
18 +
3 19 /**
4 - * Fired when the plugin is uninstalled.
20 + * Table suffixes owned by the free plugin.
5 21 *
6 - * When populating this file, consider the following flow
7 - * of control:
22 + * Mirrors \Yatra\Services\InstallerService::getRequiredTables(). Hard-coded
23 + * on purpose: that class is not loaded during uninstall, and a missing
24 + * autoloader must not leave data half-removed. Yatra Pro removes its own
25 + * tables from its own uninstall.php.
26 + */
27 +function yatra_uninstall_free_table_suffixes(): array
28 +{
29 + return [
30 + 'yatra_trips',
31 + 'yatra_bookings',
32 + 'yatra_booking_payments',
33 + 'yatra_customers',
34 + 'yatra_booking_travellers',
35 + 'yatra_booking_traveller_meta',
36 + 'yatra_booking_departures',
37 + 'yatra_reviews',
38 + 'yatra_discounts',
39 + 'yatra_enquiries',
40 + 'yatra_trip_availability_dates',
41 + 'yatra_trip_availability_rules',
42 + 'yatra_trip_revisions',
43 + 'yatra_trip_departures',
44 + 'yatra_trip_itinerary_days',
45 + 'yatra_trip_itinerary_day_entry',
46 + 'yatra_classifications',
47 + 'yatra_trip_classifications',
48 + 'yatra_trip_content',
49 + 'yatra_tour_dates',
50 + ];
51 +}
52 +
53 +/**
54 + * Is Yatra Pro still installed on this site?
8 55 *
9 - * - This method should be static
10 - * - Check if the $_REQUEST content actually is the plugin name
11 - * - Run an admin referrer check to make sure it goes through authentication
12 - * - Verify the output of $_GET makes sense
13 - * - Repeat with other user roles. Best directly by using the links/query string parameters.
14 - * - Repeat things for multisite. Once for a single site in the network, once sitewide.
56 + * Deleting the free plugin must not take Pro's settings and scheduled work with
57 + * it while Pro is still sitting there: Pro keeps its own tables through its own
58 + * uninstall.php, so wiping its configuration here would leave it half removed.
59 + * Once Pro has gone too, there is nothing left to protect and the sweep below
60 + * takes everything, so nothing is orphaned either way.
61 + */
62 +function yatra_uninstall_pro_still_installed(): bool
63 +{
64 + return file_exists(WP_PLUGIN_DIR . '/yatra-pro/yatra-pro.php');
65 +}
66 +
67 +/**
68 + * Pro-owned options that do not carry the `yatra_pro_` prefix.
15 69 *
16 - * This file may be updated more in future version of the Boilerplate; however, this is the
17 - * general skeleton and outline for how the file should work.
70 + * Mirrors yatra_pro_uninstall_extra_option_names() in Yatra Pro. Repeated here
71 + * because uninstall.php runs with no autoloader and cannot read the other
72 + * plugin, the same reason both files hard-code their table lists.
73 + */
74 +function yatra_uninstall_pro_owned_options(): array
75 +{
76 + return [
77 + 'yatra_license',
78 + 'yatra_abandoned_last_seen_id',
79 + 'yatra_abandoned_recovery_settings',
80 + 'yatra_ai_chat_limits',
81 + 'yatra_ai_trip_chat_enabled',
82 + 'yatra_dynamic_pricing_settings',
83 + 'yatra_facebook_pixel_event_log',
84 + 'yatra_facebook_pixel_settings',
85 + 'yatra_google_analytics_event_log',
86 + 'yatra_google_analytics_settings',
87 + 'yatra_mailchimp_settings',
88 + 'yatra_mailchimp_sync_log',
89 + 'yatra_team_keep_access_on_module_disable',
90 + ];
91 +}
92 +
93 +/**
94 + * Pro cron hooks registered under the plain `yatra_` prefix.
18 95 *
19 - * For more information, see the following discussion:
20 - * https://github.com/tommcfarlin/WordPress-Plugin-Boilerplate/pull/123#issuecomment-28541913
21 - *
22 - *
23 - * @since 1.0.0
24 - * * @package Yatra
96 + * Mirrors yatra_pro_uninstall_cron_hooks(). Without this the free plugin's
97 + * prefix test matched all of them and unscheduled Pro's queue, demand scores,
98 + * reminders and consent runs while Pro was still installed and relying on them.
25 99 */
100 +function yatra_uninstall_pro_owned_cron_hooks(): array
101 +{
102 + return [
103 + 'yatra_ai_audit_retention_tick',
104 + 'yatra_calculate_demand_scores',
105 + 'yatra_cleanup_abandoned_bookings',
106 + 'yatra_consent_daily_cron',
107 + 'yatra_process_email_queue',
108 + 'yatra_process_recovery_emails',
109 + 'yatra_send_payment_reminders',
110 + 'yatra_sync_scheduled_payments',
111 + ];
112 +}
26 113
27 -// If uninstall not called from WordPress, then exit.
28 -if ( ! defined( 'WP_UNINSTALL_PLUGIN' ) ) {
29 - exit;
114 +/**
115 + * Remove Yatra's data for the current site.
116 + */
117 +function yatra_uninstall_cleanup_site(): void
118 +{
119 + global $wpdb;
120 +
121 + if (!get_option('yatra_delete_data_on_uninstall')) {
122 + return;
123 + }
124 +
125 + // Several of these tables are the target of a foreign key held by another
126 + // (availability and revisions both point at trips), so a plain DROP fails
127 + // for whichever one is reached first and that table survives the uninstall.
128 + // Order should not decide whether data is removed, so the constraints are
129 + // lifted for the duration.
130 + $wpdb->query('SET FOREIGN_KEY_CHECKS = 0');
131 +
132 + foreach (yatra_uninstall_free_table_suffixes() as $suffix) {
133 + $table = $wpdb->prefix . $suffix;
134 + // phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
135 + $wpdb->query("DROP TABLE IF EXISTS `{$table}`");
136 + }
137 +
138 + $wpdb->query('SET FOREIGN_KEY_CHECKS = 1');
139 +
140 + // Scheduled work must go too, or WordPress keeps firing hooks for a plugin
141 + // that is no longer installed.
142 + $protectPro = yatra_uninstall_pro_still_installed();
143 + $proHooks = yatra_uninstall_pro_owned_cron_hooks();
144 + foreach ((array) _get_cron_array() as $timestamp => $hooks) {
145 + foreach ((array) $hooks as $hook => $events) {
146 + $hook = (string) $hook;
147 + if (strpos($hook, 'yatra') !== 0) {
148 + continue;
149 + }
150 + if ($protectPro && (strpos($hook, 'yatra_pro') === 0 || in_array($hook, $proHooks, true))) {
151 + continue;
152 + }
153 + foreach ((array) $events as $event) {
154 + wp_unschedule_event($timestamp, $hook, $event['args'] ?? []);
155 + }
156 + }
157 + }
158 +
159 + // Options and transients. `yatra_pro_` is left alone: those belong to Yatra
160 + // Pro, which removes them from its own uninstall.php, and deleting them
161 + // here would wipe Pro's settings whenever the free plugin is removed first.
162 + $options = $wpdb->get_col(
163 + "SELECT option_name FROM {$wpdb->options}
164 + WHERE option_name LIKE 'yatra\\_%'
165 + AND option_name NOT LIKE 'yatra\\_pro\\_%'"
166 + );
167 + $proOptions = $protectPro ? yatra_uninstall_pro_owned_options() : [];
168 + foreach ((array) $options as $option) {
169 + if ($proOptions && in_array($option, $proOptions, true)) {
170 + continue;
171 + }
172 + delete_option($option);
173 + }
174 +
175 + $transients = $wpdb->get_col(
176 + "SELECT option_name FROM {$wpdb->options}
177 + WHERE option_name LIKE '\\_transient\\_yatra\\_%'
178 + OR option_name LIKE '\\_transient\\_timeout\\_yatra\\_%'"
179 + );
180 + foreach ((array) $transients as $transient) {
181 + delete_option($transient);
182 + }
183 +
184 + // User meta Yatra set on customers and staff.
185 + $wpdb->query("DELETE FROM {$wpdb->usermeta} WHERE meta_key LIKE 'yatra\\_%'");
186 +}
187 +
188 +// Network-wide installs keep a separate set of tables and options per site, so
189 +// each one has to be cleaned on its own.
190 +if (is_multisite()) {
191 + $sites = get_sites(['fields' => 'ids', 'number' => 0]);
192 + foreach ((array) $sites as $siteId) {
193 + switch_to_blog((int) $siteId);
194 + yatra_uninstall_cleanup_site();
195 + restore_current_blog();
196 + }
197 +} else {
198 + yatra_uninstall_cleanup_site();
30 199 }