PluginProbe ʕ •ᴥ•ʔ
WP STAGING – WordPress Backups, Restore, Migration & Clone / 4.11.0
WP STAGING – WordPress Backups, Restore, Migration & Clone v4.11.0
4.11.0 4.10.0 4.9.5 4.9.4 4.9.3 4.9.2 4.9.1 4.9.0 4.8.1 trunk 3.0.0 3.0.1 3.0.2 3.0.3 3.0.4 3.0.5 3.0.6 3.1.0 3.1.1 3.1.2 3.1.3 3.1.4 3.10.0 3.2.0 3.3.1 3.3.2 3.3.3 3.4.1 3.4.3 3.5.0 3.6.0 3.7.1 3.8.0 3.8.1 3.8.2 3.8.3 3.8.4 3.8.5 3.8.6 3.8.7 3.9.0 3.9.1 3.9.2 3.9.3 3.9.4 4.0.0 4.1.0 4.1.1 4.1.2 4.1.3 4.1.4 4.2.0 4.2.1 4.3.0 4.3.1 4.3.2 4.4.0 4.5.0 4.6.0 4.7.0 4.7.1 4.7.2 4.7.3 4.8.0
wp-staging / Framework / Notices / Notices.php
wp-staging / Framework / Notices Last commit date
BackupPluginsNotice.php 1 day ago BooleanNotice.php 1 day ago CliIntegrationNotice.php 1 day ago DisabledItemsNotice.php 1 day ago DismissNotice.php 1 day ago NextGenEngineNotice.php 1 day ago Notices.php 1 day ago NoticesHandler.php 1 day ago ObjectCacheNotice.php 1 day ago OutdatedWpStagingNotice.php 1 day ago WarningsNotice.php 1 day ago WpVersionCompatNotice.php 1 day ago
Notices.php
602 lines
1 <?php
2
3 namespace WPStaging\Framework\Notices;
4
5 use Exception;
6 use wpdb;
7 use WPStaging\Core\Utils\Logger;
8 use WPStaging\Core\WPStaging;
9 use WPStaging\Framework\Adapter\Directory;
10 use WPStaging\Framework\Assets\Assets;
11 use WPStaging\Framework\CloningProcess\ExcludedPlugins;
12 use WPStaging\Framework\Database\WpOptionsInfo;
13 use WPStaging\Framework\Facades\Hooks;
14 use WPStaging\Framework\Security\Capabilities;
15 use WPStaging\Staging\CloneOptions;
16 use WPStaging\Staging\FirstRun;
17 use WPStaging\Framework\ThirdParty\FreemiusScript;
18 use WPStaging\Framework\ThirdParty\Jetpack;
19 use WPStaging\Framework\ThirdParty\WordFence;
20 use WPStaging\Framework\Traits\NoticesTrait;
21 use WPStaging\Staging\Sites;
22 use WPStaging\Framework\SiteInfo;
23 use WPStaging\Framework\Utils\ServerVars;
24 use WPStaging\Backup\Service\Database\DatabaseImporter;
25 use WPStaging\Framework\Utils\Cache\Cache;
26 use WPStaging\Framework\ThirdParty\Aios;
27
28
29
30
31
32
33
34
35
36 class Notices
37 {
38 use NoticesTrait;
39
40
41 const ACTION_PRO_NOTICES = 'wpstg.notices.show_pro_notices';
42
43
44 const ACTION_BASIC_NOTICES = 'wpstg.notices.show_basic_notices';
45
46
47 const ACTION_INJECT_ANALYTICS_CONSENT_ASSETS = 'wpstg.assets.inject_analytics_consent_assets';
48
49
50 const ACTION_ADMIN_NOTICES = 'wpstg.admin_notices';
51
52
53 const ACTION_NETWORK_ADMIN_NOTICES = 'wpstg.network_admin_notices';
54
55
56 const ACTION_ALL_ADMIN_NOTICES = 'wpstg.all_admin_notices';
57
58
59 const FILTER_NOTICES_HIDE_DIRECTORY_LISTING_WARNINGS = 'wpstg.notices.hideDirectoryListingWarnings';
60
61 const FILTER_NOTICES_HIDE_MISSING_PRIMARY_KEY_NOTICE = 'wpstg.notices.hideMissingPrimaryKeyNotice';
62
63
64 private $assets;
65
66
67 private $dirUtil;
68
69
70 private $cache;
71
72
73 private $logger;
74
75
76 private $cloneOptions;
77
78
79 private $excludedPlugins;
80
81
82 private $freemiusScript;
83
84
85 private $wordfence;
86
87
88 private $disabledItemsNotice;
89
90
91 private $warningsNotice;
92
93
94 private $outdatedWpStagingNotice;
95
96
97 private $objectCacheNotice;
98
99
100 private $db;
101
102
103 const SHOW_ALL_NOTICES = false;
104
105
106
107
108 public static $directoryListingErrors = 'directoryListingErrors';
109
110
111 private $siteInfo;
112
113
114 private $viewsNoticesPath;
115
116
117 private $settings;
118
119
120 private $serverVars;
121
122
123 private $isWpComSite;
124
125
126 private $wpOptionsInfo;
127
128
129
130
131 public function __construct(Assets $assets)
132 {
133 $this->assets = $assets;
134 $this->viewsNoticesPath = WPSTG_VIEWS_DIR . "notices/";
135
136
137 $this->dirUtil = WPStaging::make(Directory::class);
138 $this->wordfence = WPStaging::make(WordFence::class);
139 $this->cloneOptions = WPStaging::make(CloneOptions::class);
140 $this->freemiusScript = WPStaging::make(FreemiusScript::class);
141 $this->excludedPlugins = WPStaging::make(ExcludedPlugins::class);
142 $this->logger = WPStaging::make("logger");
143 $this->cache = WPStaging::make("cache");
144 $this->db = WPStaging::make('wpdb');
145 $this->wpOptionsInfo = WPStaging::make(WpOptionsInfo::class);
146
147
148 $this->disabledItemsNotice = WPStaging::make(DisabledItemsNotice::class);
149 $this->warningsNotice = WPStaging::make(WarningsNotice::class);
150 $this->outdatedWpStagingNotice = WPStaging::make(OutdatedWpStagingNotice::class);
151 $this->objectCacheNotice = WPStaging::make(ObjectCacheNotice::class);
152 $this->siteInfo = WPStaging::make(SiteInfo::class);
153 $this->serverVars = WPStaging::make(ServerVars::class);
154
155 $this->isWpComSite = $this->siteInfo->isHostedOnWordPressCom();
156 }
157
158
159
160
161
162
163 protected function isPro(): bool
164 {
165 return WPStaging::isPro();
166 }
167
168
169
170
171
172 public function renderNotices()
173 {
174 if (!current_user_can(WPStaging::make(Capabilities::class)->manageWPSTG())) {
175 return;
176 }
177
178 $this->settings = get_option('wpstg_settings', []);
179
180 $this->renderNoticesBasicVersion();
181 $this->renderNoticesProVersion();
182 $this->renderNoticesOnAllWpAdminPages();
183 $this->renderNoticesOnWpStagingAdminPages();
184 }
185
186
187
188
189 private function renderNoticesOnAllWpAdminPages()
190 {
191 $this->noticeListItemsDisabledOnStagingSite();
192 $this->noticeDbHasMissingOrUnexpectedPrimaryKeys();
193 $this->noticeWordFenceHasBeenDisabled();
194 $this->noticeSettingsAreCorrupted();
195 $this->noticeStagingUploadsFolderIsSymlinked();
196 $this->noticeTableTmpPrefixConflictNotice();
197 $this->noticeNextGenEngineStagingSites();
198 $this->showAnalyticsModal();
199 }
200
201
202
203
204
205
206
207 private function noticeNextGenEngineStagingSites()
208 {
209 if (self::SHOW_ALL_NOTICES || WPStaging::make(NextGenEngineNotice::class)->isEnabled()) {
210 require $this->viewsNoticesPath . "next-gen-engine-notice.php";
211 }
212 }
213
214
215
216
217 private function renderNoticesBasicVersion()
218 {
219 if (!$this->isPro()) {
220 do_action(self::ACTION_BASIC_NOTICES);
221 }
222 }
223
224
225
226
227 private function renderNoticesProVersion()
228 {
229 if ($this->isPro()) {
230
231 do_action(self::ACTION_PRO_NOTICES);
232 }
233 }
234
235
236
237
238 private function renderNoticesOnWpStagingAdminPages()
239 {
240 if (!current_user_can("update_plugins") || !$this->isWPStagingAdminPage()) {
241 return;
242 }
243
244 $this->noticeUploadsDirIsOutsideAbspath();
245 $this->noticeWpStagingVersionIsOutdated();
246 $this->noticeObjectCachePluginNotRestored();
247 $this->noticeCacheDirectoryNotWriteable();
248 $this->noticeLoggerDirectoryNotWriteable();
249 $this->noticeAbspathDirectoryNotWriteable();
250 $this->noticeHomeAndSiteurlHaveDifferentScheme();
251 $this->noticeWpStagingHooksPluginIsOutdated();
252 $this->noticeMuPluginDirNotWriteable();
253 $this->noticeOptimizerIsDisabled();
254 $this->noticeShowDirectoryListingWarning($this->viewsNoticesPath);
255 $this->noticeDbPrefixDoesNotExist();
256 $this->noticeWPEnginePermalinkWarning();
257 $this->noticeAiosSaltPostfixEnabled();
258 }
259
260
261
262
263 private function noticeStagingUploadsFolderIsSymlinked()
264 {
265 $uploadsPath = wp_upload_dir()['basedir'];
266 if (self::SHOW_ALL_NOTICES || (is_link($uploadsPath) && $this->siteInfo->isStagingSite())) {
267 require_once $this->viewsNoticesPath . "staging-symlink-enabled-notice.php";
268 }
269 }
270
271
272
273
274 private function noticeTableTmpPrefixConflictNotice()
275 {
276 $disallowedPrefixes = [DatabaseImporter::TMP_DATABASE_PREFIX_TO_DROP, DatabaseImporter::TMP_DATABASE_PREFIX];
277 if (self::SHOW_ALL_NOTICES || in_array($this->db->prefix, $disallowedPrefixes, true)) {
278 require $this->viewsNoticesPath . "table-tmp-prefix-conflict-notice.php";
279 }
280 }
281
282
283
284
285
286
287
288
289
290
291
292
293
294 private function noticeShowDirectoryListingWarning(string $viewsNoticesPath)
295 {
296 $directoryListingErrors = WPStaging::getInstance()->getContainer()->getFromArray(static::$directoryListingErrors);
297
298
299 if (!self::SHOW_ALL_NOTICES && empty($directoryListingErrors)) {
300 return;
301 }
302
303
304 if (Hooks::applyFilters(self::FILTER_NOTICES_HIDE_DIRECTORY_LISTING_WARNINGS, false)) {
305 return;
306 }
307
308 require_once "{$viewsNoticesPath}directory-listing-could-not-be-prevented.php";
309 }
310
311
312
313
314
315 private function isDifferentScheme(): bool
316 {
317 $siteurlScheme = parse_url(get_option('siteurl'), PHP_URL_SCHEME);
318 $homeScheme = parse_url(get_option('home'), PHP_URL_SCHEME);
319
320 return !($siteurlScheme === $homeScheme);
321 }
322
323
324
325
326
327 private function isUsingOutdatedWpstgHooksPlugin(): bool
328 {
329
330 $versionToCheck = '0.0.4';
331
332
333 $wpstgHooksPath = 'wp-staging-hooks/wp-staging-hooks.php';
334
335
336 if (file_exists(WP_PLUGIN_DIR . '/' . $wpstgHooksPath)) {
337 $wpstgHooksData = get_plugin_data(WP_PLUGIN_DIR . '/' . $wpstgHooksPath);
338
339 return version_compare($wpstgHooksData['Version'], $versionToCheck, '>=') ? false : true;
340 }
341
342
343 $wpstgHooksPath = 'wp-staging-hooks.php';
344
345
346 if (file_exists(WP_PLUGIN_DIR . '/' . $wpstgHooksPath)) {
347 $wpstgHooksData = get_plugin_data(WP_PLUGIN_DIR . '/' . $wpstgHooksPath);
348
349 return version_compare($wpstgHooksData['Version'], $versionToCheck, '>=') ? false : true;
350 }
351
352 return false;
353 }
354
355
356
357
358
359
360
361
362
363
364
365 public static function renderNoticeDismissAction(string $viewsNoticesPath, $wpstgNotice, $cssClassSelectorDismiss, $cssClassSelectorNotice)
366 {
367 require "{$viewsNoticesPath}_partial/notice_dismiss_action.php";
368 }
369
370
371
372
373 public function maybeShowElementorCloudNotice()
374 {
375 if (self::SHOW_ALL_NOTICES || ($this->isWPStagingClonePage() && $this->siteInfo->isHostedOnElementorCloud())) {
376 require_once "{$this->viewsNoticesPath}elementor-cloud-notice.php";
377 }
378 }
379
380
381
382
383
384 private function isSettingsCorrupt(): bool
385 {
386 if (!is_array($this->settings) && !is_object($this->settings)) {
387 return true;
388 }
389
390 return false;
391 }
392
393
394
395
396 private function noticeDbHasMissingOrUnexpectedPrimaryKeys()
397 {
398 if (Hooks::applyFilters(self::FILTER_NOTICES_HIDE_MISSING_PRIMARY_KEY_NOTICE, false)) {
399 return;
400 }
401
402 $optionTable = $this->db->prefix . 'options';
403 $isPrimaryKeyMissing = $this->wpOptionsInfo->isOptionTablePrimaryKeyMissing($optionTable);
404 $isPrimaryKeyIsOptionName = $this->wpOptionsInfo->isPrimaryKeyIsOptionName($optionTable);
405 if (self::SHOW_ALL_NOTICES || (current_user_can("manage_options") && ($isPrimaryKeyMissing || $isPrimaryKeyIsOptionName) && $this->isWPStagingAdminPage())) {
406 require $this->viewsNoticesPath . "wp-options-missing-pk.php";
407 }
408 }
409
410
411
412
413 private function noticeDbPrefixDoesNotExist()
414 {
415 if (self::SHOW_ALL_NOTICES || empty($this->db->prefix)) {
416 require_once $this->viewsNoticesPath . "no-db-prefix-notice.php";
417 }
418 }
419
420
421
422
423 private function noticeWPEnginePermalinkWarning()
424 {
425 if (self::SHOW_ALL_NOTICES || class_exists('WPE_API')) {
426 require_once $this->viewsNoticesPath . "wpe-permalink-issue-notice.php";
427 }
428 }
429
430
431
432
433
434 private function noticeOptimizerIsDisabled()
435 {
436 $wpstgSettings = (object)$this->settings;
437 if (self::SHOW_ALL_NOTICES || empty($wpstgSettings->optimizer)) {
438 require_once $this->viewsNoticesPath . "disabled-optimizer-notice.php";
439 }
440 }
441
442
443
444
445 private function noticeMuPluginDirNotWriteable()
446 {
447 $varsDirectory = defined('WPMU_PLUGIN_DIR') ? WPMU_PLUGIN_DIR : trailingslashit(WP_CONTENT_DIR) . 'mu-plugins';
448 $wpstgSettings = (object)$this->settings;
449 if (
450 self::SHOW_ALL_NOTICES || (!is_writable($varsDirectory) || !is_readable($varsDirectory))
451 && isset($wpstgSettings->optimizer) && $wpstgSettings->optimizer
452 ) {
453 require $this->viewsNoticesPath . "mu-plugin-directory-permission-problem.php";
454 }
455 }
456
457
458
459
460 private function noticeWpStagingHooksPluginIsOutdated()
461 {
462 if (self::SHOW_ALL_NOTICES || ($this->isUsingOutdatedWpstgHooksPlugin())) {
463 require_once $this->viewsNoticesPath . "outdated-wp-staging-hooks.php";
464 }
465 }
466
467
468
469
470 private function noticeHomeAndSiteurlHaveDifferentScheme()
471 {
472 if (self::SHOW_ALL_NOTICES || ($this->isDifferentScheme())) {
473 require_once $this->viewsNoticesPath . "wrong-scheme.php";
474 }
475 }
476
477
478
479
480 private function noticeAbspathDirectoryNotWriteable()
481 {
482
483 if (self::SHOW_ALL_NOTICES || ((!is_writable(ABSPATH)) && !$this->isWpComSite)) {
484 require_once $this->viewsNoticesPath . "staging-directory-permission-problem.php";
485 }
486 }
487
488
489
490
491 private function noticeLoggerDirectoryNotWriteable()
492 {
493 $logsDir = $this->logger->getLogDir();
494 if (self::SHOW_ALL_NOTICES || (!is_dir($logsDir) || !is_writable($logsDir))) {
495 require_once $this->viewsNoticesPath . "logs-directory-permission-problem.php";
496 }
497 }
498
499
500
501
502 private function noticeCacheDirectoryNotWriteable()
503 {
504 $cacheDir = $this->cache->getPath();
505 if (self::SHOW_ALL_NOTICES || (!is_dir($cacheDir) || !is_writable($cacheDir))) {
506 require_once $this->viewsNoticesPath . "cache-directory-permission-problem.php";
507 }
508 }
509
510
511
512
513 private function noticeObjectCachePluginNotRestored()
514 {
515 if (self::SHOW_ALL_NOTICES || ($this->objectCacheNotice->isEnabled())) {
516 require_once $this->viewsNoticesPath . "object-cache-skipped.php";
517 }
518 }
519
520
521
522
523 private function noticeWpStagingVersionIsOutdated()
524 {
525
526
527
528 $this->outdatedWpStagingNotice->showNotice($this->viewsNoticesPath);
529 }
530
531
532
533
534 private function noticeUploadsDirIsOutsideAbspath()
535 {
536 if (self::SHOW_ALL_NOTICES || (!$this->dirUtil->isPathInWpRoot($this->dirUtil->getUploadsDirectory()) && !$this->siteInfo->isFlywheel() && !$this->isWpComSite)) {
537 require $this->viewsNoticesPath . "uploads-outside-wp-root.php";
538 }
539 }
540
541
542
543
544 private function noticeSettingsAreCorrupted()
545 {
546 if (self::SHOW_ALL_NOTICES || ($this->isSettingsCorrupt())) {
547 require $this->viewsNoticesPath . "settings_option_corrupt.php";
548 }
549 }
550
551
552
553
554 private function noticeWordFenceHasBeenDisabled()
555 {
556 $this->wordfence->showNotice($this->viewsNoticesPath);
557 }
558
559
560
561
562 private function noticeListItemsDisabledOnStagingSite()
563 {
564
565 $outgoingMailsDisabled = false;
566
567 if ($this->isPro()) {
568
569 $outgoingMailsDisabled = $this->cloneOptions->get(FirstRun::MAILS_DISABLED_KEY) || (get_option(FirstRun::MAILS_DISABLED_KEY, false));
570 }
571
572
573 if (self::SHOW_ALL_NOTICES || $this->disabledItemsNotice->isEnabled()) {
574 $excludedPlugins = (array)$this->excludedPlugins->getExcludedPlugins();
575
576 $freemiusOptionsCleared = $this->freemiusScript->isNoticeEnabled();
577
578 $isJetpackStagingModeActive = defined(Jetpack::STAGING_MODE_CONST) && constant(Jetpack::STAGING_MODE_CONST) === true;
579 $excludedFiles = get_option(Sites::STAGING_EXCLUDED_FILES_OPTION, []);
580 $excludedGoDaddyFiles = get_option(Sites::STAGING_EXCLUDED_GD_FILES_OPTION, []);
581
582
583 require $this->viewsNoticesPath . "disabled-items-notice.php";
584 }
585 }
586
587
588
589
590 private function noticeAiosSaltPostfixEnabled()
591 {
592 $aios = WPStaging::make(Aios::class);
593
594
595 $aios->optimizerWhitelistUpdater();
596
597 if (self::SHOW_ALL_NOTICES || $aios->isSaltPostfixOptionEnabled()) {
598 require $this->viewsNoticesPath . "aios-salt-postfix-enabled.php";
599 }
600 }
601 }
602