Deny Wordpress and plugins from updating .htaccess file - php

I am having some problems with Wordpress or some plugins occasionally updating/overwriting my .htaccess file, which will return 404 error pages when visiting posts. To fix this i need to save permalinks again.
I have removed url slug "categories" on my site, so it looks like this:
Original
www.mysite.com/category/post-title
Updated with hack
www.mysite.com/post-title
I have +20 plugins installed and i am not sure what is causing this problem.
Is it possible to deny Wordpress and plugins from writing to .htaccess file?
This is my hack to disable category from URL slug in functions.php
/* Kill category base */
function kill_category_base ($string) {
$string = str_replace('category/', '', $string);
return $string;
}
add_filter('category_link', 'kill_category_base');
And this is my .htaccess
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
# redirect everything else to wordpress
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
# END WordPress

If you have ssh access to your server, you can issue the following command to limit write access to the file, so that nobody, except the root user, can edit the file, including WordPress:
chmod 444 .htaccess
You will need to either run this command as the root user, or as the current owning user of the file.
If you do not have ssh access to your server, then you have little option here. If that is the case, you will need to hunt through the code of all your plugins and figure out which one it is that writes to that file. Then either deactivate that plugin, or change the code so that it does not write to that file anymore.
UPDATE
I noticed that several people are giving my answer a bit of guff here. I read all them, and reread the question just to be sure. As it turns out, I must have misread the question to begin with.
My original answer was based from a security stand point. I thought the question was asking about how to prevent the file from being overwritten, from a security standpoint, as in maybe your site got hacked or something. If that were the case, setting the permissions to 444 will work 100% of the time, but you would need to do it to basically all files, except a small handful of them and the uploads dir. In fact doing this, along with keeping all my plugins up to date, has prevented any of the sites my company personally hosts from being hacked, ever, and we host almost 300, with traffic ranging from 1000/month to 0.5 billion/month. The deployment process is a little longer, but the benefits of being security vigilant severely out weight the consequences of the extra deployment time.
BUT, the question was not asking that, so my bad. In fact, after looking again, and actually understanding the question this time, #mr_mmmmore has close to the correct response. You do simply need to MOVE YOUR MODIFICATIONS out side of the # BEGIN WordPress and # END WordPress, but there is a little more to it though.
If you want (most) plugins to also not overwrite your changes (not just core WordPress), you need to also wrap your code in similar markers. Otherwise, your code might still be removed when the htaccess is updated. Your final file should look something like this:
# BEGIN MyCodeTop
RewriteEngine On
RewriteBase /
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
# END MyCodeTop
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
# END WordPress
# BEGIN MyCodeBottom
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
# END MyCodeBottom
In general, WordPress itself will keep your changes to the htaccess file, without modifying them, even if they are not in their own marker group; however, there are a few plugins out there that bastardize the core WordPress functions that manage the htaccess file, and misuse them in such a way that they wind up just removing your changes, because they do not exist inside their own marker group. To be safe, it is best to just follow the WordPress standard, and make your own marker group, and put your code in there.
Thanks #mr_mmmmore for making me reread the question here, because I totally missed the whole point the first time. Plus one.

Denying Worpress from writing to .htaccess seems overkill for the problem you encounter. Plus some plugins depend on being able to write to .htaccess, so I wouldn't advise to do so without investigating on possible consequences (for example cache plugins may need to add rewrite rules).
And you don't have to do so: the reason why WP deletes your own editings is because you put them between the # BEGIN Wordpress and # END Wordpress comments. You have no control on what goes between those: consider it as a reserved place in the .htaccess file where WP does whatever it needs to. Everything not added by WP here will be removed at some point.
So all you have to do is move your editings outside the BEGIN/END WP comments, like so (you have to decide what must go before and after the WP rules):
# editings that must run before WP rewrite rules
#-------------------------
RewriteEngine On
RewriteBase /
# add a trailing slash to /wp-admin
RewriteRule ^wp-admin$ wp-admin/ [R=301,L]
# BEGIN WordPress
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^(.*)$ index.php [L]
# END WordPress
# editings that must run after WP rewrite rules
#-------------------------
RewriteRule ^ - [L]
RewriteRule ^(wp-(content|admin|includes).*) $1 [L]
RewriteRule ^(.*\.php)$ $1 [L]
Defining what must go before or after WP rules depends on what you're wanting to do. Usually I keep WP rules at the end and put mine before.

I have over half a year struggling with this .htaccess reset issue on various sites until now.
My temporal solution was to reinstall the latest file-system backup (.zip) each time this happened (which in some cases even avoided the site to display correctly or at least even display, but on most it avoided admins to enter the admin panel).
The real solution seems really easy, but works only for the case that your site has been hacked (haven't yet been able to catch how or exactly when are those sites being hacked). In this cases the wp-includes/nav-menu.php file is being corrupted and forces the .htaccess to reset to default and sets it's permissions to 444.
So the solution is to restore that file with the correct one for your WP version.
Nevertheless, this is not a solution for the security issue that allow this hack to happen, and I suspect many different plugins can be the leak or backdoor for this type of hack. So what you could do to solve the security issue is installing the Sucuri Security - Auditing, Malware Scanner and Security Hardening or Wordfence plugins.
Personally, installing plugins to augment the security of a site seems to be an analogy to installing antivirus in PC's. I would also recommend some environment approaches like Cloudflare.

If you really know what your are doing, you can prevent wordpress from updating your .htaccess file. Put this line at the end of your wp-config.php (after the require_once):
add_filter('got_rewrite', '__return_false');
You can also use this filter in a mu-plugin/plugin.
I like this solution better than the chmod hack because it doesn't spam permission errors in the logs.

CHMOD doesnt work Wordpress rewrite it
No matter if lines are between Begin and ND Wordpress
No Plugins installed and WORDPRESS rewrite it
none of answers here is correct

Related

Wordpress - Sub domain URL slash / missing after domain and before Post & page slug

WordPress page/page is not working after moved the file to subdomain. URL structure domain.com/subdomain/post1 is loading as domain.com/subdomainpost1 - slash (/) is missing before post/page slug. Home page and Other site assets working fine (i.e., images, css, js) - Only post and pages not loading.
Site .htaccess
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
RewriteBase /subdomain/
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /subdomain/index.php [L]
</IfModule>
# END WordPress
I have updated different permalink and still, it's not working. Also, deactivate all plugins and tested, still no fix. Someone, please help me to fix.
Generally you shouldn't be messing around with .htaccess files, if you don't fully understand the rewrite rules you're changing or the security risks.
Besides that, I assume that your "home" and "siteurl" are both updated in the database, so the easiest way to go from here, would probably be to delete the .htaccess file and then save permalinks in the admin page.
By doing so, WordPress will automatically generate a new .htaccess file that logically should be working out of the box. Then you can add your authorization block afterwards. That should go somewhere below the # END WordPress comment. You should never have to change the default WordPress .htaccess rules as it potentially breaks stuff.
If it still messes up, try searching your database for wrong formatted url's etc.

How to redirect all API requests using .htaccess, while keeping asset requests intact?

TL; DR: I would like to hit the index-api.php file if api is found in the URL, but then simply keep all other requests pointing to the site/dist directory as if it were the 'root' of the site.
So, I've spent way too many hours on this and trust me, I've dug through all of the resources for mod_rewrite. I guess I'm just not quite understanding and figured I'd ask on here.
What I want to do, in theory, seems simple. I'm building a single page application (Angular App) using Grunt, outputting that to a the root of a WordPress install. The WordPress install is simply serving up an API using the WordPress JSON API plugin, so I want the root of the site to hit my Grunt directory (located at site/dist/index.html), but all requests to siteurl.com/api to hit the index.php file and proceed normally.
Keep in mind I have other assets / images located in this site/dist directory, so ideally, it would be awesome if all requests to the site root would simply use this folder as the "base" of the site (e.g. a request to siteurl.com/images/testimage.jpg pulls from site/dist/images/testimage.jpg).
I feel like I'm onto something here and am surprised I couldn't find anything that directly tackles this issue.
What I've done now is renamed the index.php from WordPress to index-api.php and left it the same:
index-api.php:
<?php
define('WP_USE_THEMES', true);
/** Loads the WordPress Environment and Template */
require('./wordpress/wp-blog-header.php');
// phpInfo();
.htaccess:
<ifModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^api/(.*)$ index-api.php [L]
RewriteRule (.*)$ site/dist/index.html [L]
</ifModule>
I tried a myriad of other efforts from a few posts trying to get this working, and it seems to me like it should work fine. The funny thing is, if I comment out the last line RewriteRule (.*)$ site/dist/index.html [L] the api request works normally as expected, so I know I'm close.
Any suggestions?
Would appreciate anyone's help on this, it's been really confusing!
In the first place you'll need to make sure that requests made to /index-api.php are not matched and rewritten by the second rule. In the second rule you can use $1. $1 will be replaced with whatever was matched in the first capture group. We'll also need to make sure that the second rule will not match what it rewrites, or we'll end up with an infinite loop and an internal error.
You can use the $1 in the first rule too, as I show below:
RewriteRule ^api/(.*)$ index-api.php?url=$1 [L]
RewriteCond %{REQUEST_URI} !^/site/dist/
RewriteCond %{REQUEST_URI} !^/index-api\.php
RewriteRule (.*)$ site/dist/$1 [L]
I recommend reading the documentation of mod_rewrite to get a better understanding how you can use it and what things you have at your disposal while rewriting url's.

mod_rewrite to direct site.com/something to index.php?values=something

(I might be an idiot, it appears that .htaccess isn't enabled by default in Apache on OSX.)
I know there are a lot of mod_rewrite questions out there, but I just can't get mine right and nothing else seems to quite cover it.
All I want to do is redirect
www.url.com/something
or
www.url.com/something/anything/more
to
www.url.com/index.php?values=something
or
www.url.com/index.php?values=something/anything/more
Nothing fancier than that (I'll put in something about ignoring gif/jpg/png, adding www. etc later later) - all processing of something/anything/more will be done in PHP.
I just can't get it right though. Any hints/resources or anyone who's just managed to do this? It's more frustrating knowing that I once got it absolutely perfect but lost that code years ago.
This is pretty straightforward, at least in what you are asking But basically you need to make index.php passthrough (so you don't rewrite index.php to index.php), then the main rewrite.
RewriteEngine On
RewriteRule index.php - [L]
# your conditions here
RewriteRule ^/?(.*)$ /index.php?values=$1 [L]
Add whatever conditions you want to exclude rewrite at the # your conditions here spot
RewriteEngineOn
RewriteCond %{REQUEST_URI} !-f
RewriteCond %{REQUEST_URI} !-d
RewriteRule ^(.*)$ /index.php?values=$1 [L]
Please note that you need to have AllowOverride On set in the Apache host config file for the directory in question if you are trying to do this in an .htaccess file and of course need to have mod_rewrite module enabled.
This rule will ignore the redirect for any actual files or directories (i.e. images) that actually exist (including index.php).

Using $_POST data after wordpress url rewrite

My permalink structure is set so I have url.com/page
I made a basic PHP script prior to installing wordpress that uses $_POST data to display the correct set of information, so the base would look like url.com/work.php?featured=print
After adding this to my Wordpress installation with the rewrite from the permalink structure above, the link actually works as:
url.com/work/?featured=print
I'm having trouble getting the extra rewrite to work so that a clean url.com/work/print will work properly.
This is what my .htaccess file looks like, I appended the last line before the end IfModule tag hoping that would take anything work/[page]/ and direct it to work/?featured=[page]
# BEGIN WordPress
<IfModule mod_rewrite.c>
RewriteEngine On
RewriteBase /
RewriteRule ^index\.php$ - [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule . /index.php
RewriteRule ^work/([^/.]+)/?$ work/?featured=$1 [L]
</IfModule>
# END WordPress
any help?
EDIT
Discovered rewrite via the functions page and found this quite resourceful
Rewrite rules for WordPress
however, my rule is taking .com/work/print (work/?feat=print) and simply showing it as .com/work without the page data being passed through
'work/([^/]+)/?$' => 'work&feat=$matches[1]'
The above is the only thing I changed from post I just referenced. I tried keeping is specific to get it to work first to avoid any loose ends...
Still not working properly though
The wp-admin dashboard has a tool that helps with the rewrites. When I ran a few WP sites, I used it to achieve what I wanted. Did you try that first?
http://www.rlmseo.com/blog/passing-get-query-string-parameters-in-wordpress-url/
For some reason, couldn't get anything to work, but ^ is quite simple and worked great

htaccess rewrite ".../pages/about.php" to ".../about"

I've searched and found a lot of questions on this site and elsewhere that are very similar, but I've tried implementing and modifying all the suggestions I've found and none of it works. I realize this is a very basic question an I am extremely frustrated because nothing I'm trying is working.
With that having been said... I am trying to organize my content pages within kurtiskronk.com/pages/... (e.g. kurtiskronk.com/pages/about.php)
What I want to do is make it so that I can simply link to kurtiskronk.com/about ... So how do I go about stripping "pages/" and ".php"? I don't have a ton of content pages, so it's not a big deal if I have to specify for each page, though something dynamic would be handy.
NOTES: I am using Rackspace Cloud hosting, and WordPress is installed in /blog. My phpinfo() can be seen at http://kurtiskronk.com/pages/phpinfo.php
This is my existing .htaccess file (in the root)
php_value register_globals "on"
Options +FollowSymLinks
RewriteEngine On
#301 redirect to domain without 'www.'
RewriteCond %{HTTP_HOST} ^www\.kurtiskronk\.com$ [NC]
RewriteRule ^(.*)$ http://kurtiskronk.com/$1 [R=301,NC]
RewriteBase /
RewriteCond %{ENV:PHP_DOCUMENT_ROOT}/pages/$1 -f
RewriteRule ^(.*)$ pages/$1 [L]
RewriteCond %{ENV:PHP_DOCUMENT_ROOT}/pages/$1.php -f
RewriteRule ^(.*)$ pages/$1.php [L]
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/ blog/index.php [L]
# PHP - MAIL
php_value mail.force_extra_parameters -kurtis#kurtiskronk.com
I tested and the rewrite works with the line below (/about as URL brings up file /pages/about.php), but then the homepage gives a 500 Internal Server Error:
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /pages/$1.php [L]
So I'm still sort of in the same boat as before, and as a follow-up, possibly more difficult question, if you go to http://kurtiskronk.com/weddings I am using SlideShowPro (flash) w/ SSP Director (self-hosted) as the back-end for it. When it pulls up a new image, it adds the following after /weddings ... "#id=album-152&num=content-9698"
There are four sections of the portfolio
# Homepage (kurtiskronk.com) id=album-148 ($id is constant for this section)
# Weddings (/weddings) id=album-152 ($id is constant for this section)
# Portraits (/portraits) id=album-151 ($id is constant for this section)
# Commercial (/commercial) id=album-150 ($id is constant for this section)
Assuming we get kurtiskronk.com/weddings to rewrite successfully without breaking anything, how would we make the total URL something cleaner kurtiskronk.com/weddings/9698 since the $num is the only thing that will change within a given section?
Kurtis, thanks for the extra information. It's a lot easier to give a specific answer to this.
My first comment is that you need to separate out in your thinking URI space -- that is what URIs you want your users to type into their browser -- and filesystem space -- what physical files you want to map to. Some of your mappings are URI->URI and some are URI->FS
For example you want to issue a permanent redirect of www.kurtiskronk.com/* to kurtiskronk.com/*. Assuming that you only server the base and www subdomains from this tree, then this cond/rule pair should come first, so that you can assume that all other rules only refer to kurtiskronk.com.
Next, you need to review the RewiteBase documentation. .htaccess files are processed in what Apache calls a Per-Directory context and this directive tells the rewrite engine what to assume as the URI base which got to this directory and .htaccess file. From what I gather, your blog is installed in docroot/blog (in the filesystem, and that you want to get to directory by typing in http://kurtiskronk.com/blog/ but that this .htaccess file is for the root folder -- that is the base should be (this goes before the www mapping rule)
DirectorySlash On
DirectoryIndex index.php
RewriteBase /
#301 redirect to domain without 'www.'
RewriteCond %{HTTP_HOST} ^www\.kurtiskronk\.com$ [NC]
RewriteRule ^(.*)$ http://kurtiskronk.com/$1 [R=301,NC]
You can add some field dumps look for REDIRECT_* in the Server or Environment table in the phpinfo O/P to see if these are sensible. For example:
RewriteWrite ^(.*)$ - \
[E=TESTDR:%{DOCUMENT_ROOT}/pages/$1.php,E=TESTPDR:%{DOCUMENT_ROOT}/pages/$1.php]
Your next rule is that if the file exists in the subdirectory pages then use it:
RewriteCond %{DOCUMENT_ROOT}/pages/$1 -f
RewriteRule ^(.*)$ pages/$1 [NS,L]
[Note that some shared service sites don't set up DOCUMENT_ROOT properly for the rewrite engine so you may need to run a variableinfo script (<?php phpinfo(INFO_ENVIRONMENT | INFO_VARIABLES); to see if it sets up alternatives. On your site you have to use %{ENV:PHP_DOCUMENT_ROOT} instead.]
Your next rule is that if the file exists, but with the extension .php in the subdirectory pages then use it:
RewriteCond %{DOCUMENT_ROOT}/pages/$1.php -f
RewriteRule ^(.*)$ pages/$1.php [NS,L]
Now redirect any blog references to the blog subdirectory unless the URI maps to a real file (e.g. the blog stylesheets and your uploads.)
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^blog/ blog/index.php [L]
A complication here is that WP may be using a poorly documented Apache feature call Path Info that is a script can act as a pseudo directory so http://kurtiskronk.com/blog/tag/downtown/ is redirected to docroot/blog/index.php/tag/downtown/ which is then executed by `docroot/blog/index.php using /tag/downtown/ as the PATH_INFO. But this is one for Wordpress experts to comment on. If this last rule doesn't work then try:
RewriteRule ^blog/(.*) blog/index.php/$1 [L]
PS. I like your site. I wish I was that young again :(
Postscript
When you say "it doesn't work", what doesn't with this .htaccess?
http://kurtiskronk.com/phpinfo,
http://kurtiskronk.com/phpinfo.php,
http://kurtiskronk.comblog/tag/downtown/
It's just that these rules work for these tests (with domain swapped) on mine. (One way is to move or copy the above variableinfo.php to the various subdirectories. If necessary temporarily rename the index.php to index.php.keep, say, and copy the variableinfo.php to the index.php file. You can now enter the various URI test patterns and see what is happening. Look for the REDIRECT_* fields in the phpinfo output, and the SCRIPT_NAME will tell you which is being executed. You can add more {E=...] flags to examine the various pattern results. (Remember that these only get assigned if the rule is a match.
Lastly note the changes above especially the additional NS flags. For some reason mod_rewrite was going directly into a subquery which was resulting in redirect: being dumped into the file pattern. I've had a look at the Apache code and this is a internal botch to flag that further redirection needs to take place (which then replaces this or backs out). However this open bug indicates that this backout can be missed in sub-queries and maybe that's what is happening here. Certainly adding the NS flas cured the problem on my test environment.
PS. Note the added explicit DirectoryIndex directive and also that whilst http://kurtiskronk.com will run the root index.php, the explicit /index.php version will run the one in pages, because that's what your rules say.
Here is a simple solution. You can use it apache conf file(s) or in .htaccess (easier to set up when you're trying).
mod_rewrite has to be enabled.
For example, use .htaccess in your DocumentRoot with:
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteRule ^(.*)$ /pages/$1.php [L]
It will redirect /about to /pages/about.php, and any other page.
The "RewriteCond" part is to authorize access to an existing file (eg: if you had an "about" file at the root of your site, then it will be served, instead of redirecting to /pages/about.php).
Options +FollowSymLinks
RewriteEngine On
RewriteRule /([0-9]+)$ /pages/$1.php [L]
Put something like this in your .htaccess file. I guess that is what you want.
Juest a redirect from a simple url to a longer url.

Categories