<b>ver. 0.312 - 23.02.2026</b><br />
FIX - krytyczne bugi integracji Apilo: curl_getinfo po curl_close, nieskończona pętla wysyłki, ceny 0.00 PLN, walidacja cen
<hr>
<b>ver. 0.311 - 23.02.2026</b><br />
FIX - race condition callback pĹ‚atnoĹ›ci Apilo, persistence filtrĂłw tabel admin, poprawki cen zamĂłwieĹ„
<hr>
<b>ver. 0.310 - 23.02.2026</b><br />
NEW - Zakladka Logi w sekcji Integracje (podglad pp_log z paginacja, sortowaniem, filtrami)
<hr>
<b>ver. 0.309 - 23.02.2026</b><br />
NEW - ApiloLogger (logowanie operacji Apilo do pp_log), cache-busting CSS/JS w admin panelu, poprawki UI listy produktow, clipboard API
<hr>
<b>ver. 0.308 - 22.02.2026</b><br />
NEW - kolorowe badge statusow zamowien, walidacja hex, sanityzacja HTML transport, optymalizacja SQL
<hr>
<b>ver. 0.308 - 22.02.2026</b><br />
NEW - kolorowe badge statusow zamowien, walidacja hex, sanityzacja HTML transport, optymalizacja SQL
<hr>
<?php
// Auto-generated changelog from manifest files + legacy entries.
// Scans manifest JSON files, merges with changelog-legacy.json, sorts descending, outputs HTML.

$entries = [];

// 1. Scan manifest files
$manifests = glob( __DIR__ . '/0.*/ver_*_manifest.json' );
if ( $manifests ) {
    foreach ( $manifests as $file ) {
        $json = @file_get_contents( $file );
        if ( !$json ) continue;
        // Strip UTF-8 BOM if present
        if ( substr( $json, 0, 3 ) === "\xEF\xBB\xBF" ) {
            $json = substr( $json, 3 );
        }
        $data = @json_decode( $json, true );
        if ( !$data || empty( $data['version'] ) || empty( $data['changelog'] ) ) continue;

        $date = isset( $data['date'] ) ? $data['date'] : '';
        // Convert YYYY-MM-DD to DD.MM.YYYY
        if ( $date && preg_match( '/^(\d{4})-(\d{2})-(\d{2})$/', $date, $m ) ) {
            $date = $m[3] . '.' . $m[2] . '.' . $m[1];
        }

        $entries[] = [
            'version' => (float) $data['version'],
            'ver_str' => $data['version'],
            'date'    => $date,
            'text'    => $data['changelog'],
        ];
    }
}

// 2. Load legacy entries
$legacyFile = __DIR__ . '/changelog-legacy.json';
if ( file_exists( $legacyFile ) ) {
    $legacyJson = @file_get_contents( $legacyFile );
    if ( $legacyJson ) {
        $legacy = @json_decode( $legacyJson, true );
        if ( is_array( $legacy ) ) {
            foreach ( $legacy as $item ) {
                if ( empty( $item['version'] ) ) continue;
                $entries[] = [
                    'version' => (float) $item['version'],
                    'ver_str' => $item['version'],
                    'date'    => isset( $item['date'] ) ? $item['date'] : '',
                    'text'    => isset( $item['text'] ) ? $item['text'] : '',
                ];
            }
        }
    }
}

// 3. Sort descending by version
usort( $entries, function ( $a, $b ) {
    if ( $a['version'] == $b['version'] ) return 0;
    return ( $a['version'] > $b['version'] ) ? -1 : 1;
} );

// 4. Output HTML
foreach ( $entries as $entry ) {
    $header = 'ver. ' . htmlspecialchars( $entry['ver_str'] );
    if ( $entry['date'] ) {
        $header .= ' - ' . htmlspecialchars( $entry['date'] );
    }
    $text = nl2br( htmlspecialchars( $entry['text'] ) );

    echo '<b>' . $header . '</b><br />' . "\n";
    echo $text . "\n";
    echo '<hr>' . "\n";
}
