Many WordPress plugins include as their core functionality the ability to output things on the front end.
For example, an events calendar plugin needs to show a calendar on a page or post of your site.
That brings us to today’s topic. How do you, as a plugin developer, create a plugin whose output (styling and HTML structure) can be easily overridden by a user?
The first rule is to keep styling to the bare minimum.
Remember that plugins are built to provide functionality to WordPress websites. The site’s appearance is the job of the theme, so as far as possible don’t mess with that.
Pippin Williamson has recently written an excellent plugin on writing CSS for your plugins. Here’s an important excerpt from his article:
I usually think of there being two main types of CSS in plugins: skeleton and pretty. The skeleton CSS simply ensures that the HTML markup of the plugin displays in the format it is supposed to. It ensures that form elements, buttons, etc, display properly. The pretty CSS, however, controls the visual aesthetics, such as gradients, shadows, font sizes, colors, etc, and itβs this βprettyβ CSS that usually causes problems.
The ‘skelenton CSS’ should always be present, else it will simply be impossible to output anything that makes sense. Consider the events calendar plugin example we mentioned at the start of the article. To output the calendar, it is obvious that we would need some basic CSS. The key idea here is not to go fancy with that CSS. Stick to pastel modest colours, and let the user easily override that CSS.
How can we give the user an easy way to override CSS?
The easiest way would be to let the user add styles to his theme’s CSS file, while giving him the option to disable the plugin’s CSS file. This is usually done through an option in the plugin’s settings page, or through a hook in the code. Here’s an example from Pippin’s Easy Digital Downloads plugin:
This works fine if you are using only skeleton CSS.
There are plugins however that need to provide more styling than that usually included in the skeleton CSS. In these cases you should add another option to disable the ‘pretty’ styles.
Apart from the CSS styling, we also need to consider cases where the user would want to modify the HTML structure in the output. How do we go about that?
The easiest way I’ve found is to enable the user to override the plugin’s output by including template files in the theme. Again a very good example can be had with the Easy Digital Downloads plugin. Here’s an excerpt from the documentation, explaining how to override the plugin’s output:
The shopping cart shown on the checkout page can be very easily customized, thanks to the template system in Easy Digital Downloads. First, create a new folder called edd_templates inside of your currently active themeβs folder. Second, locate the checkout_cart.php file inside of easy-digital-downloads/includes/templates and copy (not move) it to the newly created edd_templates folder in your theme.Once you have the file copied to your themeβs folder, you can safely modify it as much as you want.
This is an approach used by many plugins, and one that I can recommend you use as well.
If you enjoyed this post, make sure to subscribe to WP Mayor’s RSS feed.
2 Responses
I’ve seen a few plugins that do this. My question is how do you set it up to check the theme dir for a file first before the plugin dir?
This depends. If you have a post type ‘foo’, your plug-in may want to provide a default template ‘single-foo.php’ in case the user’s theme does not have one already. In this case you can use the
template_include
filter to check if the template WordPress found (in the child/parent theme) was ‘single-foo.php’ – if it didn’t, you can change the template to point to the one your the plug-in provided.But you’ll want to ‘play nice’ with WordPress’ template hierarchy – so if WordPress finds in the theme ‘taxonomy-bar.php’ or ‘taxonomy-bar-myslug.php’ – both of those should be considered as appropriate templates for the ‘myslug’ term of the ‘bar’ taxonomy – and your plug-in shouldn’t over-ride them. Since ‘myslug’ is arbitrary you’ll need to do some preg_match magic.
In another situation (both Pippin and myself have used this), we’ve needed to include a template (say for a shortcode or widget). In this case I’ve (and Pippin) have defined a function which behaves almost identically to `locate_template()`, except that in checks in the plug-in directory as a last resort. This solution is in fact just a stop gap until this ticket is resolved: