TimThumb idź do domu! Jak obsługiwać obrazki w WordPress w 2026?

TimThumb idź do domu! Jak obsługiwać obrazki w WordPress w 2026?

Ostatnio zweryfikowano: 12 października 2026
14 min czytania
Przewodnik
Full-stack developer
Audytor bezpieczeństwa

Jeśli jesteś weteranem WordPressa, na pewno pamiętasz TimThumb. Był to mały skrypt PHP, który w okolicach 2010 roku znajdował się w niemal każdym “płatnym motywie”. Pozwalał na łatwe przycinanie i skalowanie obrazków w locie.

W sierpniu 2011 roku odkryto w nim krytyczną lukę (Zero-Day), która pozwalała atakującym wgrać i uruchomić kod PHP na serwerach ze skryptem. To był koniec ery “prostych skryptów”.

Dziś, w 2026 roku, WordPress ma potężny silnik obsługi mediów. Jeśli nadal widzisz timthumb.php w swoim motywie, usuń go natychmiast. Ten poradnik pokazuje, jak zrobić to profesjonalnie.

#Dlaczego TimThumb był niebezpieczny

TimThumb działał “w locie”: brał obrazek z URL-a, przetwarzał go i zapisywał w cache. Problemy były liczne i poważne:

  1. Bezpieczeństwo: Pozwalał na zdalne wykonanie kodu (RCE). Lukę upublicznił Mark Maunder 1 sierpnia 2011 roku, po tym jak zaatakowano jego własnego bloga. Skrypt tylko częściowo porównywał nazwę hosta z białą listą domen, więc atakujący mógł zmusić go do pobrania pliku PHP do katalogu cache, a potem uruchomić ten plik bezpośrednim żądaniem. To dawało pełny dostęp do strony i potencjalnie do całego serwera. Maunder radził też przeszukać katalog WordPressa pod kątem funkcji base64_decode i długich zakodowanych ciągów, typowego śladu wstrzykniętego kodu.

  2. Wydajność: Obciążał serwer PHP przy każdym nowym żądaniu obrazka. Za każdym razem, gdy odwiedzający otwierał stronę z obrazkami z TimThumb, serwer musiał uruchomić PHP, sprawdzić cache, przetworzyć obrazek, jeśli go nie było, i go wysłać. Na stronach z dużym ruchem oznaczało to wiele dodatkowych wywołań PHP zużywających CPU i pamięć. Przetwarzanie obrazów jest zasobożerne, a robienie tego na żywo przez PHP było bardzo nieefektywne w porównaniu z serwowaniem gotowych plików statycznych.

  3. Brak integracji: Nie widział biblioteki mediów WordPressa. TimThumb działał całkowicie poza ekosystemem WordPressa. Nie korzystał z hooków ani funkcji core, nie zapisywał przetworzonych obrazków w bazie danych i nie korzystał z ulepszeń, które WordPress wprowadzał w obsłudze mediów. Obrazki z TimThumb nie pojawiały się w bibliotece mediów, nie dało się nimi zarządzać z panelu i nie miały tekstu alternatywnego, opisów ani podpisów.


#Historia luk w TimThumb

Historia skryptu mieści się w czterech datach i każda ma źródło pierwotne:

DataCo się stałoŹródło
sierpień 2011Błąd białej listy domen w wersjach przed 2.0, aktywnie wykorzystywanyNVD, CVE-2011-4106
sierpień 2011Maunder przepisuje skrypt jako WordThumb, który zostaje włączony do TimThumb 2.0blog Marka Maundera
czerwiec 2014Zdalne wykonanie poleceń w TimThumb 2.8.13 i WordThumb 1.07 przy włączonej funkcji WebShotNVD, CVE-2014-4663
27 września 2014Autor, Ben Gillbanks, ogłasza koniec utrzymaniaBinaryMoon

Identyfikator CVE-2011-4106 trafił do NVD później, w październiku 2013 roku, ale oficjalny opis mówi, że lukę wykorzystywano w sierpniu 2011. Maunder szacował wtedy skalę pośrednio: Google zwracał ponad 39 milionów wyników dla nazwy skryptu. Jego diagnoza nadal pasuje do każdego skryptu skalującego zaszytego w motywie:

“timthumb.php jest z natury niebezpieczny, bo opiera się na możliwości zapisywania plików w katalogu dostępnym dla osób odwiedzających twoją stronę.”

Mark Maunder, 1 sierpnia 2011, tłumaczenie własne

Łatka z 2011 roku zamknęła tamtą konkretną dziurę, ale nie zmieniła konstrukcji. Trzy lata później przyszła luka w WebShot, która przekazywała metaznaki powłoki z parametru src do polecenia systemowego. Gillbanks napisał w ogłoszeniu z 2014 roku, że od lat prawie nie dotykał kodu i że kto nadal używa TimThumb, robi to na własne ryzyko. Motyw, który wciąż zawiera ten plik, opiera się więc na kodzie bez utrzymania od ponad dekady.


#Jak używać add_image_size zamiast TimThumb

WordPress od lat posiada funkcję add_image_size(). Pozwala ona zdefiniować formaty, które system wygeneruje automatycznie podczas wgrywania pliku. To najwydajniejszy i najbezpieczniejszy sposób obsługi różnych rozmiarów obrazków, których potrzebuje motyw.

#Rejestracja rozmiarów w functions.php

function wppoland_setup_theme() {
    // Włącz obsługę obrazka wyróżniającego
    add_theme_support( 'post-thumbnails' );

    // Standardowe rozmiary (przycinanie miękkie: zachowuje proporcje)
    add_image_size( 'blog-list', 800, 400 );

    // Hard Crop (przycinanie twarde: ucina nadmiar)
    // WordPress wykadruje dokładnie środek obrazka
    add_image_size( 'team-member', 300, 300, true );

    // Crop z pozycjonowaniem (np. od góry, od lewej)
    add_image_size( 'hero-banner', 1920, 600, ['center', 'top'] );
}
add_action( 'after_setup_theme', 'wppoland_setup_theme' );

Gdy definiujesz własne rozmiary przez add_image_size(), WordPress generuje wszystkie warianty w momencie wgrywania. Ciężka praca odbywa się raz, przy uploadzie, a nie przy każdym wyświetleniu strony. Dlatego to podejście działa znacznie szybciej niż każde skalowanie w locie.

Warto rozumieć trzy dostępne tryby przycinania. Przycinanie miękkie (soft crop) jest domyślne, gdy nie podasz parametru przycinania. WordPress zmniejsza obrazek tak, by zmieścił się w podanych wymiarach, z zachowaniem oryginalnych proporcji, więc jeden z wymiarów może wyjść mniejszy niż podany. Przycinanie twarde (hard crop), włączane przez true jako trzeci parametr, wymusza dokładnie podane wymiary i obcina nadmiar przy krawędziach. Przycinanie z pozycją pozwala wskazać, od którego miejsca obrazka liczy się kadr, co przydaje się w banerach, gdzie główny motyw zwykle jest u góry.

#Wyświetlanie rozmiaru w szablonie (single.php)

if ( has_post_thumbnail() ) {
    the_post_thumbnail( 'hero-banner', ['class' => 'img-fluid'] );
}

Jeśli masz już ID załącznika, wp_get_attachment_image() robi to samo poza pętlą:

echo wp_get_attachment_image( $attachment_id, 'blog-list' );

Zaleta: Obrazki są generowane raz (podczas uploadu). Serwowane są jako gotowe pliki statyczne. Zero obciążenia PHP przy wyświetlaniu. Pliki statyczne łatwo też cache’ować zarówno na serwerze, jak i w CDN.

#Jak regenerować miniatury przez WP-CLI

Gdy dodajesz nowe rozmiary do istniejącego motywu, wcześniej wgrane obrazki nie mają nowych wariantów. Trzeba odtworzyć miniatury, a najwygodniej zrobić to przez WP-CLI:

wp media regenerate --yes

Przy dużych bibliotekach dokumentacja wp media regenerate daje opcje ograniczające pracę: --only-missing tworzy tylko brakujące rozmiary, --image_size=<nazwa> odtwarza jeden rozmiar, a --skip-delete zostawia stare miniatury, jeśli ktoś linkuje do nich z zewnątrz:

wp media regenerate --only-missing --yes
wp media regenerate --image_size=hero-banner --yes

#Jakie rozmiary obrazków WordPress tworzy domyślnie

Zanim zarejestrujesz własne rozmiary, sprawdź, ile plików core tworzy już przy każdym uploadzie. Domyślne wartości opcji w schemacie WordPressa są takie:

NazwaDomyślne wymiaryOd kiedy
thumbnail150 × 150, przycinanie twardeustawienia mediów
mediummaksymalnie 300 × 300ustawienia mediów
medium_large768 szerokości, bez limitu wysokościWordPress 4.4
largemaksymalnie 1024 × 1024ustawienia mediów
1536x1536maksymalnie 1536 × 1536WordPress 5.3
2048x2048maksymalnie 2048 × 2048WordPress 5.3

Dwa ostatnie dodaje wewnętrzna funkcja _wp_add_additional_image_sizes(), a komentarz w kodzie core odradza ich zmianę, bo nazwa odpowiada wymiarom. Każde add_image_size() z motywu dokłada się do tej listy, więc jeden upload łatwo daje dziesięć plików i więcej.

WordPress 5.3 wprowadził też próg dla dużych obrazów. Jeśli oryginał przekracza 2560 pikseli szerokości lub wysokości, core tworzy pomniejszoną kopię z przyrostkiem -scaled i używa jej jako rozmiaru “full”; oryginał zostaje na dysku, a jego nazwa trafia do metadanych załącznika (original_image). Wartość zmienia się albo wyłącza filtrem big_image_size_threshold:

// Podnieś próg do 4000 px
add_filter( 'big_image_size_threshold', fn() => 4000 );

// Wyłącz go całkowicie
add_filter( 'big_image_size_threshold', '__return_false' );

Dla srcset istnieje analogiczny limit: filtr max_srcset_image_width w obecnym kodzie core wyklucza z zestawu kandydatów szerszych niż 2048 pikseli. Jeśli motyw potrzebuje większych kandydatów dla ekranów o wysokiej gęstości, zmienia się ten filtr, a nie dopisuje skrypt skalujący.


#Jak skalować obrazy WordPress przez CDN

Natywne rozmiary mają wadę: jeśli zmienisz motyw, musisz regenerować miniatury (np. wtyczką Regenerate Thumbnails), co przy 100GB bibliotece trwa wieki.

W 2026 roku serwery są szybkie, a CDN-y tanie. Często używamy podejścia hybrydowego lub zewnętrznych usług, które przetwarzają obrazki na brzegu sieci, blisko użytkownika.

#Zmiana rozmiaru obrazów parametrami w URL

Zamiast męczyć serwer PHP, użyj parametrów w URL, a przetwarzanie zrobi CDN. Dokładna składnia zależy od dostawcy; schematycznie:

<img src="https://twojastrona.pl/wp-content/uploads/obraz.jpg?width=400&height=300&format=avif">

Oryginał leży na twoim serwerze, a CDN skaluje go, zmienia format i wysyła zoptymalizowaną wersję. Nie potrzebujesz do tego skryptu PHP na swoim serwerze.

Zalety są wyraźne. Po pierwsze, nie musisz regenerować miniatur dla nowych rozmiarów, bo CDN tworzy dowolny rozmiar na żądanie. Po drugie, konwersja formatu jest automatyczna: CDN może podać AVIF przeglądarkom, które go obsługują, a WebP jako zapas. Po trzecie, każda transformacja trafia do cache na brzegu, więc koszt jej wykonania płacisz raz.

#Cloudflare Image Resizing

W Cloudflare transformację zamawia się wprost w adresie, w formacie https://<strefa>/cdn-cgi/image/<opcje>/<oryginalny-obraz>, na przykład /cdn-cgi/image/width=400,format=auto/wp-content/uploads/2026/10/zdjecie.jpg. Według dokumentacji Cloudflare działa to w strefach z włączonymi transformacjami, a format=auto podaje najwydajniejszy format, jaki obsługuje przeglądarka. Do tego nie trzeba Workera; Workery przydają się, gdy chcesz własnych reguł, na przykład automatycznego przepisywania adresów z /wp-content/uploads/.


#Jak ustawić srcset i sizes dla obrazów w WordPressie

WordPress automatycznie generuje atrybut srcset dla twoich obrazków, pozwalając przeglądarce wybrać odpowiedni rozmiar dla urządzenia (telefon vs desktop 4K). Funkcja pojawiła się w WordPressie 4.4 i od tego czasu jest rozwijana.

<!-- WordPress generuje to automatycznie: -->
<img src="obraz-800x400.jpg"
     srcset="obraz-300x150.jpg 300w,
             obraz-800x400.jpg 800w,
             obraz-1024x512.jpg 1024w"
     sizes="(max-width: 600px) 100vw, 800px">

Atrybut srcset wymienia wszystkie dostępne warianty obrazka z ich szerokością w pikselach. Przeglądarka łączy tę informację z atrybutem sizes i wybiera plik najlepiej pasujący do rozmiaru ekranu, gęstości pikseli i szerokości viewportu.

Według notatki deweloperskiej do WordPressa 4.4 domyślne sizes odpowiada (max-width: {szerokość}px) 100vw, {szerokość}px, a jeśli HTML treści ma już srcset lub sizes, WordPress ich nie zmienia. Twoim zadaniem jako developera jest poprawne zdefiniowanie sizes za pomocą filtra wp_calculate_image_sizes. Filtr pozwala opisać, jak obrazek wyświetla się na poszczególnych breakpointach, żeby przeglądarka wybrała najlepiej:

add_filter( 'wp_calculate_image_sizes', function( $sizes, $size, $image_src, $image_meta ) {
    // Dla obrazków w artykułach
    if ( is_singular() ) {
        return '(max-width: 768px) 100vw, (max-width: 1200px) 75vw, 800px';
    }
    return $sizes;
}, 10, 4 );

#Jakie atrybuty ładowania WordPress dodaje do obrazków

Od WordPressa 5.5 atrybut loading="lazy" dodawany jest do obrazków automatycznie. Obrazki spoza pierwszego widoku nie pobierają się, dopóki użytkownik do nich nie przewinie, co przyspiesza pierwsze ładowanie strony.

WordPress 6.1 dodał do wp_get_attachment_image() atrybut decoding="async", który pozwala przeglądarce dekodować obrazki bez blokowania renderowania. Od WordPressa 6.3 wszystkie trzy atrybuty ustala jedna funkcja, wp_get_loading_optimization_attributes(). Oznacza ona fetchpriority="high" pierwszy wystarczająco duży obrazek (domyślny próg to 50 000 pikseli powierzchni, filtr wp_min_priority_img_pixels) i nie dodaje mu loading="lazy", bo jeden element nigdy nie powinien mieć obu. Jeśli twój obrazek LCP pochodzi z bloku albo z tła CSS, którego ta funkcja nie widzi, oznacz go samodzielnie.


#Jak serwować obrazy WebP i AVIF w WordPressie

W 2026 roku JPG i PNG to przeżytek dla zdjęć. WordPress natywnie obsługuje WebP (od wersji 5.8) i AVIF (od wersji 6.5), o ile biblioteka graficzna serwera (Imagick albo GD) obsługuje dany format. Ekran Narzędzia > Kondycja witryny, zakładka Informacje, sekcja obsługi mediów, pokazuje, jakie formaty obsługuje twój serwer.

Nie potrzebujesz wtyczek. Po prostu wgraj plik AVIF, a WordPress go obsłuży. Albo użyj wtyczki Modern Image Formats zespołu wydajności WordPressa, która z wgrywanych JPEG tworzy podrozmiary w AVIF (albo w WebP, jeśli serwer nie obsługuje AVIF) i zachowuje oryginał.

#Ile ważą WebP i AVIF w porównaniu z JPG

Oficjalne liczby z core są takie:

AVIF zwykle kompresuje lepiej niż WebP, zwłaszcza zdjęcia z płynnymi gradientami. WebP ma nieco szersze wsparcie w starszych przeglądarkach, dlatego częsta strategia to AVIF jako pierwszy wybór i WebP jako zapas.

#Jak użyć elementu picture z AVIF i WebP

Jeśli chcesz pełnej kontroli nad serwowanymi formatami, użyj elementu HTML <picture>:

<picture>
    <source srcset="obraz.avif" type="image/avif">
    <source srcset="obraz.webp" type="image/webp">
    <img src="obraz.jpg" alt="Opis obrazka">
</picture>

W większości przypadków praktyczniej i łatwiej w utrzymaniu jest jednak zostawić negocjację formatu WordPressowi i CDN.


#Jak zmienić jakość i format wyjściowy obrazków w WordPressie

Każdy podrozmiar, który tworzy WordPress, przechodzi przez klasę WP_Image_Editor, a jej wynik kontrolują dwa filtry.

Pierwszy dotyczy jakości. W obecnym kodzie źródłowym klasy domyślna jakość to 82 dla JPEG i 86 dla WebP; pozostałe formaty dostają 82. Filtr wp_editor_set_quality dostaje jakość i typ MIME, więc każdy format można ustawić osobno. Dla JPEG core stosuje potem starszy filtr jpeg_quality, który ma ostatnie słowo, jeśli używa go jakaś wtyczka:

add_filter( 'wp_editor_set_quality', function( $quality, $mime_type ) {
    if ( 'image/avif' === $mime_type ) {
        return 70;
    }
    return $quality;
}, 10, 2 );

Drugi dotyczy formatu wyjściowego. Filtr image_editor_output_format przypisuje każdemu typowi MIME na wejściu format, w którym zapisywane są podrozmiary. Notatka do WordPressa 6.5 używa dokładnie tego przykładu, żeby wgrywane JPEG dawały podrozmiary w AVIF:

add_filter( 'image_editor_output_format', function( $formats ) {
    $formats['image/jpeg'] = 'image/avif';
    return $formats;
} );

Od WordPressa 6.7 core używa tego samego mechanizmu domyślnie dla zdjęć HEIC z iPhone’ów: jeśli serwer potrafi je odczytać, konwertuje je przy uploadzie do JPEG. Zmiana formatu dotyczy tylko nowych lub regenerowanych obrazków, więc po włączeniu filtra trzeba uruchomić wp media regenerate.


#Jak usunąć TimThumb z motywu WordPress

Jeśli odziedziczyłeś stary projekt, usuń TimThumb bezpiecznie i do końca:

  1. Skanuj: Przeszukaj katalog wp-content w poszukiwaniu timthumb.php lub thumb.php. Szukaj też powiązanych katalogów cache.
  2. Usuń: Skasuj plik i powiązany katalog cache (zwykle folder cache w katalogu motywu).
  3. Napraw: Znajdź w kodzie miejsca, gdzie był wywoływany:
    // STARY KOD (ZŁY)
    <img src="<?php echo get_template_directory_uri(); ?>/timthumb.php?src=..." />
    
    // ZAMIEŃ NA (DOBRY)
    <?php the_post_thumbnail( 'moj-rozmiar' ); ?>
  4. Regeneruj: Zainstaluj WP-CLI i uruchom wp media regenerate.
  5. Sprawdź: Po migracji przejdź przez wszystkie główne podstrony i upewnij się, że obrazki wyświetlają się poprawnie. Zwróć szczególną uwagę na archiwa, widżety w sidebarze i stopkę, gdzie TimThumb mógł być używany.

#Jak znaleźć odwołania do TimThumb przez grep

Samo usunięcie pliku nie wystarczy. Trzeba znaleźć wszystkie odwołania w kodzie:

# Szukaj we wszystkich plikach PHP motywu
grep -r "timthumb" wp-content/themes/twoj-motyw/
grep -r "thumb.php" wp-content/themes/twoj-motyw/

# Szukaj też we własnych wtyczkach
grep -r "timthumb" wp-content/plugins/

# Ślad wstrzykniętego kodu, który radził sprawdzić Maunder
grep -rl "base64_decode" wp-content/

Każde znalezione odwołanie zastąp odpowiednią natywną funkcją WordPressa. Zwykle oznacza to the_post_thumbnail() albo wp_get_attachment_image() z właściwym rozmiarem. Trafienie base64_decode nie dowodzi infekcji, bo część legalnych wtyczek używa tej funkcji, ale każde wystąpienie w motywie warto przeczytać.

Zobacz nasz audyt bezpieczeństwa WordPress, jeśli chcesz uporządkować ryzyka i zabezpieczenia serwisu.


#Jak zmierzyć wydajność obrazków w WordPressie

Po przejściu z TimThumb na metody natywne sprawdź, czy wydajność się poprawiła. Użyj Google PageSpeed Insights, Lighthouse i WebPageTest, żeby zmierzyć czas ładowania przed migracją i po niej.

#Jakie metryki obrazków mierzyć: LCP, CLS i TTFB

  • Largest Contentful Paint (LCP): Główny obrazek jest zwykle elementem LCP. Z gotowymi rozmiarami natywnymi, fetchpriority="high" i CDN wynik LCP powinien się poprawić.
  • Cumulative Layout Shift (CLS): Upewnij się, że wszystkie obrazki mają określone width i height, żeby układ nie skakał podczas ładowania. Funkcje załączników WordPressa dodają je same.
  • Time to First Byte (TTFB) obrazków: Bez skalowania PHP w locie odpowiedź na każdy obrazek nie czeka już na PHP ani na GD.

#Konfiguracja serwera dla obrazków WordPress

Dla dobrej wydajności obrazków w WordPressie w 2026 roku zalecana konfiguracja obejmuje:

  • Cache przeglądarki z długimi nagłówkami Cache-Control dla plików graficznych (co najmniej rok)
  • CDN z transformacjami obrazów i automatyczną konwersją formatu
  • Preload obrazka LCP przez <link rel="preload">, gdy obrazek nie pojawia się wcześnie w HTML

#Jak obsługiwać obrazy w WordPressie bez TimThumb

Historia TimThumb to lekcja pokory. Wygoda (skalowanie w locie) nie może stać ponad bezpieczeństwem. W 2026 roku mamy natywne add_image_size(), responsywne srcset i CDN-y przetwarzające obrazy w chmurze. Nie ma żadnego powodu, by wracać do rozwiązań sprzed 15 lat.

Nowoczesna obsługa obrazków w WordPressie stoi na trzech filarach: generowaniu rozmiarów przy uploadzie przez add_image_size(), responsywnym dostarczaniu przez srcset i sizes oraz optymalizacji formatu przez WebP/AVIF. W połączeniu z CDN do dostarczania dają szybkie, bezpieczne i łatwe w utrzymaniu obrazki na każdej stronie WordPress.

Następny krok

Przekuj artykuł w realne wdrożenie

Pod tym wpisem dokładam linki, które domykają intencję użytkownika i prowadzą dalej w strukturze serwisu.

Powiązany klaster

Sprawdź inne usługi WordPress i bazę wiedzy

Wzmocnij swój biznes dzięki profesjonalnemu wsparciu technicznemu w kluczowych obszarach ekosystemu WordPress.

Polecane artykuły