• June 12, 2013, 6:19 p.m.

    While its still pretty early, I'm constantly thinking on making Misago extensible. I've created issue for 0.6 that I intend to eventually become plan for adding extensibility to Misago:

    github.com/rafalp/Misago/issues/138

    For starters, Misago itself is de facto extension for Django, but its not written to be "reuseable" Django App. You won't be able to add forum to your project by simply adding 'misago' to your project INSTALLED_APPS setting. It can be argued if writing project on higher level of abstraction is good or bad, but this thread is not a place for it.

    On other side, Django comes in with many hooks on its own that Misago uses to provide necessary functionalities. There is middleware framework that allows you to write code that has to be executed before or after response is created. There are context processors that allow you to inject additional variables into rendered templates. Then there are also signals that allow you to write code that has to react to certain events like new user creation or thread deletion.

    Finally there's INSTALLED_APPS settings that allows you to expose your django app to Django thus making your models visible for database management utilities, and then you have ROOT_URLCONF setting that allows you to decide which links setting to use, thus creating your own URL setting that will extend Misago's one.

    Starting from there, Misago provides its own extra hooks for adding code. Currently you have PERMISSION_PROVIDERS that allows you to extend Misago ACL system with new permission types, USERCP_EXTENSIONS for adding new tabs for user control panels, PROFILE_EXTENSIONS for adding new tabs to user profile lists and MARKDOWN_EXTENSIONS for adding new items to user posts. Finally, you can add custom admin actions to ACP by creating admin.py module in your app that defines custom ADMIN_SECTIONS and ADMIN_ACTIONS like Misago admin actions already do.

    Once this all is summed, Misago is already pretty extensible, but theres much more to be done before I would truly call extensibility "allright". Over course of days I'll be posting ideas and props for new features that would make Misago more friendly for plugin developers.

  • June 12, 2013, 7:28 p.m.

    1. Template Middlewares

    Problem: Plugins must have ways to inject template-specific variables on template render

    Following Django's example, simple middlewares system could be put in place for plugins to use. Middleware would be provided with current request object, template name that Misago is going to render and template context that will be used in rendering. Middleware method would return either nothing or changed template context that Misago would use in rendering. Then second pass will be done. This time middlewares will be asked if they want to use different template file and first middleware to return string with new template name will break the loop and cause new template to render.

    Such middlewares system is easy to implement and quick to run, so I don't see many troubles from including it even in 0.3 release. Adding hooks to templates for plugins to use is different story however. In theory I could start with most basic hooks that would allow extensions to add custom nav links to forum's header and footer nav's and then include new hooks as people request them.

    Update

    And so template middleware framework is already in develop branch. In order to use it write your own middleware and make it known to Misago by including path to it in 'TEMPLATE_MIDDLEWARES' setting.

    Example middleware looks like this:

    class ExampleMiddleware(object):
        def process_context(self, theme, templates, context):
            """
            Optional, use this method to modify context that will
            be passed to target template when its rendered.
    
            Should return dict-like object or nothing.
            """
            pass
    
        def process_template(self, theme, templates, context):
            """
            Optional, use this method to change template that will be rendered
            by Misago. Those methods are called until one returns string or
            tuple with template names.
    
            Should return string, tuple or nothing.
            """
            pass
    

    Both methods are optional. process_context is called before process_template.
    Middlewares always take three arguments:

    • theme - theme helper, allows middlewares to render templates into other templates context dicts.
    • templates - string or tuple with templates that Misago is going to render using passed context. You can use this to limit your middleware only to specific pages.
    • context - template context, depending on origin this will be dictionary or dict-like object. It's complete context that was ran trough context_processors, and so it can be used as surrogate for request object for your middleware.

    Available Hooks

    Currently Misago implements following hooks for those interested in playing with template middlewares:

    base.html - Layout Container

    • hook_append_extra - Right before closing </body> tag. Allows for adding extra site-wide scripts or fixed html.

    layout.html - Forum Layout

    • hook_primary_menu_prepend - In primary menu after "Board Index" link.
    • hook_primary_menu_append - In primary menu after all other links.
    • hook_foot_menu_prepend - In footer menu before "Forum Map" link.
    • hook_foot_menu_append - In footer menu after "Forum Map" link.
    • hook_guest_menu_prepend - In guest menu before "Sign In" link.
    • hook_guest_menu_append - In guest menu after"Sign In" link.
    • hook_user_menu_prepend - In user menu between "Alers" link and Username.
    • hook_user_menu_append - In guest menu before "Sign Out" link.
    • hook_credits_side - Right side of forum credits. This forum uses this hook for Github and PayPal buttons

    index.html - Board Index

    • hook_above_forum_home - Above everything else.
    • hook_below_forum_home - Below everything else.
    • hook_above_home_forums_list - Above forums list.
    • hook_below_home_forums_list - Below forums list.
    • hook_above_home_sidepanel - Above sidepanel.
    • hook_after_home_sidepanel_ranks_online - In sidepanel, under "Ranks Online".
    • hook_after_home_sidepanel_popular_threads - In sidepanel, under "Popular Threads".
    • hook_after_home_sidepanel_forum_stats - In sidepanel, under forum statistics.
    • hook_below_home_sidepanel - In sidepanel, below everything else.

    Every hook is defautly empty unicode string. To display something in this hook, simply append or prepend unicode string to its contents. Those variables are trusted in order to allow your plugins to render HTML. For this reason middlewares are provided with theme helper that comes with render_to_string(template, variables) method that allows you to render other templates into hook variables.

    Naturally you are not limited to or forced to do adding html to hooks. If you want to, you can instead modify other variables in context and then in make Misago use different template to render page.

    Finally, instead of checking for template name in templates argument, you can check context for presence of hook variable. Standard hooks will be always included into template context for you to know what hooks are currently available.