Answers.Body: <p>You can't find pages based on which templates are included, because that information is not stored in the database at all. Instead, you need to query entries based on their attributes or content – for example, if their template includes a <code>button.twig</code>, maybe this component is only included for entries if a <code>button_url</code> field is not empty?</p>
  <p>In this case, you can search for all entries that have a <code>button_url</code> like this:</p>
  <pre class="lang-php prettyprint-override"><code>$entries = Entry::find()
      -&gt;button_url(':notempty:')
      -&gt;all();
  </code></pre>
  <p>If there are multiple conditions in your templates for including the <code>button.twig</code> component, you will need to replicate those conditions in your entry query.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-08-02T14:40:00.860Z
Answers.LastActivityDate: 2023-08-02T14:40:00.860Z
Answers.UserDisplayName: MoritzLost
Answers.Body: <p>What @MortizLost said is correct, there's no straightforward way to determine which entries are using which templates.</p>
  <p>You may also want to check out the <a href="https://plugins.craftcms.com/templatecomments" rel="nofollow noreferrer">Template Comments</a> plugin. It will add HTML comments surrounding each <code>include</code>d template, so you can then just look at the source code to see which templates are being used on the page.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-08-02T16:20:15.403Z
Answers.LastActivityDate: 2023-08-02T16:20:15.403Z
Answers.UserDisplayName: Lindsey D
Answers.Body: <p>Thanks for the answers @Lindsey D and @MoritzLost,</p>
  <p>Because we took over an existing craft website from another company, it's not so clear to know which pages are using which exact twig templates/components. To solve our problem we wrote an own twig extension that would add the twig filename into the printed twig source (someting simular like the Template Comments plugin @Lindsey D mentioned).</p>
  <p>/modules/sitemodule/extensions/DataTwigExtension.php</p>
  <pre><code>&lt;?php
  
  namespace modules\sitemodule\extensions;
  
  use Twig\Extension\AbstractExtension;
  use Twig\TwigFunction;
  
  class DataTwigExtension extends AbstractExtension
  {
      public function getFunctions()
      {
          return [
              new TwigFunction('dataTwig', [$this, 'dataTwig']),
          ];
      }
  
      private function getTemplateName(): string
      {
          foreach (debug_backtrace() as $trace) {
              if (isset($trace['object']) &amp;&amp; (strpos($trace['class'], 'TwigTemplate') !== false) &amp;&amp; 'Twig_Template' !== get_class($trace['object'])) {
                  $templateName = $trace['object']-&gt;getTemplateName();
                  if (strtolower(substr($templateName, -5)) !== &quot;.twig&quot;)
                      $templateName.=&quot;.twig&quot;;
                  return $templateName;
              }
          }
          return '';
      }
  
      public function dataTwig($asComment = false)
      {
          if (getenv('ENVIRONMENT') !== 'dev')
              return '';
          return $asComment ? '&lt;!-- data-twig:'.$this-&gt;getTemplateName().' --&gt;' : 'data-twig='.$this-&gt;getTemplateName();
      }
  }
  </code></pre>
  <p>In our existing module.php we added:</p>
  <pre><code>use modules\sitemodule\extensions\DataTwigExtension;
  
  public function init() {
      parent::init();
      
      ...
      
      Craft::$app-&gt;view-&gt;registerTwigExtension(new DataTwigExtension());
  }
  </code></pre>
  <p>Within our .twig files we can now add {{ dataTwig() }} or {{ dataTwig(true)|raw }} to print the current twig filename in the source code when in dev mode.</p>
  <p>EX: sample.twig</p>
  <pre><code>&lt;div {{ dataTwig() }}&gt;This is a sample&lt;/div&gt;
  </code></pre>
  <p>Will print:</p>
  <pre><code>&lt;div data-twig=&quot;sample.twig&quot;&gt;This is a sample&lt;/div&gt;
  </code></pre>
  <p>Beside this extra data-twig attribute we also created an api route to fetch all the entries and lookup if the response body contained the .twig components we where looking for.</p>
  <p>In our existing module.php we added:</p>
  <pre><code>use modules\sitemodule\controllers\ApiController;
  
  public function init() {
      parent::init();
      
      ...
      
      Craft::$app-&gt;controllerMap['api'] = ['class' =&gt; ApiController::class];
  }
  </code></pre>
  <p>/modules/sitemodule/controllers/ApiController.php</p>
  <pre><code>&lt;?php
  
  namespace modules\sitemodule\controllers;
  
  use craft\elements\Entry;
  use craft\web\Controller;
  use yii\web\Response;
  
  class ApiController extends Controller
  {
      protected $allowAnonymous = true;
  
      private function getAllEntryUrls() {
          $urls = array_map(function($entry) {
              return $entry-&gt;url;
          }, array_filter(
              Entry::find()-&gt;site('*')-&gt;all(),
              function($entry) {
                  return $entry-&gt;url;
              }
          ));
          sort($urls);
          return $urls;
      }
  
      // /actions/sitemodule/api/find-pages-using-twig?template=sample.twig
      public function actionFindPagesUsingTwig(): Response
      {
          $twigTemplate = \Craft::$app-&gt;getRequest()-&gt;getParam('template');
          if (!$twigTemplate) return $this-&gt;asErrorJson('Missing template paramater. Please add something like ?template=sample.twig to use this api call.');
          
          $client = new \GuzzleHttp\Client(['allow_redirects' =&gt; false]);
          $successStatus = [&quot;matches&quot; =&gt; [], &quot;mismatches&quot; =&gt; []];
          $errorStatus = [];
  
          foreach ($this-&gt;getAllEntryUrls() as $url) {
              $response = $client-&gt;request('GET', $url, ['allow_redirects' =&gt; false,  'exceptions' =&gt; false]);
              $statusCode = $response-&gt;getStatusCode();
              if ($statusCode === 200) {
                  $body = $response-&gt;getBody()-&gt;getContents();
                  if (stripos($body, $twigTemplate) !== false) {
                      $successStatus[&quot;matches&quot;][] = $url;
                  } else {
                      $successStatus[&quot;mismatches&quot;][] = $url;
                  }
              } else {
                  if (!array_key_exists($statusCode, $errorStatus)) {
                      $errorStatus[$statusCode] = [];
                  }
                  $errorStatus[$statusCode][] = $url;
              }
          }
  
          return $this-&gt;asJson(['success' =&gt; $successStatus, 'error' =&gt; $errorStatus]);
      }
  }
  </code></pre>
  <p>When navigating to the api url, we can now add the twig filename and after a while we will receive a list of urls which are matching and mismatching the requested twig filename. Also an error list is added to know which urls are not returning a 200 status.</p>
  <p>localhost:8080/actions/sitemodule/api/find-pages-using-twig/?template=sample.twig</p>
  <pre><code>{
    &quot;success&quot;: {
      &quot;matches&quot;: [
        &quot;http://localhost:8080/en/sample/&quot;,
        &quot;http://localhost:8080/fr/sample/&quot;,
        &quot;http://localhost:8080/nl/sample/&quot;
      ],
      &quot;mismatches&quot;: [
        &quot;http://localhost:8080/en/&quot;,
        &quot;http://localhost:8080/fr/&quot;,
        &quot;http://localhost:8080/nl/&quot;
      ]
    },
    &quot;error&quot;: {
      &quot;404&quot;: [
        &quot;http://localhost:8080/en/template-not-found/&quot;
      ]
    }
  }
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-08-03T16:15:58.987Z
Answers.LastActivityDate: 2023-08-03T16:15:58.987Z
Answers.UserDisplayName: Brecht Cloetens
Answers.Body: <p>The solutions for querying entries for blocks used are correct, but there are other things you can do to help identify what is being included and from where.</p>
  <p>Personally, in my base layout I'll always include something like;</p>
  <pre><code>class=&quot;{% if entry is defined %} entryId-{{ entry.id }} template-{{ defaultTemplate ?? entry.type.handle }}{% endif %}&quot;
  </code></pre>
  <p>That will ID both the entry in Craft that is generating a given page and the template that it's using.</p>
  <p>I also add the following to each Twig component so it will print the name of the component as an html comment:</p>
  <p><code>&lt;!-- Template: {{ _self }} --&gt;</code></p>
  <p>Personally, I'd only want to see this info in source whilst in development so I'd wrap that in a conditional:</p>
  <p><code>{% if craft.app.config.general.devMode %}&lt;!-- Template: {{ _self }} --&gt;{% endif %}</code></p>
  <p>Combining the above and inspecting the source gives you:</p>
  <ol>
  <li>The Craft entry involved</li>
  <li>The template</li>
  <li>The components being output</li>
  </ol>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-08-04T13:19:15.347Z
Answers.LastActivityDate: 2023-08-04T13:19:15.347Z
Answers.UserDisplayName: Seth
Body: <p>How can I get all the pages (entry urls) which are containing a certain .twig component?</p>
  <p>Ex:</p>
  <pre><code>$entries = Entry::find()-&gt;search('button.twig')-&gt;all();
  $urls = [];
  foreach ($entries as $entry) {
      $urls[] = $entry-&gt;url;
  }
  </code></pre>
  <p>When a twig template is containging the 'button.twig' at a deeper level, I also want to retreive the pages url. For example: layout.twig is including content.twig which includes button.twig.</p>
  
Tags: <templating><entries>
Title: Find all entries containing a certain twig component
ThreadText: # Find all entries containing a certain twig component
  
  (Asked by: username_0 on 2023-08-02)
  
  How can I get all the pages (entry urls) which are containing a certain .twig component?
  
  Ex:
  
  ```
  $entries = Entry::find()->search('button.twig')->all();
  $urls = [];
  foreach ($entries as $entry) {
      $urls[] = $entry->url;
  }
  
  ```
  
  When a twig template is containging the 'button.twig' at a deeper level, I also want to retreive the pages url. For example: layout.twig is including content.twig which includes button.twig.
  
  **Tags:** templating, entries
  
  
  ---
  
  ## 4 answers
  
  ### Answer by username_1 on 2023-08-02. Score: 4
  
  You can't find pages based on which templates are included, because that information is not stored in the database at all. Instead, you need to query entries based on their attributes or content – for example, if their template includes a `button.twig`, maybe this component is only included for entries if a `button_url` field is not empty?
  
  In this case, you can search for all entries that have a `button_url` like this:
  
  ```php
  $entries = Entry::find()
      ->button_url(':notempty:')
      ->all();
  
  ```
  
  If there are multiple conditions in your templates for including the `button.twig` component, you will need to replicate those conditions in your entry query.
  
  
  ---
  
  ### Answer by username_2 on 2023-08-02. Score: 2
  
  What @MortizLost said is correct, there's no straightforward way to determine which entries are using which templates.
  
  You may also want to check out the [Template Comments](https://plugins.craftcms.com/templatecomments) plugin. It will add HTML comments surrounding each `include`d template, so you can then just look at the source code to see which templates are being used on the page.
  
  
  ---
  
  ### Answer by username_0 on 2023-08-03. Score: 2
  
  Thanks for the answers @username_2 and @username_1,
  
  Because we took over an existing craft website from another company, it's not so clear to know which pages are using which exact twig templates/components. To solve our problem we wrote an own twig extension that would add the twig filename into the printed twig source (someting simular like the Template Comments plugin @username_2 mentioned).
  
  /modules/sitemodule/extensions/DataTwigExtension.php
  
  ```
  <?php
  
  namespace modules\sitemodule\extensions;
  
  use Twig\Extension\AbstractExtension;
  use Twig\TwigFunction;
  
  class DataTwigExtension extends AbstractExtension
  {
      public function getFunctions()
      {
          return [
              new TwigFunction('dataTwig', [$this, 'dataTwig']),
          ];
      }
  
      private function getTemplateName(): string
      {
          foreach (debug_backtrace() as $trace) {
              if (isset($trace['object']) && (strpos($trace['class'], 'TwigTemplate') !== false) && 'Twig_Template' !== get_class($trace['object'])) {
                  $templateName = $trace['object']->getTemplateName();
                  if (strtolower(substr($templateName, -5)) !== ".twig")
                      $templateName.=".twig";
                  return $templateName;
              }
          }
          return '';
      }
  
      public function dataTwig($asComment = false)
      {
          if (getenv('ENVIRONMENT') !== 'dev')
              return '';
          return $asComment ? '<!-- data-twig:'.$this->getTemplateName().' -->' : 'data-twig='.$this->getTemplateName();
      }
  }
  
  ```
  
  In our existing module.php we added:
  
  ```
  use modules\sitemodule\extensions\DataTwigExtension;
  
  public function init() {
      parent::init();
      
      ...
      
      Craft::$app->view->registerTwigExtension(new DataTwigExtension());
  }
  
  ```
  
  Within our .twig files we can now add {{ dataTwig() }} or {{ dataTwig(true)|raw }} to print the current twig filename in the source code when in dev mode.
  
  EX: sample.twig
  
  ```
  <div {{ dataTwig() }}>This is a sample</div>
  
  ```
  
  Will print:
  
  ```
  <div data-twig="sample.twig">This is a sample</div>
  
  ```
  
  Beside this extra data-twig attribute we also created an api route to fetch all the entries and lookup if the response body contained the .twig components we where looking for.
  
  In our existing module.php we added:
  
  ```
  use modules\sitemodule\controllers\ApiController;
  
  public function init() {
      parent::init();
      
      ...
      
      Craft::$app->controllerMap['api'] = ['class' => ApiController::class];
  }
  
  ```
  
  /modules/sitemodule/controllers/ApiController.php
  
  ```
  <?php
  
  namespace modules\sitemodule\controllers;
  
  use craft\elements\Entry;
  use craft\web\Controller;
  use yii\web\Response;
  
  class ApiController extends Controller
  {
      protected $allowAnonymous = true;
  
      private function getAllEntryUrls() {
          $urls = array_map(function($entry) {
              return $entry->url;
          }, array_filter(
              Entry::find()->site('*')->all(),
              function($entry) {
                  return $entry->url;
              }
          ));
          sort($urls);
          return $urls;
      }
  
      // /actions/sitemodule/api/find-pages-using-twig?template=sample.twig
      public function actionFindPagesUsingTwig(): Response
      {
          $twigTemplate = \Craft::$app->getRequest()->getParam('template');
          if (!$twigTemplate) return $this->asErrorJson('Missing template paramater. Please add something like ?template=sample.twig to use this api call.');
          
          $client = new \GuzzleHttp\Client(['allow_redirects' => false]);
          $successStatus = ["matches" => [], "mismatches" => []];
          $errorStatus = [];
  
          foreach ($this->getAllEntryUrls() as $url) {
              $response = $client->request('GET', $url, ['allow_redirects' => false,  'exceptions' => false]);
              $statusCode = $response->getStatusCode();
              if ($statusCode === 200) {
                  $body = $response->getBody()->getContents();
                  if (stripos($body, $twigTemplate) !== false) {
                      $successStatus["matches"][] = $url;
                  } else {
                      $successStatus["mismatches"][] = $url;
                  }
              } else {
                  if (!array_key_exists($statusCode, $errorStatus)) {
                      $errorStatus[$statusCode] = [];
                  }
                  $errorStatus[$statusCode][] = $url;
              }
          }
  
          return $this->asJson(['success' => $successStatus, 'error' => $errorStatus]);
      }
  }
  
  ```
  
  When navigating to the api url, we can now add the twig filename and after a while we will receive a list of urls which are matching and mismatching the requested twig filename. Also an error list is added to know which urls are not returning a 200 status.
  
  localhost:8080/actions/sitemodule/api/find-pages-using-twig/?template=sample.twig
  
  ```
  {
    "success": {
      "matches": [
        "http://localhost:8080/en/sample/",
        "http://localhost:8080/fr/sample/",
        "http://localhost:8080/nl/sample/"
      ],
      "mismatches": [
        "http://localhost:8080/en/",
        "http://localhost:8080/fr/",
        "http://localhost:8080/nl/"
      ]
    },
    "error": {
      "404": [
        "http://localhost:8080/en/template-not-found/"
      ]
    }
  }
  
  ```
  
  
  ---
  
  ### Answer by username_3 on 2023-08-04. Score: 2
  
  The solutions for querying entries for blocks used are correct, but there are other things you can do to help identify what is being included and from where.
  
  Personally, in my base layout I'll always include something like;
  
  ```
  class="{% if entry is defined %} entryId-{{ entry.id }} template-{{ defaultTemplate ?? entry.type.handle }}{% endif %}"
  
  ```
  
  That will ID both the entry in Craft that is generating a given page and the template that it's using.
  
  I also add the following to each Twig component so it will print the name of the component as an html comment:
  
  `<!-- Template: {{ _self }} -->`
  
  Personally, I'd only want to see this info in source whilst in development so I'd wrap that in a conditional:
  
  `{% if craft.app.config.general.devMode %}<!-- Template: {{ _self }} -->{% endif %}`
  
  Combining the above and inspecting the source gives you:
  
  1. The Craft entry involved
  2. The template
  3. The components being output
  
  
  ---
  
  