Gentoo Archives: gentoo-commits

From: Yury German <blueknight@g.o>
To: gentoo-commits@l.g.o
Subject: [gentoo-commits] proj/blogs-gentoo:master commit in: plugins/akismet/, plugins/akismet/_inc/img/, plugins/akismet/views/, ...
Date: Mon, 24 Jan 2022 00:12:40
Message-Id: 1642982886.0949f1a8dfdad78ba67fb1dcd58537b83a26e8a3.blueknight@gentoo
1 commit: 0949f1a8dfdad78ba67fb1dcd58537b83a26e8a3
2 Author: Yury German <blueknight <AT> gentoo <DOT> org>
3 AuthorDate: Mon Jan 24 00:08:06 2022 +0000
4 Commit: Yury German <blueknight <AT> gentoo <DOT> org>
5 CommitDate: Mon Jan 24 00:08:06 2022 +0000
6 URL: https://gitweb.gentoo.org/proj/blogs-gentoo.git/commit/?id=0949f1a8
7
8 Plugin - akismet update from 4.1.3 to 4.2.1
9
10 Signed-off-by: Yury German <blueknight <AT> gentoo.org>
11
12 plugins/akismet/.htaccess | 2 +-
13 plugins/akismet/_inc/akismet.css | 83 ++++-
14 plugins/akismet/_inc/akismet.js | 207 +++++++----
15 plugins/akismet/_inc/form.js | 30 --
16 plugins/akismet/_inc/img/logo-a-2x.png | Bin 0 -> 904 bytes
17 plugins/akismet/akismet.php | 6 +-
18 plugins/akismet/{readme.txt => changelog.txt} | 39 +--
19 plugins/akismet/class.akismet-admin.php | 167 +++++----
20 plugins/akismet/class.akismet-widget.php | 24 +-
21 plugins/akismet/class.akismet.php | 477 ++++++++++++++++++++------
22 plugins/akismet/readme.txt | 476 +++----------------------
23 plugins/akismet/views/config.php | 8 +-
24 plugins/akismet/views/enter.php | 2 +-
25 plugins/akismet/views/notice.php | 193 +++++++++--
26 plugins/akismet/views/setup.php | 5 +-
27 plugins/akismet/views/stats.php | 2 +-
28 16 files changed, 939 insertions(+), 782 deletions(-)
29
30 diff --git a/plugins/akismet/.htaccess b/plugins/akismet/.htaccess
31 index 49d72d71..d2675517 100644
32 --- a/plugins/akismet/.htaccess
33 +++ b/plugins/akismet/.htaccess
34 @@ -23,7 +23,7 @@
35 </FilesMatch>
36
37 # Akismet images
38 -<FilesMatch "^logo-full-2x\.png$">
39 +<FilesMatch "^logo-(a|full)-2x\.png$">
40 <IfModule !mod_authz_core.c>
41 Allow from all
42 </IfModule>
43
44 diff --git a/plugins/akismet/_inc/akismet.css b/plugins/akismet/_inc/akismet.css
45 index fea4eb7b..a62f7a84 100644
46 --- a/plugins/akismet/_inc/akismet.css
47 +++ b/plugins/akismet/_inc/akismet.css
48 @@ -79,15 +79,6 @@ table.comments td.comment p a:after {
49 .checkforspam {
50 display: inline-block !important;
51 }
52 -.checkforspam-progress {
53 - display: none;
54 -}
55 -.checkforspam.checking .checkforspam-progress {
56 - padding-left: 1ex;
57 -}
58 -.checkforspam.button-disabled .checkforspam-progress {
59 - display: inline;
60 -}
61
62 .checkforspam-spinner {
63 display: inline-block;
64 @@ -109,12 +100,9 @@ table.comments td.comment p a:after {
65 margin-top: .5rem;
66 }
67 .akismet-alert {
68 - border: 1px solid #e5e5e5;
69 padding: 0.4em 1em 1.4em 1em;
70 - border-radius: 3px;
71 - -webkit-border-radius: 3px;
72 - border-width: 1px;
73 - border-style: solid;
74 + box-sizing: border-box;
75 + box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
76 }
77
78 .akismet-alert h3.akismet-key-status {
79 @@ -661,3 +649,70 @@ table.comments td.comment p a:after {
80 .akismet-section-header__actions {
81 line-height: 1.75rem;
82 }
83 +
84 +.akismet-setup-instructions {
85 + text-align: center;
86 +}
87 +
88 +.akismet-setup-instructions form {
89 + padding-bottom: 1.5rem;
90 +}
91 +
92 +div.error.akismet-usage-limit-alert {
93 + padding: 25px 45px 25px 15px;
94 + display: flex;
95 + align-items: center;
96 +}
97 +
98 +#akismet-plugin-container .akismet-usage-limit-alert {
99 + margin: 0 auto 0.625rem auto;
100 + box-sizing: border-box;
101 + box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
102 + border: none;
103 + border-left: 4px solid #d63638;
104 +}
105 +
106 +.akismet-usage-limit-alert .akismet-usage-limit-logo {
107 + width: 38px;
108 + min-width: 38px;
109 + height: 38px;
110 + border-radius: 20px;
111 + margin-right: 18px;
112 + background: black;
113 + position: relative;
114 +}
115 +
116 +.akismet-usage-limit-alert .akismet-usage-limit-logo img {
117 + position: absolute;
118 + width: 22px;
119 + left: 8px;
120 + top: 10px;
121 +}
122 +
123 +.akismet-usage-limit-alert .akismet-usage-limit-text {
124 + flex-grow: 1;
125 + margin-right: 18px;
126 +}
127 +
128 +.akismet-usage-limit-alert h3 {
129 + margin: 0;
130 +}
131 +
132 +.akismet-usage-limit-alert .akismet-usage-limit-cta {
133 + text-align: right;
134 +}
135 +
136 +@media (max-width: 550px) {
137 + div.error.akismet-usage-limit-alert {
138 + display: block;
139 + }
140 +
141 + .akismet-usage-limit-alert .akismet-usage-limit-logo,
142 + .akismet-usage-limit-alert .akismet-usage-limit-text {
143 + margin-bottom: 15px;
144 + }
145 +
146 + .akismet-usage-limit-alert .akismet-usage-limit-cta {
147 + text-align: left;
148 + }
149 +}
150 \ No newline at end of file
151
152 diff --git a/plugins/akismet/_inc/akismet.js b/plugins/akismet/_inc/akismet.js
153 index 3445a094..7ebac1a5 100644
154 --- a/plugins/akismet/_inc/akismet.js
155 +++ b/plugins/akismet/_inc/akismet.js
156 @@ -1,10 +1,12 @@
157 jQuery( function ( $ ) {
158 var mshotRemovalTimer = null;
159 - var mshotSecondTryTimer = null
160 - var mshotThirdTryTimer = null
161 -
162 + var mshotRetryTimer = null;
163 + var mshotTries = 0;
164 + var mshotRetryInterval = 1000;
165 var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
166 -
167 +
168 + var preloadedMshotURLs = [];
169 +
170 $('.akismet-status').each(function () {
171 var thisId = $(this).attr('commentid');
172 $(this).prependTo('#comment-' + thisId + ' .column-comment');
173 @@ -84,69 +86,142 @@ jQuery( function ( $ ) {
174 });
175
176 // Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
177 - $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
178 - clearTimeout( mshotRemovalTimer );
179 + if ( "enable_mshots" in WPAkismet && WPAkismet.enable_mshots ) {
180 + $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
181 + clearTimeout( mshotRemovalTimer );
182
183 - if ( $( '.akismet-mshot' ).length > 0 ) {
184 - if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
185 - // The preview is already showing for this link.
186 - return;
187 + if ( $( '.akismet-mshot' ).length > 0 ) {
188 + if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
189 + // The preview is already showing for this link.
190 + return;
191 + }
192 + else {
193 + // A new link is being hovered, so remove the old preview.
194 + $( '.akismet-mshot' ).remove();
195 + }
196 + }
197 +
198 + clearTimeout( mshotRetryTimer );
199 +
200 + var linkUrl = $( this ).attr( 'href' );
201 +
202 + if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
203 + // This preview image was already preloaded, so begin with a retry URL so the user doesn't see the placeholder image for the first second.
204 + mshotTries = 2;
205 }
206 else {
207 - // A new link is being hovered, so remove the old preview.
208 - $( '.akismet-mshot' ).remove();
209 + mshotTries = 1;
210 }
211 - }
212
213 - clearTimeout( mshotSecondTryTimer );
214 - clearTimeout( mshotThirdTryTimer );
215 + var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + akismet_mshot_url( linkUrl, mshotTries ) + '" width="450" height="338" class="mshot-image" /></div>' );
216 + mShot.data( 'link', this );
217 + mShot.data( 'url', linkUrl );
218 +
219 + mShot.find( 'img' ).on( 'load', function () {
220 + $( '.akismet-mshot' ).data( 'pending-request', false );
221 + } );
222
223 - var thisHref = $( this ).attr( 'href' );
224 + var offset = $( this ).offset();
225
226 - var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="' + akismet_mshot_url( thisHref ) + '" width="450" height="338" class="mshot-image" /></div>' );
227 - mShot.data( 'link', this );
228 + mShot.offset( {
229 + left : Math.min( $( window ).width() - 475, offset.left + $( this ).width() + 10 ), // Keep it on the screen if the link is near the edge of the window.
230 + top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
231 + } );
232
233 - var offset = $( this ).offset();
234 + $( 'body' ).append( mShot );
235
236 - mShot.offset( {
237 - left : Math.min( $( window ).width() - 475, offset.left + $( this ).width() + 10 ), // Keep it on the screen if the link is near the edge of the window.
238 - top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
239 + mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
240 + } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
241 + mshotRemovalTimer = setTimeout( function () {
242 + clearTimeout( mshotRetryTimer );
243 +
244 + $( '.akismet-mshot' ).remove();
245 + }, 200 );
246 } );
247
248 - // These retries appear to be superfluous if .mshot-image has already loaded, but it's because mShots
249 - // can return a "Generating thumbnail..." image if it doesn't have a thumbnail ready, so we need
250 - // to retry to see if we can get the newly generated thumbnail.
251 - mshotSecondTryTimer = setTimeout( function () {
252 - mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 2 ) );
253 - }, 6000 );
254 -
255 - mshotThirdTryTimer = setTimeout( function () {
256 - mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 3 ) );
257 - }, 12000 );
258 -
259 - $( 'body' ).append( mShot );
260 - } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
261 - mshotRemovalTimer = setTimeout( function () {
262 - clearTimeout( mshotSecondTryTimer );
263 - clearTimeout( mshotThirdTryTimer );
264 -
265 - $( '.akismet-mshot' ).remove();
266 - }, 200 );
267 - } ).on( 'mouseover', 'tr', function () {
268 - // When the mouse hovers over a comment row, begin preloading mshots for any links in the comment or the comment author.
269 - var linksToPreloadMshotsFor = $( this ).find( mshotEnabledLinkSelector );
270 -
271 - linksToPreloadMshotsFor.each( function () {
272 - // Don't attempt to preload an mshot for a single link twice. Browser caching should cover this, but in case of
273 - // race conditions, save a flag locally when we've begun trying to preload one.
274 - if ( ! $( this ).data( 'akismet-mshot-preloaded' ) ) {
275 - akismet_preload_mshot( $( this ).attr( 'href' ) );
276 + var preloadDelayTimer = null;
277 +
278 + $( window ).on( 'scroll resize', function () {
279 + clearTimeout( preloadDelayTimer );
280 +
281 + preloadDelayTimer = setTimeout( preloadMshotsInViewport, 500 );
282 + } );
283 +
284 + preloadMshotsInViewport();
285 + }
286 +
287 + /**
288 + * The way mShots works is if there was no screenshot already recently generated for the URL,
289 + * it returns a "loading..." image for the first request. Then, some subsequent request will
290 + * receive the actual screenshot, but it's unknown how long it will take. So, what we do here
291 + * is continually re-request the mShot, waiting a second after every response until we get the
292 + * actual screenshot.
293 + */
294 + function retryMshotUntilLoaded() {
295 + clearTimeout( mshotRetryTimer );
296 +
297 + var imageWidth = $( '.akismet-mshot img' ).get(0).naturalWidth;
298 +
299 + if ( imageWidth == 0 ) {
300 + // It hasn't finished loading yet the first time. Check again shortly.
301 + setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
302 + }
303 + else if ( imageWidth == 400 ) {
304 + // It loaded the preview image.
305 +
306 + if ( mshotTries == 20 ) {
307 + // Give up if we've requested the mShot 20 times already.
308 + return;
309 + }
310 +
311 + if ( ! $( '.akismet-mshot' ).data( 'pending-request' ) ) {
312 + $( '.akismet-mshot' ).data( 'pending-request', true );
313 +
314 + mshotTries++;
315 +
316 + $( '.akismet-mshot .mshot-image' ).attr( 'src', akismet_mshot_url( $( '.akismet-mshot' ).data( 'url' ), mshotTries ) );
317 + }
318 +
319 + mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
320 + }
321 + else {
322 + // All done.
323 + }
324 + }
325 +
326 + function preloadMshotsInViewport() {
327 + var windowWidth = $( window ).width();
328 + var windowHeight = $( window ).height();
329 +
330 + $( '#the-comment-list' ).find( mshotEnabledLinkSelector ).each( function ( index, element ) {
331 + var linkUrl = $( this ).attr( 'href' );
332 +
333 + // Don't attempt to preload an mshot for a single link twice.
334 + if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
335 + // The URL is already preloaded.
336 + return true;
337 + }
338 +
339 + if ( typeof element.getBoundingClientRect !== 'function' ) {
340 + // The browser is too old. Return false to stop this preloading entirely.
341 + return false;
342 + }
343 +
344 + var rect = element.getBoundingClientRect();
345 +
346 + if ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= windowHeight && rect.right <= windowWidth ) {
347 + akismet_preload_mshot( linkUrl );
348 $( this ).data( 'akismet-mshot-preloaded', true );
349 }
350 } );
351 - } );
352 + }
353 +
354 + $( '.checkforspam.enable-on-load' ).on( 'click', function( e ) {
355 + if ( $( this ).hasClass( 'ajax-disabled' ) ) {
356 + // Akismet hasn't been configured yet. Allow the user to proceed to the button's link.
357 + return;
358 + }
359
360 - $( '.checkforspam' ).click( function( e ) {
361 e.preventDefault();
362
363 if ( $( this ).hasClass( 'button-disabled' ) ) {
364 @@ -157,11 +232,8 @@ jQuery( function ( $ ) {
365 $('.checkforspam').addClass('button-disabled').addClass( 'checking' );
366 $('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
367
368 - // Update the label on the "Check for Spam" button to use the active "Checking for Spam" language.
369 - $( '.checkforspam .akismet-label' ).text( $( '.checkforspam' ).data( 'active-label' ) );
370 -
371 akismet_check_for_spam(0, 100);
372 - });
373 + }).removeClass( 'button-disabled' );
374
375 var spam_count = 0;
376 var recheck_count = 0;
377 @@ -176,7 +248,7 @@ jQuery( function ( $ ) {
378 var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
379
380 // Update the progress counter on the "Check for Spam" button.
381 - $( '.checkforspam-progress' ).text( check_for_spam_buttons.data( 'progress-label-format' ).replace( '%1$s', percentage_complete ) );
382 + $( '.checkforspam' ).text( check_for_spam_buttons.data( 'progress-label' ).replace( '%1$s', percentage_complete ) );
383
384 $.post(
385 ajaxurl,
386 @@ -269,12 +341,14 @@ jQuery( function ( $ ) {
387 * @return string The mShot URL;
388 */
389 function akismet_mshot_url( linkUrl, retry ) {
390 - var mshotUrl = '//s0.wordpress.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
391 -
392 - if ( retry ) {
393 + var mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
394 +
395 + if ( retry > 1 ) {
396 mshotUrl += '&r=' + encodeURIComponent( retry );
397 }
398 -
399 +
400 + mshotUrl += '&source=akismet';
401 +
402 return mshotUrl;
403 }
404
405 @@ -286,17 +360,10 @@ jQuery( function ( $ ) {
406 function akismet_preload_mshot( linkUrl ) {
407 var img = new Image();
408 img.src = akismet_mshot_url( linkUrl );
409 +
410 + preloadedMshotURLs.push( linkUrl );
411 }
412
413 - /**
414 - * Sets the comment form privacy notice display to hide when one clicks Core's dismiss button on the related admin notice.
415 - */
416 - $( '#akismet-privacy-notice-admin-notice' ).on( 'click', '.notice-dismiss', function () {
417 - $.ajax( {
418 - url: './options-general.php?page=akismet-key-config&akismet_comment_form_privacy_notice=hide',
419 - } );
420 - });
421 -
422 $( '.akismet-could-be-primary' ).each( function () {
423 var form = $( this ).closest( 'form' );
424
425
426 diff --git a/plugins/akismet/_inc/form.js b/plugins/akismet/_inc/form.js
427 deleted file mode 100644
428 index 3a5be8af..00000000
429 --- a/plugins/akismet/_inc/form.js
430 +++ /dev/null
431 @@ -1,30 +0,0 @@
432 -var ak_js = document.getElementById( "ak_js" );
433 -
434 -if ( ! ak_js ) {
435 - ak_js = document.createElement( 'input' );
436 - ak_js.setAttribute( 'id', 'ak_js' );
437 - ak_js.setAttribute( 'name', 'ak_js' );
438 - ak_js.setAttribute( 'type', 'hidden' );
439 -}
440 -else {
441 - ak_js.parentNode.removeChild( ak_js );
442 -}
443 -
444 -ak_js.setAttribute( 'value', ( new Date() ).getTime() );
445 -
446 -var commentForm = document.getElementById( 'commentform' );
447 -
448 -if ( commentForm ) {
449 - commentForm.appendChild( ak_js );
450 -}
451 -else {
452 - var replyRowContainer = document.getElementById( 'replyrow' );
453 -
454 - if ( replyRowContainer ) {
455 - var children = replyRowContainer.getElementsByTagName( 'td' );
456 -
457 - if ( children.length > 0 ) {
458 - children[0].appendChild( ak_js );
459 - }
460 - }
461 -}
462 \ No newline at end of file
463
464 diff --git a/plugins/akismet/_inc/img/logo-a-2x.png b/plugins/akismet/_inc/img/logo-a-2x.png
465 new file mode 100644
466 index 00000000..087144ae
467 Binary files /dev/null and b/plugins/akismet/_inc/img/logo-a-2x.png differ
468
469 diff --git a/plugins/akismet/akismet.php b/plugins/akismet/akismet.php
470 index 538a7dbc..2175a913 100644
471 --- a/plugins/akismet/akismet.php
472 +++ b/plugins/akismet/akismet.php
473 @@ -6,7 +6,7 @@
474 Plugin Name: Akismet Anti-Spam
475 Plugin URI: https://akismet.com/
476 Description: Used by millions, Akismet is quite possibly the best way in the world to <strong>protect your blog from spam</strong>. It keeps your site protected even while you sleep. To get started: activate the Akismet plugin and then go to your Akismet Settings page to set up your API key.
477 -Version: 4.1.3
478 +Version: 4.2.1
479 Author: Automattic
480 Author URI: https://automattic.com/wordpress-plugins/
481 License: GPLv2 or later
482 @@ -37,8 +37,8 @@ if ( !function_exists( 'add_action' ) ) {
483 exit;
484 }
485
486 -define( 'AKISMET_VERSION', '4.1.3' );
487 -define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
488 +define( 'AKISMET_VERSION', '4.2.1' );
489 +define( 'AKISMET__MINIMUM_WP_VERSION', '5.0' );
490 define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
491 define( 'AKISMET_DELETE_LIMIT', 100000 );
492
493
494 diff --git a/plugins/akismet/readme.txt b/plugins/akismet/changelog.txt
495 similarity index 92%
496 copy from plugins/akismet/readme.txt
497 copy to plugins/akismet/changelog.txt
498 index bf0081a9..680bc2e6 100644
499 --- a/plugins/akismet/readme.txt
500 +++ b/plugins/akismet/changelog.txt
501 @@ -1,34 +1,25 @@
502 === Akismet Anti-Spam ===
503 -Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
504 -Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
505 -Requires at least: 4.0
506 -Tested up to: 5.3
507 -Stable tag: 4.1.3
508 -License: GPLv2 or later
509
510 -Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
511 +== Archived Changelog Entries ==
512
513 -== Description ==
514 +This file contains older changelog entries, so we can keep the size of the standard WordPress readme.txt file reasonable.
515 +For the latest changes, please see the "Changelog" section of the [readme.txt file](https://plugins.svn.wordpress.org/akismet/trunk/readme.txt).
516
517 -Akismet checks your comments and contact form submissions against our global database of spam to prevent your site from publishing malicious content. You can review the comment spam it catches on your blog's "Comments" admin screen.
518 += 4.1.5 =
519 +*Release Date - 29 April 2020*
520
521 -Major features in Akismet include:
522 +* Based on user feedback, we have dropped the in-admin notice explaining the availability of the "privacy notice" option in the AKismet settings screen. The option itself is available, but after displaying the notice for the last 2 years, it is now considered a known fact.
523 +* Updated the "Requires at least" to WP 4.6, based on recommendations from https://wp-info.org/tools/checkplugini18n.php?slug=akismet
524 +* Moved older changelog entries to a separate file to keep the size of this readme reasonable, also based on recommendations from https://wp-info.org/tools/checkplugini18n.php?slug=akismet
525
526 -* Automatically checks all comments and filters out the ones that look like spam.
527 -* Each comment has a status history, so you can easily see which comments were caught or cleared by Akismet and which were spammed or unspammed by a moderator.
528 -* URLs are shown in the comment body to reveal hidden or misleading links.
529 -* Moderators can see the number of approved comments for each user.
530 -* A discard feature that outright blocks the worst spam, saving you disk space and speeding up your site.
531 += 4.1.4 =
532 +*Release Date - 17 March 2020*
533
534 -PS: You'll be prompted to get an Akismet.com API key to use it, once activated. Keys are free for personal blogs; paid subscriptions are available for businesses and commercial sites.
535 -
536 -== Installation ==
537 -
538 -Upload the Akismet plugin to your blog, activate it, and then enter your Akismet.com API key.
539 -
540 -1, 2, 3: You're done!
541 -
542 -== Changelog ==
543 +* Only redirect to the Akismet setup screen upon plugin activation if the plugin was activated manually from within the plugin-related screens, to help users with non-standard install workflows, like WP-CLI.
544 +* Update the layout of the initial setup screen to be more readable on small screens.
545 +* If no API key has been entered, don't run code that expects an API key.
546 +* Improve the readability of the comment history entries.
547 +* Don't modify the comment form HTML if no API key has been set.
548
549 = 4.1.3 =
550 *Release Date - 31 October 2019*
551
552 diff --git a/plugins/akismet/class.akismet-admin.php b/plugins/akismet/class.akismet-admin.php
553 index b5e2ef8e..c6cb1355 100644
554 --- a/plugins/akismet/class.akismet-admin.php
555 +++ b/plugins/akismet/class.akismet-admin.php
556 @@ -32,10 +32,6 @@ class Akismet_Admin {
557 if ( isset( $_POST['action'] ) && $_POST['action'] == 'enter-key' ) {
558 self::enter_api_key();
559 }
560 -
561 - if ( ! empty( $_GET['akismet_comment_form_privacy_notice'] ) && empty( $_GET['settings-updated']) ) {
562 - self::set_form_privacy_notice_option( $_GET['akismet_comment_form_privacy_notice'] );
563 - }
564 }
565
566 public static function init_hooks() {
567 @@ -70,11 +66,6 @@ class Akismet_Admin {
568
569 add_filter( 'all_plugins', array( 'Akismet_Admin', 'modify_plugin_description' ) );
570
571 - if ( class_exists( 'Jetpack' ) ) {
572 - add_filter( 'akismet_comment_form_privacy_notice_url_display', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
573 - add_filter( 'akismet_comment_form_privacy_notice_url_hide', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
574 - }
575 -
576 // priority=1 because we need ours to run before core's comment anonymizer runs, and that's registered at priority=10
577 add_filter( 'wp_privacy_personal_data_erasers', array( 'Akismet_Admin', 'register_personal_data_eraser' ), 1 );
578 }
579 @@ -146,7 +137,7 @@ class Akismet_Admin {
580
581 wp_register_script( 'akismet.js', plugin_dir_url( __FILE__ ) . '_inc/akismet.js', array('jquery'), AKISMET_VERSION );
582 wp_enqueue_script( 'akismet.js' );
583 -
584 +
585 $inline_js = array(
586 'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' ),
587 'strings' => array(
588 @@ -162,6 +153,10 @@ class Akismet_Admin {
589 $inline_js['start_recheck'] = true;
590 }
591
592 + if ( apply_filters( 'akismet_enable_mshots', true ) ) {
593 + $inline_js['enable_mshots'] = true;
594 + }
595 +
596 wp_localize_script( 'akismet.js', 'WPAkismet', $inline_js );
597 }
598 }
599 @@ -392,27 +387,40 @@ class Akismet_Admin {
600 return;
601 }
602
603 - $link = add_query_arg( array( 'action' => 'akismet_recheck_queue' ), admin_url( 'admin.php' ) );
604 + $link = '';
605
606 $comments_count = wp_count_comments();
607
608 echo '</div>';
609 echo '<div class="alignleft actions">';
610 +
611 + $classes = array(
612 + 'button-secondary',
613 + 'checkforspam',
614 + 'button-disabled' // Disable button until the page is loaded
615 + );
616 +
617 + if ( $comments_count->moderated > 0 ) {
618 + $classes[] = 'enable-on-load';
619 +
620 + if ( ! Akismet::get_api_key() ) {
621 + $link = add_query_arg( array( 'page' => 'akismet-key-config' ), class_exists( 'Jetpack' ) ? admin_url( 'admin.php' ) : admin_url( 'options-general.php' ) );
622 + $classes[] = 'ajax-disabled';
623 + }
624 + }
625 +
626 echo '<a
627 - class="button-secondary checkforspam' . ( $comments_count->moderated == 0 ? ' button-disabled' : '' ) . '"
628 - href="' . esc_url( $link ) . '"
629 - data-active-label="' . esc_attr( __( 'Checking for Spam', 'akismet' ) ) . '"
630 - data-progress-label-format="' . esc_attr( __( '(%1$s%)', 'akismet' ) ) . '"
631 + class="' . esc_attr( implode( ' ', $classes ) ) . '"' .
632 + ( ! empty( $link ) ? ' href="' . esc_url( $link ) . '"' : '' ) .
633 + /* translators: The placeholder is for showing how much of the process has completed, as a percent. e.g., "Checking for Spam (40%)" */
634 + ' data-progress-label="' . esc_attr( __( 'Checking for Spam (%1$s%)', 'akismet' ) ) . '"
635 data-success-url="' . esc_attr( remove_query_arg( array( 'akismet_recheck', 'akismet_recheck_error' ), add_query_arg( array( 'akismet_recheck_complete' => 1, 'recheck_count' => urlencode( '__recheck_count__' ), 'spam_count' => urlencode( '__spam_count__' ) ) ) ) ) . '"
636 data-failure-url="' . esc_attr( remove_query_arg( array( 'akismet_recheck', 'akismet_recheck_complete' ), add_query_arg( array( 'akismet_recheck_error' => 1 ) ) ) ) . '"
637 data-pending-comment-count="' . esc_attr( $comments_count->moderated ) . '"
638 data-nonce="' . esc_attr( wp_create_nonce( 'akismet_check_for_spam' ) ) . '"
639 - >';
640 - echo '<span class="akismet-label">' . esc_html__('Check for Spam', 'akismet') . '</span>';
641 - echo '<span class="checkforspam-progress"></span>';
642 - echo '</a>';
643 + ' . ( ! in_array( 'ajax-disabled', $classes ) ? 'onclick="return false;"' : '' ) . '
644 + >' . esc_html__('Check for Spam', 'akismet') . '</a>';
645 echo '<span class="checkforspam-spinner"></span>';
646 -
647 }
648
649 public static function recheck_queue() {
650 @@ -575,10 +583,8 @@ class Akismet_Admin {
651 $history = Akismet::get_comment_history( $comment->comment_ID );
652
653 if ( $history ) {
654 - echo '<div class="akismet-history" style="margin: 13px;">';
655 -
656 foreach ( $history as $row ) {
657 - $time = date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT';
658 + $time = date( 'D d M Y @ h:i:s a', $row['time'] ) . ' GMT';
659
660 $message = '';
661
662 @@ -588,56 +594,67 @@ class Akismet_Admin {
663 // 1) Save space.
664 // 2) The message can be translated into the current language of the blog, not stuck
665 // in the language of the blog when the comment was made.
666 - $message = $row['message'];
667 + $message = esc_html( $row['message'] );
668 }
669
670 // If possible, use a current translation.
671 switch ( $row['event'] ) {
672 case 'recheck-spam';
673 - $message = __( 'Akismet re-checked and caught this comment as spam.', 'akismet' );
674 + $message = esc_html( __( 'Akismet re-checked and caught this comment as spam.', 'akismet' ) );
675 break;
676 case 'check-spam':
677 - $message = __( 'Akismet caught this comment as spam.', 'akismet' );
678 + $message = esc_html( __( 'Akismet caught this comment as spam.', 'akismet' ) );
679 break;
680 case 'recheck-ham':
681 - $message = __( 'Akismet re-checked and cleared this comment.', 'akismet' );
682 + $message = esc_html( __( 'Akismet re-checked and cleared this comment.', 'akismet' ) );
683 break;
684 case 'check-ham':
685 - $message = __( 'Akismet cleared this comment.', 'akismet' );
686 + $message = esc_html( __( 'Akismet cleared this comment.', 'akismet' ) );
687 break;
688 case 'wp-blacklisted':
689 - $message = __( 'Comment was caught by wp_blacklist_check.', 'akismet' );
690 + case 'wp-disallowed':
691 + $message = sprintf(
692 + /* translators: The placeholder is a WordPress PHP function name. */
693 + esc_html( __( 'Comment was caught by %s.', 'akismet' ) ),
694 + function_exists( 'wp_check_comment_disallowed_list' ) ? '<code>wp_check_comment_disallowed_list</code>' : '<code>wp_blacklist_check</code>'
695 + );
696 break;
697 case 'report-spam':
698 if ( isset( $row['user'] ) ) {
699 - $message = sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] );
700 + $message = esc_html( sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] ) );
701 }
702 else if ( ! $message ) {
703 - $message = __( 'This comment was reported as spam.', 'akismet' );
704 + $message = esc_html( __( 'This comment was reported as spam.', 'akismet' ) );
705 }
706 break;
707 case 'report-ham':
708 if ( isset( $row['user'] ) ) {
709 - $message = sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] );
710 + $message = esc_html( sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] ) );
711 }
712 else if ( ! $message ) {
713 - $message = __( 'This comment was reported as not spam.', 'akismet' );
714 + $message = esc_html( __( 'This comment was reported as not spam.', 'akismet' ) );
715 }
716 break;
717 case 'cron-retry-spam':
718 - $message = __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet');
719 + $message = esc_html( __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet') );
720 break;
721 case 'cron-retry-ham':
722 - $message = __( 'Akismet cleared this comment during an automatic retry.', 'akismet');
723 + $message = esc_html( __( 'Akismet cleared this comment during an automatic retry.', 'akismet') );
724 break;
725 case 'check-error':
726 if ( isset( $row['meta'], $row['meta']['response'] ) ) {
727 - $message = sprintf( __( 'Akismet was unable to check this comment (response: %s) but will automatically retry later.', 'akismet'), $row['meta']['response'] );
728 + $message = sprintf( esc_html( __( 'Akismet was unable to check this comment (response: %s) but will automatically retry later.', 'akismet') ), '<code>' . esc_html( $row['meta']['response'] ) . '</code>' );
729 + }
730 + else {
731 + $message = esc_html( __( 'Akismet was unable to check this comment but will automatically retry later.', 'akismet' ) );
732 }
733 break;
734 case 'recheck-error':
735 if ( isset( $row['meta'], $row['meta']['response'] ) ) {
736 - $message = sprintf( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet'), $row['meta']['response'] );
737 + $message = sprintf( esc_html( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet') ), '<code>' . esc_html( $row['meta']['response'] ) . '</code>' );
738 + }
739 + else {
740 + $message = esc_html( __( 'Akismet was unable to recheck this comment.', 'akismet' ) );
741 }
742 break;
743 default:
744 @@ -645,27 +662,32 @@ class Akismet_Admin {
745 // Half of these used to be saved without the dash after 'status-changed'.
746 // See https://plugins.trac.wordpress.org/changeset/1150658/akismet/trunk
747 $new_status = preg_replace( '/^status-changed-?/', '', $row['event'] );
748 - $message = sprintf( __( 'Comment status was changed to %s', 'akismet' ), $new_status );
749 + $message = sprintf( esc_html( __( 'Comment status was changed to %s', 'akismet' ) ), '<code>' . esc_html( $new_status ) . '</code>' );
750 }
751 else if ( preg_match( '/^status-/', $row['event'] ) ) {
752 $new_status = preg_replace( '/^status-/', '', $row['event'] );
753
754 if ( isset( $row['user'] ) ) {
755 - $message = sprintf( __( '%1$s changed the comment status to %2$s.', 'akismet' ), $row['user'], $new_status );
756 + $message = sprintf( esc_html( __( '%1$s changed the comment status to %2$s.', 'akismet' ) ), $row['user'], '<code>' . esc_html( $new_status ) . '</code>' );
757 }
758 }
759 break;
760
761 }
762
763 - echo '<div style="margin-bottom: 13px;">';
764 + if ( ! empty( $message ) ) {
765 + echo '<p>';
766 echo '<span style="color: #999;" alt="' . $time . '" title="' . $time . '">' . sprintf( esc_html__('%s ago', 'akismet'), human_time_diff( $row['time'] ) ) . '</span>';
767 echo ' - ';
768 - echo esc_html( $message );
769 - echo '</div>';
770 + echo $message; // esc_html() is done above so that we can use HTML in some messages.
771 + echo '</p>';
772 + }
773 }
774 -
775 - echo '</div>';
776 + }
777 + else {
778 + echo '<p>';
779 + echo esc_html( __( 'No comment history.', 'akismet' ) );
780 + echo '</p>';
781 }
782 }
783
784 @@ -866,12 +888,21 @@ class Akismet_Admin {
785 ) );
786 }
787
788 - public static function display_privacy_notice_control_warning() {
789 - if ( !current_user_can( 'manage_options' ) )
790 - return;
791 - Akismet::view( 'notice', array(
792 - 'type' => 'privacy',
793 - ) );
794 + public static function get_usage_limit_alert_data() {
795 + return array(
796 + 'type' => 'usage-limit',
797 + 'code' => (int) get_option( 'akismet_alert_code' ),
798 + 'msg' => get_option( 'akismet_alert_msg' ),
799 + 'api_calls' => get_option( 'akismet_alert_api_calls' ),
800 + 'usage_limit' => get_option( 'akismet_alert_usage_limit' ),
801 + 'upgrade_plan' => get_option( 'akismet_alert_upgrade_plan' ),
802 + 'upgrade_url' => get_option( 'akismet_alert_upgrade_url' ),
803 + 'upgrade_type' => get_option( 'akismet_alert_upgrade_type' ),
804 + );
805 + }
806 +
807 + public static function display_usage_limit_alert() {
808 + Akismet::view( 'notice', self::get_usage_limit_alert_data() );
809 }
810
811 public static function display_spam_check_warning() {
812 @@ -1007,8 +1038,9 @@ class Akismet_Admin {
813 $notices[] = array( 'type' => $akismet_user->status );
814 }
815
816 - if ( false === get_option( 'akismet_comment_form_privacy_notice' ) ) {
817 - $notices[] = array( 'type' => 'privacy' );
818 + $alert_code = get_option( 'akismet_alert_code' );
819 + if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
820 + $notices[] = self::get_usage_limit_alert_data();
821 }
822
823 /*
824 @@ -1030,6 +1062,7 @@ class Akismet_Admin {
825 $notices[] = array( 'type' => 'new-key-failed' );
826 $notices[] = array( 'type' => 'limit-reached', 'level' => 'yellow' );
827 $notices[] = array( 'type' => 'limit-reached', 'level' => 'red' );
828 + $notices[] = array( 'type' => 'usage-limit', 'api_calls' => '15000', 'usage_limit' => '10000', 'upgrade_plan' => 'Enterprise', 'upgrade_url' => 'https://akismet.com/account/' );
829 */
830
831 Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
832 @@ -1046,22 +1079,28 @@ class Akismet_Admin {
833
834 if ( in_array( $hook_suffix, array( 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
835 Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
836 -
837 - if ( get_option( 'akismet_alert_code' ) > 0 )
838 +
839 + $alert_code = get_option( 'akismet_alert_code' );
840 + if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
841 + self::display_usage_limit_alert();
842 + } elseif ( $alert_code > 0 ) {
843 self::display_alert();
844 + }
845 }
846 - elseif ( $hook_suffix == 'plugins.php' && !Akismet::get_api_key() ) {
847 + elseif ( ( 'plugins.php' === $hook_suffix || 'edit-comments.php' === $hook_suffix ) && ! Akismet::get_api_key() ) {
848 + // Show the "Set Up Akismet" banner on the comments and plugin pages if no API key has been set.
849 self::display_api_key_warning();
850 }
851 elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
852 self::display_spam_check_warning();
853 }
854 - else if ( isset( $_GET['akismet_recheck_complete'] ) ) {
855 +
856 + if ( isset( $_GET['akismet_recheck_complete'] ) ) {
857 $recheck_count = (int) $_GET['recheck_count'];
858 $spam_count = (int) $_GET['spam_count'];
859
860 if ( $recheck_count === 0 ) {
861 - $message = __( 'There were no comments to check. Akismet will only check comments in the Pending queue.', 'akismet' );
862 + $message = __( 'There were no comments to check. Akismet will only check comments awaiting moderation.', 'akismet' );
863 }
864 else {
865 $message = sprintf( _n( 'Akismet checked %s comment.', 'Akismet checked %s comments.', $recheck_count, 'akismet' ), number_format( $recheck_count ) );
866 @@ -1080,14 +1119,6 @@ class Akismet_Admin {
867 else if ( isset( $_GET['akismet_recheck_error'] ) ) {
868 echo '<div class="notice notice-error"><p>' . esc_html( __( 'Akismet could not recheck your comments for spam.', 'akismet' ) ) . '</p></div>';
869 }
870 -
871 - $akismet_comment_form_privacy_notice_option = get_option( 'akismet_comment_form_privacy_notice' );
872 - if ( ! in_array( $akismet_comment_form_privacy_notice_option, array( 'hide', 'display' ) ) ) {
873 - $api_key = Akismet::get_api_key();
874 - if ( ! empty( $api_key ) ) {
875 - self::display_privacy_notice_control_warning();
876 - }
877 - }
878 }
879
880 public static function display_status() {
881 @@ -1127,7 +1158,7 @@ class Akismet_Admin {
882 if ( !class_exists('Jetpack') )
883 return false;
884
885 - if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '7.7', '<' ) ) {
886 + if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '7.7', '<' ) ) {
887 // For version of Jetpack prior to 7.7.
888 Jetpack::load_xml_rpc_client();
889 }
890 @@ -1202,10 +1233,6 @@ class Akismet_Admin {
891 update_option( 'akismet_comment_form_privacy_notice', $state );
892 }
893 }
894 -
895 - public static function jetpack_comment_form_privacy_notice_url( $url ) {
896 - return str_replace( 'options-general.php', 'admin.php', $url );
897 - }
898
899 public static function register_personal_data_eraser( $erasers ) {
900 $erasers['akismet'] = array(
901
902 diff --git a/plugins/akismet/class.akismet-widget.php b/plugins/akismet/class.akismet-widget.php
903 index 55b0f35c..9f0458b0 100644
904 --- a/plugins/akismet/class.akismet-widget.php
905 +++ b/plugins/akismet/class.akismet-widget.php
906 @@ -99,7 +99,29 @@ class Akismet_Widget extends WP_Widget {
907 ?>
908
909 <div class="a-stats">
910 - <a href="https://akismet.com" target="_blank" title=""><?php printf( _n( '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>', '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>', $count , 'akismet'), number_format_i18n( $count ) ); ?></a>
911 + <a href="https://akismet.com" target="_blank" rel="noopener" title="">
912 + <?php
913 +
914 + echo wp_kses(
915 + sprintf(
916 + /* translators: The placeholder is the number of pieces of spam blocked by Akismet. */
917 + _n(
918 + '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
919 + '<strong class="count">%1$s spam</strong> blocked by <strong>Akismet</strong>',
920 + $count,
921 + 'akismet'
922 + ),
923 + number_format_i18n( $count )
924 + ),
925 + array(
926 + 'strong' => array(
927 + 'class' => true,
928 + ),
929 + )
930 + );
931 +
932 + ?>
933 + </a>
934 </div>
935
936 <?php
937
938 diff --git a/plugins/akismet/class.akismet.php b/plugins/akismet/class.akismet.php
939 index 01753014..1681d0e1 100644
940 --- a/plugins/akismet/class.akismet.php
941 +++ b/plugins/akismet/class.akismet.php
942 @@ -5,12 +5,19 @@ class Akismet {
943 const API_PORT = 80;
944 const MAX_DELAY_BEFORE_MODERATION_EMAIL = 86400; // One day in seconds
945
946 + public static $limit_notices = array(
947 + 10501 => 'FIRST_MONTH_OVER_LIMIT',
948 + 10502 => 'SECOND_MONTH_OVER_LIMIT',
949 + 10504 => 'THIRD_MONTH_APPROACHING_LIMIT',
950 + 10508 => 'THIRD_MONTH_OVER_LIMIT',
951 + 10516 => 'FOUR_PLUS_MONTHS_OVER_LIMIT',
952 + );
953 +
954 private static $last_comment = '';
955 private static $initiated = false;
956 private static $prevent_moderation_email_for_these_comments = array();
957 private static $last_comment_result = null;
958 private static $comment_as_submitted_allowed_keys = array( 'blog' => '', 'blog_charset' => '', 'blog_lang' => '', 'blog_ua' => '', 'comment_agent' => '', 'comment_author' => '', 'comment_author_IP' => '', 'comment_author_email' => '', 'comment_author_url' => '', 'comment_content' => '', 'comment_date_gmt' => '', 'comment_tags' => '', 'comment_type' => '', 'guid' => '', 'is_test' => '', 'permalink' => '', 'reporter' => '', 'site_domain' => '', 'submit_referer' => '', 'submit_uri' => '', 'user_ID' => '', 'user_agent' => '', 'user_id' => '', 'user_ip' => '' );
959 - private static $is_rest_api_call = false;
960
961 public static function init() {
962 if ( ! self::$initiated ) {
963 @@ -34,11 +41,7 @@ class Akismet {
964 add_action( 'akismet_schedule_cron_recheck', array( 'Akismet', 'cron_recheck' ) );
965
966 add_action( 'comment_form', array( 'Akismet', 'add_comment_nonce' ), 1 );
967 -
968 - add_action( 'admin_head-edit-comments.php', array( 'Akismet', 'load_form_js' ) );
969 - add_action( 'comment_form', array( 'Akismet', 'load_form_js' ) );
970 - add_action( 'comment_form', array( 'Akismet', 'inject_ak_js' ) );
971 - add_filter( 'script_loader_tag', array( 'Akismet', 'set_form_js_async' ), 10, 3 );
972 + add_action( 'comment_form', array( 'Akismet', 'output_custom_form_fields' ) );
973
974 add_filter( 'comment_moderation_recipients', array( 'Akismet', 'disable_moderation_emails_if_unreachable' ), 1000, 2 );
975 add_filter( 'pre_comment_approved', array( 'Akismet', 'last_comment_status' ), 10, 2 );
976 @@ -47,9 +50,20 @@ class Akismet {
977
978 // Run this early in the pingback call, before doing a remote fetch of the source uri
979 add_action( 'xmlrpc_call', array( 'Akismet', 'pre_check_pingback' ) );
980 -
981 +
982 // Jetpack compatibility
983 add_filter( 'jetpack_options_whitelist', array( 'Akismet', 'add_to_jetpack_options_whitelist' ) );
984 + add_filter( 'jetpack_contact_form_html', array( 'Akismet', 'inject_custom_form_fields' ) );
985 + add_filter( 'jetpack_contact_form_akismet_values', array( 'Akismet', 'prepare_custom_form_values' ) );
986 +
987 + // Gravity Forms
988 + add_filter( 'gform_get_form_filter', array( 'Akismet', 'inject_custom_form_fields' ) );
989 + add_filter( 'gform_akismet_fields', array( 'Akismet', 'prepare_custom_form_values' ) );
990 +
991 + // Contact Form 7
992 + add_filter( 'wpcf7_form_elements', array( 'Akismet', 'append_custom_form_fields' ) );
993 + add_filter( 'wpcf7_akismet_parameters', array( 'Akismet', 'prepare_custom_form_values' ) );
994 +
995 add_action( 'update_option_wordpress_api_key', array( 'Akismet', 'updated_option' ), 10, 2 );
996 add_action( 'add_option_wordpress_api_key', array( 'Akismet', 'added_option' ), 10, 2 );
997
998 @@ -131,12 +145,23 @@ class Akismet {
999 }
1000
1001 public static function rest_auto_check_comment( $commentdata ) {
1002 - self::$is_rest_api_call = true;
1003 -
1004 - return self::auto_check_comment( $commentdata );
1005 + return self::auto_check_comment( $commentdata, 'rest_api' );
1006 }
1007
1008 - public static function auto_check_comment( $commentdata ) {
1009 + /**
1010 + * Check a comment for spam.
1011 + *
1012 + * @param array $commentdata
1013 + * @param string $context What kind of request triggered this comment check? Possible values are 'default', 'rest_api', and 'xml-rpc'.
1014 + * @return array|WP_Error Either the $commentdata array with additional entries related to its spam status
1015 + * or a WP_Error, if it's a REST API request and the comment should be discarded.
1016 + */
1017 + public static function auto_check_comment( $commentdata, $context = 'default' ) {
1018 + // If no key is configured, then there's no point in doing any of this.
1019 + if ( ! self::get_api_key() ) {
1020 + return $commentdata;
1021 + }
1022 +
1023 self::$last_comment_result = null;
1024
1025 $comment = $commentdata;
1026 @@ -202,7 +227,15 @@ class Akismet {
1027 do_action( 'akismet_comment_check_response', $response );
1028
1029 $commentdata['comment_as_submitted'] = array_intersect_key( $comment, self::$comment_as_submitted_allowed_keys );
1030 - $commentdata['akismet_result'] = $response[1];
1031 +
1032 + // Also include any form fields we inject into the comment form, like ak_js
1033 + foreach ( $_POST as $key => $value ) {
1034 + if ( is_string( $value ) && strpos( $key, 'ak_' ) === 0 ) {
1035 + $commentdata['comment_as_submitted'][ 'POST_' . $key ] = $value;
1036 + }
1037 + }
1038 +
1039 + $commentdata['akismet_result'] = $response[1];
1040
1041 if ( isset( $response[0]['x-akismet-pro-tip'] ) )
1042 $commentdata['akismet_pro_tip'] = $response[0]['x-akismet-pro-tip'];
1043 @@ -227,17 +260,19 @@ class Akismet {
1044 update_option( 'akismet_spam_count', get_option( 'akismet_spam_count' ) + $incr );
1045 }
1046
1047 - if ( self::$is_rest_api_call ) {
1048 + if ( 'rest_api' === $context ) {
1049 return new WP_Error( 'akismet_rest_comment_discarded', __( 'Comment discarded.', 'akismet' ) );
1050 - }
1051 - else {
1052 + } else if ( 'xml-rpc' === $context ) {
1053 + // If this is a pingback that we're pre-checking, the discard behavior is the same as the normal spam response behavior.
1054 + return $commentdata;
1055 + } else {
1056 // Redirect back to the previous page, or failing that, the post permalink, or failing that, the homepage of the blog.
1057 $redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : ( $post ? get_permalink( $post ) : home_url() );
1058 wp_safe_redirect( esc_url_raw( $redirect_to ) );
1059 die();
1060 }
1061 }
1062 - else if ( self::$is_rest_api_call ) {
1063 + else if ( 'rest_api' === $context ) {
1064 // The way the REST API structures its calls, we can set the comment_approved value right away.
1065 $commentdata['comment_approved'] = 'spam';
1066 }
1067 @@ -296,48 +331,56 @@ class Akismet {
1068 // as was checked by auto_check_comment
1069 if ( is_object( $comment ) && !empty( self::$last_comment ) && is_array( self::$last_comment ) ) {
1070 if ( self::matches_last_comment( $comment ) ) {
1071 -
1072 - load_plugin_textdomain( 'akismet' );
1073 -
1074 - // normal result: true or false
1075 - if ( self::$last_comment['akismet_result'] == 'true' ) {
1076 - update_comment_meta( $comment->comment_ID, 'akismet_result', 'true' );
1077 - self::update_comment_history( $comment->comment_ID, '', 'check-spam' );
1078 - if ( $comment->comment_approved != 'spam' )
1079 - self::update_comment_history(
1080 - $comment->comment_ID,
1081 - '',
1082 - 'status-changed-'.$comment->comment_approved
1083 - );
1084 - }
1085 - elseif ( self::$last_comment['akismet_result'] == 'false' ) {
1086 - update_comment_meta( $comment->comment_ID, 'akismet_result', 'false' );
1087 - self::update_comment_history( $comment->comment_ID, '', 'check-ham' );
1088 - // Status could be spam or trash, depending on the WP version and whether this change applies:
1089 - // https://core.trac.wordpress.org/changeset/34726
1090 - if ( $comment->comment_approved == 'spam' || $comment->comment_approved == 'trash' ) {
1091 - if ( wp_blacklist_check($comment->comment_author, $comment->comment_author_email, $comment->comment_author_url, $comment->comment_content, $comment->comment_author_IP, $comment->comment_agent) )
1092 - self::update_comment_history( $comment->comment_ID, '', 'wp-blacklisted' );
1093 - else
1094 - self::update_comment_history( $comment->comment_ID, '', 'status-changed-'.$comment->comment_approved );
1095 - }
1096 - } // abnormal result: error
1097 - else {
1098 - update_comment_meta( $comment->comment_ID, 'akismet_error', time() );
1099 + load_plugin_textdomain( 'akismet' );
1100 +
1101 + // normal result: true or false
1102 + if ( self::$last_comment['akismet_result'] == 'true' ) {
1103 + update_comment_meta( $comment->comment_ID, 'akismet_result', 'true' );
1104 + self::update_comment_history( $comment->comment_ID, '', 'check-spam' );
1105 + if ( $comment->comment_approved != 'spam' ) {
1106 self::update_comment_history(
1107 $comment->comment_ID,
1108 '',
1109 - 'check-error',
1110 - array( 'response' => substr( self::$last_comment['akismet_result'], 0, 50 ) )
1111 + 'status-changed-' . $comment->comment_approved
1112 );
1113 }
1114 + } elseif ( self::$last_comment['akismet_result'] == 'false' ) {
1115 + update_comment_meta( $comment->comment_ID, 'akismet_result', 'false' );
1116 + self::update_comment_history( $comment->comment_ID, '', 'check-ham' );
1117 + // Status could be spam or trash, depending on the WP version and whether this change applies:
1118 + // https://core.trac.wordpress.org/changeset/34726
1119 + if ( $comment->comment_approved == 'spam' || $comment->comment_approved == 'trash' ) {
1120 + if ( function_exists( 'wp_check_comment_disallowed_list' ) ) {
1121 + if ( wp_check_comment_disallowed_list( $comment->comment_author, $comment->comment_author_email, $comment->comment_author_url, $comment->comment_content, $comment->comment_author_IP, $comment->comment_agent ) ) {
1122 + self::update_comment_history( $comment->comment_ID, '', 'wp-disallowed' );
1123 + } else {
1124 + self::update_comment_history( $comment->comment_ID, '', 'status-changed-' . $comment->comment_approved );
1125 + }
1126 + } else if ( function_exists( 'wp_blacklist_check' ) && wp_blacklist_check( $comment->comment_author, $comment->comment_author_email, $comment->comment_author_url, $comment->comment_content, $comment->comment_author_IP, $comment->comment_agent ) ) {
1127 + self::update_comment_history( $comment->comment_ID, '', 'wp-blacklisted' );
1128 + } else {
1129 + self::update_comment_history( $comment->comment_ID, '', 'status-changed-' . $comment->comment_approved );
1130 + }
1131 + }
1132 + } else {
1133 + // abnormal result: error
1134 + update_comment_meta( $comment->comment_ID, 'akismet_error', time() );
1135 + self::update_comment_history(
1136 + $comment->comment_ID,
1137 + '',
1138 + 'check-error',
1139 + array( 'response' => substr( self::$last_comment['akismet_result'], 0, 50 ) )
1140 + );
1141 + }
1142
1143 - // record the complete original data as submitted for checking
1144 - if ( isset( self::$last_comment['comment_as_submitted'] ) )
1145 - update_comment_meta( $comment->comment_ID, 'akismet_as_submitted', self::$last_comment['comment_as_submitted'] );
1146 + // record the complete original data as submitted for checking
1147 + if ( isset( self::$last_comment['comment_as_submitted'] ) ) {
1148 + update_comment_meta( $comment->comment_ID, 'akismet_as_submitted', self::$last_comment['comment_as_submitted'] );
1149 + }
1150
1151 - if ( isset( self::$last_comment['akismet_pro_tip'] ) )
1152 - update_comment_meta( $comment->comment_ID, 'akismet_pro_tip', self::$last_comment['akismet_pro_tip'] );
1153 + if ( isset( self::$last_comment['akismet_pro_tip'] ) ) {
1154 + update_comment_meta( $comment->comment_ID, 'akismet_pro_tip', self::$last_comment['akismet_pro_tip'] );
1155 + }
1156 }
1157 }
1158 }
1159 @@ -380,6 +423,10 @@ class Akismet {
1160
1161 clean_comment_cache( $comment_ids );
1162 do_action( 'akismet_delete_comment_batch', count( $comment_ids ) );
1163 +
1164 + foreach ( $comment_ids as $comment_id ) {
1165 + do_action( 'deleted_comment', $comment_id );
1166 + }
1167 }
1168
1169 if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->comments ) ) // lucky number
1170 @@ -469,6 +516,44 @@ class Akismet {
1171 // get the full comment history for a given comment, as an array in reverse chronological order
1172 public static function get_comment_history( $comment_id ) {
1173 $history = get_comment_meta( $comment_id, 'akismet_history', false );
1174 + if ( empty( $history ) || empty( $history[ 0 ] ) ) {
1175 + return false;
1176 + }
1177 +
1178 + /*
1179 + // To see all variants when testing.
1180 + $history[] = array( 'time' => 445856401, 'message' => 'Old versions of Akismet stored the message as a literal string in the commentmeta.', 'event' => null );
1181 + $history[] = array( 'time' => 445856402, 'event' => 'recheck-spam' );
1182 + $history[] = array( 'time' => 445856403, 'event' => 'check-spam' );
1183 + $history[] = array( 'time' => 445856404, 'event' => 'recheck-ham' );
1184 + $history[] = array( 'time' => 445856405, 'event' => 'check-ham' );
1185 + $history[] = array( 'time' => 445856406, 'event' => 'wp-blacklisted' );
1186 + $history[] = array( 'time' => 445856406, 'event' => 'wp-disallowed' );
1187 + $history[] = array( 'time' => 445856407, 'event' => 'report-spam' );
1188 + $history[] = array( 'time' => 445856408, 'event' => 'report-spam', 'user' => 'sam' );
1189 + $history[] = array( 'message' => 'sam reported this comment as spam (hardcoded message).', 'time' => 445856400, 'event' => 'report-spam', 'user' => 'sam' );
1190 + $history[] = array( 'time' => 445856409, 'event' => 'report-ham', 'user' => 'sam' );
1191 + $history[] = array( 'message' => 'sam reported this comment as ham (hardcoded message).', 'time' => 445856400, 'event' => 'report-ham', 'user' => 'sam' ); //
1192 + $history[] = array( 'time' => 445856410, 'event' => 'cron-retry-spam' );
1193 + $history[] = array( 'time' => 445856411, 'event' => 'cron-retry-ham' );
1194 + $history[] = array( 'time' => 445856412, 'event' => 'check-error' ); //
1195 + $history[] = array( 'time' => 445856413, 'event' => 'check-error', 'meta' => array( 'response' => 'The server was taking a nap.' ) );
1196 + $history[] = array( 'time' => 445856414, 'event' => 'recheck-error' ); // Should not generate a message.
1197 + $history[] = array( 'time' => 445856415, 'event' => 'recheck-error', 'meta' => array( 'response' => 'The server was taking a nap.' ) );
1198 + $history[] = array( 'time' => 445856416, 'event' => 'status-changedtrash' );
1199 + $history[] = array( 'time' => 445856417, 'event' => 'status-changedspam' );
1200 + $history[] = array( 'time' => 445856418, 'event' => 'status-changedhold' );
1201 + $history[] = array( 'time' => 445856419, 'event' => 'status-changedapprove' );
1202 + $history[] = array( 'time' => 445856420, 'event' => 'status-changed-trash' );
1203 + $history[] = array( 'time' => 445856421, 'event' => 'status-changed-spam' );
1204 + $history[] = array( 'time' => 445856422, 'event' => 'status-changed-hold' );
1205 + $history[] = array( 'time' => 445856423, 'event' => 'status-changed-approve' );
1206 + $history[] = array( 'time' => 445856424, 'event' => 'status-trash', 'user' => 'sam' );
1207 + $history[] = array( 'time' => 445856425, 'event' => 'status-spam', 'user' => 'sam' );
1208 + $history[] = array( 'time' => 445856426, 'event' => 'status-hold', 'user' => 'sam' );
1209 + $history[] = array( 'time' => 445856427, 'event' => 'status-approve', 'user' => 'sam' );
1210 + */
1211 +
1212 usort( $history, array( 'Akismet', '_cmp_time' ) );
1213 return $history;
1214 }
1215 @@ -506,6 +591,10 @@ class Akismet {
1216 public static function check_db_comment( $id, $recheck_reason = 'recheck_queue' ) {
1217 global $wpdb;
1218
1219 + if ( ! self::get_api_key() ) {
1220 + return new WP_Error( 'akismet-not-configured', __( 'Akismet is not configured. Please enter an API key.', 'akismet' ) );
1221 + }
1222 +
1223 $c = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->comments} WHERE comment_ID = %d", $id ), ARRAY_A );
1224
1225 if ( ! $c ) {
1226 @@ -653,6 +742,13 @@ class Akismet {
1227 if ( 'spam' != $comment->comment_approved )
1228 return;
1229
1230 + self::update_comment_history( $comment_id, '', 'report-spam' );
1231 +
1232 + // If the user hasn't configured Akismet, there's nothing else to do at this point.
1233 + if ( ! self::get_api_key() ) {
1234 + return;
1235 + }
1236 +
1237 // use the original version stored in comment_meta if available
1238 $as_submitted = self::sanitize_comment_as_submitted( get_comment_meta( $comment_id, 'akismet_as_submitted', true ) );
1239
1240 @@ -685,9 +781,10 @@ class Akismet {
1241 }
1242
1243 $response = Akismet::http_post( Akismet::build_query( $comment ), 'submit-spam' );
1244 +
1245 + update_comment_meta( $comment_id, 'akismet_user_result', 'true' );
1246 +
1247 if ( $comment->reporter ) {
1248 - self::update_comment_history( $comment_id, '', 'report-spam' );
1249 - update_comment_meta( $comment_id, 'akismet_user_result', 'true' );
1250 update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
1251 }
1252
1253 @@ -703,6 +800,13 @@ class Akismet {
1254 if ( !$comment ) // it was deleted
1255 return;
1256
1257 + self::update_comment_history( $comment_id, '', 'report-ham' );
1258 +
1259 + // If the user hasn't configured Akismet, there's nothing else to do at this point.
1260 + if ( ! self::get_api_key() ) {
1261 + return;
1262 + }
1263 +
1264 // use the original version stored in comment_meta if available
1265 $as_submitted = self::sanitize_comment_as_submitted( get_comment_meta( $comment_id, 'akismet_as_submitted', true ) );
1266
1267 @@ -735,9 +839,10 @@ class Akismet {
1268 }
1269
1270 $response = self::http_post( Akismet::build_query( $comment ), 'submit-ham' );
1271 +
1272 + update_comment_meta( $comment_id, 'akismet_user_result', 'false' );
1273 +
1274 if ( $comment->reporter ) {
1275 - self::update_comment_history( $comment_id, '', 'report-ham' );
1276 - update_comment_meta( $comment_id, 'akismet_user_result', 'false' );
1277 update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
1278 }
1279
1280 @@ -860,6 +965,11 @@ class Akismet {
1281 * has not been set and that Akismet should just choose the default behavior for that
1282 * situation.
1283 */
1284 +
1285 + if ( ! self::get_api_key() ) {
1286 + return;
1287 + }
1288 +
1289 $akismet_comment_nonce_option = apply_filters( 'akismet_comment_nonce', get_option( 'akismet_comment_nonce' ) );
1290
1291 if ( $akismet_comment_nonce_option == 'true' || $akismet_comment_nonce_option == '' ) {
1292 @@ -879,7 +989,7 @@ class Akismet {
1293 if ( is_user_logged_in() )
1294 return false;
1295
1296 - return ( get_option( 'akismet_strictness' ) === '1' );
1297 + return ( get_option( 'akismet_strictness' ) === '1' );
1298 }
1299
1300 public static function get_ip_address() {
1301 @@ -1029,10 +1139,12 @@ class Akismet {
1302 if ( ! empty( self::$prevent_moderation_email_for_these_comments ) && ! empty( $emails ) ) {
1303 $comment = get_comment( $comment_id );
1304
1305 - foreach ( self::$prevent_moderation_email_for_these_comments as $possible_match ) {
1306 - if ( self::comments_match( $possible_match, $comment ) ) {
1307 - update_comment_meta( $comment_id, 'akismet_delayed_moderation_email', true );
1308 - return array();
1309 + if ( $comment ) {
1310 + foreach ( self::$prevent_moderation_email_for_these_comments as $possible_match ) {
1311 + if ( self::comments_match( $possible_match, $comment ) ) {
1312 + update_comment_meta( $comment_id, 'akismet_delayed_moderation_email', true );
1313 + return array();
1314 + }
1315 }
1316 }
1317 }
1318 @@ -1163,51 +1275,106 @@ class Akismet {
1319
1320 // given a response from an API call like check_key_status(), update the alert code options if an alert is present.
1321 public static function update_alert( $response ) {
1322 - $code = $msg = null;
1323 - if ( isset( $response[0]['x-akismet-alert-code'] ) ) {
1324 - $code = $response[0]['x-akismet-alert-code'];
1325 - $msg = $response[0]['x-akismet-alert-msg'];
1326 - }
1327 + $alert_option_prefix = 'akismet_alert_';
1328 + $alert_header_prefix = 'x-akismet-alert-';
1329 + $alert_header_names = array(
1330 + 'code',
1331 + 'msg',
1332 + 'api-calls',
1333 + 'usage-limit',
1334 + 'upgrade-plan',
1335 + 'upgrade-url',
1336 + 'upgrade-type',
1337 + );
1338
1339 - // only call update_option() if the value has changed
1340 - if ( $code != get_option( 'akismet_alert_code' ) ) {
1341 - if ( ! $code ) {
1342 - delete_option( 'akismet_alert_code' );
1343 - delete_option( 'akismet_alert_msg' );
1344 + foreach ( $alert_header_names as $alert_header_name ) {
1345 + $value = null;
1346 + if ( isset( $response[0][ $alert_header_prefix . $alert_header_name ] ) ) {
1347 + $value = $response[0][ $alert_header_prefix . $alert_header_name ];
1348 }
1349 - else {
1350 - update_option( 'akismet_alert_code', $code );
1351 - update_option( 'akismet_alert_msg', $msg );
1352 +
1353 + $option_name = $alert_option_prefix . str_replace( '-', '_', $alert_header_name );
1354 + if ( $value != get_option( $option_name ) ) {
1355 + if ( ! $value ) {
1356 + delete_option( $option_name );
1357 + } else {
1358 + update_option( $option_name, $value );
1359 + }
1360 }
1361 }
1362 }
1363
1364 public static function load_form_js() {
1365 - if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
1366 - return;
1367 + /* deprecated */
1368 + }
1369 +
1370 + public static function set_form_js_async( $tag, $handle, $src ) {
1371 + /* deprecated */
1372 + return $tag;
1373 + }
1374 +
1375 + public static function get_akismet_form_fields() {
1376 + $fields = '';
1377 +
1378 + $prefix = 'ak_';
1379 +
1380 + // Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
1381 + if ( 'wpcf7_form_elements' === current_filter() ) {
1382 + $prefix = '_wpcf7_ak_';
1383 + }
1384 +
1385 + $fields .= '<p style="display: none !important;">';
1386 + $fields .= '<label>&#916;<textarea name="' . $prefix . 'hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label>';
1387 +
1388 + if ( ! function_exists( 'amp_is_request' ) || ! amp_is_request() ) {
1389 + $fields .= '<input type="hidden" id="ak_js" name="' . $prefix . 'js" value="' . mt_rand( 0, 250 ) . '"/>';
1390 + $fields .= '<script>document.getElementById( "ak_js" ).setAttribute( "value", ( new Date() ).getTime() );</script>';
1391 }
1392
1393 - wp_register_script( 'akismet-form', plugin_dir_url( __FILE__ ) . '_inc/form.js', array(), AKISMET_VERSION, true );
1394 - wp_enqueue_script( 'akismet-form' );
1395 + $fields .= '</p>';
1396 +
1397 + return $fields;
1398 }
1399 -
1400 +
1401 + public static function output_custom_form_fields( $post_id ) {
1402 + // phpcs:ignore WordPress.Security.EscapeOutput
1403 + echo self::get_akismet_form_fields();
1404 + }
1405 +
1406 + public static function inject_custom_form_fields( $html ) {
1407 + $html = str_replace( '</form>', self::get_akismet_form_fields() . '</form>', $html );
1408 +
1409 + return $html;
1410 + }
1411 +
1412 + public static function append_custom_form_fields( $html ) {
1413 + $html .= self::get_akismet_form_fields();
1414 +
1415 + return $html;
1416 + }
1417 +
1418 /**
1419 - * Mark form.js as async. Because nothing depends on it, it can run at any time
1420 - * after it's loaded, and the browser won't have to wait for it to load to continue
1421 - * parsing the rest of the page.
1422 + * Ensure that any Akismet-added form fields are included in the comment-check call.
1423 + *
1424 + * @param array $form
1425 + * @return array $form
1426 */
1427 - public static function set_form_js_async( $tag, $handle, $src ) {
1428 - if ( 'akismet-form' !== $handle ) {
1429 - return $tag;
1430 + public static function prepare_custom_form_values( $form ) {
1431 + $prefix = 'ak_';
1432 +
1433 + // Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
1434 + if ( 'wpcf7_akismet_parameters' === current_filter() ) {
1435 + $prefix = '_wpcf7_ak_';
1436 }
1437 -
1438 - return preg_replace( '/^<script /i', '<script async="async" ', $tag );
1439 - }
1440 -
1441 - public static function inject_ak_js( $fields ) {
1442 - echo '<p style="display: none;">';
1443 - echo '<input type="hidden" id="ak_js" name="ak_js" value="' . mt_rand( 0, 250 ) . '"/>';
1444 - echo '</p>';
1445 +
1446 + // phpcs:ignore WordPress.Security.NonceVerification.Missing
1447 + foreach ( $_POST as $key => $val ) {
1448 + if ( 0 === strpos( $key, $prefix ) ) {
1449 + $form[ 'POST_ak_' . substr( $key, strlen( $prefix ) ) ] = $val;
1450 + }
1451 + }
1452 +
1453 + return $form;
1454 }
1455
1456 private static function bail_on_activation( $message, $deactivate = true ) {
1457 @@ -1277,7 +1444,7 @@ p {
1458 $message = '<strong>'.sprintf(esc_html__( 'Akismet %s requires WordPress %s or higher.' , 'akismet'), AKISMET_VERSION, AKISMET__MINIMUM_WP_VERSION ).'</strong> '.sprintf(__('Please <a href="%1$s">upgrade WordPress</a> to a current version, or <a href="%2$s">downgrade to version 2.4 of the Akismet plugin</a>.', 'akismet'), 'https://codex.wordpress.org/Upgrading_WordPress', 'https://wordpress.org/extend/plugins/akismet/download/');
1459
1460 Akismet::bail_on_activation( $message );
1461 - } else {
1462 + } elseif ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], '/wp-admin/plugins.php' ) ) {
1463 add_option( 'Activated_Akismet', true );
1464 }
1465 }
1466 @@ -1333,16 +1500,98 @@ p {
1467 if ( $method !== 'pingback.ping' )
1468 return;
1469
1470 + // A lot of this code is tightly coupled with the IXR class because the xmlrpc_call action doesn't pass along any information besides the method name.
1471 + // This ticket should hopefully fix that: https://core.trac.wordpress.org/ticket/52524
1472 + // Until that happens, when it's a system.multicall, pre_check_pingback will be called once for every internal pingback call.
1473 + // Keep track of how many times this function has been called so we know which call to reference in the XML.
1474 + static $call_count = 0;
1475 +
1476 + $call_count++;
1477 +
1478 global $wp_xmlrpc_server;
1479 -
1480 +
1481 if ( !is_object( $wp_xmlrpc_server ) )
1482 return false;
1483 -
1484 - // Lame: tightly coupled with the IXR class.
1485 - $args = $wp_xmlrpc_server->message->params;
1486 -
1487 - if ( !empty( $args[1] ) ) {
1488 - $post_id = url_to_postid( $args[1] );
1489 +
1490 + $is_multicall = false;
1491 + $multicall_count = 0;
1492 +
1493 + if ( 'system.multicall' === $wp_xmlrpc_server->message->methodName ) {
1494 + $is_multicall = true;
1495 +
1496 + if ( 0 === $call_count ) {
1497 + // Only pass along the number of entries in the multicall the first time we see it.
1498 + $multicall_count = count( $wp_xmlrpc_server->message->params );
1499 + }
1500 +
1501 + /*
1502 + * $wp_xmlrpc_server->message looks like this:
1503 + *
1504 + (
1505 + [message] =>
1506 + [messageType] => methodCall
1507 + [faultCode] =>
1508 + [faultString] =>
1509 + [methodName] => system.multicall
1510 + [params] => Array
1511 + (
1512 + [0] => Array
1513 + (
1514 + [methodName] => pingback.ping
1515 + [params] => Array
1516 + (
1517 + [0] => http://www.example.net/?p=1 // Site that created the pingback.
1518 + [1] => https://www.example.com/?p=1 // Post being pingback'd on this site.
1519 + )
1520 + )
1521 + [1] => Array
1522 + (
1523 + [methodName] => pingback.ping
1524 + [params] => Array
1525 + (
1526 + [0] => http://www.example.net/?p=1 // Site that created the pingback.
1527 + [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
1528 + )
1529 + )
1530 + )
1531 + )
1532 + */
1533 +
1534 + // Use the params from the nth pingback.ping call in the multicall.
1535 + $pingback_calls_found = 0;
1536 +
1537 + foreach ( $wp_xmlrpc_server->message->params as $xmlrpc_action ) {
1538 + if ( 'pingback.ping' === $xmlrpc_action['methodName'] ) {
1539 + $pingback_calls_found++;
1540 + }
1541 +
1542 + if ( $call_count === $pingback_calls_found ) {
1543 + $pingback_args = $xmlrpc_action['params'];
1544 + break;
1545 + }
1546 + }
1547 + } else {
1548 + /*
1549 + * $wp_xmlrpc_server->message looks like this:
1550 + *
1551 + (
1552 + [message] =>
1553 + [messageType] => methodCall
1554 + [faultCode] =>
1555 + [faultString] =>
1556 + [methodName] => pingback.ping
1557 + [params] => Array
1558 + (
1559 + [0] => http://www.example.net/?p=1 // Site that created the pingback.
1560 + [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
1561 + )
1562 + )
1563 + */
1564 + $pingback_args = $wp_xmlrpc_server->message->params;
1565 + }
1566 +
1567 + if ( ! empty( $pingback_args[1] ) ) {
1568 + $post_id = url_to_postid( $pingback_args[1] );
1569
1570 // If pingbacks aren't open on this post, we'll still check whether this request is part of a potential DDOS,
1571 // but indicate to the server that pingbacks are indeed closed so we don't include this request in the user's stats,
1572 @@ -1355,23 +1604,30 @@ p {
1573 $pingbacks_closed = true;
1574 }
1575
1576 + // Note: If is_multicall is true and multicall_count=0, then we know this is at least the 2nd pingback we've processed in this multicall.
1577 +
1578 $comment = array(
1579 - 'comment_author_url' => $args[0],
1580 + 'comment_author_url' => $pingback_args[0],
1581 'comment_post_ID' => $post_id,
1582 'comment_author' => '',
1583 'comment_author_email' => '',
1584 'comment_content' => '',
1585 'comment_type' => 'pingback',
1586 'akismet_pre_check' => '1',
1587 - 'comment_pingback_target' => $args[1],
1588 + 'comment_pingback_target' => $pingback_args[1],
1589 'pingbacks_closed' => $pingbacks_closed ? '1' : '0',
1590 + 'is_multicall' => $is_multicall,
1591 + 'multicall_count' => $multicall_count,
1592 );
1593
1594 - $comment = Akismet::auto_check_comment( $comment );
1595 + $comment = self::auto_check_comment( $comment, 'xml-rpc' );
1596
1597 if ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) {
1598 - // Lame: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
1599 + // Sad: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
1600 $wp_xmlrpc_server->error( new IXR_Error( 0, 'Invalid discovery target' ) );
1601 +
1602 + // Also note that if this was part of a multicall, a spam result will prevent the subsequent calls from being executed.
1603 + // This is probably fine, but it raises the bar for what should be acceptable as a false positive.
1604 }
1605 }
1606 }
1607 @@ -1390,8 +1646,17 @@ p {
1608 $meta_value = (array) $meta_value;
1609
1610 foreach ( $meta_value as $key => $value ) {
1611 - if ( ! isset( self::$comment_as_submitted_allowed_keys[$key] ) || ! is_scalar( $value ) ) {
1612 - unset( $meta_value[$key] );
1613 + if ( ! is_scalar( $value ) ) {
1614 + unset( $meta_value[ $key ] );
1615 + } else {
1616 + // These can change, so they're not explicitly listed in comment_as_submitted_allowed_keys.
1617 + if ( strpos( $key, 'POST_ak_' ) === 0 ) {
1618 + continue;
1619 + }
1620 +
1621 + if ( ! isset( self::$comment_as_submitted_allowed_keys[ $key ] ) ) {
1622 + unset( $meta_value[ $key ] );
1623 + }
1624 }
1625 }
1626
1627
1628 diff --git a/plugins/akismet/readme.txt b/plugins/akismet/readme.txt
1629 index bf0081a9..0058c338 100644
1630 --- a/plugins/akismet/readme.txt
1631 +++ b/plugins/akismet/readme.txt
1632 @@ -1,12 +1,12 @@
1633 -=== Akismet Anti-Spam ===
1634 +=== Akismet Spam Protection ===
1635 Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
1636 -Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
1637 -Requires at least: 4.0
1638 -Tested up to: 5.3
1639 -Stable tag: 4.1.3
1640 +Tags: comments, spam, antispam, anti-spam, contact form, anti spam, comment moderation, comment spam, contact form spam, spam comments
1641 +Requires at least: 5.0
1642 +Tested up to: 5.8
1643 +Stable tag: 4.2.1
1644 License: GPLv2 or later
1645
1646 -Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
1647 +The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
1648
1649 == Description ==
1650
1651 @@ -30,445 +30,61 @@ Upload the Akismet plugin to your blog, activate it, and then enter your Akismet
1652
1653 == Changelog ==
1654
1655 -= 4.1.3 =
1656 -*Release Date - 31 October 2019*
1657 += 4.2.1 =
1658 +*Release Date - 1 October 2021*
1659
1660 -* Prevented an attacker from being able to cause a user to unknowingly recheck their Pending comments for spam.
1661 -* Improved compatibility with Jetpack 7.7+.
1662 -* Updated the plugin activation page to use consistent language and markup.
1663 -* Redirecting users to the Akismet connnection/settings screen upon plugin activation, in an effort to make it easier for people to get setup.
1664 +* Fixed a bug causing AMP validation to fail on certain pages with forms.
1665
1666 -= 4.1.2 =
1667 -*Release Date - 14 May 2019*
1668 += 4.2 =
1669 +*Release Date - 30 September 2021*
1670
1671 -* Fixed a conflict between the Akismet setup banner and other plugin notices.
1672 -* Reduced the number of API requests made by the plugin when attempting to verify the API key.
1673 -* Include additional data in the pingback pre-check API request to help make the stats more accurate.
1674 -* Fixed a bug that was enabling the "Check for Spam" button when no comments were eligible to be checked.
1675 -* Improved Akismet's AMP compatibility.
1676 +* Added links to additional information on API usage notifications.
1677 +* Reduced the number of network requests required for a comment page when running Akismet.
1678 +* Improved compatibility with the most popular contact form plugins.
1679 +* Improved API usage buttons for clarity on what upgrade is needed.
1680
1681 -= 4.1.1 =
1682 -*Release Date - 31 January 2019*
1683 += 4.1.12 =
1684 +*Release Date - 3 September 2021*
1685
1686 -* Fixed the "Setup Akismet" notice so it resizes responsively.
1687 -* Only highlight the "Save Changes" button in the Akismet config when changes have been made.
1688 -* The count of comments in your spam queue shown on the dashboard show now always be up-to-date.
1689 +* Fixed "Use of undefined constant" notice.
1690 +* Improved styling of alert notices.
1691
1692 -= 4.1 =
1693 -*Release Date - 12 November 2018*
1694 += 4.1.11 =
1695 +*Release Date - 23 August 2021*
1696
1697 -* Added a WP-CLI method for retrieving stats.
1698 -* Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
1699 -* Added functionality to clear outdated alerts from Akismet.com.
1700 -
1701 -= 4.0.8 =
1702 -*Release Date - 19 June 2018*
1703 -
1704 -* Improved the grammar and consistency of the in-admin privacy related notes (notice and config).
1705 -* Revised in-admin explanation of the comment form privacy notice to make its usage clearer.
1706 -* Added `rel="nofollow noopener"` to the comment form privacy notice to improve SEO and security.
1707 -
1708 -= 4.0.7 =
1709 -*Release Date - 28 May 2018*
1710 -
1711 -* Based on user feedback, the link on "Learn how your comment data is processed." in the optional privacy notice now has a `target` of `_blank` and opens in a new tab/window.
1712 -* Updated the in-admin privacy notice to use the term "comment" instead of "contact" in "Akismet can display a notice to your users under your comment forms."
1713 -* Only show in-admin privacy notice if Akismet has an API Key configured
1714 -
1715 -= 4.0.6 =
1716 -*Release Date - 26 May 2018*
1717 -
1718 -* Moved away from using `empty( get_option() )` to instantiating a variable to be compatible with older versions of PHP (5.3, 5.4, etc).
1719 -
1720 -= 4.0.5 =
1721 -*Release Date - 26 May 2018*
1722 -
1723 -* Corrected version number after tagging. Sorry...
1724 -
1725 -= 4.0.4 =
1726 -*Release Date - 26 May 2018*
1727 -
1728 -* Added a hook to provide Akismet-specific privacy information for a site's privacy policy.
1729 -* Added tools to control the display of a privacy related notice under comment forms.
1730 -* Fixed HTML in activation failure message to close META and HEAD tag properly.
1731 -* Fixed a bug that would sometimes prevent Akismet from being correctly auto-configured.
1732 -
1733 -= 4.0.3 =
1734 -*Release Date - 19 February 2018*
1735 -
1736 -* Added a scheduled task to remove entries in wp_commentmeta that no longer have corresponding comments in wp_comments.
1737 -* Added a new `akismet_batch_delete_count` action to the batch delete methods for people who'd like to keep track of the numbers of records being processed by those methods.
1738 -
1739 -= 4.0.2 =
1740 -*Release Date - 18 December 2017*
1741 -
1742 -* Fixed a bug that could cause Akismet to recheck a comment that has already been manually approved or marked as spam.
1743 -* Fixed a bug that could cause Akismet to claim that some comments are still waiting to be checked when no comments are waiting to be checked.
1744 -
1745 -= 4.0.1 =
1746 -*Release Date - 6 November 2017*
1747 -
1748 -* Fixed a bug that could prevent some users from connecting Akismet via their Jetpack connection.
1749 -* Ensured that any pending Akismet-related events are unscheduled if the plugin is deactivated.
1750 -* Allow some JavaScript to be run asynchronously to avoid affecting page render speeds.
1751 -
1752 -= 4.0 =
1753 -*Release Date - 19 September 2017*
1754 -
1755 -* Added REST API endpoints for configuring Akismet and retrieving stats.
1756 -* Increased the minimum supported WordPress version to 4.0.
1757 -* Added compatibility with comments submitted via the REST API.
1758 -* Improved the progress indicator on the "Check for Spam" button.
1759 -
1760 -= 3.3.4 =
1761 -*Release Date - 3 August 2017*
1762 -
1763 -* Disabled Akismet's debug log output by default unless AKISMET_DEBUG is defined.
1764 -* URL previews now begin preloading when the mouse moves near them in the comments section of wp-admin.
1765 -* When a comment is caught by the Comment Blacklist, Akismet will always allow it to stay in the trash even if it is spam as well.
1766 -* Fixed a bug that was preventing an error from being shown when a site can't reach Akismet's servers.
1767 -
1768 -= 3.3.3 =
1769 -*Release Date - 13 July 2017*
1770 -
1771 -* Reduced amount of bandwidth used by the URL Preview feature.
1772 -* Improved the admin UI when the API key is manually pre-defined for the site.
1773 -* Removed a workaround for WordPress installations older than 3.3 that will improve Akismet's compatibility with other plugins.
1774 -* The number of spam blocked that is displayed on the WordPress dashboard will now be more accurate and updated more frequently.
1775 -* Fixed a bug in the Akismet widget that could cause PHP warnings.
1776 -
1777 -= 3.3.2 =
1778 -*Release Date - 10 May 2017*
1779 -
1780 -* Fixed a bug causing JavaScript errors in some browsers.
1781 +* Added support for Akismet API usage notifications on Akismet settings and edit-comments admin pages.
1782 +* Added support for the deleted_comment action when bulk-deleting comments from Spam.
1783
1784 -= 3.3.1 =
1785 -*Release Date - 2 May 2017*
1786 -
1787 -* Improve performance by only requesting the akismet_comment_nonce option when absolutely necessary.
1788 -* Fixed two bugs that could cause PHP warnings.
1789 -* Fixed a bug that was preventing the "Remove author URL" feature from working after a comment was edited using "Quick Edit."
1790 -* Fixed a bug that was preventing the URL preview feature from working after a comment was edited using "Quick Edit."
1791 -
1792 -= 3.3 =
1793 -*Release Date - 23 February 2017*
1794 -
1795 -* Updated the Akismet admin pages with a new clean design.
1796 -* Fixed bugs preventing the `akismet_add_comment_nonce` and `akismet_update_alert` wrapper functions from working properly.
1797 -* Fixed bug preventing the loading indicator from appearing when re-checking all comments for spam.
1798 -* Added a progress indicator to the "Check for Spam" button.
1799 -* Added a success message after manually rechecking the Pending queue for spam.
1800 -
1801 -= 3.2 =
1802 -*Release Date - 6 September 2016*
1803 -
1804 -* Added a WP-CLI module. You can now check comments and recheck the moderation queue from the command line.
1805 -* Stopped using the deprecated jQuery function `.live()`.
1806 -* Fixed a bug in `remove_comment_author_url()` and `add_comment_author_url()` that could generate PHP notices.
1807 -* Fixed a bug that could cause an infinite loop for sites with very very very large comment IDs.
1808 -* Fixed a bug that could cause the Akismet widget title to be blank.
1809 -
1810 -= 3.1.11 =
1811 -*Release Date - 12 May 2016*
1812 -
1813 -* Fixed a bug that could cause the "Check for Spam" button to skip some comments.
1814 -* Fixed a bug that could prevent some spam submissions from being sent to Akismet.
1815 -* Updated all links to use https:// when possible.
1816 -* Disabled Akismet debug logging unless WP_DEBUG and WP_DEBUG_LOG are both enabled.
1817 -
1818 -= 3.1.10 =
1819 -*Release Date - 1 April 2016*
1820 -
1821 -* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
1822 -* Fixed a bug that could have resulted in comments that were caught by the core WordPress comment blacklist not to have a corresponding History entry.
1823 -* Fixed a bug that could have caused avoidable PHP warnings in the error log.
1824 -
1825 -= 3.1.9 =
1826 -*Release Date - 28 March 2016*
1827 -
1828 -* Add compatibility with Jetpack so that Jetpack can automatically configure Akismet settings when appropriate.
1829 -* Fixed a bug preventing some comment data from being sent to Akismet.
1830 -
1831 -= 3.1.8 =
1832 -*Release Date - 4 March 2016*
1833 -
1834 -* Fixed a bug preventing Akismet from being used with some plugins that rewrite admin URLs.
1835 -* Reduced the amount of bandwidth used on Akismet API calls
1836 -* Reduced the amount of space Akismet uses in the database
1837 -* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
1838 -
1839 -= 3.1.7 =
1840 -*Release Date - 4 January 2016*
1841 -
1842 -* Added documentation for the 'akismet_comment_nonce' filter.
1843 -* The post-install activation button is now accessible to screen readers and keyboard-only users.
1844 -* Fixed a bug that was preventing the "Remove author URL" feature from working in WordPress 4.4
1845 -
1846 -= 3.1.6 =
1847 -*Release Date - 14 December 2015*
1848 -
1849 -* Improve the notices shown after activating Akismet.
1850 -* Update some strings to allow for the proper plural forms in all languages.
1851 -
1852 -= 3.1.5 =
1853 -*Release Date - 13 October 2015*
1854 -
1855 -* Closes a potential XSS vulnerability.
1856 -
1857 -= 3.1.4 =
1858 -*Release Date - 24 September 2015*
1859 -
1860 -* Fixed a bug that was preventing some users from automatically connecting using Jetpack if they didn't have a current Akismet subscription.
1861 -* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
1862 -* Error messages and instructions have been simplified to be more understandable.
1863 -* Link previews are enabled for all links inside comments, not just the author's website link.
1864 -
1865 -= 3.1.3 =
1866 -*Release Date - 6 July 2015*
1867 -
1868 -* Notify users when their account status changes after previously being successfully set up. This should help any users who are seeing blank Akismet settings screens.
1869 -
1870 -= 3.1.2 =
1871 -*Release Date - 7 June 2015*
1872 -
1873 -* Reduced the amount of space Akismet uses in the commentmeta table.
1874 -* Fixed a bug where some comments with quotes in the author name weren't getting history entries
1875 -* Pre-emptive security improvements to ensure that the Akismet plugin can't be used by attackers to compromise a WordPress installation.
1876 -* Better UI for the key entry field: allow whitespace to be included at the beginning or end of the key and strip it out automatically when the form is submitted.
1877 -* When deactivating the plugin, notify the Akismet API so the site can be marked as inactive.
1878 -* Clearer error messages.
1879 -
1880 -= 3.1.1 =
1881 -*Release Date - 17th March, 2015*
1882 -
1883 -* Improvements to the "Remove comment author URL" JavaScript
1884 -* Include the pingback pre-check from the 2.6 branch.
1885 -
1886 -= 3.1 =
1887 -*Release Date - 11th March, 2015*
1888 -
1889 -* Use HTTPS by default for all requests to Akismet.
1890 -* Fix for a situation where Akismet might strip HTML from a comment.
1891 -
1892 -= 3.0.4 =
1893 -*Release Date - 11th December, 2014*
1894 -
1895 -* Fix to make .htaccess compatible with Apache 2.4.
1896 -* Fix to allow removal of https author URLs.
1897 -* Fix to avoid stripping part of the author URL when removing and re-adding.
1898 -* Removed the "Check for Spam" button from the "Trash" and "Approved" queues, where it would have no effect.
1899 -* Allow automatic API key configuration when Jetpack is installed and connected to a WordPress.com account
1900 -
1901 -= 3.0.3 =
1902 -*Release Date - 3rd November, 2014*
1903 -
1904 -* Fix for sending the wrong data to delete_comment action that could have prevented old spam comments from being deleted.
1905 -* Added a filter to disable logging of Akismet debugging information.
1906 -* Added a filter for the maximum comment age when deleting old spam comments.
1907 -* Added a filter for the number per batch when deleting old spam comments.
1908 -* Removed the "Check for Spam" button from the Spam folder.
1909 -
1910 -= 3.0.2 =
1911 -*Release Date - 18th August, 2014*
1912 -
1913 -* Performance improvements.
1914 -* Fixed a bug that could truncate the comment data being sent to Akismet for checking.
1915 -
1916 -= 3.0.1 =
1917 -*Release Date - 9th July, 2014*
1918 -
1919 -* Removed dependency on PHP's fsockopen function
1920 -* Fix spam/ham reports to work when reported outside of the WP dashboard, e.g., from Notifications or the WP app
1921 -* Remove jQuery dependency for comment form JavaScript
1922 -* Remove unnecessary data from some Akismet comment meta
1923 -* Suspended keys will now result in all comments being put in moderation, not spam.
1924 -
1925 -= 3.0.0 =
1926 -*Release Date - 15th April, 2014*
1927 -
1928 -* Move Akismet to Settings menu
1929 -* Drop Akismet Stats menu
1930 -* Add stats snapshot to Akismet settings
1931 -* Add Akismet subscription details and status to Akismet settings
1932 -* Add contextual help for each page
1933 -* Improve Akismet setup to use Jetpack to automate plugin setup
1934 -* Fix "Check for Spam" to use AJAX to avoid page timing out
1935 -* Fix Akismet settings page to be responsive
1936 -* Drop legacy code
1937 -* Tidy up CSS and Javascript
1938 -* Replace the old discard setting with a new "discard pervasive spam" feature.
1939 -
1940 -= 2.6.0 =
1941 -*Release Date - 18th March, 2014*
1942 -
1943 -* Add ajax paging to the check for spam button to handle large volumes of comments
1944 -* Optimize javascript and add localization support
1945 -* Fix bug in link to spam comments from right now dashboard widget
1946 -* Fix bug with deleting old comments to avoid timeouts dealing with large volumes of comments
1947 -* Include X-Pingback-Forwarded-For header in outbound WordPress pingback verifications
1948 -* Add pre-check for pingbacks, to stop spam before an outbound verification request is made
1949 -
1950 -= 2.5.9 =
1951 -*Release Date - 1st August, 2013*
1952 -
1953 -* Update 'Already have a key' link to redirect page rather than depend on javascript
1954 -* Fix some non-translatable strings to be translatable
1955 -* Update Activation banner in plugins page to redirect user to Akismet config page
1956 -
1957 -= 2.5.8 =
1958 -*Release Date - 20th January, 2013*
1959 -
1960 -* Simplify the activation process for new users
1961 -* Remove the reporter_ip parameter
1962 -* Minor preventative security improvements
1963 -
1964 -= 2.5.7 =
1965 -*Release Date - 13th December, 2012*
1966 -
1967 -* FireFox Stats iframe preview bug
1968 -* Fix mshots preview when using https
1969 -* Add .htaccess to block direct access to files
1970 -* Prevent some PHP notices
1971 -* Fix Check For Spam return location when referrer is empty
1972 -* Fix Settings links for network admins
1973 -* Fix prepare() warnings in WP 3.5
1974 -
1975 -= 2.5.6 =
1976 -*Release Date - 26th April, 2012*
1977 -
1978 -* Prevent retry scheduling problems on sites where wp_cron is misbehaving
1979 -* Preload mshot previews
1980 -* Modernize the widget code
1981 -* Fix a bug where comments were not held for moderation during an error condition
1982 -* Improve the UX and display when comments are temporarily held due to an error
1983 -* Make the Check For Spam button force a retry when comments are held due to an error
1984 -* Handle errors caused by an invalid key
1985 -* Don't retry comments that are too old
1986 -* Improve error messages when verifying an API key
1987 -
1988 -= 2.5.5 =
1989 -*Release Date - 11th January, 2012*
1990 -
1991 -* Add nonce check for comment author URL remove action
1992 -* Fix the settings link
1993 -
1994 -= 2.5.4 =
1995 -*Release Date - 5th January, 2012*
1996 -
1997 -* Limit Akismet CSS and Javascript loading in wp-admin to just the pages that need it
1998 -* Added author URL quick removal functionality
1999 -* Added mShot preview on Author URL hover
2000 -* Added empty index.php to prevent directory listing
2001 -* Move wp-admin menu items under Jetpack, if it is installed
2002 -* Purge old Akismet comment meta data, default of 15 days
2003 -
2004 -= 2.5.3 =
2005 -*Release Date - 8th Febuary, 2011*
2006 -
2007 -* Specify the license is GPL v2 or later
2008 -* Fix a bug that could result in orphaned commentmeta entries
2009 -* Include hotfix for WordPress 3.0.5 filter issue
2010 -
2011 -= 2.5.2 =
2012 -*Release Date - 14th January, 2011*
2013 -
2014 -* Properly format the comment count for author counts
2015 -* Look for super admins on multisite installs when looking up user roles
2016 -* Increase the HTTP request timeout
2017 -* Removed padding for author approved count
2018 -* Fix typo in function name
2019 -* Set Akismet stats iframe height to fixed 2500px. Better to have one tall scroll bar than two side by side.
2020 -
2021 -= 2.5.1 =
2022 -*Release Date - 17th December, 2010*
2023 -
2024 -* Fix a bug that caused the "Auto delete" option to fail to discard comments correctly
2025 -* Remove the comment nonce form field from the 'Akismet Configuration' page in favor of using a filter, akismet_comment_nonce
2026 -* Fixed padding bug in "author" column of posts screen
2027 -* Added margin-top to "cleared by ..." badges on dashboard
2028 -* Fix possible error when calling akismet_cron_recheck()
2029 -* Fix more PHP warnings
2030 -* Clean up XHTML warnings for comment nonce
2031 -* Fix for possible condition where scheduled comment re-checks could get stuck
2032 -* Clean up the comment meta details after deleting a comment
2033 -* Only show the status badge if the comment status has been changed by someone/something other than Akismet
2034 -* Show a 'History' link in the row-actions
2035 -* Translation fixes
2036 -* Reduced font-size on author name
2037 -* Moved "flagged by..." notification to top right corner of comment container and removed heavy styling
2038 -* Hid "flagged by..." notification while on dashboard
2039 -
2040 -= 2.5.0 =
2041 -*Release Date - 7th December, 2010*
2042 -
2043 -* Track comment actions under 'Akismet Status' on the edit comment screen
2044 -* Fix a few remaining deprecated function calls ( props Mike Glendinning )
2045 -* Use HTTPS for the stats IFRAME when wp-admin is using HTTPS
2046 -* Use the WordPress HTTP class if available
2047 -* Move the admin UI code to a separate file, only loaded when needed
2048 -* Add cron retry feature, to replace the old connectivity check
2049 -* Display Akismet status badge beside each comment
2050 -* Record history for each comment, and display it on the edit page
2051 -* Record the complete comment as originally submitted in comment_meta, to use when reporting spam and ham
2052 -* Highlight links in comment content
2053 -* New option, "Show the number of comments you've approved beside each comment author."
2054 -* New option, "Use a nonce on the comment form."
2055 -
2056 -= 2.4.0 =
2057 -*Release Date - 23rd August, 2010*
2058 -
2059 -* Spell out that the license is GPLv2
2060 -* Fix PHP warnings
2061 -* Fix WordPress deprecated function calls
2062 -* Fire the delete_comment action when deleting comments
2063 -* Move code specific for older WP versions to legacy.php
2064 -* General code clean up
2065 -
2066 -= 2.3.0 =
2067 -*Release Date - 5th June, 2010*
2068 -
2069 -* Fix "Are you sure" nonce message on config screen in WPMU
2070 -* Fix XHTML compliance issue in sidebar widget
2071 -* Change author link; remove some old references to WordPress.com accounts
2072 -* Localize the widget title (core ticket #13879)
2073 -
2074 -= 2.2.9 =
2075 -*Release Date - 2nd June, 2010*
2076 -
2077 -* Eliminate a potential conflict with some plugins that may cause spurious reports
2078 += 4.1.10 =
2079 +*Release Date - 6 July 2021*
2080
2081 -= 2.2.8 =
2082 -*Release Date - 27th May, 2010*
2083 +* Simplified the code around checking comments in REST API and XML-RPC requests.
2084 +* Updated Plus plan terminology in notices to match current subscription names.
2085 +* Added `rel="noopener"` to the widget link to avoid warnings in Google Lighthouse.
2086 +* Set the Akismet JavaScript as deferred instead of async to improve responsiveness.
2087 +* Improved the preloading of screenshot popups on the edit comments admin page.
2088
2089 -* Fix bug in initial comment check for ipv6 addresses
2090 -* Report comments as ham when they are moved from spam to moderation
2091 -* Report comments as ham when clicking undo after spam
2092 -* Use transition_comment_status action when available instead of older actions for spam/ham submissions
2093 -* Better diagnostic messages when PHP network functions are unavailable
2094 -* Better handling of comments by logged-in users
2095 += 4.1.9 =
2096 +*Release Date - 2 March 2021*
2097
2098 -= 2.2.7 =
2099 -*Release Date - 17th December, 2009*
2100 +* Improved handling of pingbacks in XML-RPC multicalls
2101
2102 -* Add a new AKISMET_VERSION constant
2103 -* Reduce the possibility of over-counting spam when another spam filter plugin is in use
2104 -* Disable the connectivity check when the API key is hard-coded for WPMU
2105 += 4.1.8 =
2106 +*Release Date - 6 January 2021*
2107
2108 -= 2.2.6 =
2109 -*Release Date - 20th July, 2009*
2110 +* Fixed missing fields in submit-spam and submit-ham calls that could lead to reduced accuracy.
2111 +* Fixed usage of deprecated jQuery function.
2112
2113 -* Fix a global warning introduced in 2.2.5
2114 -* Add changelog and additional readme.txt tags
2115 -* Fix an array conversion warning in some versions of PHP
2116 -* Support a new WPCOM_API_KEY constant for easier use with WordPress MU
2117 += 4.1.7 =
2118 +*Release Date - 22 October 2020*
2119
2120 -= 2.2.5 =
2121 -*Release Date - 13th July, 2009*
2122 +* Show the "Set up your Akismet account" banner on the comments admin screen, where it's relevant to mention if Akismet hasn't been configured.
2123 +* Don't use wp_blacklist_check when the new wp_check_comment_disallowed_list function is available.
2124
2125 -* Include a new Server Connectivity diagnostic check, to detect problems caused by firewalls
2126 += 4.1.6 =
2127 +*Release Date - 4 June 2020*
2128
2129 -= 2.2.4 =
2130 -*Release Date - 3rd June, 2009*
2131 +* Disable "Check for Spam" button until the page is loaded to avoid errors with clicking through to queue recheck endpoint directly.
2132 +* Add filter "akismet_enable_mshots" to allow disabling screenshot popups on the edit comments admin page.
2133
2134 -* Fixed a key problem affecting the stats feature in WordPress MU
2135 -* Provide additional blog information in Akismet API calls
2136 +For older changelog entries, please see the [additional changelog.txt file](https://plugins.svn.wordpress.org/akismet/trunk/changelog.txt) delivered with the plugin.
2137
2138 diff --git a/plugins/akismet/views/config.php b/plugins/akismet/views/config.php
2139 index 6bbcd6d4..df24b91d 100644
2140 --- a/plugins/akismet/views/config.php
2141 +++ b/plugins/akismet/views/config.php
2142 @@ -1,3 +1,9 @@
2143 +<?php
2144 +
2145 +//phpcs:disable VariableAnalysis
2146 +// There are "undefined" variables here because they're defined in the code that includes this file as a template.
2147 +
2148 +?>
2149 <div id="akismet-plugin-container">
2150 <div class="akismet-masthead">
2151 <div class="akismet-masthead__inside-container">
2152 @@ -53,7 +59,7 @@
2153 </div>
2154 <?php endif;?>
2155
2156 - <?php if ( $akismet_user ):?>
2157 + <?php if ( $akismet_user ) : ?>
2158 <div class="akismet-card">
2159 <div class="akismet-section-header">
2160 <div class="akismet-section-header__label">
2161
2162 diff --git a/plugins/akismet/views/enter.php b/plugins/akismet/views/enter.php
2163 index 0a79ca97..23dda40a 100644
2164 --- a/plugins/akismet/views/enter.php
2165 +++ b/plugins/akismet/views/enter.php
2166 @@ -1,5 +1,5 @@
2167 <div class="akismet-enter-api-key-box centered">
2168 - <a href="#"><?php esc_html_e( 'Manually enter an API key' ); ?></a>
2169 + <a href="#"><?php esc_html_e( 'Manually enter an API key', 'akismet' ); ?></a>
2170 <div class="enter-api-key">
2171 <form action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="post">
2172 <?php wp_nonce_field( Akismet_Admin::NONCE ) ?>
2173
2174 diff --git a/plugins/akismet/views/notice.php b/plugins/akismet/views/notice.php
2175 index fa098b8b..28dc6722 100644
2176 --- a/plugins/akismet/views/notice.php
2177 +++ b/plugins/akismet/views/notice.php
2178 @@ -4,7 +4,7 @@
2179 // There are "undefined" variables here because they're defined in the code that includes this file as a template.
2180
2181 ?>
2182 -<?php if ( $type == 'plugin' ) :?>
2183 +<?php if ( $type == 'plugin' ) : ?>
2184 <div class="updated" id="akismet_setup_prompt">
2185 <form name="akismet_activate" action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="POST">
2186 <div class="akismet_activate">
2187 @@ -18,7 +18,7 @@
2188 </div>
2189 </form>
2190 </div>
2191 -<?php elseif ( $type == 'spam-check' ) :?>
2192 +<?php elseif ( $type == 'spam-check' ) : ?>
2193 <div class="notice notice-warning">
2194 <p><strong><?php esc_html_e( 'Akismet has detected a problem.', 'akismet' );?></strong></p>
2195 <p><?php esc_html_e( 'Some comments have not yet been checked for spam by Akismet. They have been temporarily held for moderation and will automatically be rechecked later.', 'akismet' ); ?></p>
2196 @@ -26,7 +26,7 @@
2197 <p><?php echo $link_text; ?></p>
2198 <?php } ?>
2199 </div>
2200 -<?php elseif ( $type == 'alert' ) :?>
2201 +<?php elseif ( $type == 'alert' ) : ?>
2202 <div class='error'>
2203 <p><strong><?php printf( esc_html__( 'Akismet Error Code: %s', 'akismet' ), $code ); ?></strong></p>
2204 <p><?php echo esc_html( $msg ); ?></p>
2205 @@ -38,49 +38,49 @@
2206 ?>
2207 </p>
2208 </div>
2209 -<?php elseif ( $type == 'notice' ) :?>
2210 +<?php elseif ( $type == 'notice' ) : ?>
2211 <div class="akismet-alert akismet-critical">
2212 <h3 class="akismet-key-status failed"><?php echo $notice_header; ?></h3>
2213 <p class="akismet-description">
2214 <?php echo $notice_text; ?>
2215 </p>
2216 </div>
2217 -<?php elseif ( $type == 'missing-functions' ) :?>
2218 +<?php elseif ( $type == 'missing-functions' ) : ?>
2219 <div class="akismet-alert akismet-critical">
2220 <h3 class="akismet-key-status failed"><?php esc_html_e('Network functions are disabled.', 'akismet'); ?></h3>
2221 <p class="akismet-description"><?php printf( __('Your web host or server administrator has disabled PHP&#8217;s <code>gethostbynamel</code> function. <strong>Akismet cannot work correctly until this is fixed.</strong> Please contact your web host or firewall administrator and give them <a href="%s" target="_blank">this information about Akismet&#8217;s system requirements</a>.', 'akismet'), 'https://blog.akismet.com/akismet-hosting-faq/'); ?></p>
2222 </div>
2223 -<?php elseif ( $type == 'servers-be-down' ) :?>
2224 +<?php elseif ( $type == 'servers-be-down' ) : ?>
2225 <div class="akismet-alert akismet-critical">
2226 <h3 class="akismet-key-status failed"><?php esc_html_e("Your site can&#8217;t connect to the Akismet servers.", 'akismet'); ?></h3>
2227 <p class="akismet-description"><?php printf( __('Your firewall may be blocking Akismet from connecting to its API. Please contact your host and refer to <a href="%s" target="_blank">our guide about firewalls</a>.', 'akismet'), 'https://blog.akismet.com/akismet-hosting-faq/'); ?></p>
2228 </div>
2229 -<?php elseif ( $type == 'active-dunning' ) :?>
2230 +<?php elseif ( $type == 'active-dunning' ) : ?>
2231 <div class="akismet-alert akismet-critical">
2232 <h3 class="akismet-key-status"><?php esc_html_e("Please update your payment information.", 'akismet'); ?></h3>
2233 <p class="akismet-description"><?php printf( __('We cannot process your payment. Please <a href="%s" target="_blank">update your payment details</a>.', 'akismet'), 'https://akismet.com/account/'); ?></p>
2234 </div>
2235 -<?php elseif ( $type == 'cancelled' ) :?>
2236 +<?php elseif ( $type == 'cancelled' ) : ?>
2237 <div class="akismet-alert akismet-critical">
2238 <h3 class="akismet-key-status"><?php esc_html_e("Your Akismet plan has been cancelled.", 'akismet'); ?></h3>
2239 <p class="akismet-description"><?php printf( __('Please visit your <a href="%s" target="_blank">Akismet account page</a> to reactivate your subscription.', 'akismet'), 'https://akismet.com/account/'); ?></p>
2240 </div>
2241 -<?php elseif ( $type == 'suspended' ) :?>
2242 +<?php elseif ( $type == 'suspended' ) : ?>
2243 <div class="akismet-alert akismet-critical">
2244 <h3 class="akismet-key-status failed"><?php esc_html_e("Your Akismet subscription is suspended.", 'akismet'); ?></h3>
2245 <p class="akismet-description"><?php printf( __('Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet'), 'https://akismet.com/contact/'); ?></p>
2246 </div>
2247 -<?php elseif ( $type == 'active-notice' && $time_saved ) :?>
2248 +<?php elseif ( $type == 'active-notice' && $time_saved ) : ?>
2249 <div class="akismet-alert akismet-active">
2250 <h3 class="akismet-key-status"><?php echo esc_html( $time_saved ); ?></h3>
2251 <p class="akismet-description"><?php printf( __('You can help us fight spam and upgrade your account by <a href="%s" target="_blank">contributing a token amount</a>.', 'akismet'), 'https://akismet.com/account/upgrade/'); ?></p>
2252 </div>
2253 -<?php elseif ( $type == 'missing' ) :?>
2254 +<?php elseif ( $type == 'missing' ) : ?>
2255 <div class="akismet-alert akismet-critical">
2256 <h3 class="akismet-key-status failed"><?php esc_html_e( 'There is a problem with your API key.', 'akismet'); ?></h3>
2257 <p class="akismet-description"><?php printf( __('Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet'), 'https://akismet.com/contact/'); ?></p>
2258 </div>
2259 -<?php elseif ( $type == 'no-sub' ) :?>
2260 +<?php elseif ( $type == 'no-sub' ) : ?>
2261 <div class="akismet-alert akismet-critical">
2262 <h3 class="akismet-key-status failed"><?php esc_html_e( 'You don&#8217;t have an Akismet plan.', 'akismet'); ?></h3>
2263 <p class="akismet-description">
2264 @@ -107,30 +107,83 @@
2265 <p class="akismet-description"><?php printf( __( 'Would you like to <a href="%s">check pending comments</a>?', 'akismet' ), esc_url( $check_pending_link ) ); ?></p>
2266 <?php } ?>
2267 </div>
2268 -<?php elseif ( $type == 'new-key-invalid' ) :?>
2269 +<?php elseif ( $type == 'new-key-invalid' ) : ?>
2270 <div class="akismet-alert akismet-critical">
2271 <h3 class="akismet-key-status"><?php esc_html_e( 'The key you entered is invalid. Please double-check it.' , 'akismet'); ?></h3>
2272 </div>
2273 -<?php elseif ( $type == 'existing-key-invalid' ) :?>
2274 +<?php elseif ( $type == 'existing-key-invalid' ) : ?>
2275 <div class="akismet-alert akismet-critical">
2276 - <h3 class="akismet-key-status"><?php esc_html_e( 'Your API key is no longer valid. Please enter a new key or contact support@×××××××.com.' , 'akismet'); ?></h3>
2277 + <h3 class="akismet-key-status"><?php echo esc_html( __( 'Your API key is no longer valid.', 'akismet' ) ); ?></h3>
2278 + <p class="akismet-description">
2279 + <?php
2280 +
2281 + echo wp_kses(
2282 + sprintf(
2283 + /* translators: The placeholder is a URL. */
2284 + __( 'Please enter a new key or <a href="%s" target="_blank">contact Akismet support</a>.', 'akismet' ),
2285 + 'https://akismet.com/contact/'
2286 + ),
2287 + array(
2288 + 'a' => array(
2289 + 'href' => true,
2290 + 'target' => true,
2291 + ),
2292 + )
2293 + );
2294 +
2295 + ?>
2296 + </p>
2297 </div>
2298 -<?php elseif ( $type == 'new-key-failed' ) :?>
2299 +<?php elseif ( $type == 'new-key-failed' ) : ?>
2300 <div class="akismet-alert akismet-critical">
2301 <h3 class="akismet-key-status"><?php esc_html_e( 'The API key you entered could not be verified.' , 'akismet'); ?></h3>
2302 - <p class="akismet-description"><?php printf( __('The connection to akismet.com could not be established. Please refer to <a href="%s" target="_blank">our guide about firewalls</a> and check your server configuration.', 'akismet'), 'https://blog.akismet.com/akismet-hosting-faq/'); ?></p>
2303 + <p class="akismet-description">
2304 + <?php
2305 +
2306 + echo wp_kses(
2307 + sprintf(
2308 + /* translators: The placeholder is a URL. */
2309 + __( 'The connection to akismet.com could not be established. Please refer to <a href="%s" target="_blank">our guide about firewalls</a> and check your server configuration.', 'akismet' ),
2310 + 'https://blog.akismet.com/akismet-hosting-faq/'
2311 + ),
2312 + array(
2313 + 'a' => array(
2314 + 'href' => true,
2315 + 'target' => true,
2316 + ),
2317 + )
2318 + );
2319 +
2320 + ?>
2321 + </p>
2322 </div>
2323 -<?php elseif ( $type == 'limit-reached' && in_array( $level, array( 'yellow', 'red' ) ) ) :?>
2324 +<?php elseif ( $type == 'limit-reached' && in_array( $level, array( 'yellow', 'red' ) ) ) : ?>
2325 <div class="akismet-alert akismet-critical">
2326 <?php if ( $level == 'yellow' ): ?>
2327 - <h3 class="akismet-key-status failed"><?php esc_html_e( 'You&#8217;re using your Akismet key on more sites than your Pro subscription allows.', 'akismet' ); ?></h3>
2328 + <h3 class="akismet-key-status failed"><?php esc_html_e( 'You&#8217;re using your Akismet key on more sites than your Plus subscription allows.', 'akismet' ); ?></h3>
2329 <p class="akismet-description">
2330 - <?php printf( __( 'Your Pro subscription allows the use of Akismet on only one site. Please <a href="%s" target="_blank">purchase additional Pro subscriptions</a> or upgrade to an Enterprise subscription that allows the use of Akismet on unlimited sites.', 'akismet' ), 'https://docs.akismet.com/billing/add-more-sites/' ); ?>
2331 + <?php
2332 +
2333 + echo wp_kses(
2334 + sprintf(
2335 + /* translators: The placeholder is a URL. */
2336 + __( 'Your Plus subscription allows the use of Akismet on only one site. Please <a href="%s" target="_blank">purchase additional Plus subscriptions</a> or upgrade to an Enterprise subscription that allows the use of Akismet on unlimited sites.', 'akismet' ),
2337 + 'https://docs.akismet.com/billing/add-more-sites/'
2338 + ),
2339 + array(
2340 + 'a' => array(
2341 + 'href' => true,
2342 + 'target' => true,
2343 + ),
2344 + )
2345 + );
2346 +
2347 + ?>
2348 <br /><br />
2349 <?php printf( __( 'Please <a href="%s" target="_blank">contact our support team</a> with any questions.', 'akismet' ), 'https://akismet.com/contact/'); ?>
2350 </p>
2351 <?php elseif ( $level == 'red' ): ?>
2352 - <h3 class="akismet-key-status failed"><?php esc_html_e( 'You&#8217;re using Akismet on far too many sites for your Pro subscription.', 'akismet' ); ?></h3>
2353 + <h3 class="akismet-key-status failed"><?php esc_html_e( 'You&#8217;re using Akismet on far too many sites for your Plus subscription.', 'akismet' ); ?></h3>
2354 <p class="akismet-description">
2355 <?php printf( __( 'To continue your service, <a href="%s" target="_blank">upgrade to an Enterprise subscription</a>, which covers an unlimited number of sites.', 'akismet'), 'https://akismet.com/account/upgrade/' ); ?>
2356 <br /><br />
2357 @@ -138,10 +191,96 @@
2358 </p>
2359 <?php endif; ?>
2360 </div>
2361 -<?php elseif ( $type == 'privacy' ) :?>
2362 -<div class="notice notice-warning is-dismissible" id="akismet-privacy-notice-admin-notice">
2363 - <p><strong><?php esc_html_e( 'Akismet & Privacy.', 'akismet' );?></strong></p>
2364 - <p><?php esc_html_e( 'To help your site with transparency under privacy laws like the GDPR, Akismet can display a notice to your users under your comment forms. This feature is disabled by default, however, you can turn it on below.', 'akismet' ); ?></p>
2365 - <p><?php printf( __(' Please <a href="%s">enable</a> or <a href="%s">disable</a> this feature. <a href="%s" id="akismet-privacy-notice-control-notice-info-link" target="_blank">More information</a>.', 'akismet' ), admin_url( apply_filters( 'akismet_comment_form_privacy_notice_url_display', 'options-general.php?page=akismet-key-config&akismet_comment_form_privacy_notice=display' ) ), admin_url( apply_filters( 'akismet_comment_form_privacy_notice_url_hide', 'options-general.php?page=akismet-key-config&akismet_comment_form_privacy_notice=hide' ) ), 'https://akismet.com/privacy/' ); ?></p>
2366 +<?php elseif ( $type == 'usage-limit' && isset( Akismet::$limit_notices[ $code ] ) ) : ?>
2367 +<div class="error akismet-usage-limit-alert">
2368 + <div class="akismet-usage-limit-logo">
2369 + <img src="<?php echo esc_url( plugins_url( '../_inc/img/logo-a-2x.png', __FILE__ ) ); ?>" alt="Akismet" />
2370 + </div>
2371 + <div class="akismet-usage-limit-text">
2372 + <h3>
2373 + <?php
2374 + switch ( Akismet::$limit_notices[ $code ] ) {
2375 + case 'FIRST_MONTH_OVER_LIMIT':
2376 + case 'SECOND_MONTH_OVER_LIMIT':
2377 + esc_html_e( 'Your Akismet account usage is over your plan&#8217;s limit', 'akismet' );
2378 + break;
2379 + case 'THIRD_MONTH_APPROACHING_LIMIT':
2380 + esc_html_e( 'Your Akismet account usage is approaching your plan&#8217;s limit', 'akismet' );
2381 + break;
2382 + case 'THIRD_MONTH_OVER_LIMIT':
2383 + case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
2384 + esc_html_e( 'Your account has been restricted', 'akismet' );
2385 + break;
2386 + default:
2387 + }
2388 + ?>
2389 + </h3>
2390 + <p>
2391 + <?php
2392 + switch ( Akismet::$limit_notices[ $code ] ) {
2393 + case 'FIRST_MONTH_OVER_LIMIT':
2394 + echo esc_html(
2395 + sprintf(
2396 + /* translators: The first placeholder is a date, the second is a (formatted) number, the third is another formatted number. */
2397 + __( 'Since %1$s, your account made %2$s API calls, compared to your plan&#8217;s limit of %3$s.', 'akismet' ),
2398 + esc_html( gmdate( 'F' ) . ' 1' ),
2399 + number_format( $api_calls ),
2400 + number_format( $usage_limit )
2401 + )
2402 + );
2403 +
2404 + echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
2405 + echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
2406 + echo '</a>';
2407 +
2408 + break;
2409 + case 'SECOND_MONTH_OVER_LIMIT':
2410 + echo esc_html( __( 'Your Akismet usage has been over your plan&#8217;s limit for two consecutive months. Next month, we will restrict your account after you reach the limit. Please consider upgrading your plan.', 'akismet' ) );
2411 +
2412 + echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
2413 + echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
2414 + echo '</a>';
2415 +
2416 + break;
2417 + case 'THIRD_MONTH_APPROACHING_LIMIT':
2418 + echo esc_html( __( 'Your Akismet usage is nearing your plan&#8217;s limit for the third consecutive month. We will restrict your account after you reach the limit. Upgrade your plan so Akismet can continue blocking spam.', 'akismet' ) );
2419 +
2420 + echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
2421 + echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
2422 + echo '</a>';
2423 +
2424 + break;
2425 + case 'THIRD_MONTH_OVER_LIMIT':
2426 + case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
2427 + echo esc_html( __( 'Your Akismet usage has been over your plan&#8217;s limit for three consecutive months. We have restricted your account for the rest of the month. Upgrade your plan so Akismet can continue blocking spam.', 'akismet' ) );
2428 +
2429 + echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
2430 + echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
2431 + echo '</a>';
2432 +
2433 + break;
2434 + default:
2435 + }
2436 + ?>
2437 + </p>
2438 + </div>
2439 + <div class="akismet-usage-limit-cta">
2440 + <a href="<?php echo esc_attr( $upgrade_url ); ?>" class="button" target="_blank">
2441 + <?php
2442 + // If only a qty upgrade is required, show a more generic message.
2443 + if ( ! empty( $upgrade_type ) && 'qty' === $upgrade_type ) {
2444 + esc_html_e( 'Upgrade your Subscription Level', 'akismet' );
2445 + } else {
2446 + echo esc_html(
2447 + sprintf(
2448 + /* translators: The placeholder is the name of a subscription level, like "Plus" or "Enterprise" . */
2449 + __( 'Upgrade to %s', 'akismet' ),
2450 + $upgrade_plan
2451 + )
2452 + );
2453 + }
2454 + ?>
2455 + </a>
2456 + </div>
2457 </div>
2458 -<?php endif;?>
2459 \ No newline at end of file
2460 +<?php endif; ?>
2461
2462 diff --git a/plugins/akismet/views/setup.php b/plugins/akismet/views/setup.php
2463 index d21c89a9..50780090 100644
2464 --- a/plugins/akismet/views/setup.php
2465 +++ b/plugins/akismet/views/setup.php
2466 @@ -1,5 +1,4 @@
2467 -<h3><?php esc_html_e( 'Set Up Akismet' , 'akismet' );?></h3>
2468 -<div class="akismet-right">
2469 +<div class="akismet-setup-instructions">
2470 + <p><?php esc_html_e( 'Set up your Akismet account to enable spam filtering on this site.', 'akismet' ); ?></p>
2471 <?php Akismet::view( 'get', array( 'text' => __( 'Set up your Akismet account' , 'akismet' ), 'classes' => array( 'akismet-button', 'akismet-is-primary' ) ) ); ?>
2472 </div>
2473 -<p><?php esc_html_e( 'Set up your Akismet account to enable spam filtering on this site.', 'akismet' ); ?></p>
2474 \ No newline at end of file
2475
2476 diff --git a/plugins/akismet/views/stats.php b/plugins/akismet/views/stats.php
2477 index 2302c11a..81d82ce4 100644
2478 --- a/plugins/akismet/views/stats.php
2479 +++ b/plugins/akismet/views/stats.php
2480 @@ -1,7 +1,7 @@
2481 <div id="akismet-plugin-container">
2482 <div class="akismet-masthead">
2483 <div class="akismet-masthead__inside-container">
2484 - <a href="<?php echo esc_url( Akismet_Admin::get_page_url() );?>" class="akismet-right"><?php esc_html_e( 'Akismet Settings' , 'akismet' ); ?></a>
2485 + <a href="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" class="akismet-right"><?php esc_html_e( 'Anti-Spam Settings', 'akismet' ); ?></a>
2486 <div class="akismet-masthead__logo-container">
2487 <img class="akismet-masthead__logo" src="<?php echo esc_url( plugins_url( '../_inc/img/logo-full-2x.png', __FILE__ ) ); ?>" alt="Akismet" />
2488 </div>