Answers.Body: <p>Alright, if you didn't already create a custom plugin I suggest you to visit <a href="http://pluginfactory.io" rel="nofollow noreferrer">Pluginfactory.io</a> to create the boilerplate. Let's assume your plugin handle is <code>awesome-plugin</code>, just for testing purposes.</p>
  
  <p>You create a controller with the name <code>RouteController</code> that contains the function <code>actionMyAwesomeRoute</code></p>
  
  <h3>In summary:</h3>
  
  <p><em>handle</em>: <code>awesome-plugin</code><br>
  <em>controller</em>: <code>RouteController</code><br>
  <em>function</em>: <code>actionMyAwesomeRoute</code></p>
  
  <p>All routes in Craft are defined via <code>plugin-handle/controller-name/function-name</code> without the "required" parts - and in <code>snake-case</code></p>
  
  <p>That means your route will be <code>awesome-plugin/route/my-awesome-route</code> (remove "Controller" and "action")</p>
  
  <p>That being said: you can register your routes in your Plugins main init function</p>
  
  <h3>Defining the routes</h3>
  
  <pre><code>public function init(){
  
      Event::on(
          UrlManager::class,
          UrlManager::EVENT_REGISTER_SITE_URL_RULES,
          function(RegisterUrlRulesEvent $event) {
              // easy route for demonstration
              $event-&gt;rules[] = [
                  'pattern' =&gt; '/some-nice-url',
                  'route'   =&gt; 'awesome-plugin/route/my-awesome-route'
              ];
              // when you visit www.example.com/some-nice-url your function will be executed
  
              // more complex example if you are not interested
              // skip that and don't think about it
              $event-&gt;rules[] = [
                  'pattern' =&gt; 'my-fancy-route/&lt;action:&gt;/&lt;id:\d+&gt;/&lt;siteHandle:\w+&gt;', 
                  'route' =&gt; 'awesome-plugin/route/&lt;action&gt;', 
                  'defaults' =&gt; [
                      'id' =&gt; null, 
                      'siteHandle' =&gt; null, 
                      'action' =&gt; 'index'
                  ]
              ];
              // you can visit this route via www.example.com/my-fancy-route
              // this way, your actionIndex will be called
              // when you do www.example.com/my-fancy-route/foo
              // Craft tries to call the actionFoo in your Controller
              // www.example.com/my-fancy-route/bar -&gt; actionBar
  
              // when you do www.example.com/my-fancy-route/edit/5
              // your actionEdit will be called and Craft passes 5 as a parameter
  
              // www.example.com/my-fancy-route/save-entry/9/siteOne
              // will call actionSaveEntry(9, 'siteOne');
  
          }
      }
  }
  </code></pre>
  
  <h3>Your Controller</h3>
  
  <pre><code>public function actionMyAwesomeRoute(){
      $variables = // define whatever you want
  
      return $this-&gt;renderTemplate('path/to/template', $variables);
  }
  </code></pre>
  
  <h3>More complex examples, skip that if you don't need it</h3>
  
  <pre><code>// www.example.com/my-fancy-route/show-entry/9/siteOne
  public function actionShowEntry($id = null, $siteHandle = null){
      // $id will be 9, $siteHandle 'siteOne' since those parameters
      // are passed via URL, otherwise they are both null
      $entry = Craft::$app-&gt;getElements()-&gt;getElementById($id, $siteHandle);
  
      return $this-&gt;renderTemplate('path/to/template',  ['entry' =&gt; $entry]);
  }
  </code></pre>
  
  <h3>Just a little bit more complex stuff</h3>
  
  <p>You could actually use the default route and inject it with another parameter as well. So When you have an existing route to an entry like <code>news/2018/feb/awesome-news/</code> you can as well visit this entry with <code>news/2018/feb/awesome-news/fooBar</code></p>
  
  <pre><code>$event-&gt;rules[] = [
      'pattern' =&gt; '/&lt;route:\S+&gt;/&lt;something:\S+&gt;',
      'route'   =&gt; 'awesome-plugin/route/catch-all'
  ];
  </code></pre>
  
  <p>And in your Controller</p>
  
  <pre><code>public function actionCatchAll($route, $something){
      $entry = Craft::$app-&gt;getElements()-&gt;getElementByUri($route);
      if ($entry instanceof Entry) {
          $section = $event-&gt;getSection();
          $siteSettings = $section-&gt;getSiteSettings();
          foreach ($siteSettings as $site) {
              if ((int) $site-&gt;siteId === (int) $entry-&gt;siteId) {
                  $templatePath = $site-&gt;template; // the template path for the entry
                  return $this-&gt;renderTemplate(
                      $templatePath,
                          [
                              'entry'     =&gt; $entry,
                              'whatever'  =&gt; $something
                          ]
                      );
              }
          }
      }
  
      return Craft::$app-&gt;runAction(Craft::$app-&gt;getRequest()-&gt;getFullPath());
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-06-06T18:06:58.993Z
Answers.Text: Great, I got it, the explanation is perfect for my level. Yes I had created a custom plugin but I had only created template variables and services and thought of Controllers somehow else. Will come back when I test this with any question. Thank you again.
Answers.UserDisplayName: Rosana Ruiz
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-06-06T18:08:59.343Z
Answers.Text: It became a wall of text, just pick the information you need and ignore the rest or keep it in mind if you ever need it^^ I thought it could be a compilation of useful information
Answers.UserDisplayName: Robin Schambach
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-06-10T10:56:48.637Z
Answers.Text: Here I define a custom route and add my template variable for those routes, but the variable is informed only for the routes that match my custom route. I would like that variable to be informed also for all the site requests that are handled by Craft. I have tried using the same approximation (adding a rule that matches all routes) but Craft catches the entry requests before my Controller rules are reached. Is it possible to add extra variables to requests handled by Craft or override Craft's? Thank you
Answers.UserDisplayName: Rosana Ruiz
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-06-10T11:00:47.453Z
Answers.Text: You need to add a global somewhere. If it's really for all requests, no matter what you can do it in your plugins init function `Craft::$app->getView()->getTwig()->addGlobal('foo', $bar)`. Then you can access `{{ foo }}`
Answers.UserDisplayName: Robin Schambach
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2018-06-06T17:59:14.460Z
Answers.LastActivityDate: 2018-06-06T18:13:18.767Z
Answers.LastEditDate: 2018-06-06T18:13:18.767Z
Answers.UserDisplayName: Robin Schambach
Body: <p>I have several custom routes defined on the <code>routes.php</code> and, as usual, I am resolving the value of the template's <code>entry</code> in the Twig template when it is not defined (which is when it doesn't match a Craft Route) but I'd like to do it somewhere else before it reaches the template because I want to <strong>remove the logic in Twig</strong>. </p>
  
  <p>Can I add a method to be executed before last Craft's <code>renderTemplate($template, $variables)</code> in which I would resolve and add $entry to $variables when it's not defined? What's the way to go?</p>
  
  <p>Thank you :)</p>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-06-06T17:35:57.393Z
Comments.Text: Would it be an option for you to create a custom Controller in the first place? These things are usually done via Controller route instead of template route
Comments.UserDisplayName: Robin Schambach
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-06-06T17:37:06.117Z
Comments.Text: @RobinSchambach Yes, I am open to using a Controller, but I don't know how would I make Craft to redirect my custom routes requests to the controller...
Comments.UserDisplayName: Rosana Ruiz
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-06-06T17:39:43.563Z
Comments.Text: @RobinSchambach Oh, I think you mean I won't be defining the routes on `routes.php`... I'm going to read about Controller routing. Thanks
Comments.UserDisplayName: Rosana Ruiz
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2018-06-06T18:15:11.700Z
Comments.Text: You can define the route in your `routes.php` as well, it's actually the same, it doesn't matter where you define the route, as long as you define it.
Comments.UserDisplayName: Robin Schambach
Tags: <routes>
Title: Resolving the $entry variable for custom routes somewhere but a Twig template
ThreadText: # Resolving the $entry variable for custom routes somewhere but a Twig template
  
  (Asked by: username_0 on 2018-06-06)
  
  I have several custom routes defined on the `routes.php` and, as usual, I am resolving the value of the template's `entry` in the Twig template when it is not defined (which is when it doesn't match a Craft Route) but I'd like to do it somewhere else before it reaches the template because I want to **remove the logic in Twig**.
  
  Can I add a method to be executed before last Craft's `renderTemplate($template, $variables)` in which I would resolve and add $entry to $variables when it's not defined? What's the way to go?
  
  Thank you :)
  
  **Tags:** routes
  
  > **Comments:**
  > **username_1**: Would it be an option for you to create a custom Controller in the first place? These things are usually done via Controller route instead of template route  
  > **username_0**: @username_1 Yes, I am open to using a Controller, but I don't know how would I make Craft to redirect my custom routes requests to the controller...  
  > **username_0**: @username_1 Oh, I think you mean I won't be defining the routes on `routes.php`... I'm going to read about Controller routing. Thanks  
  > **username_1**: You can define the route in your `routes.php` as well, it's actually the same, it doesn't matter where you define the route, as long as you define it.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2018-06-06. Score: 5 | Accepted answer
  
  Alright, if you didn't already create a custom plugin I suggest you to visit [Pluginfactory.io](http://pluginfactory.io) to create the boilerplate. Let's assume your plugin handle is `awesome-plugin`, just for testing purposes.
  
  You create a controller with the name `RouteController` that contains the function `actionMyAwesomeRoute`
  
  ### In summary:
  
  *handle*: `awesome-plugin`  
  *controller*: `RouteController`  
  *function*: `actionMyAwesomeRoute`
  
  All routes in Craft are defined via `plugin-handle/controller-name/function-name` without the "required" parts - and in `snake-case`
  
  That means your route will be `awesome-plugin/route/my-awesome-route` (remove "Controller" and "action")
  
  That being said: you can register your routes in your Plugins main init function
  
  ### Defining the routes
  
  ```
  public function init(){
  
      Event::on(
          UrlManager::class,
          UrlManager::EVENT_REGISTER_SITE_URL_RULES,
          function(RegisterUrlRulesEvent $event) {
              // easy route for demonstration
              $event->rules[] = [
                  'pattern' => '/some-nice-url',
                  'route'   => 'awesome-plugin/route/my-awesome-route'
              ];
              // when you visit www.example.com/some-nice-url your function will be executed
  
              // more complex example if you are not interested
              // skip that and don't think about it
              $event->rules[] = [
                  'pattern' => 'my-fancy-route/<action:>/<id:\d+>/<siteHandle:\w+>', 
                  'route' => 'awesome-plugin/route/<action>', 
                  'defaults' => [
                      'id' => null, 
                      'siteHandle' => null, 
                      'action' => 'index'
                  ]
              ];
              // you can visit this route via www.example.com/my-fancy-route
              // this way, your actionIndex will be called
              // when you do www.example.com/my-fancy-route/foo
              // Craft tries to call the actionFoo in your Controller
              // www.example.com/my-fancy-route/bar -> actionBar
  
              // when you do www.example.com/my-fancy-route/edit/5
              // your actionEdit will be called and Craft passes 5 as a parameter
  
              // www.example.com/my-fancy-route/save-entry/9/siteOne
              // will call actionSaveEntry(9, 'siteOne');
  
          }
      }
  }
  
  ```
  
  ### Your Controller
  
  ```
  public function actionMyAwesomeRoute(){
      $variables = // define whatever you want
  
      return $this->renderTemplate('path/to/template', $variables);
  }
  
  ```
  
  ### More complex examples, skip that if you don't need it
  
  ```
  // www.example.com/my-fancy-route/show-entry/9/siteOne
  public function actionShowEntry($id = null, $siteHandle = null){
      // $id will be 9, $siteHandle 'siteOne' since those parameters
      // are passed via URL, otherwise they are both null
      $entry = Craft::$app->getElements()->getElementById($id, $siteHandle);
  
      return $this->renderTemplate('path/to/template',  ['entry' => $entry]);
  }
  
  ```
  
  ### Just a little bit more complex stuff
  
  You could actually use the default route and inject it with another parameter as well. So When you have an existing route to an entry like `news/2018/feb/awesome-news/` you can as well visit this entry with `news/2018/feb/awesome-news/fooBar`
  
  ```
  $event->rules[] = [
      'pattern' => '/<route:\S+>/<something:\S+>',
      'route'   => 'awesome-plugin/route/catch-all'
  ];
  
  ```
  
  And in your Controller
  
  ```
  public function actionCatchAll($route, $something){
      $entry = Craft::$app->getElements()->getElementByUri($route);
      if ($entry instanceof Entry) {
          $section = $event->getSection();
          $siteSettings = $section->getSiteSettings();
          foreach ($siteSettings as $site) {
              if ((int) $site->siteId === (int) $entry->siteId) {
                  $templatePath = $site->template; // the template path for the entry
                  return $this->renderTemplate(
                      $templatePath,
                          [
                              'entry'     => $entry,
                              'whatever'  => $something
                          ]
                      );
              }
          }
      }
  
      return Craft::$app->runAction(Craft::$app->getRequest()->getFullPath());
  }
  
  ```
  
  > **Comments:**
  > **username_0**: Great, I got it, the explanation is perfect for my level. Yes I had created a custom plugin but I had only created template variables and services and thought of Controllers somehow else. Will come back when I test this with any question. Thank you again.  
  > **username_1**: It became a wall of text, just pick the information you need and ignore the rest or keep it in mind if you ever need it^^ I thought it could be a compilation of useful information  
  > **username_0**: Here I define a custom route and add my template variable for those routes, but the variable is informed only for the routes that match my custom route. I would like that variable to be informed also for all the site requests that are handled by Craft. I have tried using the same approximation (adding a rule that matches all routes) but Craft catches the entry requests before my Controller rules are reached. Is it possible to add extra variables to requests handled by Craft or override Craft's? Thank you  
  > **username_1**: You need to add a global somewhere. If it's really for all requests, no matter what you can do it in your plugins init function `Craft::$app->getView()->getTwig()->addGlobal('foo', $bar)`. Then you can access `{{ foo }}`  
  
  ---
  
  