summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/akismet/.htaccess2
-rw-r--r--plugins/akismet/_inc/akismet.css83
-rw-r--r--plugins/akismet/_inc/akismet.js207
-rw-r--r--plugins/akismet/_inc/form.js30
-rw-r--r--plugins/akismet/_inc/img/logo-a-2x.pngbin0 -> 904 bytes
-rw-r--r--plugins/akismet/akismet.php6
-rw-r--r--plugins/akismet/changelog.txt465
-rw-r--r--plugins/akismet/class.akismet-admin.php167
-rw-r--r--plugins/akismet/class.akismet-widget.php24
-rw-r--r--plugins/akismet/class.akismet.php477
-rw-r--r--plugins/akismet/readme.txt476
-rw-r--r--plugins/akismet/views/config.php8
-rw-r--r--plugins/akismet/views/enter.php2
-rw-r--r--plugins/akismet/views/notice.php193
-rw-r--r--plugins/akismet/views/setup.php5
-rw-r--r--plugins/akismet/views/stats.php2
16 files changed, 1389 insertions, 758 deletions
diff --git a/plugins/akismet/.htaccess b/plugins/akismet/.htaccess
index 49d72d71..d2675517 100644
--- a/plugins/akismet/.htaccess
+++ b/plugins/akismet/.htaccess
@@ -23,7 +23,7 @@
</FilesMatch>
# Akismet images
-<FilesMatch "^logo-full-2x\.png$">
+<FilesMatch "^logo-(a|full)-2x\.png$">
<IfModule !mod_authz_core.c>
Allow from all
</IfModule>
diff --git a/plugins/akismet/_inc/akismet.css b/plugins/akismet/_inc/akismet.css
index fea4eb7b..a62f7a84 100644
--- a/plugins/akismet/_inc/akismet.css
+++ b/plugins/akismet/_inc/akismet.css
@@ -79,15 +79,6 @@ table.comments td.comment p a:after {
.checkforspam {
display: inline-block !important;
}
-.checkforspam-progress {
- display: none;
-}
-.checkforspam.checking .checkforspam-progress {
- padding-left: 1ex;
-}
-.checkforspam.button-disabled .checkforspam-progress {
- display: inline;
-}
.checkforspam-spinner {
display: inline-block;
@@ -109,12 +100,9 @@ table.comments td.comment p a:after {
margin-top: .5rem;
}
.akismet-alert {
- border: 1px solid #e5e5e5;
padding: 0.4em 1em 1.4em 1em;
- border-radius: 3px;
- -webkit-border-radius: 3px;
- border-width: 1px;
- border-style: solid;
+ box-sizing: border-box;
+ box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
}
.akismet-alert h3.akismet-key-status {
@@ -661,3 +649,70 @@ table.comments td.comment p a:after {
.akismet-section-header__actions {
line-height: 1.75rem;
}
+
+.akismet-setup-instructions {
+ text-align: center;
+}
+
+.akismet-setup-instructions form {
+ padding-bottom: 1.5rem;
+}
+
+div.error.akismet-usage-limit-alert {
+ padding: 25px 45px 25px 15px;
+ display: flex;
+ align-items: center;
+}
+
+#akismet-plugin-container .akismet-usage-limit-alert {
+ margin: 0 auto 0.625rem auto;
+ box-sizing: border-box;
+ box-shadow: 0 0 0 1px rgba(200, 215, 225, 0.5), 0 1px 2px #e9eff3;
+ border: none;
+ border-left: 4px solid #d63638;
+}
+
+.akismet-usage-limit-alert .akismet-usage-limit-logo {
+ width: 38px;
+ min-width: 38px;
+ height: 38px;
+ border-radius: 20px;
+ margin-right: 18px;
+ background: black;
+ position: relative;
+}
+
+.akismet-usage-limit-alert .akismet-usage-limit-logo img {
+ position: absolute;
+ width: 22px;
+ left: 8px;
+ top: 10px;
+}
+
+.akismet-usage-limit-alert .akismet-usage-limit-text {
+ flex-grow: 1;
+ margin-right: 18px;
+}
+
+.akismet-usage-limit-alert h3 {
+ margin: 0;
+}
+
+.akismet-usage-limit-alert .akismet-usage-limit-cta {
+ text-align: right;
+}
+
+@media (max-width: 550px) {
+ div.error.akismet-usage-limit-alert {
+ display: block;
+ }
+
+ .akismet-usage-limit-alert .akismet-usage-limit-logo,
+ .akismet-usage-limit-alert .akismet-usage-limit-text {
+ margin-bottom: 15px;
+ }
+
+ .akismet-usage-limit-alert .akismet-usage-limit-cta {
+ text-align: left;
+ }
+} \ No newline at end of file
diff --git a/plugins/akismet/_inc/akismet.js b/plugins/akismet/_inc/akismet.js
index 3445a094..7ebac1a5 100644
--- a/plugins/akismet/_inc/akismet.js
+++ b/plugins/akismet/_inc/akismet.js
@@ -1,10 +1,12 @@
jQuery( function ( $ ) {
var mshotRemovalTimer = null;
- var mshotSecondTryTimer = null
- var mshotThirdTryTimer = null
-
+ var mshotRetryTimer = null;
+ var mshotTries = 0;
+ var mshotRetryInterval = 1000;
var mshotEnabledLinkSelector = 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a';
-
+
+ var preloadedMshotURLs = [];
+
$('.akismet-status').each(function () {
var thisId = $(this).attr('commentid');
$(this).prependTo('#comment-' + thisId + ' .column-comment');
@@ -84,69 +86,142 @@ jQuery( function ( $ ) {
});
// Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
- $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
- clearTimeout( mshotRemovalTimer );
+ if ( "enable_mshots" in WPAkismet && WPAkismet.enable_mshots ) {
+ $( '#the-comment-list' ).on( 'mouseover', mshotEnabledLinkSelector, function () {
+ clearTimeout( mshotRemovalTimer );
- if ( $( '.akismet-mshot' ).length > 0 ) {
- if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
- // The preview is already showing for this link.
- return;
+ if ( $( '.akismet-mshot' ).length > 0 ) {
+ if ( $( '.akismet-mshot:first' ).data( 'link' ) == this ) {
+ // The preview is already showing for this link.
+ return;
+ }
+ else {
+ // A new link is being hovered, so remove the old preview.
+ $( '.akismet-mshot' ).remove();
+ }
+ }
+
+ clearTimeout( mshotRetryTimer );
+
+ var linkUrl = $( this ).attr( 'href' );
+
+ if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
+ // 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.
+ mshotTries = 2;
}
else {
- // A new link is being hovered, so remove the old preview.
- $( '.akismet-mshot' ).remove();
+ mshotTries = 1;
}
- }
- clearTimeout( mshotSecondTryTimer );
- clearTimeout( mshotThirdTryTimer );
+ 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>' );
+ mShot.data( 'link', this );
+ mShot.data( 'url', linkUrl );
+
+ mShot.find( 'img' ).on( 'load', function () {
+ $( '.akismet-mshot' ).data( 'pending-request', false );
+ } );
- var thisHref = $( this ).attr( 'href' );
+ var offset = $( this ).offset();
- 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>' );
- mShot.data( 'link', this );
+ mShot.offset( {
+ 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.
+ top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
+ } );
- var offset = $( this ).offset();
+ $( 'body' ).append( mShot );
- mShot.offset( {
- 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.
- top: offset.top + ( $( this ).height() / 2 ) - 101 // 101 = top offset of the arrow plus the top border thickness
+ mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
+ } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
+ mshotRemovalTimer = setTimeout( function () {
+ clearTimeout( mshotRetryTimer );
+
+ $( '.akismet-mshot' ).remove();
+ }, 200 );
} );
- // These retries appear to be superfluous if .mshot-image has already loaded, but it's because mShots
- // can return a "Generating thumbnail..." image if it doesn't have a thumbnail ready, so we need
- // to retry to see if we can get the newly generated thumbnail.
- mshotSecondTryTimer = setTimeout( function () {
- mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 2 ) );
- }, 6000 );
-
- mshotThirdTryTimer = setTimeout( function () {
- mShot.find( '.mshot-image' ).attr( 'src', akismet_mshot_url( thisHref, 3 ) );
- }, 12000 );
-
- $( 'body' ).append( mShot );
- } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
- mshotRemovalTimer = setTimeout( function () {
- clearTimeout( mshotSecondTryTimer );
- clearTimeout( mshotThirdTryTimer );
-
- $( '.akismet-mshot' ).remove();
- }, 200 );
- } ).on( 'mouseover', 'tr', function () {
- // When the mouse hovers over a comment row, begin preloading mshots for any links in the comment or the comment author.
- var linksToPreloadMshotsFor = $( this ).find( mshotEnabledLinkSelector );
-
- linksToPreloadMshotsFor.each( function () {
- // Don't attempt to preload an mshot for a single link twice. Browser caching should cover this, but in case of
- // race conditions, save a flag locally when we've begun trying to preload one.
- if ( ! $( this ).data( 'akismet-mshot-preloaded' ) ) {
- akismet_preload_mshot( $( this ).attr( 'href' ) );
+ var preloadDelayTimer = null;
+
+ $( window ).on( 'scroll resize', function () {
+ clearTimeout( preloadDelayTimer );
+
+ preloadDelayTimer = setTimeout( preloadMshotsInViewport, 500 );
+ } );
+
+ preloadMshotsInViewport();
+ }
+
+ /**
+ * The way mShots works is if there was no screenshot already recently generated for the URL,
+ * it returns a "loading..." image for the first request. Then, some subsequent request will
+ * receive the actual screenshot, but it's unknown how long it will take. So, what we do here
+ * is continually re-request the mShot, waiting a second after every response until we get the
+ * actual screenshot.
+ */
+ function retryMshotUntilLoaded() {
+ clearTimeout( mshotRetryTimer );
+
+ var imageWidth = $( '.akismet-mshot img' ).get(0).naturalWidth;
+
+ if ( imageWidth == 0 ) {
+ // It hasn't finished loading yet the first time. Check again shortly.
+ setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
+ }
+ else if ( imageWidth == 400 ) {
+ // It loaded the preview image.
+
+ if ( mshotTries == 20 ) {
+ // Give up if we've requested the mShot 20 times already.
+ return;
+ }
+
+ if ( ! $( '.akismet-mshot' ).data( 'pending-request' ) ) {
+ $( '.akismet-mshot' ).data( 'pending-request', true );
+
+ mshotTries++;
+
+ $( '.akismet-mshot .mshot-image' ).attr( 'src', akismet_mshot_url( $( '.akismet-mshot' ).data( 'url' ), mshotTries ) );
+ }
+
+ mshotRetryTimer = setTimeout( retryMshotUntilLoaded, mshotRetryInterval );
+ }
+ else {
+ // All done.
+ }
+ }
+
+ function preloadMshotsInViewport() {
+ var windowWidth = $( window ).width();
+ var windowHeight = $( window ).height();
+
+ $( '#the-comment-list' ).find( mshotEnabledLinkSelector ).each( function ( index, element ) {
+ var linkUrl = $( this ).attr( 'href' );
+
+ // Don't attempt to preload an mshot for a single link twice.
+ if ( preloadedMshotURLs.indexOf( linkUrl ) !== -1 ) {
+ // The URL is already preloaded.
+ return true;
+ }
+
+ if ( typeof element.getBoundingClientRect !== 'function' ) {
+ // The browser is too old. Return false to stop this preloading entirely.
+ return false;
+ }
+
+ var rect = element.getBoundingClientRect();
+
+ if ( rect.top >= 0 && rect.left >= 0 && rect.bottom <= windowHeight && rect.right <= windowWidth ) {
+ akismet_preload_mshot( linkUrl );
$( this ).data( 'akismet-mshot-preloaded', true );
}
} );
- } );
+ }
+
+ $( '.checkforspam.enable-on-load' ).on( 'click', function( e ) {
+ if ( $( this ).hasClass( 'ajax-disabled' ) ) {
+ // Akismet hasn't been configured yet. Allow the user to proceed to the button's link.
+ return;
+ }
- $( '.checkforspam' ).click( function( e ) {
e.preventDefault();
if ( $( this ).hasClass( 'button-disabled' ) ) {
@@ -157,11 +232,8 @@ jQuery( function ( $ ) {
$('.checkforspam').addClass('button-disabled').addClass( 'checking' );
$('.checkforspam-spinner').addClass( 'spinner' ).addClass( 'is-active' );
- // Update the label on the "Check for Spam" button to use the active "Checking for Spam" language.
- $( '.checkforspam .akismet-label' ).text( $( '.checkforspam' ).data( 'active-label' ) );
-
akismet_check_for_spam(0, 100);
- });
+ }).removeClass( 'button-disabled' );
var spam_count = 0;
var recheck_count = 0;
@@ -176,7 +248,7 @@ jQuery( function ( $ ) {
var percentage_complete = Math.round( ( recheck_count / check_for_spam_buttons.data( 'pending-comment-count' ) ) * 1000 ) / 10;
// Update the progress counter on the "Check for Spam" button.
- $( '.checkforspam-progress' ).text( check_for_spam_buttons.data( 'progress-label-format' ).replace( '%1$s', percentage_complete ) );
+ $( '.checkforspam' ).text( check_for_spam_buttons.data( 'progress-label' ).replace( '%1$s', percentage_complete ) );
$.post(
ajaxurl,
@@ -269,12 +341,14 @@ jQuery( function ( $ ) {
* @return string The mShot URL;
*/
function akismet_mshot_url( linkUrl, retry ) {
- var mshotUrl = '//s0.wordpress.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
-
- if ( retry ) {
+ var mshotUrl = '//s0.wp.com/mshots/v1/' + encodeURIComponent( linkUrl ) + '?w=900';
+
+ if ( retry > 1 ) {
mshotUrl += '&r=' + encodeURIComponent( retry );
}
-
+
+ mshotUrl += '&source=akismet';
+
return mshotUrl;
}
@@ -286,17 +360,10 @@ jQuery( function ( $ ) {
function akismet_preload_mshot( linkUrl ) {
var img = new Image();
img.src = akismet_mshot_url( linkUrl );
+
+ preloadedMshotURLs.push( linkUrl );
}
- /**
- * Sets the comment form privacy notice display to hide when one clicks Core's dismiss button on the related admin notice.
- */
- $( '#akismet-privacy-notice-admin-notice' ).on( 'click', '.notice-dismiss', function () {
- $.ajax( {
- url: './options-general.php?page=akismet-key-config&akismet_comment_form_privacy_notice=hide',
- } );
- });
-
$( '.akismet-could-be-primary' ).each( function () {
var form = $( this ).closest( 'form' );
diff --git a/plugins/akismet/_inc/form.js b/plugins/akismet/_inc/form.js
deleted file mode 100644
index 3a5be8af..00000000
--- a/plugins/akismet/_inc/form.js
+++ /dev/null
@@ -1,30 +0,0 @@
-var ak_js = document.getElementById( "ak_js" );
-
-if ( ! ak_js ) {
- ak_js = document.createElement( 'input' );
- ak_js.setAttribute( 'id', 'ak_js' );
- ak_js.setAttribute( 'name', 'ak_js' );
- ak_js.setAttribute( 'type', 'hidden' );
-}
-else {
- ak_js.parentNode.removeChild( ak_js );
-}
-
-ak_js.setAttribute( 'value', ( new Date() ).getTime() );
-
-var commentForm = document.getElementById( 'commentform' );
-
-if ( commentForm ) {
- commentForm.appendChild( ak_js );
-}
-else {
- var replyRowContainer = document.getElementById( 'replyrow' );
-
- if ( replyRowContainer ) {
- var children = replyRowContainer.getElementsByTagName( 'td' );
-
- if ( children.length > 0 ) {
- children[0].appendChild( ak_js );
- }
- }
-} \ No newline at end of file
diff --git a/plugins/akismet/_inc/img/logo-a-2x.png b/plugins/akismet/_inc/img/logo-a-2x.png
new file mode 100644
index 00000000..087144ae
--- /dev/null
+++ b/plugins/akismet/_inc/img/logo-a-2x.png
Binary files differ
diff --git a/plugins/akismet/akismet.php b/plugins/akismet/akismet.php
index 538a7dbc..2175a913 100644
--- a/plugins/akismet/akismet.php
+++ b/plugins/akismet/akismet.php
@@ -6,7 +6,7 @@
Plugin Name: Akismet Anti-Spam
Plugin URI: https://akismet.com/
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.
-Version: 4.1.3
+Version: 4.2.1
Author: Automattic
Author URI: https://automattic.com/wordpress-plugins/
License: GPLv2 or later
@@ -37,8 +37,8 @@ if ( !function_exists( 'add_action' ) ) {
exit;
}
-define( 'AKISMET_VERSION', '4.1.3' );
-define( 'AKISMET__MINIMUM_WP_VERSION', '4.0' );
+define( 'AKISMET_VERSION', '4.2.1' );
+define( 'AKISMET__MINIMUM_WP_VERSION', '5.0' );
define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
define( 'AKISMET_DELETE_LIMIT', 100000 );
diff --git a/plugins/akismet/changelog.txt b/plugins/akismet/changelog.txt
new file mode 100644
index 00000000..680bc2e6
--- /dev/null
+++ b/plugins/akismet/changelog.txt
@@ -0,0 +1,465 @@
+=== Akismet Anti-Spam ===
+
+== Archived Changelog Entries ==
+
+This file contains older changelog entries, so we can keep the size of the standard WordPress readme.txt file reasonable.
+For the latest changes, please see the "Changelog" section of the [readme.txt file](https://plugins.svn.wordpress.org/akismet/trunk/readme.txt).
+
+= 4.1.5 =
+*Release Date - 29 April 2020*
+
+* 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.
+* Updated the "Requires at least" to WP 4.6, based on recommendations from https://wp-info.org/tools/checkplugini18n.php?slug=akismet
+* 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
+
+= 4.1.4 =
+*Release Date - 17 March 2020*
+
+* 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.
+* Update the layout of the initial setup screen to be more readable on small screens.
+* If no API key has been entered, don't run code that expects an API key.
+* Improve the readability of the comment history entries.
+* Don't modify the comment form HTML if no API key has been set.
+
+= 4.1.3 =
+*Release Date - 31 October 2019*
+
+* Prevented an attacker from being able to cause a user to unknowingly recheck their Pending comments for spam.
+* Improved compatibility with Jetpack 7.7+.
+* Updated the plugin activation page to use consistent language and markup.
+* Redirecting users to the Akismet connnection/settings screen upon plugin activation, in an effort to make it easier for people to get setup.
+
+= 4.1.2 =
+*Release Date - 14 May 2019*
+
+* Fixed a conflict between the Akismet setup banner and other plugin notices.
+* Reduced the number of API requests made by the plugin when attempting to verify the API key.
+* Include additional data in the pingback pre-check API request to help make the stats more accurate.
+* Fixed a bug that was enabling the "Check for Spam" button when no comments were eligible to be checked.
+* Improved Akismet's AMP compatibility.
+
+= 4.1.1 =
+*Release Date - 31 January 2019*
+
+* Fixed the "Setup Akismet" notice so it resizes responsively.
+* Only highlight the "Save Changes" button in the Akismet config when changes have been made.
+* The count of comments in your spam queue shown on the dashboard show now always be up-to-date.
+
+= 4.1 =
+*Release Date - 12 November 2018*
+
+* Added a WP-CLI method for retrieving stats.
+* Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
+* Added functionality to clear outdated alerts from Akismet.com.
+
+= 4.0.8 =
+*Release Date - 19 June 2018*
+
+* Improved the grammar and consistency of the in-admin privacy related notes (notice and config).
+* Revised in-admin explanation of the comment form privacy notice to make its usage clearer.
+* Added `rel="nofollow noopener"` to the comment form privacy notice to improve SEO and security.
+
+= 4.0.7 =
+*Release Date - 28 May 2018*
+
+* 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.
+* 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."
+* Only show in-admin privacy notice if Akismet has an API Key configured
+
+= 4.0.6 =
+*Release Date - 26 May 2018*
+
+* Moved away from using `empty( get_option() )` to instantiating a variable to be compatible with older versions of PHP (5.3, 5.4, etc).
+
+= 4.0.5 =
+*Release Date - 26 May 2018*
+
+* Corrected version number after tagging. Sorry...
+
+= 4.0.4 =
+*Release Date - 26 May 2018*
+
+* Added a hook to provide Akismet-specific privacy information for a site's privacy policy.
+* Added tools to control the display of a privacy related notice under comment forms.
+* Fixed HTML in activation failure message to close META and HEAD tag properly.
+* Fixed a bug that would sometimes prevent Akismet from being correctly auto-configured.
+
+= 4.0.3 =
+*Release Date - 19 February 2018*
+
+* Added a scheduled task to remove entries in wp_commentmeta that no longer have corresponding comments in wp_comments.
+* 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.
+
+= 4.0.2 =
+*Release Date - 18 December 2017*
+
+* Fixed a bug that could cause Akismet to recheck a comment that has already been manually approved or marked as spam.
+* 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.
+
+= 4.0.1 =
+*Release Date - 6 November 2017*
+
+* Fixed a bug that could prevent some users from connecting Akismet via their Jetpack connection.
+* Ensured that any pending Akismet-related events are unscheduled if the plugin is deactivated.
+* Allow some JavaScript to be run asynchronously to avoid affecting page render speeds.
+
+= 4.0 =
+*Release Date - 19 September 2017*
+
+* Added REST API endpoints for configuring Akismet and retrieving stats.
+* Increased the minimum supported WordPress version to 4.0.
+* Added compatibility with comments submitted via the REST API.
+* Improved the progress indicator on the "Check for Spam" button.
+
+= 3.3.4 =
+*Release Date - 3 August 2017*
+
+* Disabled Akismet's debug log output by default unless AKISMET_DEBUG is defined.
+* URL previews now begin preloading when the mouse moves near them in the comments section of wp-admin.
+* 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.
+* Fixed a bug that was preventing an error from being shown when a site can't reach Akismet's servers.
+
+= 3.3.3 =
+*Release Date - 13 July 2017*
+
+* Reduced amount of bandwidth used by the URL Preview feature.
+* Improved the admin UI when the API key is manually pre-defined for the site.
+* Removed a workaround for WordPress installations older than 3.3 that will improve Akismet's compatibility with other plugins.
+* The number of spam blocked that is displayed on the WordPress dashboard will now be more accurate and updated more frequently.
+* Fixed a bug in the Akismet widget that could cause PHP warnings.
+
+= 3.3.2 =
+*Release Date - 10 May 2017*
+
+* Fixed a bug causing JavaScript errors in some browsers.
+
+= 3.3.1 =
+*Release Date - 2 May 2017*
+
+* Improve performance by only requesting the akismet_comment_nonce option when absolutely necessary.
+* Fixed two bugs that could cause PHP warnings.
+* Fixed a bug that was preventing the "Remove author URL" feature from working after a comment was edited using "Quick Edit."
+* Fixed a bug that was preventing the URL preview feature from working after a comment was edited using "Quick Edit."
+
+= 3.3 =
+*Release Date - 23 February 2017*
+
+* Updated the Akismet admin pages with a new clean design.
+* Fixed bugs preventing the `akismet_add_comment_nonce` and `akismet_update_alert` wrapper functions from working properly.
+* Fixed bug preventing the loading indicator from appearing when re-checking all comments for spam.
+* Added a progress indicator to the "Check for Spam" button.
+* Added a success message after manually rechecking the Pending queue for spam.
+
+= 3.2 =
+*Release Date - 6 September 2016*
+
+* Added a WP-CLI module. You can now check comments and recheck the moderation queue from the command line.
+* Stopped using the deprecated jQuery function `.live()`.
+* Fixed a bug in `remove_comment_author_url()` and `add_comment_author_url()` that could generate PHP notices.
+* Fixed a bug that could cause an infinite loop for sites with very very very large comment IDs.
+* Fixed a bug that could cause the Akismet widget title to be blank.
+
+= 3.1.11 =
+*Release Date - 12 May 2016*
+
+* Fixed a bug that could cause the "Check for Spam" button to skip some comments.
+* Fixed a bug that could prevent some spam submissions from being sent to Akismet.
+* Updated all links to use https:// when possible.
+* Disabled Akismet debug logging unless WP_DEBUG and WP_DEBUG_LOG are both enabled.
+
+= 3.1.10 =
+*Release Date - 1 April 2016*
+
+* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
+* 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.
+* Fixed a bug that could have caused avoidable PHP warnings in the error log.
+
+= 3.1.9 =
+*Release Date - 28 March 2016*
+
+* Add compatibility with Jetpack so that Jetpack can automatically configure Akismet settings when appropriate.
+* Fixed a bug preventing some comment data from being sent to Akismet.
+
+= 3.1.8 =
+*Release Date - 4 March 2016*
+
+* Fixed a bug preventing Akismet from being used with some plugins that rewrite admin URLs.
+* Reduced the amount of bandwidth used on Akismet API calls
+* Reduced the amount of space Akismet uses in the database
+* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
+
+= 3.1.7 =
+*Release Date - 4 January 2016*
+
+* Added documentation for the 'akismet_comment_nonce' filter.
+* The post-install activation button is now accessible to screen readers and keyboard-only users.
+* Fixed a bug that was preventing the "Remove author URL" feature from working in WordPress 4.4
+
+= 3.1.6 =
+*Release Date - 14 December 2015*
+
+* Improve the notices shown after activating Akismet.
+* Update some strings to allow for the proper plural forms in all languages.
+
+= 3.1.5 =
+*Release Date - 13 October 2015*
+
+* Closes a potential XSS vulnerability.
+
+= 3.1.4 =
+*Release Date - 24 September 2015*
+
+* Fixed a bug that was preventing some users from automatically connecting using Jetpack if they didn't have a current Akismet subscription.
+* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
+* Error messages and instructions have been simplified to be more understandable.
+* Link previews are enabled for all links inside comments, not just the author's website link.
+
+= 3.1.3 =
+*Release Date - 6 July 2015*
+
+* 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.
+
+= 3.1.2 =
+*Release Date - 7 June 2015*
+
+* Reduced the amount of space Akismet uses in the commentmeta table.
+* Fixed a bug where some comments with quotes in the author name weren't getting history entries
+* Pre-emptive security improvements to ensure that the Akismet plugin can't be used by attackers to compromise a WordPress installation.
+* 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.
+* When deactivating the plugin, notify the Akismet API so the site can be marked as inactive.
+* Clearer error messages.
+
+= 3.1.1 =
+*Release Date - 17th March, 2015*
+
+* Improvements to the "Remove comment author URL" JavaScript
+* Include the pingback pre-check from the 2.6 branch.
+
+= 3.1 =
+*Release Date - 11th March, 2015*
+
+* Use HTTPS by default for all requests to Akismet.
+* Fix for a situation where Akismet might strip HTML from a comment.
+
+= 3.0.4 =
+*Release Date - 11th December, 2014*
+
+* Fix to make .htaccess compatible with Apache 2.4.
+* Fix to allow removal of https author URLs.
+* Fix to avoid stripping part of the author URL when removing and re-adding.
+* Removed the "Check for Spam" button from the "Trash" and "Approved" queues, where it would have no effect.
+* Allow automatic API key configuration when Jetpack is installed and connected to a WordPress.com account
+
+= 3.0.3 =
+*Release Date - 3rd November, 2014*
+
+* Fix for sending the wrong data to delete_comment action that could have prevented old spam comments from being deleted.
+* Added a filter to disable logging of Akismet debugging information.
+* Added a filter for the maximum comment age when deleting old spam comments.
+* Added a filter for the number per batch when deleting old spam comments.
+* Removed the "Check for Spam" button from the Spam folder.
+
+= 3.0.2 =
+*Release Date - 18th August, 2014*
+
+* Performance improvements.
+* Fixed a bug that could truncate the comment data being sent to Akismet for checking.
+
+= 3.0.1 =
+*Release Date - 9th July, 2014*
+
+* Removed dependency on PHP's fsockopen function
+* Fix spam/ham reports to work when reported outside of the WP dashboard, e.g., from Notifications or the WP app
+* Remove jQuery dependency for comment form JavaScript
+* Remove unnecessary data from some Akismet comment meta
+* Suspended keys will now result in all comments being put in moderation, not spam.
+
+= 3.0.0 =
+*Release Date - 15th April, 2014*
+
+* Move Akismet to Settings menu
+* Drop Akismet Stats menu
+* Add stats snapshot to Akismet settings
+* Add Akismet subscription details and status to Akismet settings
+* Add contextual help for each page
+* Improve Akismet setup to use Jetpack to automate plugin setup
+* Fix "Check for Spam" to use AJAX to avoid page timing out
+* Fix Akismet settings page to be responsive
+* Drop legacy code
+* Tidy up CSS and Javascript
+* Replace the old discard setting with a new "discard pervasive spam" feature.
+
+= 2.6.0 =
+*Release Date - 18th March, 2014*
+
+* Add ajax paging to the check for spam button to handle large volumes of comments
+* Optimize javascript and add localization support
+* Fix bug in link to spam comments from right now dashboard widget
+* Fix bug with deleting old comments to avoid timeouts dealing with large volumes of comments
+* Include X-Pingback-Forwarded-For header in outbound WordPress pingback verifications
+* Add pre-check for pingbacks, to stop spam before an outbound verification request is made
+
+= 2.5.9 =
+*Release Date - 1st August, 2013*
+
+* Update 'Already have a key' link to redirect page rather than depend on javascript
+* Fix some non-translatable strings to be translatable
+* Update Activation banner in plugins page to redirect user to Akismet config page
+
+= 2.5.8 =
+*Release Date - 20th January, 2013*
+
+* Simplify the activation process for new users
+* Remove the reporter_ip parameter
+* Minor preventative security improvements
+
+= 2.5.7 =
+*Release Date - 13th December, 2012*
+
+* FireFox Stats iframe preview bug
+* Fix mshots preview when using https
+* Add .htaccess to block direct access to files
+* Prevent some PHP notices
+* Fix Check For Spam return location when referrer is empty
+* Fix Settings links for network admins
+* Fix prepare() warnings in WP 3.5
+
+= 2.5.6 =
+*Release Date - 26th April, 2012*
+
+* Prevent retry scheduling problems on sites where wp_cron is misbehaving
+* Preload mshot previews
+* Modernize the widget code
+* Fix a bug where comments were not held for moderation during an error condition
+* Improve the UX and display when comments are temporarily held due to an error
+* Make the Check For Spam button force a retry when comments are held due to an error
+* Handle errors caused by an invalid key
+* Don't retry comments that are too old
+* Improve error messages when verifying an API key
+
+= 2.5.5 =
+*Release Date - 11th January, 2012*
+
+* Add nonce check for comment author URL remove action
+* Fix the settings link
+
+= 2.5.4 =
+*Release Date - 5th January, 2012*
+
+* Limit Akismet CSS and Javascript loading in wp-admin to just the pages that need it
+* Added author URL quick removal functionality
+* Added mShot preview on Author URL hover
+* Added empty index.php to prevent directory listing
+* Move wp-admin menu items under Jetpack, if it is installed
+* Purge old Akismet comment meta data, default of 15 days
+
+= 2.5.3 =
+*Release Date - 8th Febuary, 2011*
+
+* Specify the license is GPL v2 or later
+* Fix a bug that could result in orphaned commentmeta entries
+* Include hotfix for WordPress 3.0.5 filter issue
+
+= 2.5.2 =
+*Release Date - 14th January, 2011*
+
+* Properly format the comment count for author counts
+* Look for super admins on multisite installs when looking up user roles
+* Increase the HTTP request timeout
+* Removed padding for author approved count
+* Fix typo in function name
+* Set Akismet stats iframe height to fixed 2500px. Better to have one tall scroll bar than two side by side.
+
+= 2.5.1 =
+*Release Date - 17th December, 2010*
+
+* Fix a bug that caused the "Auto delete" option to fail to discard comments correctly
+* Remove the comment nonce form field from the 'Akismet Configuration' page in favor of using a filter, akismet_comment_nonce
+* Fixed padding bug in "author" column of posts screen
+* Added margin-top to "cleared by ..." badges on dashboard
+* Fix possible error when calling akismet_cron_recheck()
+* Fix more PHP warnings
+* Clean up XHTML warnings for comment nonce
+* Fix for possible condition where scheduled comment re-checks could get stuck
+* Clean up the comment meta details after deleting a comment
+* Only show the status badge if the comment status has been changed by someone/something other than Akismet
+* Show a 'History' link in the row-actions
+* Translation fixes
+* Reduced font-size on author name
+* Moved "flagged by..." notification to top right corner of comment container and removed heavy styling
+* Hid "flagged by..." notification while on dashboard
+
+= 2.5.0 =
+*Release Date - 7th December, 2010*
+
+* Track comment actions under 'Akismet Status' on the edit comment screen
+* Fix a few remaining deprecated function calls ( props Mike Glendinning )
+* Use HTTPS for the stats IFRAME when wp-admin is using HTTPS
+* Use the WordPress HTTP class if available
+* Move the admin UI code to a separate file, only loaded when needed
+* Add cron retry feature, to replace the old connectivity check
+* Display Akismet status badge beside each comment
+* Record history for each comment, and display it on the edit page
+* Record the complete comment as originally submitted in comment_meta, to use when reporting spam and ham
+* Highlight links in comment content
+* New option, "Show the number of comments you've approved beside each comment author."
+* New option, "Use a nonce on the comment form."
+
+= 2.4.0 =
+*Release Date - 23rd August, 2010*
+
+* Spell out that the license is GPLv2
+* Fix PHP warnings
+* Fix WordPress deprecated function calls
+* Fire the delete_comment action when deleting comments
+* Move code specific for older WP versions to legacy.php
+* General code clean up
+
+= 2.3.0 =
+*Release Date - 5th June, 2010*
+
+* Fix "Are you sure" nonce message on config screen in WPMU
+* Fix XHTML compliance issue in sidebar widget
+* Change author link; remove some old references to WordPress.com accounts
+* Localize the widget title (core ticket #13879)
+
+= 2.2.9 =
+*Release Date - 2nd June, 2010*
+
+* Eliminate a potential conflict with some plugins that may cause spurious reports
+
+= 2.2.8 =
+*Release Date - 27th May, 2010*
+
+* Fix bug in initial comment check for ipv6 addresses
+* Report comments as ham when they are moved from spam to moderation
+* Report comments as ham when clicking undo after spam
+* Use transition_comment_status action when available instead of older actions for spam/ham submissions
+* Better diagnostic messages when PHP network functions are unavailable
+* Better handling of comments by logged-in users
+
+= 2.2.7 =
+*Release Date - 17th December, 2009*
+
+* Add a new AKISMET_VERSION constant
+* Reduce the possibility of over-counting spam when another spam filter plugin is in use
+* Disable the connectivity check when the API key is hard-coded for WPMU
+
+= 2.2.6 =
+*Release Date - 20th July, 2009*
+
+* Fix a global warning introduced in 2.2.5
+* Add changelog and additional readme.txt tags
+* Fix an array conversion warning in some versions of PHP
+* Support a new WPCOM_API_KEY constant for easier use with WordPress MU
+
+= 2.2.5 =
+*Release Date - 13th July, 2009*
+
+* Include a new Server Connectivity diagnostic check, to detect problems caused by firewalls
+
+= 2.2.4 =
+*Release Date - 3rd June, 2009*
+
+* Fixed a key problem affecting the stats feature in WordPress MU
+* Provide additional blog information in Akismet API calls
diff --git a/plugins/akismet/class.akismet-admin.php b/plugins/akismet/class.akismet-admin.php
index b5e2ef8e..c6cb1355 100644
--- a/plugins/akismet/class.akismet-admin.php
+++ b/plugins/akismet/class.akismet-admin.php
@@ -32,10 +32,6 @@ class Akismet_Admin {
if ( isset( $_POST['action'] ) && $_POST['action'] == 'enter-key' ) {
self::enter_api_key();
}
-
- if ( ! empty( $_GET['akismet_comment_form_privacy_notice'] ) && empty( $_GET['settings-updated']) ) {
- self::set_form_privacy_notice_option( $_GET['akismet_comment_form_privacy_notice'] );
- }
}
public static function init_hooks() {
@@ -70,11 +66,6 @@ class Akismet_Admin {
add_filter( 'all_plugins', array( 'Akismet_Admin', 'modify_plugin_description' ) );
- if ( class_exists( 'Jetpack' ) ) {
- add_filter( 'akismet_comment_form_privacy_notice_url_display', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
- add_filter( 'akismet_comment_form_privacy_notice_url_hide', array( 'Akismet_Admin', 'jetpack_comment_form_privacy_notice_url' ) );
- }
-
// priority=1 because we need ours to run before core's comment anonymizer runs, and that's registered at priority=10
add_filter( 'wp_privacy_personal_data_erasers', array( 'Akismet_Admin', 'register_personal_data_eraser' ), 1 );
}
@@ -146,7 +137,7 @@ class Akismet_Admin {
wp_register_script( 'akismet.js', plugin_dir_url( __FILE__ ) . '_inc/akismet.js', array('jquery'), AKISMET_VERSION );
wp_enqueue_script( 'akismet.js' );
-
+
$inline_js = array(
'comment_author_url_nonce' => wp_create_nonce( 'comment_author_url_nonce' ),
'strings' => array(
@@ -162,6 +153,10 @@ class Akismet_Admin {
$inline_js['start_recheck'] = true;
}
+ if ( apply_filters( 'akismet_enable_mshots', true ) ) {
+ $inline_js['enable_mshots'] = true;
+ }
+
wp_localize_script( 'akismet.js', 'WPAkismet', $inline_js );
}
}
@@ -392,27 +387,40 @@ class Akismet_Admin {
return;
}
- $link = add_query_arg( array( 'action' => 'akismet_recheck_queue' ), admin_url( 'admin.php' ) );
+ $link = '';
$comments_count = wp_count_comments();
echo '</div>';
echo '<div class="alignleft actions">';
+
+ $classes = array(
+ 'button-secondary',
+ 'checkforspam',
+ 'button-disabled' // Disable button until the page is loaded
+ );
+
+ if ( $comments_count->moderated > 0 ) {
+ $classes[] = 'enable-on-load';
+
+ if ( ! Akismet::get_api_key() ) {
+ $link = add_query_arg( array( 'page' => 'akismet-key-config' ), class_exists( 'Jetpack' ) ? admin_url( 'admin.php' ) : admin_url( 'options-general.php' ) );
+ $classes[] = 'ajax-disabled';
+ }
+ }
+
echo '<a
- class="button-secondary checkforspam' . ( $comments_count->moderated == 0 ? ' button-disabled' : '' ) . '"
- href="' . esc_url( $link ) . '"
- data-active-label="' . esc_attr( __( 'Checking for Spam', 'akismet' ) ) . '"
- data-progress-label-format="' . esc_attr( __( '(%1$s%)', 'akismet' ) ) . '"
+ class="' . esc_attr( implode( ' ', $classes ) ) . '"' .
+ ( ! empty( $link ) ? ' href="' . esc_url( $link ) . '"' : '' ) .
+ /* translators: The placeholder is for showing how much of the process has completed, as a percent. e.g., "Checking for Spam (40%)" */
+ ' data-progress-label="' . esc_attr( __( 'Checking for Spam (%1$s%)', 'akismet' ) ) . '"
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__' ) ) ) ) ) . '"
data-failure-url="' . esc_attr( remove_query_arg( array( 'akismet_recheck', 'akismet_recheck_complete' ), add_query_arg( array( 'akismet_recheck_error' => 1 ) ) ) ) . '"
data-pending-comment-count="' . esc_attr( $comments_count->moderated ) . '"
data-nonce="' . esc_attr( wp_create_nonce( 'akismet_check_for_spam' ) ) . '"
- >';
- echo '<span class="akismet-label">' . esc_html__('Check for Spam', 'akismet') . '</span>';
- echo '<span class="checkforspam-progress"></span>';
- echo '</a>';
+ ' . ( ! in_array( 'ajax-disabled', $classes ) ? 'onclick="return false;"' : '' ) . '
+ >' . esc_html__('Check for Spam', 'akismet') . '</a>';
echo '<span class="checkforspam-spinner"></span>';
-
}
public static function recheck_queue() {
@@ -575,10 +583,8 @@ class Akismet_Admin {
$history = Akismet::get_comment_history( $comment->comment_ID );
if ( $history ) {
- echo '<div class="akismet-history" style="margin: 13px;">';
-
foreach ( $history as $row ) {
- $time = date( 'D d M Y @ h:i:m a', $row['time'] ) . ' GMT';
+ $time = date( 'D d M Y @ h:i:s a', $row['time'] ) . ' GMT';
$message = '';
@@ -588,56 +594,67 @@ class Akismet_Admin {
// 1) Save space.
// 2) The message can be translated into the current language of the blog, not stuck
// in the language of the blog when the comment was made.
- $message = $row['message'];
+ $message = esc_html( $row['message'] );
}
// If possible, use a current translation.
switch ( $row['event'] ) {
case 'recheck-spam';
- $message = __( 'Akismet re-checked and caught this comment as spam.', 'akismet' );
+ $message = esc_html( __( 'Akismet re-checked and caught this comment as spam.', 'akismet' ) );
break;
case 'check-spam':
- $message = __( 'Akismet caught this comment as spam.', 'akismet' );
+ $message = esc_html( __( 'Akismet caught this comment as spam.', 'akismet' ) );
break;
case 'recheck-ham':
- $message = __( 'Akismet re-checked and cleared this comment.', 'akismet' );
+ $message = esc_html( __( 'Akismet re-checked and cleared this comment.', 'akismet' ) );
break;
case 'check-ham':
- $message = __( 'Akismet cleared this comment.', 'akismet' );
+ $message = esc_html( __( 'Akismet cleared this comment.', 'akismet' ) );
break;
case 'wp-blacklisted':
- $message = __( 'Comment was caught by wp_blacklist_check.', 'akismet' );
+ case 'wp-disallowed':
+ $message = sprintf(
+ /* translators: The placeholder is a WordPress PHP function name. */
+ esc_html( __( 'Comment was caught by %s.', 'akismet' ) ),
+ function_exists( 'wp_check_comment_disallowed_list' ) ? '<code>wp_check_comment_disallowed_list</code>' : '<code>wp_blacklist_check</code>'
+ );
break;
case 'report-spam':
if ( isset( $row['user'] ) ) {
- $message = sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] );
+ $message = esc_html( sprintf( __( '%s reported this comment as spam.', 'akismet' ), $row['user'] ) );
}
else if ( ! $message ) {
- $message = __( 'This comment was reported as spam.', 'akismet' );
+ $message = esc_html( __( 'This comment was reported as spam.', 'akismet' ) );
}
break;
case 'report-ham':
if ( isset( $row['user'] ) ) {
- $message = sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] );
+ $message = esc_html( sprintf( __( '%s reported this comment as not spam.', 'akismet' ), $row['user'] ) );
}
else if ( ! $message ) {
- $message = __( 'This comment was reported as not spam.', 'akismet' );
+ $message = esc_html( __( 'This comment was reported as not spam.', 'akismet' ) );
}
break;
case 'cron-retry-spam':
- $message = __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet');
+ $message = esc_html( __( 'Akismet caught this comment as spam during an automatic retry.' , 'akismet') );
break;
case 'cron-retry-ham':
- $message = __( 'Akismet cleared this comment during an automatic retry.', 'akismet');
+ $message = esc_html( __( 'Akismet cleared this comment during an automatic retry.', 'akismet') );
break;
case 'check-error':
if ( isset( $row['meta'], $row['meta']['response'] ) ) {
- $message = sprintf( __( 'Akismet was unable to check this comment (response: %s) but will automatically retry later.', 'akismet'), $row['meta']['response'] );
+ $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>' );
+ }
+ else {
+ $message = esc_html( __( 'Akismet was unable to check this comment but will automatically retry later.', 'akismet' ) );
}
break;
case 'recheck-error':
if ( isset( $row['meta'], $row['meta']['response'] ) ) {
- $message = sprintf( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet'), $row['meta']['response'] );
+ $message = sprintf( esc_html( __( 'Akismet was unable to recheck this comment (response: %s).', 'akismet') ), '<code>' . esc_html( $row['meta']['response'] ) . '</code>' );
+ }
+ else {
+ $message = esc_html( __( 'Akismet was unable to recheck this comment.', 'akismet' ) );
}
break;
default:
@@ -645,27 +662,32 @@ class Akismet_Admin {
// Half of these used to be saved without the dash after 'status-changed'.
// See https://plugins.trac.wordpress.org/changeset/1150658/akismet/trunk
$new_status = preg_replace( '/^status-changed-?/', '', $row['event'] );
- $message = sprintf( __( 'Comment status was changed to %s', 'akismet' ), $new_status );
+ $message = sprintf( esc_html( __( 'Comment status was changed to %s', 'akismet' ) ), '<code>' . esc_html( $new_status ) . '</code>' );
}
else if ( preg_match( '/^status-/', $row['event'] ) ) {
$new_status = preg_replace( '/^status-/', '', $row['event'] );
if ( isset( $row['user'] ) ) {
- $message = sprintf( __( '%1$s changed the comment status to %2$s.', 'akismet' ), $row['user'], $new_status );
+ $message = sprintf( esc_html( __( '%1$s changed the comment status to %2$s.', 'akismet' ) ), $row['user'], '<code>' . esc_html( $new_status ) . '</code>' );
}
}
break;
}
- echo '<div style="margin-bottom: 13px;">';
+ if ( ! empty( $message ) ) {
+ echo '<p>';
echo '<span style="color: #999;" alt="' . $time . '" title="' . $time . '">' . sprintf( esc_html__('%s ago', 'akismet'), human_time_diff( $row['time'] ) ) . '</span>';
echo ' - ';
- echo esc_html( $message );
- echo '</div>';
+ echo $message; // esc_html() is done above so that we can use HTML in some messages.
+ echo '</p>';
+ }
}
-
- echo '</div>';
+ }
+ else {
+ echo '<p>';
+ echo esc_html( __( 'No comment history.', 'akismet' ) );
+ echo '</p>';
}
}
@@ -866,12 +888,21 @@ class Akismet_Admin {
) );
}
- public static function display_privacy_notice_control_warning() {
- if ( !current_user_can( 'manage_options' ) )
- return;
- Akismet::view( 'notice', array(
- 'type' => 'privacy',
- ) );
+ public static function get_usage_limit_alert_data() {
+ return array(
+ 'type' => 'usage-limit',
+ 'code' => (int) get_option( 'akismet_alert_code' ),
+ 'msg' => get_option( 'akismet_alert_msg' ),
+ 'api_calls' => get_option( 'akismet_alert_api_calls' ),
+ 'usage_limit' => get_option( 'akismet_alert_usage_limit' ),
+ 'upgrade_plan' => get_option( 'akismet_alert_upgrade_plan' ),
+ 'upgrade_url' => get_option( 'akismet_alert_upgrade_url' ),
+ 'upgrade_type' => get_option( 'akismet_alert_upgrade_type' ),
+ );
+ }
+
+ public static function display_usage_limit_alert() {
+ Akismet::view( 'notice', self::get_usage_limit_alert_data() );
}
public static function display_spam_check_warning() {
@@ -1007,8 +1038,9 @@ class Akismet_Admin {
$notices[] = array( 'type' => $akismet_user->status );
}
- if ( false === get_option( 'akismet_comment_form_privacy_notice' ) ) {
- $notices[] = array( 'type' => 'privacy' );
+ $alert_code = get_option( 'akismet_alert_code' );
+ if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
+ $notices[] = self::get_usage_limit_alert_data();
}
/*
@@ -1030,6 +1062,7 @@ class Akismet_Admin {
$notices[] = array( 'type' => 'new-key-failed' );
$notices[] = array( 'type' => 'limit-reached', 'level' => 'yellow' );
$notices[] = array( 'type' => 'limit-reached', 'level' => 'red' );
+ $notices[] = array( 'type' => 'usage-limit', 'api_calls' => '15000', 'usage_limit' => '10000', 'upgrade_plan' => 'Enterprise', 'upgrade_url' => 'https://akismet.com/account/' );
*/
Akismet::log( compact( 'stat_totals', 'akismet_user' ) );
@@ -1046,22 +1079,28 @@ class Akismet_Admin {
if ( in_array( $hook_suffix, array( 'edit-comments.php' ) ) && (int) get_option( 'akismet_alert_code' ) > 0 ) {
Akismet::verify_key( Akismet::get_api_key() ); //verify that the key is still in alert state
-
- if ( get_option( 'akismet_alert_code' ) > 0 )
+
+ $alert_code = get_option( 'akismet_alert_code' );
+ if ( isset( Akismet::$limit_notices[ $alert_code ] ) ) {
+ self::display_usage_limit_alert();
+ } elseif ( $alert_code > 0 ) {
self::display_alert();
+ }
}
- elseif ( $hook_suffix == 'plugins.php' && !Akismet::get_api_key() ) {
+ elseif ( ( 'plugins.php' === $hook_suffix || 'edit-comments.php' === $hook_suffix ) && ! Akismet::get_api_key() ) {
+ // Show the "Set Up Akismet" banner on the comments and plugin pages if no API key has been set.
self::display_api_key_warning();
}
elseif ( $hook_suffix == 'edit-comments.php' && wp_next_scheduled( 'akismet_schedule_cron_recheck' ) ) {
self::display_spam_check_warning();
}
- else if ( isset( $_GET['akismet_recheck_complete'] ) ) {
+
+ if ( isset( $_GET['akismet_recheck_complete'] ) ) {
$recheck_count = (int) $_GET['recheck_count'];
$spam_count = (int) $_GET['spam_count'];
if ( $recheck_count === 0 ) {
- $message = __( 'There were no comments to check. Akismet will only check comments in the Pending queue.', 'akismet' );
+ $message = __( 'There were no comments to check. Akismet will only check comments awaiting moderation.', 'akismet' );
}
else {
$message = sprintf( _n( 'Akismet checked %s comment.', 'Akismet checked %s comments.', $recheck_count, 'akismet' ), number_format( $recheck_count ) );
@@ -1080,14 +1119,6 @@ class Akismet_Admin {
else if ( isset( $_GET['akismet_recheck_error'] ) ) {
echo '<div class="notice notice-error"><p>' . esc_html( __( 'Akismet could not recheck your comments for spam.', 'akismet' ) ) . '</p></div>';
}
-
- $akismet_comment_form_privacy_notice_option = get_option( 'akismet_comment_form_privacy_notice' );
- if ( ! in_array( $akismet_comment_form_privacy_notice_option, array( 'hide', 'display' ) ) ) {
- $api_key = Akismet::get_api_key();
- if ( ! empty( $api_key ) ) {
- self::display_privacy_notice_control_warning();
- }
- }
}
public static function display_status() {
@@ -1127,7 +1158,7 @@ class Akismet_Admin {
if ( !class_exists('Jetpack') )
return false;
- if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '7.7', '<' ) ) {
+ if ( defined( 'JETPACK__VERSION' ) && version_compare( JETPACK__VERSION, '7.7', '<' ) ) {
// For version of Jetpack prior to 7.7.
Jetpack::load_xml_rpc_client();
}
@@ -1202,10 +1233,6 @@ class Akismet_Admin {
update_option( 'akismet_comment_form_privacy_notice', $state );
}
}
-
- public static function jetpack_comment_form_privacy_notice_url( $url ) {
- return str_replace( 'options-general.php', 'admin.php', $url );
- }
public static function register_personal_data_eraser( $erasers ) {
$erasers['akismet'] = array(
diff --git a/plugins/akismet/class.akismet-widget.php b/plugins/akismet/class.akismet-widget.php
index 55b0f35c..9f0458b0 100644
--- a/plugins/akismet/class.akismet-widget.php
+++ b/plugins/akismet/class.akismet-widget.php
@@ -99,7 +99,29 @@ class Akismet_Widget extends WP_Widget {
?>
<div class="a-stats">
- <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>
+ <a href="https://akismet.com" target="_blank" rel="noopener" title="">
+ <?php
+
+ echo wp_kses(
+ sprintf(
+ /* translators: The placeholder is the number of pieces of spam blocked by Akismet. */
+ _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 )
+ ),
+ array(
+ 'strong' => array(
+ 'class' => true,
+ ),
+ )
+ );
+
+ ?>
+ </a>
</div>
<?php
diff --git a/plugins/akismet/class.akismet.php b/plugins/akismet/class.akismet.php
index 01753014..1681d0e1 100644
--- a/plugins/akismet/class.akismet.php
+++ b/plugins/akismet/class.akismet.php
@@ -5,12 +5,19 @@ class Akismet {
const API_PORT = 80;
const MAX_DELAY_BEFORE_MODERATION_EMAIL = 86400; // One day in seconds
+ public static $limit_notices = array(
+ 10501 => 'FIRST_MONTH_OVER_LIMIT',
+ 10502 => 'SECOND_MONTH_OVER_LIMIT',
+ 10504 => 'THIRD_MONTH_APPROACHING_LIMIT',
+ 10508 => 'THIRD_MONTH_OVER_LIMIT',
+ 10516 => 'FOUR_PLUS_MONTHS_OVER_LIMIT',
+ );
+
private static $last_comment = '';
private static $initiated = false;
private static $prevent_moderation_email_for_these_comments = array();
private static $last_comment_result = null;
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' => '' );
- private static $is_rest_api_call = false;
public static function init() {
if ( ! self::$initiated ) {
@@ -34,11 +41,7 @@ class Akismet {
add_action( 'akismet_schedule_cron_recheck', array( 'Akismet', 'cron_recheck' ) );
add_action( 'comment_form', array( 'Akismet', 'add_comment_nonce' ), 1 );
-
- add_action( 'admin_head-edit-comments.php', array( 'Akismet', 'load_form_js' ) );
- add_action( 'comment_form', array( 'Akismet', 'load_form_js' ) );
- add_action( 'comment_form', array( 'Akismet', 'inject_ak_js' ) );
- add_filter( 'script_loader_tag', array( 'Akismet', 'set_form_js_async' ), 10, 3 );
+ add_action( 'comment_form', array( 'Akismet', 'output_custom_form_fields' ) );
add_filter( 'comment_moderation_recipients', array( 'Akismet', 'disable_moderation_emails_if_unreachable' ), 1000, 2 );
add_filter( 'pre_comment_approved', array( 'Akismet', 'last_comment_status' ), 10, 2 );
@@ -47,9 +50,20 @@ class Akismet {
// Run this early in the pingback call, before doing a remote fetch of the source uri
add_action( 'xmlrpc_call', array( 'Akismet', 'pre_check_pingback' ) );
-
+
// Jetpack compatibility
add_filter( 'jetpack_options_whitelist', array( 'Akismet', 'add_to_jetpack_options_whitelist' ) );
+ add_filter( 'jetpack_contact_form_html', array( 'Akismet', 'inject_custom_form_fields' ) );
+ add_filter( 'jetpack_contact_form_akismet_values', array( 'Akismet', 'prepare_custom_form_values' ) );
+
+ // Gravity Forms
+ add_filter( 'gform_get_form_filter', array( 'Akismet', 'inject_custom_form_fields' ) );
+ add_filter( 'gform_akismet_fields', array( 'Akismet', 'prepare_custom_form_values' ) );
+
+ // Contact Form 7
+ add_filter( 'wpcf7_form_elements', array( 'Akismet', 'append_custom_form_fields' ) );
+ add_filter( 'wpcf7_akismet_parameters', array( 'Akismet', 'prepare_custom_form_values' ) );
+
add_action( 'update_option_wordpress_api_key', array( 'Akismet', 'updated_option' ), 10, 2 );
add_action( 'add_option_wordpress_api_key', array( 'Akismet', 'added_option' ), 10, 2 );
@@ -131,12 +145,23 @@ class Akismet {
}
public static function rest_auto_check_comment( $commentdata ) {
- self::$is_rest_api_call = true;
-
- return self::auto_check_comment( $commentdata );
+ return self::auto_check_comment( $commentdata, 'rest_api' );
}
- public static function auto_check_comment( $commentdata ) {
+ /**
+ * Check a comment for spam.
+ *
+ * @param array $commentdata
+ * @param string $context What kind of request triggered this comment check? Possible values are 'default', 'rest_api', and 'xml-rpc'.
+ * @return array|WP_Error Either the $commentdata array with additional entries related to its spam status
+ * or a WP_Error, if it's a REST API request and the comment should be discarded.
+ */
+ public static function auto_check_comment( $commentdata, $context = 'default' ) {
+ // If no key is configured, then there's no point in doing any of this.
+ if ( ! self::get_api_key() ) {
+ return $commentdata;
+ }
+
self::$last_comment_result = null;
$comment = $commentdata;
@@ -202,7 +227,15 @@ class Akismet {
do_action( 'akismet_comment_check_response', $response );
$commentdata['comment_as_submitted'] = array_intersect_key( $comment, self::$comment_as_submitted_allowed_keys );
- $commentdata['akismet_result'] = $response[1];
+
+ // Also include any form fields we inject into the comment form, like ak_js
+ foreach ( $_POST as $key => $value ) {
+ if ( is_string( $value ) && strpos( $key, 'ak_' ) === 0 ) {
+ $commentdata['comment_as_submitted'][ 'POST_' . $key ] = $value;
+ }
+ }
+
+ $commentdata['akismet_result'] = $response[1];
if ( isset( $response[0]['x-akismet-pro-tip'] ) )
$commentdata['akismet_pro_tip'] = $response[0]['x-akismet-pro-tip'];
@@ -227,17 +260,19 @@ class Akismet {
update_option( 'akismet_spam_count', get_option( 'akismet_spam_count' ) + $incr );
}
- if ( self::$is_rest_api_call ) {
+ if ( 'rest_api' === $context ) {
return new WP_Error( 'akismet_rest_comment_discarded', __( 'Comment discarded.', 'akismet' ) );
- }
- else {
+ } else if ( 'xml-rpc' === $context ) {
+ // If this is a pingback that we're pre-checking, the discard behavior is the same as the normal spam response behavior.
+ return $commentdata;
+ } else {
// Redirect back to the previous page, or failing that, the post permalink, or failing that, the homepage of the blog.
$redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : ( $post ? get_permalink( $post ) : home_url() );
wp_safe_redirect( esc_url_raw( $redirect_to ) );
die();
}
}
- else if ( self::$is_rest_api_call ) {
+ else if ( 'rest_api' === $context ) {
// The way the REST API structures its calls, we can set the comment_approved value right away.
$commentdata['comment_approved'] = 'spam';
}
@@ -296,48 +331,56 @@ class Akismet {
// as was checked by auto_check_comment
if ( is_object( $comment ) && !empty( self::$last_comment ) && is_array( self::$last_comment ) ) {
if ( self::matches_last_comment( $comment ) ) {
-
- load_plugin_textdomain( 'akismet' );
-
- // normal result: true or false
- if ( self::$last_comment['akismet_result'] == 'true' ) {
- update_comment_meta( $comment->comment_ID, 'akismet_result', 'true' );
- self::update_comment_history( $comment->comment_ID, '', 'check-spam' );
- if ( $comment->comment_approved != 'spam' )
- self::update_comment_history(
- $comment->comment_ID,
- '',
- 'status-changed-'.$comment->comment_approved
- );
- }
- elseif ( self::$last_comment['akismet_result'] == 'false' ) {
- update_comment_meta( $comment->comment_ID, 'akismet_result', 'false' );
- self::update_comment_history( $comment->comment_ID, '', 'check-ham' );
- // Status could be spam or trash, depending on the WP version and whether this change applies:
- // https://core.trac.wordpress.org/changeset/34726
- if ( $comment->comment_approved == 'spam' || $comment->comment_approved == 'trash' ) {
- 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) )
- self::update_comment_history( $comment->comment_ID, '', 'wp-blacklisted' );
- else
- self::update_comment_history( $comment->comment_ID, '', 'status-changed-'.$comment->comment_approved );
- }
- } // abnormal result: error
- else {
- update_comment_meta( $comment->comment_ID, 'akismet_error', time() );
+ load_plugin_textdomain( 'akismet' );
+
+ // normal result: true or false
+ if ( self::$last_comment['akismet_result'] == 'true' ) {
+ update_comment_meta( $comment->comment_ID, 'akismet_result', 'true' );
+ self::update_comment_history( $comment->comment_ID, '', 'check-spam' );
+ if ( $comment->comment_approved != 'spam' ) {
self::update_comment_history(
$comment->comment_ID,
'',
- 'check-error',
- array( 'response' => substr( self::$last_comment['akismet_result'], 0, 50 ) )
+ 'status-changed-' . $comment->comment_approved
);
}
+ } elseif ( self::$last_comment['akismet_result'] == 'false' ) {
+ update_comment_meta( $comment->comment_ID, 'akismet_result', 'false' );
+ self::update_comment_history( $comment->comment_ID, '', 'check-ham' );
+ // Status could be spam or trash, depending on the WP version and whether this change applies:
+ // https://core.trac.wordpress.org/changeset/34726
+ if ( $comment->comment_approved == 'spam' || $comment->comment_approved == 'trash' ) {
+ if ( function_exists( 'wp_check_comment_disallowed_list' ) ) {
+ 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 ) ) {
+ self::update_comment_history( $comment->comment_ID, '', 'wp-disallowed' );
+ } else {
+ self::update_comment_history( $comment->comment_ID, '', 'status-changed-' . $comment->comment_approved );
+ }
+ } 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 ) ) {
+ self::update_comment_history( $comment->comment_ID, '', 'wp-blacklisted' );
+ } else {
+ self::update_comment_history( $comment->comment_ID, '', 'status-changed-' . $comment->comment_approved );
+ }
+ }
+ } else {
+ // abnormal result: error
+ update_comment_meta( $comment->comment_ID, 'akismet_error', time() );
+ self::update_comment_history(
+ $comment->comment_ID,
+ '',
+ 'check-error',
+ array( 'response' => substr( self::$last_comment['akismet_result'], 0, 50 ) )
+ );
+ }
- // record the complete original data as submitted for checking
- if ( isset( self::$last_comment['comment_as_submitted'] ) )
- update_comment_meta( $comment->comment_ID, 'akismet_as_submitted', self::$last_comment['comment_as_submitted'] );
+ // record the complete original data as submitted for checking
+ if ( isset( self::$last_comment['comment_as_submitted'] ) ) {
+ update_comment_meta( $comment->comment_ID, 'akismet_as_submitted', self::$last_comment['comment_as_submitted'] );
+ }
- if ( isset( self::$last_comment['akismet_pro_tip'] ) )
- update_comment_meta( $comment->comment_ID, 'akismet_pro_tip', self::$last_comment['akismet_pro_tip'] );
+ if ( isset( self::$last_comment['akismet_pro_tip'] ) ) {
+ update_comment_meta( $comment->comment_ID, 'akismet_pro_tip', self::$last_comment['akismet_pro_tip'] );
+ }
}
}
}
@@ -380,6 +423,10 @@ class Akismet {
clean_comment_cache( $comment_ids );
do_action( 'akismet_delete_comment_batch', count( $comment_ids ) );
+
+ foreach ( $comment_ids as $comment_id ) {
+ do_action( 'deleted_comment', $comment_id );
+ }
}
if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->comments ) ) // lucky number
@@ -469,6 +516,44 @@ class Akismet {
// get the full comment history for a given comment, as an array in reverse chronological order
public static function get_comment_history( $comment_id ) {
$history = get_comment_meta( $comment_id, 'akismet_history', false );
+ if ( empty( $history ) || empty( $history[ 0 ] ) ) {
+ return false;
+ }
+
+ /*
+ // To see all variants when testing.
+ $history[] = array( 'time' => 445856401, 'message' => 'Old versions of Akismet stored the message as a literal string in the commentmeta.', 'event' => null );
+ $history[] = array( 'time' => 445856402, 'event' => 'recheck-spam' );
+ $history[] = array( 'time' => 445856403, 'event' => 'check-spam' );
+ $history[] = array( 'time' => 445856404, 'event' => 'recheck-ham' );
+ $history[] = array( 'time' => 445856405, 'event' => 'check-ham' );
+ $history[] = array( 'time' => 445856406, 'event' => 'wp-blacklisted' );
+ $history[] = array( 'time' => 445856406, 'event' => 'wp-disallowed' );
+ $history[] = array( 'time' => 445856407, 'event' => 'report-spam' );
+ $history[] = array( 'time' => 445856408, 'event' => 'report-spam', 'user' => 'sam' );
+ $history[] = array( 'message' => 'sam reported this comment as spam (hardcoded message).', 'time' => 445856400, 'event' => 'report-spam', 'user' => 'sam' );
+ $history[] = array( 'time' => 445856409, 'event' => 'report-ham', 'user' => 'sam' );
+ $history[] = array( 'message' => 'sam reported this comment as ham (hardcoded message).', 'time' => 445856400, 'event' => 'report-ham', 'user' => 'sam' ); //
+ $history[] = array( 'time' => 445856410, 'event' => 'cron-retry-spam' );
+ $history[] = array( 'time' => 445856411, 'event' => 'cron-retry-ham' );
+ $history[] = array( 'time' => 445856412, 'event' => 'check-error' ); //
+ $history[] = array( 'time' => 445856413, 'event' => 'check-error', 'meta' => array( 'response' => 'The server was taking a nap.' ) );
+ $history[] = array( 'time' => 445856414, 'event' => 'recheck-error' ); // Should not generate a message.
+ $history[] = array( 'time' => 445856415, 'event' => 'recheck-error', 'meta' => array( 'response' => 'The server was taking a nap.' ) );
+ $history[] = array( 'time' => 445856416, 'event' => 'status-changedtrash' );
+ $history[] = array( 'time' => 445856417, 'event' => 'status-changedspam' );
+ $history[] = array( 'time' => 445856418, 'event' => 'status-changedhold' );
+ $history[] = array( 'time' => 445856419, 'event' => 'status-changedapprove' );
+ $history[] = array( 'time' => 445856420, 'event' => 'status-changed-trash' );
+ $history[] = array( 'time' => 445856421, 'event' => 'status-changed-spam' );
+ $history[] = array( 'time' => 445856422, 'event' => 'status-changed-hold' );
+ $history[] = array( 'time' => 445856423, 'event' => 'status-changed-approve' );
+ $history[] = array( 'time' => 445856424, 'event' => 'status-trash', 'user' => 'sam' );
+ $history[] = array( 'time' => 445856425, 'event' => 'status-spam', 'user' => 'sam' );
+ $history[] = array( 'time' => 445856426, 'event' => 'status-hold', 'user' => 'sam' );
+ $history[] = array( 'time' => 445856427, 'event' => 'status-approve', 'user' => 'sam' );
+ */
+
usort( $history, array( 'Akismet', '_cmp_time' ) );
return $history;
}
@@ -506,6 +591,10 @@ class Akismet {
public static function check_db_comment( $id, $recheck_reason = 'recheck_queue' ) {
global $wpdb;
+ if ( ! self::get_api_key() ) {
+ return new WP_Error( 'akismet-not-configured', __( 'Akismet is not configured. Please enter an API key.', 'akismet' ) );
+ }
+
$c = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->comments} WHERE comment_ID = %d", $id ), ARRAY_A );
if ( ! $c ) {
@@ -653,6 +742,13 @@ class Akismet {
if ( 'spam' != $comment->comment_approved )
return;
+ self::update_comment_history( $comment_id, '', 'report-spam' );
+
+ // If the user hasn't configured Akismet, there's nothing else to do at this point.
+ if ( ! self::get_api_key() ) {
+ return;
+ }
+
// use the original version stored in comment_meta if available
$as_submitted = self::sanitize_comment_as_submitted( get_comment_meta( $comment_id, 'akismet_as_submitted', true ) );
@@ -685,9 +781,10 @@ class Akismet {
}
$response = Akismet::http_post( Akismet::build_query( $comment ), 'submit-spam' );
+
+ update_comment_meta( $comment_id, 'akismet_user_result', 'true' );
+
if ( $comment->reporter ) {
- self::update_comment_history( $comment_id, '', 'report-spam' );
- update_comment_meta( $comment_id, 'akismet_user_result', 'true' );
update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
}
@@ -703,6 +800,13 @@ class Akismet {
if ( !$comment ) // it was deleted
return;
+ self::update_comment_history( $comment_id, '', 'report-ham' );
+
+ // If the user hasn't configured Akismet, there's nothing else to do at this point.
+ if ( ! self::get_api_key() ) {
+ return;
+ }
+
// use the original version stored in comment_meta if available
$as_submitted = self::sanitize_comment_as_submitted( get_comment_meta( $comment_id, 'akismet_as_submitted', true ) );
@@ -735,9 +839,10 @@ class Akismet {
}
$response = self::http_post( Akismet::build_query( $comment ), 'submit-ham' );
+
+ update_comment_meta( $comment_id, 'akismet_user_result', 'false' );
+
if ( $comment->reporter ) {
- self::update_comment_history( $comment_id, '', 'report-ham' );
- update_comment_meta( $comment_id, 'akismet_user_result', 'false' );
update_comment_meta( $comment_id, 'akismet_user', $comment->reporter );
}
@@ -860,6 +965,11 @@ class Akismet {
* has not been set and that Akismet should just choose the default behavior for that
* situation.
*/
+
+ if ( ! self::get_api_key() ) {
+ return;
+ }
+
$akismet_comment_nonce_option = apply_filters( 'akismet_comment_nonce', get_option( 'akismet_comment_nonce' ) );
if ( $akismet_comment_nonce_option == 'true' || $akismet_comment_nonce_option == '' ) {
@@ -879,7 +989,7 @@ class Akismet {
if ( is_user_logged_in() )
return false;
- return ( get_option( 'akismet_strictness' ) === '1' );
+ return ( get_option( 'akismet_strictness' ) === '1' );
}
public static function get_ip_address() {
@@ -1029,10 +1139,12 @@ class Akismet {
if ( ! empty( self::$prevent_moderation_email_for_these_comments ) && ! empty( $emails ) ) {
$comment = get_comment( $comment_id );
- foreach ( self::$prevent_moderation_email_for_these_comments as $possible_match ) {
- if ( self::comments_match( $possible_match, $comment ) ) {
- update_comment_meta( $comment_id, 'akismet_delayed_moderation_email', true );
- return array();
+ if ( $comment ) {
+ foreach ( self::$prevent_moderation_email_for_these_comments as $possible_match ) {
+ if ( self::comments_match( $possible_match, $comment ) ) {
+ update_comment_meta( $comment_id, 'akismet_delayed_moderation_email', true );
+ return array();
+ }
}
}
}
@@ -1163,51 +1275,106 @@ class Akismet {
// given a response from an API call like check_key_status(), update the alert code options if an alert is present.
public static function update_alert( $response ) {
- $code = $msg = null;
- if ( isset( $response[0]['x-akismet-alert-code'] ) ) {
- $code = $response[0]['x-akismet-alert-code'];
- $msg = $response[0]['x-akismet-alert-msg'];
- }
+ $alert_option_prefix = 'akismet_alert_';
+ $alert_header_prefix = 'x-akismet-alert-';
+ $alert_header_names = array(
+ 'code',
+ 'msg',
+ 'api-calls',
+ 'usage-limit',
+ 'upgrade-plan',
+ 'upgrade-url',
+ 'upgrade-type',
+ );
- // only call update_option() if the value has changed
- if ( $code != get_option( 'akismet_alert_code' ) ) {
- if ( ! $code ) {
- delete_option( 'akismet_alert_code' );
- delete_option( 'akismet_alert_msg' );
+ foreach ( $alert_header_names as $alert_header_name ) {
+ $value = null;
+ if ( isset( $response[0][ $alert_header_prefix . $alert_header_name ] ) ) {
+ $value = $response[0][ $alert_header_prefix . $alert_header_name ];
}
- else {
- update_option( 'akismet_alert_code', $code );
- update_option( 'akismet_alert_msg', $msg );
+
+ $option_name = $alert_option_prefix . str_replace( '-', '_', $alert_header_name );
+ if ( $value != get_option( $option_name ) ) {
+ if ( ! $value ) {
+ delete_option( $option_name );
+ } else {
+ update_option( $option_name, $value );
+ }
}
}
}
public static function load_form_js() {
- if ( function_exists( 'is_amp_endpoint' ) && is_amp_endpoint() ) {
- return;
+ /* deprecated */
+ }
+
+ public static function set_form_js_async( $tag, $handle, $src ) {
+ /* deprecated */
+ return $tag;
+ }
+
+ public static function get_akismet_form_fields() {
+ $fields = '';
+
+ $prefix = 'ak_';
+
+ // Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
+ if ( 'wpcf7_form_elements' === current_filter() ) {
+ $prefix = '_wpcf7_ak_';
+ }
+
+ $fields .= '<p style="display: none !important;">';
+ $fields .= '<label>&#916;<textarea name="' . $prefix . 'hp_textarea" cols="45" rows="8" maxlength="100"></textarea></label>';
+
+ if ( ! function_exists( 'amp_is_request' ) || ! amp_is_request() ) {
+ $fields .= '<input type="hidden" id="ak_js" name="' . $prefix . 'js" value="' . mt_rand( 0, 250 ) . '"/>';
+ $fields .= '<script>document.getElementById( "ak_js" ).setAttribute( "value", ( new Date() ).getTime() );</script>';
}
- wp_register_script( 'akismet-form', plugin_dir_url( __FILE__ ) . '_inc/form.js', array(), AKISMET_VERSION, true );
- wp_enqueue_script( 'akismet-form' );
+ $fields .= '</p>';
+
+ return $fields;
}
-
+
+ public static function output_custom_form_fields( $post_id ) {
+ // phpcs:ignore WordPress.Security.EscapeOutput
+ echo self::get_akismet_form_fields();
+ }
+
+ public static function inject_custom_form_fields( $html ) {
+ $html = str_replace( '</form>', self::get_akismet_form_fields() . '</form>', $html );
+
+ return $html;
+ }
+
+ public static function append_custom_form_fields( $html ) {
+ $html .= self::get_akismet_form_fields();
+
+ return $html;
+ }
+
/**
- * Mark form.js as async. Because nothing depends on it, it can run at any time
- * after it's loaded, and the browser won't have to wait for it to load to continue
- * parsing the rest of the page.
+ * Ensure that any Akismet-added form fields are included in the comment-check call.
+ *
+ * @param array $form
+ * @return array $form
*/
- public static function set_form_js_async( $tag, $handle, $src ) {
- if ( 'akismet-form' !== $handle ) {
- return $tag;
+ public static function prepare_custom_form_values( $form ) {
+ $prefix = 'ak_';
+
+ // Contact Form 7 uses _wpcf7 as a prefix to know which fields to exclude from comment_content.
+ if ( 'wpcf7_akismet_parameters' === current_filter() ) {
+ $prefix = '_wpcf7_ak_';
}
-
- return preg_replace( '/^<script /i', '<script async="async" ', $tag );
- }
-
- public static function inject_ak_js( $fields ) {
- echo '<p style="display: none;">';
- echo '<input type="hidden" id="ak_js" name="ak_js" value="' . mt_rand( 0, 250 ) . '"/>';
- echo '</p>';
+
+ // phpcs:ignore WordPress.Security.NonceVerification.Missing
+ foreach ( $_POST as $key => $val ) {
+ if ( 0 === strpos( $key, $prefix ) ) {
+ $form[ 'POST_ak_' . substr( $key, strlen( $prefix ) ) ] = $val;
+ }
+ }
+
+ return $form;
}
private static function bail_on_activation( $message, $deactivate = true ) {
@@ -1277,7 +1444,7 @@ p {
$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/');
Akismet::bail_on_activation( $message );
- } else {
+ } elseif ( ! empty( $_SERVER['SCRIPT_NAME'] ) && false !== strpos( $_SERVER['SCRIPT_NAME'], '/wp-admin/plugins.php' ) ) {
add_option( 'Activated_Akismet', true );
}
}
@@ -1333,16 +1500,98 @@ p {
if ( $method !== 'pingback.ping' )
return;
+ // 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.
+ // This ticket should hopefully fix that: https://core.trac.wordpress.org/ticket/52524
+ // Until that happens, when it's a system.multicall, pre_check_pingback will be called once for every internal pingback call.
+ // Keep track of how many times this function has been called so we know which call to reference in the XML.
+ static $call_count = 0;
+
+ $call_count++;
+
global $wp_xmlrpc_server;
-
+
if ( !is_object( $wp_xmlrpc_server ) )
return false;
-
- // Lame: tightly coupled with the IXR class.
- $args = $wp_xmlrpc_server->message->params;
-
- if ( !empty( $args[1] ) ) {
- $post_id = url_to_postid( $args[1] );
+
+ $is_multicall = false;
+ $multicall_count = 0;
+
+ if ( 'system.multicall' === $wp_xmlrpc_server->message->methodName ) {
+ $is_multicall = true;
+
+ if ( 0 === $call_count ) {
+ // Only pass along the number of entries in the multicall the first time we see it.
+ $multicall_count = count( $wp_xmlrpc_server->message->params );
+ }
+
+ /*
+ * $wp_xmlrpc_server->message looks like this:
+ *
+ (
+ [message] =>
+ [messageType] => methodCall
+ [faultCode] =>
+ [faultString] =>
+ [methodName] => system.multicall
+ [params] => Array
+ (
+ [0] => Array
+ (
+ [methodName] => pingback.ping
+ [params] => Array
+ (
+ [0] => http://www.example.net/?p=1 // Site that created the pingback.
+ [1] => https://www.example.com/?p=1 // Post being pingback'd on this site.
+ )
+ )
+ [1] => Array
+ (
+ [methodName] => pingback.ping
+ [params] => Array
+ (
+ [0] => http://www.example.net/?p=1 // Site that created the pingback.
+ [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
+ )
+ )
+ )
+ )
+ */
+
+ // Use the params from the nth pingback.ping call in the multicall.
+ $pingback_calls_found = 0;
+
+ foreach ( $wp_xmlrpc_server->message->params as $xmlrpc_action ) {
+ if ( 'pingback.ping' === $xmlrpc_action['methodName'] ) {
+ $pingback_calls_found++;
+ }
+
+ if ( $call_count === $pingback_calls_found ) {
+ $pingback_args = $xmlrpc_action['params'];
+ break;
+ }
+ }
+ } else {
+ /*
+ * $wp_xmlrpc_server->message looks like this:
+ *
+ (
+ [message] =>
+ [messageType] => methodCall
+ [faultCode] =>
+ [faultString] =>
+ [methodName] => pingback.ping
+ [params] => Array
+ (
+ [0] => http://www.example.net/?p=1 // Site that created the pingback.
+ [1] => https://www.example.com/?p=2 // Post being pingback'd on this site.
+ )
+ )
+ */
+ $pingback_args = $wp_xmlrpc_server->message->params;
+ }
+
+ if ( ! empty( $pingback_args[1] ) ) {
+ $post_id = url_to_postid( $pingback_args[1] );
// If pingbacks aren't open on this post, we'll still check whether this request is part of a potential DDOS,
// but indicate to the server that pingbacks are indeed closed so we don't include this request in the user's stats,
@@ -1355,23 +1604,30 @@ p {
$pingbacks_closed = true;
}
+ // 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.
+
$comment = array(
- 'comment_author_url' => $args[0],
+ 'comment_author_url' => $pingback_args[0],
'comment_post_ID' => $post_id,
'comment_author' => '',
'comment_author_email' => '',
'comment_content' => '',
'comment_type' => 'pingback',
'akismet_pre_check' => '1',
- 'comment_pingback_target' => $args[1],
+ 'comment_pingback_target' => $pingback_args[1],
'pingbacks_closed' => $pingbacks_closed ? '1' : '0',
+ 'is_multicall' => $is_multicall,
+ 'multicall_count' => $multicall_count,
);
- $comment = Akismet::auto_check_comment( $comment );
+ $comment = self::auto_check_comment( $comment, 'xml-rpc' );
if ( isset( $comment['akismet_result'] ) && 'true' == $comment['akismet_result'] ) {
- // Lame: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
+ // Sad: tightly coupled with the IXR classes. Unfortunately the action provides no context and no way to return anything.
$wp_xmlrpc_server->error( new IXR_Error( 0, 'Invalid discovery target' ) );
+
+ // Also note that if this was part of a multicall, a spam result will prevent the subsequent calls from being executed.
+ // This is probably fine, but it raises the bar for what should be acceptable as a false positive.
}
}
}
@@ -1390,8 +1646,17 @@ p {
$meta_value = (array) $meta_value;
foreach ( $meta_value as $key => $value ) {
- if ( ! isset( self::$comment_as_submitted_allowed_keys[$key] ) || ! is_scalar( $value ) ) {
- unset( $meta_value[$key] );
+ if ( ! is_scalar( $value ) ) {
+ unset( $meta_value[ $key ] );
+ } else {
+ // These can change, so they're not explicitly listed in comment_as_submitted_allowed_keys.
+ if ( strpos( $key, 'POST_ak_' ) === 0 ) {
+ continue;
+ }
+
+ if ( ! isset( self::$comment_as_submitted_allowed_keys[ $key ] ) ) {
+ unset( $meta_value[ $key ] );
+ }
}
}
diff --git a/plugins/akismet/readme.txt b/plugins/akismet/readme.txt
index bf0081a9..0058c338 100644
--- a/plugins/akismet/readme.txt
+++ b/plugins/akismet/readme.txt
@@ -1,12 +1,12 @@
-=== Akismet Anti-Spam ===
+=== Akismet Spam Protection ===
Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs, procifer, stephdau
-Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
-Requires at least: 4.0
-Tested up to: 5.3
-Stable tag: 4.1.3
+Tags: comments, spam, antispam, anti-spam, contact form, anti spam, comment moderation, comment spam, contact form spam, spam comments
+Requires at least: 5.0
+Tested up to: 5.8
+Stable tag: 4.2.1
License: GPLv2 or later
-Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
+The best anti-spam protection to block spam comments and spam in a contact form. The most trusted antispam solution for WordPress and WooCommerce.
== Description ==
@@ -30,445 +30,61 @@ Upload the Akismet plugin to your blog, activate it, and then enter your Akismet
== Changelog ==
-= 4.1.3 =
-*Release Date - 31 October 2019*
+= 4.2.1 =
+*Release Date - 1 October 2021*
-* Prevented an attacker from being able to cause a user to unknowingly recheck their Pending comments for spam.
-* Improved compatibility with Jetpack 7.7+.
-* Updated the plugin activation page to use consistent language and markup.
-* Redirecting users to the Akismet connnection/settings screen upon plugin activation, in an effort to make it easier for people to get setup.
+* Fixed a bug causing AMP validation to fail on certain pages with forms.
-= 4.1.2 =
-*Release Date - 14 May 2019*
+= 4.2 =
+*Release Date - 30 September 2021*
-* Fixed a conflict between the Akismet setup banner and other plugin notices.
-* Reduced the number of API requests made by the plugin when attempting to verify the API key.
-* Include additional data in the pingback pre-check API request to help make the stats more accurate.
-* Fixed a bug that was enabling the "Check for Spam" button when no comments were eligible to be checked.
-* Improved Akismet's AMP compatibility.
+* Added links to additional information on API usage notifications.
+* Reduced the number of network requests required for a comment page when running Akismet.
+* Improved compatibility with the most popular contact form plugins.
+* Improved API usage buttons for clarity on what upgrade is needed.
-= 4.1.1 =
-*Release Date - 31 January 2019*
+= 4.1.12 =
+*Release Date - 3 September 2021*
-* Fixed the "Setup Akismet" notice so it resizes responsively.
-* Only highlight the "Save Changes" button in the Akismet config when changes have been made.
-* The count of comments in your spam queue shown on the dashboard show now always be up-to-date.
+* Fixed "Use of undefined constant" notice.
+* Improved styling of alert notices.
-= 4.1 =
-*Release Date - 12 November 2018*
+= 4.1.11 =
+*Release Date - 23 August 2021*
-* Added a WP-CLI method for retrieving stats.
-* Hooked into the new "Personal Data Eraser" functionality from WordPress 4.9.6.
-* Added functionality to clear outdated alerts from Akismet.com.
-
-= 4.0.8 =
-*Release Date - 19 June 2018*
-
-* Improved the grammar and consistency of the in-admin privacy related notes (notice and config).
-* Revised in-admin explanation of the comment form privacy notice to make its usage clearer.
-* Added `rel="nofollow noopener"` to the comment form privacy notice to improve SEO and security.
-
-= 4.0.7 =
-*Release Date - 28 May 2018*
-
-* 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.
-* 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."
-* Only show in-admin privacy notice if Akismet has an API Key configured
-
-= 4.0.6 =
-*Release Date - 26 May 2018*
-
-* Moved away from using `empty( get_option() )` to instantiating a variable to be compatible with older versions of PHP (5.3, 5.4, etc).
-
-= 4.0.5 =
-*Release Date - 26 May 2018*
-
-* Corrected version number after tagging. Sorry...
-
-= 4.0.4 =
-*Release Date - 26 May 2018*
-
-* Added a hook to provide Akismet-specific privacy information for a site's privacy policy.
-* Added tools to control the display of a privacy related notice under comment forms.
-* Fixed HTML in activation failure message to close META and HEAD tag properly.
-* Fixed a bug that would sometimes prevent Akismet from being correctly auto-configured.
-
-= 4.0.3 =
-*Release Date - 19 February 2018*
-
-* Added a scheduled task to remove entries in wp_commentmeta that no longer have corresponding comments in wp_comments.
-* 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.
-
-= 4.0.2 =
-*Release Date - 18 December 2017*
-
-* Fixed a bug that could cause Akismet to recheck a comment that has already been manually approved or marked as spam.
-* 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.
-
-= 4.0.1 =
-*Release Date - 6 November 2017*
-
-* Fixed a bug that could prevent some users from connecting Akismet via their Jetpack connection.
-* Ensured that any pending Akismet-related events are unscheduled if the plugin is deactivated.
-* Allow some JavaScript to be run asynchronously to avoid affecting page render speeds.
-
-= 4.0 =
-*Release Date - 19 September 2017*
-
-* Added REST API endpoints for configuring Akismet and retrieving stats.
-* Increased the minimum supported WordPress version to 4.0.
-* Added compatibility with comments submitted via the REST API.
-* Improved the progress indicator on the "Check for Spam" button.
-
-= 3.3.4 =
-*Release Date - 3 August 2017*
-
-* Disabled Akismet's debug log output by default unless AKISMET_DEBUG is defined.
-* URL previews now begin preloading when the mouse moves near them in the comments section of wp-admin.
-* 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.
-* Fixed a bug that was preventing an error from being shown when a site can't reach Akismet's servers.
-
-= 3.3.3 =
-*Release Date - 13 July 2017*
-
-* Reduced amount of bandwidth used by the URL Preview feature.
-* Improved the admin UI when the API key is manually pre-defined for the site.
-* Removed a workaround for WordPress installations older than 3.3 that will improve Akismet's compatibility with other plugins.
-* The number of spam blocked that is displayed on the WordPress dashboard will now be more accurate and updated more frequently.
-* Fixed a bug in the Akismet widget that could cause PHP warnings.
-
-= 3.3.2 =
-*Release Date - 10 May 2017*
-
-* Fixed a bug causing JavaScript errors in some browsers.
+* Added support for Akismet API usage notifications on Akismet settings and edit-comments admin pages.
+* Added support for the deleted_comment action when bulk-deleting comments from Spam.
-= 3.3.1 =
-*Release Date - 2 May 2017*
-
-* Improve performance by only requesting the akismet_comment_nonce option when absolutely necessary.
-* Fixed two bugs that could cause PHP warnings.
-* Fixed a bug that was preventing the "Remove author URL" feature from working after a comment was edited using "Quick Edit."
-* Fixed a bug that was preventing the URL preview feature from working after a comment was edited using "Quick Edit."
-
-= 3.3 =
-*Release Date - 23 February 2017*
-
-* Updated the Akismet admin pages with a new clean design.
-* Fixed bugs preventing the `akismet_add_comment_nonce` and `akismet_update_alert` wrapper functions from working properly.
-* Fixed bug preventing the loading indicator from appearing when re-checking all comments for spam.
-* Added a progress indicator to the "Check for Spam" button.
-* Added a success message after manually rechecking the Pending queue for spam.
-
-= 3.2 =
-*Release Date - 6 September 2016*
-
-* Added a WP-CLI module. You can now check comments and recheck the moderation queue from the command line.
-* Stopped using the deprecated jQuery function `.live()`.
-* Fixed a bug in `remove_comment_author_url()` and `add_comment_author_url()` that could generate PHP notices.
-* Fixed a bug that could cause an infinite loop for sites with very very very large comment IDs.
-* Fixed a bug that could cause the Akismet widget title to be blank.
-
-= 3.1.11 =
-*Release Date - 12 May 2016*
-
-* Fixed a bug that could cause the "Check for Spam" button to skip some comments.
-* Fixed a bug that could prevent some spam submissions from being sent to Akismet.
-* Updated all links to use https:// when possible.
-* Disabled Akismet debug logging unless WP_DEBUG and WP_DEBUG_LOG are both enabled.
-
-= 3.1.10 =
-*Release Date - 1 April 2016*
-
-* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
-* 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.
-* Fixed a bug that could have caused avoidable PHP warnings in the error log.
-
-= 3.1.9 =
-*Release Date - 28 March 2016*
-
-* Add compatibility with Jetpack so that Jetpack can automatically configure Akismet settings when appropriate.
-* Fixed a bug preventing some comment data from being sent to Akismet.
-
-= 3.1.8 =
-*Release Date - 4 March 2016*
-
-* Fixed a bug preventing Akismet from being used with some plugins that rewrite admin URLs.
-* Reduced the amount of bandwidth used on Akismet API calls
-* Reduced the amount of space Akismet uses in the database
-* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
-
-= 3.1.7 =
-*Release Date - 4 January 2016*
-
-* Added documentation for the 'akismet_comment_nonce' filter.
-* The post-install activation button is now accessible to screen readers and keyboard-only users.
-* Fixed a bug that was preventing the "Remove author URL" feature from working in WordPress 4.4
-
-= 3.1.6 =
-*Release Date - 14 December 2015*
-
-* Improve the notices shown after activating Akismet.
-* Update some strings to allow for the proper plural forms in all languages.
-
-= 3.1.5 =
-*Release Date - 13 October 2015*
-
-* Closes a potential XSS vulnerability.
-
-= 3.1.4 =
-*Release Date - 24 September 2015*
-
-* Fixed a bug that was preventing some users from automatically connecting using Jetpack if they didn't have a current Akismet subscription.
-* Fixed a bug that could cause comments caught as spam to be placed in the Pending queue.
-* Error messages and instructions have been simplified to be more understandable.
-* Link previews are enabled for all links inside comments, not just the author's website link.
-
-= 3.1.3 =
-*Release Date - 6 July 2015*
-
-* 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.
-
-= 3.1.2 =
-*Release Date - 7 June 2015*
-
-* Reduced the amount of space Akismet uses in the commentmeta table.
-* Fixed a bug where some comments with quotes in the author name weren't getting history entries
-* Pre-emptive security improvements to ensure that the Akismet plugin can't be used by attackers to compromise a WordPress installation.
-* 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.
-* When deactivating the plugin, notify the Akismet API so the site can be marked as inactive.
-* Clearer error messages.
-
-= 3.1.1 =
-*Release Date - 17th March, 2015*
-
-* Improvements to the "Remove comment author URL" JavaScript
-* Include the pingback pre-check from the 2.6 branch.
-
-= 3.1 =
-*Release Date - 11th March, 2015*
-
-* Use HTTPS by default for all requests to Akismet.
-* Fix for a situation where Akismet might strip HTML from a comment.
-
-= 3.0.4 =
-*Release Date - 11th December, 2014*
-
-* Fix to make .htaccess compatible with Apache 2.4.
-* Fix to allow removal of https author URLs.
-* Fix to avoid stripping part of the author URL when removing and re-adding.
-* Removed the "Check for Spam" button from the "Trash" and "Approved" queues, where it would have no effect.
-* Allow automatic API key configuration when Jetpack is installed and connected to a WordPress.com account
-
-= 3.0.3 =
-*Release Date - 3rd November, 2014*
-
-* Fix for sending the wrong data to delete_comment action that could have prevented old spam comments from being deleted.
-* Added a filter to disable logging of Akismet debugging information.
-* Added a filter for the maximum comment age when deleting old spam comments.
-* Added a filter for the number per batch when deleting old spam comments.
-* Removed the "Check for Spam" button from the Spam folder.
-
-= 3.0.2 =
-*Release Date - 18th August, 2014*
-
-* Performance improvements.
-* Fixed a bug that could truncate the comment data being sent to Akismet for checking.
-
-= 3.0.1 =
-*Release Date - 9th July, 2014*
-
-* Removed dependency on PHP's fsockopen function
-* Fix spam/ham reports to work when reported outside of the WP dashboard, e.g., from Notifications or the WP app
-* Remove jQuery dependency for comment form JavaScript
-* Remove unnecessary data from some Akismet comment meta
-* Suspended keys will now result in all comments being put in moderation, not spam.
-
-= 3.0.0 =
-*Release Date - 15th April, 2014*
-
-* Move Akismet to Settings menu
-* Drop Akismet Stats menu
-* Add stats snapshot to Akismet settings
-* Add Akismet subscription details and status to Akismet settings
-* Add contextual help for each page
-* Improve Akismet setup to use Jetpack to automate plugin setup
-* Fix "Check for Spam" to use AJAX to avoid page timing out
-* Fix Akismet settings page to be responsive
-* Drop legacy code
-* Tidy up CSS and Javascript
-* Replace the old discard setting with a new "discard pervasive spam" feature.
-
-= 2.6.0 =
-*Release Date - 18th March, 2014*
-
-* Add ajax paging to the check for spam button to handle large volumes of comments
-* Optimize javascript and add localization support
-* Fix bug in link to spam comments from right now dashboard widget
-* Fix bug with deleting old comments to avoid timeouts dealing with large volumes of comments
-* Include X-Pingback-Forwarded-For header in outbound WordPress pingback verifications
-* Add pre-check for pingbacks, to stop spam before an outbound verification request is made
-
-= 2.5.9 =
-*Release Date - 1st August, 2013*
-
-* Update 'Already have a key' link to redirect page rather than depend on javascript
-* Fix some non-translatable strings to be translatable
-* Update Activation banner in plugins page to redirect user to Akismet config page
-
-= 2.5.8 =
-*Release Date - 20th January, 2013*
-
-* Simplify the activation process for new users
-* Remove the reporter_ip parameter
-* Minor preventative security improvements
-
-= 2.5.7 =
-*Release Date - 13th December, 2012*
-
-* FireFox Stats iframe preview bug
-* Fix mshots preview when using https
-* Add .htaccess to block direct access to files
-* Prevent some PHP notices
-* Fix Check For Spam return location when referrer is empty
-* Fix Settings links for network admins
-* Fix prepare() warnings in WP 3.5
-
-= 2.5.6 =
-*Release Date - 26th April, 2012*
-
-* Prevent retry scheduling problems on sites where wp_cron is misbehaving
-* Preload mshot previews
-* Modernize the widget code
-* Fix a bug where comments were not held for moderation during an error condition
-* Improve the UX and display when comments are temporarily held due to an error
-* Make the Check For Spam button force a retry when comments are held due to an error
-* Handle errors caused by an invalid key
-* Don't retry comments that are too old
-* Improve error messages when verifying an API key
-
-= 2.5.5 =
-*Release Date - 11th January, 2012*
-
-* Add nonce check for comment author URL remove action
-* Fix the settings link
-
-= 2.5.4 =
-*Release Date - 5th January, 2012*
-
-* Limit Akismet CSS and Javascript loading in wp-admin to just the pages that need it
-* Added author URL quick removal functionality
-* Added mShot preview on Author URL hover
-* Added empty index.php to prevent directory listing
-* Move wp-admin menu items under Jetpack, if it is installed
-* Purge old Akismet comment meta data, default of 15 days
-
-= 2.5.3 =
-*Release Date - 8th Febuary, 2011*
-
-* Specify the license is GPL v2 or later
-* Fix a bug that could result in orphaned commentmeta entries
-* Include hotfix for WordPress 3.0.5 filter issue
-
-= 2.5.2 =
-*Release Date - 14th January, 2011*
-
-* Properly format the comment count for author counts
-* Look for super admins on multisite installs when looking up user roles
-* Increase the HTTP request timeout
-* Removed padding for author approved count
-* Fix typo in function name
-* Set Akismet stats iframe height to fixed 2500px. Better to have one tall scroll bar than two side by side.
-
-= 2.5.1 =
-*Release Date - 17th December, 2010*
-
-* Fix a bug that caused the "Auto delete" option to fail to discard comments correctly
-* Remove the comment nonce form field from the 'Akismet Configuration' page in favor of using a filter, akismet_comment_nonce
-* Fixed padding bug in "author" column of posts screen
-* Added margin-top to "cleared by ..." badges on dashboard
-* Fix possible error when calling akismet_cron_recheck()
-* Fix more PHP warnings
-* Clean up XHTML warnings for comment nonce
-* Fix for possible condition where scheduled comment re-checks could get stuck
-* Clean up the comment meta details after deleting a comment
-* Only show the status badge if the comment status has been changed by someone/something other than Akismet
-* Show a 'History' link in the row-actions
-* Translation fixes
-* Reduced font-size on author name
-* Moved "flagged by..." notification to top right corner of comment container and removed heavy styling
-* Hid "flagged by..." notification while on dashboard
-
-= 2.5.0 =
-*Release Date - 7th December, 2010*
-
-* Track comment actions under 'Akismet Status' on the edit comment screen
-* Fix a few remaining deprecated function calls ( props Mike Glendinning )
-* Use HTTPS for the stats IFRAME when wp-admin is using HTTPS
-* Use the WordPress HTTP class if available
-* Move the admin UI code to a separate file, only loaded when needed
-* Add cron retry feature, to replace the old connectivity check
-* Display Akismet status badge beside each comment
-* Record history for each comment, and display it on the edit page
-* Record the complete comment as originally submitted in comment_meta, to use when reporting spam and ham
-* Highlight links in comment content
-* New option, "Show the number of comments you've approved beside each comment author."
-* New option, "Use a nonce on the comment form."
-
-= 2.4.0 =
-*Release Date - 23rd August, 2010*
-
-* Spell out that the license is GPLv2
-* Fix PHP warnings
-* Fix WordPress deprecated function calls
-* Fire the delete_comment action when deleting comments
-* Move code specific for older WP versions to legacy.php
-* General code clean up
-
-= 2.3.0 =
-*Release Date - 5th June, 2010*
-
-* Fix "Are you sure" nonce message on config screen in WPMU
-* Fix XHTML compliance issue in sidebar widget
-* Change author link; remove some old references to WordPress.com accounts
-* Localize the widget title (core ticket #13879)
-
-= 2.2.9 =
-*Release Date - 2nd June, 2010*
-
-* Eliminate a potential conflict with some plugins that may cause spurious reports
+= 4.1.10 =
+*Release Date - 6 July 2021*
-= 2.2.8 =
-*Release Date - 27th May, 2010*
+* Simplified the code around checking comments in REST API and XML-RPC requests.
+* Updated Plus plan terminology in notices to match current subscription names.
+* Added `rel="noopener"` to the widget link to avoid warnings in Google Lighthouse.
+* Set the Akismet JavaScript as deferred instead of async to improve responsiveness.
+* Improved the preloading of screenshot popups on the edit comments admin page.
-* Fix bug in initial comment check for ipv6 addresses
-* Report comments as ham when they are moved from spam to moderation
-* Report comments as ham when clicking undo after spam
-* Use transition_comment_status action when available instead of older actions for spam/ham submissions
-* Better diagnostic messages when PHP network functions are unavailable
-* Better handling of comments by logged-in users
+= 4.1.9 =
+*Release Date - 2 March 2021*
-= 2.2.7 =
-*Release Date - 17th December, 2009*
+* Improved handling of pingbacks in XML-RPC multicalls
-* Add a new AKISMET_VERSION constant
-* Reduce the possibility of over-counting spam when another spam filter plugin is in use
-* Disable the connectivity check when the API key is hard-coded for WPMU
+= 4.1.8 =
+*Release Date - 6 January 2021*
-= 2.2.6 =
-*Release Date - 20th July, 2009*
+* Fixed missing fields in submit-spam and submit-ham calls that could lead to reduced accuracy.
+* Fixed usage of deprecated jQuery function.
-* Fix a global warning introduced in 2.2.5
-* Add changelog and additional readme.txt tags
-* Fix an array conversion warning in some versions of PHP
-* Support a new WPCOM_API_KEY constant for easier use with WordPress MU
+= 4.1.7 =
+*Release Date - 22 October 2020*
-= 2.2.5 =
-*Release Date - 13th July, 2009*
+* 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.
+* Don't use wp_blacklist_check when the new wp_check_comment_disallowed_list function is available.
-* Include a new Server Connectivity diagnostic check, to detect problems caused by firewalls
+= 4.1.6 =
+*Release Date - 4 June 2020*
-= 2.2.4 =
-*Release Date - 3rd June, 2009*
+* Disable "Check for Spam" button until the page is loaded to avoid errors with clicking through to queue recheck endpoint directly.
+* Add filter "akismet_enable_mshots" to allow disabling screenshot popups on the edit comments admin page.
-* Fixed a key problem affecting the stats feature in WordPress MU
-* Provide additional blog information in Akismet API calls
+For older changelog entries, please see the [additional changelog.txt file](https://plugins.svn.wordpress.org/akismet/trunk/changelog.txt) delivered with the plugin.
diff --git a/plugins/akismet/views/config.php b/plugins/akismet/views/config.php
index 6bbcd6d4..df24b91d 100644
--- a/plugins/akismet/views/config.php
+++ b/plugins/akismet/views/config.php
@@ -1,3 +1,9 @@
+<?php
+
+//phpcs:disable VariableAnalysis
+// There are "undefined" variables here because they're defined in the code that includes this file as a template.
+
+?>
<div id="akismet-plugin-container">
<div class="akismet-masthead">
<div class="akismet-masthead__inside-container">
@@ -53,7 +59,7 @@
</div>
<?php endif;?>
- <?php if ( $akismet_user ):?>
+ <?php if ( $akismet_user ) : ?>
<div class="akismet-card">
<div class="akismet-section-header">
<div class="akismet-section-header__label">
diff --git a/plugins/akismet/views/enter.php b/plugins/akismet/views/enter.php
index 0a79ca97..23dda40a 100644
--- a/plugins/akismet/views/enter.php
+++ b/plugins/akismet/views/enter.php
@@ -1,5 +1,5 @@
<div class="akismet-enter-api-key-box centered">
- <a href="#"><?php esc_html_e( 'Manually enter an API key' ); ?></a>
+ <a href="#"><?php esc_html_e( 'Manually enter an API key', 'akismet' ); ?></a>
<div class="enter-api-key">
<form action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="post">
<?php wp_nonce_field( Akismet_Admin::NONCE ) ?>
diff --git a/plugins/akismet/views/notice.php b/plugins/akismet/views/notice.php
index fa098b8b..28dc6722 100644
--- a/plugins/akismet/views/notice.php
+++ b/plugins/akismet/views/notice.php
@@ -4,7 +4,7 @@
// There are "undefined" variables here because they're defined in the code that includes this file as a template.
?>
-<?php if ( $type == 'plugin' ) :?>
+<?php if ( $type == 'plugin' ) : ?>
<div class="updated" id="akismet_setup_prompt">
<form name="akismet_activate" action="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" method="POST">
<div class="akismet_activate">
@@ -18,7 +18,7 @@
</div>
</form>
</div>
-<?php elseif ( $type == 'spam-check' ) :?>
+<?php elseif ( $type == 'spam-check' ) : ?>
<div class="notice notice-warning">
<p><strong><?php esc_html_e( 'Akismet has detected a problem.', 'akismet' );?></strong></p>
<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>
@@ -26,7 +26,7 @@
<p><?php echo $link_text; ?></p>
<?php } ?>
</div>
-<?php elseif ( $type == 'alert' ) :?>
+<?php elseif ( $type == 'alert' ) : ?>
<div class='error'>
<p><strong><?php printf( esc_html__( 'Akismet Error Code: %s', 'akismet' ), $code ); ?></strong></p>
<p><?php echo esc_html( $msg ); ?></p>
@@ -38,49 +38,49 @@
?>
</p>
</div>
-<?php elseif ( $type == 'notice' ) :?>
+<?php elseif ( $type == 'notice' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php echo $notice_header; ?></h3>
<p class="akismet-description">
<?php echo $notice_text; ?>
</p>
</div>
-<?php elseif ( $type == 'missing-functions' ) :?>
+<?php elseif ( $type == 'missing-functions' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php esc_html_e('Network functions are disabled.', 'akismet'); ?></h3>
<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>
</div>
-<?php elseif ( $type == 'servers-be-down' ) :?>
+<?php elseif ( $type == 'servers-be-down' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php esc_html_e("Your site can&#8217;t connect to the Akismet servers.", 'akismet'); ?></h3>
<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>
</div>
-<?php elseif ( $type == 'active-dunning' ) :?>
+<?php elseif ( $type == 'active-dunning' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status"><?php esc_html_e("Please update your payment information.", 'akismet'); ?></h3>
<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>
</div>
-<?php elseif ( $type == 'cancelled' ) :?>
+<?php elseif ( $type == 'cancelled' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status"><?php esc_html_e("Your Akismet plan has been cancelled.", 'akismet'); ?></h3>
<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>
</div>
-<?php elseif ( $type == 'suspended' ) :?>
+<?php elseif ( $type == 'suspended' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php esc_html_e("Your Akismet subscription is suspended.", 'akismet'); ?></h3>
<p class="akismet-description"><?php printf( __('Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet'), 'https://akismet.com/contact/'); ?></p>
</div>
-<?php elseif ( $type == 'active-notice' && $time_saved ) :?>
+<?php elseif ( $type == 'active-notice' && $time_saved ) : ?>
<div class="akismet-alert akismet-active">
<h3 class="akismet-key-status"><?php echo esc_html( $time_saved ); ?></h3>
<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>
</div>
-<?php elseif ( $type == 'missing' ) :?>
+<?php elseif ( $type == 'missing' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php esc_html_e( 'There is a problem with your API key.', 'akismet'); ?></h3>
<p class="akismet-description"><?php printf( __('Please contact <a href="%s" target="_blank">Akismet support</a> for assistance.', 'akismet'), 'https://akismet.com/contact/'); ?></p>
</div>
-<?php elseif ( $type == 'no-sub' ) :?>
+<?php elseif ( $type == 'no-sub' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status failed"><?php esc_html_e( 'You don&#8217;t have an Akismet plan.', 'akismet'); ?></h3>
<p class="akismet-description">
@@ -107,30 +107,83 @@
<p class="akismet-description"><?php printf( __( 'Would you like to <a href="%s">check pending comments</a>?', 'akismet' ), esc_url( $check_pending_link ) ); ?></p>
<?php } ?>
</div>
-<?php elseif ( $type == 'new-key-invalid' ) :?>
+<?php elseif ( $type == 'new-key-invalid' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status"><?php esc_html_e( 'The key you entered is invalid. Please double-check it.' , 'akismet'); ?></h3>
</div>
-<?php elseif ( $type == 'existing-key-invalid' ) :?>
+<?php elseif ( $type == 'existing-key-invalid' ) : ?>
<div class="akismet-alert akismet-critical">
- <h3 class="akismet-key-status"><?php esc_html_e( 'Your API key is no longer valid. Please enter a new key or contact support@akismet.com.' , 'akismet'); ?></h3>
+ <h3 class="akismet-key-status"><?php echo esc_html( __( 'Your API key is no longer valid.', 'akismet' ) ); ?></h3>
+ <p class="akismet-description">
+ <?php
+
+ echo wp_kses(
+ sprintf(
+ /* translators: The placeholder is a URL. */
+ __( 'Please enter a new key or <a href="%s" target="_blank">contact Akismet support</a>.', 'akismet' ),
+ 'https://akismet.com/contact/'
+ ),
+ array(
+ 'a' => array(
+ 'href' => true,
+ 'target' => true,
+ ),
+ )
+ );
+
+ ?>
+ </p>
</div>
-<?php elseif ( $type == 'new-key-failed' ) :?>
+<?php elseif ( $type == 'new-key-failed' ) : ?>
<div class="akismet-alert akismet-critical">
<h3 class="akismet-key-status"><?php esc_html_e( 'The API key you entered could not be verified.' , 'akismet'); ?></h3>
- <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>
+ <p class="akismet-description">
+ <?php
+
+ echo wp_kses(
+ sprintf(
+ /* translators: The placeholder is a URL. */
+ __( '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/'
+ ),
+ array(
+ 'a' => array(
+ 'href' => true,
+ 'target' => true,
+ ),
+ )
+ );
+
+ ?>
+ </p>
</div>
-<?php elseif ( $type == 'limit-reached' && in_array( $level, array( 'yellow', 'red' ) ) ) :?>
+<?php elseif ( $type == 'limit-reached' && in_array( $level, array( 'yellow', 'red' ) ) ) : ?>
<div class="akismet-alert akismet-critical">
<?php if ( $level == 'yellow' ): ?>
- <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>
+ <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>
<p class="akismet-description">
- <?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/' ); ?>
+ <?php
+
+ echo wp_kses(
+ sprintf(
+ /* translators: The placeholder is a URL. */
+ __( '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' ),
+ 'https://docs.akismet.com/billing/add-more-sites/'
+ ),
+ array(
+ 'a' => array(
+ 'href' => true,
+ 'target' => true,
+ ),
+ )
+ );
+
+ ?>
<br /><br />
<?php printf( __( 'Please <a href="%s" target="_blank">contact our support team</a> with any questions.', 'akismet' ), 'https://akismet.com/contact/'); ?>
</p>
<?php elseif ( $level == 'red' ): ?>
- <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>
+ <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>
<p class="akismet-description">
<?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/' ); ?>
<br /><br />
@@ -138,10 +191,96 @@
</p>
<?php endif; ?>
</div>
-<?php elseif ( $type == 'privacy' ) :?>
-<div class="notice notice-warning is-dismissible" id="akismet-privacy-notice-admin-notice">
- <p><strong><?php esc_html_e( 'Akismet & Privacy.', 'akismet' );?></strong></p>
- <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>
- <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>
+<?php elseif ( $type == 'usage-limit' && isset( Akismet::$limit_notices[ $code ] ) ) : ?>
+<div class="error akismet-usage-limit-alert">
+ <div class="akismet-usage-limit-logo">
+ <img src="<?php echo esc_url( plugins_url( '../_inc/img/logo-a-2x.png', __FILE__ ) ); ?>" alt="Akismet" />
+ </div>
+ <div class="akismet-usage-limit-text">
+ <h3>
+ <?php
+ switch ( Akismet::$limit_notices[ $code ] ) {
+ case 'FIRST_MONTH_OVER_LIMIT':
+ case 'SECOND_MONTH_OVER_LIMIT':
+ esc_html_e( 'Your Akismet account usage is over your plan&#8217;s limit', 'akismet' );
+ break;
+ case 'THIRD_MONTH_APPROACHING_LIMIT':
+ esc_html_e( 'Your Akismet account usage is approaching your plan&#8217;s limit', 'akismet' );
+ break;
+ case 'THIRD_MONTH_OVER_LIMIT':
+ case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
+ esc_html_e( 'Your account has been restricted', 'akismet' );
+ break;
+ default:
+ }
+ ?>
+ </h3>
+ <p>
+ <?php
+ switch ( Akismet::$limit_notices[ $code ] ) {
+ case 'FIRST_MONTH_OVER_LIMIT':
+ echo esc_html(
+ sprintf(
+ /* translators: The first placeholder is a date, the second is a (formatted) number, the third is another formatted number. */
+ __( 'Since %1$s, your account made %2$s API calls, compared to your plan&#8217;s limit of %3$s.', 'akismet' ),
+ esc_html( gmdate( 'F' ) . ' 1' ),
+ number_format( $api_calls ),
+ number_format( $usage_limit )
+ )
+ );
+
+ echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
+ echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
+ echo '</a>';
+
+ break;
+ case 'SECOND_MONTH_OVER_LIMIT':
+ 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' ) );
+
+ echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
+ echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
+ echo '</a>';
+
+ break;
+ case 'THIRD_MONTH_APPROACHING_LIMIT':
+ 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' ) );
+
+ echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
+ echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
+ echo '</a>';
+
+ break;
+ case 'THIRD_MONTH_OVER_LIMIT':
+ case 'FOUR_PLUS_MONTHS_OVER_LIMIT':
+ 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' ) );
+
+ echo '<a href="https://docs.akismet.com/akismet-api-usage-limits/" target="_blank">';
+ echo esc_html( __( 'Learn more about usage limits.', 'akismet' ) );
+ echo '</a>';
+
+ break;
+ default:
+ }
+ ?>
+ </p>
+ </div>
+ <div class="akismet-usage-limit-cta">
+ <a href="<?php echo esc_attr( $upgrade_url ); ?>" class="button" target="_blank">
+ <?php
+ // If only a qty upgrade is required, show a more generic message.
+ if ( ! empty( $upgrade_type ) && 'qty' === $upgrade_type ) {
+ esc_html_e( 'Upgrade your Subscription Level', 'akismet' );
+ } else {
+ echo esc_html(
+ sprintf(
+ /* translators: The placeholder is the name of a subscription level, like "Plus" or "Enterprise" . */
+ __( 'Upgrade to %s', 'akismet' ),
+ $upgrade_plan
+ )
+ );
+ }
+ ?>
+ </a>
+ </div>
</div>
-<?php endif;?> \ No newline at end of file
+<?php endif; ?>
diff --git a/plugins/akismet/views/setup.php b/plugins/akismet/views/setup.php
index d21c89a9..50780090 100644
--- a/plugins/akismet/views/setup.php
+++ b/plugins/akismet/views/setup.php
@@ -1,5 +1,4 @@
-<h3><?php esc_html_e( 'Set Up Akismet' , 'akismet' );?></h3>
-<div class="akismet-right">
+<div class="akismet-setup-instructions">
+ <p><?php esc_html_e( 'Set up your Akismet account to enable spam filtering on this site.', 'akismet' ); ?></p>
<?php Akismet::view( 'get', array( 'text' => __( 'Set up your Akismet account' , 'akismet' ), 'classes' => array( 'akismet-button', 'akismet-is-primary' ) ) ); ?>
</div>
-<p><?php esc_html_e( 'Set up your Akismet account to enable spam filtering on this site.', 'akismet' ); ?></p> \ No newline at end of file
diff --git a/plugins/akismet/views/stats.php b/plugins/akismet/views/stats.php
index 2302c11a..81d82ce4 100644
--- a/plugins/akismet/views/stats.php
+++ b/plugins/akismet/views/stats.php
@@ -1,7 +1,7 @@
<div id="akismet-plugin-container">
<div class="akismet-masthead">
<div class="akismet-masthead__inside-container">
- <a href="<?php echo esc_url( Akismet_Admin::get_page_url() );?>" class="akismet-right"><?php esc_html_e( 'Akismet Settings' , 'akismet' ); ?></a>
+ <a href="<?php echo esc_url( Akismet_Admin::get_page_url() ); ?>" class="akismet-right"><?php esc_html_e( 'Anti-Spam Settings', 'akismet' ); ?></a>
<div class="akismet-masthead__logo-container">
<img class="akismet-masthead__logo" src="<?php echo esc_url( plugins_url( '../_inc/img/logo-full-2x.png', __FILE__ ) ); ?>" alt="Akismet" />
</div>