0

When developing plugins, to avoid using a prefix for all functions and variables, it is common to use a wrapper for the plugin code. I have seen in many places the practice of using a class and I want to compare that to simply using a function as a wrapper.

A. Class wrapper

class Nice_Plugin {
    var $plugin_dir = plugin_dir_url(__FILE__);

    function __contruct() {
        is_admin() ? $this->build_admin() : $this->build_public();
    }
    function build_admin() {
        register_activation_hook(__FILE__, array($this, 'activate'));
        register_deactivation_hook(__FILE__, array($this, 'deactivate'));
        register_uninstall_hook(__FILE__, array($this, 'uninstall'));
    }
    function build_public() {
        add_action('wp_enqueue_scripts', array($this, 'add_scripts'));
        add_action('wp_footer', array($this, 'add_html'));
    }
    public function activate() {}
    public function deactivate() {}
    public function uninstall() {}
    public function add_scripts() {}
    public function add_html() {}
}
new Nice_Plugin();

B. Function wrapper

function nice_plugin() {
    $plugin_dir = plugin_dir_url(__FILE__);

    is_admin() ? build_admin() : build_public();

    function build_admin() {
        register_activation_hook(__FILE__, 'activate');
        register_deactivation_hook(__FILE__, 'deactivate');
        register_uninstall_hook(__FILE__, 'uninstall');
    }
    function build_public() {
        add_action('wp_enqueue_scripts', 'add_scripts');
        add_action('wp_footer', 'add_html');
    }
    function activate() {}
    function deactivate() {}
    function uninstall() {}
    function add_scripts() {}
    function add_html() {}
}
nice_plugin();

I have tested both of these and they work well.

(I want to point out that I am starting to learn about WP development and the structure that I presented here although good for the current needs of my project may need to change for a more complex project. That is why I am asking here for information from people with more experience about what may lie ahead and what would be a better practice to have.)

Although I like classes and OOP, I am leaning towards method B for the following reasons:

  • I think it should be as simple as possible and given two similar solutions, the simpler one is better. If there is no good reason to define a class and create an object, then simply using a function as a wrapper seems better.
  • I have read that themes are mostly procedural based and not class based and the same about WordPress core. I don't like the idea of using classes mostly for plugins alone.

Questions:

  1. Are the above practices both valid?
  2. Is using a class inherently better?

Extra question:

  1. There is something I don't get about case B: how does the hook get the scope of the target function if you only pass it the string name?

For example, if you are in the global scope:

function niceplugin_add_scripts() {}
add_action('wp_enqueue_scripts', 'niceplugin_add_scripts');

In this case, I presume that the string name is used to call the function from the global scope.

But when the function that you pass is located in the scope of the "nice_plugin" function, how is it accessible? How is the scope passed too?

function nice_plugin() {
    function add_scripts() {}
    add_action('wp_enqueue_scripts', 'add_scripts');
}

I tested this and I was surprised when I saw it works.

1 Answer 1

1

Are the above practices both valid?

I've never seen anyone use method B. Functions declared inside functions still need to be unique. Therefore, just because they are declared inside another function does not guarantee that there won't be a name conflict. As far as I can tell, there is no useful purpose in doing this.

Is using a class inherently better?

Yes. Using a class is better. Then you can name the methods whatever you want in the class. Better yet, use namespaces. Then you can use classes as they were intended instead of as pseudo-namespaces.

There is something I don't get about case B: how does the hook get the scope of the target function if you only pass it the string name?

You don't just pass the string. You pass an array:

Static method: [ 'MyClass', 'MyMethod' ]

Non-static method: [ new MyClass(), 'MyMethod' ]

If you use namespaces (as you should), it would be:

Static method: [ '\MyNamespace\MyClass', 'MyMethod' ]

Non-static method: [ new \MyNamespace\MyClass(), 'MyMethod' ]


As an example, suppose we have a file named class-stackexchange-example.php that contains a class called example in the StackExchange namespace as so:

<?php
namespace StackExchange;

class example {
  public function register() {
    //* Do something awesome
  }
}

Now suppose that our main plugin file ( stackexchange-example.php ) wants to hook into the register method on the admin_init hook. To do that we'd add the following to our stackexchange-example.php file:

add_action( 'admin_init', [ new \StackExchange\sample(), 'register' ] );

Assuming you include the required PHP file correctly, this will now call the register method of the sample class in the StackExchange namespace on the admin_init hook.

Namespaces were introduced in PHP 5.3. Unless you have a need to support 5.2, I'd encourage you to use them in new projects.

2
  • Functions defined within "nice_plugin" are accessible outside the function? I did not know PHP functioned that way.
    – AncientRo
    Commented Feb 3, 2017 at 23:48
  • As long as the "nice_plugin" function is called before trying to call function inside the "nice_plugin" function then they are available in the global namespace. Otherwise they won't have been defined yet and PHP will throw an error. Commented Feb 3, 2017 at 23:52

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