0

I'm currently working on writing my first OOP Plugin for Wordpress.

To help out a little bit with structure I looked for, and found, a boiler plate that sets up the basics for me.

In Main.php there's a method that loads JS and CSS assets for admin:

/**
 * Register all of the hooks related to the admin area functionality
 * of the plugin.
 *
 * @since    0.1.0
 * @access   private
 */
private function define_admin_hooks() {

  $plugin_admin = new Admin\Controller( $this->get_plugin_name(), $this->get_version(), $this->get_plugin_path() );

  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );

}

So far, so good. But as my plugin grows in complexity, it feels like this method is gonna get unwieldy with alot of hooks.

Here's an example with a CPT setup and a setting page added

/**
 * Register all of the hooks related to the admin area functionality
 * of the plugin.
 *
 * @since    0.1.0
 * @access   private
 */
private function define_admin_hooks() {

  $plugin_admin = new Admin\Controller( $this->get_plugin_name(), $this->get_version(), $this->get_plugin_path() );

  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_styles' );
  $this->loader->add_action( 'admin_enqueue_scripts', $plugin_admin, 'enqueue_scripts' );


  $interactWithVimeo = new Admin\InteractWithVimeo();
  $this->loader->add_action ( 'admin_init', $interactWithVimeo, 'setCredentials');


  $cpt = new Admin\CustomPostType();

  // Create the custom post type
  $this->loader->add_action ( 'init', $cpt, 'create_post_type' );

  // Remove post row actions
  $this->loader->add_filter ( 'post_row_actions', $cpt, 'remove_row_actions', 10, 2 );



  $settingsPage = new Admin\SettingsPage();

  // Add the settings page to CPT menu
  $this->loader->add_action ( 'admin_menu', $settingsPage, 'add_settings_page' );
}

At this point I'm wondering if it would be better to simply setup the different classes to load their own hooks within themselves to avoid the clutter in Main.php

Such as

/**
 * Register all of the hooks related to the admin area functionality
 * of the plugin.
 *
 * @since    0.1.0
 * @access   private
 */
private function define_admin_hooks() {

  $myExensiveClassWithAlotOfMethods = new Admin\MyExensiveClassWithAlotOfMethods();
  $this->loader->add_action ( 'admin_init', $myExensiveClassWithAlotOfMethods, 'init' );

}

And the init method in the class then contains all the hooks that the class needs.

Is this a bad idea? There seems to be different ways to do it of course. I'm just curious which approach seems to be inline with the boiler plate.

8
  • I flagged this question as off topic and think you'll better be fit to post it on CodeReview. As to what is "inline with the boiler plate" - no idea, you could ask via an issue. I use a similar boilerplate, but with static classes for the actions - makes every add_action a one-liner (and should be better for memory). But will switch to a more "dependancy injection" style soon
    – kero
    Commented Oct 5, 2018 at 12:43
  • 2
    IMHO, a class should only initialize its own hooks, and if the class instantiates other classes, let the classes initialize their own hooks. There are exceptions, but that depend on your code.
    – Sally CJ
    Commented Oct 5, 2018 at 13:19
  • @SallyCJ Would you be able to supply a condensed example of what you mean?
    – INT
    Commented Oct 5, 2018 at 13:20
  • Something like this simplified example. But of course that doesn't use the boilerplate in question. Hope it helps..
    – Sally CJ
    Commented Oct 5, 2018 at 14:39
  • 1
    Here's a brilliant old thread, wordpress.stackexchange.com/questions/70055/…, and answer, wordpress.stackexchange.com/a/166532/144392, regarding initializing classes. I don't know if this helps you with the boiler plate, but at least I learned a lot when reading that thread and answers to it. Commented Oct 21, 2018 at 18:07

1 Answer 1

0

Sally CJ raises a good point in their comment that it is probably better to have each class initialize its own actions and filters.

I've been working with the same boiler plate for some time now and created my own version of this boiler plate on GitHub.

In that version I have a Back\Hooks and a General\Hooks, both Singletons and getting passed the Loader. This is how the General\Hooks looks in one project

<?php

namespace ACME\General;

class Hooks
{
        protected static $instance;
        protected $loader;

        public static function getInstance($loader)
        {
                if (self::$instance === null) {
                        self::$instance = new self($loader);
                }
                return self::$instance;
        }

        protected function __construct($loader)
        {
                $this->loader = $loader;
        }

        public function run()
        {
                $this->addActions();
                $this->addFilters();
        }

        protected function addActions()
        {
                AdvancedCustomFields\Options::add($this->loader);
                $this->loader->addAction('init', Shortcode\News::class, 'init');
                $this->loader->addAction('init', Shortcode\Courses::class, 'init');
                $this->loader->addAction('wp_footer', WooCommerce\Foo::class, 'print_modal');
                // and many more
        }

        protected function addFilters()
        {
                $this->loader->addFilter('the_content', Bar\Baz::class, 'filter_the_content', 999);
                // and many more
        }
}

Now in the case of AdvancedCustomFields\Options I already pass the loader and do the initialization inside that class, doing that for all the other cases would probably be much cleaner.

General\Shortcode\News looks like this

<?php

namespace ACME\General\Shortcode;

class News
{
    public static function init()
    {
        add_shortcode('acme_news', [__CLASS__, 'render']);
    }

    public static function render($raw_atts = [], $content = null, $tag = '')
    {
        $raw_atts = array_change_key_case((array)$raw_atts, CASE_LOWER);
        $atts = shortcode_atts([
            'size' => 'large',
            'amount' => '4',
            'offset' => '0',
            'exclude' => '',
        ], $raw_atts, $tag);

        /* filter $atts */
        $atts['amount'] = intval($atts['amount']);
        $atts['offset'] = intval($atts['offset']);

        /* get result */
        $result = '';
        // actual code, doing WP_Query, etc.
        // never directly outputted but only saved in $result

        return $result;
}

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.