├── .editorconfig
├── .travis.yml
├── LICENSE.md
├── README.md
├── composer.json
├── h5bp-htaccess.conf
├── ruleset.xml
└── wp-h5bp-htaccess.php
/.editorconfig:
--------------------------------------------------------------------------------
1 | # editorconfig.org
2 |
3 | root = true
4 |
5 | [*]
6 | indent_style = space
7 | indent_size = 2
8 | end_of_line = lf
9 | charset = utf-8
10 | trim_trailing_whitespace = true
11 | insert_final_newline = true
12 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | sudo: false
2 | language: php
3 | php:
4 | - nightly
5 | - 5.6
6 | - 5.5
7 | - 5.4
8 | - hhvm
9 |
10 | matrix:
11 | allow_failures:
12 | - php: nightly
13 |
14 | install:
15 | - composer self-update && composer --version
16 | - export PATH="$HOME/.composer/vendor/bin:$PATH"
17 | - composer global require squizlabs/php_codesniffer
18 |
19 | script:
20 | - phpcs --standard=ruleset.xml --extensions=php -n -s .
21 |
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | Copyright (c) Roots
2 |
3 | Permission is hereby granted, free of charge, to any person obtaining a copy of
4 | this software and associated documentation files (the "Software"), to deal in
5 | the Software without restriction, including without limitation the rights to
6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
7 | of the Software, and to permit persons to whom the Software is furnished to do
8 | so, subject to the following conditions:
9 |
10 | The above copyright notice and this permission notice shall be included in all
11 | copies or substantial portions of the Software.
12 |
13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
19 | SOFTWARE.
20 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # HTML5 Boilerplate's `.htaccess` for WordPress
2 | [](https://travis-ci.org/roots/wp-h5bp-htaccess)
3 |
4 | Add [HTML5 Boilerplate's `.htaccess`](https://github.com/h5bp/server-configs-apache) to your WordPress installation.
5 |
6 | ## Installation
7 |
8 | You can install this plugin via the command-line or the WordPress admin panel.
9 |
10 | ### via Command-line
11 |
12 | If you're [using Composer to manage WordPress](https://roots.io/using-composer-with-wordpress/), add wp-h5bp-htaccess to your project's dependencies.
13 |
14 | ```sh
15 | composer require roots/wp-h5bp-htaccess 2.0.1
16 | ```
17 |
18 | Then activate the plugin via [wp-cli](http://wp-cli.org/commands/plugin/activate/).
19 |
20 | ```sh
21 | wp plugin activate wp-h5bp-htaccess
22 | ```
23 |
24 | ### via WordPress Admin Panel
25 |
26 | 1. Download the [latest zip](https://github.com/roots/wp-h5bp-htaccess/archive/master.zip) of this repo.
27 | 2. In your WordPress admin panel, navigate to Plugins->Add New
28 | 3. Click Upload Plugin
29 | 4. Upload the zip file that you downloaded.
30 |
31 | ## Configuration
32 |
33 | The plugin will work right out of the box, but we have made some options available to developers who wish to fine-tune the resulting `.htaccess` file.
34 |
35 | ### !!! WARNING !!!
36 |
37 | Using these configuration options can result in unexpected, undesired, and even damaging behaviors. You must understand that changing the output of this plugin will change what WordPress puts into your `.htaccess` file. Misconfigured `.htaccess` files will likely result server errors. Be sure that you have a way of removing the `.htaccess` file if necessary.
38 |
39 | ### Use a custom server config (`server_configs.conf`)
40 |
41 | You can use your own server config instead of the included Apache Server Config by H5BP. Do this by placing a file named `server_configs.conf` in the root of your theme directory.
42 |
43 | ```
44 | /
45 | ├── wp-admin/
46 | ├── wp-content/
47 | │ └── themes/
48 | │ └── your-theme-here/
49 | │ └── server_configs.conf
50 | └── wp-includes/
51 | ```
52 |
53 | ### Hooks
54 |
55 | There are a few WordPress filters into which a developer can hook to modify the resulting `.htaccess` file. The rules below are listed in the order in which they are applied in the code.
56 |
57 | #### `roots/h5bp-htaccess-filters`
58 |
59 | This hook passes an associative array of modification filters to be applied to the rules where the keys of the array represent a string that is to be searched and the values of the array represent a replacement.
60 |
61 | Use this for simple string replacements, such as commenting out lines.
62 |
63 | ```php
64 | add_filter('roots/h5bp-htaccess-filters', function($rules_filters) {
65 | // comments out all `RewriteRule`s
66 | $rules_filters['RewriteRule'] = '# RewriteRule';
67 | return $rules_filters;
68 | });
69 | ```
70 |
71 | #### `roots/h5bp-htaccess-rules`
72 |
73 | This hook passes a string containing all of the rules that are going to be added to your `.htaccess` file by this plugin.
74 |
75 | ```php
76 | add_filter('roots/h5bp-htaccess-rules', function($server_config_rules) {
77 | // Removes all comments and whitespace
78 | return preg_replace(['/#.*/', '/(^[\r\n]*|[\r\n]+)[\s\t]*[\r\n]+/'], ['',PHP_EOL], $server_config_rules);
79 | });
80 | ```
81 |
82 | ## Changelog
83 |
84 | ### 2.0.1: April 29th, 2015
85 | * Fix reference error ([#12](https://github.com/roots/wp-h5bp-htaccess/issues/12))
86 | * Update link to h5bp server config repo ([#13](https://github.com/roots/wp-h5bp-htaccess/issues/13))
87 |
88 | ### 2.0.0: April 11th, 2015
89 | * Update to Apache Server Configs v2.14.0
90 | * Rewrote plugin as a class
91 | * Rewrote logic so that server and WordPress configurations are only checked when plugin is actively in use
92 | * Added filters to provide users with more control over the rules that are being applied
93 | * Added a dedicated WordPress section to the bottom of h5bp-htaccess
94 |
95 | ### 1.1.0: June 7th, 2014
96 | * Update to Apache Server Configs v2.4.1
97 |
98 | ### 1.0.0: April 30th, 2013
99 | * Removed from [Roots Theme](http://www.rootstheme.com/), moved to plugin
100 |
101 | ## License
102 |
103 | * [Apache Server Configs](https://github.com/h5bp/server-configs-apache): MIT License
104 | * Everything else: MIT License
105 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "roots/wp-h5bp-htaccess",
3 | "type": "wordpress-plugin",
4 | "license": "MIT",
5 | "description": "HTML5 Boilerplate's .htaccess for WordPress",
6 | "homepage": "http://roots.io/plugins/html5-boilerplate-htaccess/",
7 | "authors": [
8 | {
9 | "name": "Ben Word",
10 | "email": "ben@benword.com",
11 | "homepage": "https://github.com/retlehs"
12 | },
13 | {
14 | "name": "Scott Walkinshaw",
15 | "email": "scott.walkinshaw@gmail.com",
16 | "homepage": "https://github.com/swalkinshaw"
17 | }
18 | ],
19 | "keywords": [
20 | "wordpress"
21 | ],
22 | "support": {
23 | "issues": "https://github.com/roots/wp-h5bp-htaccess/issues",
24 | "forum": "https://discourse.roots.io/"
25 | },
26 | "require": {
27 | "php": ">=5.4.0",
28 | "composer/installers": "^1.4"
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/h5bp-htaccess.conf:
--------------------------------------------------------------------------------
1 | # Apache Server Configs v2.14.0 | MIT License
2 | # https://github.com/h5bp/server-configs-apache
3 |
4 | # (!) Using `.htaccess` files slows down Apache, therefore, if you have
5 | # access to the main server configuration file (which is usually called
6 | # `httpd.conf`), you should add this logic there.
7 | #
8 | # https://httpd.apache.org/docs/current/howto/htaccess.html.
9 |
10 | # ######################################################################
11 | # # CROSS-ORIGIN #
12 | # ######################################################################
13 |
14 | # ----------------------------------------------------------------------
15 | # | Cross-origin requests |
16 | # ----------------------------------------------------------------------
17 |
18 | # Allow cross-origin requests.
19 | #
20 | # https://developer.mozilla.org/en-US/docs/Web/HTTP/Access_control_CORS
21 | # http://enable-cors.org/
22 | # http://www.w3.org/TR/cors/
23 |
24 | #
25 | # Header set Access-Control-Allow-Origin "*"
26 | #
27 |
28 | # ----------------------------------------------------------------------
29 | # | Cross-origin images |
30 | # ----------------------------------------------------------------------
31 |
32 | # Send the CORS header for images when browsers request it.
33 | #
34 | # https://developer.mozilla.org/en-US/docs/Web/HTML/CORS_enabled_image
35 | # https://blog.chromium.org/2011/07/using-cross-domain-images-in-webgl-and.html
36 |
37 |
38 |
39 |
40 | SetEnvIf Origin ":" IS_CORS
41 | Header set Access-Control-Allow-Origin "*" env=IS_CORS
42 |
43 |
44 |
45 |
46 | # ----------------------------------------------------------------------
47 | # | Cross-origin web fonts |
48 | # ----------------------------------------------------------------------
49 |
50 | # Allow cross-origin access to web fonts.
51 |
52 |
53 |
54 | Header set Access-Control-Allow-Origin "*"
55 |
56 |
57 |
58 | # ----------------------------------------------------------------------
59 | # | Cross-origin resource timing |
60 | # ----------------------------------------------------------------------
61 |
62 | # Allow cross-origin access to the timing information for all resources.
63 | #
64 | # If a resource isn't served with a `Timing-Allow-Origin` header that
65 | # would allow its timing information to be shared with the document,
66 | # some of the attributes of the `PerformanceResourceTiming` object will
67 | # be set to zero.
68 | #
69 | # http://www.w3.org/TR/resource-timing/
70 | # http://www.stevesouders.com/blog/2014/08/21/resource-timing-practical-tips/
71 |
72 | #
73 | # Header set Timing-Allow-Origin: "*"
74 | #
75 |
76 |
77 | # ######################################################################
78 | # # ERRORS #
79 | # ######################################################################
80 |
81 | # ----------------------------------------------------------------------
82 | # | Custom error messages/pages |
83 | # ----------------------------------------------------------------------
84 |
85 | # Customize what Apache returns to the client in case of an error.
86 | # https://httpd.apache.org/docs/current/mod/core.html#errordocument
87 |
88 | # ErrorDocument 404 /404.html
89 |
90 | # ----------------------------------------------------------------------
91 | # | Error prevention |
92 | # ----------------------------------------------------------------------
93 |
94 | # Disable the pattern matching based on filenames.
95 | #
96 | # This setting prevents Apache from returning a 404 error as the result
97 | # of a rewrite when the directory with the same name does not exist.
98 | #
99 | # https://httpd.apache.org/docs/current/content-negotiation.html#multiviews
100 |
101 | # Options -MultiViews
102 |
103 |
104 | # ######################################################################
105 | # # INTERNET EXPLORER #
106 | # ######################################################################
107 |
108 | # ----------------------------------------------------------------------
109 | # | Document modes |
110 | # ----------------------------------------------------------------------
111 |
112 | # Force Internet Explorer 8/9/10 to render pages in the highest mode
113 | # available in the various cases when it may not.
114 | #
115 | # https://hsivonen.fi/doctype/#ie8
116 | #
117 | # (!) Starting with Internet Explorer 11, document modes are deprecated.
118 | # If your business still relies on older web apps and services that were
119 | # designed for older versions of Internet Explorer, you might want to
120 | # consider enabling `Enterprise Mode` throughout your company.
121 | #
122 | # https://msdn.microsoft.com/en-us/library/ie/bg182625.aspx#docmode
123 | # http://blogs.msdn.com/b/ie/archive/2014/04/02/stay-up-to-date-with-enterprise-mode-for-internet-explorer-11.aspx
124 |
125 |
126 |
127 | Header set X-UA-Compatible "IE=edge"
128 |
129 | # `mod_headers` cannot match based on the content-type, however,
130 | # the `X-UA-Compatible` response header should be send only for
131 | # HTML documents and not for the other resources.
132 |
133 |
134 | Header unset X-UA-Compatible
135 |
136 |
137 |
138 |
139 | # ----------------------------------------------------------------------
140 | # | Iframes cookies |
141 | # ----------------------------------------------------------------------
142 |
143 | # Allow cookies to be set from iframes in Internet Explorer.
144 | #
145 | # https://msdn.microsoft.com/en-us/library/ms537343.aspx
146 | # http://www.w3.org/TR/2000/CR-P3P-20001215/
147 |
148 | #
149 | # Header set P3P "policyref=\"/w3c/p3p.xml\", CP=\"IDC DSP COR ADM DEVi TAIi PSA PSD IVAi IVDi CONi HIS OUR IND CNT\""
150 | #
151 |
152 |
153 | # ######################################################################
154 | # # MEDIA TYPES AND CHARACTER ENCODINGS #
155 | # ######################################################################
156 |
157 | # ----------------------------------------------------------------------
158 | # | Media types |
159 | # ----------------------------------------------------------------------
160 |
161 | # Serve resources with the proper media types (f.k.a. MIME types).
162 | #
163 | # https://www.iana.org/assignments/media-types/media-types.xhtml
164 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addtype
165 |
166 |
167 |
168 | # Data interchange
169 |
170 | AddType application/atom+xml atom
171 | AddType application/json json map topojson
172 | AddType application/ld+json jsonld
173 | AddType application/rss+xml rss
174 | AddType application/vnd.geo+json geojson
175 | AddType application/xml rdf xml
176 |
177 |
178 | # JavaScript
179 |
180 | # Normalize to standard type.
181 | # https://tools.ietf.org/html/rfc4329#section-7.2
182 |
183 | AddType application/javascript js
184 |
185 |
186 | # Manifest files
187 |
188 | AddType application/manifest+json webmanifest
189 | AddType application/x-web-app-manifest+json webapp
190 | AddType text/cache-manifest appcache
191 |
192 |
193 | # Media files
194 |
195 | AddType audio/mp4 f4a f4b m4a
196 | AddType audio/ogg oga ogg opus
197 | AddType image/bmp bmp
198 | AddType image/svg+xml svg svgz
199 | AddType image/webp webp
200 | AddType video/mp4 f4v f4p m4v mp4
201 | AddType video/ogg ogv
202 | AddType video/webm webm
203 | AddType video/x-flv flv
204 |
205 | # Serving `.ico` image files with a different media type
206 | # prevents Internet Explorer from displaying then as images:
207 | # https://github.com/h5bp/html5-boilerplate/commit/37b5fec090d00f38de64b591bcddcb205aadf8ee
208 |
209 | AddType image/x-icon cur ico
210 |
211 |
212 | # Web fonts
213 |
214 | AddType application/font-woff woff
215 | AddType application/font-woff2 woff2
216 | AddType application/vnd.ms-fontobject eot
217 |
218 | # Browsers usually ignore the font media types and simply sniff
219 | # the bytes to figure out the font type.
220 | # https://mimesniff.spec.whatwg.org/#matching-a-font-type-pattern
221 | #
222 | # However, Blink and WebKit based browsers will show a warning
223 | # in the console if the following font types are served with any
224 | # other media types.
225 |
226 | AddType application/x-font-ttf ttc ttf
227 | AddType font/opentype otf
228 |
229 |
230 | # Other
231 |
232 | AddType application/octet-stream safariextz
233 | AddType application/x-bb-appworld bbaw
234 | AddType application/x-chrome-extension crx
235 | AddType application/x-opera-extension oex
236 | AddType application/x-xpinstall xpi
237 | AddType text/vcard vcard vcf
238 | AddType text/vnd.rim.location.xloc xloc
239 | AddType text/vtt vtt
240 | AddType text/x-component htc
241 |
242 |
243 |
244 | # ----------------------------------------------------------------------
245 | # | Character encodings |
246 | # ----------------------------------------------------------------------
247 |
248 | # Serve all resources labeled as `text/html` or `text/plain`
249 | # with the media type `charset` parameter set to `UTF-8`.
250 | #
251 | # https://httpd.apache.org/docs/current/mod/core.html#adddefaultcharset
252 |
253 | AddDefaultCharset utf-8
254 |
255 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
256 |
257 | # Serve the following file types with the media type `charset`
258 | # parameter set to `UTF-8`.
259 | #
260 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addcharset
261 |
262 |
263 | AddCharset utf-8 .atom \
264 | .bbaw \
265 | .css \
266 | .geojson \
267 | .js \
268 | .json \
269 | .jsonld \
270 | .manifest \
271 | .rdf \
272 | .rss \
273 | .topojson \
274 | .vtt \
275 | .webapp \
276 | .webmanifest \
277 | .xloc \
278 | .xml
279 |
280 |
281 |
282 | # ######################################################################
283 | # # REWRITES #
284 | # ######################################################################
285 |
286 | # ----------------------------------------------------------------------
287 | # | Rewrite engine |
288 | # ----------------------------------------------------------------------
289 |
290 | # (1) Turn on the rewrite engine (this is necessary in order for
291 | # the `RewriteRule` directives to work).
292 | #
293 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#RewriteEngine
294 | #
295 | # (2) Enable the `FollowSymLinks` option if it isn't already.
296 | #
297 | # https://httpd.apache.org/docs/current/mod/core.html#options
298 | #
299 | # (3) If your web host doesn't allow the `FollowSymlinks` option,
300 | # you need to comment it out or remove it, and then uncomment
301 | # the `Options +SymLinksIfOwnerMatch` line (4), but be aware
302 | # of the performance impact.
303 | #
304 | # https://httpd.apache.org/docs/current/misc/perf-tuning.html#symlinks
305 | #
306 | # (4) Some cloud hosting services will require you set `RewriteBase`.
307 | #
308 | # https://www.rackspace.com/knowledge_center/frequently-asked-question/why-is-modrewrite-not-working-on-my-site
309 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
310 | #
311 | # (5) Depending on how your server is set up, you may also need to
312 | # use the `RewriteOptions` directive to enable some options for
313 | # the rewrite engine.
314 | #
315 | # https://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewriteoptions
316 | #
317 | # (6) Set %{ENV:PROTO} variable, to allow rewrites to redirect with the
318 | # appropriate schema automatically (http or https).
319 |
320 |
321 |
322 | # (1)
323 | RewriteEngine On
324 |
325 | # (2)
326 | Options +FollowSymlinks
327 |
328 | # (3)
329 | # Options +SymLinksIfOwnerMatch
330 |
331 | # (4)
332 | # RewriteBase /
333 |
334 | # (5)
335 | # RewriteOptions
336 |
337 | # (6)
338 | RewriteCond %{HTTPS} =on
339 | RewriteRule ^ - [env=proto:https]
340 | RewriteCond %{HTTPS} !=on
341 | RewriteRule ^ - [env=proto:http]
342 |
343 |
344 |
345 | # ----------------------------------------------------------------------
346 | # | Forcing `https://` |
347 | # ----------------------------------------------------------------------
348 |
349 | # Redirect from the `http://` to the `https://` version of the URL.
350 | # https://wiki.apache.org/httpd/RewriteHTTPToHTTPS
351 |
352 | #
353 | # RewriteEngine On
354 | # RewriteCond %{HTTPS} !=on
355 | # RewriteRule ^(.*)$ https://%{HTTP_HOST}/$1 [R=301,L]
356 | #
357 |
358 | # ----------------------------------------------------------------------
359 | # | Suppressing / Forcing the `www.` at the beginning of URLs |
360 | # ----------------------------------------------------------------------
361 |
362 | # The same content should never be available under two different
363 | # URLs, especially not with and without `www.` at the beginning.
364 | # This can cause SEO problems (duplicate content), and therefore,
365 | # you should choose one of the alternatives and redirect the other
366 | # one.
367 | #
368 | # By default `Option 1` (no `www.`) is activated.
369 | # http://no-www.org/faq.php?q=class_b
370 | #
371 | # If you would prefer to use `Option 2`, just comment out all the
372 | # lines from `Option 1` and uncomment the ones from `Option 2`.
373 | #
374 | # (!) NEVER USE BOTH RULES AT THE SAME TIME!
375 |
376 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
377 |
378 | # Option 1: rewrite www.example.com → example.com
379 |
380 |
381 | RewriteEngine On
382 | RewriteCond %{HTTPS} !=on
383 | RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
384 | RewriteRule ^ %{ENV:PROTO}://%1%{REQUEST_URI} [R=301,L]
385 |
386 |
387 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
388 |
389 | # Option 2: rewrite example.com → www.example.com
390 | #
391 | # Be aware that the following might not be a good idea if you use "real"
392 | # subdomains for certain parts of your website.
393 |
394 | #
395 | # RewriteEngine On
396 | # RewriteCond %{HTTPS} !=on
397 | # RewriteCond %{HTTP_HOST} !^www\. [NC]
398 | # RewriteCond %{SERVER_ADDR} !=127.0.0.1
399 | # RewriteCond %{SERVER_ADDR} !=::1
400 | # RewriteRule ^ %{ENV:PROTO}://www.%{HTTP_HOST}%{REQUEST_URI} [R=301,L]
401 | #
402 |
403 |
404 | # ######################################################################
405 | # # SECURITY #
406 | # ######################################################################
407 |
408 | # ----------------------------------------------------------------------
409 | # | Clickjacking |
410 | # ----------------------------------------------------------------------
411 |
412 | # Protect website against clickjacking.
413 | #
414 | # The example below sends the `X-Frame-Options` response header with
415 | # the value `DENY`, informing browsers not to display the content of
416 | # the web page in any frame.
417 | #
418 | # This might not be the best setting for everyone. You should read
419 | # about the other two possible values the `X-Frame-Options` header
420 | # field can have: `SAMEORIGIN` and `ALLOW-FROM`.
421 | # https://tools.ietf.org/html/rfc7034#section-2.1.
422 | #
423 | # Keep in mind that while you could send the `X-Frame-Options` header
424 | # for all of your website’s pages, this has the potential downside that
425 | # it forbids even non-malicious framing of your content (e.g.: when
426 | # users visit your website using a Google Image Search results page).
427 | #
428 | # Nonetheless, you should ensure that you send the `X-Frame-Options`
429 | # header for all pages that allow a user to make a state changing
430 | # operation (e.g: pages that contain one-click purchase links, checkout
431 | # or bank-transfer confirmation pages, pages that make permanent
432 | # configuration changes, etc.).
433 | #
434 | # Sending the `X-Frame-Options` header can also protect your website
435 | # against more than just clickjacking attacks:
436 | # https://cure53.de/xfo-clickjacking.pdf.
437 | #
438 | # https://tools.ietf.org/html/rfc7034
439 | # http://blogs.msdn.com/b/ieinternals/archive/2010/03/30/combating-clickjacking-with-x-frame-options.aspx
440 | # https://www.owasp.org/index.php/Clickjacking
441 |
442 | #
443 |
444 | # Header set X-Frame-Options "DENY"
445 |
446 | # # `mod_headers` cannot match based on the content-type, however,
447 | # # the `X-Frame-Options` response header should be send only for
448 | # # HTML documents and not for the other resources.
449 |
450 | #
451 | # Header unset X-Frame-Options
452 | #
453 |
454 | #
455 |
456 | # ----------------------------------------------------------------------
457 | # | Content Security Policy (CSP) |
458 | # ----------------------------------------------------------------------
459 |
460 | # Mitigate the risk of cross-site scripting and other content-injection
461 | # attacks.
462 | #
463 | # This can be done by setting a `Content Security Policy` which
464 | # whitelists trusted sources of content for your website.
465 | #
466 | # The example header below allows ONLY scripts that are loaded from
467 | # the current website's origin (no inline scripts, no CDN, etc).
468 | # That almost certainly won't work as-is for your website!
469 | #
470 | # To make things easier, you can use an online CSP header generator
471 | # such as: http://cspisawesome.com/.
472 | #
473 | # http://content-security-policy.com/
474 | # http://www.html5rocks.com/en/tutorials/security/content-security-policy/
475 | # http://www.w3.org/TR/CSP11/).
476 |
477 | #
478 |
479 | # Header set Content-Security-Policy "script-src 'self'; object-src 'self'"
480 |
481 | # # `mod_headers` cannot match based on the content-type, however,
482 | # # the `Content-Security-Policy` response header should be send
483 | # # only for HTML documents and not for the other resources.
484 |
485 | #
486 | # Header unset Content-Security-Policy
487 | #
488 |
489 | #
490 |
491 | # ----------------------------------------------------------------------
492 | # | File access |
493 | # ----------------------------------------------------------------------
494 |
495 | # Block access to directories without a default document.
496 | #
497 | # You should leave the following uncommented, as you shouldn't allow
498 | # anyone to surf through every directory on your server (which may
499 | # includes rather private places such as the CMS's directories).
500 |
501 |
502 | Options -Indexes
503 |
504 |
505 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
506 |
507 | # Block access to all hidden files and directories with the exception of
508 | # the visible content from within the `/.well-known/` hidden directory.
509 | #
510 | # These types of files usually contain user preferences or the preserved
511 | # state of an utility, and can include rather private places like, for
512 | # example, the `.git` or `.svn` directories.
513 | #
514 | # The `/.well-known/` directory represents the standard (RFC 5785) path
515 | # prefix for "well-known locations" (e.g.: `/.well-known/manifest.json`,
516 | # `/.well-known/keybase.txt`), and therefore, access to its visible
517 | # content should not be blocked.
518 | #
519 | # https://www.mnot.net/blog/2010/04/07/well-known
520 | # https://tools.ietf.org/html/rfc5785
521 |
522 |
523 | RewriteEngine On
524 | RewriteCond %{REQUEST_URI} "!(^|/)\.well-known/([^./]+./?)+$" [NC]
525 | RewriteCond %{SCRIPT_FILENAME} -d [OR]
526 | RewriteCond %{SCRIPT_FILENAME} -f
527 | RewriteRule "(^|/)\." - [F]
528 |
529 |
530 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
531 |
532 | # Block access to files that can expose sensitive information.
533 | #
534 | # By default, block access to backup and source files that may be
535 | # left by some text editors and can pose a security risk when anyone
536 | # has access to them.
537 | #
538 | # http://feross.org/cmsploit/
539 | #
540 | # (!) Update the `` regular expression from below to
541 | # include any files that might end up on your production server and
542 | # can expose sensitive information about your website. These files may
543 | # include: configuration files, files that contain metadata about the
544 | # project (e.g.: project dependencies), build scripts, etc..
545 |
546 |
547 |
548 | # Apache < 2.3
549 |
550 | Order allow,deny
551 | Deny from all
552 | Satisfy All
553 |
554 |
555 | # Apache ≥ 2.3
556 |
557 | Require all denied
558 |
559 |
560 |
561 |
562 | # ----------------------------------------------------------------------
563 | # | HTTP Strict Transport Security (HSTS) |
564 | # ----------------------------------------------------------------------
565 |
566 | # Force client-side SSL redirection.
567 | #
568 | # If a user types `example.com` in their browser, even if the server
569 | # redirects them to the secure version of the website, that still leaves
570 | # a window of opportunity (the initial HTTP connection) for an attacker
571 | # to downgrade or redirect the request.
572 | #
573 | # The following header ensures that browser will ONLY connect to your
574 | # server via HTTPS, regardless of what the users type in the browser's
575 | # address bar.
576 | #
577 | # (!) Remove the `includeSubDomains` optional directive if the website's
578 | # subdomains are not using HTTPS.
579 | #
580 | # http://www.html5rocks.com/en/tutorials/security/transport-layer-security/
581 | # https://tools.ietf.org/html/draft-ietf-websec-strict-transport-sec-14#section-6.1
582 | # http://blogs.msdn.com/b/ieinternals/archive/2014/08/18/hsts-strict-transport-security-attacks-mitigations-deployment-https.aspx
583 |
584 | #
585 | # Header always set Strict-Transport-Security "max-age=16070400; includeSubDomains"
586 | #
587 |
588 | # ----------------------------------------------------------------------
589 | # | Reducing MIME type security risks |
590 | # ----------------------------------------------------------------------
591 |
592 | # Prevent some browsers from MIME-sniffing the response.
593 | #
594 | # This reduces exposure to drive-by download attacks and cross-origin
595 | # data leaks, and should be left uncommented, especially if the server
596 | # is serving user-uploaded content or content that could potentially be
597 | # treated as executable by the browser.
598 | #
599 | # http://www.slideshare.net/hasegawayosuke/owasp-hasegawa
600 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-v-comprehensive-protection.aspx
601 | # https://msdn.microsoft.com/en-us/library/ie/gg622941.aspx
602 | # https://mimesniff.spec.whatwg.org/
603 |
604 |
605 | Header set X-Content-Type-Options "nosniff"
606 |
607 |
608 | # ----------------------------------------------------------------------
609 | # | Reflected Cross-Site Scripting (XSS) attacks |
610 | # ----------------------------------------------------------------------
611 |
612 | # (1) Try to re-enable the cross-site scripting (XSS) filter built
613 | # into most web browsers.
614 | #
615 | # The filter is usually enabled by default, but in some cases it
616 | # may be disabled by the user. However, in Internet Explorer for
617 | # example, it can be re-enabled just by sending the
618 | # `X-XSS-Protection` header with the value of `1`.
619 | #
620 | # (2) Prevent web browsers from rendering the web page if a potential
621 | # reflected (a.k.a non-persistent) XSS attack is detected by the
622 | # filter.
623 | #
624 | # By default, if the filter is enabled and browsers detect a
625 | # reflected XSS attack, they will attempt to block the attack
626 | # by making the smallest possible modifications to the returned
627 | # web page.
628 | #
629 | # Unfortunately, in some browsers (e.g.: Internet Explorer),
630 | # this default behavior may allow the XSS filter to be exploited,
631 | # thereby, it's better to inform browsers to prevent the rendering
632 | # of the page altogether, instead of attempting to modify it.
633 | #
634 | # https://hackademix.net/2009/11/21/ies-xss-filter-creates-xss-vulnerabilities
635 | #
636 | # (!) Do not rely on the XSS filter to prevent XSS attacks! Ensure that
637 | # you are taking all possible measures to prevent XSS attacks, the
638 | # most obvious being: validating and sanitizing your website's inputs.
639 | #
640 | # http://blogs.msdn.com/b/ie/archive/2008/07/02/ie8-security-part-iv-the-xss-filter.aspx
641 | # http://blogs.msdn.com/b/ieinternals/archive/2011/01/31/controlling-the-internet-explorer-xss-filter-with-the-x-xss-protection-http-header.aspx
642 | # https://www.owasp.org/index.php/Cross-site_Scripting_%28XSS%29
643 |
644 | #
645 |
646 | # # (1) (2)
647 | # Header set X-XSS-Protection "1; mode=block"
648 |
649 | # # `mod_headers` cannot match based on the content-type, however,
650 | # # the `X-XSS-Protection` response header should be send only for
651 | # # HTML documents and not for the other resources.
652 |
653 | #
654 | # Header unset X-XSS-Protection
655 | #
656 |
657 | #
658 |
659 | # ----------------------------------------------------------------------
660 | # | Server-side technology information |
661 | # ----------------------------------------------------------------------
662 |
663 | # Remove the `X-Powered-By` response header that:
664 | #
665 | # * is set by some frameworks and server-side languages
666 | # (e.g.: ASP.NET, PHP), and its value contains information
667 | # about them (e.g.: their name, version number)
668 | #
669 | # * doesn't provide any value as far as users are concern,
670 | # and in some cases, the information provided by it can
671 | # be used by attackers
672 | #
673 | # (!) If you can, you should disable the `X-Powered-By` header from the
674 | # language / framework level (e.g.: for PHP, you can do that by setting
675 | # `expose_php = off` in `php.ini`)
676 | #
677 | # https://php.net/manual/en/ini.core.php#ini.expose-php
678 |
679 |
680 | Header unset X-Powered-By
681 |
682 |
683 | # ----------------------------------------------------------------------
684 | # | Server software information |
685 | # ----------------------------------------------------------------------
686 |
687 | # Prevent Apache from adding a trailing footer line containing
688 | # information about the server to the server-generated documents
689 | # (e.g.: error messages, directory listings, etc.)
690 | #
691 | # https://httpd.apache.org/docs/current/mod/core.html#serversignature
692 |
693 | ServerSignature Off
694 |
695 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
696 |
697 | # Prevent Apache from sending in the `Server` response header its
698 | # exact version number, the description of the generic OS-type or
699 | # information about its compiled-in modules.
700 | #
701 | # (!) The `ServerTokens` directive will only work in the main server
702 | # configuration file, so don't try to enable it in the `.htaccess` file!
703 | #
704 | # https://httpd.apache.org/docs/current/mod/core.html#servertokens
705 |
706 | #ServerTokens Prod
707 |
708 |
709 | # ######################################################################
710 | # # WEB PERFORMANCE #
711 | # ######################################################################
712 |
713 | # ----------------------------------------------------------------------
714 | # | Compression |
715 | # ----------------------------------------------------------------------
716 |
717 |
718 |
719 | # Force compression for mangled `Accept-Encoding` request headers
720 | # https://developer.yahoo.com/blogs/ydn/pushing-beyond-gzipping-25601.html
721 |
722 |
723 |
724 | SetEnvIfNoCase ^(Accept-EncodXng|X-cept-Encoding|X{15}|~{15}|-{15})$ ^((gzip|deflate)\s*,?\s*)+|[X~-]{4,13}$ HAVE_Accept-Encoding
725 | RequestHeader append Accept-Encoding "gzip,deflate" env=HAVE_Accept-Encoding
726 |
727 |
728 |
729 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
730 |
731 | # Compress all output labeled with one of the following media types.
732 | #
733 | # (!) For Apache versions below version 2.3.7 you don't need to
734 | # enable `mod_filter` and can remove the ``
735 | # and `` lines as `AddOutputFilterByType` is still in
736 | # the core directives.
737 | #
738 | # https://httpd.apache.org/docs/current/mod/mod_filter.html#addoutputfilterbytype
739 |
740 |
741 | AddOutputFilterByType DEFLATE "application/atom+xml" \
742 | "application/javascript" \
743 | "application/json" \
744 | "application/ld+json" \
745 | "application/manifest+json" \
746 | "application/rdf+xml" \
747 | "application/rss+xml" \
748 | "application/schema+json" \
749 | "application/vnd.geo+json" \
750 | "application/vnd.ms-fontobject" \
751 | "application/x-font-ttf" \
752 | "application/x-javascript" \
753 | "application/x-web-app-manifest+json" \
754 | "application/xhtml+xml" \
755 | "application/xml" \
756 | "font/eot" \
757 | "font/opentype" \
758 | "image/bmp" \
759 | "image/svg+xml" \
760 | "image/vnd.microsoft.icon" \
761 | "image/x-icon" \
762 | "text/cache-manifest" \
763 | "text/css" \
764 | "text/html" \
765 | "text/javascript" \
766 | "text/plain" \
767 | "text/vcard" \
768 | "text/vnd.rim.location.xloc" \
769 | "text/vtt" \
770 | "text/x-component" \
771 | "text/x-cross-domain-policy" \
772 | "text/xml"
773 |
774 |
775 |
776 | # - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
777 |
778 | # Map the following filename extensions to the specified
779 | # encoding type in order to make Apache serve the file types
780 | # with the appropriate `Content-Encoding` response header
781 | # (do note that this will NOT make Apache compress them!).
782 | #
783 | # If these files types would be served without an appropriate
784 | # `Content-Enable` response header, client applications (e.g.:
785 | # browsers) wouldn't know that they first need to uncompress
786 | # the response, and thus, wouldn't be able to understand the
787 | # content.
788 | #
789 | # https://httpd.apache.org/docs/current/mod/mod_mime.html#addencoding
790 |
791 |
792 | AddEncoding gzip svgz
793 |
794 |
795 |
796 |
797 | # ----------------------------------------------------------------------
798 | # | Content transformation |
799 | # ----------------------------------------------------------------------
800 |
801 | # Prevent intermediate caches or proxies (e.g.: such as the ones
802 | # used by mobile network providers) from modifying the website's
803 | # content.
804 | #
805 | # https://tools.ietf.org/html/rfc2616#section-14.9.5
806 | #
807 | # (!) If you are using `mod_pagespeed`, please note that setting
808 | # the `Cache-Control: no-transform` response header will prevent
809 | # `PageSpeed` from rewriting `HTML` files, and, if the
810 | # `ModPagespeedDisableRewriteOnNoTransform` directive isn't set
811 | # to `off`, also from rewriting other resources.
812 | #
813 | # https://developers.google.com/speed/pagespeed/module/configuration#notransform
814 |
815 | #
816 | # Header merge Cache-Control "no-transform"
817 | #
818 |
819 | # ----------------------------------------------------------------------
820 | # | ETags |
821 | # ----------------------------------------------------------------------
822 |
823 | # Remove `ETags` as resources are sent with far-future expires headers.
824 | #
825 | # https://developer.yahoo.com/performance/rules.html#etags
826 | # https://tools.ietf.org/html/rfc7232#section-2.3
827 |
828 | # `FileETag None` doesn't work in all cases.
829 |
830 | Header unset ETag
831 |
832 |
833 | FileETag None
834 |
835 | # ----------------------------------------------------------------------
836 | # | Expires headers |
837 | # ----------------------------------------------------------------------
838 |
839 | # Serve resources with far-future expires headers.
840 | #
841 | # (!) If you don't control versioning with filename-based
842 | # cache busting, you should consider lowering the cache times
843 | # to something like one week.
844 | #
845 | # https://httpd.apache.org/docs/current/mod/mod_expires.html
846 |
847 |
848 |
849 | ExpiresActive on
850 | ExpiresDefault "access plus 1 month"
851 |
852 | # CSS
853 |
854 | ExpiresByType text/css "access plus 1 year"
855 |
856 |
857 | # Data interchange
858 |
859 | ExpiresByType application/atom+xml "access plus 1 hour"
860 | ExpiresByType application/rdf+xml "access plus 1 hour"
861 | ExpiresByType application/rss+xml "access plus 1 hour"
862 |
863 | ExpiresByType application/json "access plus 0 seconds"
864 | ExpiresByType application/ld+json "access plus 0 seconds"
865 | ExpiresByType application/schema+json "access plus 0 seconds"
866 | ExpiresByType application/vnd.geo+json "access plus 0 seconds"
867 | ExpiresByType application/xml "access plus 0 seconds"
868 | ExpiresByType text/xml "access plus 0 seconds"
869 |
870 |
871 | # Favicon (cannot be renamed!) and cursor images
872 |
873 | ExpiresByType image/vnd.microsoft.icon "access plus 1 week"
874 | ExpiresByType image/x-icon "access plus 1 week"
875 |
876 | # HTML
877 |
878 | ExpiresByType text/html "access plus 0 seconds"
879 |
880 |
881 | # JavaScript
882 |
883 | ExpiresByType application/javascript "access plus 1 year"
884 | ExpiresByType application/x-javascript "access plus 1 year"
885 | ExpiresByType text/javascript "access plus 1 year"
886 |
887 |
888 | # Manifest files
889 |
890 | ExpiresByType application/manifest+json "access plus 1 week"
891 | ExpiresByType application/x-web-app-manifest+json "access plus 0 seconds"
892 | ExpiresByType text/cache-manifest "access plus 0 seconds"
893 |
894 |
895 | # Media files
896 |
897 | ExpiresByType audio/ogg "access plus 1 month"
898 | ExpiresByType image/bmp "access plus 1 month"
899 | ExpiresByType image/gif "access plus 1 month"
900 | ExpiresByType image/jpeg "access plus 1 month"
901 | ExpiresByType image/png "access plus 1 month"
902 | ExpiresByType image/svg+xml "access plus 1 month"
903 | ExpiresByType image/webp "access plus 1 month"
904 | ExpiresByType video/mp4 "access plus 1 month"
905 | ExpiresByType video/ogg "access plus 1 month"
906 | ExpiresByType video/webm "access plus 1 month"
907 |
908 |
909 | # Web fonts
910 |
911 | # Embedded OpenType (EOT)
912 | ExpiresByType application/vnd.ms-fontobject "access plus 1 month"
913 | ExpiresByType font/eot "access plus 1 month"
914 |
915 | # OpenType
916 | ExpiresByType font/opentype "access plus 1 month"
917 |
918 | # TrueType
919 | ExpiresByType application/x-font-ttf "access plus 1 month"
920 |
921 | # Web Open Font Format (WOFF) 1.0
922 | ExpiresByType application/font-woff "access plus 1 month"
923 | ExpiresByType application/x-font-woff "access plus 1 month"
924 | ExpiresByType font/woff "access plus 1 month"
925 |
926 | # Web Open Font Format (WOFF) 2.0
927 | ExpiresByType application/font-woff2 "access plus 1 month"
928 |
929 |
930 | # Other
931 |
932 | ExpiresByType text/x-cross-domain-policy "access plus 1 week"
933 |
934 |
935 |
936 | # ----------------------------------------------------------------------
937 | # | File concatenation |
938 | # ----------------------------------------------------------------------
939 |
940 | # Allow concatenation from within specific files.
941 | #
942 | # e.g.:
943 | #
944 | # If you have the following lines in a file called, for
945 | # example, `main.combined.js`:
946 | #
947 | #
948 | #
949 | #
950 | # Apache will replace those lines with the content of the
951 | # specified files.
952 |
953 | #
954 | #
955 | # Options +Includes
956 | # AddOutputFilterByType INCLUDES application/javascript \
957 | # application/x-javascript \
958 | # text/javascript
959 | # SetOutputFilter INCLUDES
960 | #
961 | #
962 | # Options +Includes
963 | # AddOutputFilterByType INCLUDES text/css
964 | # SetOutputFilter INCLUDES
965 | #
966 | #
967 |
968 | # ----------------------------------------------------------------------
969 | # | Filename-based cache busting |
970 | # ----------------------------------------------------------------------
971 |
972 | # If you're not using a build process to manage your filename version
973 | # revving, you might want to consider enabling the following directives
974 | # to route all requests such as `/style.12345.css` to `/style.css`.
975 | #
976 | # To understand why this is important and even a better solution than
977 | # using something like `*.css?v231`, please see:
978 | # http://www.stevesouders.com/blog/2008/08/23/revving-filenames-dont-use-querystring/
979 |
980 | #
981 | # RewriteEngine On
982 | # RewriteCond %{REQUEST_FILENAME} !-f
983 | # RewriteRule ^(.+)\.(\d+)\.(bmp|css|cur|gif|ico|jpe?g|js|png|svgz?|webp|webmanifest)$ $1.$3 [L]
984 | #
985 |
986 |
987 | # ######################################################################
988 | # # WORDPRESS #
989 | # ######################################################################
990 |
991 | # ----------------------------------------------------------------------
992 | # | Redirect all requests to home_url() |
993 | # ----------------------------------------------------------------------
994 |
995 | # http://moz.com/blog/301-redirect-or-relcanonical-which-one-should-you-use
996 |
997 | #
998 | # RewriteCond %{HTTP_HOST} !^www\.example\.com$
999 | # RewriteRule ^ %{ENV:PROTO}://www.example.com%{REQUEST_URI} [R=301,L]
1000 | #
1001 | # RewriteCond %{THE_REQUEST} index(\.php)?
1002 | # RewriteRule ^index(\.php)?$ %{ENV:PROTO}://www.example.com/ [R=301,L]
1003 | #
1004 |
1005 | # ----------------------------------------------------------------------
1006 | # | Block potentially unwanted or undesired requests |
1007 | # ----------------------------------------------------------------------
1008 |
1009 | # Many of these were taken from iThemes Security
1010 | # https://github.com/wp-plugins/better-wp-security/blob/master/modules/free/tweaks/class-itsec-tweaks-admin.php
1011 |
1012 | #
1013 |
1014 | # # Block HTTP request methods that are unused by browsers
1015 | # RewriteCond %{REQUEST_METHOD} !^(GET|POST|HEAD) [NC]
1016 | # RewriteRule ^(.*)$ - [F]
1017 | #
1018 | # # Block suspicious queries
1019 | # RewriteCond %{QUERY_STRING} \.\.\/ [NC,OR]
1020 | # RewriteCond %{QUERY_STRING} ^.*\.(bash|git|hg|log|svn|swp|cvs) [NC,OR]
1021 | # RewriteCond %{QUERY_STRING} etc/passwd [NC,OR]
1022 | # RewriteCond %{QUERY_STRING} boot\.ini [NC,OR]
1023 | # RewriteCond %{QUERY_STRING} ftp\: [NC,OR]
1024 | # RewriteCond %{QUERY_STRING} http\: [NC,OR]
1025 | # RewriteCond %{QUERY_STRING} https\: [NC,OR]
1026 | # RewriteCond %{QUERY_STRING} (\<|%3C).*script.*(\>|%3E) [NC,OR]
1027 | # RewriteCond %{QUERY_STRING} mosConfig_[a-zA-Z_]{1,21}(=|%3D) [NC,OR]
1028 | # RewriteCond %{QUERY_STRING} base64_encode.*\(.*\) [NC,OR]
1029 | # RewriteCond %{QUERY_STRING} ^.*(%24&x).* [NC,OR]
1030 | # RewriteCond %{QUERY_STRING} ^.*(127\.0).* [NC,OR]
1031 | # RewriteCond %{QUERY_STRING} ^.*(globals|encode|localhost|loopback).* [NC,OR]
1032 | # RewriteCond %{QUERY_STRING} ^.*(request|concat|insert|union|declare).* [NC]
1033 | # RewriteCond %{QUERY_STRING} !^loggedout=true
1034 | # RewriteCond %{QUERY_STRING} !^action=jetpack-sso
1035 | # RewriteCond %{QUERY_STRING} !^action=rp
1036 | # RewriteCond %{HTTP_COOKIE} !^.*wordpress_logged_in_.*$
1037 | # RewriteCond %{HTTP_REFERER} !^http://maps\.googleapis\.com(.*)$
1038 | # RewriteRule ^(.*)$ - [F]
1039 |
1040 | # # Block foreign characters in queries
1041 | # RewriteCond %{QUERY_STRING} ^.*(%0|%A|%B|%C|%D|%E|%F).* [NC]
1042 | # RewriteRule ^(.*)$ - [F]
1043 |
1044 | #
1045 |
1046 | # ----------------------------------------------------------------------
1047 | # | Block outside access to WordPress includes files |
1048 | # ----------------------------------------------------------------------
1049 |
1050 |
1051 | RewriteRule ^wp-admin/includes/ - [F,L]
1052 | RewriteRule !^wp-includes/ - [S=3]
1053 |
1054 | RewriteRule ^wp-includes/js/tinymce/langs/.+\.php - [F,L]
1055 | RewriteRule ^wp-includes/theme-compat/ - [F,L]
1056 |
1057 | RewriteCond %{SCRIPT_FILENAME} !^(.*)wp-includes/ms-files.php
1058 | RewriteRule ^wp-includes/[^/]+\.php$ - [F,L]
1059 |
1060 |
1061 | # ----------------------------------------------------------------------
1062 | # | Block sensitive WordPress files |
1063 | # ----------------------------------------------------------------------
1064 |
1065 |
1066 |
1067 | # Apache < 2.3
1068 |
1069 | Order allow,deny
1070 | Deny from all
1071 | Satisfy All
1072 |
1073 |
1074 | # Apache ≥ 2.3
1075 |
1076 | Require all denied
1077 |
1078 |
1079 |
--------------------------------------------------------------------------------
/ruleset.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 | Roots Coding Standards
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
29 |
30 |
31 |
--------------------------------------------------------------------------------
/wp-h5bp-htaccess.php:
--------------------------------------------------------------------------------
1 | HTML5 Boilerplate's .htaccess
7 | Version 2.0.0
8 | Author: Roots
9 | Author URI: http://roots.io/plugins/html5-boilerplate-htaccess/
10 | License: MIT License
11 | License URI: http://opensource.org/licenses/MIT
12 | */
13 |
14 | add_action('generate_rewrite_rules', __NAMESPACE__ . '\\ApacheServerConfig::init', -9999, 0);
15 |
16 | class ApacheServerConfig {
17 | const MARKER = 'Roots Server Config';
18 | const TEXT_DOMAIN = 'roots';
19 |
20 | private static $instance;
21 |
22 | public static $rules_filters = [];
23 |
24 | protected static $mod_rewrite_enabled;
25 | protected static $home_path;
26 | protected static $wp_htaccess_file;
27 | protected static $roots_htaccess_file;
28 |
29 | protected $errors = [];
30 |
31 | public static function init() {
32 | if (!self::$instance) {
33 | self::$instance = new static();
34 | }
35 | return self::$instance;
36 | }
37 |
38 | protected function __construct() {
39 | require_once ABSPATH . '/wp-admin/includes/file.php';
40 | require_once ABSPATH . '/wp-admin/includes/misc.php';
41 |
42 | self::$mod_rewrite_enabled = got_mod_rewrite();
43 | self::$home_path = get_home_path();
44 | self::$wp_htaccess_file = self::$home_path . '.htaccess';
45 | self::$roots_htaccess_file = locate_template(['server_configs.conf', 'h5bp-htaccess.conf']);
46 | if (!self::$roots_htaccess_file) {
47 | self::$roots_htaccess_file = __DIR__ . '/h5bp-htaccess.conf';
48 | }
49 |
50 | if (!$this->verifySetup()) {
51 | $this->alerts();
52 | } else {
53 | self::setRulesFilters();
54 | $this->write();
55 | }
56 | }
57 |
58 | public static function setRulesFilters() {
59 | $home_url = parse_url(is_multisite() ? network_home_url('/') : home_url('/'));
60 | extract($home_url);
61 | self::$rules_filters = [
62 | 'www\\.example\\.com' => preg_quote($host),
63 | 'www.example.com/' => $host . $path,
64 | 'www.example.com' => $host,
65 | '/wordpress' => parse_url(site_url(), PHP_URL_PATH)
66 | ];
67 | self::$rules_filters = apply_filters('roots/h5bp-htaccess-filters', self::$rules_filters);
68 | }
69 |
70 | protected function verifySetup() {
71 | if (!get_option('permalink_structure')) {
72 | $this->errors[] = sprintf(__('Please enable %s.', self::TEXT_DOMAIN), 'Permalinks');
73 | }
74 |
75 | if (!$this->isWritable()) {
76 | $this->errors[] = sprintf(__('Please make sure your %s file is writable.', self::TEXT_DOMAIN), '.htaccess');
77 | }
78 |
79 | if (!self::$mod_rewrite_enabled) {
80 | $this->errors[] = sprintf(__('Please enable %s.', self::TEXT_DOMAIN), 'Apache mod_rewrite');
81 | }
82 |
83 | if (!file_exists(self::$roots_htaccess_file)) {
84 | $this->errors[] = sprintf(__('Cannot find the file %s.', self::TEXT_DOMAIN), self::$roots_htaccess_file);
85 | }
86 |
87 | return empty($this->errors);
88 | }
89 |
90 | protected function isWritable() {
91 | return is_writable(self::$home_path) || (file_exists(self::$wp_htaccess_file) && is_writable(self::$wp_htaccess_file));
92 | }
93 |
94 | protected function write() {
95 | $server_config_rules = extract_from_markers(self::$wp_htaccess_file, self::MARKER);
96 | if (empty($server_config_rules)) {
97 | $server_config_rules = implode('', file(self::$roots_htaccess_file));
98 | $server_config_rules = str_replace(array_keys(self::$rules_filters), array_values(self::$rules_filters), $server_config_rules);
99 | $server_config_rules = apply_filters('roots/h5bp-htaccess-rules', $server_config_rules);
100 | insert_with_markers(self::$wp_htaccess_file, self::MARKER, explode(PHP_EOL, $server_config_rules));
101 | }
102 | }
103 |
104 | public function alerts() {
105 | $alert = function ($message) {
106 | echo '';
107 | };
108 | if (current_user_can('activate_plugins')) {
109 | add_action('admin_notices', function () use ($alert) {
110 | array_map($alert, $this->errors);
111 | });
112 | }
113 | }
114 | }
115 |
--------------------------------------------------------------------------------