惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

Martin Fowler
Martin Fowler
D
DataBreaches.Net
F
Fortinet All Blogs
阮一峰的网络日志
阮一峰的网络日志
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
H
Help Net Security
M
MIT News - Artificial intelligence
美团技术团队
人人都是产品经理
人人都是产品经理
freeCodeCamp Programming Tutorials: Python, JavaScript, Git & More
Cyber Security Advisories - MS-ISAC
Cyber Security Advisories - MS-ISAC
The Cloudflare Blog
有赞技术团队
有赞技术团队
L
LangChain Blog
博客园 - Franky
钛媒体:引领未来商业与生活新知
钛媒体:引领未来商业与生活新知
博客园 - 【当耐特】
S
SegmentFault 最新的问题
V
Visual Studio Blog
Blog — PlanetScale
Blog — PlanetScale
Hugging Face - Blog
Hugging Face - Blog
B
Blog
I
InfoQ

Jeremy Carlson

Convert Post Metadata into Tags (Terms) – Jeremy Carlson Reorganize your WordPress files to make your life easier – Jeremy Carlson Pay attention. – Jeremy Carlson A SASS Mixin to accommodate @font-face fallbacks – Jeremy Carlson Can I use type in an image? – Jeremy Carlson Creating a site structure for the future – Jeremy Carlson Running a Successful Business with the Add-On Model – Jeremy Carlson What I Learned About WordPress Development by Interviewing 15 of the Best WordPress Developers – Jeremy Carlson Quirky Client Communication and How to Fix It – Jeremy Carlson
Excluding a directory from WordPress – Jeremy Carlson
Jeremy · 2017-02-04 · via Jeremy Carlson

I’m working on a site, and we have been storing archive copies of our newsletter on our site like this:

http://example.com/newsletter/2015-05/

The site itself has been a homegrown PHP solution which I’m finally, after years, converting to WordPress. One challenge is this folder structure. I don’t really want to mess with it. But I need http://example.com to run with WordPress. So I need to exclude the newsletter directory (folder, whatever).

I looked around and found a great tip on excluding a directory which shows just how to write the proper code into my .htaccess file, like this:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_URI} !^/(mydir|mydir/.*)$
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

The salient line that’s added is saying the REQUEST_URI must NOT be either ‘mydir’ or ‘mydir/whatever’. It’s great, works a treat.

But there’s one small problem.

If you change your permalinks, your rewrite rules are flushed, and the .htaccess file is overwritten. Now, you could just make sure your .htaccess file is not writable, but where’s the fun in that? Instead I want to tap into WordPress’s WP_Rewrite API and make sure that, should we change the file, this rule will be preserved.

Luckily the API has lots of hooks so we can manipulate things. I initially looked using the add_rewrite_rule function to add to the rewrite_rules array—since WordPress at one point has an array of all the rewrite rules that seemed handy. But then I noticed that the action to hook into that only seems to be working for rewrite RULES, not rewrite CONDITIONS.

Someone had already asked if WordPress had a function to generate a rewrite condition on StackExchange. The answer given was very helpful, leading me to use the mod_rewrite_rules hook to mess with the entire string of content just before it gets written to .htaccess.

First I need to define my new rule, like this:

// Create our condition.
$exclude_newsletter_cond = PHP_EOL . 'RewriteCond %{REQUEST_URI} !^/(newsletter/.*)$';

Then I’m going to insert this condition just after the line with RewriteBase—that’s a unique point that comes somewhere in the midst of the rules. This means the condition will get inserted BEFORE the first RewriteRule. But it works just fine. (YMMV)

I’m going to do a preg_replace to search for ‘RewriteBase.+’ and replace it that with itself, plus the string I created above. My search looks like this—remember you need the forward slashes in your search string for preg_replace:

$search = '/RewriteBase.+/';

And then we just replace it. You can see this in the full code example below.

/**
* We need to parse the rewrite rules string, and insert something
* INSIDE it. If this were a rewrite RULE, then we could insert it
* into the array that gets prepped before getting converted into a
* string. If you want to do that, may want to check out the Codex:
* https://codex.wordpress.org/Class_Reference/WP_Rewrite
* (Note: this would be a different hook , too)
*
* In our case, since we are creating a CONDITION, we need to muscle
* our way into the string.
*/
function my_custom_htaccess( $rules ){

// Create our condition.
$exclude_newsletter_cond = PHP_EOL . 'RewriteCond %{REQUEST_URI} !^/(newsletter/.*)$';

// Look for a place to insert it.
// We are going to put this just after the RewriteBase line.
// This is not in the same place as all the other RewriteCond statements,
// But it seems to work.
$search = '/RewriteBase.+/';

// Replace w/ found string, plus condition
$replace = '$0' . $exclude_newsletter_cond;

// Rock and roll.
$rules = preg_replace($search, $replace, $rules);

return $rules;
}
add_filter('mod_rewrite_rules', 'my_custom_htaccess');

This produces the following set of WordPress rules:

# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_URI} !^/(newsletter/.*)$
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php [L]
</IfModule>
# END WordPress

So yes, the RewriteCond does come before the first RewriteRule, but it worked locally. I’ll update this post if I find other issues.

If you found this, and it was helpful, let me know!