-
Notifications
You must be signed in to change notification settings - Fork 0
/
wp-multisite-cookie-manager.php
500 lines (421 loc) · 20.1 KB
/
wp-multisite-cookie-manager.php
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
<?php
/**
* Plugin Name: MN - WordPress Multisite Cookie Manager
* Plugin URI: https://github.com/mnestorov/wp-multisite-cookie-manager
* Description: Manage cookies across a WordPress multisite network.
* Version: 2.1.3
* Author: Martin Nestorov
* Author URI: https://github.com/mnestorov
* Text Domain: mn-wordpress-multisite-cookie-manager
* Tags: wp, wp-plugin, wp-admin, wordpress, wordpress-plugin, wordpress-cookie, wordpress-multisite
*/
// Enable WP_DEBUG in your WordPress configuration to catch errors during development.
// In your wp-config.php file:
// define( 'WP_DEBUG', true );
// define( 'WP_DEBUG_LOG', true );
// define( 'WP_DEBUG_DISPLAY', false );
/**
* Geolocation API key
* Get the key from: https://app.ipgeolocation.io/
*/
define('GEO_API_KEY', 'YOUR_API_KEY');
// Register the uninstall hook
register_uninstall_hook(__FILE__, 'mn_custom_cookie_manager_uninstall');
// Function to run on plugin deactivation
function mn_custom_cookie_manager_deactivate() {
// Optionally remove any scheduled events related to this plugin
wp_clear_scheduled_hook('write_cookie_usage_log_entries_hook');
}
register_deactivation_hook(__FILE__, 'mn_custom_cookie_manager_deactivate');
// Remove the `cookie_usage` table from the database
function mn_custom_cookie_manager_uninstall() {
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$wpdb->query("DROP TABLE IF EXISTS $table_name");
}
// Generate the cookie name
function mn_get_unique_cookie_name() {
// Get the site name
$site_name = get_bloginfo('name');
// Convert the site name to lowercase and replace white spaces with underscores
$formatted_name = strtolower(str_replace(' ', '_', $site_name));
// Get the current blog ID
$blog_id = get_current_blog_id();
// Add a prefix of "__" before the name and append the blog_id as a suffix
$cookie_name = '__' . $formatted_name . '_' . $blog_id;
return $cookie_name;
}
// Custom error handling function to log or display errors in a standardized way.
function mn_log_error($message, $error_type = E_USER_NOTICE) {
if ( WP_DEBUG ) {
if ( defined('WP_DEBUG_LOG') && WP_DEBUG_LOG ) {
error_log($message);
}
if ( defined('WP_DEBUG_DISPLAY') && WP_DEBUG_DISPLAY ) {
trigger_error($message, $error_type);
}
}
}
// Function to register a new menu page in the network admin
function mn_register_cookie_settings_page() {
add_menu_page(
esc_html__('Cookie Settings', 'mn-wordpress-multisite-cookie-manager'),
esc_html__('Cookie Settings', 'mn-wordpress-multisite-cookie-manager'),
'manage_options',
'cookie-settings',
'mn_cookie_settings_page',
'',
99
);
}
add_action('admin_menu', 'mn_register_cookie_settings_page');
// Function to display the cookie settings page
function mn_cookie_settings_page() {
// For debug
error_reporting(E_ALL);
ini_set('display_errors', 1);
// Get the unique cookie name
$cookie_name = mn_get_unique_cookie_name();
// Get the current blog ID
$blog_id = get_current_blog_id();
// Handle form submission for updating cookie settings
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['custom_cookie_nonce']) && wp_verify_nonce($_POST['custom_cookie_nonce'], 'custom_cookie_nonce')) {
// Decode the JSON data from the textarea
$custom_cookie_expirations = json_decode(stripslashes($_POST['custom_cookie_expirations']), true);
if (json_last_error() == JSON_ERROR_NONE && is_array($custom_cookie_expirations)) {
update_blog_option($blog_id, 'custom_cookie_expirations', $custom_cookie_expirations);
echo '<div class="updated"><p>' . esc_html__('Settings saved.', 'mn-wordpress-multisite-cookie-manager') . '</p></div>';
} else {
echo '<div class="error"><p>' . esc_html__('Invalid JSON data.', 'mn-wordpress-multisite-cookie-manager') . '</p></div>';
}
}
// Fetch current settings
$custom_cookie_expirations = get_blog_option($blog_id, 'custom_cookie_expirations', array());
// Output form for managing cookie settings
echo '<div class="wrap">';
echo '<form method="post" enctype="multipart/form-data">';
wp_nonce_field('custom_cookie_nonce', 'custom_cookie_nonce');
echo '<h1>' . esc_html__('Cookie Settings', 'mn-wordpress-multisite-cookie-manager') . '</h1>';
echo '<div>';
echo '<input type="submit" name="export_settings" value="' . esc_attr__('Export Settings', 'mn-wordpress-multisite-cookie-manager') . '" class="button button-primary" style="margin-right:5px;">';
echo '<input type="submit" name="import_settings" value="' . esc_attr__('Import Settings', 'mn-wordpress-multisite-cookie-manager') . '" class="button button-primary" style="margin-right:5px;">';
echo '<input type="file" name="import_settings_file" accept=".json">';
echo '</div>';
echo '<table class="form-table" role="presentation"><tbody><tr>';
echo '<th scope="row"><label>' . esc_html__('Current Blog ID:', 'mn-wordpress-multisite-cookie-manager') . '</label></th>';
echo '<td><input type="text" class="regular-text" value="' . esc_html($blog_id) . '" disabled></td>';
echo '</tr><tr>';
echo '<th scope="row"><label>' . esc_html__('Generated Cookie Name:', 'mn-wordpress-multisite-cookie-manager') . '</label></th>';
echo '<td><input type="text" class="regular-text" value="'. esc_html($cookie_name) . '" disabled></td>';
echo '</tr></tbody></table>';
echo '<table class="form-table" role="presentation"><tbody><tr>';
echo '<th scope="row"><label>' . esc_html__('Cookie Expirations:', 'mn-wordpress-multisite-cookie-manager') . '</label></th>';
echo '<td><textarea name="custom_cookie_expirations" rows="5" cols="50">' . esc_textarea(json_encode($custom_cookie_expirations, JSON_PRETTY_PRINT)) . '</textarea><p class="description">Input a JSON object with user roles and corresponding expiration times in seconds.</p></td>';
echo '</tr></tbody></table>';
echo '<br>';
echo '<div class="tablenav bottom"><div class="alignleft actions bulkactions">';
echo '<input type="submit" value="' . esc_attr__('Save Settings', 'mn-wordpress-multisite-cookie-manager') . '" class="button button-primary">';
echo '<br class="clear">';
echo '</div></div>';
//echo '<div class="mn-debug-info"><p>DEBUG INFO</p><pre>' . print_r($custom_cookie_expirations, true) . '</pre></div>';
echo '</form>';
echo '</div>';
// Handle export of cookie settings
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['export_settings']) && isset($_POST['custom_cookie_nonce']) && wp_verify_nonce($_POST['custom_cookie_nonce'], 'custom_cookie_nonce')) {
$settings_json = mn_export_cookie_settings();
header('Content-Type: application/json');
header('Content-Disposition: attachment; filename=cookie-settings.json');
echo $settings_json;
exit;
}
// Handle import of cookie settings
if ($_SERVER['REQUEST_METHOD'] == 'POST' && isset($_POST['import_settings']) && isset($_FILES['import_settings_file']) && $_FILES['import_settings_file']['error'] == 0 && isset($_POST['custom_cookie_nonce']) && wp_verify_nonce($_POST['custom_cookie_nonce'], 'custom_cookie_nonce')) {
$json_settings = file_get_contents($_FILES['import_settings_file']['tmp_name']);
if (mn_import_cookie_settings($json_settings)) {
echo '<div class="updated"><p>' . esc_html__('Settings imported successfully.', 'mn-wordpress-multisite-cookie-manager') . '</p></div>';
} else {
echo '<div class="error"><p>' . esc_html__('Failed to import settings.', 'mn-wordpress-multisite-cookie-manager') . '</p></div>';
}
}
}
// Function to handle the logic for cookie expiration based on user roles and login status
function mn_get_cookie_expiration($default_expiration) {
$blog_id = get_current_blog_id();
$cookie_expirations = get_blog_option($blog_id, 'custom_cookie_expirations', array());
$expiration = $default_expiration;
if ($cookie_expirations) {
if (is_user_logged_in()) {
$current_user = wp_get_current_user();
if (in_array('administrator', $current_user->roles)) {
$expiration = $default_expiration + DAY_IN_SECONDS;
} else {
$expiration = $default_expiration - HOUR_IN_SECONDS;
}
} else {
$expiration = $default_expiration - (30 * MINUTE_IN_SECONDS);
}
} else {
mn_log_error('Failed to fetch custom cookie expirations from the database.');
}
return $expiration;
}
// Function to set a custom cookie on page load
function mn_set_custom_cookie() {
$default_expiration = 86400; // Example default expiration of 1 day
$cookie_expiration = mn_get_cookie_expiration($default_expiration);
$cookie_name = mn_get_unique_cookie_name(); // Get the unique cookie name
// Get geolocation data
$geo_data = mn_get_geolocation_data();
// Check if a session ID cookie already exists, otherwise generate a new session ID
$session_id = isset($_COOKIE['__user_session']) ? $_COOKIE['__user_session'] : wp_generate_uuid4();
// Build the cookie value as a JSON object
$cookie_value = json_encode(array(
'session_id' => $session_id,
'geo_data' => $geo_data
));
// Set the cookie
setcookie($cookie_name, $cookie_value, time() + $cookie_expiration, "/");
// Optionally set a separate session ID cookie if it doesn't exist yet
if (!isset($_COOKIE['__user_session'])) {
setcookie('__user_session', $session_id, time() + $cookie_expiration, "/");
}
// Log the session_id to verify it's being set correctly
mn_log_error('Session ID: ' . $session_id);
}
add_action('init', 'mn_set_custom_cookie');
// Function to create a new database table for logging cookie usage on plugin activation
function mn_create_cookie_usage_table() {
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$charset_collate = $wpdb->get_charset_collate();
$sql = "CREATE TABLE $table_name (
id mediumint(9) NOT NULL AUTO_INCREMENT,
blog_id mediumint(9) NOT NULL,
cookie_name varchar(255) NOT NULL,
cookie_value TEXT NOT NULL,
time_stamp datetime DEFAULT '0000-00-00 00:00:00' NOT NULL,
PRIMARY KEY (id)
) $charset_collate;";
require_once(ABSPATH . 'wp-admin/includes/upgrade.php');
$result = dbDelta($sql);
if ( !empty($result['errors']) ) {
mn_log_error(print_r($result['errors'], true));
}
}
register_activation_hook(__FILE__, 'mn_create_cookie_usage_table');
// Function to log cookie usage on page load
function mn_log_cookie_usage() {
if ( ! session_id() ) {
session_start();
}
$blog_id = get_current_blog_id();
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$unique_cookie_name = mn_get_unique_cookie_name(); // Get the unique cookie name
foreach ($_COOKIE as $cookie_name => $cookie_value) {
// Check if the cookie name matches the unique cookie name
if ($cookie_name === $unique_cookie_name) {
// Decode the JSON data from the cookie_value
$cookie_data = json_decode($cookie_value, true);
// Log the decoded data to your error log for debugging
mn_log_error(print_r($cookie_data, true));
$cookie_log_entry = array(
'blog_id' => $blog_id,
'cookie_name' => $cookie_name,
'cookie_value' => $cookie_value,
'time_stamp' => current_time('mysql')
);
// Log the entire cookie_log_entry array before attempting to insert it
mn_log_error(print_r($cookie_log_entry, true));
// Check if the cookie entry already exists in the database to prevent duplicates
$existing_entry = $wpdb->get_row($wpdb->prepare(
"SELECT * FROM $table_name WHERE blog_id = %d AND cookie_name = %s",
$blog_id,
$cookie_name
));
if (null === $existing_entry) {
$insert_result = $wpdb->insert($table_name, $cookie_log_entry);
if (false === $insert_result) {
mn_log_error('Failed to insert cookie usage log entry: ' . $wpdb->last_error);
} else {
mn_log_error('Successfully inserted cookie usage log entry');
}
}
// Log the raw cookie value to see what's being stored
mn_log_error('Raw cookie value: ' . $cookie_value);
}
}
}
add_action('init', 'mn_log_cookie_usage');
// Function to write log entries from transient to database hourly
function mn_write_cookie_usage_log_entries() {
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$log_entries = get_transient('cookie_usage_log_entries');
if ($log_entries && is_array($log_entries)) {
$all_inserts_successful = true;
foreach ($log_entries as $entry) {
$insert_result = $wpdb->insert($table_name, $entry);
if ($insert_result === false) {
error_log("Failed to insert cookie usage log entry: " . $wpdb->last_error);
$all_inserts_successful = false;
}
}
if ($all_inserts_successful) {
delete_transient('cookie_usage_log_entries');
}
}
}
add_action('write_cookie_usage_log_entries_hook', 'mn_write_cookie_usage_log_entries');
// Schedule hourly event to write log entries to database
if (!wp_next_scheduled('write_cookie_usage_log_entries_hook')) {
wp_schedule_event(time(), 'hourly', 'write_cookie_usage_log_entries_hook');
}
// Function to register a submenu page for cookie usage reports
function mn_register_cookie_reporting_page() {
add_submenu_page(
'cookie-settings',
esc_html__('Cookie Usage Reports', 'mn-wordpress-multisite-cookie-manager'),
esc_html__('Cookie Usage Reports', 'mn-wordpress-multisite-cookie-manager'),
'manage_options',
'cookie-reports',
'mn_cookie_reporting_page'
);
}
add_action('admin_menu', 'mn_register_cookie_reporting_page');
// Function to display cookie usage reports
function mn_cookie_reporting_page() {
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$unique_cookie_name = mn_get_unique_cookie_name(); // Get the unique cookie name
// Modify the SQL query to include a WHERE clause that filters on cookie_name
$results = $wpdb->get_results($wpdb->prepare(
"SELECT cookie_name, cookie_value, COUNT(DISTINCT blog_id) as blog_count, time_stamp
FROM $table_name
WHERE cookie_name = %s
GROUP BY cookie_name",
$unique_cookie_name
), OBJECT);
echo '<div class="wrap">';
echo '<h1>Cookie Usage Reports</h1>';
// Form for clearing cookies
echo '<form method="post" style="margin-bottom: 20px;">';
wp_nonce_field('mn_clear_cookies_action', 'mn_clear_cookies_nonce');
echo '<input type="submit" name="mn_clear_cookies" value="Clear Cookies" class="button button-primary">';
echo '</form>';
echo '<table class="wp-list-table widefat fixed striped">';
echo '<thead><tr><th>Cookie Name</th><th>Country</th><th>Session ID</th><th>Number of Blogs</th><th>Timestamp</th></tr></thead>';
echo '<tbody>';
foreach ($results as $row) {
// Remove any escape characters before decoding
$cleaned_cookie_value = stripslashes($row->cookie_value);
// Decode the cleaned JSON string into an associative array
$cookie_data = json_decode($cleaned_cookie_value, true);
// Check if json_decode was successful
if (json_last_error() == JSON_ERROR_NONE) {
$country = isset($cookie_data['geo_data']['country_name']) ? $cookie_data['geo_data']['country_name'] : 'Unknown';
$session_id = isset($cookie_data['session_id']) ? $cookie_data['session_id'] : 'Unknown';
} else {
$country = 'JSON Decoding Error';
$session_id = 'JSON Decoding Error';
}
echo '<tr>';
echo '<td>' . esc_html($row->cookie_name) . '</td>';
echo '<td>' . esc_html($country) . '</td>'; // Display country
echo '<td>' . esc_html($session_id) . '</td>'; // Display session ID
echo '<td>' . esc_html($row->blog_count) . '</td>';
echo '<td>' . esc_html($row->time_stamp) . '</td>';
echo '</tr>';
}
echo '</tbody>';
echo '</table>';
echo '</div>';
}
// Function to export cookie settings to a JSON file
function mn_export_cookie_settings() {
$custom_cookie_expirations = get_site_option('custom_cookie_expirations', '');
return json_encode($custom_cookie_expirations, JSON_PRETTY_PRINT);
}
// Function to import cookie settings from a JSON file
function mn_import_cookie_settings($json_settings) {
$settings_array = json_decode($json_settings, true);
if (json_last_error() == JSON_ERROR_NONE && is_array($settings_array)) {
update_site_option('custom_cookie_expirations', $settings_array);
return true;
}
return false;
}
// Function to get geo-location data
function mn_get_geolocation_data() {
// Check if the geolocation data is already cached
$geo_data = get_transient('geo_data');
if ($geo_data !== false) {
return $geo_data; // Return cached data if it exists
}
// Geolocation API key
$api_key = GEO_API_KEY;
// Get the user's IP address
$user_ip = $_SERVER['REMOTE_ADDR'];
$api_url = "https://api.ipgeolocation.io/ipgeo?apiKey=" . $api_key . "&ip=" . $user_ip;
// Make a request to the IP Geolocation API
$response = wp_remote_get($api_url);
// Check for errors in the response
if (is_wp_error($response)) {
mn_log_error('Geolocation API error: ' . $response->get_error_message());
return 'Unable to retrieve geo-location data';
}
// Parse the response body
$geo_data = json_decode(wp_remote_retrieve_body($response), true);
// Check for valid data
if (!isset($geo_data['country_name']) || !isset($geo_data['city'])) {
return false;
}
// Cache the geolocation data for 1 hour
set_transient('geo_data', $geo_data, HOUR_IN_SECONDS);
return $geo_data;
}
// Function to clear the cookies from the database
function mn_clear_cookies() {
global $wpdb;
$table_name = $wpdb->base_prefix . 'multisite_cookie_usage';
$unique_cookie_name = mn_get_unique_cookie_name(); // Get the unique cookie name
// Use the SQL DELETE statement to remove rows where the cookie_name matches the unique cookie name
$result = $wpdb->query($wpdb->prepare("DELETE FROM $table_name WHERE cookie_name = %s", $unique_cookie_name));
if (false === $result) {
// Handle error when query fails
mn_log_error('Failed to clear cookies: ' . $wpdb->last_error);
} else {
// Optionally, log the number of rows deleted
mn_log_error('Successfully cleared ' . $result . ' cookies');
}
}
// Function to check the nonce for security
function mn_handle_clear_cookies_request() {
if (isset($_POST['mn_clear_cookies'])) {
// Check nonce for security
check_admin_referer('mn_clear_cookies_action', 'mn_clear_cookies_nonce');
// Call function to clear cookies
mn_clear_cookies();
// Optionally, redirect or display a success message
add_settings_error('mn_clear_cookies', 'mn_clear_cookies', 'Cookies cleared successfully.', 'updated');
}
}
add_action('admin_init', 'mn_handle_clear_cookies_request');
// Function to inject custom CSS styling into the admin pages
function mn_custom_plugin_styles() {
echo '
<style type="text/css">
.mn-debug-info {
background-color: #f4cccc;
border: 1px solid #c00;
border-radius: 3px;
padding: 10px;
margin-top: 20px;
}
.mn-debug-info p {
font-weight: bold;
}
</style>
';
}
add_action('admin_head', 'mn_custom_plugin_styles');