• Hello!

    I spent the last two days reading tons of tutorials for WordPress plugin architecture. The fact that WordPress has been heavily used for so many years results, as you will probably know, in a ton of outdated tutorials. This is not made better by the fact that PHP has evolved from PHP 4.x to now PHP 7.

    Long story short: I am a bit unsure whether what I figured out works for the plugin project I have is really the best way to write a plugin. Creating small but complex bits of code is no problem, but getting the whole “architecture” set up is something I still struggle with. Anyway, I wanted to try to create my complete own system instead of copying together pieces of code from somewhere else. If you could take a look on what I figured out so far and tell me what you think could be improved (or remade), I would be more than happy!

    A small side-information: The plugin will only extend the admin interface functionality.

    File Structure (in plugin-folder):

    • admin
    • partials
    • partial.header.php
    • partial.footer.php
    • screens
    • screen.overview.php
    • screen.anotherpage.php
    • screen.settings.php
    • templates
    • template.overview.php
    • template.anotherpage.pgp
    • template.settings.php
    • includes
    • class.Demoname.php
    • class.DemonamePath.php
    • class.DemonameScreen.php
    • languages
    • demoname-de_DE.mo
    • demoname-de_DE.po
    • demoname.php

    Here is what happens:

    demoname.php in the root-folder does nothing more than include the class.Demoname.php from the “includes”-folder. The class Demoname { } is a singleton-class (I’ve read about the pros and cons and decided to use a singleton). The demoname.php also calls Demoname::getInstance() the first time to ‘create’ the plugin.

    This main classes constructor hooks many of its sibling functions to the corresponding WordPress actions. So Demoname::internationalization for example is hooked to ‘plugins_loaded’ and executes load_plugin_textdomain().

    The function Demoname::createAdminScreens(), hookd to ‘init’, automatically includes all files from admin/screens/ and automatically creates an object for the class contained in each file.

    Those screen.*.php files contain a class looking like this:

    class ScreenOverview extends DemonameScreen {
        protected function setup() {
            $this->setTitle(__('Overview', 'demoname'));
            $this->setSlug('overview');
        }
    }

    The DemonameScreen class, which every screen extends, looks like this:

    abstract class DemonameScreen {
        private $name;
        private $slug;
    
        final public function __construct() {
            $this->setup();
    
            add_action('admin_menu', array($this, 'createMenuPage');
        }
    
        abstract protected function setup();
    
        final protected function setTitle($newTitle) { $this->title = $newTitle; }
    final protected function setSlug($newSlug) { $this->slug = $newSlug; }
    
        final protected function createMenuPage() {
            add_submenu_page( ** Use $this->name and $this->slug to create submenu-page of my plugins main menu page slug, callback is array($this, 'show') ** );
        }
    
        final public function show() {
            ** include partial header **
            ** include template/template. $this->slug .php **
            ** include partial footer
        }
    }

    Parts in stars are pseudo-code since I know it is working and I wanted to simplify it to be understandable without the rest of my code.

    The whole code is working right now, I can add “screens” to my plugin and the templates are loaded and shown on the admin backend accordingly. But yet it doesn’t “feel good” and I can’t tell why. Do you have any suggestions for improvement?

    Thanks a lot in advance for your help!

Viewing 1 replies (of 1 total)
  • Moderator bcworkz

    (@bcworkz)

    I personally don’t think there’s a single architecture that will work well for all plugins you might conceive of. Work, yes; but work well, perhaps not. Some plugins do not warrant a complex screen structure, others certainly do.

    For example, I don’t know if a separate screen and template structure is always warranted, it seems to me that a particular screen and template could be rolled together into a single file in some cases. OTOH, I can see where keeping the functionality separate could be useful in some cases.

    It’s really a judgment call for what’s too much or not enough. One thing you should definitely think about is what code is loaded for any particular request. As you describe things, the main constructor includes all files and creates objects for all screens. Maybe there’s a reason for this that I’m missing, but it seems more efficient to me to only load the code and create objects that are needed for any particular request.

    Everyone works differently, but kudos for thinking seriously about the overall structure before diving into specific code. I’ve seen many plugins where this was an afterthought, if there was any thought at all! I personally would find it difficult to think about architecture without some concept of what the plugin is supposed to do.

    It may seem premature to think about this last item, as it can be managed any time, even as an after thought; but I think it’s important to think about because it may affect the admin screens concept. Seriously consider inserting plenty of action and filter hooks for other devs to be able to modify how your plugin works. No matter how flexible and well thought out you think your plugin is, someone will want to do something different that you never considered or don’t wish to provide for.

    Hooks allow for this to happen cleanly without significant effort on your part. Hooks are a good way to offer flexibility without the need for endless option screens offering minor variants that most users don’t care about. The current user experience philosophy followed by WP core devs is to minimize options offered in admin settings. Aside from items that obviously need user input, nearly all settings are set internally to the most likely default, with filters offered to allow for alteration.

    The result is a clean simple UI that works for almost everyone, but yet those that are so inclined can still alter things by adding simple filters.

Viewing 1 replies (of 1 total)
  • The topic ‘Plugin code design review’ is closed to new replies.