HackerOne users: Testing against this community violates our program's Terms of Service and will result in your bounty being denied.

How to use a custom module in a custom theme?

I've created a class.testmodule.php that I've put in /themes/mytheme/modules at first, but using {module name="TestModule"} gave me a "Error: TestModule doesn't exist" message.

I've tried it again after I moved that file to /themes/mytheme, but that wasn't helpful. I had no luck with that, too.

In class.theme.php where the error is generated, I've added a small decho(get_declared_classes()); in order to see if I had a dumb typo, but the sad truth is, that my module isn't loaded. To I have to include it "manually" in the themehooks or is there a better place than I have chosen where it would be autoloaded?

Best Answers

  • noncenonce Necro-on Forensics
    edited March 2016 Answer ✓

    apparently you asked the question before as indicated by the above answer. but you are still not satisfied.
    here is more info to help you and your kinfolk.

    you said: I'm more interested in where the class auto loading happens.

    I have looked at the code, read the tutorials, and searched the discussions.

    first - lets give some information.

    look in your cache folder.

    notice all the files.
    some start with a, p, or even possibly t.

    a is for applications
    p is for plugins
    t is for themes

    dashboard, core, library should all be self explanatory. these map names with folder location.
    you will see a variety of classes, modules, and models.

    if you don't see your module or class it is not mapped or registered in the cache. simple enough.

    now a code walk though for you.

    modules from themes are not mapped or cached in the ini files as are library modules and plugin modules. p is for plugin d is for dashboard,

    here is a code walk through. I won't answer why it is not part of the core, you can debate among yourselves.

    the index.php is called first and contains
    // Include the bootstrap to configure the framework.
    require_once(PATH_ROOT.'/bootstrap.php');

    the bootstrap.php is called and Theme Startup and Autoloading.

    // Themes startup
    Gdn::themeManager()->start();
    Gdn_Autoloader::attach(Gdn_Autoloader::CONTEXT_THEME);

    now it looks at the autoloader.php after theme manager functions are available.

    in the autoloader.php

    there are three case statements referring to plugins, apps, and themes.
    you will see the plugins are "mapped and registered" via RegisterMap in in attach method
    you will see the apps are "mapped and registered" via RegisterMap in in attach application method
    you will see the themes are essentially ignored and just a break appears.

    simply

    case self::CONTEXT_THEME:
    break;

    if you look at apps you see

        $AppModules = combinePaths(array($ApplicationPath."/modules"));
        self::registerMap(self::MAP_LIBRARY, self::CONTEXT_APPLICATION, $AppModules, array(
            'SearchSubfolders' => false,
            'Extension' => $Application,
            'ClassFilter' => '*module'
        ));
    

    fot themes, if you modified the core you would add
    self::RegisterMap(Gdn_Autoloader::MAP_LIBRARY, Gdn_Autoloader::CONTEXT_THEME, 'themes/'.Gdn::themeManager()->currentTheme );

    before the break statement.

    but you could also use a similar RegisterMap method for your theme Gdn_Autoloader::RegisterMap .... in conf/bootstrap.after.php, the thememanager is processed or by themehooks, which is what you asked in the first place and is answered by previous poster. Themehooks is a better approach, alternate method is a teaching experience.

    you can use getallclasses to debug, but you could have looked at the ini files and their mappings.

    a_dashboard_library_map.ini

    a is for application
    dashboard related
    library

    p_core_library_map.ini

    p is for plugin related modules, classes and models.

    notice how plugins that are not enabled have modules mapped in the cache.

    after you use the register map for your theme you will notice

    t_library_map.ini if you chose library as the Map Type and Context as Theme.

    I hope this helps you in one way or another.

Answers

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    I added my modules to my theme in a modules folder in views folder.

    For tpl you may need to use this in the themehooks

     public function DiscussionsController_Render_Before($Sender){
    
        if (IsMobile()) {
       return;
      }
      else {
       $Module1 = new Module1($Sender);
       $Sender->AddModule($Module1);
       $Module2 = new Module2($Sender);
       $Sender->AddModule($Module2);
       $Module3 = new Module3($Sender);
       $Sender->AddModule($Module3);
       $Module4 = new Module4($Sender);
       $Sender->AddModule($Module4);
       $Module5 = new Module5($Sender);
       $Sender->AddModule($Module5);
    
    
      }
     }
    
  • R_JR_J Ex-Fanboy Munich Admin

    Thanks, @vrijvlinder. But if I add a custom smarty function, the module and another custom smarty function, I'd have to insert a custom fireEvent in order to use your recommendation. I think it is a workaround which would be okay to use but I'm also technically interested.

    I'm more interested in where the class auto loading happens. Should/Must the theme folder be added somewhere or must some mechanism be used for themes, too? Or is this overkill? Do I have to auto load by myself out simply include it? I haven't tested it, but would it be "early" enough to include it in base_render_before or what would be the best place to take care for that?

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    For one, I think the modules folder need to be in the views folder.

  • R_JR_J Ex-Fanboy Munich Admin

    I think the views folder can be used if I override an existing module. I've tried to copy my module there but that was not working, either...

  • noncenonce Necro-on Forensics
    edited March 2016 Answer ✓

    apparently you asked the question before as indicated by the above answer. but you are still not satisfied.
    here is more info to help you and your kinfolk.

    you said: I'm more interested in where the class auto loading happens.

    I have looked at the code, read the tutorials, and searched the discussions.

    first - lets give some information.

    look in your cache folder.

    notice all the files.
    some start with a, p, or even possibly t.

    a is for applications
    p is for plugins
    t is for themes

    dashboard, core, library should all be self explanatory. these map names with folder location.
    you will see a variety of classes, modules, and models.

    if you don't see your module or class it is not mapped or registered in the cache. simple enough.

    now a code walk though for you.

    modules from themes are not mapped or cached in the ini files as are library modules and plugin modules. p is for plugin d is for dashboard,

    here is a code walk through. I won't answer why it is not part of the core, you can debate among yourselves.

    the index.php is called first and contains
    // Include the bootstrap to configure the framework.
    require_once(PATH_ROOT.'/bootstrap.php');

    the bootstrap.php is called and Theme Startup and Autoloading.

    // Themes startup
    Gdn::themeManager()->start();
    Gdn_Autoloader::attach(Gdn_Autoloader::CONTEXT_THEME);

    now it looks at the autoloader.php after theme manager functions are available.

    in the autoloader.php

    there are three case statements referring to plugins, apps, and themes.
    you will see the plugins are "mapped and registered" via RegisterMap in in attach method
    you will see the apps are "mapped and registered" via RegisterMap in in attach application method
    you will see the themes are essentially ignored and just a break appears.

    simply

    case self::CONTEXT_THEME:
    break;

    if you look at apps you see

        $AppModules = combinePaths(array($ApplicationPath."/modules"));
        self::registerMap(self::MAP_LIBRARY, self::CONTEXT_APPLICATION, $AppModules, array(
            'SearchSubfolders' => false,
            'Extension' => $Application,
            'ClassFilter' => '*module'
        ));
    

    fot themes, if you modified the core you would add
    self::RegisterMap(Gdn_Autoloader::MAP_LIBRARY, Gdn_Autoloader::CONTEXT_THEME, 'themes/'.Gdn::themeManager()->currentTheme );

    before the break statement.

    but you could also use a similar RegisterMap method for your theme Gdn_Autoloader::RegisterMap .... in conf/bootstrap.after.php, the thememanager is processed or by themehooks, which is what you asked in the first place and is answered by previous poster. Themehooks is a better approach, alternate method is a teaching experience.

    you can use getallclasses to debug, but you could have looked at the ini files and their mappings.

    a_dashboard_library_map.ini

    a is for application
    dashboard related
    library

    p_core_library_map.ini

    p is for plugin related modules, classes and models.

    notice how plugins that are not enabled have modules mapped in the cache.

    after you use the register map for your theme you will notice

    t_library_map.ini if you chose library as the Map Type and Context as Theme.

    I hope this helps you in one way or another.

  • vrijvlindervrijvlinder Papillon-Sauvage MVP

    You must be a reincarnation of someone I know... because you certainly do not "flounder" around...and give concise and enlightening answers... reminds me of the old days when I first started here... thanks for that ;)

  • R_JR_J Ex-Fanboy Munich Admin

    That's kind of embarrassing. Sorry for repeating myself and forgetting good advices :confounded:

  • vrijvlindervrijvlinder Papillon-Sauvage MVP
    edited March 2016

    It's never too late to learn from your own questions.... :P

  • R_JR_J Ex-Fanboy Munich Admin

    @nonce said:
    apparently you asked the question before as indicated by the above answer. but you are still not satisfied.

    Nope, I'm only forgetful.

    @nonce said:
    I hope this helps you in one way or another.

    You bet! Now I understand why theme classes are not autoloaded!

    If anyone is interested: think of a theme with a class.examplemodule.php and a mobile theme with class.examplemodule.php. Classes are mapped when they are accessed first. So depending on the users client who visits the site first, it would be either mapped to the module in the mobile or in the desktop version. The current implementation must be extended to always take care of the current theme of the current user.

    The need for making this changed hasn't aroused by now, so implementing something without needing it is not the best idea.

    My learning from that: if you use classes in your theme, give them unique names. If your theme is called "groovy" and you would like to create "fancymodule", consider naming it "groovyfancymodule".

Sign In or Register to comment.