query( $wpdb->prepare( "UPDATE %i SET excluded = 1 WHERE topic = 'unbekannt' AND topic_source = 'ai'", $t ) ); // 0.7.0: Content-Quality-Gate eingeführt — bereits erfasste Sections // aus den gespeicherten Feldern provisorisch bewerten (voller Re-Scan // verfeinert die Scores später mit Volltext statt 200-Zeichen-Excerpt). ADSEC_Inventory::backfill_scores(); // 0.28.0: Einzel-Ziel (goal_type) -> Mehrfach-Ziele (goal_types). Altes // 'tel_mailto' wird in die getrennten Typen 'tel' + 'mailto' aufgeteilt. $gs = get_option( 'adsec_settings', array() ); if ( !isset( $gs['goal_types'] ) ) { $map = array( 'form' => array('form'), 'tel_mailto' => array('tel', 'mailto'), 'selector' => array('selector'), ); $gs['goal_types'] = $map[$gs['goal_type'] ?? 'form'] ?? array('form'); update_option( 'adsec_settings', $gs, false ); } // 0.47.0: new reward (enquiry in the visit, normalized attention). The old // section scores were saturated after 10 s of visibility and cannot be // converted, so learning restarts once. Visit statistics stay untouched. if ( $prev && version_compare( $prev, '0.47.0', '<' ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-time migration on the plugin's own table. $wpdb->query( $wpdb->prepare( 'DELETE FROM %i', ADSEC_Database::stats_table() ) ); } // 0.49.0: remember the version before the update once, so the dashboard can // show what is new since then (cleared per user with "Got it"). if ( $prev && '' === (string) get_option( ADSEC_Updates::FROM_OPT, '' ) ) { update_option( ADSEC_Updates::FROM_OPT, $prev, false ); } // 0.48.1: snapshots made before the hidden-content rule are discarded and // made again (hourly step) – old copies may contain hidden parts whose // hidden attribute the HTML filter had removed. if ( $prev && version_compare( $prev, '0.48.1', '<' ) ) { // phpcs:ignore WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching -- one-time migration on the plugin's own table. $wpdb->query( $wpdb->prepare( 'UPDATE %i SET html = NULL', $t ) ); } update_option( 'adsec_version', ADSEC_VERSION, false ); } } /** * Bei Erstaktivierung einmalig ins Dashboard leiten (zeigt die Einführung). * Greift nicht bei Plugin-Updates (Zip-Overwrite löst keinen activate-Hook aus). */ public function maybe_activation_redirect() { if ( !get_option( 'adsec_activation_redirect' ) ) { return; } delete_option( 'adsec_activation_redirect' ); // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only flag set by WordPress core on bulk activation. if ( wp_doing_ajax() || isset( $_GET['activate-multi'] ) || !current_user_can( 'manage_options' ) ) { return; } wp_safe_redirect( admin_url( 'admin.php?page=adaptive-sections' ) ); exit; } public static function activate() { ADSEC_Database::install(); add_option( 'adsec_activation_redirect', 1, '', false ); if ( !wp_next_scheduled( self::CRON_HOOK ) ) { wp_schedule_event( time() + HOUR_IN_SECONDS, 'hourly', self::CRON_HOOK ); } $defaults = array( 'enabled' => false, 'goal_selector' => '', 'goal_types' => array('form'), ); add_option( 'adsec_settings', $defaults ); } /** Prozentwert sprachgerecht: „12,5 %“ auf Deutsch, „12.5%“ auf Englisch. */ public static function pct( $formatted ) { /* translators: %s: formatted number */ return sprintf( _x( '%s%%', 'percent value', 'sectivio' ), $formatted ); } public static function deactivate() { wp_clear_scheduled_hook( self::CRON_HOOK ); wp_clear_scheduled_hook( ADSEC_Report::HOOK ); } /** * Stündlicher Lernschritt: Events aggregieren, Modell aktualisieren, alte Events löschen. */ public function learning_tick() { $bandit = new ADSEC_Bandit(); $bandit->aggregate_events(); ADSEC_Daily::rollup(); ADSEC_Database::prune_events( 30 ); // Datenminimierung: Roh-Events max. 30 Tage. ADSEC_Sync::maybe_push(); } }