How to structure a plugin

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

10

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.

Leave a Comment