mybb2 icon indicating copy to clipboard operation
mybb2 copied to clipboard

Template hook system

Open euantorano opened this issue 7 years ago • 12 comments

Template hook system, allowing plugins and modules to easily output and modify template content without requiring edits to templates (removing the requirement for find_replace_templatesets). This should be less prone to error and make managing themes much easier (installing a new theme should mean that plugins just work).

euantorano avatar Sep 30 '17 16:09 euantorano

Is this still required? I'm willing to put something together if needed?

1e4 avatar Dec 04 '17 16:12 1e4

It would be great, yeah. Currently our focus is on 1.10 where we will hopefully manage to backport this feature.

On 4 Dec 2017, at 16:34, Ian [email protected] wrote:

Is this still required? I'm willing to put something together if needed?

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub, or mute the thread.

euantorano avatar Dec 04 '17 16:12 euantorano

I built a hook system a few months back, pretty simple so I can create a PR when I get a chance.

1e4 avatar Dec 06 '17 14:12 1e4

Sounds awesome, I'll quickly outline the kind of thing I'm hoping for 😄

  • A Twig function that can be used in any view, something like the following (each hook has a name - the header_welcomeblock_member_end hook is just an example here):
{{ hook('header-welcomeblock_member_end') }}
  • A central TemplateHookManager (or something) where plugins and modules can register functions to run at a given hook. These functions should return a string that contains HTML content to be displayed (this string could be a rendered Twig view or just raw HTML):
$hookManager = app('template_hooks;); // Example of the hook manager's registered name in the DI
$hookManager->addHook('header-welcomeblock_member_end', function(\Twig_Environment $twig) {
    // do some stuff and return a rendered view here
    return $twig->render('foo');
});
  • Hooked functions should have priorities, to decide which one runs first. This would be an optional third parameter to TemplateHookManager::addHook().
  • It would be awesome if there were implicit hooks at the start/end of each view. I don't know if this is possible as I haven't looked into it at all, but it would be great to add code to the start or end of any view without there being an explicit hook there.

I can't think of anything else at the moment - perhaps @Eric-Jackson or @justinsoltesz have some items on their wishlist (or anybody else out there - feel free to chime in with your wishes!). THe naming of things is always the hardest part I find, so feel free to use names other than TemplateHookManager and such :smile:

euantorano avatar Dec 06 '17 14:12 euantorano

Sounds good, below is what I hacked together a few months ago for a project, with a little tweaking and exposing the methods to Twig it should be golden. I need to add priority, basically just sort the array. I'll write a checklist at the end, if you can confirm then I can put it in MyBB

<?php

class HookContainer {

    /**
     * Object container all hooks that are enabled
     *
     * @var array
     */
    private $hooks;

    public function __construct()
    {

        // Get all the hooks and store them
        $this->hooks = Hooks::enabled();
    }


    /**
     * Run the hooks
     *
     * @param $location
     * @param array ...$args
     */
    public function run($location, ...$args)
    {

        $this->execute('hook_before', $args);
        $this->execute($location, $args);
        $this->execute('hook_after', $args);

    }

    /**
     * Wrapper for blade directives so we can show visible hooks
     *
     * @param $location
     * @param array ...$args
     */
    public function display($location, ...$args)
    {

        if(($debug = app('settings')->where('key', '=', 'debug')->first()) !== null)
        {
            if($debug->value === "1")
                echo view('partials.hook', [
                    'location'  =>  $location
                ]);
        }

        $this->execute('hook_before', $args);
        $this->execute($location, $args);
        $this->execute('hook_after', $args);
    }

    /**
     * Execute the hook location
     *
     * @param $location
     * @param array ...$args
     */
    public function execute($location, ...$args)
    {

        // Get hooks based on the location
        $hooks = $this->hooks;

        logDebug("Hook Location: {$location}");
        

        if(count($hooks) > 0) {
            // Loop through and execute each one
            foreach ($hooks as $hook) {
                foreach($hook->locations as $loc)
                {
                    if($loc->location !== $location)
                        continue;

                    $className = $loc->namespace;

                    // Find the class
                    $class = new $className(...$args);

                    // Add some friendly debug
                    logDebug([
                        "hook"=>[
                            "name"      =>  $hook->name,
                            "class"     =>  $className,
                            "location"  =>  $location,
                            "args"      =>  $args
                        ]
                    ], 'hooks');
                    $func = $loc->method;

                    // Allow the plugin to return a view or text or whatever
                    echo $class->$func();
                }


            }
        }
    }

}

I named it HookContainer as it contains all the hooks - this isn't limited to templates, I exposed it via IoC then wrapped a helper method so I could essentially do hook()->display('header') for example.

  • [ ] Add priorities

  • [ ] Integrate into twig

  • [ ] Add a helper method into MyBB to easily call hooks

  • [ ] Admin section to handle hooks?

  • [ ] Migrations

Is that correct?

1e4 avatar Dec 07 '17 22:12 1e4

@euantorano Hope you don't mind the little bump

1e4 avatar Dec 14 '17 09:12 1e4

Sorry, I somehow missed the notification for your reply @1e4!

Looks good to me. The only points I see are:

  • I'm not a big fan of facades for loading hooks - a repository injecting into the constructor would be nice 😄
  • An admin section would be nice, but shouldn't be a priority. Very little work has been done on the ACP, so it can always get added later on.

euantorano avatar Dec 14 '17 19:12 euantorano

No problem @euantorano, there are also no Facades. The Hooks::enabled() is a model with a static method. The hook() function simply get's the Hook instance from the Container. I'll try and carve some time out and get this in this week :)

1e4 avatar Dec 17 '17 18:12 1e4

Afternoon @euantorano Christmas & New Year were busier than I expected, I'll look at making progress on it this week and keep you posted.

1e4 avatar Jan 02 '18 16:01 1e4

Happy new year!

No problem, I know that feeling for sure 😀

On 2 Jan 2018, at 16:23, Ian [email protected] wrote:

Afternoon @euantorano Christmas & New Year were busier than I expected, I'll look at making progress on it this week and keep you posted.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

euantorano avatar Jan 02 '18 16:01 euantorano

Happy New Year @euantorano I hope MyBB 2 gets a BETA this year ^_^, hoping to contribute as much as I can to make this happen

1e4 avatar Jan 02 '18 16:01 1e4

The current focus is upon 1.9, 1.10 and other incremental steps in the 1.x line due to community demand.

On 2 Jan 2018, at 16:42, Ian [email protected] wrote:

Happy New Year @euantorano I hope MyBB 2 gets a BETA this year ^_^, hoping to contribute as much as I can to make this happen

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub, or mute the thread.

euantorano avatar Jan 02 '18 16:01 euantorano