This isn’t a question about how to build a WordPress plugin. Rather, what, if any, guides could be applied to how to put together the file architecture of any plugin.
Some other programming languages or libraries have very controlled ways of organizing directories and files. Sometimes this is annoying and highlights the freedom that PHP offers, but on the flip-side WordPress plugins are put together in any fashion as determined by their author.
There isn’t a right answer, but my hope is to refine how I, and others, build plugins to make them more friendly for other developers to disect, easier to debug, easier to navigate, and possibly more efficient.
The final question: what do you think is the best way to organize a plugin?
Below are a few sample structures, but in no way is an exhaustive list. Feel free to add your own recommendations.
Assumed Default Structure
-
/wp-content
-
/plugins
-
/my-plugin
my-plugin.php
-
-
Model View Controller (MVC) method
-
/wp-content
-
/plugins
-
/my-plugin
-
/controller
Controller.php
-
/model
Model.php
-
/view
view.php
my-plugin.php
-
-
-
MVC’s three parts:
- The model interacts with the database, querying and saving data, and contains logic.
- The controller would contain template tags and functions that the view would utilize.
- The view is responsible to display the data provided by the model as constructed by the controller.
Organized by type method
/wp-content
-
/plugins
-
/my-plugin
-
/admin
admin.php
-
/assets
css/
images/
-
/classes
my-class.php
-
/lang
my-es_ES.mo
-
/templates
my-template.php
-
/widgets
my-widget.php
my-plugin.php
-
-
WordPress Plugin Boilerplate
Available on Github
Based on the Plugin API, Coding Standards, and Documentation Standards.
-
/wp-content
-
/plugins
-
/my-plugin
-
/admin
/css
/js
/partials
my-plugin-admin.php
-
/includes
my_plugin_activator.php
my_plugin_deactivator.php
my_plugin_i18n.php
my_plugin_loader.php
my_plugin.php
-
/languages
my_plugin.pot
-
/public
/css
/js
/partials
my-plugin-public.php
LICENSE.txt
README.txt
index.php
my-plugin.php
uninstall.php
-
-
-
Loosely organized method
/wp-content
-
/plugins
-
/my-plugin
css/
images/
js/
my-admin.php
my-class.php
my-template.php
my-widget.php
my-plugin.php
-
Note that plugins are all “controllers” by WP standards.
It depends on what the plugin is supposed to do, but in all cases I would try to separate the screen output from the PHP code as much as possible.
Here’s one way to do that easily – first, define a function that loads the template:
function my_plugin_load_template(array $_vars){
// you cannot let locate_template to load your template
// because WP devs made sure you can't pass
// variables to your template :(
$_template = locate_template('my_plugin', false, false);
// use the default one if the theme doesn't have it
if(!_$template)
$_template="views/template.php";
// load it
extract($_vars);
require $template;
}
Now, if the plugin uses a widget to display data:
class Your_Widget extends WP_Widget{
...
public function widget($args, $instance){
$title = apply_filters('widget_title', $instance['title'], $instance, $this->id_base);
// this widget shows the last 5 "movies"
$posts = new WP_Query(array('posts_per_page' => 5, 'post_type' => 'movie'));
if($title)
print $before_title . $title . $after_title;
// here we rely on the template to display the data on the screen
my_plugin_load_template(array(
// variables you wish to expose in the template
'posts' => $posts,
));
print $before_widget;
}
...
}
The template:
<?php while($posts->have_posts()): $posts->the_post(); ?>
<p><?php the_title(); ?></p>
<?php endwhile; ?>
Files:
/plugins/my_plugin/plugin.php <-- just hooks
/plugins/my_plugin/widget.php <-- widget class, if you have a widget
/themes/twentyten/my_plugin.php <-- template
/plugins/my_plugin/views/template.php <-- fallback template
Where do you put your CSS, JS, images, or how do you design the container for the hooks is less important. It’s a matter of personal preference I guess.