55

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
3
  • 1
    This isn't a real question, but I'm not going to close vote, but flagged to make this a Community Wiki. Btw: I think it doesn't make any sense to perfix the file names.
    – kaiser
    Commented Apr 8, 2012 at 16:19
  • Thanks, I'd rather this be community wiki anyway. I don't think prefixing files that way makes much sense either, but I've seen it a lot. Commented Apr 8, 2012 at 16:25
  • 1
    Another side-point: Perhaps more semantically correct names for the folders css/, images/, and js/ would be styles/, images/, and scripts/. Commented Dec 6, 2012 at 0:59

11 Answers 11

19
+50

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.

8

It depends on the plugin. This is my basic structure for nearly every plugin:

my-plugin/
    inc/
        Any additional plugin-specific PHP files go here
    lib/
        Library classes, css, js, and other files that I use with many
        plugins go here
    css/
    js/
    images/
    lang/
        Translation files
    my-plugin.php
    readme.txt

This would be something that would go in the lib folder.

If it's particularly complex plugin, with a lot of admin area functionality, I'd add an admin folder to contain all of those PHP files. If the plugin does something like replace included theme files, there maybe a template or theme folder as well.

So, a directory structure might look like this:

my-plugin/
    inc/
    lib/
    admin/
    templates/
    css/
    js/
    images/
    lang/
    my-plugin.php
    readme.txt
2
  • Would you also include the admin's css and js files within the /admin folder? Therefore having another /css and /js within /admin?
    – urok93
    Commented Aug 12, 2012 at 7:52
  • Hey Chris, Wow, over a decade ago, but still a pretty great answer! However, I would like to hear your answer to @urok93's question also Commented Feb 14 at 13:36
6

IMHO, the easiest, most powerful, and most maintainable route is to use an MVC structure, and WP MVC is designed to make writing MVC plugins very easy (I'm a little biased, though...). With WP MVC, you simply make the models, views, and controllers, and everything else is handled behind the scenes for you.

Separate controllers and views can be made for the public and admin sections, and the entire framework takes advantage of many of WordPress's native features. The file structure and much of the functionality is exactly the same as it is in the most popular MVC frameworks (Rails, CakePHP, etc).

More info and a tutorial can be found here:

5

We're using a mix of all methods. First of all, we're using the Zend Framework 1.11 in our plugins and therefore we had to use a similar structure for the class files because of the autoload mechanic.

The structure of our core plugin (which is used by all our plugins as a base) looks similar to this:

webeo-core/
    css/
    images/
    js/
    languages/
    lib/
        Webeo/
            Core.php
        Zend/
            /** ZF files **/
        Loader.php
    views/
    readme.txt
    uninstall.php
    webeo-core.php
  1. WordPress calls the webeo-core.php file in the plugin root folder.
  2. In this file we're going to set the PHP include path and register the activation and deactivation hooks for the plugin.
  3. We also have a Webeo_CoreLoader class inside this file, which sets some plugin constants, initialize the class autoloader and make a call to the setup method of the Core.php class inside the lib/Webeo folder. This runs on the plugins_loaded action hook with a priority of 9.
  4. The Core.php class is our plugin bootstrap file. The name is based on the plugins name.

As you can see, we have a subdirectory inside the lib folder for all our vendor packages (Webeo, Zend). All sub packages inside a vendor are structure by the module itself. For a new Mail Settings admin form, we would have the following structure:

webeo-core/
    ...
    lib/
        Webeo/
            Form/
                Admin/
                    MailSettings.php
                Admin.php
            Core.php
            Form.php

Our sub-plugins have the same structure with one exception. We go a level deeper inside the vendor folder due to resolve naming conflicts during the autoload event. We also call the plugins boostrap class E.g. Faq.php on priority 10 inside the plugins_loaded hook.

webeo-faq/ (uses/extends webeo-core)
    css/
    images/
    js/
    languages/
    lib/
        Webeo/
            Faq/
                Faq.php
                /** all plugin relevant class files **/
    views/
    readme.txt
    uninstall.php
    webeo-faq.php

I will probably rename the lib folder to vendors and move all public folders (css, images, js, languages) to a folder named public in the next release.

5

Like many here already answered It really depends on what the plugin is supposed to do, but here is my base structure:

my-plugin/
    admin/
        holds all back-end administrative files
        js/
            holds all back-end JavaScript files
        css/                    
            holds all back-end CSS files
        images/
            holds all back-end images
        admin_file_1.php        back-end functionality file
        admin_file_2.php        another back-end functionality file 
    js/
        holds all front end JavaScript files
    css/
        holds all fronted CSS files
    inc/
        holds all helper classes
    lang/                   
        holds all translation files
    images/
        holds all fronted images
    my-plugin.php               main plugin file with plugin meta, mostly includes,action and filter hooks
    readme.txt                  
    changelog.txt
    license.txt
4

I am partial to the following plugin layout, however it usually changes depending on what the plugin requirements are.

wp-content/
    plugins/
        my-plugin/
            inc/
                Specific files for only this plugin
                admin/ 
                    Files for dealing with administrative tasks
            lib/
                Library/helper classes go here
            css/
                CSS files for the plugin
            js/
                JS files
            images/
                Images for my plugin
            lang/
                Translation files
        plugin.php 
            This is the main file that calls/includes other files 
        README 
            I normally put the license details in here in addition to helpful information 

I have yet to create a WordPress plugin requiring a MVC style architecture but if I was to do this I would lay it out with a separate MVC directory, which itself contains views/controllers/models.

4

All my plugins follow this structure, which seems to be very similar to what most other devs are doing:

plugin-folder/
    admin/
        css/
            images/
        js/
    core/
    css/
        images/
    js/
    languages/
    library/
    templates/
    plugin-folder.php
    readme.txt
    changelog.txt
    license.txt

plugin-folder.php is then usually a class that loads all required files from the core/ folder. Most often on the init or plugins_loaded hook.

I used to prefix all my files as well, but as @kaiser noted above, it's really redundant and I've recently decided to remove it from any future plugins.

The library/ folder holds all external helper libraries that the plugin might depend on.

Depending on the plugin, there might be an uninstall.php file in the plugin root as well. Most of the time this is being handled via register_uninstall_hook(), though.

Obviously, some plugins might not require any admin files or templates, etc, but the structure above works for me. In the end you just have to find a structure that works for you and then stick with it.

I also have a starter plugin, based on the structure above that I use as a starting point for all my plugins. All I need to do then is do a search/replace for function/class prefixes and off I go. When I was still prefixing my files that was an extra step I had to do (and quite annoying at that), but now I just have to rename the plugin folder and the main plugin file.

4

My logic, the bigger the plugin the more structure I use.
For big plugins I tend to use MVC.
I use this as a starting point and skip what isn't needed.

controller/
    frontend.php
    wp-admin.php
    widget1.php
    widget2.php
model/
    standard-wp-tables.php // if needed split it up
    custom-tabel1.php
    custom-tabel2.php
view/
    helper.php
    frontend/
        files...php
    wp-admin/
        files...php
    widget1/
        file...php
    widget2/
        file...php
css/
js/
image/
library/  //php only, mostly for Zend Framework, again if needed
constants.php //tend to use it often
plugin.php //init file
install-unistall.php  //only on big plugins
1

Also, see this great WP widget boilerplate . It gives great hints as of structures (even if there isn't a class nor folder for separate models).

1

A less common approach to structuring a plugin's files and directories is the file type approach. It's worth mentioning here for completeness:

plugin-name/
    js/
        sparkle.js
        shake.js
    css/
        style.css
    scss/
        header.scss
        footer.scss
    php/
        class.php
        functions.php
    plugin-name.php
    uninstall.php
    readme.txt

Each directory contains files of that type only. It's worth noting that this approach falls short when you have many file types .png .gif .jpg that might be more logically filed under a single directory, images/ for example.

1
0

I've developed a GitHub template repository for WordPress plugins, encapsulating over 10 years of experience into a structured blueprint! 😊

https://github.com/EdwardBock/wordpress-plugin-starterkit

The template adheres to PSR-4 standards to minimize string includes and utilizes namespaces for concise class naming and a templating component class. It also brings a docker compose file to be able to develop the plugin in isolation. But it can also just be placed into an existing project als work fine as well.

Enjoy exploring and feel free to contribute!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.