Defender Security – Malware Scanner, Login Security & Firewall - Version 2.4.8

Version Description

( 2021-03-12 ) =

  • Fix: Unescaped DB parameters
Download this release

Release Info

Developer BigTonny
Plugin Icon 128x128 Defender Security – Malware Scanner, Login Security & Firewall
Version 2.4.8
Comparing to
See all releases

Code changes from version 2.4.7 to 2.4.8

extra/free-dashboard/assets/admin.css ADDED
@@ -0,0 +1,165 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* ****************************************************************************
2
+ * NOTIFICATION STYLES
3
+ *
4
+ * The styles are identical with the WPMUDEV dashboard CSS (section 22)
5
+ * Any changes made here should also be made to the dashboard CSS!
6
+ */
7
+
8
+ .wrap .frash-notice.notice {
9
+ padding: 0;
10
+ margin: 5px 0 10px;
11
+ border: 1px solid #E5E5E5;
12
+ background: #FFF;
13
+ overflow: hidden;
14
+ -webkit-border-radius: 6px;
15
+ border-radius: 6px;
16
+ -webkit-box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.05);
17
+ box-shadow: 0 1px 1px 0 rgba(0, 0, 0, 0.05);
18
+ position: relative;
19
+ z-index: 1;
20
+ min-height: 80px;
21
+ display: table; /* The magic ingredient! */
22
+ font: 13px "Open Sans", sans-serif;
23
+ }
24
+ .wrap .frash-notice.notice.loading:before {
25
+ content: attr(data-message);
26
+ position: absolute;
27
+ left: 0;
28
+ right: 0;
29
+ top: 0;
30
+ bottom: 0;
31
+ background-color: rgba(255, 255, 255, 0.7);
32
+ z-index: 5;
33
+ text-align: center;
34
+ line-height: 80px;
35
+ font-size: 22px;
36
+ font-weight: bold;
37
+ }
38
+ .frash-notice > div {
39
+ display: table-cell; /* The magic ingredient! */
40
+ vertical-align: middle;
41
+ cursor: default;
42
+ }
43
+ .frash-notice.notice.loading > div {
44
+ -webkit-filter: blur(2px);
45
+ -moz-filter: blur(2px);
46
+ -o-filter: blur(2px);
47
+ -ms-filter: blur(2px);
48
+ filter: blur(2px);
49
+ }
50
+ .frash-notice-logo {
51
+ background-color: #0B2F3F;
52
+ background-image: url(data:image/png;base64,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);
53
+ background-repeat: no-repeat;
54
+ background-position: 50% 50%;
55
+ }
56
+ .frash-notice-logo span {
57
+ display: block;
58
+ width: 80px;
59
+ }
60
+ .frash-notice-message {
61
+ width: 100%;
62
+ padding: 10px 20px;
63
+ color: #444;
64
+ }
65
+ .frash-notice-message strong {
66
+ color: #000;
67
+ }
68
+ .frash-notice-cta {
69
+ border-left: 1px solid #E5E5E5;
70
+ background: #F8F8F8;
71
+ padding: 0 30px;
72
+ position: relative;
73
+ white-space: nowrap;
74
+ }
75
+ .wp-core-ui .frash-notice-cta button,
76
+ .wp-core-ui .frash-notice-cta .button-primary:active {
77
+ vertical-align: middle;
78
+ }
79
+ .wp-core-ui .frash-notice-cta input[type="email"] {
80
+ vertical-align: middle;
81
+ line-height: 20px;
82
+ margin: 0;
83
+ min-width: 50px;
84
+ max-width: 320px;
85
+ text-align: center;
86
+ padding-left: 0;
87
+ padding-right: 0;
88
+ }
89
+ .frash-notice-dismiss {
90
+ background: transparent;
91
+ border: 0;
92
+ cursor: pointer;
93
+ color: #BBB;
94
+ }
95
+ .frash-notice-dismiss:hover {
96
+ color: #666;
97
+ }
98
+
99
+ @media only all and (max-width: 1200px) {
100
+ .frash-notice-dismiss {
101
+ display: block;
102
+ margin: 0 auto;
103
+ line-height: 18px;
104
+ padding-top: 8px;
105
+ padding-bottom: 2px;
106
+ }
107
+ }
108
+
109
+ @media only all and (max-width: 1000px) {
110
+ .wrap .frash-notice.notice {
111
+ display: block;
112
+ font-size: 13px;
113
+ }
114
+ .frash-notice > .frash-notice-logo {
115
+ float: left;
116
+ display: inline-block;
117
+ height: 80px;
118
+ margin: 10px;
119
+ border-radius: 4px;
120
+ }
121
+ .frash-notice > .frash-notice-message {
122
+ width: auto;
123
+ display: block;
124
+ padding: 10px;
125
+ min-height: 80px;
126
+ }
127
+ .frash-notice > .frash-notice-cta {
128
+ display: block;
129
+ border-top: 1px solid #E5E5E5;
130
+ border-left: 0;
131
+ text-align: center;
132
+ white-space: normal;
133
+ line-height: 30px;
134
+ padding: 10px 20px;
135
+ }
136
+ .wp-core-ui .frash-notice > .frash-notice-cta > input[type="email"],
137
+ .frash-notice > .frash-notice-cta > button {
138
+ font-size: 14px;
139
+ }
140
+ .frash-notice > .frash-notice-cta > .frash-notice-dismiss {
141
+ display: inline-block;
142
+ float: none;
143
+ line-height: 26px;
144
+ padding-top: 0;
145
+ padding-bottom: 0;
146
+ font-size: 13px;
147
+ }
148
+ }
149
+
150
+ @media only all and (max-width: 500px) {
151
+ .wp-core-ui .frash-notice > .frash-notice-cta > input[type="email"],
152
+ .frash-notice > .frash-notice-cta > button {
153
+ display: block;
154
+ width: 100% !important;
155
+ max-width: none;
156
+ margin-bottom: 4px;
157
+ font-size: 16px;
158
+ height: 34px;
159
+ }
160
+ .frash-notice > .frash-notice-cta > .frash-notice-dismiss {
161
+ margin-top: 5px;
162
+ font-size: 14px;
163
+ height: 23px;
164
+ }
165
+ }
extra/free-dashboard/assets/admin.js ADDED
@@ -0,0 +1,213 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ jQuery( function () {
2
+ const notice = document.querySelector( '.frash-notice' );
3
+ const type = notice.querySelector( 'input[name=type]' ).value;
4
+ const emailInput = notice.querySelector( 'input[name=EMAIL]' );
5
+ const btnAct = notice.querySelector( '.frash-notice-act' );
6
+ const btnDismiss = notice.querySelector( '.frash-notice-dismiss' );
7
+
8
+ /**
9
+ * Display the notice after the page was loaded.
10
+ */
11
+ function initialize() {
12
+ fadeIn( notice, 500 );
13
+ initEmail();
14
+ }
15
+
16
+ /**
17
+ * Initialize the email field.
18
+ */
19
+ function initEmail() {
20
+ if ( ! emailInput ) {
21
+ return;
22
+ }
23
+
24
+ // Adjust the size of the email field to its contents.
25
+ function adjustEmailSize() {
26
+ const el = document.createElement( 'span' );
27
+
28
+ el.setAttribute( 'class', 'input-field' );
29
+ el.innerHTML = emailInput.value;
30
+ document.querySelector( 'body' ).appendChild( el );
31
+ const width = Math.ceil( el.getBoundingClientRect().width );
32
+ el.remove();
33
+
34
+ emailInput.style.width = width + 34 + 'px';
35
+ }
36
+
37
+ emailInput.addEventListener( 'keypress', function ( e ) {
38
+ if ( e.defaultPrevented ) {
39
+ return;
40
+ }
41
+
42
+ let handled = false;
43
+ if ( undefined !== e.key && 'Enter' === e.key ) {
44
+ btnAct.click();
45
+ handled = true;
46
+ } else if ( undefined !== e.keyCode && 13 === e.keyCode ) {
47
+ btnAct.click();
48
+ handled = true;
49
+ }
50
+
51
+ if ( handled ) {
52
+ // Suppress "double action" if event handled.
53
+ e.preventDefault();
54
+ } else {
55
+ adjustEmailSize();
56
+ }
57
+ } );
58
+
59
+ adjustEmailSize();
60
+ }
61
+
62
+ /**
63
+ * Open a tab to rate the plugin.
64
+ */
65
+ function actRate() {
66
+ const urlWP = notice.querySelector( 'input[name=url_wp]' ).value;
67
+ const url =
68
+ urlWP.replace( /\/plugins\//, '/support/plugin/' ) +
69
+ '/reviews/?rate=5#new-post';
70
+ const link = document.createElement( 'a' );
71
+ link.setAttribute( 'href', url );
72
+ link.setAttribute( 'target', '_blank' );
73
+ link.innerHTML = 'Rate';
74
+
75
+ document.querySelector( 'body' ).appendChild( link );
76
+ link.click();
77
+ link.remove();
78
+ }
79
+
80
+ /**
81
+ * Submit the user to our email list.
82
+ */
83
+ function actEmail() {
84
+ const form = emailInput.closest( 'form' );
85
+
86
+ const query = [];
87
+ for ( const el of form.querySelectorAll( 'input' ) ) {
88
+ query.push(
89
+ encodeURIComponent( el.name ) +
90
+ '=' +
91
+ encodeURIComponent( el.value )
92
+ );
93
+ }
94
+
95
+ // TODO: refactor jQuery to JavaScript.
96
+ jQuery.ajax( {
97
+ type: form.getAttribute( 'method' ),
98
+ url: form.getAttribute( 'action' ),
99
+ data: query.join( '&' ),
100
+ cache: false,
101
+ dataType: 'json',
102
+ contentType: 'application/json; charset=utf-8',
103
+ success( data ) {
104
+ window.console.log( data.msg );
105
+ },
106
+ } );
107
+ }
108
+
109
+ /**
110
+ * Notify WordPress about the users choice and close the message.
111
+ *
112
+ * @param {string} action
113
+ * @param {string} message
114
+ */
115
+ function notifyWordPress( action, message ) {
116
+ notice.dataset.message = message;
117
+ notice.classList.add( 'loading' );
118
+
119
+ const ajaxData = {
120
+ action,
121
+ plugin_id: notice.querySelector( 'input[name=plugin_id]' ).value,
122
+ type,
123
+ };
124
+
125
+ console.log( ajaxData );
126
+
127
+ // TODO: refactor jQuery to JavaScript
128
+ jQuery.post( window.ajaxurl, ajaxData, hideNotice );
129
+ }
130
+
131
+ /**
132
+ * Handle click on the primary CTA button.
133
+ * Either open the wp.org page or submit the email address.
134
+ */
135
+ if ( btnAct ) {
136
+ btnAct.addEventListener( 'click', function ( e ) {
137
+ e.preventDefault();
138
+
139
+ // Do not submit form if the value is not set.
140
+ const input = notice.querySelector( 'input[type="email"]' );
141
+ if ( ( ! input || ! input.value ) && type === 'email' ) {
142
+ return;
143
+ }
144
+
145
+ switch ( type ) {
146
+ case 'rate':
147
+ actRate();
148
+ break;
149
+ case 'email':
150
+ actEmail();
151
+ break;
152
+ }
153
+
154
+ notifyWordPress( 'frash_act', btnAct.dataset.msg );
155
+ } );
156
+ }
157
+
158
+ /**
159
+ * Dismiss the notice without any action.
160
+ */
161
+ if ( btnDismiss ) {
162
+ btnDismiss.addEventListener( 'click', function ( e ) {
163
+ e.preventDefault();
164
+ notifyWordPress( 'frash_dismiss', btnDismiss.dataset.msg );
165
+ } );
166
+ }
167
+
168
+ /**
169
+ * JavaScript implementation similar to a jQuery fadeIn().
170
+ *
171
+ * @param {Object} el
172
+ * @param {number} time
173
+ */
174
+ function fadeIn( el, time ) {
175
+ el.style.opacity = 0;
176
+ el.style.display = 'table';
177
+
178
+ let last = +new Date();
179
+ const tick = function () {
180
+ el.style.opacity = +el.style.opacity + ( new Date() - last ) / time;
181
+ last = +new Date();
182
+
183
+ if ( +el.style.opacity < 1 ) {
184
+ ( window.requestAnimationFrame &&
185
+ requestAnimationFrame( tick ) ) ||
186
+ setTimeout( tick, 10 );
187
+ }
188
+ };
189
+
190
+ tick();
191
+ }
192
+
193
+ /**
194
+ * Hide the notice after a CTA button was clicked.
195
+ */
196
+ function hideNotice() {
197
+ const tick = function () {
198
+ notice.style.opacity = notice.style.opacity - 0.05;
199
+
200
+ if ( +notice.style.opacity > 0 ) {
201
+ ( window.requestAnimationFrame &&
202
+ requestAnimationFrame( tick ) ) ||
203
+ setTimeout( tick, 10 );
204
+ } else {
205
+ notice.remove();
206
+ }
207
+ };
208
+
209
+ tick();
210
+ }
211
+
212
+ window.setTimeout( initialize, 500 );
213
+ } );
extra/free-dashboard/module.php CHANGED
@@ -5,8 +5,13 @@
5
  *
6
  * @version 1.3
7
  * @author Incsub (Philipp Stracker)
 
8
  */
 
9
  if ( ! class_exists( 'WDev_Frash' ) ) {
 
 
 
10
  class WDev_Frash {
11
 
12
  /**
@@ -34,7 +39,6 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
34
  * @since 1.2
35
  *
36
  * @var string
37
- *
38
  */
39
  private $mc_user_id = '53a1e972a043d1264ed082a5b';
40
 
@@ -43,14 +47,14 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
43
  *
44
  * @since 1.0.0
45
  */
46
- static public function instance() {
47
- static $Inst = null;
48
 
49
- if ( null === $Inst ) {
50
- $Inst = new WDev_Frash();
51
  }
52
 
53
- return $Inst;
54
  }
55
 
56
  /**
@@ -112,27 +116,27 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
112
  * Register an active plugin.
113
  *
114
  * @since 1.0.0
115
- * @param string $plugin_id WordPress plugin-ID (see: plugin_basename).
116
- * @param string $title Plugin name for display.
117
- * @param string $url_wp URL to the plugin on wp.org (domain not needed)
118
- * @param string $cta_email Title of the Email CTA button.
119
- * @param string $mc_list_id required. Mailchimp mailing list id for the plugin.
120
  */
121
  public function wdev_register_plugin( $plugin_id, $title, $url_wp, $cta_email = '', $mc_list_id = '' ) {
122
  // Ignore incorrectly registered plugins to avoid errors later.
123
- if ( empty( $plugin_id ) ) { return; }
124
- if ( empty( $title ) ) { return; }
125
- if ( empty( $url_wp ) ) { return; }
126
 
127
  if ( false === strpos( $url_wp, '://' ) ) {
128
  $url_wp = 'https://wordpress.org/' . trim( $url_wp, '/' );
129
  }
130
 
131
- $this->plugins[$plugin_id] = (object) array(
132
- 'id' => $plugin_id,
133
- 'title' => $title,
134
- 'url_wp' => $url_wp,
135
- 'cta_email' => $cta_email,
136
  'mc_list_id' => $mc_list_id,
137
  );
138
 
@@ -141,23 +145,25 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
141
  * in the persistent module-data that help us later to find out
142
  * if/which message should be displayed.
143
  */
144
- if ( empty( $this->stored['plugins'][$plugin_id] ) ) {
145
  // First register the plugin permanently.
146
- $this->stored['plugins'][$plugin_id] = time();
147
 
148
- // Second schedule the messages to display.
149
  $hash = md5( $plugin_id . '-email' );
150
- $this->stored['queue'][$hash] = array(
151
- 'plugin' => $plugin_id,
152
- 'type' => 'email',
 
 
153
  'show_at' => time(), // Earliest time to display note.
154
  );
155
 
156
  $hash = md5( $plugin_id . '-rate' );
157
- $this->stored['queue'][$hash] = array(
158
- 'plugin' => $plugin_id,
159
- 'type' => 'rate',
160
- 'show_at' => time() + 7 * DAY_IN_SECONDS,
 
161
  );
162
 
163
  // Finally save the details.
@@ -171,13 +177,12 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
171
  * @since 1.0.0
172
  */
173
  public function wp_ajax_frash_act() {
174
- $plugin = $_POST['plugin_id'];
175
- $type = $_POST['type'];
176
 
177
  $this->mark_as_done( $plugin, $type, 'ok' );
178
 
179
- echo 1;
180
- exit;
181
  }
182
 
183
  /**
@@ -186,13 +191,12 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
186
  * @since 1.0.0
187
  */
188
  public function wp_ajax_frash_dismiss() {
189
- $plugin = $_POST['plugin_id'];
190
- $type = $_POST['type'];
191
 
192
  $this->mark_as_done( $plugin, $type, 'ignore' );
193
 
194
- echo 1;
195
- exit;
196
  }
197
 
198
  /**
@@ -215,7 +219,9 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
215
  */
216
  public function all_admin_notices() {
217
  $info = $this->choose_message();
218
- if ( ! $info ) { return; }
 
 
219
 
220
  $this->render_message( $info );
221
  }
@@ -233,24 +239,32 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
233
  * string $plugin WordPress plugin ID?
234
  */
235
  protected function choose_message() {
236
- $obj = false;
237
- $chosen = false;
238
  $earliest = false;
239
 
240
  $now = time();
241
 
242
  // The "current" time can be changed via $_GET to test the module.
243
- if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! empty( $_GET['time'] ) ) {
244
- $custom_time = $_GET['time'];
245
- if ( ' ' == $custom_time[0] ) { $custom_time[0] = '+'; }
246
- if ( $custom_time ) { $now = strtotime( $custom_time ); }
247
- if ( ! $now ) { $now = time(); }
 
 
 
 
 
 
 
 
248
  }
249
 
250
  $tomorrow = $now + DAY_IN_SECONDS;
251
 
252
  foreach ( $this->stored['queue'] as $hash => $item ) {
253
- $show_at = intval( $item['show_at'] );
254
  $is_sticky = ! empty( $item['sticky'] );
255
 
256
  if ( ! isset( $this->plugins[ $item['plugin'] ] ) ) {
@@ -262,12 +276,12 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
262
  $can_display = true;
263
  if ( wp_is_mobile() ) {
264
  // Do not display rating message on mobile devices.
265
- if ( 'rate' == $item['type'] ) {
266
  $can_display = false;
267
  }
268
  }
269
- if ( 'email' == $item['type'] ) {
270
- //If we don't have mailchimp list id
271
  if ( ! $plugin->mc_list_id || ! $plugin->cta_email ) {
272
  // Do not display email message with missing email params.
273
  $can_display = false;
@@ -278,7 +292,9 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
278
  $can_display = false;
279
  }
280
 
281
- if ( ! $can_display ) { continue; }
 
 
282
 
283
  if ( $is_sticky ) {
284
  // If sticky item is present then choose it!
@@ -286,7 +302,7 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
286
  break;
287
  } elseif ( ! $earliest || $earliest < $show_at ) {
288
  $earliest = $show_at;
289
- $chosen = $hash;
290
  // Don't use `break` because a sticky item might follow...
291
  // Find the item with the earliest schedule.
292
  }
@@ -294,21 +310,21 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
294
 
295
  if ( $chosen ) {
296
  // Make the chosen item sticky.
297
- $this->stored['queue'][$chosen]['sticky'] = true;
298
 
299
  // Re-schedule other messages that are due today.
300
  foreach ( $this->stored['queue'] as $hash => $item ) {
301
- $show_at = intval( $item['show_at'] );
302
 
303
  if ( empty( $item['sticky'] ) && $tomorrow > $show_at ) {
304
- $this->stored['queue'][$hash]['show_at'] = $tomorrow;
305
  }
306
  }
307
 
308
  // Save the changes.
309
  $this->store_data();
310
 
311
- $obj = (object) $this->stored['queue'][$chosen];
312
  }
313
 
314
  return $obj;
@@ -318,25 +334,25 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
318
  * Moves a message from the queue to the done list.
319
  *
320
  * @since 1.0.0
321
- * @param string $plugin Plugin ID.
322
- * @param string $type [rate|email] Message type.
323
- * @param string $state [ok|ignore] Button clicked.
324
  */
325
  protected function mark_as_done( $plugin, $type, $state ) {
326
  $done_item = false;
327
 
328
  foreach ( $this->stored['queue'] as $hash => $item ) {
329
- unset( $this->stored['queue'][$hash]['sticky'] );
330
 
331
- if ( $item['plugin'] == $plugin && $item['type'] == $type ) {
332
  $done_item = $item;
333
- unset( $this->stored['queue'][$hash] );
334
  }
335
  }
336
 
337
  if ( $done_item ) {
338
- $done_item['state'] = $state;
339
- $done_item['hash'] = $hash;
340
  $done_item['handled_at'] = time();
341
  unset( $done_item['sticky'] );
342
 
@@ -349,27 +365,29 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
349
  * Renders the actual Notification message.
350
  *
351
  * @since 1.0.0
 
 
352
  */
353
  protected function render_message( $info ) {
354
- $plugin = $this->plugins[$info->plugin];
355
- $css_url = plugin_dir_url( __FILE__ ) . '/admin.css';
356
- $js_url = plugin_dir_url( __FILE__ ) . '/admin.js';
357
 
 
 
358
  ?>
359
- <link rel="stylesheet" type="text/css" href="<?php echo esc_url( $css_url ); ?>" />
360
  <div class="notice frash-notice frash-notice-<?php echo esc_attr( $info->type ); ?>" style="display:none">
361
  <input type="hidden" name="type" value="<?php echo esc_attr( $info->type ); ?>" />
362
  <input type="hidden" name="plugin_id" value="<?php echo esc_attr( $info->plugin ); ?>" />
363
  <input type="hidden" name="url_wp" value="<?php echo esc_attr( $plugin->url_wp ); ?>" />
364
  <?php
365
- if ( 'email' == $info->type ) {
366
  $this->render_email_message( $plugin );
367
- } elseif ( 'rate' == $info->type ) {
368
  $this->render_rate_message( $plugin );
369
  }
370
  ?>
371
  </div>
372
- <script src="<?php echo esc_url( $js_url ); ?>"></script>
373
  <?php
374
  }
375
 
@@ -378,13 +396,18 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
378
  * No return value. The code is directly output.
379
  *
380
  * @since 1.0.0
 
 
381
  */
382
  protected function render_email_message( $plugin ) {
383
  $admin_email = get_site_option( 'admin_email' );
 
384
  $action = "https://edublogs.us1.list-manage.com/subscribe/post-json?u={$this->mc_user_id}&id={$plugin->mc_list_id}&c=?";
385
 
 
386
  $msg = __( "We're happy that you've chosen to install %s! Are you interested in how to make the most of this plugin? How would you like a quick 5 day email crash course with actionable advice on building your membership site? Only the info you want, no subscription!", 'wdev_frash' );
387
  $msg = apply_filters( 'wdev-email-message-' . $plugin->id, $msg );
 
388
  $mc_list_id = $plugin->mc_list_id;
389
 
390
  ?>
@@ -392,31 +415,30 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
392
  <div class="frash-notice-message">
393
  <?php
394
  printf(
395
- $msg,
396
- '<strong>' . $plugin->title . '</strong>'
397
  );
398
  ?>
399
  </div>
400
  <div class="frash-notice-cta">
401
  <?php
402
  /**
403
- * Fires before subscribe form renders
404
- *
405
- * @since 1.3
406
- *
407
- * @param int $mc_list_id Mailchimp list id
408
- */
409
- do_action( 'frash_before_subscribe_form_render', $mc_list_id ); ?>
410
-
411
- <form action="<?php echo $action; ?>" method="get" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
412
  <input type="email" name="EMAIL" class="email" id="mce-EMAIL" value="<?php echo esc_attr( $admin_email ); ?>" required="required"/>
413
- <button class="frash-notice-act button-primary" data-msg="<?php _e( 'Thanks :)', 'wdev_frash' ); ?>" type="submit">
414
  <?php echo esc_html( $plugin->cta_email ); ?>
415
  </button>
416
- <button class="frash-notice-dismiss" data-msg="<?php _e( 'Saving', 'wdev_frash' ); ?>">
417
- <?php _e( 'No thanks', 'wdev_frash' ); ?>
418
  </button>
419
-
420
  <?php
421
  /**
422
  * Fires after subscribe form fields are rendered.
@@ -427,21 +449,21 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
427
  *
428
  * @since 1.3
429
  *
430
- * @param int $mc_list_id Mailchimp list id
431
  */
432
- do_action( 'frash_subscribe_form_fields', $mc_list_id ); ?>
 
433
  </form>
434
-
435
  <?php
436
  /**
437
  * Fires after subscribe form is rendered
438
  *
439
  * @since 1.3
440
  *
441
- * @param int $mc_list_id Mailchimp list id
442
  */
443
- do_action( 'frash_before_subscribe_form_render', $mc_list_id ); ?>
444
-
445
  </div>
446
  <?php
447
  }
@@ -451,12 +473,14 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
451
  * No return value. The code is directly output.
452
  *
453
  * @since 1.0.0
 
 
454
  */
455
  protected function render_rate_message( $plugin ) {
456
  $user = wp_get_current_user();
457
- $user_name = $user->display_name;
458
 
459
- $msg = __( "Hey %s, you've been using %s for a while now, and we hope you're happy with it.", 'wdev_frash' ) . '<br />'. __( "We've spent countless hours developing this free plugin for you, and we would really appreciate it if you dropped us a quick rating!", 'wdev_frash' );
 
460
  $msg = apply_filters( 'wdev-rating-message-' . $plugin->id, $msg );
461
 
462
  ?>
@@ -464,22 +488,24 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
464
  <div class="frash-notice-message">
465
  <?php
466
  printf(
467
- $msg,
468
- '<strong>' . $user_name . '</strong>',
469
- '<strong>' . $plugin->title . '</strong>'
 
470
  );
471
  ?>
472
  </div>
473
  <div class="frash-notice-cta">
474
- <button class="frash-notice-act button-primary" data-msg="<?php _e( 'Thanks :)', 'wdev_frash' ); ?>">
475
  <?php
476
- printf(
477
- __( 'Rate %s', 'wdev_frash' ),
478
  esc_html( $plugin->title )
479
- ); ?>
 
480
  </button>
481
- <button class="frash-notice-dismiss" data-msg="<?php _e( 'Saving', 'wdev_frash' ); ?>">
482
- <?php _e( 'No thanks', 'wdev_frash' ); ?>
483
  </button>
484
  </div>
485
  <?php
@@ -490,15 +516,17 @@ if ( ! class_exists( 'WDev_Frash' ) ) {
490
  * name as the action hook.
491
  *
492
  * @since 1.0.0
 
 
 
493
  */
494
  protected function add_action( $hook, $params = 1 ) {
495
  $method_name = strtolower( $hook );
496
  $method_name = preg_replace( '/[^a-z0-9]/', '_', $method_name );
497
- $handler = array( $this, $method_name );
498
- add_action( $hook, $handler, 5, $params );
499
  }
500
  }
501
 
502
  // Initialize the module.
503
  WDev_Frash::instance();
504
- }
5
  *
6
  * @version 1.3
7
  * @author Incsub (Philipp Stracker)
8
+ * @package wdev_frash
9
  */
10
+
11
  if ( ! class_exists( 'WDev_Frash' ) ) {
12
+ /**
13
+ * Class WDev_Frash
14
+ */
15
  class WDev_Frash {
16
 
17
  /**
39
  * @since 1.2
40
  *
41
  * @var string
 
42
  */
43
  private $mc_user_id = '53a1e972a043d1264ed082a5b';
44
 
47
  *
48
  * @since 1.0.0
49
  */
50
+ public static function instance() {
51
+ static $instance = null;
52
 
53
+ if ( null === $instance ) {
54
+ $instance = new WDev_Frash();
55
  }
56
 
57
+ return $instance;
58
  }
59
 
60
  /**
116
  * Register an active plugin.
117
  *
118
  * @since 1.0.0
119
+ * @param string $plugin_id WordPress plugin-ID (see: plugin_basename).
120
+ * @param string $title Plugin name for display.
121
+ * @param string $url_wp URL to the plugin on wp.org (domain not needed).
122
+ * @param string $cta_email Title of the Email CTA button.
123
+ * @param string $mc_list_id Required. Mailchimp mailing list id for the plugin.
124
  */
125
  public function wdev_register_plugin( $plugin_id, $title, $url_wp, $cta_email = '', $mc_list_id = '' ) {
126
  // Ignore incorrectly registered plugins to avoid errors later.
127
+ if ( empty( $plugin_id ) || empty( $title ) || empty( $url_wp ) ) {
128
+ return;
129
+ }
130
 
131
  if ( false === strpos( $url_wp, '://' ) ) {
132
  $url_wp = 'https://wordpress.org/' . trim( $url_wp, '/' );
133
  }
134
 
135
+ $this->plugins[ $plugin_id ] = (object) array(
136
+ 'id' => $plugin_id,
137
+ 'title' => $title,
138
+ 'url_wp' => $url_wp,
139
+ 'cta_email' => $cta_email,
140
  'mc_list_id' => $mc_list_id,
141
  );
142
 
145
  * in the persistent module-data that help us later to find out
146
  * if/which message should be displayed.
147
  */
148
+ if ( empty( $this->stored['plugins'][ $plugin_id ] ) ) {
149
  // First register the plugin permanently.
150
+ $this->stored['plugins'][ $plugin_id ] = time();
151
 
 
152
  $hash = md5( $plugin_id . '-email' );
153
+
154
+ // Second schedule the messages to display.
155
+ $this->stored['queue'][ $hash ] = array(
156
+ 'plugin' => $plugin_id,
157
+ 'type' => 'email',
158
  'show_at' => time(), // Earliest time to display note.
159
  );
160
 
161
  $hash = md5( $plugin_id . '-rate' );
162
+
163
+ $this->stored['queue'][ $hash ] = array(
164
+ 'plugin' => $plugin_id,
165
+ 'type' => 'rate',
166
+ 'show_at' => time() + WEEK_IN_SECONDS,
167
  );
168
 
169
  // Finally save the details.
177
  * @since 1.0.0
178
  */
179
  public function wp_ajax_frash_act() {
180
+ $plugin = filter_input( INPUT_POST, 'plugin_id', FILTER_SANITIZE_STRING );
181
+ $type = filter_input( INPUT_POST, 'type', FILTER_SANITIZE_STRING );
182
 
183
  $this->mark_as_done( $plugin, $type, 'ok' );
184
 
185
+ wp_die();
 
186
  }
187
 
188
  /**
191
  * @since 1.0.0
192
  */
193
  public function wp_ajax_frash_dismiss() {
194
+ $plugin = filter_input( INPUT_POST, 'plugin_id', FILTER_SANITIZE_STRING );
195
+ $type = filter_input( INPUT_POST, 'type', FILTER_SANITIZE_STRING );
196
 
197
  $this->mark_as_done( $plugin, $type, 'ignore' );
198
 
199
+ wp_die();
 
200
  }
201
 
202
  /**
219
  */
220
  public function all_admin_notices() {
221
  $info = $this->choose_message();
222
+ if ( ! $info ) {
223
+ return;
224
+ }
225
 
226
  $this->render_message( $info );
227
  }
239
  * string $plugin WordPress plugin ID?
240
  */
241
  protected function choose_message() {
242
+ $obj = false;
243
+ $chosen = false;
244
  $earliest = false;
245
 
246
  $now = time();
247
 
248
  // The "current" time can be changed via $_GET to test the module.
249
+ $custom_time = filter_input( INPUT_GET, 'time', FILTER_SANITIZE_STRING );
250
+ if ( defined( 'WP_DEBUG' ) && WP_DEBUG && ! empty( $custom_time ) ) {
251
+ if ( ' ' === $custom_time[0] ) {
252
+ $custom_time[0] = '+';
253
+ }
254
+
255
+ if ( $custom_time ) {
256
+ $now = strtotime( $custom_time );
257
+ }
258
+
259
+ if ( ! $now ) {
260
+ $now = time();
261
+ }
262
  }
263
 
264
  $tomorrow = $now + DAY_IN_SECONDS;
265
 
266
  foreach ( $this->stored['queue'] as $hash => $item ) {
267
+ $show_at = (int) $item['show_at'];
268
  $is_sticky = ! empty( $item['sticky'] );
269
 
270
  if ( ! isset( $this->plugins[ $item['plugin'] ] ) ) {
276
  $can_display = true;
277
  if ( wp_is_mobile() ) {
278
  // Do not display rating message on mobile devices.
279
+ if ( 'rate' === $item['type'] ) {
280
  $can_display = false;
281
  }
282
  }
283
+ if ( 'email' === $item['type'] ) {
284
+ // If we don't have mailchimp list id.
285
  if ( ! $plugin->mc_list_id || ! $plugin->cta_email ) {
286
  // Do not display email message with missing email params.
287
  $can_display = false;
292
  $can_display = false;
293
  }
294
 
295
+ if ( ! $can_display ) {
296
+ continue;
297
+ }
298
 
299
  if ( $is_sticky ) {
300
  // If sticky item is present then choose it!
302
  break;
303
  } elseif ( ! $earliest || $earliest < $show_at ) {
304
  $earliest = $show_at;
305
+ $chosen = $hash;
306
  // Don't use `break` because a sticky item might follow...
307
  // Find the item with the earliest schedule.
308
  }
310
 
311
  if ( $chosen ) {
312
  // Make the chosen item sticky.
313
+ $this->stored['queue'][ $chosen ]['sticky'] = true;
314
 
315
  // Re-schedule other messages that are due today.
316
  foreach ( $this->stored['queue'] as $hash => $item ) {
317
+ $show_at = (int) $item['show_at'];
318
 
319
  if ( empty( $item['sticky'] ) && $tomorrow > $show_at ) {
320
+ $this->stored['queue'][ $hash ]['show_at'] = $tomorrow;
321
  }
322
  }
323
 
324
  // Save the changes.
325
  $this->store_data();
326
 
327
+ $obj = (object) $this->stored['queue'][ $chosen ];
328
  }
329
 
330
  return $obj;
334
  * Moves a message from the queue to the done list.
335
  *
336
  * @since 1.0.0
337
+ * @param string $plugin Plugin ID.
338
+ * @param string $type Message type [rate|email].
339
+ * @param string $state Button clicked [ok|ignore].
340
  */
341
  protected function mark_as_done( $plugin, $type, $state ) {
342
  $done_item = false;
343
 
344
  foreach ( $this->stored['queue'] as $hash => $item ) {
345
+ unset( $this->stored['queue'][ $hash ]['sticky'] );
346
 
347
+ if ( $item['plugin'] === $plugin && $item['type'] === $type ) {
348
  $done_item = $item;
349
+ unset( $this->stored['queue'][ $hash ] );
350
  }
351
  }
352
 
353
  if ( $done_item ) {
354
+ $done_item['state'] = $state;
355
+ $done_item['hash'] = $hash;
356
  $done_item['handled_at'] = time();
357
  unset( $done_item['sticky'] );
358
 
365
  * Renders the actual Notification message.
366
  *
367
  * @since 1.0.0
368
+ *
369
+ * @param object $info Plugin info.
370
  */
371
  protected function render_message( $info ) {
372
+ $plugin = $this->plugins[ $info->plugin ];
373
+ $css_url = plugin_dir_url( __FILE__ ) . 'assets/admin.css';
374
+ $js_url = plugin_dir_url( __FILE__ ) . 'assets/admin.js';
375
 
376
+ wp_enqueue_style( 'wdev-frash-css', $css_url, array(), '1.3.0' );
377
+ wp_enqueue_script( 'wpev-frash-js', $js_url, array(), '1.3.0', true );
378
  ?>
 
379
  <div class="notice frash-notice frash-notice-<?php echo esc_attr( $info->type ); ?>" style="display:none">
380
  <input type="hidden" name="type" value="<?php echo esc_attr( $info->type ); ?>" />
381
  <input type="hidden" name="plugin_id" value="<?php echo esc_attr( $info->plugin ); ?>" />
382
  <input type="hidden" name="url_wp" value="<?php echo esc_attr( $plugin->url_wp ); ?>" />
383
  <?php
384
+ if ( 'email' === $info->type ) {
385
  $this->render_email_message( $plugin );
386
+ } elseif ( 'rate' === $info->type ) {
387
  $this->render_rate_message( $plugin );
388
  }
389
  ?>
390
  </div>
 
391
  <?php
392
  }
393
 
396
  * No return value. The code is directly output.
397
  *
398
  * @since 1.0.0
399
+ *
400
+ * @param object $plugin Plugin info.
401
  */
402
  protected function render_email_message( $plugin ) {
403
  $admin_email = get_site_option( 'admin_email' );
404
+
405
  $action = "https://edublogs.us1.list-manage.com/subscribe/post-json?u={$this->mc_user_id}&id={$plugin->mc_list_id}&c=?";
406
 
407
+ /* translators: %s - plugin name */
408
  $msg = __( "We're happy that you've chosen to install %s! Are you interested in how to make the most of this plugin? How would you like a quick 5 day email crash course with actionable advice on building your membership site? Only the info you want, no subscription!", 'wdev_frash' );
409
  $msg = apply_filters( 'wdev-email-message-' . $plugin->id, $msg );
410
+
411
  $mc_list_id = $plugin->mc_list_id;
412
 
413
  ?>
415
  <div class="frash-notice-message">
416
  <?php
417
  printf(
418
+ esc_html( $msg ),
419
+ '<strong>' . esc_html( $plugin->title ) . '</strong>'
420
  );
421
  ?>
422
  </div>
423
  <div class="frash-notice-cta">
424
  <?php
425
  /**
426
+ * Fires before subscribe form renders.
427
+ *
428
+ * @since 1.3
429
+ *
430
+ * @param int $mc_list_id Mailchimp list ID.
431
+ */
432
+ do_action( 'frash_before_subscribe_form_render', $mc_list_id );
433
+ ?>
434
+ <form action="<?php echo esc_attr( $action ); ?>" method="get" id="mc-embedded-subscribe-form" name="mc-embedded-subscribe-form" class="validate" target="_blank">
435
  <input type="email" name="EMAIL" class="email" id="mce-EMAIL" value="<?php echo esc_attr( $admin_email ); ?>" required="required"/>
436
+ <button class="frash-notice-act button-primary" data-msg="<?php esc_attr_e( 'Thanks :)', 'wdev_frash' ); ?>" type="submit">
437
  <?php echo esc_html( $plugin->cta_email ); ?>
438
  </button>
439
+ <button class="frash-notice-dismiss" data-msg="<?php esc_attr_e( 'Saving', 'wdev_frash' ); ?>">
440
+ <?php esc_html_e( 'No thanks', 'wdev_frash' ); ?>
441
  </button>
 
442
  <?php
443
  /**
444
  * Fires after subscribe form fields are rendered.
449
  *
450
  * @since 1.3
451
  *
452
+ * @param int $mc_list_id Mailchimp list ID.
453
  */
454
+ do_action( 'frash_subscribe_form_fields', $mc_list_id );
455
+ ?>
456
  </form>
 
457
  <?php
458
  /**
459
  * Fires after subscribe form is rendered
460
  *
461
  * @since 1.3
462
  *
463
+ * @param int $mc_list_id Mailchimp list ID.
464
  */
465
+ do_action( 'frash_before_subscribe_form_render', $mc_list_id );
466
+ ?>
467
  </div>
468
  <?php
469
  }
473
  * No return value. The code is directly output.
474
  *
475
  * @since 1.0.0
476
+ *
477
+ * @param object $plugin Plugin info.
478
  */
479
  protected function render_rate_message( $plugin ) {
480
  $user = wp_get_current_user();
 
481
 
482
+ /* translators: %1$s - user name, %2$s - plugin name, %2$s - new line <br> */
483
+ $msg = __( "Hey %1\$s, you've been using %2\$s for a while now, and we hope you're happy with it.", 'wdev_frash' ) . '%3$s' . __( "We've spent countless hours developing this free plugin for you, and we would really appreciate it if you dropped us a quick rating!", 'wdev_frash' );
484
  $msg = apply_filters( 'wdev-rating-message-' . $plugin->id, $msg );
485
 
486
  ?>
488
  <div class="frash-notice-message">
489
  <?php
490
  printf(
491
+ esc_html( $msg ),
492
+ '<strong>' . esc_html( $user->display_name ) . '</strong>',
493
+ '<strong>' . esc_html( $plugin->title ) . '</strong>',
494
+ '<br>'
495
  );
496
  ?>
497
  </div>
498
  <div class="frash-notice-cta">
499
+ <button class="frash-notice-act button-primary" data-msg="<?php esc_attr_e( 'Thanks :)', 'wdev_frash' ); ?>">
500
  <?php
501
+ printf( /* translators: %s - plugin name */
502
+ esc_html__( 'Rate %s', 'wdev_frash' ),
503
  esc_html( $plugin->title )
504
+ );
505
+ ?>
506
  </button>
507
+ <button class="frash-notice-dismiss" data-msg="<?php esc_attr_e( 'Saving', 'wdev_frash' ); ?>">
508
+ <?php esc_html_e( 'No thanks', 'wdev_frash' ); ?>
509
  </button>
510
  </div>
511
  <?php
516
  * name as the action hook.
517
  *
518
  * @since 1.0.0
519
+ *
520
+ * @param string $hook Hook name.
521
+ * @param int $params Number of passed in params.
522
  */
523
  protected function add_action( $hook, $params = 1 ) {
524
  $method_name = strtolower( $hook );
525
  $method_name = preg_replace( '/[^a-z0-9]/', '_', $method_name );
526
+ add_action( $hook, array( $this, $method_name ), 5, $params );
 
527
  }
528
  }
529
 
530
  // Initialize the module.
531
  WDev_Frash::instance();
532
+ }
extra/recommended-plugins-notice/notice.php CHANGED
@@ -299,7 +299,7 @@ if ( ! class_exists( 'WPMUDEV_Recommended_Plugins_Notice' ) ) {
299
  ),
300
  array(
301
  'name' => 'Defender Security',
302
- 'desc' => __( 'Create dynamic forms easily and quickly with our form builder.', 'wpmudev_recommended_plugins_notice' ),
303
  'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-defender.png',
304
  'free_slug' => 'defender-security/wp-defender.php',
305
  'pro_slug' => 'wp-defender/wp-defender.php',
299
  ),
300
  array(
301
  'name' => 'Defender Security',
302
+ 'desc' => __( 'Secure and protect your site from malicious hackers and bots.', 'wpmudev_recommended_plugins_notice' ),
303
  'image' => trailingslashit( plugin_dir_url( __FILE__ ) ) . '/assets/images/plugins-defender.png',
304
  'free_slug' => 'defender-security/wp-defender.php',
305
  'pro_slug' => 'wp-defender/wp-defender.php',
framework/db/mapper.php CHANGED
@@ -84,7 +84,6 @@ class Mapper extends Component {
84
  return $this;
85
  }
86
  if ( in_array( strtolower( $operator ), array( 'in', 'not in' ), true ) ) {
87
- //Todo: check implode() on php8
88
  $tmp = $key . " {$operator} (" . implode( ', ', array_fill( 0, count( $value ), $this->guess_var_type( $value ) ) ) . ')';
89
  $sql = call_user_func_array(
90
  array(
@@ -141,28 +140,38 @@ class Mapper extends Component {
141
  }
142
 
143
  /**
144
- * @param $order_by
145
- * @param $order
146
  *
147
  * @return $this
148
  */
149
  public function order_by( $order_by, $order = 'asc' ) {
 
150
  if ( ! in_array( $order, array( 'asc', 'desc' ) ) ) {
151
  // fall it back
152
  $order = 'asc';
153
  }
154
- $this->order = "ORDER BY $order_by $order";
 
 
 
 
155
 
156
  return $this;
157
  }
158
 
159
  /**
160
- * @param $offset
161
  *
162
  * @return $this
163
  */
164
  public function limit( $offset ) {
165
- $this->limit = 'LIMIT ' . $offset;
 
 
 
 
 
166
 
167
  return $this;
168
  }
@@ -265,10 +274,8 @@ class Mapper extends Component {
265
  // bind this for later use
266
  $model->id = $wpdb->insert_id;
267
  }
268
- if ( false === $ret ) {
269
- // error_log( $wpdb->last_error );
270
- // error_log( $this->saved_queries );
271
 
 
272
  return false;
273
  }
274
 
@@ -361,7 +368,8 @@ class Mapper extends Component {
361
  }
362
 
363
  /**
364
- * Join the stuff on the table to make a full query statement
 
365
  *
366
  * @param string $select
367
  *
84
  return $this;
85
  }
86
  if ( in_array( strtolower( $operator ), array( 'in', 'not in' ), true ) ) {
 
87
  $tmp = $key . " {$operator} (" . implode( ', ', array_fill( 0, count( $value ), $this->guess_var_type( $value ) ) ) . ')';
88
  $sql = call_user_func_array(
89
  array(
140
  }
141
 
142
  /**
143
+ * @param string $order_by
144
+ * @param string $order
145
  *
146
  * @return $this
147
  */
148
  public function order_by( $order_by, $order = 'asc' ) {
149
+ global $wpdb;
150
  if ( ! in_array( $order, array( 'asc', 'desc' ) ) ) {
151
  // fall it back
152
  $order = 'asc';
153
  }
154
+ $this->order = str_replace(
155
+ "'",
156
+ "",
157
+ $wpdb->prepare( "ORDER BY %s %s", $order_by, $order )
158
+ );
159
 
160
  return $this;
161
  }
162
 
163
  /**
164
+ * @param int|string $offset
165
  *
166
  * @return $this
167
  */
168
  public function limit( $offset ) {
169
+ global $wpdb;
170
+ $this->limit = str_replace(
171
+ "'",
172
+ "",
173
+ $wpdb->prepare( 'LIMIT ' . $this->guess_var_type( $offset ), $offset )
174
+ );
175
 
176
  return $this;
177
  }
274
  // bind this for later use
275
  $model->id = $wpdb->insert_id;
276
  }
 
 
 
277
 
278
+ if ( false === $ret ) {
279
  return false;
280
  }
281
 
368
  }
369
 
370
  /**
371
+ * Join the stuff on the table to make a full query statement.
372
+ * SQL params e.g. WHERE, ORDER or LIMIT were escaped on separate methods
373
  *
374
  * @param string $select
375
  *
languages/wpdef-default.pot CHANGED
@@ -6,9 +6,9 @@
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
- "Project-Id-Version: wp-defender 2.4.7\n"
10
  "Report-Msgid-Bugs-To: \n"
11
- "POT-Creation-Date: 2021-02-26 17:25+0200\n"
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
@@ -126,7 +126,7 @@ msgstr ""
126
  msgid "Hide details"
127
  msgstr ""
128
 
129
- #: extra/free-dashboard/module.php:386
130
  #, php-format
131
  msgid ""
132
  "We're happy that you've chosen to install %s! Are you interested in how to "
@@ -135,32 +135,32 @@ msgid ""
135
  "info you want, no subscription!"
136
  msgstr ""
137
 
138
- #: extra/free-dashboard/module.php:413 extra/free-dashboard/module.php:474
139
  msgid "Thanks :)"
140
  msgstr ""
141
 
142
- #: extra/free-dashboard/module.php:416 extra/free-dashboard/module.php:481
143
  msgid "Saving"
144
  msgstr ""
145
 
146
- #: extra/free-dashboard/module.php:417 extra/free-dashboard/module.php:482
147
  msgid "No thanks"
148
  msgstr ""
149
 
150
- #: extra/free-dashboard/module.php:459
151
  #, php-format
152
  msgid ""
153
- "Hey %s, you've been using %s for a while now, and we hope you're happy with "
154
- "it."
155
  msgstr ""
156
 
157
- #: extra/free-dashboard/module.php:459
158
  msgid ""
159
  "We've spent countless hours developing this free plugin for you, and we "
160
  "would really appreciate it if you dropped us a quick rating!"
161
  msgstr ""
162
 
163
- #: extra/free-dashboard/module.php:477
164
  #, php-format
165
  msgid "Rate %s"
166
  msgstr ""
@@ -179,23 +179,26 @@ msgid "Add powerful caching and optimize your assets."
179
  msgstr ""
180
 
181
  #: extra/recommended-plugins-notice/notice.php:302
182
- #: extra/recommended-plugins-notice/notice.php:318
183
- msgid "Create dynamic forms easily and quickly with our form builder."
184
  msgstr ""
185
 
186
  #: extra/recommended-plugins-notice/notice.php:310
187
  msgid "Configure your markup for optimal page and social ranking."
188
  msgstr ""
189
 
 
 
 
 
190
  #: extra/recommended-plugins-notice/notice.php:326
191
  msgid "Generate leads with pop-ups, slide-ins and email opt-ins."
192
  msgstr ""
193
 
194
- #: free/bootstrap.php:237
195
  msgid "Get Secure!"
196
  msgstr ""
197
 
198
- #: free/bootstrap.php:249
199
  msgid ""
200
  "You're awesome for installing Defender! Are you interested in how to make "
201
  "the most of this plugin? We've collected all the best security resources we "
@@ -333,7 +336,7 @@ msgstr ""
333
 
334
  #: src/behavior/scan-item/core-integrity.php:141
335
  #: src/behavior/scan-item/core-integrity.php:147
336
- #: src/behavior/scan-item/malware-result.php:105
337
  #: src/behavior/scan-item/plugin-integrity.php:207
338
  #: src/behavior/scan-item/plugin-integrity.php:213
339
  #: src/behavior/scan-item/theme-integrity.php:158
@@ -342,7 +345,7 @@ msgid "This item has been permanently removed"
342
  msgstr ""
343
 
344
  #: src/behavior/scan-item/core-integrity.php:151
345
- #: src/behavior/scan-item/malware-result.php:90
346
  #: src/behavior/scan-item/plugin-integrity.php:217
347
  #: src/behavior/scan-item/theme-integrity.php:168
348
  msgid "Defender doesn't have enough permission to remove this file"
6
  #, fuzzy
7
  msgid ""
8
  msgstr ""
9
+ "Project-Id-Version: wp-defender 2.4.8\n"
10
  "Report-Msgid-Bugs-To: \n"
11
+ "POT-Creation-Date: 2021-03-12 17:57+0200\n"
12
  "PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
13
  "Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
14
  "Language-Team: LANGUAGE <LL@li.org>\n"
126
  msgid "Hide details"
127
  msgstr ""
128
 
129
+ #: extra/free-dashboard/module.php:408
130
  #, php-format
131
  msgid ""
132
  "We're happy that you've chosen to install %s! Are you interested in how to "
135
  "info you want, no subscription!"
136
  msgstr ""
137
 
138
+ #: extra/free-dashboard/module.php:436 extra/free-dashboard/module.php:499
139
  msgid "Thanks :)"
140
  msgstr ""
141
 
142
+ #: extra/free-dashboard/module.php:439 extra/free-dashboard/module.php:507
143
  msgid "Saving"
144
  msgstr ""
145
 
146
+ #: extra/free-dashboard/module.php:440 extra/free-dashboard/module.php:508
147
  msgid "No thanks"
148
  msgstr ""
149
 
150
+ #: extra/free-dashboard/module.php:483
151
  #, php-format
152
  msgid ""
153
+ "Hey %1$s, you've been using %2$s for a while now, and we hope you're happy "
154
+ "with it."
155
  msgstr ""
156
 
157
+ #: extra/free-dashboard/module.php:483
158
  msgid ""
159
  "We've spent countless hours developing this free plugin for you, and we "
160
  "would really appreciate it if you dropped us a quick rating!"
161
  msgstr ""
162
 
163
+ #: extra/free-dashboard/module.php:502
164
  #, php-format
165
  msgid "Rate %s"
166
  msgstr ""
179
  msgstr ""
180
 
181
  #: extra/recommended-plugins-notice/notice.php:302
182
+ msgid "Secure and protect your site from malicious hackers and bots."
 
183
  msgstr ""
184
 
185
  #: extra/recommended-plugins-notice/notice.php:310
186
  msgid "Configure your markup for optimal page and social ranking."
187
  msgstr ""
188
 
189
+ #: extra/recommended-plugins-notice/notice.php:318
190
+ msgid "Create dynamic forms easily and quickly with our form builder."
191
+ msgstr ""
192
+
193
  #: extra/recommended-plugins-notice/notice.php:326
194
  msgid "Generate leads with pop-ups, slide-ins and email opt-ins."
195
  msgstr ""
196
 
197
+ #: free/bootstrap.php:239
198
  msgid "Get Secure!"
199
  msgstr ""
200
 
201
+ #: free/bootstrap.php:251
202
  msgid ""
203
  "You're awesome for installing Defender! Are you interested in how to make "
204
  "the most of this plugin? We've collected all the best security resources we "
336
 
337
  #: src/behavior/scan-item/core-integrity.php:141
338
  #: src/behavior/scan-item/core-integrity.php:147
339
+ #: src/behavior/scan-item/malware-result.php:92
340
  #: src/behavior/scan-item/plugin-integrity.php:207
341
  #: src/behavior/scan-item/plugin-integrity.php:213
342
  #: src/behavior/scan-item/theme-integrity.php:158
345
  msgstr ""
346
 
347
  #: src/behavior/scan-item/core-integrity.php:151
348
+ #: src/behavior/scan-item/malware-result.php:86
349
  #: src/behavior/scan-item/plugin-integrity.php:217
350
  #: src/behavior/scan-item/theme-integrity.php:168
351
  msgid "Defender doesn't have enough permission to remove this file"
readme.txt CHANGED
@@ -1,13 +1,13 @@
1
  === Defender Security - Malware Scanner, Login Security & Firewall ===
2
  Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
3
- Version: 2.4.7
4
  Author: WPMU DEV
5
  Author URI: https://wpmudev.com/
6
  Contributors: WPMUDEV
7
  Tags: security plugin, security, firewall, malware, malware scanner, antivirus, ip blocking, login security, brute force attacks, two-factor authentication, activity log, audit logs, block hackers, 2fa, hack
8
  Requires at least: 5.0
9
- Tested up to: 5.6.2
10
- Stable tag: 2.4.7
11
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
12
 
13
  Security plugin with malware scanner, IP blocking, audit logs, activity logs, firewall, login security & more.
@@ -158,6 +158,10 @@ WPMU DEV's expert support will restore and clean up your site after it’s been
158
 
159
  == Changelog ==
160
 
 
 
 
 
161
  = 2.4.7 ( 2021-03-01 ) =
162
 
163
  - New: Sync Config from Defender with The Hub
@@ -248,10 +252,6 @@ WPMU DEV's expert support will restore and clean up your site after it’s been
248
  - Fix: Masked Login Area not working in some cases
249
  - Fix: Hub redirect to 404 page when Masked Login Area enabled
250
 
251
- = 2.4.2 ( 2020-11-25 ) =
252
-
253
- - Fix: Fatal version on WordPress 5.2 and earlier
254
-
255
 
256
  [Changelog for previous versions](https://wpmudev.com/project/wp-defender/#view-changelog).
257
 
1
  === Defender Security - Malware Scanner, Login Security & Firewall ===
2
  Plugin Name: Defender Security - Malware Scanner, Login Security & Firewall
3
+ Version: 2.4.8
4
  Author: WPMU DEV
5
  Author URI: https://wpmudev.com/
6
  Contributors: WPMUDEV
7
  Tags: security plugin, security, firewall, malware, malware scanner, antivirus, ip blocking, login security, brute force attacks, two-factor authentication, activity log, audit logs, block hackers, 2fa, hack
8
  Requires at least: 5.0
9
+ Tested up to: 5.7
10
+ Stable tag: 2.4.8
11
  License: GPL v2 - http://www.gnu.org/licenses/old-licenses/gpl-2.0.html
12
 
13
  Security plugin with malware scanner, IP blocking, audit logs, activity logs, firewall, login security & more.
158
 
159
  == Changelog ==
160
 
161
+ = 2.4.8 ( 2021-03-12 ) =
162
+
163
+ - Fix: Unescaped DB parameters
164
+
165
  = 2.4.7 ( 2021-03-01 ) =
166
 
167
  - New: Sync Config from Defender with The Hub
252
  - Fix: Masked Login Area not working in some cases
253
  - Fix: Hub redirect to 404 page when Masked Login Area enabled
254
 
 
 
 
 
255
 
256
  [Changelog for previous versions](https://wpmudev.com/project/wp-defender/#view-changelog).
257
 
src/behavior/scan-item/malware-result.php CHANGED
@@ -80,25 +80,12 @@ class Malware_Result extends Behavior {
80
  return new \WP_Error( Error_Code::INVALID,
81
  __( 'wp-config.php can\'t be removed. Please remove the suspicious code manually.', 'wpdef' ) );
82
  }
83
- //Todo: improve logic
84
- // $plugin_path = WP_CONTENT_DIR . '/plugins';
85
- // $theme_path = WP_CONTENT_DIR . '/themes';
86
- // $rev_path = str_replace( [ $plugin_path, $theme_path ], '', $path );
87
  //if it not relative path, which mean it is something lay on wp-content folder, we can delete it
88
  if ( file_exists( $path ) ) {
89
  if ( ! @unlink( $path ) ) {
90
  return new \WP_Error( Error_Code::NOT_WRITEABLE, __( 'Defender doesn\'t have enough permission to remove this file', 'wpdef' ) );
91
  }
92
  }
93
- // $pools = explode( '/', $rev_path );
94
- // $pools = array_filter( $pools );
95
- // if ( 1 === count( $pools ) ) {
96
- // //this mean the file is hang in plugins/ or themes/ in first level, delete it
97
- // @unlink( $path );
98
- // } else {
99
- // //this is inside a folder, we delete whole
100
- // $folder_path = substr( $path, 0, strrpos( $path, $pools[0] ) );
101
- // }
102
  $scan->remove_issue( $this->owner->id );
103
 
104
  return [
80
  return new \WP_Error( Error_Code::INVALID,
81
  __( 'wp-config.php can\'t be removed. Please remove the suspicious code manually.', 'wpdef' ) );
82
  }
 
 
 
 
83
  //if it not relative path, which mean it is something lay on wp-content folder, we can delete it
84
  if ( file_exists( $path ) ) {
85
  if ( ! @unlink( $path ) ) {
86
  return new \WP_Error( Error_Code::NOT_WRITEABLE, __( 'Defender doesn\'t have enough permission to remove this file', 'wpdef' ) );
87
  }
88
  }
 
 
 
 
 
 
 
 
 
89
  $scan->remove_issue( $this->owner->id );
90
 
91
  return [
src/bootstrap.php CHANGED
@@ -209,12 +209,14 @@ class Bootstrap {
209
  private function maybe_show_onboarding() {
210
  //first we need to check if the site is newly create
211
  global $wpdb;
212
- $option = 'wp_defender_shown_activator';
213
  if ( ! is_multisite() ) {
214
- $res = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = '$option'" );
215
  } else {
216
- $network_id = get_current_network_id();
217
- $res = $wpdb->get_var( "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = '$option' AND site_id = $network_id" );
 
 
 
218
  }
219
  //Get '1' for direct SQL request if Onboarding was already
220
  if ( empty( $res ) ) {
209
  private function maybe_show_onboarding() {
210
  //first we need to check if the site is newly create
211
  global $wpdb;
 
212
  if ( ! is_multisite() ) {
213
+ $res = $wpdb->get_var( "SELECT option_value FROM $wpdb->options WHERE option_name = 'wp_defender_shown_activator'" );
214
  } else {
215
+ $sql = $wpdb->prepare(
216
+ "SELECT meta_value FROM $wpdb->sitemeta WHERE meta_key = 'wp_defender_shown_activator' AND site_id = %d",
217
+ get_current_network_id()
218
+ );
219
+ $res = $wpdb->get_var( $sql );
220
  }
221
  //Get '1' for direct SQL request if Onboarding was already
222
  if ( empty( $res ) ) {
src/controller/audit-logging.php CHANGED
@@ -50,7 +50,7 @@ class Audit_Logging extends Controller2 {
50
  * We will schedule the time for flush data into cloud
51
  */
52
  if ( ! wp_next_scheduled( 'audit_sync_events' ) ) {
53
- wp_schedule_event( time(), 'hourly', 'audit_sync_events' );
54
  }
55
  add_action( 'audit_sync_events', array( &$this, 'sync_events' ) );
56
 
@@ -58,7 +58,7 @@ class Audit_Logging extends Controller2 {
58
  * We will schedule the time to clean up old logs
59
  */
60
  if ( ! wp_next_scheduled( 'audit_clean_up_logs' ) ) {
61
- wp_schedule_event( time(), 'hourly', 'audit_clean_up_logs' );
62
  }
63
  add_action( 'audit_clean_up_logs', array( &$this, 'clean_up_audit_logs' ) );
64
  }
50
  * We will schedule the time for flush data into cloud
51
  */
52
  if ( ! wp_next_scheduled( 'audit_sync_events' ) ) {
53
+ wp_schedule_event( time() + 15, 'hourly', 'audit_sync_events' );
54
  }
55
  add_action( 'audit_sync_events', array( &$this, 'sync_events' ) );
56
 
58
  * We will schedule the time to clean up old logs
59
  */
60
  if ( ! wp_next_scheduled( 'audit_clean_up_logs' ) ) {
61
+ wp_schedule_event( time() + 5, 'hourly', 'audit_clean_up_logs' );
62
  }
63
  add_action( 'audit_clean_up_logs', array( &$this, 'clean_up_audit_logs' ) );
64
  }
src/controller/firewall.php CHANGED
@@ -58,7 +58,7 @@ class Firewall extends \WP_Defender\Controller2 {
58
  * We will schedule the time to clean up old firewall logs
59
  */
60
  if ( ! wp_next_scheduled( 'firewall_clean_up_logs' ) ) {
61
- wp_schedule_event( time(), 'hourly', 'firewall_clean_up_logs' );
62
  }
63
 
64
  add_action( 'firewall_clean_up_logs', array( &$this, 'clean_up_firewall_logs' ) );
58
  * We will schedule the time to clean up old firewall logs
59
  */
60
  if ( ! wp_next_scheduled( 'firewall_clean_up_logs' ) ) {
61
+ wp_schedule_event( time() + 10, 'hourly', 'firewall_clean_up_logs' );
62
  }
63
 
64
  add_action( 'firewall_clean_up_logs', array( &$this, 'clean_up_firewall_logs' ) );
wp-defender.php CHANGED
@@ -2,7 +2,7 @@
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
- * Version: 2.4.7
6
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
7
  * Author: WPMU DEV
8
  * Author URI: https://wpmudev.com/
@@ -15,10 +15,10 @@ if ( ! defined( 'ABSPATH' ) ) {
15
  die;
16
  }
17
  if ( ! defined( 'DEFENDER_VERSION' ) ) {
18
- define( 'DEFENDER_VERSION', '2.4.7' );
19
  }
20
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
21
- define( 'DEFENDER_DB_VERSION', '2.4.7' );
22
  }
23
  if ( ! defined( 'DEFENDER_SUI' ) ) {
24
  define( 'DEFENDER_SUI', '2-9-6' );
2
  /**
3
  * Plugin Name: Defender
4
  * Plugin URI: https://wpmudev.com/project/wp-defender/
5
+ * Version: 2.4.8
6
  * Description: Get regular security scans, vulnerability reports, safety recommendations and customized hardening for your site in just a few clicks. Defender is the analyst and enforcer who never sleeps.
7
  * Author: WPMU DEV
8
  * Author URI: https://wpmudev.com/
15
  die;
16
  }
17
  if ( ! defined( 'DEFENDER_VERSION' ) ) {
18
+ define( 'DEFENDER_VERSION', '2.4.8' );
19
  }
20
  if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
21
+ define( 'DEFENDER_DB_VERSION', '2.4.8' );
22
  }
23
  if ( ! defined( 'DEFENDER_SUI' ) ) {
24
  define( 'DEFENDER_SUI', '2-9-6' );