PluginProbe
RabbitLoader / 3.0.3
RabbitLoader v3.0.3
4.0.2 4.0.1 4.0 3.2.0 3.1.1 3.1.0 3.0.5 3.0.3 3.0.4 2.17.1 2.17.2 2.17.3 2.17.4 2.17.5 2.17.6 2.17.7 2.18.0 2.18.1 2.18.2 2.18.3 2.18.4 2.18.5 2.18.6 2.18.7 2.18.8 All 129 releases
rabbit-loader / inc / admin.php

admin.php in RabbitLoader 3.0.3, at inc/admin.php

885 lines 36.0 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 class RabbitLoader_21_Admin
4 {
5
6 public static $rabbitloader_cache_warnings = false;
7 public static $admin_notice_shown = false;
8
9 const PURGE_POST_CHANGE = "PURGE_POST";
10 const PURGE_THEME_CHANGE = "PURGE_THEME";
11 const PURGE_PLUG_CHANGE = "PURGE_PLUGIN";
12 const PURGE_MANUAL_USER = "PURGE_USER";
13 const SURVEY_DIS_PERMA = 999;
14
15 public static function addActions()
16 {
17 add_action('admin_notices', 'RabbitLoader_21_Admin::admin_notices');
18 add_action('admin_init', 'RabbitLoader_21_Admin::admin_init');
19 add_action('network_admin_notices', 'RabbitLoader_21_Admin::admin_notices');
20 add_action('admin_menu', 'RabbitLoader_21_Admin::leftMenuOption');
21 add_action('admin_enqueue_scripts', function () {
22 $is_rl_page = RabbitLoader_21_Util_Core::isRLPage();
23 $dependencies = ['jquery'];
24 if ($is_rl_page) {
25 wp_enqueue_script('rabbitloader-react', 'no', [], false);
26 wp_enqueue_script('rabbitloader-react-dom', 'no', [], false);
27 $dependencies[] = 'rabbitloader-react';
28 $dependencies[] = 'rabbitloader-react-dom';
29 }
30
31 wp_enqueue_script('rabbitloader-index', RABBITLOADER_PLUG_URL . 'admin/js/index.js', $dependencies, RABBITLOADER_PLUG_VERSION);
32 if ($is_rl_page) {
33 $guard_config = wp_json_encode([
34 'adminAjax' => admin_url('admin-ajax.php'),
35 'isConnected' => self::isPluginActivated(),
36 ], JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
37 if ($guard_config !== false) {
38 wp_add_inline_script('rabbitloader-index', 'window.RLConflictGuardConfig = ' . $guard_config . ';', 'before');
39 }
40
41 wp_enqueue_script('rabbitloader-conflict-guard', RABBITLOADER_PLUG_URL . 'admin/js/conflict-guard.js', ['rabbitloader-index'], RABBITLOADER_PLUG_VERSION, true);
42 }
43 if ($is_rl_page && self::isPluginActivated()) {
44 $boot_data = wp_json_encode(self::getAdminBootData(), JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT);
45 if ($boot_data !== false) {
46 wp_add_inline_script('rabbitloader-index', 'window.rabbitloader_local_vars = ' . $boot_data . ';', 'before');
47 }
48 }
49 });
50
51 $purge_func = function () {
52 RL21UtilWP::verifyAjaxNonce();
53 $response = [
54 'result' => false,
55 'lpc' => 0 //local purge count
56 ];
57 if (!empty($_POST['post_id'])) {
58 $post_id = RabbitLoader_21_Util_Core::get_param('post_id', true);
59 RL21UtilWP::onPostChange($post_id);
60 $response['result'] = true;
61 } else {
62 RL21UtilWP::onPostChange(RL21UtilWP::POST_ID_ALL);
63 $response['result'] = true;
64 }
65 RL21UtilWP::execute_purge($response['lpc']);
66 delete_transient('rabbitloader_trans_overview_data');
67 RabbitLoader_21_Core::sendJsonResponse($response);
68 };
69
70 add_action('wp_ajax_rabbitloader_ajax_purge', $purge_func);
71 add_action('wp_ajax_nopriv_rabbitloader_ajax_purge', $purge_func);
72
73 $mode_change_func = function () {
74 RL21UtilWP::verifyAjaxNonce();
75
76 if (!RabbitLoader_21_Admin::canAccessModeAjax()) {
77 wp_send_json_error(null, 403);
78 return;
79 }
80
81 $private_mode = !empty($_POST['private_mode']);
82 RabbitLoader_21_Admin::updateModeValue($private_mode);
83 $response = [
84 'result' => true,
85 'private_mode' => $private_mode,
86 'me_mode' => $private_mode,
87 'mode' => $private_mode ? 'me' : 'everyone'
88 ];
89
90 RabbitLoader_21_Core::sendJsonResponse($response);
91 };
92
93 add_action('wp_ajax_rabbitloader_mode_change', $mode_change_func);
94 add_action('wp_ajax_nopriv_rabbitloader_mode_change', $mode_change_func);
95
96 $mode_get_func = function () {
97 if (empty($_POST['rl_nonce'])) {
98 $request_nonce = RabbitLoader_21_Util_Core::get_param('rl_nonce', true);
99 if (!empty($request_nonce)) {
100 $_POST['rl_nonce'] = $request_nonce;
101 }
102 }
103
104 if (empty($_POST['token'])) {
105 $request_token = RabbitLoader_21_Util_Core::get_param('token', true);
106 if (!empty($request_token)) {
107 $_POST['token'] = $request_token;
108 }
109 }
110
111 RL21UtilWP::verifyAjaxNonce();
112
113 if (!RabbitLoader_21_Admin::canAccessModeAjax()) {
114 wp_send_json_error(null, 403);
115 return;
116 }
117
118 RabbitLoader_21_Core::getWpUserOption($user_options);
119 $private_mode = !empty($user_options['private_mode_val']);
120 $response = [
121 'result' => true,
122 'private_mode' => $private_mode,
123 'me_mode' => $private_mode,
124 'mode' => $private_mode ? 'me' : 'everyone'
125 ];
126
127 RabbitLoader_21_Core::sendJsonResponse($response);
128 };
129
130 add_action('wp_ajax_rabbitloader_mode_get', $mode_get_func);
131 add_action('wp_ajax_nopriv_rabbitloader_mode_get', $mode_get_func);
132 add_action('wp_ajax_rabbitloader_get_exclusions', function () {
133 RL21UtilWP::verifyAjaxNonce();
134
135 if (!current_user_can('manage_options')) {
136 wp_send_json_error(null, 403);
137 return;
138 }
139
140 $response = self::getExcludePatternsState();
141 RabbitLoader_21_Core::sendJsonResponse($response);
142 });
143 add_action('wp_ajax_rabbitloader_add_exclusion', function () {
144 $json_body = json_decode(file_get_contents('php://input'), true);
145 if (is_array($json_body)) {
146 foreach ($json_body as $key => $value) {
147 $_POST[$key] = $value;
148 }
149 }
150
151 RL21UtilWP::verifyAjaxNonce();
152
153 if (!current_user_can('manage_options')) {
154 wp_send_json_error(null, 403);
155 return;
156 }
157
158 $incoming_patterns = [];
159 $single_pattern = '';
160
161 if (isset($_POST['pattern'])) {
162 $single_pattern = wp_unslash($_POST['pattern']);
163 } elseif (isset($_GET['pattern'])) {
164 $single_pattern = wp_unslash($_GET['pattern']);
165 }
166
167 if (!empty($single_pattern)) {
168 $incoming_patterns[] = $single_pattern;
169 }
170
171 if (!empty($_POST['patterns']) && is_array($_POST['patterns'])) {
172 foreach ($_POST['patterns'] as $pattern) {
173 $incoming_patterns[] = $pattern;
174 }
175 }
176
177 $normalized_patterns = self::normalizeExcludePatterns($incoming_patterns);
178 if (empty($normalized_patterns)) {
179 wp_send_json_error(['message' => 'At least one valid exclusion pattern is required.'], 400);
180 return;
181 }
182
183 $response = self::addExcludePatterns($normalized_patterns);
184 RabbitLoader_21_Core::sendJsonResponse($response);
185 });
186 add_action('wp_ajax_rabbitloader_remove_exclusion', function () {
187 $json_body = json_decode(file_get_contents('php://input'), true);
188 if (is_array($json_body)) {
189 foreach ($json_body as $key => $value) {
190 $_POST[$key] = $value;
191 }
192 }
193
194 RL21UtilWP::verifyAjaxNonce();
195
196 if (!current_user_can('manage_options')) {
197 wp_send_json_error(null, 403);
198 return;
199 }
200
201 $incoming_patterns = [];
202 $single_pattern = '';
203
204 if (isset($_POST['pattern'])) {
205 $single_pattern = wp_unslash($_POST['pattern']);
206 } elseif (isset($_GET['pattern'])) {
207 $single_pattern = wp_unslash($_GET['pattern']);
208 }
209
210 if (!empty($single_pattern)) {
211 $incoming_patterns[] = $single_pattern;
212 }
213
214 if (!empty($_POST['patterns']) && is_array($_POST['patterns'])) {
215 foreach ($_POST['patterns'] as $pattern) {
216 $incoming_patterns[] = $pattern;
217 }
218 }
219
220 $normalized_patterns = self::normalizeExcludePatterns($incoming_patterns);
221 if (empty($normalized_patterns)) {
222 wp_send_json_error(['message' => 'At least one valid exclusion pattern is required.'], 400);
223 return;
224 }
225
226 $response = self::removeExcludePatterns($normalized_patterns);
227 RabbitLoader_21_Core::sendJsonResponse($response);
228 });
229 add_action('wp_ajax_rabbitloader_conflicts', function () {
230 if (!current_user_can('manage_options')) {
231 wp_send_json_error(null, 403);
232 return;
233 }
234
235 $context = sanitize_text_field(RabbitLoader_21_Util_Core::get_param('context'));
236 $isActivationFlow = strcmp($context, 'connected') !== 0;
237 $response = RabbitLoader_21_Conflicts::getConflictState($isActivationFlow);
238 RabbitLoader_21_Core::sendJsonResponse($response);
239 });
240 add_action('wp_ajax_rabbitloader_admin_boot', function () {
241 if (!current_user_can('manage_options')) {
242 wp_send_json_error(null, 403);
243 return;
244 }
245
246 RabbitLoader_21_Core::sendJsonResponse(self::getAdminBootData());
247 });
248 add_action('wp_ajax_rabbitloader_save_keys', function () {
249 $json_body = json_decode(file_get_contents('php://input'), true);
250 if (is_array($json_body)) {
251 foreach ($json_body as $key => $value) {
252 $_POST[$key] = $value;
253 }
254 }
255
256 RL21UtilWP::verifyAjaxNonce();
257
258 if (!current_user_can('manage_options')) {
259 wp_send_json_error(null, 403);
260 return;
261 }
262
263 $conflict_state = RabbitLoader_21_Conflicts::getConflictState(true);
264 if (!empty($conflict_state['activation_blocked'])) {
265 $conflict_state['result'] = false;
266 if (empty($conflict_state['message'])) {
267 $conflict_state['message'] = RL21UtilWP::__('Resolve the blocking RabbitLoader conflict(s) before connecting this site.');
268 }
269
270 status_header(409);
271 RabbitLoader_21_Core::sendJsonResponse($conflict_state);
272 }
273
274 $encoded_token = RabbitLoader_21_Util_Core::get_param('rl-token', true);
275 $decoded_token = !empty($encoded_token) ? base64_decode($encoded_token, true) : false;
276 if (empty($decoded_token)) {
277 wp_send_json_error(['message' => 'Invalid token'], 400);
278 return;
279 }
280
281 $tokens = json_decode($decoded_token, true);
282 if (empty($tokens['api_token'])) {
283 wp_send_json_error(['message' => 'Invalid token'], 400);
284 return;
285 }
286
287 $urlparts = parse_url(home_url());
288 RabbitLoader_21_Core::update_api_tokens($tokens['api_token'], $urlparts['host'], $tokens['did'], '');
289 if (isset($tokens['cdn_prefix'])) {
290 update_option('rabbitloader_cdn_prefix', $tokens['cdn_prefix'], true);
291 }
292
293 do_action('rl_site_connected');
294
295 $response = self::getAdminBootData();
296 $response['result'] = true;
297 RabbitLoader_21_Core::sendJsonResponse($response);
298 });
299 add_action('wp_ajax_rabbitloader_disconnect', function () {
300 RL21UtilWP::verifyAjaxNonce();
301
302 if (!current_user_can('manage_options')) {
303 wp_send_json_error(null, 403);
304 return;
305 }
306
307 self::disconnectPlugin();
308
309 $response = [
310 'result' => true,
311 'admin_ajax' => admin_url('admin-ajax.php'),
312 'rl_nonce' => wp_create_nonce('rl-ajax-nonce'),
313 'rl_acct' => false,
314 'is_connected' => false,
315 'api_token' => '',
316 'did' => '',
317 'domain' => '',
318 'plan_title' => '',
319 'home_page_url_id' => ''
320 ];
321 RabbitLoader_21_Core::sendJsonResponse($response);
322 });
323 add_action('wp_ajax_rabbitloader_ajax_cron', function () {
324 //self::deferred_exe();
325 RL21UtilWP::verifyAjaxNonce();
326 });
327 add_action('wp_ajax_rabbitloader_warmup_urls', function () {
328 RL21UtilWP::verifyAjaxNonce();
329 $response = [
330 'poffset' => intval($_POST['poffset']),
331 'posts_per_page' => intval($_POST['posts_per_page']),
332 ];
333 RabbitLoader_21_Core::get_recent_posts($response['poffset'], $response['posts_per_page'], $response['published_count'], $response['permalinks']);
334 RabbitLoader_21_Core::sendJsonResponse($response);
335 });
336 // add_action('wp_ajax_rabbitloader_ajax_survey_dismissed', function () {
337 // RL21UtilWP::verifyAjaxNonce();
338 // self::survey_dismissed(self::SURVEY_DIS_PERMA);
339 // });
340 add_action('rl_site_connected', function () {
341 self::rl_site_connected();
342 });
343 add_action('plugins_loaded', 'RabbitLoader_AD_AD::on_plugins_loaded');
344 //listeners for taxonomy changes
345
346 add_action('wp_print_scripts', function () {
347 if (RabbitLoader_21_Util_Core::isRLPage()) {
348 wp_dequeue_script('monsterinsights-vue-frontend'); //vue JS conflict with apexcharts window.SVG().addTo fails
349 }
350 }, 100);
351 }
352
353 public static function init() {}
354
355 private static function canAccessModeAjax()
356 {
357 if (!empty($_POST['token'])) {
358 return true;
359 }
360
361 return current_user_can('manage_options');
362 }
363
364 private static function normalizeExcludePatterns($patterns)
365 {
366 if (!is_array($patterns)) {
367 $patterns = [$patterns];
368 }
369
370 $normalized = [];
371 foreach ($patterns as $pattern) {
372 if (!is_scalar($pattern)) {
373 continue;
374 }
375
376 $pattern = sanitize_text_field((string) $pattern);
377 $pattern = preg_replace('/[\r\n\t]+/', '', $pattern);
378 $pattern = trim($pattern);
379
380 if ($pattern === '' || strpos($pattern, "\0") !== false) {
381 continue;
382 }
383
384 $normalized[$pattern] = true;
385 }
386
387 return array_keys($normalized);
388 }
389
390 private static function getExcludePatternsState()
391 {
392 RabbitLoader_21_Core::getWpUserOption($user_options);
393 $patterns = self::normalizeExcludePatterns(explode("\n", $user_options['exclude_patterns']));
394
395 return [
396 'result' => true,
397 'patterns' => $patterns,
398 'exclude_patterns' => implode("\n", $patterns),
399 'count' => count($patterns),
400 ];
401 }
402
403 private static function addExcludePatterns($patterns)
404 {
405 RabbitLoader_21_Core::getWpUserOption($user_options);
406 $existing_patterns = self::normalizeExcludePatterns(explode("\n", $user_options['exclude_patterns']));
407 $existing_map = [];
408 foreach ($existing_patterns as $pattern) {
409 $existing_map[$pattern] = true;
410 }
411
412 $added_patterns = [];
413 foreach ($patterns as $pattern) {
414 if (isset($existing_map[$pattern])) {
415 continue;
416 }
417
418 $existing_map[$pattern] = true;
419 $existing_patterns[] = $pattern;
420 $added_patterns[] = $pattern;
421 }
422
423 $user_options['exclude_patterns'] = implode("\n", $existing_patterns);
424 RabbitLoader_21_Core::updateUserOption($user_options);
425
426 if (!empty($added_patterns)) {
427 RL21UtilWP::onPostChange(RL21UtilWP::POST_ID_ALL);
428 }
429
430 return [
431 'result' => true,
432 'message' => empty($added_patterns) ? 'Exclusion pattern already exists.' : 'Exclusion pattern(s) added successfully.',
433 'added_patterns' => $added_patterns,
434 'patterns' => $existing_patterns,
435 'exclude_patterns' => $user_options['exclude_patterns'],
436 'count' => count($existing_patterns),
437 ];
438 }
439
440 private static function removeExcludePatterns($patterns)
441 {
442 RabbitLoader_21_Core::getWpUserOption($user_options);
443 $existing_patterns = self::normalizeExcludePatterns(explode("\n", $user_options['exclude_patterns']));
444 $remove_map = [];
445 foreach ($patterns as $pattern) {
446 $remove_map[$pattern] = true;
447 }
448
449 $remaining_patterns = [];
450 $removed_patterns = [];
451 foreach ($existing_patterns as $pattern) {
452 if (isset($remove_map[$pattern])) {
453 $removed_patterns[] = $pattern;
454 continue;
455 }
456
457 $remaining_patterns[] = $pattern;
458 }
459
460 $user_options['exclude_patterns'] = implode("\n", $remaining_patterns);
461 RabbitLoader_21_Core::updateUserOption($user_options);
462
463 if (!empty($removed_patterns)) {
464 RL21UtilWP::onPostChange(RL21UtilWP::POST_ID_ALL);
465 }
466
467 return [
468 'result' => true,
469 'message' => empty($removed_patterns) ? 'Exclusion pattern not found.' : 'Exclusion pattern(s) removed successfully.',
470 'removed_patterns' => $removed_patterns,
471 'patterns' => $remaining_patterns,
472 'exclude_patterns' => $user_options['exclude_patterns'],
473 'count' => count($remaining_patterns),
474 ];
475 }
476
477 private static function updateModeValue($private_mode)
478 {
479 RabbitLoader_21_Core::getWpUserOption($user_options);
480 $user_options['private_mode_val'] = !empty($private_mode);
481 $user_options['private_mode_ts'] = date('c');
482 RabbitLoader_21_Core::updateUserOption($user_options);
483
484 try {
485 // remove public pages cache, main purpose is to purge TPV
486 RabbitLoader_21_TP::purge_all($tp_purge_count);
487 } catch (\Throwable $e) {
488 RabbitLoader_21_Core::on_exception($e);
489 }
490 }
491
492 protected static function disconnectPlugin()
493 {
494 $disconnect_context = [
495 'did' => RabbitLoader_21_Core::getWpOptVal('did'),
496 'domain' => RabbitLoader_21_Core::getWpOptVal('domain'),
497 'token_present' => !empty(RabbitLoader_21_Core::getWpOptVal('api_token')),
498 ];
499 error_log('RabbitLoader manual disconnect test: sending heartbeat ' . wp_json_encode($disconnect_context));
500
501 $post_data = ['disconnect' => 1];
502 $http = RabbitLoader_21_Core::callPOSTAPI('domain/heartbeat', $post_data, $apiError, $apiMessage);
503 $response_body = !empty($http['body']) && is_array($http['body']) ? $http['body'] : [];
504 $response_context = [
505 'status' => empty($http['response']['code']) ? 0 : (int) $http['response']['code'],
506 'result' => array_key_exists('result', $response_body) ? (bool) $response_body['result'] : null,
507 'message' => empty($response_body['message']) ? (isset($apiMessage) ? (string) $apiMessage : '') : (string) $response_body['message'],
508 'api_error' => (bool) $apiError,
509 'token_present_after_call' => !empty(RabbitLoader_21_Core::getWpOptVal('api_token')),
510 ];
511 error_log('RabbitLoader manual disconnect test: heartbeat response ' . wp_json_encode($response_context));
512
513 if ($apiError) {
514 error_log('RabbitLoader: backend manual disconnect notification failed.');
515 }
516 error_log('RabbitLoader manual disconnect test: continuing to clear local credentials');
517 RabbitLoader_21_Core::update_api_tokens('', '', '', 'user action disconnect');
518 delete_transient('rabbitloader_trans_overview_data');
519 }
520
521 public static function leftMenuOption()
522 {
523 self::get_warnings($notification_count, false);
524 add_menu_page(
525 'RabbitLoader',
526 $notification_count ? sprintf('RabbitLoader <span class="awaiting-mod">%d</span>', $notification_count) : 'RabbitLoader',
527 'manage_options',
528 'rabbitloader',
529 'RabbitLoader_21_Tab_Init::echoPluginPage',
530 dirname(plugin_dir_url(__FILE__)) . '/images/icon_16.png',
531 //'',
532 20
533 );
534
535 if (RabbitLoader_21_Util_Core::isRLPage()) {
536 add_action('admin_head', 'admin_styles', 10, 1);
537 function admin_styles($a)
538 {
539 echo '<link rel="stylesheet" href="' . RABBITLOADER_PLUG_URL . 'admin/css/bootstrap.v5.1.3.min.css' . '" type="text/css" media="all" />
540 <link rel="stylesheet" href="' . RABBITLOADER_PLUG_URL . 'admin/css/style.css?v=' . RABBITLOADER_PLUG_VERSION . '" type="text/css" media="all" />
541 <link rel="stylesheet" href="' . RABBITLOADER_PLUG_URL . 'admin/css/mfe-patches.css?v=' . RABBITLOADER_PLUG_VERSION . '" type="text/css" media="all" />';
542 }
543 }
544 add_action('admin_head', function () {
545 echo '<link rel="stylesheet" href="' . RABBITLOADER_PLUG_URL . 'admin/css/style-common.css?v=' . RABBITLOADER_PLUG_VERSION . '" type="text/css" media="all" />';
546 }, 10, 1);
547 }
548
549
550 protected static function isPluginActivated()
551 {
552
553 return !empty(RabbitLoader_21_Core::getWpOptVal('api_token'));
554 }
555
556 protected static function getAdminBootData()
557 {
558 $overview = RabbitLoader_21_Tab_Init::getOverviewData();
559 $is_connected = self::isPluginActivated();
560
561 return [
562 'admin_ajax' => admin_url('admin-ajax.php'),
563 'rl_nonce' => wp_create_nonce('rl-ajax-nonce'),
564 'rl_acct' => $is_connected,
565 'is_connected' => $is_connected,
566 'api_token' => RabbitLoader_21_Core::getWpOptVal('api_token'),
567 'did' => RabbitLoader_21_Core::getWpOptVal('did'),
568 'domain' => RabbitLoader_21_Core::getWpOptVal('domain'),
569 'plan_title' => isset($overview['plan_title']) ? $overview['plan_title'] : '',
570 'home_page_url_id' => isset($overview['home_page_url_id']) ? $overview['home_page_url_id'] : ''
571 ];
572 }
573
574 public static function admin_notices()
575 {
576
577 //self::survey();
578
579 try {
580 $page = RabbitLoader_21_Util_Core::get_param('page');
581
582 if (self::$admin_notice_shown || ($page == 'rabbitloader')) {
583 return;
584 }
585
586 self::$admin_notice_shown = true;
587
588 $plug_url = admin_url("admin.php?page=rabbitloader");
589
590
591 if (!self::isPluginActivated()) {
592 echo '
593 <div class="notice notice-error is-dismissible"><p>';
594 printf(RL21UtilWP::__('RabbitLoader is disconnected. Your pages are not optimized. <a href="%s">Click here to connect</a>'), $plug_url);
595 echo '</p></div>';
596 } else {
597 self::get_warnings($notification_count, false);
598
599 if ($notification_count > 0) {
600 echo '<div class="notice notice-error is-dismissible"><p>';
601 printf(RL21UtilWP::_n('RabbitLoader has %d warning which is affecting your website\'s optimizations. <a href="%s">check details</a>', 'RabbitLoader has %d warnings which may affect your website\'s optimizations. <a href="%s">check details</a>', $notification_count), $notification_count, $plug_url);
602 echo '</p></div>';
603 }
604 }
605 } catch (Throwable $e) {
606 RabbitLoader_21_Core::on_exception($e);
607 } catch (Exception $e) {
608 RabbitLoader_21_Core::on_exception($e);
609 }
610 }
611
612 private static function survey()
613 {
614 $showSurvey = false;
615 $integration_start_time = RabbitLoader_21_Core::getWpOptVal('token_update_ts');
616 if (!empty($integration_start_time)) {
617 $maxTimeSec = 1 * 3600; //after 1hour
618 $elapsedTimeSec = time() - $integration_start_time;
619 $showSurvey = $elapsedTimeSec > $maxTimeSec;
620 }
621
622 if (!$showSurvey) {
623 return;
624 }
625
626 $user_id = get_current_user_id();
627 if (empty($user_id)) {
628 return;
629 }
630 //delete_user_meta($user_id, 'rl_survey_dismissed');
631 $dismiss_time = intval(get_user_meta($user_id, 'rl_survey_dismissed', true));
632 if (self::SURVEY_DIS_PERMA === $dismiss_time) {
633 //permanently dismissed
634 return;
635 } else if (!empty($dismiss_time) && ($dismiss_time > strtotime('-7 days'))) {
636 //dismiss within last 7 days
637 return;
638 }
639
640 $remindLaterURL = esc_url(add_query_arg('rl_survey_dismissed', time()));
641 $remindNeverURL = esc_url(add_query_arg('rl_survey_dismissed', self::SURVEY_DIS_PERMA));
642 echo '<div class="notice notice-info is-dismissible rl_survey_notice" style="background: #f4f4f4; color: #1d2327; border-width: 1px; border-style: solid; border-color: #1d2327; padding: 1rem 1rem; border-radius: 5px;"><div style="float:left; padding-right:1rem;"><img src="' . RABBITLOADER_PLUG_URL . '/assets/icon-dark.svg" width="100" /></div>';
643 echo '<p class="p1">';
644 RL21UtilWP::_e("Enjoying RabbitLoader? 🚀");
645 echo '</p>';
646 echo '<p>';
647 RL21UtilWP::_e('Share your thoughts in a quick 10-second anonymous survey. Your feedback helps us hop forward! 🐇');
648 echo '</p>';
649 echo '<p class="p" style="margin-top: 1.5rem;"><button id="rl_show_survey" class="rl-btn rl-btn-primary mt-2 mb-sm-0">';
650 RL21UtilWP::_e('Yes, Continue');
651 echo '</button> <a href="' . $remindLaterURL . '" class="rl-btn" style="color:#0076CE;">';
652 RL21UtilWP::_e('Ask me later');
653 echo '</a><a href="' . $remindNeverURL . '" class="rl-btn" style="color:#0076CE;">';
654 RL21UtilWP::_e('I already did');
655 echo '</a></p>';
656 echo '</div>';
657 }
658
659 // private static function survey_dismissed($forceTime)
660 // {
661 // $user_id = get_current_user_id();
662 // if (empty($user_id)) {
663 // wp_send_json_error(null, 403);
664 // }
665 // if (isset($_GET['rl_survey_dismissed'])) {
666 // delete_user_meta($user_id, 'rl_survey_dismissed');
667 // update_user_meta($user_id, 'rl_survey_dismissed', intval($_GET['rl_survey_dismissed']), false);
668 // }
669 // if ($forceTime) {
670 // delete_user_meta($user_id, 'rl_survey_dismissed');
671 // update_user_meta($user_id, 'rl_survey_dismissed', $forceTime, false);
672 // }
673 // }
674 public static function admin_init()
675 {
676 // if (isset($_GET['rl_survey_dismissed'])) {
677 // self::survey_dismissed(0);
678 // }
679 }
680
681 protected static function get_warnings(&$count, $print)
682 {
683
684 if (self::$rabbitloader_cache_warnings === false) {
685
686 self::$rabbitloader_cache_warnings = [];
687
688 $otherConflictPluginMessages = RabbitLoader_21_Conflicts::getMessages(false);
689 foreach ($otherConflictPluginMessages as $plugMessage) {
690 self::$rabbitloader_cache_warnings[] = $plugMessage;
691 }
692
693 $adv_cache_msg = RL21UtilWP::__("The file /wp-content/advanced-cache.php is not writable. Please make sure that the PHP script has write access to the /wp-content/ directory and refresh this page to make RabbitLoader work efficiently.");
694
695 if (!defined('RABBITLOADER_AC_ACTIVE') || (RABBITLOADER_PLUG_VERSION != RABBITLOADER_AC_PLUG_VERSION) || (LOGGED_IN_COOKIE != RABBITLOADER_AC_LOGGED_IN_COOKIE)) {
696 $aac_code = self::activate_advanced_cache();
697 if ($aac_code === 4) {
698 self::$rabbitloader_cache_warnings[] = $adv_cache_msg;
699 }
700 }
701
702 if ((!defined("WP_CACHE") || !WP_CACHE)) {
703 if (RL21UtilWP::is_flywheel()) {
704 self::$rabbitloader_cache_warnings[] = sprintf(RL21UtilWP::__('Please enable WP_CACHE from the Flywheel settings <a href="%s">check details</a>'), "https://rabbitloader.com/kb/settings-for-flywheel/");
705 } else if (!self::update_wp_config_const('WP_CACHE', 'true')) {
706 self::$rabbitloader_cache_warnings[] = RL21UtilWP::__("The file /wp-config.php is not writable. Please make sure the file is writable or set WP_CACHE value to true to make RabbitLoader work efficiently.");
707 }
708 }
709
710 RabbitLoader_21_Core::getWpOption($rl_wp_options);
711 if (!empty($rl_wp_options['rl_hb_messages'])) {
712 foreach ($rl_wp_options['rl_hb_messages'] as $message) {
713 if (!empty($message['fd'])) {
714 self::$rabbitloader_cache_warnings[] = RL21UtilWP::__($message['fd']);
715 }
716 }
717 }
718 if (!empty($rl_wp_options['rl_latest_plugin_v'])) {
719 if (version_compare(RABBITLOADER_PLUG_VERSION, $rl_wp_options['rl_latest_plugin_v']) == -1) {
720 self::$rabbitloader_cache_warnings[] = RL21UtilWP::__("You are using an outdated version of RabbitLoader plugin. Please update it for a better experience.");
721 }
722 }
723 }
724
725 $count = count(self::$rabbitloader_cache_warnings);
726
727 if ($print) {
728 foreach (self::$rabbitloader_cache_warnings as $message) {
729 // echo '<div class="alert alert-danger" role="alert">';
730 // _e($message, RABBITLOADER_TEXT_DOMAIN);
731 // echo '</div>';
732 echo '<div class="notice notice-error"><p><b>';
733 RL21UtilWP::_e('Warning');
734 echo ': </b>';
735 _e($message, RABBITLOADER_TEXT_DOMAIN);
736 echo '</div>';
737 }
738 }
739 }
740
741 public static function activate_advanced_cache()
742 {
743
744 try {
745 if (!empty(RabbitLoader_21_Conflicts::getMessages(false))) {
746 return 1;
747 }
748
749 // if (!RabbitLoader_21_Core::htaccessExists()) {
750 // return 2;
751 // }
752
753 $adv_cache_sample = RABBITLOADER_PLUG_DIR . "advanced-cache.php";
754 $file_updated = false;
755 if (file_exists($adv_cache_sample)) {
756 $adv_cache_contents = file_get_contents($adv_cache_sample);
757 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_ABSPATH%%", ABSPATH, $adv_cache_contents);
758 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_DIR%%", RABBITLOADER_PLUG_DIR, $adv_cache_contents);
759 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_LOGGED_IN_COOKIE%%", LOGGED_IN_COOKIE, $adv_cache_contents);
760 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_CACHE_DIR%%", RABBITLOADER_CACHE_DIR, $adv_cache_contents);
761 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_VERSION%%", RABBITLOADER_PLUG_VERSION, $adv_cache_contents);
762 $adv_cache_contents = str_replace("%%RABBITLOADER_AC_PLUG_ENV%%", RABBITLOADER_PLUG_ENV, $adv_cache_contents);
763
764 $advanced_cache_file = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'advanced-cache.php';
765 $file_updated = RabbitLoader_21_Util_Core::fpc($advanced_cache_file, $adv_cache_contents, WP_DEBUG);
766 }
767
768 if ($file_updated) {
769 self::update_wp_config_const('WP_CACHE', 'true');
770 return 3;
771 } else {
772 return 4;
773 }
774 } catch (Throwable $e) {
775 RabbitLoader_21_Core::on_exception($e);
776 }
777 }
778
779 private static function update_wp_config_const($const_name, $const_val)
780 {
781 $wp_config_path = RL21UtilWP::get_wp_config();
782 //check if config file is writable
783 if (empty($wp_config_path) || !is_writable($wp_config_path)) {
784 //echo 'rl_not_writable__';
785 return;
786 }
787
788 $lines = file($wp_config_path);
789 $last_line = count($lines) - 1;
790
791 $new_file = array();
792 $const_added = false;
793 foreach ($lines as $current_line => $line_content) {
794 //check if constant is already defined
795 if (preg_match("/define\(\s*'{$const_name}'/i", $line_content)) {
796 $const_added = true;
797 $new_file[] = "if (!defined('{$const_name}')) { define( '{$const_name}', {$const_val} );}\n\n";
798 continue; //dont't break here, its a complete file rewrite
799 }
800
801 $thatsAllLine = (preg_match("/\/\* That's all, stop editing!.*/i", $line_content)); //constants should be before this line.
802 $isLast = ($thatsAllLine && !defined($const_name)) || ($last_line == $current_line);
803
804 // If we reach the end and no define - add it.
805 if (empty($const_added) && $isLast) {
806 $const_added = true;
807 $new_file[] = "if (!defined('{$const_name}')) { define( '{$const_name}', {$const_val} );}\n\n";
808 }
809
810 $new_file[] = $line_content;
811 }
812 $file_contents = implode("", $new_file);
813 return RabbitLoader_21_Util_Core::fpc($wp_config_path, $file_contents, WP_DEBUG);
814 }
815
816 public static function plugin_deactivate($network_wide = false, $notifyBackend = true)
817 {
818 if ($notifyBackend) {
819 RabbitLoader_21_Core::notify_backend_disconnect('plugin deactivate', $apiError, $apiMessage);
820 }
821
822 try {
823 self::update_wp_config_const('WP_CACHE', 'false');
824 $advanced_cache_file = WP_CONTENT_DIR . DIRECTORY_SEPARATOR . 'advanced-cache.php';
825 if (file_exists($advanced_cache_file)) { //during uninstall RABBITLOADER_AC_ACTIVE will not be there
826 $adv_cache_contents = "";
827 $file_updated = RabbitLoader_21_Util_Core::fpc($advanced_cache_file, $adv_cache_contents, WP_DEBUG);
828 }
829 } catch (Throwable $e) {
830 RabbitLoader_21_Core::on_exception($e);
831 }
832 }
833
834 public static function plugin_uninstall()
835 {
836 self::plugin_deactivate(false, false);
837
838 RabbitLoader_21_Core::notify_backend_disconnect('plugin uninstall', $apiError, $apiMessage);
839
840 try {
841 RabbitLoader_21_Core::cleanAllCachedFiles();
842 RabbitLoader_21_Core::delete_log_file(RabbitLoader_21_Core::LOCAL_CONFIG_FILE);
843 } catch (Exception $e) {
844 }
845 $ourOptions = array('rabbitloader_field_apikey', 'rabbitloader_field_apisecret', 'rabbitloader_field_domain', 'rl_optimizer_engine_version', 'rabbit_loader_wp_options', 'rabbit_loader_user_options', 'rabbitloader_cdn_prefix');
846
847 foreach ($ourOptions as $optionName) {
848 delete_option($optionName);
849 }
850 }
851
852 private static function rl_site_connected()
853 {
854 $api_token = RabbitLoader_21_Core::getWpOptVal('api_token');
855 $domain = RabbitLoader_21_Core::getWpOptVal('domain');
856 $did = RabbitLoader_21_Core::getWpOptVal('did');
857 RabbitLoader_21_Core::callPOSTAPI('domain/heartbeat', [], $apiError, $apiMessage);
858 if ($apiError) {
859 RabbitLoader_21_Core::update_api_tokens($api_token, $domain, $did, 'connected; heartbeat notification failed');
860 error_log('RabbitLoader: backend connection heartbeat failed after saving credentials.');
861 }
862
863 try {
864 RabbitLoader_21_TP::purge_all($tp_purge_count);
865 } catch (\Throwable $e) {
866 RabbitLoader_21_Core::on_exception($e);
867 }
868 }
869
870 public static function settings_link($links)
871 {
872 $url_settings = esc_url(add_query_arg(
873 'page',
874 'rabbitloader',
875 get_admin_url() . 'admin.php'
876 ));
877 $link = "<a href='$url_settings'>" . __('Settings') . '</a>';
878 array_push($links, $link);
879 $url_kb = esc_url('https://rabbitloader.com/kb/');
880 $link = "<a target='_blank' href='$url_kb'>" . __('Knowledge Base') . '</a>';
881 array_push($links, $link);
882 return $links;
883 }
884 }
885