Akismet Anti-Spam - Version 3.3.1

Version Description

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."
Download this release

Release Info

Developer cfinke
Plugin Icon 128x128 Akismet Anti-Spam
Version 3.3.1
Comparing to
See all releases

Code changes from version 3.3 to 3.3.1

Files changed (6) hide show
  1. _inc/akismet.css +2 -2
  2. _inc/akismet.js +57 -35
  3. _inc/img/logo-full-2x.png +0 -0
  4. akismet.php +2 -2
  5. class.akismet.php +54 -26
  6. readme.txt +10 -2
_inc/akismet.css CHANGED
@@ -16,12 +16,12 @@
16
  text-decoration: inherit;
17
  color: inherit;
18
  }
19
- #the-comment-list .remove_url {
20
  margin-left: 3px;
21
  color: #999;
22
  padding: 2px 3px 2px 0;
23
  }
24
- #the-comment-list .remove_url:hover {
25
  color: #A7301F;
26
  font-weight: bold;
27
  padding: 2px 2px 2px 0;
16
  text-decoration: inherit;
17
  color: inherit;
18
  }
19
+ #the-comment-list .akismet_remove_url {
20
  margin-left: 3px;
21
  color: #999;
22
  padding: 2px 3px 2px 0;
23
  }
24
+ #the-comment-list .akismet_remove_url:hover {
25
  color: #A7301F;
26
  font-weight: bold;
27
  padding: 2px 2px 2px 0;
_inc/akismet.js CHANGED
@@ -11,31 +11,10 @@ jQuery( function ( $ ) {
11
  var thisId = $(this).attr('commentid');
12
  $(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
13
  });
14
- $('#the-comment-list')
15
- .find('tr.comment, tr[id ^= "comment-"]')
16
- .find('.column-author a[href^="http"]:first') // Ignore mailto: links, which would be the comment author's email.
17
- .each(function () {
18
- var linkHref = $(this).attr( 'href' );
19
-
20
- // Ignore any links to the current domain, which are diagnostic tools, like the IP address link
21
- // or any other links another plugin might add.
22
- var currentHostParts = document.location.href.split( '/' );
23
- var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
24
-
25
- if ( linkHref.indexOf( currentHost ) != 0 ) {
26
- var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
27
-
28
- $(this)
29
- .attr("id", "author_comment_url_"+ thisCommentId[1])
30
- .after(
31
- $( '<a href="#" class="remove_url">x</a>' )
32
- .attr( 'commentid', thisCommentId[1] )
33
- .attr( 'title', WPAkismet.strings['Remove this URL'] )
34
- );
35
- }
36
- });
37
 
38
- $( '#the-comment-list' ).on( 'click', '.remove_url', function () {
39
  var thisId = $(this).attr('commentid');
40
  var data = {
41
  action: 'comment_author_deurl',
@@ -103,7 +82,7 @@ jQuery( function ( $ ) {
103
  });
104
 
105
  // Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
106
- $( 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, table.comments td.comment p a' ).mouseover( function () {
107
  clearTimeout( mshotRemovalTimer );
108
 
109
  if ( $( '.akismet-mshot' ).length > 0 ) {
@@ -120,7 +99,7 @@ jQuery( function ( $ ) {
120
  clearTimeout( mshotSecondTryTimer );
121
  clearTimeout( mshotThirdTryTimer );
122
 
123
- var thisHref = $.URLEncode( $( this ).attr( 'href' ) );
124
 
125
  var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="//s0.wordpress.com/mshots/v1/' + thisHref + '?w=450" width="450" height="338" class="mshot-image" /></div>' );
126
  mShot.data( 'link', this );
@@ -141,7 +120,7 @@ jQuery( function ( $ ) {
141
  }, 12000 );
142
 
143
  $( 'body' ).append( mShot );
144
- } ).mouseout( function () {
145
  mshotRemovalTimer = setTimeout( function () {
146
  clearTimeout( mshotSecondTryTimer );
147
  clearTimeout( mshotThirdTryTimer );
@@ -194,11 +173,54 @@ jQuery( function ( $ ) {
194
  if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
195
  $( '.checkforspam' ).click();
196
  }
197
- });
198
- // URL encode plugin
199
- jQuery.extend({URLEncode:function(c){var o='';var x=0;c=c.toString();var r=/(^[a-zA-Z0-9_.]*)/;
200
- while(x<c.length){var m=r.exec(c.substr(x));
201
- if(m!=null && m.length>1 && m[1]!=''){o+=m[1];x+=m[1].length;
202
- }else{if(c[x]==' ')o+='+';else{var d=c.charCodeAt(x);var h=d.toString(16);
203
- o+='%'+(h.length<2?'0':'')+h.toUpperCase();}x++;}}return o;}
204
- });
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
11
  var thisId = $(this).attr('commentid');
12
  $(this).insertAfter('#comment-' + thisId + ' .author strong:first').show();
13
  });
14
+
15
+ akismet_enable_comment_author_url_removal();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
 
17
+ $( '#the-comment-list' ).on( 'click', '.akismet_remove_url', function () {
18
  var thisId = $(this).attr('commentid');
19
  var data = {
20
  action: 'comment_author_deurl',
82
  });
83
 
84
  // Show a preview image of the hovered URL. Applies to author URLs and URLs inside the comments.
85
+ $( '#the-comment-list' ).on( 'mouseover', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
86
  clearTimeout( mshotRemovalTimer );
87
 
88
  if ( $( '.akismet-mshot' ).length > 0 ) {
99
  clearTimeout( mshotSecondTryTimer );
100
  clearTimeout( mshotThirdTryTimer );
101
 
102
+ var thisHref = encodeURIComponent( $( this ).attr( 'href' ) );
103
 
104
  var mShot = $( '<div class="akismet-mshot mshot-container"><div class="mshot-arrow"></div><img src="//s0.wordpress.com/mshots/v1/' + thisHref + '?w=450" width="450" height="338" class="mshot-image" /></div>' );
105
  mShot.data( 'link', this );
120
  }, 12000 );
121
 
122
  $( 'body' ).append( mShot );
123
+ } ).on( 'mouseout', 'a[id^="author_comment_url"], tr.pingback td.column-author a:first-of-type, td.comment p a', function () {
124
  mshotRemovalTimer = setTimeout( function () {
125
  clearTimeout( mshotSecondTryTimer );
126
  clearTimeout( mshotThirdTryTimer );
173
  if ( "start_recheck" in WPAkismet && WPAkismet.start_recheck ) {
174
  $( '.checkforspam' ).click();
175
  }
176
+
177
+ if ( typeof 'MutationObserver' !== 'undefined' ) {
178
+ // Dynamically add the "X" next the the author URL links when a comment is quick-edited.
179
+ var comment_list_container = document.getElementById( 'the-comment-list' );
180
+
181
+ if ( comment_list_container ) {
182
+ var observer = new MutationObserver( function ( mutations ) {
183
+ for ( var i = 0, _len = mutations.length; i < _len; i++ ) {
184
+ if ( mutations[i].addedNodes.length > 0 ) {
185
+ akismet_enable_comment_author_url_removal();
186
+
187
+ // Once we know that we'll have to check for new author links, skip the rest of the mutations.
188
+ break;
189
+ }
190
+ }
191
+ } );
192
+
193
+ observer.observe( comment_list_container, { attributes: true, childList: true, characterData: true } );
194
+ }
195
+ }
196
+
197
+ function akismet_enable_comment_author_url_removal() {
198
+ $( '#the-comment-list' )
199
+ .find( 'tr.comment, tr[id ^= "comment-"]' )
200
+ .find( '.column-author a[href^="http"]:first' ) // Ignore mailto: links, which would be the comment author's email.
201
+ .each(function () {
202
+ if ( $( this ).parent().find( '.akismet_remove_url' ).length > 0 ) {
203
+ return;
204
+ }
205
+
206
+ var linkHref = $(this).attr( 'href' );
207
+
208
+ // Ignore any links to the current domain, which are diagnostic tools, like the IP address link
209
+ // or any other links another plugin might add.
210
+ var currentHostParts = document.location.href.split( '/' );
211
+ var currentHost = currentHostParts[0] + '//' + currentHostParts[2] + '/';
212
+
213
+ if ( linkHref.indexOf( currentHost ) != 0 ) {
214
+ var thisCommentId = $(this).parents('tr:first').attr('id').split("-");
215
+
216
+ $(this)
217
+ .attr("id", "author_comment_url_"+ thisCommentId[1])
218
+ .after(
219
+ $( '<a href="#" class="akismet_remove_url">x</a>' )
220
+ .attr( 'commentid', thisCommentId[1] )
221
+ .attr( 'title', WPAkismet.strings['Remove this URL'] )
222
+ );
223
+ }
224
+ });
225
+ }
226
+ });
_inc/img/logo-full-2x.png CHANGED
Binary file
akismet.php CHANGED
@@ -6,7 +6,7 @@
6
  Plugin Name: Akismet Anti-Spam
7
  Plugin URI: https://akismet.com/
8
  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.
9
- Version: 3.3
10
  Author: Automattic
11
  Author URI: https://automattic.com/wordpress-plugins/
12
  License: GPLv2 or later
@@ -37,7 +37,7 @@ if ( !function_exists( 'add_action' ) ) {
37
  exit;
38
  }
39
 
40
- define( 'AKISMET_VERSION', '3.3' );
41
  define( 'AKISMET__MINIMUM_WP_VERSION', '3.7' );
42
  define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
43
  define( 'AKISMET_DELETE_LIMIT', 100000 );
6
  Plugin Name: Akismet Anti-Spam
7
  Plugin URI: https://akismet.com/
8
  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.
9
+ Version: 3.3.1
10
  Author: Automattic
11
  Author URI: https://automattic.com/wordpress-plugins/
12
  License: GPLv2 or later
37
  exit;
38
  }
39
 
40
+ define( 'AKISMET_VERSION', '3.3.1' );
41
  define( 'AKISMET__MINIMUM_WP_VERSION', '3.7' );
42
  define( 'AKISMET__PLUGIN_DIR', plugin_dir_path( __FILE__ ) );
43
  define( 'AKISMET_DELETE_LIMIT', 100000 );
class.akismet.php CHANGED
@@ -29,18 +29,7 @@ class Akismet {
29
  add_action( 'akismet_scheduled_delete', array( 'Akismet', 'delete_old_comments_meta' ) );
30
  add_action( 'akismet_schedule_cron_recheck', array( 'Akismet', 'cron_recheck' ) );
31
 
32
- /**
33
- * To disable the Akismet comment nonce, add a filter for the 'akismet_comment_nonce' tag
34
- * and return any string value that is not 'true' or '' (empty string).
35
- *
36
- * Don't return boolean false, because that implies that the 'akismet_comment_nonce' option
37
- * has not been set and that Akismet should just choose the default behavior for that
38
- * situation.
39
- */
40
- $akismet_comment_nonce_option = apply_filters( 'akismet_comment_nonce', get_option( 'akismet_comment_nonce' ) );
41
-
42
- if ( $akismet_comment_nonce_option == 'true' || $akismet_comment_nonce_option == '' )
43
- add_action( 'comment_form', array( 'Akismet', 'add_comment_nonce' ), 1 );
44
 
45
  add_action( 'admin_head-edit-comments.php', array( 'Akismet', 'load_form_js' ) );
46
  add_action( 'comment_form', array( 'Akismet', 'load_form_js' ) );
@@ -171,7 +160,11 @@ class Akismet {
171
  }
172
 
173
  $post = get_post( $comment['comment_post_ID'] );
174
- $comment[ 'comment_post_modified_gmt' ] = $post->post_modified_gmt;
 
 
 
 
175
 
176
  $response = self::http_post( Akismet::build_query( $comment ), 'comment-check' );
177
 
@@ -200,7 +193,9 @@ class Akismet {
200
  // akismet_result_spam() won't be called so bump the counter here
201
  if ( $incr = apply_filters('akismet_spam_count_incr', 1) )
202
  update_option( 'akismet_spam_count', get_option('akismet_spam_count') + $incr );
203
- $redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : get_permalink( $post );
 
 
204
  wp_safe_redirect( esc_url_raw( $redirect_to ) );
205
  die();
206
  }
@@ -266,9 +261,6 @@ class Akismet {
266
  if ( !function_exists('add_comment_meta') )
267
  return false;
268
 
269
- if ( !isset( self::$last_comment['comment_author_email'] ) )
270
- self::$last_comment['comment_author_email'] = '';
271
-
272
  // wp_insert_comment() might be called in other contexts, so make sure this is the same comment
273
  // as was checked by auto_check_comment
274
  if ( is_object( $comment ) && !empty( self::$last_comment ) && is_array( self::$last_comment ) ) {
@@ -355,6 +347,7 @@ class Akismet {
355
  $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN ( " . $format_string . " )", $comment_ids ) );
356
 
357
  clean_comment_cache( $comment_ids );
 
358
  }
359
 
360
  if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->comments ) ) // lucky number
@@ -382,6 +375,8 @@ class Akismet {
382
  foreach ( $comment_ids as $comment_id ) {
383
  delete_comment_meta( $comment_id, 'akismet_as_submitted' );
384
  }
 
 
385
  }
386
 
387
  if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->commentmeta ) ) // lucky number
@@ -606,7 +601,10 @@ class Akismet {
606
  $comment->is_test = 'true';
607
 
608
  $post = get_post( $comment->comment_post_ID );
609
- $comment->comment_post_modified_gmt = $post->post_modified_gmt;
 
 
 
610
 
611
  $response = Akismet::http_post( Akismet::build_query( $comment ), 'submit-spam' );
612
  if ( $comment->reporter ) {
@@ -653,7 +651,10 @@ class Akismet {
653
  $comment->is_test = 'true';
654
 
655
  $post = get_post( $comment->comment_post_ID );
656
- $comment->comment_post_modified_gmt = $post->post_modified_gmt;
 
 
 
657
 
658
  $response = self::http_post( Akismet::build_query( $comment ), 'submit-ham' );
659
  if ( $comment->reporter ) {
@@ -768,9 +769,21 @@ class Akismet {
768
  }
769
 
770
  public static function add_comment_nonce( $post_id ) {
771
- echo '<p style="display: none;">';
772
- wp_nonce_field( 'akismet_comment_nonce_' . $post_id, 'akismet_comment_nonce', FALSE );
773
- echo '</p>';
 
 
 
 
 
 
 
 
 
 
 
 
774
  }
775
 
776
  public static function is_test_mode() {
@@ -800,7 +813,25 @@ class Akismet {
800
  private static function comments_match( $comment1, $comment2 ) {
801
  $comment1 = (array) $comment1;
802
  $comment2 = (array) $comment2;
803
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
804
  $comments_match = (
805
  isset( $comment1['comment_post_ID'], $comment2['comment_post_ID'] )
806
  && intval( $comment1['comment_post_ID'] ) == intval( $comment2['comment_post_ID'] )
@@ -834,9 +865,6 @@ class Akismet {
834
 
835
  // Does the supplied comment match the details of the one most recently stored in self::$last_comment?
836
  public static function matches_last_comment( $comment ) {
837
- if ( is_object( $comment ) )
838
- $comment = (array) $comment;
839
-
840
  return self::comments_match( self::$last_comment, $comment );
841
  }
842
 
29
  add_action( 'akismet_scheduled_delete', array( 'Akismet', 'delete_old_comments_meta' ) );
30
  add_action( 'akismet_schedule_cron_recheck', array( 'Akismet', 'cron_recheck' ) );
31
 
32
+ add_action( 'comment_form', array( 'Akismet', 'add_comment_nonce' ), 1 );
 
 
 
 
 
 
 
 
 
 
 
33
 
34
  add_action( 'admin_head-edit-comments.php', array( 'Akismet', 'load_form_js' ) );
35
  add_action( 'comment_form', array( 'Akismet', 'load_form_js' ) );
160
  }
161
 
162
  $post = get_post( $comment['comment_post_ID'] );
163
+
164
+ if ( ! is_null( $post ) ) {
165
+ // $post can technically be null, although in the past, it's always been an indicator of another plugin interfering.
166
+ $comment[ 'comment_post_modified_gmt' ] = $post->post_modified_gmt;
167
+ }
168
 
169
  $response = self::http_post( Akismet::build_query( $comment ), 'comment-check' );
170
 
193
  // akismet_result_spam() won't be called so bump the counter here
194
  if ( $incr = apply_filters('akismet_spam_count_incr', 1) )
195
  update_option( 'akismet_spam_count', get_option('akismet_spam_count') + $incr );
196
+ // The spam is obvious, so we're bailing out early. Redirect back to the previous page,
197
+ // or failing that, the post permalink, or failing that, the homepage of the blog.
198
+ $redirect_to = isset( $_SERVER['HTTP_REFERER'] ) ? $_SERVER['HTTP_REFERER'] : ( $post ? get_permalink( $post ) : home_url() );
199
  wp_safe_redirect( esc_url_raw( $redirect_to ) );
200
  die();
201
  }
261
  if ( !function_exists('add_comment_meta') )
262
  return false;
263
 
 
 
 
264
  // wp_insert_comment() might be called in other contexts, so make sure this is the same comment
265
  // as was checked by auto_check_comment
266
  if ( is_object( $comment ) && !empty( self::$last_comment ) && is_array( self::$last_comment ) ) {
347
  $wpdb->query( $wpdb->prepare( "DELETE FROM {$wpdb->commentmeta} WHERE comment_id IN ( " . $format_string . " )", $comment_ids ) );
348
 
349
  clean_comment_cache( $comment_ids );
350
+ do_action( 'akismet_delete_comment_batch', count( $comment_ids ) );
351
  }
352
 
353
  if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->comments ) ) // lucky number
375
  foreach ( $comment_ids as $comment_id ) {
376
  delete_comment_meta( $comment_id, 'akismet_as_submitted' );
377
  }
378
+
379
+ do_action( 'akismet_delete_commentmeta_batch', count( $comment_ids ) );
380
  }
381
 
382
  if ( apply_filters( 'akismet_optimize_table', ( mt_rand(1, 5000) == 11), $wpdb->commentmeta ) ) // lucky number
601
  $comment->is_test = 'true';
602
 
603
  $post = get_post( $comment->comment_post_ID );
604
+
605
+ if ( ! is_null( $post ) ) {
606
+ $comment->comment_post_modified_gmt = $post->post_modified_gmt;
607
+ }
608
 
609
  $response = Akismet::http_post( Akismet::build_query( $comment ), 'submit-spam' );
610
  if ( $comment->reporter ) {
651
  $comment->is_test = 'true';
652
 
653
  $post = get_post( $comment->comment_post_ID );
654
+
655
+ if ( ! is_null( $post ) ) {
656
+ $comment->comment_post_modified_gmt = $post->post_modified_gmt;
657
+ }
658
 
659
  $response = self::http_post( Akismet::build_query( $comment ), 'submit-ham' );
660
  if ( $comment->reporter ) {
769
  }
770
 
771
  public static function add_comment_nonce( $post_id ) {
772
+ /**
773
+ * To disable the Akismet comment nonce, add a filter for the 'akismet_comment_nonce' tag
774
+ * and return any string value that is not 'true' or '' (empty string).
775
+ *
776
+ * Don't return boolean false, because that implies that the 'akismet_comment_nonce' option
777
+ * has not been set and that Akismet should just choose the default behavior for that
778
+ * situation.
779
+ */
780
+ $akismet_comment_nonce_option = apply_filters( 'akismet_comment_nonce', get_option( 'akismet_comment_nonce' ) );
781
+
782
+ if ( $akismet_comment_nonce_option == 'true' || $akismet_comment_nonce_option == '' ) {
783
+ echo '<p style="display: none;">';
784
+ wp_nonce_field( 'akismet_comment_nonce_' . $post_id, 'akismet_comment_nonce', FALSE );
785
+ echo '</p>';
786
+ }
787
  }
788
 
789
  public static function is_test_mode() {
813
  private static function comments_match( $comment1, $comment2 ) {
814
  $comment1 = (array) $comment1;
815
  $comment2 = (array) $comment2;
816
+
817
+ // Set default values for these strings that we check in order to simplify
818
+ // the checks and avoid PHP warnings.
819
+ if ( ! isset( $comment1['comment_author'] ) ) {
820
+ $comment1['comment_author'] = '';
821
+ }
822
+
823
+ if ( ! isset( $comment2['comment_author'] ) ) {
824
+ $comment2['comment_author'] = '';
825
+ }
826
+
827
+ if ( ! isset( $comment1['comment_author_email'] ) ) {
828
+ $comment1['comment_author_email'] = '';
829
+ }
830
+
831
+ if ( ! isset( $comment2['comment_author_email'] ) ) {
832
+ $comment2['comment_author_email'] = '';
833
+ }
834
+
835
  $comments_match = (
836
  isset( $comment1['comment_post_ID'], $comment2['comment_post_ID'] )
837
  && intval( $comment1['comment_post_ID'] ) == intval( $comment2['comment_post_ID'] )
865
 
866
  // Does the supplied comment match the details of the one most recently stored in self::$last_comment?
867
  public static function matches_last_comment( $comment ) {
 
 
 
868
  return self::comments_match( self::$last_comment, $comment );
869
  }
870
 
readme.txt CHANGED
@@ -2,8 +2,8 @@
2
  Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs
3
  Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
4
  Requires at least: 3.7
5
- Tested up to: 4.7.2
6
- Stable tag: 3.3
7
  License: GPLv2 or later
8
 
9
  Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
@@ -30,6 +30,14 @@ Upload the Akismet plugin to your blog, Activate it, then enter your [Akismet.co
30
 
31
  == Changelog ==
32
 
 
 
 
 
 
 
 
 
33
  = 3.3 =
34
  *Release Date - 23 February 2017*
35
 
2
  Contributors: matt, ryan, andy, mdawaffe, tellyworth, josephscott, lessbloat, eoigal, cfinke, automattic, jgs
3
  Tags: akismet, comments, spam, antispam, anti-spam, anti spam, comment moderation, comment spam, contact form spam, spam comments
4
  Requires at least: 3.7
5
+ Tested up to: 4.7.4
6
+ Stable tag: 3.3.1
7
  License: GPLv2 or later
8
 
9
  Akismet checks your comments and contact form submissions against our global database of spam to protect you and your site from malicious content.
30
 
31
  == Changelog ==
32
 
33
+ = 3.3.1 =
34
+ *Release Date - 2 May 2017*
35
+
36
+ * Improve performance by only requesting the akismet_comment_nonce option when absolutely necessary.
37
+ * Fixed two bugs that could cause PHP warnings.
38
+ * Fixed a bug that was preventing the "Remove author URL" feature from working after a comment was edited using "Quick Edit."
39
+ * Fixed a bug that was preventing the URL preview feature from working after a comment was edited using "Quick Edit."
40
+
41
  = 3.3 =
42
  *Release Date - 23 February 2017*
43