Wordpress - What WP folder can I use to write files to?

Best place is the uploads directory - it'll be writable by the server, and it's the defacto directory for storing any user-generated/uploaded files:

$dirs = wp_upload_dir();
$path = $dirs['basedir']; // /path/to/wordpress/wp-content/uploads

The only directory with guaranteed write access is the upload directory. Everything else might be protected.

Nowadays, we deploy sites with Composer, keep everything under version control and create completely new sites with each deploy in order to be able to roll back the deployed site. That means that the directory will be created completely new with each deploy.

Use the uploads directory if you have to write files, becase that's the only one that is kept (outside of the other directories).


One alternative approach us to have a PHP file that gets the theme options and outputs the CSS and enqueue that directly instead. eg.

wp_enqueue_style('custom-css',trailingslashit(get_template_directory_uri()).'styles.php');

This may seem like a strange thing to do at first, but since actually writing a new file should be done via the WP Filesystem for correct owner/group permissions, this is one way around that problem.

// send CSS Header
header("Content-type: text/css; charset: UTF-8");

// faster load by reducing memory with SHORTINIT
define('SHORTINIT', true);

// recursively find WordPress load
function find_require($file,$folder=null) {
    if ($folder === null) {$folder = dirname(__FILE__);}
    $path = $folder.DIRECTORY_SEPARATOR.$file;
    if (file_exists($path)) {require($path); return $folder;}
    else {
        $upfolder = find_require($file,dirname($folder));
        if ($upfolder != '') {return $upfolder;}
    }
}

// load WordPress core (minimal)
$wp_root_path = find_require('wp-load.php');
define('ABSPATH', $wp_root_path);
define('WPINC', 'wp-includes');

At this point you will need to include whatever other wp-includes files you need to get the theme options, which may vary depending on your how you are saving those. (You will probably need to add more so you do not get fatal errors.) eg.

include(ABSPATH.WPINC.DIRECTORY_SEPARATOR.'version.php');
include(ABSPATH.WPINC.DIRECTORY_SEPARATOR.'general-template.php');
include(ABSPATH.WPINC.DIRECTORY_SEPARATOR.'link-template.php');

Then just output the CSS options... eg.

echo 'body {color:' . get_theme_mod('body_color') . ';}';
echo 'body {backgroundcolor:' . get_theme_mod('body_background_color') . ';}';
exit;