Version Description
( 2021-03-12 ) =
- Fix: Unescaped DB parameters
Download this release
Release Info
Developer | BigTonny |
Plugin | 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 +165 -0
- extra/free-dashboard/assets/admin.js +213 -0
- extra/free-dashboard/module.php +133 -105
- extra/recommended-plugins-notice/notice.php +1 -1
- framework/db/mapper.php +18 -10
- languages/wpdef-default.pot +20 -17
- readme.txt +7 -7
- src/behavior/scan-item/malware-result.php +0 -13
- src/bootstrap.php +6 -4
- src/controller/audit-logging.php +2 -2
- src/controller/firewall.php +1 -1
- wp-defender.php +3 -3
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
|
47 |
-
static $
|
48 |
|
49 |
-
if ( null === $
|
50 |
-
$
|
51 |
}
|
52 |
|
53 |
-
return $
|
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
|
116 |
-
* @param string $title
|
117 |
-
* @param string $url_wp
|
118 |
-
* @param string $cta_email
|
119 |
-
* @param string $mc_list_id
|
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 ) )
|
124 |
-
|
125 |
-
|
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'
|
133 |
-
'title'
|
134 |
-
'url_wp'
|
135 |
-
'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 |
-
|
151 |
-
|
152 |
-
|
|
|
|
|
153 |
'show_at' => time(), // Earliest time to display note.
|
154 |
);
|
155 |
|
156 |
$hash = md5( $plugin_id . '-rate' );
|
157 |
-
|
158 |
-
|
159 |
-
'
|
160 |
-
'
|
|
|
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 =
|
175 |
-
$type
|
176 |
|
177 |
$this->mark_as_done( $plugin, $type, 'ok' );
|
178 |
|
179 |
-
|
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 =
|
190 |
-
$type
|
191 |
|
192 |
$this->mark_as_done( $plugin, $type, 'ignore' );
|
193 |
|
194 |
-
|
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 ) {
|
|
|
|
|
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
|
237 |
-
$chosen
|
238 |
$earliest = false;
|
239 |
|
240 |
$now = time();
|
241 |
|
242 |
// The "current" time can be changed via $_GET to test the module.
|
243 |
-
|
244 |
-
|
245 |
-
if ( ' '
|
246 |
-
|
247 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
248 |
}
|
249 |
|
250 |
$tomorrow = $now + DAY_IN_SECONDS;
|
251 |
|
252 |
foreach ( $this->stored['queue'] as $hash => $item ) {
|
253 |
-
$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'
|
266 |
$can_display = false;
|
267 |
}
|
268 |
}
|
269 |
-
if ( 'email'
|
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 ) {
|
|
|
|
|
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
|
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 =
|
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
|
322 |
-
* @param string $type [rate|email]
|
323 |
-
* @param string $state [ok|ignore]
|
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']
|
332 |
$done_item = $item;
|
333 |
-
unset( $this->stored['queue'][$hash] );
|
334 |
}
|
335 |
}
|
336 |
|
337 |
if ( $done_item ) {
|
338 |
-
$done_item['state']
|
339 |
-
$done_item['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
|
355 |
-
$css_url = plugin_dir_url( __FILE__ ) . '/admin.css';
|
356 |
-
$js_url
|
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'
|
366 |
$this->render_email_message( $plugin );
|
367 |
-
} elseif ( 'rate'
|
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 |
-
|
404 |
-
|
405 |
-
|
406 |
-
|
407 |
-
|
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
|
414 |
<?php echo esc_html( $plugin->cta_email ); ?>
|
415 |
</button>
|
416 |
-
<button class="frash-notice-dismiss" data-msg="<?php
|
417 |
-
<?php
|
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
|
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
|
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 |
-
|
|
|
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>' . $
|
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
|
475 |
<?php
|
476 |
-
printf(
|
477 |
-
|
478 |
esc_html( $plugin->title )
|
479 |
-
);
|
|
|
480 |
</button>
|
481 |
-
<button class="frash-notice-dismiss" data-msg="<?php
|
482 |
-
<?php
|
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 |
-
$
|
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' => __( '
|
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 =
|
|
|
|
|
|
|
|
|
155 |
|
156 |
return $this;
|
157 |
}
|
158 |
|
159 |
/**
|
160 |
-
* @param $offset
|
161 |
*
|
162 |
* @return $this
|
163 |
*/
|
164 |
public function limit( $offset ) {
|
165 |
-
|
|
|
|
|
|
|
|
|
|
|
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.
|
10 |
"Report-Msgid-Bugs-To: \n"
|
11 |
-
"POT-Creation-Date: 2021-
|
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:
|
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:
|
139 |
msgid "Thanks :)"
|
140 |
msgstr ""
|
141 |
|
142 |
-
#: extra/free-dashboard/module.php:
|
143 |
msgid "Saving"
|
144 |
msgstr ""
|
145 |
|
146 |
-
#: extra/free-dashboard/module.php:
|
147 |
msgid "No thanks"
|
148 |
msgstr ""
|
149 |
|
150 |
-
#: extra/free-dashboard/module.php:
|
151 |
#, php-format
|
152 |
msgid ""
|
153 |
-
"Hey %s, you've been using %s for a while now, and we hope you're happy
|
154 |
-
"it."
|
155 |
msgstr ""
|
156 |
|
157 |
-
#: extra/free-dashboard/module.php:
|
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:
|
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 |
-
|
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:
|
195 |
msgid "Get Secure!"
|
196 |
msgstr ""
|
197 |
|
198 |
-
#: free/bootstrap.php:
|
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:
|
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:
|
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.
|
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.
|
10 |
-
Stable tag: 2.4.
|
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 = '
|
215 |
} else {
|
216 |
-
$
|
217 |
-
|
|
|
|
|
|
|
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.
|
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.
|
19 |
}
|
20 |
if ( ! defined( 'DEFENDER_DB_VERSION' ) ) {
|
21 |
-
define( 'DEFENDER_DB_VERSION', '2.4.
|
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' );
|