Strona firmowa · Timwhite, drukarnia i agencja reklamowa z Bielska-Białej · 2026 · 3 dni
Timwhite: nowa strona drukarni z Bielska-Białej w miejsce WordPressa, pod tymi samymi adresami
Stare adresy działają dalej, osiem nieaktualnych podstron przekierowuje na nowe, a wyłączony WordPress czeka na serwerze na wypadek powrotu.
- Astro
- TypeScript
- GSAP
- Lenis
- Node.js
- Nodemailer
- Docker
- Nginx
- GitHub Actions
Wyzwanie
Drukarnia miała stronę na WordPressie z podstronami, które przybywały latami: szycie toreb reklamowych, kopiowanie i nadruk płyt CD i DVD, wsparcie marketingowe, projekty graficzne, osobno kubki i osobno usługi poligraficzne. Nowa strona miała pokazać cztery usługi, które drukarnia sprzedaje dziś, zbierać zapytania o wycenę razem z plikiem do druku i przy tym nie zgubić żadnego starego adresu, bo każdy z nich mógł przyprowadzać klientów z wyszukiwarki.
Nasze rozwiązanie
Strona w Astro z czterema podstronami usług pod tymi samymi adresami co w WordPressie. Osiem starych adresów przekierowuje kodem 301 na najbliższą nową podstronę, a ścieżki WordPressa, takie jak /wp-json/ i /wp-admin/, zwracają kod 410, żeby wyszukiwarka szybciej usunęła je z indeksu. Formularz wyceny pyta o produkt, nakład, termin, wykończenie i plik. Drukarnia dostaje zapytanie mailem i odpowiada zwykłym „Odpowiedz”, bo adres zwrotny to adres klienta. Stary WordPress z bazą danych został na serwerze, wyłączony, i wraca jedną komendą.
3 dni
Od pierwszego commita do strony na domenie
6
Podstron pod adresami ze starej strony
8
Przekierowań 301 ze starych podstron
13
Testów uruchamianych przed każdym wdrożeniem
Co zbudowaliśmy
- 01 Strona główna, cztery podstrony usług, kontakt z wyceną i polityka prywatności
- 02 Adresy podstron identyczne z adresami w starym WordPressie
- 03 Osiem przekierowań 301 ze starych podstron, np. /szycie-toreb-reklamowych/ na odzież reklamową, /kubki/ na /kubki-reklamowe/
- 04 Kod 410 dla /wp-json/, /wp-admin/, /xmlrpc.php i katalogów WordPressa
- 05 Formularz wyceny w czterech krokach: produkt, parametry (nakład, termin, wykończenie, opis), plik, dane kontaktowe
- 06 Plik do 20 MB w formatach PDF, AI, CDR, EPS, ZIP, PNG, JPG, TIFF i SVG
- 07 Sprawdzanie sygnatury pliku: PDF, ZIP, PNG i JPG muszą mieć zawartość zgodną z rozszerzeniem
- 08 Pułapka na boty: ukryte pole, po którego wypełnieniu serwer odpowiada sukcesem i nic nie wysyła
- 09 Odrzucanie formularza wysłanego szybciej niż 3 sekundy po wczytaniu strony i limit jednego zapytania na minutę z adresu IP
- 10 Usuwanie znaków nowej linii z pól trafiających do nagłówków maila (ochrona przed wstrzyknięciem nagłówków)
- 11 Mail do drukarni z adresem zwrotnym klienta; potwierdzenie dla klienta włączane jedną zmienną
- 12 Mapa Google ładowana dopiero po kliknięciu
- 13 Preloader z pionkiem z logo pokazywany raz na wizytę, kurtyna między podstronami, płynne przewijanie (Lenis)
- 14 Przy ograniczeniu ruchu w systemie wyłączone płynne przewijanie, przypinanie sekcji, kurtyna i przesuwane taśmy; treść czytelna także bez JavaScriptu
- 15 Dane strukturalne LocalBusiness, obrazy Open Graph, mapa witryny podana w robots.txt
- 16 Wdrożenie z GitHub Actions na runnerze na serwerze: build, testy, podmiana kontenera, smoke test z powrotem do poprzedniej wersji
Spis treści +
Punkt wyjścia
Timwhite to drukarnia i agencja reklamowa z Bielska-Białej: druk cyfrowy i offsetowy, odzież z nadrukiem, długopisy z grawerem, kubki. Stara strona stała na WordPressie i miała podstrony usług, które przybywały przez lata, w tym szycie toreb, kopiowanie płyt CD i DVD oraz wsparcie marketingowe.
Zadanie miało dwie części. Pierwsza: pokazać cztery usługi, które drukarnia sprzedaje dziś, i zbierać zapytania o wycenę z plikiem do druku. Druga: przenieść stronę tak, żeby żaden link z Google ani ze starych materiałów nie kończył się błędem 404.
Decyzje, które ukształtowały projekt
Adresy przeniesione co do znaku
Podstrony nowej strony mają dokładnie te same adresy co w WordPressie: /druk-cyfrowy-i-offsetowy/, /odziez-reklamowa-z-nadrukiem/, /kubki-reklamowe/, /kontakt/. Osiem adresów, których już nie ma, przekierowuje kodem 301 na najbliższy odpowiednik. Projekty graficzne trafiają na druk, szycie toreb na odzież, a kopiowanie płyt i wsparcie marketingowe na kontakt. Ścieżki samego WordPressa (/wp-json/, /wp-admin/, /xmlrpc.php) zwracają 410 zamiast 404, bo ten kod mówi wyszukiwarce, że strona zniknęła na stałe.
Przełączenie z drogą powrotu
Nowa strona działa w osobnym kontenerze na tym samym serwerze co stary WordPress. WordPress i jego baza zostały w tym samym pliku docker-compose pod profilem legacy: wyłączone, z nietkniętymi danymi. Skrypt przełączenia podmienia konfigurację Nginx, a potem odpytuje każdą podstronę, siedem przekierowań i /wp-json/. Jeśli któryś adres zwróci coś innego, skrypt sam przywraca WordPressa.
Formularz wyceny z plikiem do druku
Wycena idzie w czterech krokach: produkt, parametry (nakład, termin, wykończenie, opis), plik i dane kontaktowe. Plik może mieć do 20 MB i format PDF, AI, CDR, EPS, ZIP, PNG, JPG, TIFF albo SVG. Serwer sprawdza nie tylko rozszerzenie. PDF, ZIP, PNG i JPG muszą zaczynać się od właściwej sygnatury, więc plik .exe przemianowany na .pdf nie przejdzie.
Mail do drukarni ma jako adres zwrotny adres klienta, więc odpowiedź z ceną to zwykłe „Odpowiedz” w skrzynce. Po wysłaniu formularza na stronie pojawia się pieczątka „PRZYJĘTO” z datą.
Ochrona bez captchy
Formularz nie ma captchy. Ma ukryte pole, które wypełnia tylko bot, a serwer odpowiada mu sukcesem i niczego nie wysyła, więc bot nie wie, że odpadł. Odrzuca formularz wysłany szybciej niż 3 sekundy po wczytaniu strony i przyjmuje jedno zapytanie na minutę z adresu IP. Pola, które trafiają do nagłówków maila, są czyszczone ze znaków nowej linii, bo przez nie dałoby się dopisać własne nagłówki i rozsyłać przez formularz spam.
Wygląd z hali drukarni
Krawędzie sekcji są perforowane jak papier z bloczka, w rogach tabel są znaczniki pasowania, sekcje są numerowane jak arkusze, a w tle hero leży raster rysowany na canvasie. Paleta to kolor papieru, czerń i jeden koralowy akcent.
Preloader z pionkiem z logo pokazuje się raz na wizytę, a nie przy każdym przejściu. Gdy ktoś ma w systemie włączone ograniczenie ruchu, strona wyłącza płynne przewijanie, przypinanie sekcji, kurtynę między podstronami i przesuwane taśmy. Krótkie pojawianie się tekstu zostaje. Treść jest czytelna także bez JavaScriptu.
Co z tego wyszło
Pierwszy commit powstał 29 września 2026 r., a 1 października timwhite.pl działało już na nowej stronie. Sześć podstron ma adresy ze starej strony, osiem starych adresów przekierowuje na nowe, a WordPress czeka wyłączony na serwerze.
Każda zmiana po starcie przechodzi tę samą drogę. Pull request buduje stronę, a merge uruchamia na serwerze build, 13 testów, podmianę kontenera i smoke test. Jeśli nowa wersja nie odpowiada, wraca poprzednia.
Technicznie
Astro 7 generuje statyczne strony, a jedyny endpoint po stronie serwera, /api/wycena, obsługuje adapter Node. Nie ma Reacta ani Tailwinda, style stoją na tokenach CSS --tw-*. Animacje to GSAP z ScrollTrigger i SplitText, przewijanie obsługuje Lenis. Fonty: Bricolage Grotesque w nagłówkach i tekście, JetBrains Mono w etykietach i numeracji.
Walidacja, limit zapytań i szablony maili są w jednym module bez zależności od Astro, więc testy node --test sprawdzają go bez uruchamiania strony: pułapkę na boty, zbyt szybkie wysłanie, plik .exe, PDF z błędną sygnaturą, przekroczony limit 20 MB i znaki nowej linii w imieniu.
Jeden błąd wyszedł dopiero na produkcji. Za Nginxem wbudowana w Astro kontrola pochodzenia żądania odrzucała formularz z kodem 403, bo serwer aplikacji widział inny host niż przeglądarka. Poprawka to lista zaufanych domen w konfiguracji Astro i przekazywanie nagłówka X-Forwarded-Host w konfiguracji Nginx.
Jeśli Twoja strona firmowa stoi na WordPressie i chcesz ją przenieść bez utraty adresów, zobacz, jak robimy strony internetowe.
Zrzuty ekranu


Hero: hasło „Druk, który robi robotę.”, raster w tle i taśma z nazwami usług.
Podobny problem do rozwiązania?
Napisz krótko, o co chodzi, wycena wraca w 24 godziny.
Zapytaj o wycenę →












