Spam protection, AntiSpam, FireWall by CleanTalk - Version 5.104

Version Description

September 18 2018 = * Fix: Error when saving settings. * Fix: Trying update anti spam plugin for the first installation. * Fix: Update system. * Fix: Errors output. * Fix: Plugin's settings under WPMS. * Fix: SpamFireWall update. * Fix: The server change system repaired. * Mod: Cron saving tasks improved.

Download this release

Release Info

Developer shagimuratov
Plugin Icon 128x128 Spam protection, AntiSpam, FireWall by CleanTalk
Version 5.104
Comparing to
See all releases

Code changes from version 5.103.1 to 5.104

cleantalk.php CHANGED
@@ -3,7 +3,7 @@
3
  Plugin Name: Anti-Spam by CleanTalk
4
  Plugin URI: http://cleantalk.org
5
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
- Version: 5.103.1
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: http://cleantalk.org
9
  */
3
  Plugin Name: Anti-Spam by CleanTalk
4
  Plugin URI: http://cleantalk.org
5
  Description: Max power, all-in-one, no Captcha, premium anti-spam plugin. No comment spam, no registration spam, no contact spam, protects any WordPress forms.
6
+ Version: 5.104
7
  Author: СleanTalk <welcome@cleantalk.org>
8
  Author URI: http://cleantalk.org
9
  */
inc/cleantalk-admin.php CHANGED
@@ -128,7 +128,7 @@ function apbct_admin__init(){
128
  global $apbct;
129
 
130
  // Update logic
131
- if($apbct->plugin_version != APBCT_VERSION){
132
  if(is_main_site()){
133
  require_once('cleantalk-updater.php');
134
  $result = apbct_run_update_actions($apbct->plugin_version, APBCT_VERSION);
128
  global $apbct;
129
 
130
  // Update logic
131
+ if($apbct->plugin_version != '1.0.0' && $apbct->plugin_version != APBCT_VERSION){
132
  if(is_main_site()){
133
  require_once('cleantalk-updater.php');
134
  $result = apbct_run_update_actions($apbct->plugin_version, APBCT_VERSION);
inc/cleantalk-common.php CHANGED
@@ -134,7 +134,7 @@ function apbct_base_call($params = array(), $reg_flag = false){
134
  update_option(
135
  'cleantalk_server',
136
  array(
137
- 'ct_work_url' => preg_replace('/http[s]?:\/\/(.*)/', '$1', $ct->work_url),
138
  'ct_server_ttl' => $ct->server_ttl,
139
  'ct_server_changed' => time(),
140
  )
@@ -366,12 +366,13 @@ function ct_send_feedback($feedback_request = null) {
366
  update_option(
367
  'cleantalk_server',
368
  array(
369
- 'ct_work_url' => preg_replace('/http[s]?:\/\/(.*)/', '$1', $ct->work_url),
370
  'ct_server_ttl' => $ct->server_ttl,
371
  'ct_server_changed' => time()
372
  )
373
  );
374
  }
 
375
  return true;
376
  }
377
 
134
  update_option(
135
  'cleantalk_server',
136
  array(
137
+ 'ct_work_url' => $ct->work_url,
138
  'ct_server_ttl' => $ct->server_ttl,
139
  'ct_server_changed' => time(),
140
  )
366
  update_option(
367
  'cleantalk_server',
368
  array(
369
+ 'ct_work_url' => $ct->work_url,
370
  'ct_server_ttl' => $ct->server_ttl,
371
  'ct_server_changed' => time()
372
  )
373
  );
374
  }
375
+
376
  return true;
377
  }
378
 
inc/cleantalk-settings.php CHANGED
@@ -365,7 +365,9 @@ function apbct_settings__error__output($return = false){
365
 
366
  // If have error message output error block.
367
 
368
- if(!empty($apbct->errors)){
 
 
369
 
370
  $errors = $apbct->errors;
371
 
@@ -407,7 +409,6 @@ function apbct_settings__error__output($return = false){
407
  }
408
  }
409
 
410
- $out = '';
411
  if(!empty($errors_out)){
412
  $out .= '<div id="apbctTopWarning" class="error" style="position: relative;">'
413
  .'<h3 style="display: inline-block;">'.__('Errors:', 'security-malware-firewall').'</h3>';
@@ -521,7 +522,7 @@ function apbct_settings__field__api_key(){
521
 
522
  echo '<div id="cleantalk_apkey_wrapper" class="apbct_settings-field_wrapper" '.(apbct_api_key__is_correct($apbct->api_key) && $apbct->key_is_ok ? 'style="display: none"' : '').'>';
523
 
524
- if(!is_multisite()){
525
 
526
  echo '<label class="apbct_settings__label" for="cleantalk_apkey">'.__('Access key', 'cleantalk').'</label>'
527
  .'<input class="apbct_settings__text_feld" name="cleantalk_settings[apikey]" size="20" type="text" value="'.$apbct->api_key.'" style=\"font-size: 14pt;\" placeholder="' . __('Enter the key', 'cleantalk') . '" />';
@@ -725,6 +726,9 @@ function apbct_settings__validate($settings) {
725
  }
726
  }
727
 
 
 
 
728
  $settings['apikey'] = isset($settings['apikey']) ? trim($settings['apikey']) : '';
729
 
730
  // Key is good by default
@@ -741,14 +745,16 @@ function apbct_settings__validate($settings) {
741
  if($result['valid'] == 1){
742
 
743
  // Deleting errors about invalid key
744
- $apbct->error_delete('key_invalid', 'save');
745
-
746
- // TO DO // Feedback with app_agent
747
- ct_send_feedback('0:' . APBCT_AGENT); // 0 - request_id, agent version.
748
 
749
  // Check account status
750
  ct_account_status_check($settings['apikey']);
751
 
 
 
 
 
 
752
  // Key is not valid
753
  }else{
754
  $apbct->data['key_is_ok'] = false;
365
 
366
  // If have error message output error block.
367
 
368
+ $out = '';
369
+
370
+ if(!empty($apbct->errors) && !defined('CLEANTALK_ACCESS_KEY')){
371
 
372
  $errors = $apbct->errors;
373
 
409
  }
410
  }
411
 
 
412
  if(!empty($errors_out)){
413
  $out .= '<div id="apbctTopWarning" class="error" style="position: relative;">'
414
  .'<h3 style="display: inline-block;">'.__('Errors:', 'security-malware-firewall').'</h3>';
522
 
523
  echo '<div id="cleantalk_apkey_wrapper" class="apbct_settings-field_wrapper" '.(apbct_api_key__is_correct($apbct->api_key) && $apbct->key_is_ok ? 'style="display: none"' : '').'>';
524
 
525
+ if(!defined('CLEANTALK_ACCESS_KEY') || !is_multisite()){
526
 
527
  echo '<label class="apbct_settings__label" for="cleantalk_apkey">'.__('Access key', 'cleantalk').'</label>'
528
  .'<input class="apbct_settings__text_feld" name="cleantalk_settings[apikey]" size="20" type="text" value="'.$apbct->api_key.'" style=\"font-size: 14pt;\" placeholder="' . __('Enter the key', 'cleantalk') . '" />';
726
  }
727
  }
728
 
729
+ // Feedback with app_agent
730
+ ct_send_feedback('0:' . APBCT_AGENT); // 0 - request_id, agent version.
731
+
732
  $settings['apikey'] = isset($settings['apikey']) ? trim($settings['apikey']) : '';
733
 
734
  // Key is good by default
745
  if($result['valid'] == 1){
746
 
747
  // Deleting errors about invalid key
748
+ $apbct->error_delete('key_invalid key_get', 'save');
 
 
 
749
 
750
  // Check account status
751
  ct_account_status_check($settings['apikey']);
752
 
753
+ if($apbct->settings['spam_firewall'] == 1){
754
+ ct_sfw_update();
755
+ ct_sfw_send_logs();
756
+ }
757
+
758
  // Key is not valid
759
  }else{
760
  $apbct->data['key_is_ok'] = false;
inc/cleantalk-updater.php CHANGED
@@ -104,8 +104,8 @@ function apbct_update_to_5_97_0(){
104
 
105
  global $apbct;
106
 
107
- if(count($abpct->data['connection_reports']['negative_report']) >= 20)
108
- $abpct->data['connection_reports']['negative_report'] = array_slice($abpct->data['connection_reports']['negative_report'], -20, 20);
109
 
110
- $abpct->saveData();
111
  }
104
 
105
  global $apbct;
106
 
107
+ if(count($apbct->data['connection_reports']['negative_report']) >= 20)
108
+ $apbct->data['connection_reports']['negative_report'] = array_slice($apbct->data['connection_reports']['negative_report'], -20, 20);
109
 
110
+ $apbct->saveData();
111
  }
lib/Cleantalk.php CHANGED
@@ -59,12 +59,6 @@ class Cleantalk {
59
  */
60
  public $server_change = false;
61
 
62
- /**
63
- * Use TRUE when need stay on server. Example: send feedback
64
- * @var bool
65
- */
66
- public $stay_on_server = false;
67
-
68
  /**
69
  * Codepage of the data
70
  * @var bool
@@ -95,6 +89,12 @@ class Cleantalk {
95
  */
96
  public $min_server_timeout = 50;
97
 
 
 
 
 
 
 
98
  /**
99
  * Function checks whether it is possible to publish the message
100
  * @param CleantalkRequest $request
@@ -351,8 +351,8 @@ class Cleantalk {
351
  * @return boolean|\CleantalkResponse
352
  */
353
  private function httpRequest($msg) {
354
- $result = false;
355
 
 
356
  if($msg->method_name != 'send_feedback'){
357
 
358
  $ct_tmp = apache_request_headers();
@@ -385,48 +385,38 @@ class Cleantalk {
385
 
386
  $msg->all_headers = json_encode($msg->all_headers);
387
 
388
- if (((isset($this->work_url) && $this->work_url !== '') && ($this->server_changed + $this->server_ttl > time()))
389
- || $this->stay_on_server == true) {
390
 
391
- $url = (!empty($this->work_url)) ? $this->work_url : $this->server_url;
392
-
393
  $result = $this->sendRequest($msg, $url, $this->server_timeout);
 
 
 
394
  }
395
 
396
- if (($result === false || $result->errno != 0) && $this->stay_on_server == false) {
 
 
397
  // Split server url to parts
398
  preg_match("@^(https?://)([^/:]+)(.*)@i", $this->server_url, $matches);
399
- $url_prefix = '';
400
- if (isset($matches[1]))
401
- $url_prefix = $matches[1];
402
-
403
- $pool = null;
404
- if (isset($matches[2]))
405
- $pool = $matches[2];
406
 
407
- $url_suffix = '';
408
- if (isset($matches[3]))
409
- $url_suffix = $matches[3];
410
 
411
- if ($url_prefix === '')
412
- $url_prefix = 'http://';
413
 
414
- if (empty($pool)) {
415
  return false;
 
416
  } else {
 
 
 
417
  // Loop until find work server
418
- foreach ($this->get_servers_ip($pool) as $server) {
419
- if ($server['host'] === 'localhost' || $server['ip'] === null) {
420
- $work_url = $server['host'];
421
- } else {
422
- $server_host = $server['ip'];
423
- $work_url = $server_host;
424
- }
425
- $work_url = $url_prefix . $work_url;
426
- if (isset($url_suffix))
427
- $work_url = $work_url . $url_suffix;
428
 
429
- $this->work_url = $work_url;
430
  $this->server_ttl = $server['ttl'];
431
 
432
  $result = $this->sendRequest($msg, $this->work_url, $this->server_timeout);
@@ -458,27 +448,27 @@ class Cleantalk {
458
  * @param $host
459
  * @return array
460
  */
461
- public function get_servers_ip($host) {
462
- $response = null;
463
  if (!isset($host))
464
- return $response;
465
 
 
466
  if (function_exists('dns_get_record')) {
467
  $records = dns_get_record($host, DNS_A);
468
-
469
  if ($records !== FALSE) {
470
  foreach ($records as $server) {
471
- $response[] = $server;
472
  }
473
  }
474
  }
475
 
476
- if (count($response) == 0 && function_exists('gethostbynamel')) {
 
477
  $records = gethostbynamel($host);
478
-
479
  if ($records !== FALSE) {
480
  foreach ($records as $server) {
481
- $response[] = array(
482
  "ip" => $server,
483
  "host" => $host,
484
  "ttl" => $this->server_ttl
@@ -487,85 +477,44 @@ class Cleantalk {
487
  }
488
  }
489
 
490
- if (count($response) == 0) {
491
- $response[] = array("ip" => null,
 
 
 
492
  "host" => $host,
493
  "ttl" => $this->server_ttl
494
  );
 
 
495
  } else {
496
- // $i - to resolve collisions with localhost
497
- $i = 0;
498
- $r_temp = null;
499
  $fast_server_found = false;
500
- foreach ($response as $server) {
501
 
502
- // Do not test servers because fast work server found
 
503
  if ($fast_server_found) {
504
- $ping = $this->min_server_timeout;
505
  } else {
506
  $ping = $this->httpPing($server['ip']);
507
  $ping = $ping * 1000;
508
  }
509
 
510
- // -1 server is down, skips not reachable server
511
- if ($ping != -1) {
512
- $r_temp[$ping + $i] = $server;
513
- }
514
- $i++;
515
 
516
- if ($ping < $this->min_server_timeout) {
517
- $fast_server_found = true;
518
- }
519
- }
520
- if (count($r_temp)){
521
- ksort($r_temp);
522
- $response = $r_temp;
523
- }
524
- }
525
 
526
- return $response;
527
  }
528
 
529
- /**
530
- * Function to get the message hash from Cleantalk.ru comment
531
- * @param $message
532
- * @return null
533
- */
534
- public function getCleantalkCommentHash($message) {
535
- $matches = array();
536
- if (preg_match('/\n\n\*\*\*.+([a-z0-9]{32}).+\*\*\*$/', $message, $matches))
537
- return $matches[1];
538
- else if (preg_match('/\<br.*\>[\n]{0,1}\<br.*\>[\n]{0,1}\*\*\*.+([a-z0-9]{32}).+\*\*\*$/', $message, $matches))
539
- return $matches[1];
540
-
541
- return NULL;
542
  }
543
 
544
- /**
545
- * Function adds to the post comment Cleantalk.ru
546
- * @param $message
547
- * @param $comment
548
- * @return string
549
- */
550
- public function addCleantalkComment($message, $comment) {
551
- $comment = preg_match('/\*\*\*(.+)\*\*\*/', $comment, $matches) ? $comment : '*** ' . $comment . ' ***';
552
- return $message . "\n\n" . $comment;
553
  }
554
 
555
- /**
556
- * Function deletes the comment Cleantalk.ru
557
- * @param $message
558
- * @return mixed
559
- */
560
- public function delCleantalkComment($message) {
561
- $message = preg_replace('/\n\n\*\*\*.+\*\*\*$/', '', $message);
562
-
563
- // DLE sign cut
564
- $message = preg_replace('/<br\s?\/><br\s?\/>\*\*\*.+\*\*\*$/', '', $message);
565
-
566
- $message = preg_replace('/\<br.*\>[\n]{0,1}\<br.*\>[\n]{0,1}\*\*\*.+\*\*\*$/', '', $message);
567
-
568
- return $message;
569
  }
570
 
571
  /**
@@ -581,11 +530,11 @@ class Cleantalk {
581
  return 0.001;
582
 
583
  $starttime = microtime(true);
584
- $file = @fsockopen ($host, 80, $errno, $errstr, $this->server_timeout);
585
  $stoptime = microtime(true);
586
- $status = 0;
587
  if (!$file) {
588
- $status = -1; // Site is down
589
  } else {
590
  fclose($file);
591
  $status = ($stoptime - $starttime);
59
  */
60
  public $server_change = false;
61
 
 
 
 
 
 
 
62
  /**
63
  * Codepage of the data
64
  * @var bool
89
  */
90
  public $min_server_timeout = 50;
91
 
92
+ /**
93
+ * Maximal server response in miliseconds to catch the server
94
+ *
95
+ */
96
+ public $max_server_timeout = 1500;
97
+
98
  /**
99
  * Function checks whether it is possible to publish the message
100
  * @param CleantalkRequest $request
351
  * @return boolean|\CleantalkResponse
352
  */
353
  private function httpRequest($msg) {
 
354
 
355
+ // Wiping cleantalk's headers but, not for send_feedback
356
  if($msg->method_name != 'send_feedback'){
357
 
358
  $ct_tmp = apache_request_headers();
385
 
386
  $msg->all_headers = json_encode($msg->all_headers);
387
 
388
+ // Using current server without changing it
389
+ if (false && (!empty($this->work_url) && ($this->server_changed + $this->server_ttl > time()))){
390
 
391
+ $url = !empty($this->work_url) ? $this->work_url : $this->server_url;
 
392
  $result = $this->sendRequest($msg, $url, $this->server_timeout);
393
+
394
+ }else{
395
+ $result = false;
396
  }
397
 
398
+ // Changing server
399
+ if (true || ($result === false || $result->errno != 0)) {
400
+
401
  // Split server url to parts
402
  preg_match("@^(https?://)([^/:]+)(.*)@i", $this->server_url, $matches);
 
 
 
 
 
 
 
403
 
404
+ $url_prefix = isset($matches[1]) ? $matches[1] : '';
405
+ $url_host = isset($matches[2]) ? $matches[2] : '';
406
+ $url_suffix = isset($matches[3]) ? $matches[3] : '';
407
 
408
+ if (empty($url_host)){
 
409
 
 
410
  return false;
411
+
412
  } else {
413
+
414
+ $servers = $this->get_servers_ip($url_host);
415
+
416
  // Loop until find work server
417
+ foreach ($servers as $server) {
 
 
 
 
 
 
 
 
 
418
 
419
+ $this->work_url = $url_prefix . $server['ip'] . $url_suffix;
420
  $this->server_ttl = $server['ttl'];
421
 
422
  $result = $this->sendRequest($msg, $this->work_url, $this->server_timeout);
448
  * @param $host
449
  * @return array
450
  */
451
+ public function get_servers_ip($host)
452
+ {
453
  if (!isset($host))
454
+ return null;
455
 
456
+ // Get DNS records about URL
457
  if (function_exists('dns_get_record')) {
458
  $records = dns_get_record($host, DNS_A);
 
459
  if ($records !== FALSE) {
460
  foreach ($records as $server) {
461
+ $servers[] = $server;
462
  }
463
  }
464
  }
465
 
466
+ // Another try if first failed
467
+ if (count($servers) == 0 && function_exists('gethostbynamel')) {
468
  $records = gethostbynamel($host);
 
469
  if ($records !== FALSE) {
470
  foreach ($records as $server) {
471
+ $servers[] = array(
472
  "ip" => $server,
473
  "host" => $host,
474
  "ttl" => $this->server_ttl
477
  }
478
  }
479
 
480
+ // If couldn't get records
481
+ if (count($servers) == 0){
482
+
483
+ $servers[] = array(
484
+ "ip" => null,
485
  "host" => $host,
486
  "ttl" => $this->server_ttl
487
  );
488
+
489
+ // If records recieved
490
  } else {
491
+
492
+ $tmp = null;
 
493
  $fast_server_found = false;
 
494
 
495
+ foreach ($servers as $server) {
496
+
497
  if ($fast_server_found) {
498
+ $ping = $this->max_server_timeout;
499
  } else {
500
  $ping = $this->httpPing($server['ip']);
501
  $ping = $ping * 1000;
502
  }
503
 
504
+ $tmp[$ping] = $server;
 
 
 
 
505
 
506
+ $fast_server_found = $ping < $this->min_server_timeout ? true : false;
 
 
 
 
 
 
 
 
507
 
 
508
  }
509
 
510
+ if (count($tmp)){
511
+ ksort($tmp);
512
+ $response = $tmp;
 
 
 
 
 
 
 
 
 
 
513
  }
514
 
 
 
 
 
 
 
 
 
 
515
  }
516
 
517
+ return empty($response) ? null : $response;
 
 
 
 
 
 
 
 
 
 
 
 
 
518
  }
519
 
520
  /**
530
  return 0.001;
531
 
532
  $starttime = microtime(true);
533
+ $file = @fsockopen ($host, 80, $errno, $errstr, $this->max_server_timeout/1000);
534
  $stoptime = microtime(true);
535
+
536
  if (!$file) {
537
+ $status = $this->max_server_timeout/1000; // Site is down
538
  } else {
539
  fclose($file);
540
  $status = ($stoptime - $starttime);
lib/CleantalkCron.php CHANGED
@@ -28,7 +28,7 @@ class CleantalkCron
28
  }
29
 
30
  // Adding new cron task
31
- static public function addTask($task, $handler, $period, $first_call = null)
32
  {
33
  // First call time() + preiod
34
  $first_call = !$first_call ? time()+$period : $first_call;
@@ -36,7 +36,7 @@ class CleantalkCron
36
  $tasks = get_option(self::CRON_OPTION_NAME);
37
  $tasks = empty($tasks) ? array() : $tasks;
38
 
39
- if(isset($tasks[$task]))
40
  return false;
41
 
42
  // Task entry
@@ -70,8 +70,7 @@ class CleantalkCron
70
 
71
  // Updates cron task, creates task if not exists
72
  static public function updateTask($task, $handler, $period, $first_call = null){
73
- self::removeTask($task);
74
- self::addTask($task, $handler, $period, $first_call = null);
75
  }
76
 
77
  // Getting tasks which should be run. Putting tasks that should be run to $this->tasks_to_run
28
  }
29
 
30
  // Adding new cron task
31
+ static public function addTask($task, $handler, $period, $first_call = null, $update = false)
32
  {
33
  // First call time() + preiod
34
  $first_call = !$first_call ? time()+$period : $first_call;
36
  $tasks = get_option(self::CRON_OPTION_NAME);
37
  $tasks = empty($tasks) ? array() : $tasks;
38
 
39
+ if(isset($tasks[$task]) && !$update)
40
  return false;
41
 
42
  // Task entry
70
 
71
  // Updates cron task, creates task if not exists
72
  static public function updateTask($task, $handler, $period, $first_call = null){
73
+ self::addTask($task, $handler, $period, $first_call, true);
 
74
  }
75
 
76
  // Getting tasks which should be run. Putting tasks that should be run to $this->tasks_to_run
lib/CleantalkHelper.php CHANGED
@@ -645,7 +645,7 @@ class CleantalkHelper
645
  $error = array('error' => true, 'error_string' => 'CURL_NOT_INSTALLED');
646
 
647
  /** Fix for get_code preset */
648
- if($presets && ($presets == 'get_code' || (is_array($presets) && in_array($presets, 'get_code') ) )
649
  && (isset($error) && $error['error_string'] == 'CURL_NOT_INSTALLED')
650
  ){
651
  $headers = get_headers($url);
645
  $error = array('error' => true, 'error_string' => 'CURL_NOT_INSTALLED');
646
 
647
  /** Fix for get_code preset */
648
+ if($presets && ($presets == 'get_code' || (is_array($presets) && in_array('get_code', $presets) ) )
649
  && (isset($error) && $error['error_string'] == 'CURL_NOT_INSTALLED')
650
  ){
651
  $headers = get_headers($url);
lib/CleantalkState.php CHANGED
@@ -51,6 +51,7 @@ class CleantalkState
51
  'show_adminbar' => 1, // Show the admin bar.
52
  'all_time_counter' => 0,
53
  'daily_counter' => 0,
 
54
 
55
  //Others
56
  'spam_store_days' => '15', // Days before delete comments from folder Spam
51
  'show_adminbar' => 1, // Show the admin bar.
52
  'all_time_counter' => 0,
53
  'daily_counter' => 0,
54
+ 'sfw_counter' => 0,
55
 
56
  //Others
57
  'spam_store_days' => '15', // Days before delete comments from folder Spam
readme.txt CHANGED
@@ -3,7 +3,7 @@ Contributors: safronik
3
  Tags: spam, antispam, protection, comments, firewall
4
  Requires at least: 3.0
5
  Tested up to: 4.9
6
- Stable tag: 5.102
7
  License: GPLv2
8
 
9
  Spam protection, antispam, all-in-one, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
@@ -44,7 +44,7 @@ CleanTalk is a free anti spam plugin which work with the premium Cloud AntiSpam
44
  = AntiSpam protection for comments =
45
  Native spam protection for WordPress, JetPack comments and any other comment plugins. The plugin moves spam comments to SPAM folder or you can set the option to ban spam comments silently. You can also enable the option in the plugin settings to auto-delete comments from SPAM folder.
46
 
47
- = Spam bot registrations filter =
48
  Filters spam bots on registration forms of WordPress, BuddyPress, bbPress, S2Member, WooCommerce, Profile builder, Login with AJAX and any other registration plugins.
49
 
50
  = Protection from contact form spam =
@@ -516,6 +516,16 @@ Yes, it is. Please read this article,
516
  10. Website's options.
517
 
518
  == Changelog ==
 
 
 
 
 
 
 
 
 
 
519
  = 5.103.1 September 14 2018 =
520
  * Fix: Error when saving settings.
521
  * Fix: Error when getting key automatically.
@@ -1646,6 +1656,16 @@ Yes, it is. Please read this article,
1646
  * First version
1647
 
1648
  == Upgrade Notice ==
 
 
 
 
 
 
 
 
 
 
1649
  = 5.103.1 September 14 2018 =
1650
  * Fix: Error when saving settings.
1651
  * Fix: Error when getting key automatically.
3
  Tags: spam, antispam, protection, comments, firewall
4
  Requires at least: 3.0
5
  Tested up to: 4.9
6
+ Stable tag: 5.104
7
  License: GPLv2
8
 
9
  Spam protection, antispam, all-in-one, premium plugin. No spam comments & users, no spam contact form & WooCommerce anti-spam.
44
  = AntiSpam protection for comments =
45
  Native spam protection for WordPress, JetPack comments and any other comment plugins. The plugin moves spam comments to SPAM folder or you can set the option to ban spam comments silently. You can also enable the option in the plugin settings to auto-delete comments from SPAM folder.
46
 
47
+ = Spam bots registrations filter =
48
  Filters spam bots on registration forms of WordPress, BuddyPress, bbPress, S2Member, WooCommerce, Profile builder, Login with AJAX and any other registration plugins.
49
 
50
  = Protection from contact form spam =
516
  10. Website's options.
517
 
518
  == Changelog ==
519
+ = 5.104 September 18 2018 =
520
+ * Fix: Error when saving settings.
521
+ * Fix: Trying update anti spam plugin for the first installation.
522
+ * Fix: Update system.
523
+ * Fix: Errors output.
524
+ * Fix: Plugin's settings under WPMS.
525
+ * Fix: SpamFireWall update.
526
+ * Fix: The server change system repaired.
527
+ * Mod: Cron saving tasks improved.
528
+
529
  = 5.103.1 September 14 2018 =
530
  * Fix: Error when saving settings.
531
  * Fix: Error when getting key automatically.
1656
  * First version
1657
 
1658
  == Upgrade Notice ==
1659
+ = 5.104 September 18 2018 =
1660
+ * Fix: Error when saving settings.
1661
+ * Fix: Trying update plugin plugin for the first installation.
1662
+ * Fix: Update system.
1663
+ * Fix: Errors output.
1664
+ * Fix: Plugin's settings under WPMS.
1665
+ * Fix: SpamFireWall update.
1666
+ * Fix: The server change system repaired.
1667
+ * Mod: Cron saving tasks improved.
1668
+
1669
  = 5.103.1 September 14 2018 =
1670
  * Fix: Error when saving settings.
1671
  * Fix: Error when getting key automatically.