{"id":13552,"date":"2026-09-02T13:16:58","date_gmt":"2026-09-02T11:16:58","guid":{"rendered":"https:\/\/www.lukaswojcik.com\/blog\/narzedzia\/redirect-rule-generator-htaccess-nginx\/"},"modified":"2026-09-02T13:16:58","modified_gmt":"2026-09-02T11:16:58","slug":"redirect-rule-generator-htaccess-nginx","status":"publish","type":"page","link":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/","title":{"rendered":"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress)"},"content":{"rendered":"<div class=\"gtm-analyser-container\" style=\"background: var(--bg-panel, #1e1e24); padding: 25px; border-radius: 8px; border: 1px solid var(--border, #2a2a35);\">\n<p style=\"color: var(--text-secondary, #a0a0b0); margin-bottom: 20px;\">Wystarczy wklei\u0107 stare i nowe adresy, po jednej parze w wierszu, rozdzielone strza\u0142k\u0105, tabulatorem lub przecinkiem. Wszystko dzia\u0142a w przegl\u0105darce. Pary z t\u0105 sam\u0105 zmian\u0105 katalogu zwijaj\u0105 si\u0119 w jedn\u0105 regu\u0142\u0119 prefiksow\u0105 z symbolem wieloznacznym, tak jak wymaga tego zmieniona nazwa kategorii. Nowy adres, kt\u00f3ry sam jest adresem starym, tworzy \u0142a\u0144cuch; generator kieruje pierwszy na ostatni, aby \u017caden odwiedzaj\u0105cy nie przechodzi\u0142 \u0142a\u0144cucha. P\u0119tle i sprzeczne cele s\u0105 zg\u0142aszane i pomijane.<\/p>\n<div style=\"margin-bottom: 14px;\">\n        <label for=\"rg-paare\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Stary adres -&gt; nowy adres, jedna para w wierszu<\/label><br \/>\n        <textarea id=\"rg-paare\" style=\"width: 100%; height: 190px; padding: 10px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px; box-sizing: border-box; font-family: monospace; font-size: 0.85rem; resize: vertical;\">\/blog\/en\/wordpress-hacks\/ -> \/blog\/en\/wordpress-plugins-tricks\/<br \/>\n\/blog\/en\/wordpress-hacks\/speed-up\/ -> \/blog\/en\/wordpress-plugins-tricks\/speed-up\/<br \/>\n\/alte-seite.html -> \/neue-seite\/<br \/>\n\/produkt\/alt -> \/produkt\/neu<br \/>\n\/produkt\/neu -> \/shop\/produkt-neu\/<br \/>\nhttps:\/\/old.example\/archive\/2019\/ -> https:\/\/www.example.com\/blog\/<\/textarea>\n    <\/div>\n<div style=\"display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 12px 18px; margin-bottom: 14px;\">\n<div>\n            <label for=\"rg-format\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Wynik<\/label><br \/>\n            <select id=\"rg-format\" class=\"form-control\" style=\"width: 100%; padding: 9px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px;\"><option value=\"htaccess\">Apache .htaccess (RewriteRule)<\/option><option value=\"redirect\">Apache .htaccess (Redirect \/ RedirectMatch)<\/option><option value=\"nginx\">nginx (location \/ rewrite)<\/option><option value=\"nginx_map\">nginx (map + return)<\/option><option value=\"wordpress\">WordPress (functions.php, template_redirect)<\/option><\/select>\n        <\/div>\n<div>\n            <label for=\"rg-code\" style=\"color: var(--text-secondary, #a0a0b0); display: block; font-size: 0.85rem; margin-bottom: 5px;\">Kod statusu<\/label><br \/>\n            <select id=\"rg-code\" class=\"form-control\" style=\"width: 100%; padding: 9px; background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); color: var(--text-primary, #e8e8ee); border-radius: 6px;\"><option value=\"301\">301<\/option><option value=\"308\">308<\/option><option value=\"302\">302<\/option><option value=\"307\">307<\/option><\/select>\n        <\/div>\n<div style=\"display: flex; flex-direction: column; gap: 6px; justify-content: flex-end;\">\n            <label style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.85rem;\"><input id=\"rg-qsa\" type=\"checkbox\" checked style=\"margin-right: 6px;\">Przekazuj cz\u0119\u015b\u0107 zapytania<\/label><br \/>\n            <label style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.85rem;\"><input id=\"rg-praefix\" type=\"checkbox\" checked style=\"margin-right: 6px;\">Scalaj zmiany katalog\u00f3w w regu\u0142y prefiksowe<\/label><br \/>\n            <label style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.85rem;\"><input id=\"rg-glaetten\" type=\"checkbox\" checked style=\"margin-right: 6px;\">Sp\u0142aszczaj \u0142a\u0144cuchy do celu ko\u0144cowego<\/label>\n        <\/div>\n<\/p><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.82rem; margin-bottom: 16px;\">Nic, co zostanie tu wpisane, nie opuszcza przegl\u0105darki. Regu\u0142y powstaj\u0105 lokalnie.<\/p>\n<p>    <button id=\"rg-btn\" class=\"button\" style=\"background: var(--accent, #7ee787); color: var(--on-accent, #0b1114); border: none; padding: 12px 24px; border-radius: 6px; font-weight: 700; cursor: pointer;\">Generuj regu\u0142y<\/button><\/p>\n<div id=\"rg-ausgabe\" style=\"margin-top: 22px;\" data-mp-mask><\/div>\n<p style=\"color: var(--text-secondary, #a0a0b0); font-size: 0.8rem; margin: 24px 0 0;\">Granice, o kt\u00f3rych warto wiedzie\u0107: regu\u0142y prefiksowe trafiaj\u0105 we wszystko poni\u017cej starego katalogu, tak\u017ce w adresy nigdy niewymienione; para z cz\u0119\u015bci\u0105 zapytania staje si\u0119 w Apache RewriteCond, a w nginx if, co jest zamierzone, ale nieeleganckie; a regu\u0142a przekierowuj\u0105ca na host, na kt\u00f3rym te same regu\u0142y zn\u00f3w dzia\u0142aj\u0105, wpada w p\u0119tl\u0119, kt\u00f3r\u0105 pokazuje tylko \u015bledzenie prawdziwego \u0142a\u0144cucha.<\/p>\n<\/div>\n<p><script>\n(function () {\n    'use strict';<\/p>\n<p>    const T = {\"einleitung\":\"Wystarczy wklei\u0107 stare i nowe adresy, po jednej parze w wierszu, rozdzielone strza\u0142k\u0105, tabulatorem lub przecinkiem. Wszystko dzia\u0142a w przegl\u0105darce. Pary z t\u0105 sam\u0105 zmian\u0105 katalogu zwijaj\u0105 si\u0119 w jedn\u0105 regu\u0142\u0119 prefiksow\u0105 z symbolem wieloznacznym, tak jak wymaga tego zmieniona nazwa kategorii. Nowy adres, kt\u00f3ry sam jest adresem starym, tworzy \u0142a\u0144cuch; generator kieruje pierwszy na ostatni, aby \u017caden odwiedzaj\u0105cy nie przechodzi\u0142 \u0142a\u0144cucha. P\u0119tle i sprzeczne cele s\u0105 zg\u0142aszane i pomijane.\",\"label_paare\":\"Stary adres -\\u003E nowy adres, jedna para w wierszu\",\"label_format\":\"Wynik\",\"label_code\":\"Kod statusu\",\"label_qsa\":\"Przekazuj cz\u0119\u015b\u0107 zapytania\",\"label_praefix\":\"Scalaj zmiany katalog\u00f3w w regu\u0142y prefiksowe\",\"label_glaetten\":\"Sp\u0142aszczaj \u0142a\u0144cuchy do celu ko\u0144cowego\",\"datenschutz\":\"Nic, co zostanie tu wpisane, nie opuszcza przegl\u0105darki. Regu\u0142y powstaj\u0105 lokalnie.\",\"knopf\":\"Generuj regu\u0142y\",\"grenze\":\"Granice, o kt\u00f3rych warto wiedzie\u0107: regu\u0142y prefiksowe trafiaj\u0105 we wszystko poni\u017cej starego katalogu, tak\u017ce w adresy nigdy niewymienione; para z cz\u0119\u015bci\u0105 zapytania staje si\u0119 w Apache RewriteCond, a w nginx if, co jest zamierzone, ale nieeleganckie; a regu\u0142a przekierowuj\u0105ca na host, na kt\u00f3rym te same regu\u0142y zn\u00f3w dzia\u0142aj\u0105, wpada w p\u0119tl\u0119, kt\u00f3r\u0105 pokazuje tylko \u015bledzenie prawdziwego \u0142a\u0144cucha.\",\"zusammenfassung\":\"Odczytano {gelesen} par(y), {paare} u\u017cytecznych, {praefixe} regu\u0142(y) prefiksowych, {einzeln} pojedynczych.\",\"h_fehler\":\"Nieczytelne wiersze\",\"h_hinweise\":\"Sprawdzenia\",\"h_praefixe\":\"Regu\u0142y prefiksowe\",\"h_ausgabe\":\"Regu\u0142y\",\"h_ausgabe_htaccess\":\"Apache .htaccess (mod_rewrite)\",\"h_ausgabe_redirect\":\"Apache .htaccess (mod_alias)\",\"h_ausgabe_nginx\":\"Blok server nginx\",\"h_ausgabe_nginx_map\":\"nginx map\",\"h_ausgabe_wordpress\":\"WordPress functions.php\",\"kopieren\":\"Kopiuj\",\"kopiert\":\"Skopiowano\",\"kommentar_kopf\":\"Wygenerowano w generatorze regu\u0142 przekierowa\u0144 301, lukaswojcik.com\",\"kommentar_query\":\"Cz\u0119\u015bci zapytania nie da si\u0119 sprawdzi\u0107 w mod_alias, dla tej pary nale\u017cy u\u017cy\u0107 formatu RewriteRule:\",\"fehler_form\":\"Wiersz {zeile}: to nie jest para adres\u00f3w ({roh}).\",\"fehler_host\":\"Wiersz {zeile}: cz\u0119\u015b\u0107 z hostem jest nieu\u017cyteczna ({roh}).\",\"hinweis_doppelt\":\"Wiersz {zeile}: {alt} wyst\u0119puje dwa razy z tym samym celem, powt\u00f3rzenie pomini\u0119to.\",\"hinweis_widerspruch\":\"Wiersz {zeile}: {alt} wskazuje ju\u017c {a}, ten wiersz chce {b}. Drugi cel pomini\u0119to.\",\"hinweis_selbst\":\"Wiersz {zeile}: {alt} wskazuje sam siebie i zosta\u0142 pomini\u0119ty.\",\"hinweis_kette\":\"Wiersz {zeile}: \u0142a\u0144cuch {kette}. Do w\u0142\u0105czenia sp\u0142aszczanie albo pierwszy adres powinien wskazywa\u0107 ostatni.\",\"hinweis_geglaettet\":\"Wiersz {zeile}: \u0142a\u0144cuch {kette} sp\u0142aszczony, {alt} wskazuje teraz {ziel}.\",\"hinweis_schleife\":\"Wiersz {zeile}: p\u0119tla {kette}. Wszystkie adresy p\u0119tli pomini\u0119to; serwer odpowiedzia\u0142by ERR_TOO_MANY_REDIRECTS.\",\"hinweis_format_htaccess\":\"Miejsce w .htaccess: nad blokiem WordPressa (wszystko mi\u0119dzy BEGIN a END WordPress jest nadpisywane przy zapisie permalink\u00f3w). Wzorce dzia\u0142aj\u0105 bez wiod\u0105cego uko\u015bnika i wzgl\u0119dem katalogu pliku .htaccess; QSA przekazuje cz\u0119\u015b\u0107 zapytania, NE zachowuje znaki zakodowane. Przed poleganiem na regu\u0142ach warto sprawdzi\u0107 je przez curl -I.\",\"hinweis_format_redirect\":\"mod_alias dzia\u0142a przed mod_rewrite i nie widzi cz\u0119\u015bci zapytania. Redirect trafia w \u015bcie\u017ck\u0119 i wszystko poni\u017cej, dlatego pojedyncze strony maj\u0105 dok\u0142adn\u0105 \u015bcie\u017ck\u0119; RedirectMatch przyjmuje wyra\u017cenie regularne.\",\"hinweis_format_nginx\":\"Miejsce w bloku server. location = trafia dok\u0142adnie w jedn\u0105 \u015bcie\u017ck\u0119, location ^~ w prefiks. permanent to 301, redirect to 302; inne kody id\u0105 przez return. Po nginx -t nale\u017cy prze\u0142adowa\u0107 konfiguracj\u0119.\",\"hinweis_format_nginx_map\":\"map nale\u017cy do bloku http, if do bloku server. Jedno wyszukanie na \u017c\u0105danie, bez \u0142a\u0144cucha blok\u00f3w location; wyra\u017cenia regularne w map zaczynaj\u0105 si\u0119 od ~.\",\"hinweis_format_wordpress\":\"Dzia\u0142a przy template_redirect, wi\u0119c tylko dla \u017c\u0105da\u0144 docieraj\u0105cych do WordPressa; cache stron serwuje zapisane strony, zanim ten kod si\u0119 uruchomi. Najpierw dopasowania dok\u0142adne, potem prefiksy. wp_redirect wymaga exit.\"};<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Reine Logik: parsen, pruefen, glaetten, Praefixe, erzeugen\n    \/\/ =========================================================================<\/p>\n<p>    function trennen(zeile) {\n        var z = zeile.trim();\n        if (!z || z.charAt(0) === '#') { return null; }\n        var m = z.match(\/^(\\S+)\\s*(?:->|=>|\u2192|\\t|,|;|\\s+)\\s*(\\S+)$\/);\n        if (!m) { return { fehler: 'form', roh: z }; }\n        return { alt: m[1], neu: m[2] };\n    }\n    function zerlegen(adresse) {\n        var m = adresse.match(\/^(https?:\\\/\\\/[^\\\/?#]+)?([^?#]*)(\\?[^#]*)?(#.*)?$\/i);\n        if (!m) { return null; }\n        var pfad = m[2] || '\/';\n        if (pfad.charAt(0) !== '\/') { pfad = '\/' + pfad; }\n        return { host: m[1] ? m[1].toLowerCase() : '', pfad: pfad, query: m[3] || '', voll: (m[1] ? m[1].toLowerCase() : '') + pfad + (m[3] || '') };\n    }\n    function parsen(text) {\n        var paare = [], fehler = [];\n        String(text || '').split(\/\\r?\\n\/).forEach(function (zeile, i) {\n            var t = trennen(zeile);\n            if (t === null) { return; }\n            if (t.fehler) { fehler.push({ zeile: i + 1, art: 'form', roh: t.roh }); return; }\n            var a = zerlegen(t.alt), n = zerlegen(t.neu);\n            if (!a || !n) { fehler.push({ zeile: i + 1, art: 'form', roh: zeile.trim() }); return; }\n            if (a.host && !\/^https?:\\\/\\\/[a-z0-9.-]+(:\\d+)?$\/i.test(a.host)) { fehler.push({ zeile: i + 1, art: 'host', roh: t.alt }); return; }\n            paare.push({ zeile: i + 1, alt: a, neu: n, altRoh: t.alt, neuRoh: t.neu });\n        });\n        return { paare: paare, fehler: fehler };\n    }<\/p>\n<p>    \/** Doppelte, Selbstverweise, Ketten und Schleifen finden; Ketten optional glaetten. *\/\n    function pruefen(paare, glaetten) {\n        var hinweise = [];\n        var nachAlt = {};\n        var raus = [];\n        paare.forEach(function (p) {\n            var k = p.alt.voll;\n            if (nachAlt[k]) {\n                if (nachAlt[k].neu.voll === p.neu.voll) { hinweise.push({ art: 'doppelt', zeile: p.zeile, alt: p.altRoh }); }\n                else { hinweise.push({ art: 'widerspruch', zeile: p.zeile, alt: p.altRoh, a: nachAlt[k].neuRoh, b: p.neuRoh }); }\n                return;\n            }\n            if (p.alt.voll === p.neu.voll) { hinweise.push({ art: 'selbst', zeile: p.zeile, alt: p.altRoh }); return; }\n            nachAlt[k] = p;\n            raus.push(p);\n        });\n        \/\/ Ketten: neu ist wieder ein alt\n        raus.forEach(function (p) {\n            var ziel = p.neu, schritte = 0, gesehen = {};\n            gesehen[p.alt.voll] = true;\n            var kette = [p.altRoh];\n            while (nachAlt[ziel.voll] && schritte < 20) {\n                if (gesehen[ziel.voll]) { hinweise.push({ art: 'schleife', zeile: p.zeile, alt: p.altRoh, kette: kette.concat([ziel.voll]).join(' -> ') }); p.schleife = true; return; }\n                gesehen[ziel.voll] = true;\n                kette.push(ziel.voll);\n                ziel = nachAlt[ziel.voll].neu;\n                schritte++;\n            }\n            if (schritte > 0) {\n                kette.push(ziel.voll);\n                if (glaetten) { hinweise.push({ art: 'geglaettet', zeile: p.zeile, alt: p.altRoh, kette: kette.join(' -> '), ziel: ziel.voll }); p.neu = ziel; p.neuRoh = ziel.voll; }\n                else { hinweise.push({ art: 'kette', zeile: p.zeile, alt: p.altRoh, kette: kette.join(' -> ') }); }\n            }\n        });\n        return { paare: raus.filter(function (p) { return !p.schleife; }), hinweise: hinweise };\n    }<\/p>\n<p>    \/** Paare, die denselben Ordnerwechsel teilen, zu einer Praefixregel zusammenfassen. *\/\n    function praefixe(paare) {\n        var gruppen = {}, einzeln = [];\n        paare.forEach(function (p) {\n            if (p.alt.host !== p.neu.host && p.neu.host && p.alt.host) { einzeln.push(p); return; }\n            var a = p.alt.pfad.split('\/'), n = p.neu.pfad.split('\/');\n            \/\/ gemeinsamer Rest von hinten\n            var rest = 0;\n            while (rest < a.length - 1 &#038;&#038; rest < n.length - 1 &#038;&#038; a[a.length - 1 - rest] === n[n.length - 1 - rest]) { rest++; }\n            if (rest === 0 || p.alt.query || p.neu.query) { einzeln.push(p); return; }\n            var altPraefix = a.slice(0, a.length - rest).join('\/') + '\/';\n            var neuPraefix = n.slice(0, n.length - rest).join('\/') + '\/';\n            if (altPraefix === '\/' || altPraefix === neuPraefix) { einzeln.push(p); return; }\n            var k = (p.alt.host || '') + altPraefix + ' => ' + (p.neu.host || '') + neuPraefix;\n            if (!gruppen[k]) { gruppen[k] = { altHost: p.alt.host, alt: altPraefix, neuHost: p.neu.host, neu: neuPraefix, paare: [] }; }\n            gruppen[k].paare.push(p);\n        });\n        var regeln = [];\n        Object.keys(gruppen).forEach(function (k) {\n            var g = gruppen[k];\n            if (g.paare.length >= 2) { regeln.push(g); } else { einzeln.push(g.paare[0]); }\n        });\n        einzeln.sort(function (x, y) { return x.zeile - y.zeile; });\n        return { praefixe: regeln, einzeln: einzeln };\n    }<\/p>\n<p>    function reEsc(s) { return s.replace(\/[.*+?^${}()|[\\]\\\\]\/g, '\\\\$&'); }\n    function ohneSlash(p) { return p.replace(\/^\\\/\/, ''); }<\/p>\n<p>    function erzeugen(paare, praefixRegeln, format, code, qsa) {\n        var zeilen = [];\n        var flags = function (extra) { var f = ['L', 'R=' + code, 'NE']; if (qsa) { f.push('QSA'); } if (extra) { f = f.concat(extra); } return '[' + f.join(',') + ']'; };\n        var nginxCode = function () { return String(code); };\n        if (format === 'htaccess') {\n            zeilen.push('# ' + T.kommentar_kopf);\n            zeilen.push('RewriteEngine On');\n            praefixRegeln.forEach(function (g) {\n                var ziel = (g.neuHost || '') + g.neu + '$1';\n                zeilen.push('RewriteRule ^' + reEsc(ohneSlash(g.alt)) + '(.*)$ ' + ziel + ' ' + flags());\n            });\n            paare.forEach(function (p) {\n                var ziel = (p.neu.host || '') + p.neu.pfad + (p.neu.query || '');\n                if (p.alt.query) {\n                    zeilen.push('RewriteCond %{QUERY_STRING} ^' + reEsc(p.alt.query.slice(1)) + '$');\n                    zeilen.push('RewriteRule ^' + reEsc(ohneSlash(p.alt.pfad)) + '\/?$ ' + ziel + (p.neu.query ? '' : '?') + ' ' + flags().replace(',QSA', ''));\n                } else {\n                    zeilen.push('RewriteRule ^' + reEsc(ohneSlash(p.alt.pfad)) + '\/?$ ' + ziel + ' ' + flags());\n                }\n            });\n        } else if (format === 'redirect') {\n            zeilen.push('# ' + T.kommentar_kopf);\n            praefixRegeln.forEach(function (g) {\n                zeilen.push('RedirectMatch ' + code + ' ^' + reEsc(g.alt) + '(.*)$ ' + (g.neuHost || '') + g.neu + '$1');\n            });\n            paare.forEach(function (p) {\n                if (p.alt.query) { zeilen.push('# ' + T.kommentar_query + ' ' + p.altRoh); return; }\n                zeilen.push('Redirect ' + code + ' ' + p.alt.pfad + ' ' + (p.neu.host || '') + p.neu.pfad + (p.neu.query || ''));\n            });\n        } else if (format === 'nginx') {\n            zeilen.push('# ' + T.kommentar_kopf);\n            praefixRegeln.forEach(function (g) {\n                zeilen.push('location ^~ ' + g.alt + ' {');\n                zeilen.push('    rewrite ^' + reEsc(g.alt) + '(.*)$ ' + (g.neuHost || '$scheme:\/\/$host') + g.neu + '$1 ' + (code === '301' ? 'permanent' : 'redirect') + ';');\n                zeilen.push('}');\n            });\n            paare.forEach(function (p) {\n                var ziel = (p.neu.host || '$scheme:\/\/$host') + p.neu.pfad + (p.neu.query ? p.neu.query : (qsa ? '$is_args$args' : ''));\n                if (p.alt.query) {\n                    zeilen.push('if ($request_uri = \"' + p.alt.pfad + p.alt.query + '\") { return ' + nginxCode() + ' ' + (p.neu.host || '$scheme:\/\/$host') + p.neu.pfad + (p.neu.query || '') + '; }');\n                } else {\n                    zeilen.push('location = ' + p.alt.pfad + ' { return ' + nginxCode() + ' ' + ziel + '; }');\n                }\n            });\n        } else if (format === 'nginx_map') {\n            zeilen.push('# ' + T.kommentar_kopf);\n            zeilen.push('# http { ... }');\n            zeilen.push('map $request_uri $lw_redirect {');\n            zeilen.push('    default \"\";');\n            praefixRegeln.forEach(function (g) {\n                zeilen.push('    ~^' + reEsc(g.alt) + '(?<rest>.*)$ ' + (g.neuHost || '') + g.neu + '$rest;');\n            });\n            paare.forEach(function (p) {\n                zeilen.push('    ' + (p.alt.query ? '' : '') + p.alt.pfad + (p.alt.query || '') + ' ' + (p.neu.host || '') + p.neu.pfad + (p.neu.query || '') + ';');\n            });\n            zeilen.push('}');\n            zeilen.push('# server { ... }');\n            zeilen.push('if ($lw_redirect) { return ' + nginxCode() + ' $lw_redirect; }');\n        } else if (format === 'wordpress') {\n            zeilen.push('<?php');\n            zeilen.push('\/\/ ' + T.kommentar_kopf);\n            zeilen.push(\"add_action( 'template_redirect', function () {\");\n            zeilen.push(\"    $pfad = rtrim( (string) parse_url( $_SERVER['REQUEST_URI'], PHP_URL_PATH ), '\/' );\");\n            zeilen.push(\"    $query = (string) parse_url( $_SERVER['REQUEST_URI'], PHP_URL_QUERY );\");\n            zeilen.push('    $praefixe = array(');\n            praefixRegeln.forEach(function (g) { zeilen.push(\"        '\" + g.alt + \"' => '\" + (g.neuHost || '') + g.neu + \"',\"); });\n            zeilen.push('    );');\n            zeilen.push('    $einzeln = array(');\n            paare.forEach(function (p) { zeilen.push(\"        '\" + p.alt.pfad.replace(\/\\\/$\/, '') + (p.alt.query || '') + \"' => '\" + (p.neu.host || '') + p.neu.pfad + (p.neu.query || '') + \"',\"); });\n            zeilen.push('    );');\n            zeilen.push(\"    $schluessel = $pfad === '' ? '\/' : $pfad;\");\n            zeilen.push(\"    if ( isset( $einzeln[ $schluessel . ( $query !== '' ? '?' . $query : '' ) ] ) ) { $ziel = $einzeln[ $schluessel . ( $query !== '' ? '?' . $query : '' ) ]; }\");\n            zeilen.push(\"    elseif ( isset( $einzeln[ $schluessel ] ) ) { $ziel = $einzeln[ $schluessel ]\" + (qsa ? \" . ( $query !== '' ? '?' . $query : '' )\" : '') + '; }');\n            zeilen.push('    else {');\n            zeilen.push('        foreach ( $praefixe as $alt => $neu ) {');\n            zeilen.push(\"            if ( strpos( $pfad . '\/', $alt ) === 0 ) { $ziel = $neu . substr( $pfad . '\/', strlen( $alt ) )\" + (qsa ? \" . ( $query !== '' ? '?' . $query : '' )\" : '') + '; break; }');\n            zeilen.push('        }');\n            zeilen.push('    }');\n            zeilen.push('    if ( ! empty( $ziel ) ) { wp_redirect( $ziel, ' + code + \" ); exit; }\");\n            zeilen.push('} );');\n        }\n        return zeilen.join('\\n');\n    }<\/p>\n<p>    function bauen(text, optionen) {\n        var o = optionen || {};\n        var p = parsen(text);\n        var g = pruefen(p.paare, o.glaetten !== false);\n        var pr = o.praefix !== false ? praefixe(g.paare) : { praefixe: [], einzeln: g.paare.slice() };\n        var ausgabe = erzeugen(pr.einzeln, pr.praefixe, o.format || 'htaccess', String(o.code || '301'), o.qsa !== false);\n        return { fehler: p.fehler, hinweise: g.hinweise, paare: g.paare.length, praefixe: pr.praefixe, einzeln: pr.einzeln.length, ausgabe: ausgabe, format: o.format || 'htaccess', gelesen: p.paare.length };\n    }<\/p>\n<p>    window.LW_TEST = window.LW_TEST || {};\n    window.LW_TEST.RG = { parsen: parsen, pruefen: pruefen, praefixe: praefixe, erzeugen: erzeugen, bauen: bauen, darstellen: null, T: T };<\/p>\n<p>    \/\/ =========================================================================\n    \/\/ Oberflaeche\n    \/\/ =========================================================================<\/p>\n<p>    var btn = document.getElementById('rg-btn');\n    var out = document.getElementById('rg-ausgabe');\n    if (!btn || !out) { return; }\n    function el(tag, stil, txt) { var e = document.createElement(tag); if (stil) { e.setAttribute('style', stil); } if (txt !== undefined && txt !== null) { e.textContent = txt; } return e; }\n    function wert(id) { var e = document.getElementById(id); return e ? e.value : ''; }\n    function haken(id) { var e = document.getElementById(id); return e ? e.checked : true; }\n    var UEBERSCHRIFT = 'font-family: \"Nunito Sans\", sans-serif; font-weight: 700; color: var(--text-primary, #e8e8ee); font-size: 0.95rem; margin: 22px 0 8px;';\n    var ZELLE = 'padding: 5px 12px 5px 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem;';\n    var VORFORM = 'background: var(--bg-body, #14141a); border: 1px solid var(--border, #2a2a35); border-radius: 6px; padding: 12px; color: var(--text-primary, #e8e8ee); font-family: monospace; font-size: 0.8rem; white-space: pre; overflow-x: auto; margin: 0;';\n    var GUT = ' color: #7ee787;', WARN = ' color: #ffa94d;', ROT = ' color: #ff7b72;', GRAU = ' color: #8a8a99;';\n    function text(k, d) { var t = T[k]; if (typeof t !== 'string') { return k; } return t.replace(\/\\{([a-z_]+)\\}\/g, function (m, x) { return d && d[x] !== undefined ? String(d[x]) : m; }); }<\/p>\n<p>    function darstellen(b, ziel) {\n        ziel.innerHTML = '';\n        ziel.appendChild(el('div', ZELLE + ' margin: 0 0 6px;' + (b.paare ? GRAU : WARN), text('zusammenfassung', { gelesen: b.gelesen, paare: b.paare, praefixe: b.praefixe.length, einzeln: b.einzeln })));\n        if (b.fehler.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_fehler));\n            var lf = el('ul', 'margin: 0 0 0 18px; padding: 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem; line-height: 1.6;');\n            b.fehler.forEach(function (f) { lf.appendChild(el('li', ROT, text('fehler_' + f.art, { zeile: f.zeile, roh: f.roh }))); });\n            ziel.appendChild(lf);\n        }\n        if (b.hinweise.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_hinweise));\n            var lh = el('ul', 'margin: 0 0 0 18px; padding: 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem; line-height: 1.6;');\n            b.hinweise.forEach(function (h) {\n                var stil = (h.art === 'schleife' || h.art === 'widerspruch') ? ROT : (h.art === 'geglaettet' ? GUT : WARN);\n                lh.appendChild(el('li', stil, text('hinweis_' + h.art, h)));\n            });\n            ziel.appendChild(lh);\n        }\n        if (b.praefixe.length) {\n            ziel.appendChild(el('div', UEBERSCHRIFT, T.h_praefixe));\n            var lp = el('ul', 'margin: 0 0 0 18px; padding: 0; color: var(--text-secondary, #a0a0b0); font-size: 0.87rem; font-family: monospace; line-height: 1.6;');\n            b.praefixe.forEach(function (g) { lp.appendChild(el('li', '', (g.altHost || '') + g.alt + ' -> ' + (g.neuHost || '') + g.neu + '  (' + g.paare.length + ')')); });\n            ziel.appendChild(lp);\n        }\n        ziel.appendChild(el('div', UEBERSCHRIFT, T['h_ausgabe_' + b.format] || T.h_ausgabe));\n        var pre = el('pre', VORFORM, b.ausgabe);\n        ziel.appendChild(pre);\n        var kopieren = el('button', 'margin-top: 8px; background: transparent; color: var(--accent, #7ee787); border: 1px solid var(--accent, #7ee787); padding: 7px 14px; border-radius: 6px; font-weight: 700; cursor: pointer; font-size: 0.82rem;', T.kopieren);\n        kopieren.className = 'button rg-kopieren';\n        kopieren.addEventListener('click', function () {\n            if (navigator.clipboard) { navigator.clipboard.writeText(b.ausgabe).then(function () { kopieren.textContent = T.kopiert; setTimeout(function () { kopieren.textContent = T.kopieren; }, 1500); }); }\n        });\n        ziel.appendChild(kopieren);\n        ziel.appendChild(el('p', ZELLE + GRAU + ' margin: 12px 0 0; line-height: 1.55;', T['hinweis_format_' + b.format] || ''));\n    }\n    window.LW_TEST.RG.darstellen = darstellen;<\/p>\n<p>    btn.addEventListener('click', function () {\n        darstellen(bauen(wert('rg-paare'), { format: wert('rg-format'), code: wert('rg-code'), qsa: haken('rg-qsa'), praefix: haken('rg-praefix'), glaetten: haken('rg-glaetten') }), out);\n    });\n})();\n<\/script><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Zamienia list\u0119 starych i nowych adres\u00f3w w regu\u0142y przekierowa\u0144 dla Apache .htaccess, nginx lub hooka WordPressa. Scala pary z t\u0105 sam\u0105 zmian\u0105 katalogu w jedn\u0105 regu\u0142\u0119 prefiksow\u0105, sp\u0142aszcza \u0142a\u0144cuchy, tak aby ka\u017cdy stary adres wskazywa\u0142 cel ko\u0144cowy, i odrzuca p\u0119tle oraz sprzeczno\u015bci, zanim trafi\u0105 na serwer.<\/p>\n","protected":false},"author":1,"featured_media":0,"parent":9284,"menu_order":0,"comment_status":"closed","ping_status":"closed","template":"template-tool-base.php","meta":{"footnotes":""},"tags":[92229,92295,92421,92286],"class_list":["post-13552","page","type-page","status-publish","hentry","tag-devops-pl","tag-seo-pl","tag-server-administration-pl","tag-wordpress-pl"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v28.1 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog<\/title>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog\" \/>\n<meta property=\"og:description\" content=\"Zamienia list\u0119 starych i nowych adres\u00f3w w regu\u0142y przekierowa\u0144 dla Apache .htaccess, nginx lub hooka WordPressa. Scala pary z t\u0105 sam\u0105 zmian\u0105 katalogu w jedn\u0105 regu\u0142\u0119 prefiksow\u0105, sp\u0142aszcza \u0142a\u0144cuchy, tak aby ka\u017cdy stary adres wskazywa\u0142 cel ko\u0144cowy, i odrzuca p\u0119tle oraz sprzeczno\u015bci, zanim trafi\u0105 na serwer.\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/\" \/>\n<meta property=\"og:site_name\" content=\"Lukas Wojcik - Blog\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"1200\" \/>\n\t<meta property=\"og:image:height\" content=\"630\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:label1\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data1\" content=\"1 minute\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/redirect-rule-generator-htaccess-nginx\\\/\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/redirect-rule-generator-htaccess-nginx\\\/\",\"name\":\"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\"},\"datePublished\":\"2026-09-02T11:16:58+00:00\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/redirect-rule-generator-htaccess-nginx\\\/#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/redirect-rule-generator-htaccess-nginx\\\/\"]}]},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/pl\\\/narzedzia\\\/redirect-rule-generator-htaccess-nginx\\\/#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"Toolbox\",\"item\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/toolbox-3\\\/\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress)\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#website\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/\",\"name\":\"Lukas Wojcik - Blog\",\"description\":\"\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\"},\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":[\"Person\",\"Organization\"],\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/#\\\/schema\\\/person\\\/895f7604f9b6b71aad9bba33af28d0f9\",\"name\":\"luky\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"url\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"contentUrl\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\",\"width\":424,\"height\":636,\"caption\":\"luky\"},\"logo\":{\"@id\":\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\\\/wp-content\\\/uploads\\\/2026\\\/07\\\/lw-x2.jpg\"},\"sameAs\":[\"https:\\\/\\\/www.lukaswojcik.com\\\/blog\"]}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/","og_locale":"en_US","og_type":"article","og_title":"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog","og_description":"Zamienia list\u0119 starych i nowych adres\u00f3w w regu\u0142y przekierowa\u0144 dla Apache .htaccess, nginx lub hooka WordPressa. Scala pary z t\u0105 sam\u0105 zmian\u0105 katalogu w jedn\u0105 regu\u0142\u0119 prefiksow\u0105, sp\u0142aszcza \u0142a\u0144cuchy, tak aby ka\u017cdy stary adres wskazywa\u0142 cel ko\u0144cowy, i odrzuca p\u0119tle oraz sprzeczno\u015bci, zanim trafi\u0105 na serwer.","og_url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/","og_site_name":"Lukas Wojcik - Blog","og_image":[{"width":1200,"height":630,"url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/08\/og-default.jpg","type":"image\/jpeg"}],"twitter_card":"summary_large_image","twitter_misc":{"Est. reading time":"1 minute"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"WebPage","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/","url":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/","name":"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress) - Lukas Wojcik - Blog","isPartOf":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#website"},"datePublished":"2026-09-02T11:16:58+00:00","breadcrumb":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/"]}]},{"@type":"BreadcrumbList","@id":"https:\/\/www.lukaswojcik.com\/blog\/pl\/narzedzia\/redirect-rule-generator-htaccess-nginx\/#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.lukaswojcik.com\/blog\/"},{"@type":"ListItem","position":2,"name":"Toolbox","item":"https:\/\/www.lukaswojcik.com\/blog\/toolbox-3\/"},{"@type":"ListItem","position":3,"name":"Generator regu\u0142 przekierowa\u0144 301 (.htaccess, nginx, WordPress)"}]},{"@type":"WebSite","@id":"https:\/\/www.lukaswojcik.com\/blog\/#website","url":"https:\/\/www.lukaswojcik.com\/blog\/","name":"Lukas Wojcik - Blog","description":"","publisher":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9"},"potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.lukaswojcik.com\/blog\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":["Person","Organization"],"@id":"https:\/\/www.lukaswojcik.com\/blog\/#\/schema\/person\/895f7604f9b6b71aad9bba33af28d0f9","name":"luky","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","url":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","contentUrl":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg","width":424,"height":636,"caption":"luky"},"logo":{"@id":"https:\/\/www.lukaswojcik.com\/blog\/wp-content\/uploads\/2026\/07\/lw-x2.jpg"},"sameAs":["https:\/\/www.lukaswojcik.com\/blog"]}]}},"_links":{"self":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13552","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages"}],"about":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/types\/page"}],"author":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/users\/1"}],"replies":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/comments?post=13552"}],"version-history":[{"count":0,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/13552\/revisions"}],"up":[{"embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/pages\/9284"}],"wp:attachment":[{"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/media?parent=13552"}],"wp:term":[{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.lukaswojcik.com\/blog\/wp-json\/wp\/v2\/tags?post=13552"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}