PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 5.7.2
Defender Security – Malware Scanner, Login Security & Firewall v5.7.2
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / component / class-rate.php

class-rate.php in Defender Security – Malware Scanner, Login Security & Firewall 5.7.2, at src/component/class-rate.php

493 lines 13.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2 /**
3 * Handles the functionality related to user ratings and notifications.
4 *
5 * @package WP_Defender\Component
6 */
7
8 namespace WP_Defender\Component;
9
10 use Calotes\Base\Component;
11 use WP_Defender\Model\Setting\Security_Tweaks;
12 use WP_Defender\Traits\Defender_Bootstrap;
13 use WP_Defender\Helper\Analytics\Rate as Rate_Analytics;
14
15 /**
16 * Handles the functionality related to user ratings and notifications.
17 *
18 * @since 4.4.0
19 */
20 class Rate extends Component {
21
22 use Defender_Bootstrap;
23
24 /**
25 * URL for leaving a new review on WordPress.org.
26 *
27 * @var string
28 */
29 public const URL_PLUGIN_NEW_REVIEW_VCS = 'https://wordpress.org/support/plugin/defender-security/reviews/#new-post';
30
31 /**
32 * Number of completed scans required to trigger a rating prompt.
33 *
34 * @var int
35 */
36 public const NUMBER_COMPLETED_SCANS = 3;
37
38 /**
39 * Number of fixed scan issues required to trigger a rating prompt.
40 *
41 * @var int
42 */
43 public const NUMBER_FIXED_SCANS = 5;
44
45 /**
46 * Number of UA lockouts required to trigger a rating prompt.
47 *
48 * @var int
49 */
50 public const NUMBER_UA_LOCKOUTS = 25;
51
52 /**
53 * Number of IP lockouts required to trigger a rating prompt.
54 *
55 * @var int
56 */
57 public const NUMBER_IP_LOCKOUTS = 25;
58
59 /**
60 * Option name for tracking the number of completed scans.
61 *
62 * @var string
63 */
64 public const SLUG_COMPLETED_SCANS = 'defender_counter_completed_scans';
65
66 /**
67 * Option name for tracking the number of fixed scan issues.
68 *
69 * @var string
70 */
71 public const SLUG_FIXED_SCAN_ISSUES = 'defender_counter_fixed_scan_issues';
72
73 /**
74 * Option name for tracking if the rate button was clicked.
75 *
76 * @var string
77 */
78 public const SLUG_FOR_BUTTON_RATE = 'defender_rating_success';
79
80 /**
81 * Option name for tracking if the later button was clicked.
82 *
83 * @var string
84 */
85 public const SLUG_FOR_BUTTON_THANKS = 'defender_days_rating_later_dismiss';
86
87 /**
88 * Option name for storing the installation date of the plugin.
89 *
90 * @var string
91 */
92 public const SLUG_FREE_INSTALL_DATE = 'defender_free_install_date';
93
94 /**
95 * Option name for storing the date of the postponed notice. This is global for all rating notices.
96 *
97 * @var string
98 */
99 public const SLUG_POSTPONED_NOTICE_DATE = 'defender_postponed_notice_date';
100
101 /**
102 * Option name for tracking the number of UA lockouts.
103 *
104 * @var string
105 */
106 public const SLUG_UA_LOCKOUTS = 'defender_counter_ua_lockouts';
107
108 /**
109 * Option name for tracking the number of IP lockouts.
110 *
111 * @var string
112 */
113 public const SLUG_IP_LOCKOUTS = 'defender_counter_ip_lockouts';
114
115 /**
116 * Retrieves the count of scans from the database.
117 *
118 * @param string $slug The option name to retrieve the count from.
119 *
120 * @return int The count of scans.
121 */
122 protected static function get_count_scans( $slug ): int {
123 $scan_count = get_site_option( $slug, false );
124
125 return empty( $scan_count ) ? 0 : (int) $scan_count;
126 }
127
128 /**
129 * Get a button label to rate.
130 *
131 * @return string
132 */
133 public static function get_rate_button_title(): string {
134 return esc_html__( 'Rate Defender', 'defender-security' );
135 }
136
137 /**
138 * Get a button label to postpone.
139 *
140 * @return string
141 */
142 public static function get_postpone_button_title(): string {
143 return esc_html__( 'Remind me later', 'defender-security' );
144 }
145
146 /**
147 * Get a button label to dismiss.
148 *
149 * @return string
150 */
151 public static function get_dismiss_button_title(): string {
152 return esc_html__( 'I already did', 'defender-security' );
153 }
154
155 /**
156 * Count completed scans.
157 */
158 public static function run_counter_of_completed_scans(): void {
159 $scan_count = self::get_count_scans( self::SLUG_COMPLETED_SCANS );
160 if ( $scan_count < self::NUMBER_COMPLETED_SCANS ) {
161 update_site_option( self::SLUG_COMPLETED_SCANS, ++$scan_count );
162 }
163 }
164
165 /**
166 * Count fixed scans.
167 */
168 public static function run_counter_of_fixed_scans(): void {
169 $scan_count = self::get_count_scans( self::SLUG_FIXED_SCAN_ISSUES );
170 if ( $scan_count < self::NUMBER_FIXED_SCANS ) {
171 update_site_option( self::SLUG_FIXED_SCAN_ISSUES, ++$scan_count );
172 }
173 }
174
175 /**
176 * Count UA lockouts.
177 */
178 public static function run_counter_of_ua_lockouts(): void {
179 $lockout_count = self::get_count_scans( self::SLUG_UA_LOCKOUTS );
180 if ( $lockout_count < self::NUMBER_UA_LOCKOUTS ) {
181 update_site_option( self::SLUG_UA_LOCKOUTS, ++$lockout_count );
182 }
183 }
184
185 /**
186 * Count IP lockouts.
187 */
188 public static function run_counter_of_ip_lockouts(): void {
189 $lockout_count = self::get_count_scans( self::SLUG_IP_LOCKOUTS );
190 if ( $lockout_count < self::NUMBER_IP_LOCKOUTS ) {
191 update_site_option( self::SLUG_IP_LOCKOUTS, ++$lockout_count );
192 }
193 }
194
195 /**
196 * Get notice by given slug.
197 *
198 * @param string $notice_slug Notice slug.
199 *
200 * @return string
201 */
202 public static function get_notice_by_slug( string $notice_slug ): string {
203 switch ( $notice_slug ) {
204 case 'completed_scans':
205 default:
206 $text = '<p class="notice-header">' . sprintf(
207 /* translators: %d - Number of completed scans. */
208 esc_html__( '🎉 Nice work — %d scans completed!', 'defender-security' ),
209 self::NUMBER_COMPLETED_SCANS
210 );
211 $text .= '</p><p class="notice-body">';
212 $text .= esc_html__(
213 'Your site’s files have been thoroughly scanned for file modifications and outdated plugins. Defender’s here to keep your site safe — could you share your experience with others on WordPress.org?',
214 'defender-security'
215 );
216 $text .= '</p>';
217 break;
218
219 case 'fixed_scans':
220 $text = '<p class="notice-body">' . sprintf(
221 /* translators: %d - Number of fixed scans. */
222 esc_html__(
223 'You`ve successfully resolved %d malware scan issues! We are happy to be a part of helping you secure your site, and we would appreciate it if you dropped us a rating on wp.org to help us spread the word and boost our motivation.',
224 'defender-security'
225 ),
226 self::NUMBER_FIXED_SCANS
227 );
228 $text .= '</p>';
229 break;
230
231 case 'resolved_tweaks':
232 $tweak_arr = wd_di()->get( Security_Tweaks::class )->get_tweak_types();
233 $total_tweaks = $tweak_arr['count_fixed'] + $tweak_arr['count_ignored'] + $tweak_arr['count_issues'];
234 $text = '<p class="notice-body">' . sprintf(
235 /* translators: %d - Total number. */
236 esc_html__(
237 'You`ve resolved all %d security recommendations - that`s impressive! We are happy to be a part of helping you secure your site, and we would appreciate it if you dropped us a rating on wp.org to help us spread the word and boost our motivation.',
238 'defender-security'
239 ),
240 $total_tweaks
241 );
242 $text .= '</p>';
243 break;
244
245 case 'ua_lockouts':
246 $text = '<p class="notice-header">' . sprintf(
247 /* translators: %d - Number of UA lockouts. */
248 esc_html__( '🤖 Defender has blocked %d malicious bots!', 'defender-security' ),
249 self::NUMBER_UA_LOCKOUTS
250 );
251 $text .= '</p><p class="notice-body">';
252 $text .= sprintf(
253 /* translators: %d - Number of UA lockouts. */
254 esc_html__(
255 'That’s %1$d fake crawlers and bad bots stopped from accessing your site. Defender’s User Agent lockouts keep unwanted traffic away so your site stays safe. If Defender’s helped protect your site, please share your experience with a review on WordPress.org.',
256 'defender-security'
257 ),
258 self::NUMBER_UA_LOCKOUTS
259 );
260 $text .= '</p>';
261 break;
262
263 case 'ip_lockouts':
264 $text = '<p class="notice-header">' . sprintf(
265 /* translators: %d - Number of IP lockouts. */
266 esc_html__( '🚫 Defender has blocked %d suspicious IPs!', 'defender-security' ),
267 self::NUMBER_IP_LOCKOUTS
268 );
269 $text .= '</p><p class="notice-body">';
270 $text .= sprintf(
271 /* translators: %d - Number of IP lockouts. */
272 esc_html__(
273 'That’s %1$d potential threats stopped before they could harm your site. Defender’s Firewall is keeping the bad guys and bots out so you can stay focused on running your site. If you’ve found Defender helpful, please share your experience with a review on WordPress.org.',
274 'defender-security'
275 ),
276 self::NUMBER_IP_LOCKOUTS
277 );
278 $text .= '</p>';
279 break;
280
281 case '7_days_installed':
282 $text = '<p class="notice-header">' . esc_html__(
283 'Enjoying Defender? We’d love to hear your feedback!',
284 'defender-security'
285 );
286 $text .= '</p><p class="notice-body">';
287 $text .= esc_html__(
288 'You’ve been using Defender for over a week now, and we’d love to hear about your experience! We’ve spent countless hours developing it for you, and your feedback is important to us. We’d really appreciate your rating.',
289 'defender-security'
290 );
291 $text .= '</p>';
292 break;
293 }
294
295 return $text;
296 }
297
298 /**
299 * Get label by given slug. No need to translate a returned text.
300 *
301 * @param string $notice_slug Notice slug.
302 *
303 * @return string
304 */
305 public static function get_label_by_slug( string $notice_slug ): string {
306 switch ( $notice_slug ) {
307 case 'completed_scans':
308 $text = '3 Malware Scan Completed';
309 break;
310 case 'fixed_scans':
311 $text = '5 Malware Issues Fixed';
312 break;
313 case 'resolved_tweaks':
314 $text = 'Recommendation Resolved';
315 break;
316 case 'ua_lockouts':
317 $text = '25 User Agent Lockout';
318 break;
319 case 'ip_lockouts':
320 $text = '25 IP Lockout';
321 break;
322 case '7_days_installed':
323 $text = '7 Days installed';
324 break;
325 default:
326 $text = '';
327 break;
328 }
329 return $text;
330 }
331
332 /**
333 * Get label of the current page.
334 *
335 * @return string
336 */
337 public static function get_current_page_label(): string {
338 switch ( defender_get_current_page() ) {
339 case 'wp-defender':
340 $text = 'Dashboard';
341 break;
342 case 'wdf-hardener':
343 $text = 'Recommendations';
344 break;
345 case 'wdf-scan':
346 $text = 'Malware Scan';
347 break;
348 case 'wdf-logging':
349 $text = 'Audit Log';
350 break;
351 case 'wdf-ip-lockout':
352 $text = 'Firewall';
353 break;
354 case 'wdf-2fa':
355 $text = '2FA';
356 break;
357 case 'wdf-advanced-tools':
358 $text = 'Tools';
359 break;
360 case 'wdf-notification':
361 $text = 'Notifications';
362 break;
363 case 'wdf-setting':
364 $text = 'Settings';
365 break;
366 default:
367 $text = '';
368 break;
369 }
370
371 return $text;
372 }
373
374 /**
375 * Reset counter of all prompts.
376 */
377 public static function reset_counters(): void {
378 update_site_option( self::SLUG_COMPLETED_SCANS, 0 );
379 update_site_option( self::SLUG_FIXED_SCAN_ISSUES, 0 );
380 update_site_option( self::SLUG_UA_LOCKOUTS, 0 );
381 update_site_option( self::SLUG_IP_LOCKOUTS, 0 );
382 }
383
384 /**
385 * Is the rating notice displayed? The priority list of prompts:
386 * 1) completed malware scans,
387 * 2) fixed scans,
388 * 3) resolved tweaks,
389 * 4) UA lockouts,
390 * 5) IP lockouts,
391 * 6) default one after 7 days installed.
392 * Note: items #1-5 are without waiting for 7 days.
393 *
394 * @return array
395 */
396 public static function is_achievement_displayed(): array {
397 $res = array(
398 'is_displayed' => true,
399 'slug' => '',
400 );
401 if ( self::was_rate_request() ) {
402 $res['is_displayed'] = false;
403
404 return $res;
405 }
406 if ( ! self::is_required_page() ) {
407 $res['is_displayed'] = false;
408
409 return $res;
410 }
411
412 // No needed to translate slugs.
413 if ( self::get_count_scans( self::SLUG_COMPLETED_SCANS ) >= self::NUMBER_COMPLETED_SCANS ) {
414 $res['slug'] = 'completed_scans';
415 } elseif ( self::get_count_scans( self::SLUG_FIXED_SCAN_ISSUES ) >= self::NUMBER_FIXED_SCANS ) {
416 $res['slug'] = 'fixed_scans';
417 } else {
418 $tweak_arr = wd_di()->get( Security_Tweaks::class )->get_tweak_types();
419 $total_tweaks = $tweak_arr['count_fixed'] + $tweak_arr['count_ignored'] + $tweak_arr['count_issues'];
420 if ( $tweak_arr['count_fixed'] === $total_tweaks ) {
421 $res['slug'] = 'resolved_tweaks';
422 } elseif ( self::get_count_scans( self::SLUG_UA_LOCKOUTS ) >= self::NUMBER_UA_LOCKOUTS ) {
423 $res['slug'] = 'ua_lockouts';
424 } elseif ( self::get_count_scans( self::SLUG_IP_LOCKOUTS ) >= self::NUMBER_IP_LOCKOUTS ) {
425 $res['slug'] = 'ip_lockouts';
426 } elseif ( self::was_postponed_request() ) {
427 $res['is_displayed'] = false;
428
429 return $res;
430 }
431 }
432 // If the conditions are met, display the notice about plugin achievements.
433 if ( $res['is_displayed'] && '' !== $res['slug'] ) {
434 return $res;
435 }
436 // If no, display the default one.
437 $res['slug'] = '7_days_installed';
438
439 return $res;
440 }
441
442 /**
443 * Have there already been clicks on the Rate or Dismiss buttons?
444 *
445 * @return bool
446 */
447 private static function was_rate_request(): bool {
448 if ( get_site_option( self::SLUG_FOR_BUTTON_RATE, (bool) apply_filters( 'wd_display_rating', false ) ) ) {
449 return true;
450 }
451 if ( get_site_option( self::SLUG_FOR_BUTTON_THANKS, (bool) apply_filters( 'wd_dismiss_rating', false ) ) ) {
452 return true;
453 }
454
455 return false;
456 }
457
458 /**
459 * Have there already been click to postpone the notice?
460 *
461 * @return bool
462 */
463 private static function was_postponed_request(): bool {
464 $postponed_date = (int) get_site_option( self::SLUG_POSTPONED_NOTICE_DATE, 0 );
465
466 return time() <= strtotime( '+7 days', $postponed_date );
467 }
468
469 /**
470 * Is this required page? Excluded pages: WAF, Free Plugins, Onboard.
471 *
472 * @return bool
473 */
474 protected static function is_required_page(): bool {
475 $arr = array(
476 'wdf-hardener',
477 'wdf-scan',
478 'wdf-logging',
479 'wdf-ip-lockout',
480 'wdf-2fa',
481 'wdf-advanced-tools',
482 'wdf-notification',
483 'wdf-setting',
484 );
485 $_this = new self();
486 if ( ! $_this->is_onboarding() ) {
487 $arr[] = 'wp-defender';
488 }
489
490 return in_array( defender_get_current_page(), $arr, true );
491 }
492 }
493