2

I try to fix my plugin with the answers i got here: Using wp_filesystem in Plugins Background i wrote a theme (https://github.com/bassjobsen/jamedo-bootstrap-start-theme) and a plugin (https://github.com/bassjobsen/wp-less-to-css) now i want to integrate the plugin in the theme. The plugin wrote a CSS file to a folder. Write files with native PHP function is not secure as described here: http://ottopress.com/2011/tutorial-using-the-wp_filesystem/. The previous answer helps me to fix this issues for the plugin.

The solution provide by @otto relays on request_filesystem_credentials which seems to requires a URL. This URL will give me some troubles when integrate the plugin with the theme.

My target is to use settings from the customizer after saving to create a new css file.

Now i have in functions.php:

add_action( 'customize_save_after', 'lesscustomize' );

function lesscustomize($setting)
{
//$setting is no used here
$updatecss = WP_LESS_to_CSS::$instance;
add_filter( 'add_extra_less_code', 'add_extra_less_now_live');

function add_extra_less_now_live($parser)
{
    return 'h1{color:'.get_theme_mod( 'heading_color').'}';          
}
$updatecss->wpless2csssavecss();
}

Where wpless2csssavecss() now saves the file with file_put_contents. The file_put_contents should be replace with a $wp_filesystem->put_contents();. Cause $wp_filesystem will be used as a global i think it should be possible to get the file system credentials in my lesscustomize() function. Beside i have no idea how to do this without a URL. There will be a URL but it is called by Ajax and not visible for the user.

The idea to use 'customize_save_after' came from https://stackoverflow.com/questions/14802251/hook-into-the-wordpress-theme-customizer-save-action/16679837

My initial question will it be possible to get file system credentials in my lesscustomize()? Or if not will there be an alternative to hook the customizer settings save action and get file system credentials to save my settings?

update In this update of the question, i will react on the useful answer of Mark Kaplun. I expect this will help to understand my initial question.

What you are trying to do is wrong if it is for general purpose use and is not >tailored for the needs of a specific client. Dynamically modifying your >theme's code, and css is code like JS, is usually a bad idea that bring only >maintenance problems

In my theme i use LESS in stead of CSS (although you could also write CSS). I think this will be useful and fits the needs of the theme users. In the first place LESS keeps things clean and in the second place my theme is build with Twitter's Bootstrap. LESS will be the most kind of direct way to modify Bootstrap based HTML/CSS. I don't modify my theme code, i only want to save my CSS to file, where CSS will be compiled from LESS. Maintenance strategy of the code i have described here: http://bassjobsen.weblogs.fm/integrate-less-jbst-wordpress-theme/

In addition to the theoretical reasons there are user expectations related to the UX of theme customization which do not involve writing files to the server.

I do not understand what write files has to do with UX. People using my theme choose a theme which use Bootstrap and so LESS. I think they should understand there should be written files somewhere. I agree an extra step for filling in your credentials will give a bad UX.

If you truly need to save files on the server then the right place for them is >the /wp-content/uploads directory.

Yes, that's what i do now. http://ottopress.com/2011/tutorial-using-the-wp_filesystem/ tells me it is a bad idea. Since WP3.8 it will also don't pass the theme tests on wordpress.org: "WARNING: file_put_contents was found in the file wp-less-to-css.php possible file operations."

The better way to do it is to have minimal LESS files that are relevant only to the options that are controlled by the user. once the options are changed you compile the LESS and store the generated CSS in an option and output it as part of each pages HTML, like most themes are doing with their customizable options.

I agree this could be an option. Writing inline CSS does not be the best solution always, see also: https://developers.google.com/speed/docs/insights/OptimizeCSSDelivery. Not all customization setting have to be critical or part of the above-the-fold CSS. Beside in my case some setting will also recompile Bootstrap's CSS (for example changing the @grid-float-breakingpoint) i can not inline thhis code.

  • This can be interesting as a discussion on the chat, but it doesn't fit a Q&A format. my answer was bordering off-topic as it is. – Mark Kaplun Dec 17 '13 at 12:58
1

What you are trying to do is wrong if it is for general purpose use and is not tailored for the needs of a specific client. Dynamically modifying your theme's code, and css is code like JS, is usually a bad idea that bring only maintenance problems - are you validating all values to be able to compile? How will you handle upgrades? How will you handle network installs where users don't know the FTP credentials?

In addition to the theoretical reasons there are user expectations related to the UX of theme customization which do not involve writing files to the server.

If you truly need to save files on the server then the right place for them is the /wp-content/uploads directory.

The better way to do it is to have minimal LESS files that are relevant only to the options that are controlled by the user. once the options are changed you compile the LESS and store the generated CSS in an option and output it as part of each pages HTML, like most themes are doing with their customizable options.

  • thanks for you constructive answer, i react on it in my initial question (doesn't fit in a comment). Most important seems reasons to write or not to /wp-content/uploads. – Bass Jobsen Dec 17 '13 at 9:56
  • Do you have an example (or use story) of "network installs where users don't know the FTP credentials". – Bass Jobsen Dec 17 '13 at 9:57
  • 1
    @BassJobsen, on network installs the admin of the individual site/blog in the network is never the admin of the server, that is 90%+ of the use case of having a network install. – Mark Kaplun Dec 17 '13 at 12:21
1

update

The session option describe below seems very insecure! Further investigation make clear the array returned by request_filesystem_credentials contains your credentials in plain text. So store this in a session seems a bad idea.

Note sending the credentials over an non-secure connection (http) when posting the form also seems a bad idea. The latest can be solved by adding your credentials to wp_config.php. When doing this make sure to chmod 600 your wp_config.php (see: http://codex.wordpress.org/Changing_File_Permissions).

Setting the credentials in wp-config.php for example:

define('FS_METHOD', 'ftpext');
define('FTP_HOST', 'localhost');
define('FTP_USER', 'ftpuser');
define('FTP_PASS', 'ftpuser');
define('FTP_BASE', '/home/username/http_docs/');

After doing this we can save them ( temporary ) to the database for use by the customizer. This seems save to do cause the setting from wp-config.php are saved to the database too. Saving to the database will be done with set_theme_mod inspired by: https://stackoverflow.com/questions/14802251/hook-into-the-wordpress-theme-customizer-save-action/16679837

After doing all this the final code which enable me to store the customizer setting in a file using wp_filesystem:

function lesscustomize($setting)
{
$updatecss = WP_LESS_to_CSS::$instance;
$updatecss->wpless2csssavecss(unserialize(get_theme_mod('customizercredits')));
}

add_action( 'customize_save_after', 'lesscustomize' );

function storecedits( $wp_customize ) {

            $in = true;
            $url = 'customize.php';
            if (false === ($creds = request_filesystem_credentials($url, '', false, false,null) ) ) {
                $in = false;
                exit;
            }

            if ($in && ! WP_Filesystem($creds) ) {
                // our credentials were no good, ask the user for them again
                request_filesystem_credentials($url, '', true, false,null);
                $in = false;
                exit;
            }

            set_theme_mod('customizercredits', serialize($creds));

}
add_action('customize_controls_init', 'storecedits', 1);  

----------------- end update ----------------------

I found i can solve the problem theoretical by using sessions. Unfortunately this introduce new questions about security. First will enable sessions (found here https://stackoverflow.com/a/4769449/1596547) cause any other trouble? and if not what are the risks of storing my file credentials in a session?

function kana_init_session()
{
  session_start();
}

add_action('init', 'kana_init_session', 1);

function updatefiles( $wp_customize ) {
WP_Filesystem($_SESSION['creds']);

            global $wp_filesystem;
            $contentdir = trailingslashit( $wp_filesystem->wp_content_dir() ); 
            echo $contentdir;
            $wp_filesystem->mkdir( $contentdir. 'cbe' );
            if ( ! $wp_filesystem->put_contents(  $contentdir . 'cbe/test.txt', 'Test file contents', FS_CHMOD_FILE) ) 
            {
                echo "error saving file!";
            }



}

add_action('customize_save', 'updatefiles', 1);

function storecredentials( $wp_customize ) 
{

            $in = true;
            $url = 'customize.php';
            if (false === ($creds = request_filesystem_credentials($url, '', false, false,null) ) ) {
                $in = false;
                exit;
            }
            if ($in && ! WP_Filesystem($creds) ) {
                // our credentials were no good, ask the user for them again
                request_filesystem_credentials($url, '', true, false,null);
                $in = false;
                exit;
            }
            $_SESSION['creds'] = $creds;

}
add_action('customize_controls_init', 'storecredentials', 1);</strike>

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.