I wrote a plugin (https://github.com/bassjobsen/custom-bootstrap-editor) this plugin writes a stylesheet to wp-content/uploads/cbe
.
I will use something like the code below to do this:
$upload_dir = wp_upload_dir();
$this->folder = trailingslashit($upload_dir['basedir']).'cbe/';
if( !is_dir( $this->folder ) ) wp_mkdir_p( $this->folder );
if ( is_writable( $this->folder ) ){
file_put_contents( $this->folder.$this->filename, $css);
}
My first question about the above, what will be the best place to check if wp_upload_dir() is writable? Will there be a standard check (plus error) for this?
After reading http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ i got some other questions too.
The post mentioned tell i should use the Filesystem API to replace the code above. Will this observation still be true?
request_filesystem_credentials
seems to work as expected but to login for every file change seems some kind of overkill. Could my plugin skip the login screen?
Althought the credits seems valid my $wp_filesystem->mkdir( $folder )
and $wp_filesystem->put_contents( $folder.'/'.$filename, $css, FS_CHMOD_FILE)
seems always return false. How can i debug the Filesystem API calls?
update
thanks to @otto file writing works now:
if (isset($_POST['SaveCBESettings'])) {
if ( !empty($_POST) && check_admin_referer( 'cbe-nonce') )
{
$SaveCBESettings = 1;
$in = true;
$url = wp_nonce_url('options-general.php?page=filewriting','cbe-nonce');
if (false === ($creds = request_filesystem_credentials($url, '', false, false, array('SaveCBESettings')) ) ) {
$in = false;
}
if ($in && ! WP_Filesystem($creds) ) {
// our credentials were no good, ask the user for them again
request_filesystem_credentials($url, '', true, false,array('SaveCBESettings'));
$in = false;
}
if($in)
{
// by this point, the $wp_filesystem global should be working, so let's use it to create a file
global $wp_filesystem;
$contentdir = trailingslashit( $wp_filesystem->wp_content_dir() );
$wp_filesystem->mkdir( $contentdir. 'cbe' );
if ( ! $wp_filesystem->put_contents( $contentdir . 'cbe/test.txt', 'Test file contents', FS_CHMOD_FILE) )
{
echo "error saving file!";
}
unset($_POST);
}
}
}
Few things to explain here:
In that tutorial, I only chose the upload_dir as an example of how to do it. A demonstration of how the WP_Filesystem functions work. Normally you would not use the WP_Filesystem to write to the upload directory. That code is not meant to be copy-pasta’d into live production code.
Writing CSS, PHP, HTML, or really any other kind of files except images into the upload directory… and which will then be included in the web page in some fashion, is unsafe.
Doesn’t really matter how you do it, the upload directory is expected to contain things that are not considered necessarily XSS safe by its very nature. If you need to write files to be included in the page, like stylesheets, then you should make your own folder under /wp-content, not under /wp-content/uploads. The uploads directory should be used strictly for media files and downloads and other things uploaded through the various wp_upload functions.
When using the $wp_filesystem, there’s a handy function call for getting the content directory path:
$wp_filesystem->wp_content_dir();
. You need to use this function because the “remote” directory path may not be the same as the “local” directory path.There is not a similar function for getting the uploads_dir, because again, you normally would never do that. Really doesn’t make a lot of sense to use the uploads dir for those files.
So, this will give you the “remote” path to the content directory, and you can use it to write files and make directories and such like so:
And so forth. Of course, you still need to request the credentials and instantiate with the
WP_Filesystem($creds)
call first to use thatglobal $wp_filesystem
, but this works.