CI/CD dla WordPress: automatyzacja wdrożeń w 2026 roku

CI/CD dla WordPress: automatyzacja wdrożeń w 2026 roku

Ostatnio zweryfikowano: 22 września 2026
8 min czytania
Przewodnik
Full-stack developer

Ręczne przeciąganie motywów przez FTP w 2026 roku kończy się zwykle tak samo: brakuje jednego pliku z inc/, composer.lock jest z innego laptopa, a produkcja leży, bo ktoś nadpisał wp-config.php. Continuous Integration i Continuous Deployment nie są fanaberią enterprise - to sposób, by każda zmiana w Gicie przeszła ten sam build, te same testy i ten sam sposób wgrania na serwer.

Ten przewodnik dotyczy WordPressa z motywem lub wtyczką w repozytorium (Composer, npm, ewent. Docker), nie „strony klikanej wyłącznie w panelu”. Jeśli cały kod żyje tylko w bazie i w mediach, najpierw przenieś motywy i custom code do Gita - bez tego CI/CD nie ma czego budować.

Oficjalna dokumentacja runnerów: GitHub Actions. Twierdzenie WordPressa o hardeningu serwera warto czytać równolegle: Hardening WordPress.

#Dlaczego FTP i „wrzuć na FTP” odpadają

Trzy problemy wracają w audytach polskich sklepów WooCommerce i stron agencji:

  1. Niespójność środowiska - lokalnie PHP 8.2 i Composer 2.7, na VPS PHP 8.1 bez rozszerzenia intl. Lokalny composer install „działa”, produkcja pada na class not found.
  2. Brak audytu - po incydencie nie da się powiedzieć, który commit był na żywo. Panel hostingu pokazuje datę pliku, nie SHA z Gita.
  3. Sekrety na dysku - zapisane hasła SFTP w FileZilli albo w .env commitowanym „na chwilę” to klasyczna droga do wycieku.

CI/CD rozwiązuje to mechanicznie: build na znanym obrazie (np. shivammathur/setup-php albo własny Docker), artefakt wersjonowany SHA, deploy po SSH kluczem trzymanym w Secrets.

#Minimalny potok: push, build, test, deploy

Typowy workflow dla motywu custom + wtyczek z Composer:

  1. Trigger - push do main albo merge Pull Requestu po review. Gałąź develop często idzie tylko na staging.
  2. Build - composer install --no-dev --optimize-autoloader, npm ci, npm run build. Wersje PHP i Node pinujesz w workflow (php-version: '8.2', node-version: '20').
  3. Test - PHPUnit dla wtyczek, ewent. Playwright na krytyczny flow koszyka. Fail = stop, zero deployu.
  4. Artefakt - pakujesz katalog release bez .git, bez node_modules, z vendor/ i zbudowanym assets/dist/.
  5. Deploy - rsync/SCP do releases/<run_id>/, potem atomowe przełączenie symlinku.

Fragment idei (skrócony) w GitHub Actions:

name: deploy-production
on:
  push:
    branches: [main]
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: shivammathur/setup-php@v2
        with:
          php-version: '8.2'
      - run: composer install --no-dev --optimize-autoloader
      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: npm
      - run: npm ci && npm run build
      - name: rsync release
        env:
          SSH_KEY: ${{ secrets.DEPLOY_SSH_KEY }}
        run: |
          # zapisz klucz, rsync do releases/$GITHUB_SHA, ln -sfn

Pełny skrypt symlinku trzymasz w repo jako bin/release.sh - w workflow tylko go wywołujesz. Dzięki temu ten sam skrypt działa z laptopa w awarii, gdy Actions leży.

#Wdrożenia atomowe zamiast nadpisywania plików

Nadpisywanie plików „w miejscu” na public_html oznacza, że przez kilka sekund połowa requestów widzi stary functions.php i nowy template. Przy WooCommerce to potrafi zepsuć sesję koszyka.

Model atomowy:

  • katalog bazowy: /var/www/site/
  • releases: /var/www/site/releases/20260920-142211/
  • shared: uploads, wp-config.php, cache object - poza release
  • current → symlink do aktywnego release

Po udanym rsync:

ln -sfn /var/www/site/releases/20260920-142211 /var/www/site/current

Nginx root wskazuje na .../current/public (albo odpowiednik). Przełączenie jest natychmiastowe. Stare release kasujesz po N dniach albo zostawiasz ostatnie trzy na rollback.

WordPress uploads muszą być poza release - inaczej każdy deploy kasuje media albo wymaga kopiowania gigabajtów. Klasyczny układ: shared/uploads linkowany do wp-content/uploads w każdym release.

#Staging, preview i macierz strategii

W 2026 roku ścieżka feature branch → PR → staging → main/production nie jest opcjonalna dla sklepów i stron leadowych. Staging powinien mieć:

  • tę samą wersję PHP i rozszerzeń co produkcja
  • kopię bazy (anonimizowaną, jeśli są dane osobowe RODO)
  • te same sekrety płatności w trybie sandbox

Preview per PR (tymczasowy URL) ma sens przy redesignie i przy zmianach CSS, mniej przy migracjach schematu bazy - te i tak testujesz na stagingu z prawdziwą kopią.

StrategiaRyzykoKoszt utrzymaniaKiedy ma sens
Ręczne FTPBardzo wysokieNiski start, wysoki koszt awariiTylko sandbox / nauka
Git hook na serwerzeŚrednieNiskiMałe portfolio, jeden deweloper
CI + rsync atomowyNiskieŚredniBiznes, WooCommerce, agencje
Blue/green lub dwa VPSMinimalneWysokiDuży ruch, SLA, płatności

Blue/green (dwa pełne środowiska, przełączenie load balancera) rzadko opłaca się poniżej kilkuset równoległych sesji. Dla większości polskich sklepów wystarcza atomowy symlink + rollback katalogu.

#Sekrety, WP-CLI i baza danych

Nigdy nie commituj:

  • kluczy SSH
  • haseł bazy
  • AUTH_KEY / SECURE_AUTH_KEY z wp-config.php
  • tokenów API bramek płatności

W GitHubie: Settings → Secrets and variables → Actions. Wstrzykujesz je jako env w kroku deploy. Na serwerze wp-config.php leży w shared/ i nie jest częścią artefaktu z CI.

WP-CLI w potoku po przełączeniu symlinku:

  • wp cache flush (jeśli object cache)
  • wp rewrite flush po zmianie CPT
  • wp plugin list jako smoke w logu

Migracje bazy (custom tabele, ACF JSON już w repo) planuj osobno od deployu plików. Rollback symlinku nie cofa ALTER TABLE. Jeśli migracja jest destrukcyjna, najpierw backup (wp db export na stagingu i produkcji), potem migracja, potem dopiero przełączenie ruchu na kod, który jej wymaga - albo feature flag w PHP.

Dokumentacja instalacji zależności PHP: Composer install - w CI zawsze --no-dev na produkcji i zablokowany composer.lock.

#Co najczęściej psuje pierwszy potok WordPress

Z praktyki wdrożeń na VPS (Hetzner, DigitalOcean, własne OVH) i na managed z SSH:

  • .gitignore zjada vendor/ - produkcja dostaje motyw bez autoloadera. Albo budujesz vendor na runnerze i wrzucasz do artefaktu, albo uruchamiasz Composer na serwerze w kroku po rsync (wtedy serwer musi mieć Composer i sieć do Packagist).
  • różne ABSPATH / ścieżki - skrypt zakłada /var/www/html, a hosting ma /home/user/domains/.... Pinuj ścieżki w Secrets per środowisko.
  • opcache trzyma stary kod - po ln -sfn wywołaj reload PHP-FPM albo opcache_reset przez WP-CLI/mu-plugin tylko dla deploy usera.
  • cron i kolejki - Action Scheduler WooCommerce może odpalać joby na starym kodzie przez kilka minut; po dużym release warto chwilę obserwować failed jobs.

Smoke test po deployu (curl z runnera albo osobny job):

  • strona główna HTTP 200
  • /wp-login.php 200
  • jeden krytyczny URL produktu lub landing z formularzem
  • opcjonalnie HEAD do CDN, jeśli assety mają hash w nazwie

Jeśli smoke padnie, automatyczny rollback symlinku jest tańszy niż telefon od klienta o 23:00.

#Motywy blokowe, mu-pluginy i wyjątki od „pełnego Gita”

Nie cały WordPress nadaje się do tego samego potoku. Treści w bazie (wpisy, ACF field groups jeśli nie eksportujesz JSON, Elementor CSS) i tak żyją poza release. CI/CD chroni kod, nie zastępuje backupu bazy.

Praktyczne podziały:

  • Motyw klasyczny lub hybrydowy z Vite - pełny build w CI, artefakt z style.css + dist/.
  • Block theme (FSE) - trzymasz theme.json i szablony HTML w Gicie; eksport zmian z Site Editora wraca do repo przez PR, inaczej produkcja i Git rozjeżdżają się po pierwszym kliknięciu „Zapisz”.
  • Must-use pluginy - wgrywane razem z release; nie aktualizujesz ich z panelu. To dobre miejsce na healthcheck deployu i wyłączenie file editora.
  • Wtyczki z wordpress.org - albo pinujesz wersje w Composer (wpackagist), albo aktualizujesz je osobnym jobem z review. Mieszanie „panel kliknął Update” z „CI nadpisał katalog” kończy się losowym stanem plugins/.

Na stronach agencji w PL często widzimy hybrydę: custom motyw + WooCommerce z wpackagist + dwie wtyczki premium wgrane jako zip do private/ i instalowane Composerem z path repository. Potok musi znać wszystkie trzy źródła, inaczej staging i produkcja różnią się jednym ZIP-em sprzed pół roku.

#Checklist przed pierwszym deployem z Actions

Zanim podłączysz main do produkcji, przejdź tę listę raz - oszczędza weekend:

  1. Repozytorium prywatne albo bez sekretów w historii (git log -p nie pokazuje starych .env).
  2. Branch protection: wymagany PR, wymagany zielony workflow test.
  3. Osobne Secrets: DEPLOY_HOST_STAGING, DEPLOY_HOST_PROD, osobne klucze SSH.
  4. Staging zsynchronizowany z produkcją co do wersji PHP (nie „u nas działa 8.3, u klienta 8.1”).
  5. Backup bazy przed pierwszym atomowym przełączeniem - nawet jeśli rollback kodu jest gotowy.
  6. Monitoring uptime (UptimeRobot, Better Stack, cokolwiek) z alertem SMS/Slack na URL produkcyjny.
  7. Runbook na jednej stronie: jak ręcznie ln -sfn na poprzedni release, kto ma dostęp do serwera.

Dopiero potem włączasz auto-deploy z main. Wcześniej wystarczy workflow „build + test” na PR i ręczny workflow_dispatch na staging.

#Podsumowanie

CI/CD dla WordPressa to nie „magiczny YAML”, tylko powtarzalny kontrakt: ten sam PHP, ten sam lockfile, ten sam artefakt, przełączenie bez okna z połową plików. Zaczynasz od Gita i stagingu, dokładasz Actions z buildem Composer/npm, kończysz atomowym current i smoke testem. FTP zostaje narzędziem awaryjnym, nie procesem.

Jeśli budujesz taki potok pod sklep lub stronę leadową i potrzebujesz kogoś, kto utrzyma go razem z kodem motywu, napisz przez formularz kontaktowy - opisujemy zakres wdrożenia i utrzymania CI/CD przy realnym stacku 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.

Chcesz wdrożyć ten temat na swojej stronie?

Jeśli chcesz przełożyć wiedzę z artykułu na działającą stronę, sklep albo przebudowę serwisu, przygotuję konkretny zakres prac.

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.

FAQ do artykułu

Często zadawane pytania

Najważniejsze odpowiedzi, które pomagają wdrożyć temat w praktyce.

SEO-readyGEO-readyAEO-ready5 Q&A
Czy CI/CD ma sens dla jednego freelancera?#
Tak. Samotny deweloper najbardziej traci na zapomnianym pliku PHP albo na composer.lock zbudowanym lokalnie na innej wersji PHP. Potok wymusza ten sam build na każdym commitcie i zostawia audytowalny log, kto (i z którego SHA) wdrożył produkcję.
Co to jest wdrożenie zero-downtime w WordPressie?#
Nowa wersja kodu ląduje w katalogu releases/, a dopiero po udanym rsync i ewentualnym wp cache flush przełączasz symlink current. PHP-FPM czy Nginx serwują ścieżkę przez current, więc przełączenie trwa milisekundy i nie wymaga trybu konserwacji.
Czy potrzebuję VPS, żeby mieć CI/CD?#
VPS lub kontenery dają pełną kontrolę (SSH, symlinki, WP-CLI). Na hostingu zarządzanym często zostaje API deployu albo SFTP z kluczem w Secrets - nadal lepsze niż ręczne przeciąganie z FileZilli, choć bez prawdziwego blue/green.
Co robić, gdy deploy się wywali?#
Trzymasz N poprzednich katalogów releases. Jeśli smoke test po przełączeniu zwraca 500 albo brakuje vendor/, przestawiasz symlink z powrotem na poprzedni release. Migracje bazy planuj osobno - rollback kodu nie cofa ALTER TABLE.
Gdzie budować motywy z Vite albo webpackiem?#
Na runnerze CI: checkout, setup Node, npm ci, npm run build, potem pakujesz dist/ do artefaktu razem z PHP. Na serwer produkcyjny nie wgrywasz node_modules ani źródeł TS - tylko skompilowane CSS/JS.

Potrzebujesz FAQ dopasowanego do branży i rynku? Przygotujemy wersję pod Twoje cele biznesowe.

Porozmawiajmy

Polecane artykuły