Skip to content
Blog

How AI-Generated .htaccess Rules Can Break WordPress

November 12, 2026 · Nordic Digi Solutions · 15 min read

AI tools can generate WordPress code fast, .htaccess rules included. That speed is useful, but .htaccess is one of the riskiest places to paste AI-generated code without review. A single rewrite rule changes how requests reach WordPress, and it can touch the homepage, the login page, admin AJAX, the REST API, WooCommerce checkout, forms, redirects and static files.

The real danger is that the site still looks like it works. The homepage loads and the menu opens, while checkout, search, a form or a payment fails silently, because the request is intercepted before WordPress ever sees it.

This article explains why AI-generated .htaccess rules break WordPress, the mistakes to avoid, and how to review a rule before it goes live. For the wider picture, see our post on common mistakes with AI-generated code in WordPress.

What is .htaccess in WordPress?

.htaccess is Apache’s per-directory configuration file. Its rules apply to the folder it sits in and every folder below it, and Apache reads it again on every request. LiteSpeed, which some hosts run instead of Apache, is built to understand Apache’s configuration and follows its rewrite syntax. Nginx has no .htaccess at all. WordPress uses the file for pretty permalinks with this block:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

Requests for files and folders that exist are served as they are (the !-f and !-d checks); everything else goes to index.php, and WordPress decides what to show. The dash in the index.php line means “no substitution”: requests for that file pass straight through and skip the file checks.

Two things follow. When WordPress writes its rules, which saving Settings > Permalinks does, it replaces everything between # BEGIN WordPress and # END WordPress and keeps the rest of the file, so your own rules go above or below the block, never inside it. And anything above the block runs first, before WordPress gets a say. That is where the trouble starts.

Why AI-generated .htaccess code is risky

AI can produce a rule that looks technically valid:

RewriteRule ^$ /home.html [L]

It reads as “send homepage requests to home.html“. But WordPress also handles dynamic requests on the homepage address with a query string. WooCommerce’s classic checkout, for instance, refreshes the order totals with:

/?wc-ajax=update_order_review

A rule meant for the homepage catches that request too, and WooCommerce receives a static HTML page instead of the JSON it expected. The customer sees checkout loading forever, an order review that never updates, missing payment methods or a Place order button that does nothing.

This is not hypothetical. In one WooCommerce case we traced, exactly this pattern made checkout load forever while the rest of the site looked healthy. The rule looks small. The impact can be large.

Mistake 1: Using static HTML rewrites inside a dynamic WordPress site

A typical AI suggestion for a faster homepage is a static file plus a rule like this:

RewriteCond %{REQUEST_URI} ^/$
RewriteRule ^$ /home.html [L]

The condition adds nothing: REQUEST_URI is the path without the query string, so /?wc-ajax=update_order_review passes it like any homepage visit. The result is a mixed architecture, with the homepage served as static HTML and everything else by WordPress, while plugins, forms and WooCommerce expect normal routing. That mix is fragile.

Let WordPress serve the homepage: a page chosen under Settings > Reading or a front-page.php template, with page caching for speed. Our guide to converting static HTML into a WordPress theme shows how to keep an AI-generated design without the rewrite.

Mistake 2: Forgetting that query strings matter

A RewriteRule pattern is matched against the path only, never the query string, and in .htaccess the leading slash is removed first. So to ^$, all of these are the site root:

/?wc-ajax=update_order_review
/?rest_route=/wp/v2/posts
/?s=search-term
/?add-to-cart=123

Those are WooCommerce’s checkout requests, the REST API on sites without pretty permalinks, the WordPress search form and WooCommerce’s add-to-cart links. Apache even passes the original query string on to the new target by default, and a static file simply ignores it.

If you really must keep a static homepage, limit the rule to plain page views: GET or HEAD requests with no query string, from visitors who are not logged in and have nothing in their cart.

RewriteCond %{REQUEST_METHOD} ^(GET|HEAD)$
RewriteCond %{QUERY_STRING} ^$
RewriteCond %{HTTP_COOKIE} !(wordpress_logged_in_|woocommerce_items_in_cart) [NC]
RewriteRule ^$ /home.html [L]

Conditions combine with AND, so the rule only fires when all three match. Even so, the better answer is usually no rewrite at all: a theme template keeps WordPress in charge, and a page cache set up the way WooCommerce’s caching guide describes handles these exceptions for you.

Mistake 3: Placing custom rules before WordPress without knowing the impact

Rules near the top of the file see the request before WordPress does:

RewriteEngine On
RewriteRule ^$ /home.html [L]

# BEGIN WordPress
...
# END WordPress

[L] is often explained as “last rule”, which is only half true in .htaccess. It ends the current pass, but Apache then runs the rewritten request through the file again, so a rule whose result matches its own pattern can loop until Apache gives up after ten internal redirects (LimitInternalRecursion). [END] stops rewriting for good. On LiteSpeed, [L] already acts like Apache’s [END], one reason a rule can behave differently on two hosts.

Habits from the main server configuration fail quietly too: Apache’s documentation says a pattern starting with ^/ never matches in per-directory context, so RewriteRule ^/old-page$ /new-page/ [R=301,L] does nothing in .htaccess. Before placing anything above the WordPress block, ask whether it could affect AJAX, the REST API, checkout, login and account pages, query strings, multilingual URLs or caching.

Mistake 4: Redirecting cart, checkout or account pages

AI-generated rules that clean up URLs, force trailing slashes or redirect old pages can collide with the pages, endpoints and query-string requests WooCommerce relies on:

/cart/
/checkout/
/checkout/order-received/
/my-account/
/my-account/lost-password/
/?wc-ajax=...
/?wc-api=...

Those are the default English slugs; a store set up in another language gets translated ones. Rules like these are risky:

RewriteRule ^checkout$ /checkout/ [R=301,L]
RewriteRule ^my-account$ /login/ [R=301,L]
  • Redirect loops. WordPress already redirects visitors to its canonical address, with or without www, for example. A server rule pointing the other way bounces the browser back and forth until it gives up.
  • Lost form data. On a 301 or 302 a browser may turn a POST into a GET, so a redirect in front of a form, checkout or callback can drop what was sent. WordPress itself never redirects POST requests to canonical URLs.
  • Lost query strings. A substitution ending in ?, or the [QSD] flag, throws the query string away. That breaks wc-ajax requests and payment callbacks such as PayPal Standard’s, which WooCommerce’s gateway documentation shows as the homepage address plus ?wc-api=.
  • Endpoints sent nowhere. Apache’s Redirect keeps the rest of the path, so Redirect 301 /my-account /login also sends /my-account/lost-password/ to /login/lost-password/, which does not exist.

Leave cart, checkout and account pages alone unless there is a specific reason, and test the full order flow, payment included, afterwards.

Mistake 5: Returning HTML where AJAX expects JSON

A WooCommerce AJAX request expects JSON such as {"result":"success","fragments":{}}. A bad rule returns <!DOCTYPE html> and a whole page instead. The browser may still show 200 OK, but checkout’s JavaScript cannot use the answer. Open the Network panel, filter on Fetch/XHR and inspect the failing request’s URL, status, headers, content type and body: wc-ajax=update_order_review for the classic checkout, requests under /wp-json/wc/store/ for the Checkout block. WooCommerce’s troubleshooting guide lists what turns its JSON into HTML: a cache, maintenance or security layer, a redirect, a proxy or a PHP warning. Our post on WooCommerce checkout stuck loading goes through each cause.

Mistake 6: Using .htaccess for problems WordPress should handle

Many AI-generated rules solve at server level what WordPress handles more safely, and Apache’s own documentation calls mod_rewrite a last resort when simpler tools exist.

  • Homepage: instead of RewriteRule ^$ /home.html [L], set a static homepage under Settings > Reading or build front-page.php.
  • Redirects: instead of RewriteRule ^old-page$ /new-page [R=301,L], use a redirect plugin for anything editors maintain. For a few fixed redirects, Apache recommends its simpler Redirect and RedirectMatch over RewriteRule.
  • Assets: instead of RewriteRule ^assets/(.*)$ /custom-folder/$1 [L], load files with wp_enqueue_style() and wp_enqueue_script().
  • Checkout changes: instead of RewriteRule ^checkout/(.*)$ /custom-checkout.php [L], use WooCommerce’s hooks and template overrides.

Mistake 7: Pasting caching and header blocks that hit every page

Ask an AI tool to speed up WordPress and you may get something like this:

<IfModule mod_headers.c>
  Header set Cache-Control "public, max-age=31536000"
</IfModule>

Unscoped, that header goes on every successful response Apache sends, including the pages WordPress builds through index.php: cart, checkout and My account too. WooCommerce sends no-cache headers on exactly those pages. Header set replaces a header of the same name, and where PHP runs on PHP-FPM through mod_proxy_fcgi, Apache’s documentation warns it can leave both values in the response instead. Either way, checkout now carries a one-year cache header. Scope the rule to static files:

<FilesMatch "\.(css|js|png|jpe?g|gif|webp|avif|svg|woff2?)$">
  Header set Cache-Control "public, max-age=31536000"
</FilesMatch>

A long lifetime is only safe when a file’s URL changes whenever the file does, which is what the version WordPress adds to enqueued files is for. Notice the <IfModule> wrapper, too. Apache only reads what is inside it when the module is loaded, and its documentation says normal configurations do not need it. If mod_headers is missing, the wrapped rule silently does nothing, while the same rule unwrapped gives a 500 error. Check in the browser that the header is really there.

Mistake 8: Not testing logged-in and logged-out visitors

Rules can test cookies, the request method and the query string, and WooCommerce asks caches to skip visitors who carry its cart and session cookies. A logged-in admin may see the right pages while customers get cached or redirected ones. After a change, test logged in and logged out, in a private window, on a phone, through the whole product-to-checkout flow, plus a form, search, login, the account page and any REST API or AJAX endpoints you rely on.

Mistake 9: Not keeping a backup, and not reading the 500

One broken line in .htaccess can take the whole site down with a 500 internal server error. The usual causes:

  • A typo. Apache’s error log names it, for example RewriteCond: bad flag delimiters.
  • A directive the host does not allow. AllowOverride in the server configuration decides what .htaccess may contain, and anything else is a server error. A line such as Options -Indexes needs AllowOverride Options.
  • A module that is not loaded. An unknown directive is an error too. Apache’s own test for whether .htaccess is read at all is to type a nonsense word into it and look for the 500.
  • PHP settings in the wrong place. php_value and php_flag lines, for example to raise memory or upload limits, belong to PHP running as an Apache module and are unknown directives without it. Where PHP runs as FastCGI or PHP-FPM, use a .user.ini file.

Before changing the file, download a copy or save one outside the public web root. Make one change at a time and reload the site after each. If it breaks, put the backup back immediately.

Mistake 10: Ignoring cache and CDN layers

After you fix .htaccess, the old behaviour can seem to continue because a cache plugin, a server cache, the CDN or the browser still holds old responses. Clear the relevant caches and retest. Redirects need extra care: a 301 is cacheable by default, so a wrong permanent redirect can keep firing from visitors’ browsers after you remove the rule. Test new redirects as 302, which is what Apache’s [R] flag sends when you give no code, and switch to 301 once they are right.

For WooCommerce, keep cart, checkout and My account out of page and edge caching, and make sure the cache, CDN and firewall let WooCommerce’s AJAX requests through:

/cart/
/checkout/
/my-account/
/?wc-ajax=

How to review an AI-generated .htaccess rule safely

  1. What exact request should it affect? “The homepage” is a weak answer. Better: only a GET request to / with no query string, from a visitor who is not logged in, never AJAX, REST API or WooCommerce.
  2. Does it handle or ignore query strings? The pattern never sees them.
  3. Could it touch WordPress’s dynamic routes? Check /wp-admin/, /wp-login.php, /wp-json/, /?wc-ajax=, /?wc-api=, cart, checkout and My account.
  4. Is there a WordPress-native solution? If yes, prefer it.
  5. Can you test it on staging, on the same kind of server as the live site?
  6. Is there a rollback plan? Keep the backup within reach.

Quick debug checklist: did .htaccess break WordPress?

  • Do the site and /wp-admin/ load? Do permalinks and /wp-json/ work?
  • Is the homepage served by WordPress or by a static file?
  • Does the checkout’s AJAX request return JSON? Does checkout complete?
  • Any redirect loops? Do CSS and JS load? Do search and the contact form work?
  • Did you clear the caches, and does restoring the previous .htaccess fix it?

Restoring the previous version and retesting is often the fastest way to confirm that .htaccess is responsible.

When to ask for help

Bring in a specialist when checkout loads forever, WooCommerce AJAX returns HTML, redirects behave inconsistently, the admin works but the front end fails, the site broke right after an AI-generated change, or nobody can say what a rule does. The cause may be one line, but finding it means following the request path properly.

Reviewing and fixing AI-written .htaccess rules is part of our WordPress fixing service: free diagnosis, a fixed price in writing before we start (from €199), and if we can’t fix it, you pay nothing. If the change surfaced PHP errors, PHP bug fixing works on the same terms. Send us the issue; we reply within 30 minutes during business hours and follow the request to the real cause before changing anything.

Final thoughts

AI can generate .htaccess rules quickly, but that does not make them safe for WordPress. The risk comes from adding server-level rules without knowing what WordPress, WooCommerce and plugins expect from each request. Before using one, ask: what else could this rule affect? That question can save hours of debugging and lost orders.

Sources

Last checked 12 November 2026.

Chat on WhatsApp