Note: An actual working implementation of the WP_Filesystem can be found in my Pluginception plugin.

Lot of talk amongst theme authors recently about writing local files. Writing files from code, whether it be from a theme or from a plugin, is generally bad mojo. However understanding why you shouldn’t is confusing to many, and then understanding why you shouldn’t do-it-yourself and should use the WP_Filesystem is even more confusing. To further muddy up the waters, many theme authors have expressed confusion at how to use WP_Filesystem in the first place.

So, let’s run the gamut in this tutorial. Note that I wrote it quickly, so it may be uneven in parts. 😉

Why Not To Do It

The most common reasons I see theme authors wanting to write local files falls into three categories:

  1. Dynamic CSS
  2. Configuration Saving
  3. Export/Import

Take the Dynamic CSS case to start with, since it’s the most common one by far. Some theme authors say “I’m making a framework/system/construction-kit where the user can define their own theme/layout/color-schemes and thus produce a bunch of CSS. I want to save this CSS in the theme/uploads directory, and then put a link to it from their page, so that the browser downloads it from there.

Why they shouldn’t do that: There’s half a dozen reasons here, but the big two are a) put just the dynamic parts of CSS inline into the page instead, because it’s faster, simpler, and avoids an extra HTTP roundtrip for the user’s browser to get this CSS file and b) writing a CSS file locally is insecure as hell if you do it in the “natural” way.

Security is going to be a big issue for the next two items, so I’ll cover it right now.

Modern UNIX-like systems have the concept of “users”. When I SSH or FTP into my hosting account, then I’m logged in as me and my user account. However, my webserver doesn’t run as my user account. It runs under some different user account, usually “nobody” or “apache” or “web” or something similar to that.

So when I create files, they’re owned by me. When my webserver creates files, then they’re owned by the webserver’s user, whatever it is. Normally, this isn’t a big deal. The webserver can read and serve files either way, so who cares, right? Well, when you’re creating files that are owned by the webserver, then the webserver has permission to write to those files. It’s the owner of them, after all. What’s important here is that I’m not the only person on this webserver.

Shared hosting systems have many users files all served by the same webserver. So if I allow that “nobody” user to own files that are part of my webpage, then anybody else can use their account on the same webserver to modify those files, and thus modify my webpage. For the case of CSS files, this poses a cross-site-scripting risk. Somebody else on my shared webserver could insert code into my CSS files and change them so as to steal my account information. Bad mojo.

The other two, where theme authors are saving configuration or exporting and importing things have the same basic problems, although the risks might be even higher. In one case, I found a theme saving its configuration settings by creating a PHP file in the uploads directory and then using var_export to export the configuration variable to it. Then it proceeded to include this file when the theme loaded, to load its configuration back in. Talk about insecure, anybody running this theme is basically handing over the entire control of their website to anybody on the same web server.

How To Do It Anyway

“But Otto”, I hear you shouting from halfway around the world, “WordPress itself writes files all the time! It can even upgrade itself. How is this safe?” Well, Mr. Incredbly Loud Person, WordPress uses a system called WP_Filesystem to make this safe.

The WP_Filesystem basically support five different ways of writing files to the system and they all ensure that ownership of those files remains firmly in the hands of the same person that owns the WordPress files. In other words, it writes files using your user account and not as the webserver user.

I’m sure many people have seen this before: