Answers.Body: <p>My guess is still: you did not define a route correct route for your template. You can check if you can access the file when you call the route normally via url <code>www.example.com/blog/test</code> if you can see the template, then it should usually work, if not you did not define any routing rules <a href="https://github.com/craftcms/docs/blob/master/en/updating-plugins.md#registersiteroutes" rel="nofollow noreferrer">see here</a></p>
  
  <p>However: when you do it that way everyone with the link may see this template and I expect it to look not very good without content since it's probably only a partial, so I would highly recommend you to use the proper way via controller.</p>
  
  <pre class="lang-php prettyprint-override"><code>public function actionRenderTemplate(){
      $response = [
          'success'   =&gt; false,
          'message'   =&gt; 'something went wrong'
      ];
      if($template = Craft::$app-&gt;getRequest()-&gt;getBodyParam('template')){
          try{
              $response['success'] = true;
              $response['html'] = Craft::$app-&gt;getView()-&gt;renderTemplate($template, [
                  'foo' =&gt; Craft::$app-&gt;getRequest()-&gt;getBodyParam('just an example to pass values');
              ]);
          }catch(\Twig_Error_Loader $e){
              $response['message'] = $e-&gt;getMessage(); 
          }catch(\yii\base\Exception $e){
              $response['message'] = $e-&gt;getMessage();
          }
      }
      return $this-&gt;asJson($response);
  }
  </code></pre>
  
  <p>And your javascript</p>
  
  <pre class="lang-js prettyprint-override"><code>$.ajax({
      type: "post",
      data: {
          action: 'plugin-handle/controller/render-template',
          template: 'path/to/template'
      },
      url: '',
      success: function (data) {
          if (data.success === true) {
              // do your stuff
              $('body').append(data.html);
          } else {
              // something went wrong
              // show a message or whatever
          }
      }
  });
  </code></pre>
  
  <p><strong>Edit</strong><br>
  Please make sure you are in the correct folder for rendering your template, there is a difference between frontend and cp requests <a href="https://github.com/craftcms/docs/blob/master/en/updating-plugins.md#rendering-plugin-templates-on-front-end-requests" rel="nofollow noreferrer">docs</a> that's why we always build a custom template service that checks if there is a template in the normal path first and only takes the plugin template if there is none so we can overwrite plugin templates if needed and don't need to check/overwrite the paths every time</p>
  
Answers.ContentLicense: CC BY-SA 3.0
Answers.CreationDate: 2018-01-01T08:54:47.997Z
Answers.LastActivityDate: 2018-01-02T17:12:50.257Z
Answers.LastEditDate: 2018-01-02T17:12:50.257Z
Answers.UserDisplayName: Robin Schambach
Body: <p>I'm not sure if this is a bug, a security feature, or something to do with Twig 2; but since Craft 3 (RC3) I'm no longer able to access hidden twig files via ajax. </p>
  
  <p>This works fine:</p>
  
  <pre><code>  $.ajax({
      method:'GET',
      url:'/blog/test',
      success:function(data){
        $('body').append(data);
        console.log("SUCCESS", data);
      },
      error:function(data){
        console.log("ERROR", data);
      }
    });
  </code></pre>
  
  <p>However, when I point the url to a hidden file with this:</p>
  
  <pre><code>url:'/blog/_test',
  </code></pre>
  
  <p>I get a <strong>404 (Not Found)</strong> error. For my example, I have both '_test.twig' and 'test.twig' files in the 'blog' directory.</p>
  
  <p>Am I missing a breaking <a href="https://github.com/craftcms/docs/blob/master/en/changes-in-craft-3.md" rel="nofollow noreferrer">change</a>? </p>
  
  <hr>
  
  <p><strong>Update:</strong></p>
  
  <p>I didn't really know what it was for, but <code>'enableCsrfProtection' =&gt; true</code> has always been set in my config/general.php file. (In both Craft 2 and 3). I've tried setting this to <code>false</code> too, and I'm getting the same results. </p>
  
  <p>Following Robins comment, I've attempted to follow these instructions: <a href="https://craftcms.com/support/csrf-protection" rel="nofollow noreferrer">Enabling CSRF Protection</a>.</p>
  
  <p>I've set the global variables <code>window.csrfTokenName</code> and <code>window.csrfTokenValue</code>. And now I'm stuck. </p>
  
  <p>I'm pretty new to ajax, and I'm not sure how to extrapolate <a href="https://craftcms.com/support/csrf-protection#updating-your-javascript" rel="nofollow noreferrer">the example</a> in a way where I can add the CSRF Token correctly in my 'GET' method.    </p>
  
  <p>This is the response I'm getting: </p>
  
  <pre><code>ERROR 
  {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
  abort : (statusText)
  always : ()
  catch : (fn)
  done : ()
  fail : ()
  getAllResponseHeaders : ()
  getResponseHeader : (key)
  overrideMimeType : (type)
  pipe : ()
  progress : ()
  promise : (obj)
  readyState : 4
  responseText : "&lt;pre&gt;Not Found: Page not found.&lt;/pre&gt;"
  setRequestHeader : (name,value)
  state : ()
  status : 404
  statusCode : (map)
  statusText : "Not Found"
  then : (onFulfilled,onRejected,onProgress)
  __proto__ : Object
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 3.0
Comments.CreationDate: 2017-12-31T14:18:10.587Z
Comments.Text: Did you disable the CSRF validation in your config? If not, it's not going to work since you need to include it and I'll post how to get it in my answer. If not maybe you could show us your complete response?
Comments.UserDisplayName: Robin Schambach
Tags: <ajax><craft3>
Title: Hidden files are no longer accessible with AJAX in Craft 3
ThreadText: # Hidden files are no longer accessible with AJAX in Craft 3
  
  (Asked by: username_0 on 2017-12-31)
  
  I'm not sure if this is a bug, a security feature, or something to do with Twig 2; but since Craft 3 (RC3) I'm no longer able to access hidden twig files via ajax.
  
  This works fine:
  
  ```
    $.ajax({
      method:'GET',
      url:'/blog/test',
      success:function(data){
        $('body').append(data);
        console.log("SUCCESS", data);
      },
      error:function(data){
        console.log("ERROR", data);
      }
    });
  
  ```
  
  However, when I point the url to a hidden file with this:
  
  ```
  url:'/blog/_test',
  
  ```
  
  I get a **404 (Not Found)** error. For my example, I have both '\_test.twig' and 'test.twig' files in the 'blog' directory.
  
  Am I missing a breaking [change](https://github.com/craftcms/docs/blob/master/en/changes-in-craft-3.md)?
  
  ---
  
  **Update:**
  
  I didn't really know what it was for, but `'enableCsrfProtection' => true` has always been set in my config/general.php file. (In both Craft 2 and 3). I've tried setting this to `false` too, and I'm getting the same results.
  
  Following Robins comment, I've attempted to follow these instructions: [Enabling CSRF Protection](https://craftcms.com/support/csrf-protection).
  
  I've set the global variables `window.csrfTokenName` and `window.csrfTokenValue`. And now I'm stuck.
  
  I'm pretty new to ajax, and I'm not sure how to extrapolate [the example](https://craftcms.com/support/csrf-protection#updating-your-javascript) in a way where I can add the CSRF Token correctly in my 'GET' method.
  
  This is the response I'm getting:
  
  ```
  ERROR 
  {readyState: 4, getResponseHeader: ƒ, getAllResponseHeaders: ƒ, setRequestHeader: ƒ, overrideMimeType: ƒ, …}
  abort : (statusText)
  always : ()
  catch : (fn)
  done : ()
  fail : ()
  getAllResponseHeaders : ()
  getResponseHeader : (key)
  overrideMimeType : (type)
  pipe : ()
  progress : ()
  promise : (obj)
  readyState : 4
  responseText : "<pre>Not Found: Page not found.</pre>"
  setRequestHeader : (name,value)
  state : ()
  status : 404
  statusCode : (map)
  statusText : "Not Found"
  then : (onFulfilled,onRejected,onProgress)
  __proto__ : Object
  
  ```
  
  **Tags:** ajax, craft3
  
  > **Comments:**
  > **username_1**: Did you disable the CSRF validation in your config? If not, it's not going to work since you need to include it and I'll post how to get it in my answer. If not maybe you could show us your complete response?  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2018-01-01. Score: 2 | Accepted answer
  
  My guess is still: you did not define a route correct route for your template. You can check if you can access the file when you call the route normally via url `www.example.com/blog/test` if you can see the template, then it should usually work, if not you did not define any routing rules [see here](https://github.com/craftcms/docs/blob/master/en/updating-plugins.md#registersiteroutes)
  
  However: when you do it that way everyone with the link may see this template and I expect it to look not very good without content since it's probably only a partial, so I would highly recommend you to use the proper way via controller.
  
  ```php
  public function actionRenderTemplate(){
      $response = [
          'success'   => false,
          'message'   => 'something went wrong'
      ];
      if($template = Craft::$app->getRequest()->getBodyParam('template')){
          try{
              $response['success'] = true;
              $response['html'] = Craft::$app->getView()->renderTemplate($template, [
                  'foo' => Craft::$app->getRequest()->getBodyParam('just an example to pass values');
              ]);
          }catch(\Twig_Error_Loader $e){
              $response['message'] = $e->getMessage(); 
          }catch(\yii\base\Exception $e){
              $response['message'] = $e->getMessage();
          }
      }
      return $this->asJson($response);
  }
  
  ```
  
  And your javascript
  
  ```js
  $.ajax({
      type: "post",
      data: {
          action: 'plugin-handle/controller/render-template',
          template: 'path/to/template'
      },
      url: '',
      success: function (data) {
          if (data.success === true) {
              // do your stuff
              $('body').append(data.html);
          } else {
              // something went wrong
              // show a message or whatever
          }
      }
  });
  
  ```
  
  **Edit**  
  Please make sure you are in the correct folder for rendering your template, there is a difference between frontend and cp requests [docs](https://github.com/craftcms/docs/blob/master/en/updating-plugins.md#rendering-plugin-templates-on-front-end-requests) that's why we always build a custom template service that checks if there is a template in the normal path first and only takes the plugin template if there is none so we can overwrite plugin templates if needed and don't need to check/overwrite the paths every time
  
  
  ---
  
  