For more technical users or to skip the the background explanation, skip directly to the code.

One of the challenges that comes with building WordPress plugins is supporting the conflicts that ensue with other poorly coded plugins and/or poorly coded themes.

It’s just the nature of the beast.

When it comes to addressing the way a plugin or widget looks on the frontend, I’ve often advised users to modify the plugin’s stylesheet in order to achieve the results they want.

Unfortunately, this is problematic for a number of reasons.

The Problems with Stylesheets

First, I never advise my users to update their theme’s stylesheet – only my plugin’s stylesheet. This gives me at least some level of managing the problem. If I were to instruct user’s to update the core style.css file, then the changes would be at the mercy of the theme developer.

The second problem is that when the plugin is updated, the changes will be overwritten so anything that they’ve added, removed, or modified will be lost. For many, this causes frustration and clearly negatively impacts their experience with me and my plugin and, by extension, with the visitors to their blog.

Ain't No Body Got Time For That

This ends up with needing to create some type of feature that makes updating stylesheets manageable from the dashboard without being lost during upgrades.

Dynamically Creating Stylesheets

To do this, I’ve begun adding a custom.css file to some of my plugins. The idea of a custom stylesheet is not a new idea. In fact, it’s something that I used to do, then I stopped doing, but have obviously resulted in doing it again out of necessity.

But that whole topic is content for another post.

To dynamically create stylesheets in the context of WordPress plugins, I do the following:

First, I add a hook in my constructor:

/* Setup the activation hook specifically for checking for the custom.css file
 * I'm calling the same function using the activation hook - which is when the user activates the plugin,
 * and during upgrade plugin event. This ensures that the custom.css file can also be managed
 * when the plugin is updated.
 */
register_activation_hook( __FILE__, array( $this, 'activate' ) );
add_action( 'pre_set_site_transient_update_plugins', array( $this, 'activate' ) );

Secondly, I define the function. The code comments should make this clear enough but I’ll discuss it a bit more after the code:

 /**
  * Checks to see if a custom.css file exists. If not, creates it; otherwise, does nothing. This will
  * prevent customizations from being overwritten in future upgrades.
  */
 function activate() {
	 
	 // The path where the custom.css should be stored.
	 $str_custom_path =  dirname( __FILE__ ) . '/css/custom.css';
	 
	 // If the custom.css file doesn't exist, then we create it
	 if( is_writable( $str_custom_path) && ! file_exists( $str_custom_path ) ) {
		 file_put_contents( $str_custom_path, '' );
	 } // end if
	 
 } // end activate

Note Thanks to comments by Geert and Stephen, I’ve added the is_writable checks and also made sure to check for the custom.css file upon plugin upgrade as well as activation.

Simply put, the plugin – upon activation or upgrade – will check to see if a custom stylesheet exists. If not, it will create it; otherwise, it will not. This ensures that users will always have a way to customize the look of their plugin without losing changes during upgrades.

The feature’s easy enough to port from plugin to plugin and it provides a consist way for me to support users. Again, I’ve my own thoughts on custom stylesheets that I’ll discuss in another post.

Category:
Notes
Tags:

Join the conversation! 12 Comments

  1. You might want to throw in an is_writable() check in there.

    So you’re saying that when a plugin gets updated, the existing custom.css file (if any) remains intact and doesn’t get removed? I thought that wasn’t the case, or maybe it is because the plugin activation hook is run first during an upgrade?

  2. Great post Tom!

    One question though: does the stylesheet file not get deleted if you upgrade automatically? Going through the motions of wp_update_plugin() you end up here: https://github.com/WordPress/WordPress/blob/3.5/wp-admin/includes/class-wp-upgrader.php#L306. That seems like it would delete all existing plug-in files (unless I’ve missed something).

    • Nope – you’re right. I did some more investigation and digging on this this afternoon, so I’m going to release a small update to the plugin as soon as I get it resolved.

      I’ll be sure to update the post linking back to your comment to make sure future readers are aware.

      Thanks Stephen – good stuff!

  3. Interesting … although I do allow for a custom stylesheet to be created (and properly enqueued) with all of my plugins I had left the actual file creation process to the end-user.

    Adding the custom stylesheet at activation / upgrade of the plugin seems to definitely add to the plugin’s UX especially for those less technically inclined end-users.

    • Adding the custom stylesheet at activation / upgrade of the plugin seems to definitely add to the plugin’s UX especially for those less technically inclined end-users.

      Exactly. The problem is that even that it enhances the UX a little bit, they still have to write CSS, and I’m a little uncomfortable with that.

      The thing is, the alternative is to introduce a new UI element that includes something like a color picker, or that just gives them a finite number of styles from which to choose.

      I dislike the first option because I dislike the UI element, and I dislike the latter option because it just kicks the can further down the road. There will always be people who want more customizations.

      So this is basically a single, very small step. Better than none, though :).

      • That is what I like about the whole aspect of providing an upgrade-survivable end-user CSS file (and creating the actual file before hand, too) is the ability to simply give the end-user some copy&paste CSS to sort out the issue if that is the case.

        Fortunately most of my plugin support requests can be solved with a minor CSS tweak. One that is either site specific or in rarer cases a temporary fix until I can get a new version of the plugin committed with the correction.

  4. Any plans on adding this to your plugin boilerplate?

  5. I started putting together a few thoughts on this, but it looks like most of the issues were hashed on Twitter. I figured I’d just throw this out there in any case to outline the issues and a few approaches. Sorry for the long response, it helps me organize my thoughts and there are a lot of variables to take into consideration. I skipped over a few things and I’m sure there are some approaches I missed.

    Issues

    Maintaining customizations during plugin updates.
    Maintaining customizations when the theme is updated or switched.
    Leveraging the built-in plugin editor.
    Make it easy to get started.

    To start with, I don’t think a plugin’s directory is ever a good place to make modifications for a couple of reasons: It won’t always be writable and changes aren’t maintained during a plugin update. Less importantly, it just feels like hacking the plugin. For instance, if you wanted to customize the appearance of the WordPress dashboard, you wouldn’t place a stylesheet in the /wp-admin directory.

    Theme Stylesheets

    If we consider a plugin’s front-end presentation layer beyond just the CSS, there’s a best practice for allowing that to take place using locate_template() to overload template files. CSS is a little different, but the concept should be the same.

    Or if the user has a child theme already, they could simply include the updates in the child theme’s style.css without worrying about it ever being overwritten. If they’re using a parent theme, then they should only modify the style.css file if it’s a custom theme and it won’t be receiving updates. Otherwise, they’d need to create a child theme to implement the customizations.

    The downside here are that the user would need to understand the relationship between parent themes and child themes and where to apply their modifications. However, this is how WordPress behaves in general and something the user would need to understand if they were to make any customizations at all, so it’s a concept they’ll run into at one point or another.

    As far as addressing the issues, customizations would be maintained during plugin updates and theme updates (as long as they were applied to the right theme). The built-in editor could still be leveraged, but a custom stylesheet or child theme might need to be created first.

    Maintaining changes between theme switches doesn’t seem as important because any presentation customizations are likely to be specific to the theme in use, so the custom stylesheet would likely need to be updated anyways if it were stored in a different location. In that case, it seems better to keep the presentation grouped together.

    This approach would require very little code in the plugin to make it work and it would be the expected behavior for anyone already familiar with WordPress.

    Textarea / Editor Plugin Setting

    A textarea or editor could be provided as a plugin setting for entering custom CSS rules. I believe there was a plugin by Automattic that allowed for doing something similar, but it may have been rolled into Jetpack.

    Because the custom CSS is stored in the database, it won’t be affected by updates and you can output the CSS into the page head or body directly. You could also dynamically generate a stylesheet from this option and it could be regenerated on update. You could even combine the custom rules with the default stylesheet when generating the file in order to minimize requests. Storing any generated files in the uploads directory and enqueueing them from there, might be a better approach, though. If a write fails, you can still insert the rules into the page directly.

    This would probably be the easiest route for users, but you may not want to provide that option to everyone for various reasons. It couldn’t leverage the built-in editor, which is a bummer and would increase the footprint of the plugin if an editor needed to be included.

    Generate a Custom Plugin (Pluginception)

    Another option would be to generate a custom plugin for housing the custom stylesheet. It wouldn’t get wiped out when the main plugin is updated, would persist across theme switches, and could still leverage the built-in plugin editor.

  6. I know this is an old thread, but just in case somebody is still looking for a solution to this scenario here is a very nice and clean piece of code that will allow you to generate a dynamic “virtual” CSS file (by virtual I mean that the file itself does not exist) and enqueue it to your header in just one line avoiding the mess of printing all your CSS right there…

    http://awordpressthing.com/how-to-enqueue-a-dynamic-stylesheet-built-on-the-go-in-wordpress

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.