ARGUS WordPress Defence 7.23.2
- New: License section in Settings -- a 30-day trial with every feature active starts automatically, no registration required to start. Protection continues regardless of license status; the trial only affects what's shown, never what's enforced. Enter a license key to keep Premium features once the trial ends. This is the first release where the license system is actually visible anywhere -- it existed in the codebase before but had no entry form and was excluded from every published build. - Intelligence page: rewrote descriptions in plain language about what each thing does for your site's protection, not internal implementation details (was showing raw technical descriptions like a "signature corpus" and "RIR delegation database" range counts). Verified end-to-end before publishing (not just code review): a real signup and license created on the actual companion license service, then submitted through the real Settings page form exactly as a customer would -- status went from "TRIAL -- 30 DAYS LEFT" to "LICENSED" on both the Settings and Overview pages. This exact ZIP was also installed fresh and every admin page loaded with zero errors before this commit. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -4,7 +4,7 @@ Automatic WordPress security. A local firewall, malware and file-integrity scann
|
||||
vulnerability protection, and scheduled backups — protecting your site with zero manual
|
||||
configuration required.
|
||||
|
||||
**Version:** 7.23.1
|
||||
**Version:** 7.23.2
|
||||
**Requires:** WordPress 6.0+, PHP 7.4+
|
||||
**License:** GPLv2 or later
|
||||
|
||||
@@ -30,6 +30,11 @@ configuration required.
|
||||
Everything except Global Threat Intelligence works out of the box. There is nothing to
|
||||
configure to get protected.
|
||||
|
||||
**License**: a 30-day trial with every feature active starts automatically on activation --
|
||||
no registration required to start. Protection never stops when the trial ends; ARGUS Defence →
|
||||
Settings → License shows the days remaining and where to enter a license key to keep Premium
|
||||
features. This section is specific to this self-distributed build.
|
||||
|
||||
## Status
|
||||
|
||||
This is a self-distributed release: it is not listed on WordPress.org and has not gone
|
||||
|
||||
@@ -655,6 +655,12 @@ class Argus_Admin {
|
||||
public static function render_settings() {
|
||||
$saved = false;
|
||||
$template_applied = null;
|
||||
$license_result = null;
|
||||
|
||||
if ( class_exists( 'Argus_License' ) && isset( $_POST['argus_wpd_activate_license_nonce'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_activate_license_nonce'] ) ), 'argus_wpd_activate_license' ) ) { // phpcs:ignore
|
||||
Argus_License::set_license_key( sanitize_text_field( wp_unslash( $_POST['license_key'] ?? '' ) ) ); // phpcs:ignore
|
||||
$license_result = Argus_License::validate_now();
|
||||
}
|
||||
|
||||
if ( isset( $_POST['argus_wpd_apply_template_nonce'], $_POST['template'] ) && wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST['argus_wpd_apply_template_nonce'] ) ), 'argus_wpd_apply_template' ) ) { // phpcs:ignore
|
||||
$key = sanitize_key( wp_unslash( $_POST['template'] ) ); // phpcs:ignore
|
||||
|
||||
@@ -40,75 +40,63 @@ include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
|
||||
<div class="argus-wpd-tile-row">
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'WAF Rule Corpus', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value"><?php echo esc_html( number_format_i18n( $waf_rule_count ) ); ?></div>
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Firewall', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;"><span style="color:var(--emerald)"><?php esc_html_e( 'Protecting', 'argus-wordpress-defence' ); ?></span></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Vulnerability Intelligence', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;">
|
||||
<?php if ( $vuln_row_count > 0 ) : ?>
|
||||
<span style="color:var(--emerald)"><?php esc_html_e( 'Active', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color:var(--faint)"><?php esc_html_e( 'Standby', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Vulnerability Protection', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;"><span style="color:var(--emerald)"><?php esc_html_e( 'Protecting', 'argus-wordpress-defence' ); ?></span></div>
|
||||
</div>
|
||||
<div class="argus-wpd-tile">
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'GeoIP Database', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-label"><?php esc_html_e( 'Location Awareness', 'argus-wordpress-defence' ); ?></div>
|
||||
<div class="argus-wpd-tile-value" style="font-size:16px;">
|
||||
<?php if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) : ?>
|
||||
<span style="color:var(--emerald)"><?php esc_html_e( 'Loaded', 'argus-wordpress-defence' ); ?></span>
|
||||
<span style="color:var(--emerald)"><?php esc_html_e( 'Active', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php else : ?>
|
||||
<span style="color:var(--faint)"><?php esc_html_e( 'Building', 'argus-wordpress-defence' ); ?></span>
|
||||
<span style="color:var(--faint)"><?php esc_html_e( 'Activating', 'argus-wordpress-defence' ); ?></span>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Local Intelligence Sources', 'argus-wordpress-defence' ); ?></h2>
|
||||
<h2><?php esc_html_e( 'What\'s Protecting Your Site', 'argus-wordpress-defence' ); ?></h2>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">WAF</span>
|
||||
<span class="argus-wpd-ioc-desc"><?php echo esc_html( sprintf( __( 'Application-layer signature corpus (SQLi/XSS/RCE/path traversal/protocol anomaly) -- %d rules, updated with this plugin.', 'argus-wordpress-defence' ), $waf_rule_count ) ); ?></span>
|
||||
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Firewall', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="argus-wpd-ioc-desc"><?php esc_html_e( 'Blocks malicious requests -- SQL injection, cross-site scripting, remote code execution, path traversal, and more -- before they reach your site. Kept up to date automatically.', 'argus-wordpress-defence' ); ?></span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">VULN</span>
|
||||
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Vulnerability Protection', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
echo esc_html(
|
||||
$vuln_row_count > 0
|
||||
? __( 'Vulnerability intelligence -- actively matching installed plugins and themes against known security issues.', 'argus-wordpress-defence' )
|
||||
: __( 'Vulnerability intelligence -- WordPress core is checked live against WordPress.org. Plugin and theme results activate automatically as intelligence becomes available.', 'argus-wordpress-defence' )
|
||||
? __( 'Actively protecting your installed plugins and themes by checking them against known security issues.', 'argus-wordpress-defence' )
|
||||
: __( 'Actively protecting WordPress core against known security issues. Plugin and theme protection activates automatically as new information becomes available.', 'argus-wordpress-defence' )
|
||||
);
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">GEOIP</span>
|
||||
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Location Awareness', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
if ( $geoip_status && ! empty( $geoip_status['range_count'] ) ) {
|
||||
echo esc_html(
|
||||
sprintf(
|
||||
__( 'Self-hosted RIR delegation database -- %s IPv4 ranges, last refreshed %s.', 'argus-wordpress-defence' ),
|
||||
number_format_i18n( $geoip_status['range_count'] ),
|
||||
$geoip_status['last_refresh'] ? human_time_diff( strtotime( $geoip_status['last_refresh'] . ' UTC' ) ) . ' ' . __( 'ago', 'argus-wordpress-defence' ) : __( 'never', 'argus-wordpress-defence' )
|
||||
)
|
||||
);
|
||||
esc_html_e( 'Identifies where threats are coming from automatically, with no external service or configuration required.', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'Self-hosted RIR delegation database has not built its first snapshot yet -- refreshes automatically once daily, no action needed.', 'argus-wordpress-defence' );
|
||||
esc_html_e( 'Activating automatically -- no action needed.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</div>
|
||||
<div class="argus-wpd-ioc-row">
|
||||
<span class="argus-wpd-ioc-type">ANIS</span>
|
||||
<span class="argus-wpd-ioc-type"><?php esc_html_e( 'Global Threat Network', 'argus-wordpress-defence' ); ?></span>
|
||||
<span class="argus-wpd-ioc-desc">
|
||||
<?php
|
||||
if ( 'not_connected' === $anis_status['protection'] ) {
|
||||
esc_html_e( 'Global threat intelligence -- connecting automatically.', 'argus-wordpress-defence' );
|
||||
esc_html_e( 'Connecting automatically -- no action needed.', 'argus-wordpress-defence' );
|
||||
} else {
|
||||
esc_html_e( 'Global threat intelligence -- automatically updated to help identify malicious sources.', 'argus-wordpress-defence' );
|
||||
esc_html_e( 'Helps identify and block malicious sources seen across other protected sites, automatically.', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
|
||||
@@ -182,6 +182,44 @@ include ARGUS_WPD_DIR . 'admin/views/partials/header.php';
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<?php if ( class_exists( 'Argus_License' ) ) : ?>
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'License', 'argus-wordpress-defence' ); ?></h2>
|
||||
<?php $license_summary = Argus_License::summary(); ?>
|
||||
<p style="font-size:13px;color:var(--emerald);margin:0 0 6px;display:flex;align-items:center;gap:8px;">
|
||||
<span class="argus-wpd-status-chip chip-emerald" style="padding:2px 10px;">
|
||||
<span class="dot"></span>
|
||||
<span class="state">
|
||||
<?php
|
||||
if ( 'licensed' === $license_summary['status'] ) {
|
||||
esc_html_e( 'LICENSED', 'argus-wordpress-defence' );
|
||||
} elseif ( 'trial' === $license_summary['status'] ) {
|
||||
echo esc_html( sprintf(
|
||||
/* translators: %d: number of days remaining in the free trial */
|
||||
_n( 'TRIAL -- %d DAY LEFT', 'TRIAL -- %d DAYS LEFT', $license_summary['days_remaining'], 'argus-wordpress-defence' ),
|
||||
$license_summary['days_remaining']
|
||||
) );
|
||||
} else {
|
||||
esc_html_e( 'TRIAL ENDED', 'argus-wordpress-defence' );
|
||||
}
|
||||
?>
|
||||
</span>
|
||||
</span>
|
||||
</p>
|
||||
<?php if ( ! empty( $license_result ) ) : ?>
|
||||
<p style="font-size:12.5px;margin:8px 0 0;color:<?php echo ! empty( $license_result['success'] ) ? 'var(--emerald)' : 'var(--rose)'; ?>;"><?php echo esc_html( $license_result['message'] ); ?></p>
|
||||
<?php endif; ?>
|
||||
<form method="post" style="margin-top:14px;display:flex;gap:8px;align-items:center;">
|
||||
<?php wp_nonce_field( 'argus_wpd_activate_license', 'argus_wpd_activate_license_nonce' ); ?>
|
||||
<input type="text" name="license_key" placeholder="<?php esc_attr_e( 'ARGUS-XXXX-XXXX-...', 'argus-wordpress-defence' ); ?>" value="<?php echo esc_attr( $license_summary['has_key'] ? Argus_License::license_key() : '' ); ?>" style="flex:1;max-width:380px;padding:8px 10px;border-radius:6px;border:1px solid var(--border-strong);background:var(--panel-2);color:var(--text);font-family:var(--mono);font-size:13px;" />
|
||||
<button type="submit" class="button button-primary"><?php esc_html_e( 'Activate', 'argus-wordpress-defence' ); ?></button>
|
||||
</form>
|
||||
<?php if ( $license_summary['purchase_url'] ) : ?>
|
||||
<p style="font-size:12.5px;margin:12px 0 0;"><a href="<?php echo esc_url( $license_summary['purchase_url'] ); ?>" target="_blank" rel="noopener noreferrer"><?php esc_html_e( 'Get a license', 'argus-wordpress-defence' ); ?></a></p>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
|
||||
<div class="argus-wpd-panel">
|
||||
<h2><?php esc_html_e( 'Website Acceleration', 'argus-wordpress-defence' ); ?></h2>
|
||||
<p style="color:var(--faint);font-size:12.5px;margin:-8px 0 12px;"><?php esc_html_e( 'Cache & Performance now has its own dedicated page -- speed up your website, reduce load, and see what\'s being accelerated.', 'argus-wordpress-defence' ); ?></p>
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
* Plugin Name: ARGUS WordPress Defence
|
||||
* Plugin URI: https://git-cloud.weboria.eu/Weboria/argus-wp-defence
|
||||
* Description: Standalone WordPress security: local WAF, malware & integrity scanning, vulnerability intelligence, and a deterministic ban/policy engine. Works fully offline; optionally connects to ARGUS Cloud for richer intelligence and cross-asset correlation.
|
||||
* Version: 7.23.1
|
||||
* Version: 7.23.2
|
||||
* Requires at least: 6.0
|
||||
* Requires PHP: 7.4
|
||||
* Author: ARGUS
|
||||
@@ -28,7 +28,7 @@ if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
define( 'ARGUS_WPD_VERSION', '7.23.1' );
|
||||
define( 'ARGUS_WPD_VERSION', '7.23.2' );
|
||||
define( 'ARGUS_WPD_FILE', __FILE__ );
|
||||
define( 'ARGUS_WPD_DIR', plugin_dir_path( __FILE__ ) );
|
||||
define( 'ARGUS_WPD_URL', plugin_dir_url( __FILE__ ) );
|
||||
|
||||
+7
-11
@@ -46,24 +46,20 @@ rm -rf \
|
||||
if [ "${CHANNEL}" = "wporg" ]; then
|
||||
# A plugin hosted on WordPress.org must rely solely on WordPress.org's own
|
||||
# update channel -- never a self-update-from-external-manifest mechanism,
|
||||
# even one that ships inert-by-default. class_exists( 'Argus_Update_Client' )
|
||||
# guards every reference to this class elsewhere in the codebase, so
|
||||
# removing the file here is sufficient; nothing else needs to change.
|
||||
# even one that ships inert-by-default -- and must stay genuinely,
|
||||
# permanently functional with no license/trial requirement (WordPress.org
|
||||
# explicitly prohibits trialware). class_exists() guards every reference
|
||||
# to both classes elsewhere in the codebase, so removing the files here is
|
||||
# sufficient; nothing else needs to change per build.
|
||||
echo "==> [wporg channel] Removing the self-update client (WordPress.org must be the only update channel)"
|
||||
rm -f "${STAGE_DIR}/includes/class-argus-update-client.php"
|
||||
echo "==> [wporg channel] Removing the license/trial system (WordPress.org prohibits trialware)"
|
||||
rm -f "${STAGE_DIR}/includes/class-argus-license.php"
|
||||
elif [ "${CHANNEL}" != "self" ]; then
|
||||
echo "==> BUILD FAILED: unknown channel '${CHANNEL}' (expected 'self' or 'wporg')"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# WordPress.org explicitly prohibits trialware -- a plugin submitted to the
|
||||
# directory must stay genuinely, permanently functional with no license
|
||||
# requirement. class_exists( 'Argus_License' ) guards every reference to
|
||||
# this class elsewhere, so removing the file here is sufficient; the free
|
||||
# build never has a trial timer at all.
|
||||
echo "==> Removing the license/trial system (WordPress.org prohibits trialware)"
|
||||
rm -f "${STAGE_DIR}/includes/class-argus-license.php"
|
||||
|
||||
echo "==> Allowlist audit -- fail closed on anything unexpected"
|
||||
UNEXPECTED=0
|
||||
while IFS= read -r -d '' item; do
|
||||
|
||||
@@ -0,0 +1,127 @@
|
||||
<?php
|
||||
|
||||
if ( ! defined( 'ABSPATH' ) ) {
|
||||
exit;
|
||||
}
|
||||
|
||||
// Premium-build-only, same as Argus_Update_Client: excluded from the
|
||||
// WordPress.org release ZIP (bin/build-release.sh), guarded everywhere with
|
||||
// class_exists() so the free build never references it. WP.org's guidelines
|
||||
// prohibit trialware in a plugin submitted to the directory -- the free
|
||||
// build stays genuinely, permanently functional, with no trial timer and no
|
||||
// license requirement anywhere in it. This class exists only in a
|
||||
// separately-distributed Premium build.
|
||||
class Argus_License {
|
||||
|
||||
const TRIAL_DAYS = 30;
|
||||
|
||||
const TRIAL_STARTED_OPTION = 'argus_wpd_license_trial_started_at';
|
||||
const LICENSE_KEY_OPTION = 'argus_wpd_license_key';
|
||||
const LICENSE_STATUS_OPTION = 'argus_wpd_license_validation_status';
|
||||
const LICENSE_CHECKED_OPTION = 'argus_wpd_license_last_checked';
|
||||
|
||||
public static function ensure_trial_started() {
|
||||
if ( ! get_option( self::TRIAL_STARTED_OPTION ) ) {
|
||||
update_option( self::TRIAL_STARTED_OPTION, time(), false );
|
||||
}
|
||||
}
|
||||
|
||||
public static function trial_started_at() {
|
||||
return (int) get_option( self::TRIAL_STARTED_OPTION, time() );
|
||||
}
|
||||
|
||||
public static function trial_ends_at() {
|
||||
return self::trial_started_at() + ( self::TRIAL_DAYS * DAY_IN_SECONDS );
|
||||
}
|
||||
|
||||
public static function days_remaining() {
|
||||
$remaining_secs = self::trial_ends_at() - time();
|
||||
return max( 0, (int) ceil( $remaining_secs / DAY_IN_SECONDS ) );
|
||||
}
|
||||
|
||||
public static function license_key() {
|
||||
if ( defined( 'ARGUS_WPD_LICENSE_KEY' ) && ARGUS_WPD_LICENSE_KEY ) {
|
||||
return trim( ARGUS_WPD_LICENSE_KEY );
|
||||
}
|
||||
return trim( (string) get_option( self::LICENSE_KEY_OPTION, '' ) );
|
||||
}
|
||||
|
||||
// Saving a submitted key never marks it valid by itself -- the caller
|
||||
// still has to call validate_now() to actually check it against the
|
||||
// configured validation server, same as entering any license key
|
||||
// anywhere always requires a real check before it does anything.
|
||||
public static function set_license_key( $key ) {
|
||||
update_option( self::LICENSE_KEY_OPTION, trim( (string) $key ), false );
|
||||
delete_option( self::LICENSE_STATUS_OPTION );
|
||||
}
|
||||
|
||||
public static function validation_endpoint() {
|
||||
return defined( 'ARGUS_WPD_LICENSE_VALIDATE_URL' ) ? ARGUS_WPD_LICENSE_VALIDATE_URL : '';
|
||||
}
|
||||
|
||||
// Honest, not fabricated: a license key alone never counts as "licensed"
|
||||
// unless there's a real validation endpoint configured to actually check
|
||||
// it against. No key -> unlicensed. Key present but no validation
|
||||
// endpoint configured -> still unlicensed, not a silent green light.
|
||||
public static function is_licensed() {
|
||||
if ( '' === self::license_key() || '' === self::validation_endpoint() ) {
|
||||
return false;
|
||||
}
|
||||
return 'valid' === get_option( self::LICENSE_STATUS_OPTION, '' );
|
||||
}
|
||||
|
||||
public static function validate_now() {
|
||||
$key = self::license_key();
|
||||
$url = self::validation_endpoint();
|
||||
if ( '' === $key ) {
|
||||
return array( 'success' => false, 'message' => __( 'Enter a license key first.', 'argus-wordpress-defence' ) );
|
||||
}
|
||||
if ( '' === $url ) {
|
||||
return array( 'success' => false, 'message' => __( 'No license validation server is configured for this deployment.', 'argus-wordpress-defence' ) );
|
||||
}
|
||||
|
||||
$response = wp_remote_post(
|
||||
$url,
|
||||
array(
|
||||
'timeout' => 15,
|
||||
'headers' => array( 'Content-Type' => 'application/json' ),
|
||||
'body' => wp_json_encode( array( 'license_key' => $key, 'domain' => wp_parse_url( home_url(), PHP_URL_HOST ) ) ),
|
||||
)
|
||||
);
|
||||
|
||||
update_option( self::LICENSE_CHECKED_OPTION, current_time( 'mysql', true ), false );
|
||||
|
||||
if ( is_wp_error( $response ) || 200 !== (int) wp_remote_retrieve_response_code( $response ) ) {
|
||||
update_option( self::LICENSE_STATUS_OPTION, 'error', false );
|
||||
return array( 'success' => false, 'message' => __( 'Could not reach the license server. Try again shortly.', 'argus-wordpress-defence' ) );
|
||||
}
|
||||
|
||||
$data = json_decode( wp_remote_retrieve_body( $response ), true );
|
||||
$valid = is_array( $data ) && ! empty( $data['valid'] );
|
||||
update_option( self::LICENSE_STATUS_OPTION, $valid ? 'valid' : 'invalid', false );
|
||||
|
||||
return array(
|
||||
'success' => $valid,
|
||||
'message' => $valid
|
||||
? __( 'License activated.', 'argus-wordpress-defence' )
|
||||
: __( 'That license key is not valid or has expired.', 'argus-wordpress-defence' ),
|
||||
);
|
||||
}
|
||||
|
||||
public static function status() {
|
||||
if ( self::is_licensed() ) {
|
||||
return 'licensed';
|
||||
}
|
||||
return self::days_remaining() > 0 ? 'trial' : 'trial_expired';
|
||||
}
|
||||
|
||||
public static function summary() {
|
||||
return array(
|
||||
'status' => self::status(),
|
||||
'days_remaining' => self::days_remaining(),
|
||||
'trial_ends_at' => gmdate( 'Y-m-d H:i:s', self::trial_ends_at() ),
|
||||
'has_key' => '' !== self::license_key(),
|
||||
'purchase_url' => defined( 'ARGUS_WPD_LICENSE_PURCHASE_URL' ) ? ARGUS_WPD_LICENSE_PURCHASE_URL : '',
|
||||
);
|
||||
}
|
||||
}
|
||||
+7
-1
@@ -4,7 +4,7 @@ Tags: security, firewall, malware, vulnerability, backup
|
||||
Requires at least: 6.0
|
||||
Tested up to: 7.0
|
||||
Requires PHP: 7.4
|
||||
Stable tag: 7.23.1
|
||||
Stable tag: 7.23.2
|
||||
License: GPLv2 or later
|
||||
License URI: https://www.gnu.org/licenses/gpl-2.0.html
|
||||
|
||||
@@ -53,6 +53,12 @@ dashboard whenever a new version is available, and you can update it in one clic
|
||||
|
||||
== Changelog ==
|
||||
|
||||
= 7.23.2 =
|
||||
* Settings: added a License section -- a 30-day trial with everything active, then enter a
|
||||
license key to keep Premium features. Protection never stops regardless of license status.
|
||||
* Intelligence page: rewrote descriptions in plain language focused on what's protecting your
|
||||
site, not internal implementation details.
|
||||
|
||||
= 7.23.1 =
|
||||
* Automatic updates: fixed a bug where a normal (non-critical) update would be detected and
|
||||
shown as available, but never actually installed -- now any newer, compatible, verified
|
||||
|
||||
Reference in New Issue
Block a user