feat: Werbe-Badge im content blocker (unten rechts) + abschaltbar nur mit unlimited (v1.5.0)

- Kleines Badge "GDPR Content Blocker" unten rechts im platzhalter, verlinkt
  auf die kaufseite (rel=nofollow sponsored). Server- und client-seitig.
- Wird IMMER angezeigt; abschaltbar via checkbox im Darstellung-tab
  ("Werbe-Badge ausblenden") - die checkbox ist aber nur mit aktiver
  Unlimited-lizenz nutzbar (sonst disabled) und greift am render-punkt nur,
  wenn is_unlimited() true ist.
- Dafuer speichert das plugin jetzt max_activations aus der backend-antwort
  (activate/validate/swap) und bietet is_unlimited().

+ i18n DE/EN (134 strings). version 1.5.0.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
s4luorth
2026-06-08 14:08:08 +02:00
parent c796400492
commit 2ef1d0769b
10 changed files with 101 additions and 11 deletions

View File

@@ -64,6 +64,7 @@ class CB_License {
'last_check' => 0,
'message' => '',
'pending_domains' => [],
'max_activations' => 0, // -1 = unlimited (from the backend)
] );
if ( ! is_array( $lic['pending_domains'] ) ) {
$lic['pending_domains'] = [];
@@ -75,6 +76,12 @@ class CB_License {
return self::get_license()['status'] === 'active';
}
/** True only for an active, unlimited-seat (max_activations = -1) license. */
public static function is_unlimited(): bool {
$lic = self::get_license();
return $lic['status'] === 'active' && (int) ( $lic['max_activations'] ?? 0 ) === -1;
}
/** Mask a key for display: keep dashes + last 4 chars, hide the rest. */
public static function mask_key( string $key ): string {
$n = strlen( $key );
@@ -148,7 +155,7 @@ class CB_License {
}
if ( ! empty( $result['ok'] ) && ( $result['status'] ?? '' ) === 'valid' ) {
self::store( $key, 'active', __( 'Lizenz erfolgreich aktiviert.', 'gdpr-content-blocker' ) );
self::store( $key, 'active', __( 'Lizenz erfolgreich aktiviert.', 'gdpr-content-blocker' ), [], isset( $result['max_activations'] ) ? (int) $result['max_activations'] : null );
} elseif ( ( $result['code'] ?? '' ) === 'limit_reached' ) {
// No free slots: keep the key and offer to release one of the bound domains.
$domains = is_array( $result['domains'] ?? null ) ? $result['domains'] : [];
@@ -216,7 +223,7 @@ class CB_License {
/* translators: %s: released domain */
__( 'Domain %s freigegeben und diese Seite aktiviert.', 'gdpr-content-blocker' ),
$release
) );
), [], isset( $result['max_activations'] ) ? (int) $result['max_activations'] : null );
} else {
$domains = is_array( $result['domains'] ?? null ) ? $result['domains'] : $lic['pending_domains'];
$msg = $result['error'] ?? __( 'Aktivierung fehlgeschlagen.', 'gdpr-content-blocker' );
@@ -269,14 +276,18 @@ class CB_License {
}
if ( ! empty( $result['ok'] ) && ( $result['status'] ?? '' ) === 'valid' ) {
self::store( $lic['key'], 'active', '' );
self::store( $lic['key'], 'active', '', [], isset( $result['max_activations'] ) ? (int) $result['max_activations'] : null );
} else {
$msg = $result['error'] ?? __( 'Lizenz nicht mehr gültig.', 'gdpr-content-blocker' );
self::store( $lic['key'], 'invalid', $msg );
}
}
private static function store( string $key, string $status, string $message, array $pending_domains = [] ): void {
private static function store( string $key, string $status, string $message, array $pending_domains = [], ?int $max = null ): void {
// Preserve the previously stored seat count unless a fresh one is given.
$prev = get_option( CB_LICENSE_OPTION, [] );
$prev_max = is_array( $prev ) && isset( $prev['max_activations'] ) ? (int) $prev['max_activations'] : 0;
update_option( CB_LICENSE_OPTION, [
'key' => $key,
'status' => $status,
@@ -284,6 +295,7 @@ class CB_License {
'last_check' => time(),
'message' => $message,
'pending_domains' => array_values( array_filter( array_map( 'strval', $pending_domains ) ) ),
'max_activations' => $max !== null ? $max : $prev_max,
] );
// License state changed → invalidate cached update info and force WP to