Answers.Body: <p>You need to define the template root (<code>password-global</code>) in your main module file. This is a gotcha when working on site-specific modules instead of plugins – plugins get a template root based on their ID automatically, but modules don't.</p>
  <p>Use <a href="https://docs.craftcms.com/api/v3/craft-web-view.html#event-register-cp-template-roots" rel="nofollow noreferrer">View::EVENT_REGISTER_CP_TEMPLATE_ROOTS</a> to define your template root:</p>
  <pre class="lang-php prettyprint-override"><code>use yii\base\Event;
  use craft\web\View;
  use craft\events\RegisterTemplateRootsEvent;
  
  // put this inside the init() method
  Event::on(
      View::class,
      View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
      function (RegisterTemplateRootsEvent $e) {
          $e-&gt;roots[$this-&gt;id] = __DIR__ . '/src/templates';
      }
  );
  </code></pre>
  <p>See <a href="https://craftcms.com/docs/3.x/extend/template-roots.html" rel="nofollow noreferrer">Template Roots</a> for more information.</p>
  <hr />
  <p>Small sidenote, you don't need to manually keep track of and restore the old template mode afterwards. If you pass a template mode as the third argument to <code>View::renderTemplate</code>, it only applies to this function call:</p>
  <pre class="lang-php prettyprint-override"><code>return \Craft::$app-&gt;view-&gt;renderTemplate(
      'password-global/_formTemplate',
      [],
      \craft\web\View::TEMPLATE_MODE_CP,
  );
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T14:33:24.403Z
Answers.Text: thank you so much for your help with this. It clarifies quite a few things. I did as you indicated: added the template root in the main module's file init(). And in my twig extension file, in the function that should render the temlate I have now `\Craft::$app->view->renderTemplate('password-global/_formTemplate');`
  However, I still get the same error. Not sure what's wrong. 
  Side question: I'm using this on the site's front end. Should I use `EVENT_REGISTER_SITE_TEMPLATE_ROOTS` instead?
Answers.UserDisplayName: mauricio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T14:35:15.613Z
Answers.Text: @mauricio Yes, use EVENT_REGISTER_SITE_TEMPLATE_ROOTS if you need the templates in the frontend. Otherwise they won't be available. Or just use both :)
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T14:36:50.173Z
Answers.Text: @mauricio If it's still not working, try rendering the template with TEMPLATE_MODE_SITE. Not quite sure how custom template roots interact with template modes.
Answers.UserDisplayName: MoritzLost
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T14:48:35.377Z
Answers.Text: hmm, Ok, using now   EVENT_REGISTER_SITE_TEMPLATE_ROOTS, and rendering with TEMPLATE_MODE_SITE. Do you know if there's a way to see what is the root url that got registered in the  module's init()?
Answers.UserDisplayName: mauricio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T17:05:06.103Z
Answers.Text: wow, finally, problem solved(!!)... 
  By chance I saw another post using this registration of the template root:
  ```
  Event::on(
              View::class, 
              View::EVENT_REGISTER_SITE_TEMPLATE_ROOTS, 
              function (RegisterTemplateRootsEvent $e) {
              if (is_dir($baseDir = $this->getBasePath() . DIRECTORY_SEPARATOR . 'templates')) {
                  $e->roots[$this->id] = $baseDir;
                  }
              }
          );
  ```
  The little change in the init made the difference. Thanks for all the input.
Answers.UserDisplayName: mauricio
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T12:56:02.313Z
Answers.LastActivityDate: 2021-10-21T14:35:42.300Z
Answers.LastEditDate: 2021-10-21T14:35:42.300Z
Answers.UserDisplayName: MoritzLost
Answers.Body: <p>For future reference, this is what solved my issue:
  On main class' init() function -- note the <strong>DIRECTORY_SEPARATOR</strong> part:</p>
  <pre><code>Event::on(
              View::class, 
              View::EVENT_REGISTER_SITE_TEMPLATE_ROOTS, 
              function (RegisterTemplateRootsEvent $e) {
              if (is_dir($baseDir = $this-&gt;getBasePath() . DIRECTORY_SEPARATOR . 'templates')) {
                  $e-&gt;roots[$this-&gt;id] = $baseDir;
                  }
              }
          );
  </code></pre>
  <p>This is registering this path:</p>
  <pre><code>/app/modules/abc/passwordglobal/src/templates
  </code></pre>
  <p>And in my twig extension function, there's no need to add the TEMPLATE_MODE_SITE parameter:</p>
  <pre><code> $html = \Craft::$app-&gt;view-&gt;renderTemplate(
                  'password-global/_formTemplate');
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2021-10-21T17:11:59.573Z
Answers.LastActivityDate: 2021-10-21T17:11:59.573Z
Answers.UserDisplayName: mauricio
Body: <p>I know this question has been asked multiple times. I have read all the post on this topic, and craft's docs. But still, I haven't figure out what I'm doing wrong. I would really appreciate a hand here!</p>
  <p>I'm using Craft 3.7, and I am trying to render a template file, which is called from my module's twig extension.</p>
  <p>I have this:</p>
  <p>The template file is in</p>
  <p><code>modules/abc/passwordglobal/src/templates/_formTemplate.twig</code></p>
  <p><code>In app.php:</code></p>
  <pre><code>'modules' =&gt; [
          'password-global' =&gt; abc\passwordglobal\PasswordGlobal::class,
      ],
      'bootstrap' =&gt; ['password-global']
  </code></pre>
  <p>And in my <em>twig extension</em> file, I have a function with this code:</p>
  <pre><code>// ... returns html template;
  $oldMode = \Craft::$app-&gt;view-&gt;getTemplateMode();
  \Craft::$app-&gt;view-&gt;setTemplateMode(View::TEMPLATE_MODE_CP);
  $html = \Craft::$app-&gt;view-&gt;renderTemplate('password-global/templates/_formTemplate');
  \Craft::$app-&gt;view-&gt;setTemplateMode($oldMode);
  
  return $html;
  </code></pre>
  <p>And the error I see:</p>
  <p><strong>Twig Template Loading Error – craft\web\twig\TemplateLoaderException</strong></p>
  <p><strong>Unable to find the template “password-global/templates/_formTemplate”.</strong></p>
  <p>Thank you so much.</p>
  
Tags: <templating><modules>
Title: Unable to find the template
ThreadText: # Unable to find the template
  
  (Asked by: username_0 on 2021-10-21)
  
  I know this question has been asked multiple times. I have read all the post on this topic, and craft's docs. But still, I haven't figure out what I'm doing wrong. I would really appreciate a hand here!
  
  I'm using Craft 3.7, and I am trying to render a template file, which is called from my module's twig extension.
  
  I have this:
  
  The template file is in
  
  `modules/abc/passwordglobal/src/templates/_formTemplate.twig`
  
  `In app.php:`
  
  ```
  'modules' => [
          'password-global' => abc\passwordglobal\PasswordGlobal::class,
      ],
      'bootstrap' => ['password-global']
  
  ```
  
  And in my *twig extension* file, I have a function with this code:
  
  ```
  // ... returns html template;
  $oldMode = \Craft::$app->view->getTemplateMode();
  \Craft::$app->view->setTemplateMode(View::TEMPLATE_MODE_CP);
  $html = \Craft::$app->view->renderTemplate('password-global/templates/_formTemplate');
  \Craft::$app->view->setTemplateMode($oldMode);
  
  return $html;
  
  ```
  
  And the error I see:
  
  **Twig Template Loading Error – craft\web\twig\TemplateLoaderException**
  
  **Unable to find the template “password-global/templates/\_formTemplate”.**
  
  Thank you so much.
  
  **Tags:** templating, modules
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_1 on 2021-10-21. Score: 3 | Accepted answer
  
  You need to define the template root (`password-global`) in your main module file. This is a gotcha when working on site-specific modules instead of plugins – plugins get a template root based on their ID automatically, but modules don't.
  
  Use [View::EVENT\_REGISTER\_CP\_TEMPLATE\_ROOTS](https://docs.craftcms.com/api/v3/craft-web-view.html#event-register-cp-template-roots) to define your template root:
  
  ```php
  use yii\base\Event;
  use craft\web\View;
  use craft\events\RegisterTemplateRootsEvent;
  
  // put this inside the init() method
  Event::on(
      View::class,
      View::EVENT_REGISTER_CP_TEMPLATE_ROOTS,
      function (RegisterTemplateRootsEvent $e) {
          $e->roots[$this->id] = __DIR__ . '/src/templates';
      }
  );
  
  ```
  
  See [Template Roots](https://craftcms.com/docs/3.x/extend/template-roots.html) for more information.
  
  ---
  
  Small sidenote, you don't need to manually keep track of and restore the old template mode afterwards. If you pass a template mode as the third argument to `View::renderTemplate`, it only applies to this function call:
  
  ```php
  return \Craft::$app->view->renderTemplate(
      'password-global/_formTemplate',
      [],
      \craft\web\View::TEMPLATE_MODE_CP,
  );
  
  ```
  
  > **Comments:**
  > **username_0**: thank you so much for your help with this. It clarifies quite a few things. I did as you indicated: added the template root in the main module's file init(). And in my twig extension file, in the function that should render the temlate I have now `\Craft::$app->view->renderTemplate('password-global/_formTemplate');` However, I still get the same error. Not sure what's wrong.  Side question: I'm using this on the site's front end. Should I use `EVENT_REGISTER_SITE_TEMPLATE_ROOTS` instead?  
  > **username_1**: @username_0 Yes, use EVENT_REGISTER_SITE_TEMPLATE_ROOTS if you need the templates in the frontend. Otherwise they won't be available. Or just use both :)  
  > **username_1**: @username_0 If it's still not working, try rendering the template with TEMPLATE_MODE_SITE. Not quite sure how custom template roots interact with template modes.  
  > **username_0**: hmm, Ok, using now   EVENT_REGISTER_SITE_TEMPLATE_ROOTS, and rendering with TEMPLATE_MODE_SITE. Do you know if there's a way to see what is the root url that got registered in the  module's init()?  
  > **username_0**: wow, finally, problem solved(!!)...  By chance I saw another post using this registration of the template root: ``` Event::on(             View::class,              View::EVENT_REGISTER_SITE_TEMPLATE_ROOTS,              function (RegisterTemplateRootsEvent $e) {             if (is_dir($baseDir = $this->getBasePath() . DIRECTORY_SEPARATOR . 'templates')) {                 $e->roots[$this->id] = $baseDir;                 }             }         ); ``` The little change in the init made the difference. Thanks for all the input.  
  
  ---
  
  ### Answer by username_0 on 2021-10-21. Score: 3
  
  For future reference, this is what solved my issue:
  On main class' init() function -- note the **DIRECTORY\_SEPARATOR** part:
  
  ```
  Event::on(
              View::class, 
              View::EVENT_REGISTER_SITE_TEMPLATE_ROOTS, 
              function (RegisterTemplateRootsEvent $e) {
              if (is_dir($baseDir = $this->getBasePath() . DIRECTORY_SEPARATOR . 'templates')) {
                  $e->roots[$this->id] = $baseDir;
                  }
              }
          );
  
  ```
  
  This is registering this path:
  
  ```
  /app/modules/abc/passwordglobal/src/templates
  
  ```
  
  And in my twig extension function, there's no need to add the TEMPLATE\_MODE\_SITE parameter:
  
  ```
   $html = \Craft::$app->view->renderTemplate(
                  'password-global/_formTemplate');
  
  ```
  
  
  ---
  
  