Wildcard forward all posts and pages with few exceptions

You could do something like the following at the top of your .htaccess file, before the WordPress front-controller:

# Prevent rewritten requests (to the WP front-controller) from being redirected
RewriteCond %{ENV:REDIRECT_STATUS} .
RewriteRule ^ - [L]

# Redirect everything from "example.com" to "example.dev"
# Except for certain URLs that should stay at .com
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{REQUEST_URI} !^/pageA-to-stay-at-com
RewriteCond %{REQUEST_URI} !^/pageB-to-stay-at-com
RewriteCond %{REQUEST_URI} !^/pageC-to-stay-at-com
RewriteRule ^ https://example.dev%{REQUEST_URI} [R=302,L]

# Redirect certain URLs from "example.dev" to "example.com"
#  - That should stay at .com (not .dev)
RewriteCond %{HTTP_HOST} ^(www\.)?example\.dev [NC]
RewriteCond %{REQUEST_URI} ^/pageA-to-stay-at-com [OR]
RewriteCond %{REQUEST_URI} ^/pageB-to-stay-at-com [OR]
RewriteCond %{REQUEST_URI} ^/pageC-to-stay-at-com
RewriteRule ^ https://example.com%{REQUEST_URI} [R=302,L]

Note the ! (negation) prefix on the CondPatterns in the first rule block. This makes the condition successful only when the URL does not match. However, in the second rule block (no ! prefix), the requested URL must match one of the stated URLs in order to be redirected back to .com.

Test first with 302 (temporary) redirects and only change to 301 (permanent) – if that is the intention – once you have confirmed everything is working OK. This is to avoid potential caching issues.


Another (better) approach, avoiding repetition of the URLs:

# Prevent rewritten requests (to the WP front-controller) from being redirected
RewriteCond %{ENV:REDIRECT_STATUS} .
RewriteRule ^ - [L]

# Set an environment variable STAY_AT_COM if the requested URL 
# is one of those that should stay at the .com domain
RewriteCond %{REQUEST_URI} =/pageA-to-stay-at-com [OR]
RewriteCond %{REQUEST_URI} =/pageB-to-stay-at-com [OR]
RewriteCond %{REQUEST_URI} =/pageC-to-stay-at-com
RewriteRule ^ - [E=STAY_AT_COM:yes]

# Nothing to change below here except for the domain names...

# Redirect everything from "example.com" to "example.dev"
# Except for the URLs that should stay at .com
RewriteCond %{HTTP_HOST} ^(www\.)?example\.com [NC]
RewriteCond %{ENV:STAY_AT_COM} !yes
RewriteRule ^ https://example.dev%{REQUEST_URI} [R=302,L]

# Redirect URLs back from "example.dev" that should stay at .com
RewriteCond %{HTTP_HOST} ^(www\.)?example\.dev [NC]
RewriteCond %{ENV:STAY_AT_COM} yes
RewriteRule ^ https://example.com%{REQUEST_URI} [R=302,L]

I’ve changed the conditions in the first rule block to exact string matches (= prefix), rather than regex (that were missing the end-of-string anchor). This shouldn’t make much difference with the URLs you are using, but it is easier to enter and avoids potential conflicts in the future.


UPDATE: I’d overlooked that some URLs need to be accessible from both domains and not redirected. The above would redirect to one or the other (two-state). You need triple-state… one or the other or both.

Try the following instead (at the top of the .htaccess file):

# Prevent rewritten requests (to the WP front-controller) from being redirected
RewriteCond %{ENV:REDIRECT_STATUS} .
RewriteRule ^ - [L]

# The TARGET_DOMAIN environment variable holds the desired target domain (if any)
#  - for the requested URL
# eg. "example.com" or "example.dev" or empty for no redirect / accessible from both.

# Set the "default" target domain
#  - Any URLs not listed below will redirect to this domain
RewriteRule ^ - [E=TARGET_DOMAIN:example.dev]

# URLs that should be redirected to (or remain at) the other domain
RewriteCond %{REQUEST_URI} ^/bio [OR]
RewriteCond %{REQUEST_URI} ^/computing [OR]
RewriteCond %{REQUEST_URI} ^/contact [OR]
RewriteCond %{REQUEST_URI} ^/donate [OR]
RewriteCond %{REQUEST_URI} ^/encrypt [OR]
RewriteCond %{REQUEST_URI} ^/genderless-pronouns [OR]
RewriteCond %{REQUEST_URI} ^/gnu-linux-controversy [OR]
RewriteCond %{REQUEST_URI} ^/legal [OR]
RewriteCond %{REQUEST_URI} ^/readings [OR]
RewriteCond %{REQUEST_URI} ^/now
RewriteRule ^ - [E=TARGET_DOMAIN:example.com]

# URLs that should not be redirected - accessible from both domains
#  - Sets TARGET_DOMAIN to empty string (ie. no target domain)
RewriteCond %{REQUEST_URI} ^/login [OR]
RewriteCond %{REQUEST_URI} ^/admin [OR]
RewriteCond %{REQUEST_URI} ^/wp-admin [OR]
RewriteCond %{REQUEST_URI} ^/wp-login [OR]
RewriteCond %{REQUEST_URI} \.(php|css|js|jpg|gif|webp)$ [NC,OR]
RewriteCond %{REQUEST_FILENAME} -f [OR]
RewriteCond %{REQUEST_FILENAME} -d
RewriteRule ^ - [E=TARGET_DOMAIN]

# Redirect to the desired TARGET_DOMAIN (if any)
#  - if not already at the TARGET_DOMAIN
RewriteCond %{ENV:TARGET_DOMAIN} .
RewriteCond %{HTTP_HOST}@@%{ENV:TARGET_DOMAIN} !^([a-z0-9.-]+)@@\1$
RewriteRule ^ https://%{ENV:TARGET_DOMAIN}%{REQUEST_URI} [R=302,L]

Additional explanation:

RewriteCond %{REQUEST_URI} ^/bio [OR]

I’ve gone back to using a regular expression (regex) match. This gives you greatest flexible at the expense of additional complexity (although you can mix the two). The above matches any URL that starts with /bio. So, it will also match /bio/ and /bioanything. Use an end-of-string anchor ($) to match /bio only. eg. ^/bio$.

Using a regex will be required to avoid redirecting any URL that starts /wp-admin.

RewriteCond %{ENV:TARGET_DOMAIN} .
RewriteCond %{HTTP_HOST}@@%{ENV:TARGET_DOMAIN} !^([a-z0-9.-]+)@@\1$
RewriteRule ^ https://%{ENV:TARGET_DOMAIN}%{REQUEST_URI} [R=302,L]

The first condition ensures we only try to redirect when there is a target domain set. The second condition checks to see whether the currently requested domain (ie. the Host header) is different to the TARGET_DOMAIN. If both of these checks are successful then it redirects to the target domain on the same URL.

As before, make sure your browser cache is clear before testing and test with a 302 (temporary) redirect to avoid potential caching issues.