Using WP_Filesystem to generate dynamic CSS

A few months ago I wrote an article on how to generate dynamic css file which you can use for storing your css options data, among its many other practical uses. There is no shortage of real world examples where dynamic css were used with little to zero impact on security & performance it might do to your site (with correct implementation), but a few doing_it_right() policemen were not very happy with how we’re using certain functions that’s not “WP compliant” in that tutorial. Therefore here’s another instalment of that method, and a small enhancement to top it off.

I’m going to be very brief here and just put the codes which you can just copy and replace the function you used in the previous tutorial, specifically the generate_options_css function.

You can see that the function is relatively a bit more lengthy now.

On line 9-13, I have added a little check to make sure that your options.css file will be stored independently on a Multisite setup. On a Multisite setup, the CSS file will now be written on individual blog’s uploads folder instead of directly inside your theme’s /css folder. If your theme is not going to be used on a MS, ever, then you can just delete those lines. The only reason why I have them there is that I’m doing most of my client’s development on a multisite setup, so I don’t want the options to be writing off each other if I were to use the same theme on multiple sites.

Line 21-25 is where the good stuff are. Previously, this is where the file_put_contents() were used, and we swapped them with the WP_Filesystem instead to better comply with WP coding standards. If you want to dig a little deeper into what’s going in there, read on.

The first line of that chunk of code initialises the WP_Filesystem_Base class via the WP_Filesystem_Direct subclass (see line 802 of /wp-admin/includes/file.php).

“But Syamil”, I hear you shouting from halfway around the world, “I saw from another tutorial that you need to use the request_filesystem_credentials() and all that before you use WP_Filesystem, while your method do not. How is this safe?” Well, Mr. Incredibly Loud Person, you don’t need a bloody credential if you’re just using the default “direct” method.

If you look at line 891-892 of /wp-admin/includes/file.php, the request_filesystem_credentials() function will simply return a true if there was no method defined, i.e. it defaults to “direct” method which requires no credentials whatsoever to run. It is only useful if you’re planning to use other methods like FTP or SSH.

Rather than worrying for something that’s not even remotely safer than the widely used file_put_contents() in the first place, you could be worrying about the state of the WordPress community that’s beginning to be infested with a certain breed of elitist who think they’re above everyone else and reserve the right to make fun of others just because they know some PHP codes.

Where were we..

Okay, after the WP_Filesystem function is called, you will now have access to the $wp_filesystem object and its method, which in our specific case is the $wp_filesystem->put_contents method. There are a bunch of other methods in that class, all of which are public so feel free to dig around and innovate some cool & awesome stuff from them.

The last parameter in that put_contents method, $mode (0644) is optional, but you might want to change that to something more secure if you’re ever going to publish your WP username & password on Facebook or Twitter.

A little snippet that you might need if you chose to support multisites is as below:

Just put that where you registers all your theme’s scripts/styles and you’re all good.

So that’s about it from me for now. I hope you found the article useful, and have a great day :)

Discussions — 30 Responses

  • Azhari Subroto November 23, 2012 on 11:47 am

    Hmmm,,, no comments yet.
    Well, I tried this method to my theme and I just got error…
    Will you be able to make this tutorial more clear and “newbie-friendly” :D?

    Because until now, I just put the generated css to php file (let’s say customstyle.php). And I think that’s not good. Because it’ll make the page load slowly.

    Reply
    • syamilmj Azhari Subroto November 26, 2012 on 4:46 am

      You can take a look at Cuvette’s WP theme to see how it’s done ;)

      Reply
  • Hildegard January 5, 2013 on 3:06 pm

    Ѕimplу nееd tο say your report maу be аstonishing.

    Reply
    • syamilmj Hildegard January 9, 2013 on 12:08 am

      Thanks!

      Reply
  • Mj January 9, 2013 on 12:03 am

    Hi

    This is what i was searching and reading for days. finally i remembered one of your post about osmf. i checked it out and finally find this article. that is the case :d

    All parts are clear. Thanks syamil.

    The only thing i can not figure out is, how can i warn user if user needs to set permission

    Thanks in advance for sharing your code ;)

    Reply
    • syamilmj Mj January 9, 2013 on 12:21 am

      WP_Filesystem will fail/provide a fallback if the “direct” method is not available, and you can check for this using get_filesystem_method($args, $context)

      Something like:

      $test = get_filesystem_method(”, ‘path-to-css-dir’);

      If $test is anything other than “direct” then that means the folder is either not writable because of file permission, or they have url_allow_fopen disabled.

      Hope that helps

      Reply
      • Mj syamilmj January 9, 2013 on 4:54 pm

        Thanks my friend, It works great. i did the check and now user see a warning if enough permission is not available

        here is it is:

        function pre_check_custom_css_writable() {
        // custom css directory
        $the_dir = get_template_directory() . ‘/css/dir';

        if(! get_filesystem_method(array(), $the_dir ) == “direct”)
        add_action(‘admin_notices’, ‘pre_notice_custom_css_permission’);
        }

        add_action( ‘admin_init’, ‘pre_check_custom_css_writable’ );

        // display notice if user need to set permission for directory
        function pre_notice_custom_css_permission(){
        echo ‘
        This theme needs permission to write custom styles in css file. Please change directory permission at ( [theme_directory]/css/dir) to 644 or higher
        ‘;
        }

        Reply
      • syamilmj syamilmj January 10, 2013 on 9:26 am

        Looks awesome. Great work there! ;)

        Reply
      • dariodev syamilmj October 13, 2013 on 3:33 am

        May I ask wouldn’t be better to always write css inside $uploads[‘baseurl’] regardless of multisite or not? This way will reduce the possibility of permission problems.

        Reply
  • hainug January 21, 2013 on 5:08 pm

    Hi Syamil,

    thanks for your reply on forum, 1 question please, if i use of_get_option for $data, what should i wrote on $data = $newdata;
    Sorry for silly question, i’m not good in php :D

    thanks again in advance

    Reply
    • syamilmj hainug January 24, 2013 on 9:45 pm

      $newdata is defined when you’re using the generate_options_css() function. It could be anything you like.

      Reply
  • AnyDog January 23, 2013 on 8:26 am

    Ok, now … I’m using your SMOF, applied this code above (works perfectly) … currently I’m working on page builder block for my new theme.
    I think you deserved I purchase at least one of your themes … ;) (probably Cuvette)

    Best regards and … keep it comming ! ;)

    Reply
    • syamilmj AnyDog January 24, 2013 on 9:43 pm

      Glad to hear that mate. All the best! :)

      Reply
  • Dwayne February 10, 2013 on 12:05 pm

    I’m not having any luck with getting the option data saved or reset when using the 2 lines of code:
    generate_options_css($data); //generate static css file
    for saving
    and
    generate_options_css($defaults); //generate static css file
    for reset

    I’m not sure if I have them in the right place or file. I’m adding them to function.interface.php inside admin/function folder. The save code is on line234 and reset is on line241. Is this right

    Also where can I add the new generate_options_css function code to what page, is that my theme function or your blank function inside admin/function folder.

    Thanks in advance for the the help and which looks like a great theme option.

    Dwayne

    Reply
  • Scot February 11, 2013 on 6:40 am

    Great information here. It’s been very helpful. I was following the code from the last post about this and got it working using the original file_put_contents method. When I updated the code to replace that with WP_Filesystem, I get this error “Fatal error: Call to undefined function WP_Filesystem()”. Why would this fail like this?

    Reply
    • syamilmj Scot February 11, 2013 on 9:52 pm

      Were you trying to run the function outside of WP admin?

      Reply
  • Scot February 12, 2013 on 9:06 pm

    I wasn’t trying to but at the time, I actually was. It is on my local development environment as I am still working building the theme.

    The function I had to generate the css wasn’t in the proper hook yet so it was running on all page loads. I resolved the hook issue this morning so it only runs when my specific theme option page is updated. Now, WP_Filesystem() is not generating an error and the custom css file is being build exactly how, and when, it should be.

    syamilmj, thank you for your help and the quick follow up.

    Reply
    • syamilmj Scot February 12, 2013 on 10:34 pm

      Glad to help out ;)

      Reply
  • Flava Flav March 5, 2013 on 1:16 pm

    Hi,

    Thanks for your great work!!

    I have been using this in themes for quite some time now, and 99.9% of the time the theme options are populated nicely into the dynamic stylesheet.

    On a few rare occasions, the options save fine in the WP backend, no error messages etc, but the CSS file is not populated, and remains empty?? I have checked that permissions (0644) are set ok, and now am really stumped??!

    Would this be with their hosting? Or possibly something else?

    Your thoughts would be truly appreciated.

    thanks

    Reply
    • syamilmj Flava Flav March 6, 2013 on 6:27 am

      Sometimes the server probably had the “url_allow_fopen” disabled. Might want to ask them to check with the host.

      Reply
  • Flava Flav March 6, 2013 on 8:07 am

    Thanks for that buddy. Checked via phpinfo, allow_url_fopen seems to be On.

    ??

    Sorry if this off base a little, but how would you personally test a little further? Do you have a file that you maybe use that shows any error messages? I have FTP access to the clients site.

    Many thanks again

    Reply
  • Flava Flav March 6, 2013 on 9:04 am

    Sorry, scrap that last question. Was having a ‘Doh’!! moment ;)

    Awesome work as always with everything you do!

    thanks

    Reply
    • syamilmj Flava Flav March 6, 2013 on 12:57 pm

      Hey no worries ;)

      What was the error the user was having? Probably useful in case someone else here gets in the same mud later :)

      Cheers

      Reply
  • Flava Flav March 6, 2013 on 1:18 pm

    Hey,

    On one it was the error –

    failed to open stream: Permission denied.

    So i suggested they speak to the host in regards to permissions issues.

    The other one has me stumped?!

    No error that I can see in their logs, options save, but the dynamic stylesheet never populates?!? Really has me baffled!!

    thanks

    Reply
  • Flava Flav March 6, 2013 on 1:27 pm

    This is the full log from the first error –

    [Tue Mar 05 19:22:53 2013] [error] [client 81.159.230.245] PHP Warning: file_put_contents(/home/c058/domains/clearforlanding.nl/public_html/wp-content/themes/essential/assets/css/dynamic-css/options.css): failed to open stream: Permission denied in /home/c058/domains/clearforlanding.nl/public_html/wp-content/themes/essential/admin/functions/functions.admin.php on line 69, referer: http://clearforlanding.nl/wp-admin/themes.php?page=optionsframework

    Many thanks

    Reply
  • Sandro June 15, 2013 on 11:24 pm

    Hi,

    I am trying to use your code but it gives me an weird error : Fatal error: Call to undefined function WP_Filesystem() in …

    Do you have any ideea why is this error raised ?

    Thanks

    Reply
    • syamilmj Sandro June 16, 2013 on 9:16 am

      That’s probably caused by calling the function outside out of admin area

      Reply
  • Sandro June 16, 2013 on 6:48 pm

    Thanks for the reply syamilmj …

    In the functions.php I included an file MyThemeOptions.php. In this file I load options and generate the custom css. I did it very simple with file_get_contents, fopen and fwrite. Of course this approach triggered several warnings in Theme Check and thats why I am trying to implement in MyThemeOptions.php the WP_Filesystem approach.

    Can you please explain how to implement the WP_Filesystem in MyThemeOptions.php or other file so I will be able to read and write the dynamic css.

    Thank you

    Reply
  • secretja November 7, 2013 on 6:46 pm

    Hi,

    I did all what you wrote but each time I get 404 for css file. Is maybe new wp update fault for that?

    Reply
  • Luiz January 20, 2014 on 7:35 pm

    Very good. Thanks ;)

    Reply