W 2008 roku, kiedy ten artykuł został opublikowany po raz pierwszy, jQuery było wybawieniem. Internet Explorer 6 obsługiwał zdarzenia inaczej, selektóry CSS były niespójne, a AJAX wymagał implementacji XMLHttpRequest specyficznych dla przeglądarki. $('.element').hide() było magią, która normalizowała ten chaos.
Dowiedz się więcej o optymalizacji szybkości WordPress na WPPoland.
W 2026 roku każdy problem, który rozwiązywało jQuery, jest obsługiwany natywnie przez przeglądarki. Pytanie nie brzmi już czy migrować, lecz jak to zrobić bezpiecznie, nie psując istniejącej funkcjonalności.
Czy jQuery spowalnia stronę WordPress
jQuery 3.7 waży 87KB nieskompresowanego kodu (30KB po gzip). To może brzmieć niewiele, ale weź pod uwagę koszt:
- Total Blocking Time (TBT): jQuery musi się sparsować i wykonać, zanim jakikolwiek zależny kod ruszy. Na średniej klasy urządzeniach mobilnych dodaje to 150-300ms do TBT.
- Interaction to Next Paint (INP): System delegacji zdarzeń jQuery dodaje narzut do każdej interakcji użytkownika, mierzalnie pogarszając wyniki INP.
- Łańcuch zależności: Załadowanie jQuery oznacza, że każdy skrypt od niego zależny musi czekać, tworząc kaskadę blokujących zasobów.
- Redundantny kod: Każda metoda jQuery, którą wywołujesz, ma natywny odpowiednik, który przeglądarka już dostarcza. Płacisz podwójnie za tę samą funkcjonalność.
Benchmarki wydajności: jQuery vs vanilla JS
Pomiary z produkcyjnego motywu WordPress z typowymi interakcjami (przełączanie menu, zakładki, walidacja formularza, AJAX „load more”):
| Metryka | Z jQuery | Bez jQuery | Poprawa |
|---|---|---|---|
| Całkowity rozmiar JS | 142KB | 55KB | -61% |
| TBT (mobile) | 480ms | 180ms | -62% |
| INP (p75) | 220ms | 95ms | -57% |
| LCP | 2.1s | 1.7s | -19% |
| Lighthouse Performance | 72 | 94 | +22 punkty |
Te liczby pochodzą z produkcyjnej strony WordPress na GeneratePress z WooCommerce, testowanej na Moto G Power (reprezentatywne urządzenie średniej klasy).
Jak zastąpić jQuery czystym JavaScriptem
Specyfikacja ES2024, w pełni wspierana w Chrome 124+, Firefox 126+, Safari 17.4+ i Edge 124+, dostarcza natywne alternatywy dla każdego popularnego wzorca jQuery.
querySelector zamiast $() z jQuery
// jQuery
const $buttons = $('.btn');
const $container = $('#main-container');
const $firstItem = $('.menu-item:first');
// Vanilla JS (ES2024+)
const buttons = document.querySelectorAll('.btn');
const container = document.getElementById('main-container');
const firstItem = document.querySelector('.menu-item');
// Scoped selection (jak jQuery .find())
const navLinks = container.querySelectorAll('a.nav-link');Kluczowa różnica: querySelectorAll zwraca statyczny NodeList, a nie kolekcję „na żywo”. To jest bezpieczniejsze, bo lista nie zmienia się niespodziewanie, gdy DOM mutuje.
addEventListener zamiast .click() z jQuery
// jQuery
$('.btn').click(function () {
$(this).toggleClass('active');
});
$('.menu').on('click', '.menu-item', function () {
// delegacja zdarzenia
});
// Vanilla JS
document.querySelectorAll('.btn').forEach(btn => {
btn.addEventListener('click', () => {
btn.classList.toggle('active');
});
});
// Delegacja zdarzeń (zastępuje .on() z selektorem)
document.querySelector('.menu').addEventListener('click', (e) => {
const item = e.target.closest('.menu-item');
if (item) {
// obsłuż kliknięcie elementu menu
}
});Metoda closest() to nowoczesny odpowiednik dopasowania delegowanych zdarzeń w jQuery. Przechodzi w górę drzewa DOM, szukając najbliższego przodka pasującego do selektóra.
classList zamiast addClass z jQuery
// jQuery
$el.addClass('active');
$el.removeClass('hidden');
$el.toggleClass('open');
$el.hasClass('visible');
// Vanilla JS
el.classList.add('active');
el.classList.remove('hidden');
el.classList.toggle('open');
el.classList.contains('visible');
// Wiele klas naraz
el.classList.add('active', 'highlighted', 'animate-in');
el.classList.remove('hidden', 'collapsed');Jak zastąpić $.ajax przez fetch i async/await
// jQuery
$.ajax({
url: '/wp-json/wp/v2/posts',
method: 'GET',
data: { per_page: 5 },
success: function (posts) { renderPosts(posts); },
error: function (xhr) { console.error(xhr); }
});
// Vanilla JS (nowoczesne async/await)
async function loadPosts() {
try {
const response = await fetch('/wp-json/wp/v2/posts?per_page=5');
if (!response.ok) {
throw new Error(`HTTP ${response.status}: ${response.statusText}`);
}
const posts = await response.json();
renderPosts(posts);
} catch (error) {
console.error('Nie udało się załadować postów:', error);
}
}
// POST z nonce (wzorzec WordPress)
async function submitForm(data) {
const response = await fetch('/wp-json/custom/v1/submit', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': wpApiSettings.nonce,
},
body: JSON.stringify(data),
});
return response.json();
}Jak zastąpić fadeIn i slideDown animacjami CSS
Metody jQuery .fadeIn(), .slideDown() i .animate() można zastąpić przejściami CSS, animacjami CSS lub Web Animations API.
// jQuery
$('.panel').slideDown(300);
$('.modal').fadeIn(200);
// Podejście CSS (preferowane pod kątem wydajności)
// W CSS:
// .panel { max-height: 0; overflow: hidden; transition: max-height 0.3s ease; }
// .panel.open { max-height: 500px; }
// W JS:
panel.classList.add('open');
// Web Animations API (dla złożonych, programowalnych animacji)
modal.animate(
[
{ opacity: 0, transform: 'scale(0.95)' },
{ opacity: 1, transform: 'scale(1)' },
],
{ duration: 200, easing: 'ease-out', fill: 'forwards' }
);Web Animations API działa w wątku kompozytora, więc animacje nie blokują głównego wątku. Animacje jQuery działają w głównym wątku i powodują „jank” na wolniejszych urządzeniach.
Tworzenie i wstawianie elementów DOM bez jQuery
// jQuery
$('<div class="notice">Witaj</div>').appendTo('#container');
$('.old-element').replaceWith('<span>Nowy</span>');
$('.item').remove();
$('.list').empty();
// Vanilla JS
const notice = document.createElement('div');
notice.className = 'notice';
notice.textContent = 'Witaj';
container.append(notice);
// Lub insertAdjacentHTML dla stringów HTML
container.insertAdjacentHTML('beforeend', '<div class="notice">Witaj</div>');
// Zamiana
oldElement.replaceWith(Object.assign(document.createElement('span'), { textContent: 'Nowy' }));
// Usuwanie
item.remove();
// Opróżnianie
list.replaceChildren();Document ready bez jQuery
// jQuery
$(document).ready(function () { /* ... */ });
$(function () { /* skrót */ });
// Vanilla JS
document.addEventListener('DOMContentLoaded', () => {
// DOM jest gotowy
});
// Lub po prostu umieść tag <script> z type="module" na końcu <body>
// Moduły są domyślnie odroczone, więc DOM jest już gotowyWeb Components zamiast pluginów jQuery
Pluginy jQuery dostarczały wielokrotnego użytku komponenty UI (slidery, modale, zakładki, akordeony). W 2026 roku Web Components oferują alternatywę opartą na standardach z lepszą enkapsulacją.
Panel rozwijalny jako Web Component
class TogglePanel extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
connectedCallback() {
const title = this.getAttribute('title') || 'Rozwiń';
this.shadowRoot.innerHTML = `
<style>
:host { display: block; margin: 1rem 0; }
button {
width: 100%; padding: 0.75rem 1rem;
background: #f5f5f5; border: 1px solid #ddd;
cursor: pointer; text-align: left;
font-size: 1rem; font-weight: 600;
}
.content {
display: none; padding: 1rem;
border: 1px solid #ddd; border-top: none;
}
:host([open]) .content { display: block; }
</style>
<button part="trigger">${title}</button>
<div class="content"><slot></slot></div>
`;
this.shadowRoot.querySelector('button').addEventListener('click', () => {
this.toggleAttribute('open');
});
}
}
customElements.define('toggle-panel', TogglePanel);Użycie w HTML:
<toggle-panel title="Informacje o dostawie">
<p>Darmowa dostawa przy zamówieniach powyżej 200 zł.</p>
</toggle-panel>Web Components zapewniają enkapsulację Shadow DOM (style nie wyciekają), sloty do projekcji treści i lifecycle callbacks. Działają w każdej nowoczesnej przeglądarce bez polyfilli.
Kiedy wybrać Web Components, a kiedy framework
| Scenariusz | Rekomendacja |
|---|---|
| Prosty interaktywny widget (akordeon, zakładki, modal) | Web Component |
| Pełna aplikacja SPA | React / Vue / Svelte |
| Blok WordPress (Gutenberg) | React (standard WordPress) |
| Współdzielony komponent między serwisami | Web Component |
| Złożone zarządzanie stanem | Framework z biblioteką stanu |
Jak usunąć jQuery z motywu WordPress
Krok 1: Zaudytuj użycie jQuery
Uruchom to polecenie w katalogu motywu, aby znaleźć wszystkie odwołania do jQuery:
grep -rn '\$(\|jQuery\.\|jQuery(' --include='*.js' --include='*.php' .Skategoryzuj każde użycie:
- Twój kod (motyw / własna wtyczka): migruj to
- Wtyczka zewnętrzna: zostaw, wtyczka zarządza własnymi zależnościami
- Panel administracyjny WordPress: nie ruszaj, rdzeń WordPress tym zarządza
Krok 2: Stwórz plan migracji
Priorytetyzuj według wpływu:
- Frontend motywu (wpływa na każdego odwiedzającego) - migruj najpierw
- Frontend własnej wtyczki - migruj w drugiej kolejności
- Dostosowania panelu admina - migruj na końcu (mniejszy ruch)
Krok 3: Zastępuj wzorce inkrementalnie
Nie przepisuj wszystkiego naraz. Zastępuj plik po pliku:
- Usuń
array('jquery')z tablicy zależnościwp_enqueue_scriptpliku - Zamień wszystkie wzorce jQuery na odpowiedniki vanilla JS
- Przetestuj w Chrome, Firefox, Safari i Edge
- Przetestuj z wszystkimi aktywnymi wtyczkami
- Uruchom Lighthouse przed i po, aby zmierzyć poprawę
Krok 4: Obsłuż wzorzec WordPress AJAX
Starszy wzorzec AJAX w WordPress używa admin-ajax.php z jQuery:
// Stary wzorzec (jQuery + admin-ajax)
jQuery.post(ajaxurl, {
action: 'my_custom_action',
nonce: myData.nonce,
post_id: 123,
}, function (response) {
console.log(response);
});
// Nowoczesny wzorzec (fetch + REST API)
async function myCustomAction(postId) {
const response = await fetch('/wp-json/myplugin/v1/action', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
'X-WP-Nonce': myData.nonce,
},
body: JSON.stringify({ post_id: postId }),
});
return response.json();
}Podejście REST API jest szybsze (brak narzutu admin-ajax.php), bardziej „cacheable” i zgodne z nowoczesnymi standardami rozwoju WordPress.
Krok 5: Dołącz skrypty przez wp_enqueue_script bez jQuery
// Przed (z zależnością jQuery)
wp_enqueue_script(
'my-theme-scripts',
get_template_directory_uri() . '/js/main.js',
array('jquery'),
'1.0.0',
true
);
// Po (bez jQuery, z obsługą modułów)
wp_enqueue_script_module(
'my-theme-scripts',
get_template_directory_uri() . '/js/main.js',
array(),
'2.0.0'
);WordPress 6.5+ wspiera wp_enqueue_script_module(), która ładuje skrypty jako moduły ES z type="module", umożliwiając natywną składnię import/export.
Kiedy warto zostać przy jQuery w 2026
jQuery może być wciąż uzasadnione, jeśli:
- Legacy codebase z 50+ zależnościami od pluginów jQuery: Koszt migracji przewyższa korzyść wydajnościową. Zaplanuj stopniowe wycofywanie w ciągu 6-12 miesięcy.
- Dostosowania panelu administracyjnego: Panel admina już ładuje jQuery. Dodanie własnych skryptów admina z zależnością jQuery nic nie kosztuje.
- Wymagania wtyczek zewnętrznych: Niektóre popularne wtyczki (kreatory formularzy, page buildery) wymagają jQuery. Nie walcz z zależnością, jeśli nie masz nad nią kontroli.
- Luka kompetencyjna zespołu: Jeśli Twój zespół programistyczny nie czuje się komfortowo z nowoczesnym JS, zainwestuj w szkolenie przed wymuszaniem migracji.
Celem jest pragmatyczna poprawa, nie ideologiczna czystość. Usuń jQuery tam, gdzie kosztuje Cię wydajność i nie wnosi wartości. Zachowaj tam, gdzie usunięcie popsuliby coś lub kosztowało więcej niż oszczędza.
Natywne odpowiedniki $.extend, $.each i $.Deferred
Głęboka kopia obiektu bez $.extend
// jQuery
const copy = $.extend(true, {}, original);
// ES2024+
const copy = structuredClone(original);forEach zamiast $.each
// jQuery
$.each(items, function (index, item) { /* ... */ });
// ES2024+
items.forEach((item, index) => { /* ... */ });
// Lub Array.from dla NodeList
Array.from(document.querySelectorAll('.item')).map(item => item.textContent);
// Operator spread
[...document.querySelectorAll('.item')].filter(item => item.dataset.active);Promise zamiast $.Deferred
// jQuery
const deferred = $.Deferred();
deferred.resolve('done');
deferred.promise().then(val => console.log(val));
// ES2024+
const promise = new Promise((resolve) => resolve('done'));
promise.then(val => console.log(val));
// Promise.withResolvers() - funkcja ES2024
const { promise, resolve, reject } = Promise.withResolvers();IntersectionObserver zamiast scroll handlerów jQuery
// jQuery (kosztowny scroll handler)
$(window).scroll(function () {
$('.lazy-image').each(function () {
if ($(this).offset().top < $(window).scrollTop() + $(window).height()) {
$(this).attr('src', $(this).data('src'));
}
});
});
// Vanilla JS (wydajne, poza głównym wątkiem)
const observer = new IntersectionObserver((entries) => {
entries.forEach(entry => {
if (entry.isIntersecting) {
const img = entry.target;
img.src = img.dataset.src;
observer.unobserve(img);
}
});
});
document.querySelectorAll('.lazy-image').forEach(img => observer.observe(img));Alpine.js lub htmx zamiast jQuery
Jeśli wielokrotnie piszesz te same wzorce vanilla JS, rozważ mikro-bibliotekę zamiast jQuery:
| Biblioteka | Rozmiar | Przeznaczenie |
|---|---|---|
| Alpine.js | 15KB | Deklaratywna reaktywność (x-data, x-on) |
| htmx | 14KB | AJAX, WebSocket, SSE via atrybuty HTML |
| Petite-Vue | 6KB | Składnia szablonów kompatybilna z Vue |
| Brak (vanilla) | 0KB | Najlepsza wydajność, pełna kontrola |
Dla motywów WordPress w 2026 roku rekomendacja to vanilla JS dla prostych interakcji i Alpine.js lub htmx, jeśli potrzebujesz deklaratywnego zachowania bez pełnego frameworka.
Lista kontrolna migracji z jQuery
- Zaudytuj całe użycie jQuery w motywie i własnych wtyczkach
- Zmierz aktualne Core Web Vitals jako punkt odniesienia
- Zamień kod frontendu motywu jako pierwszy (największy wpływ na odwiedzających)
- Używaj
querySelector,addEventListener,fetch,classListi Web Animations API - Rozważ Web Components dla wielokrotnego użytku elementów UI
- Używaj
wp_enqueue_script_module()dla obsługi modułów ES - Testuj we wszystkich głównych przeglądarkach po migracji każdego pliku
- Zmierz Core Web Vitals ponownie i udokumentuj poprawę
- Zachowaj jQuery tylko dla skryptów admina i zależności wtyczek zewnętrznych
- Przeszkol swój zespół z nowoczesnych wzorców JavaScript
Platforma webowa w 2026 roku dostarcza wszystko, co oferowało jQuery, i więcej. Każdy kilobajt niepotrzebnego JavaScript, który usuniesz, sprawia, że Twoja strona WordPress jest szybsza, bardziej dostępna i łatwiejsza w utrzymaniu.
Co sprawdzić, gdy po usunięciu jQuery coś przestaje działać
Po usunięciu array('jquery') z pierwszego pliku otwórz konsolę przeglądarki. Błąd $ is not defined albo jQuery is not defined znaczy, że inny skrypt motywu lub wtyczki nadal korzysta z biblioteki i trzeba go dopisać do audytu z kroku 1.
- Kliknięcia działają tylko na elementach z pierwszego renderu. Treść doładowana przez AJAX, na przykład przyciskiem “load more”, potrzebuje listenera na elemencie nadrzędnym i delegacji zdarzeń.
- Nowy endpoint REST odrzuca żądania. Sprawdź, czy nonce trafia do nagłówka
X-WP-Nonce, tak jak w przykładzie z kroku 4, i czy trasa/wp-json/jest zarejestrowana. - Kreator formularzy albo page builder przestał działać. To zależność wtyczki zewnętrznej. Przywróć jQuery dla tej wtyczki i migruj tylko własny kod.
- Lighthouse pokazuje ten sam wynik co przed migracją. Jeśli jQuery nadal ładuje się na froncie, ściąga je któraś z aktywnych wtyczek. Zobacz w zakładce Network, który skrypt je wymaga.
Każdy z tych testów powtórz w Chrome, Firefox, Safari i Edge, zanim przejdziesz do następnego pliku.







