Answers.Body: <p>My guess is that you're using the <code>@web</code> <a href="https://craftcms.com/docs/4.x/config/#aliases" rel="nofollow noreferrer">alias</a> for your sites' &quot;Base URL&quot; setting. Unless explicitly declared in your project, this alias will resolve to an empty string for console requests, since Craft isn't able to deduce what your host name is in that environment.</p>
  <p>To fix this issue, you should explicitly declare the <code>@web</code> alias by adding an environment variable <code>CRAFT_WEB_URL</code>, e.g. in your <code>.env</code> file:</p>
  <pre><code>CRAFT_WEB_URL=http://localhost:3000
  </code></pre>
  <p>Alternatively, you can override the <code>@web</code> alias via your <code>config/general.php</code> config file:</p>
  <pre class="lang-php prettyprint-override"><code>use craft\helpers\App;
  
  return [
      'aliases' =&gt; [
          '@web' =&gt; App::env('BASE_SITE_URL'),
      ],
  ];
  </code></pre>
  <p>In addition to (likely) solving the relevant issue, explicitly setting the <code>@web</code> alias to a fully qualified URL is considered a good practice as it prevents a variety of security issues.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2023-03-23T15:13:56.600Z
Answers.LastActivityDate: 2023-03-23T15:13:56.600Z
Answers.UserDisplayName: Mats Mikkel Rummelhoff
Body: <p>In an e-mail template in a custom plugin I want to render a link to an entry. This needs to be an absolute URL.</p>
  <p>I need this to work both when triggering the action from the control panel, and when running it as a console command. This means I cannot hard code the base URL in front of the <code>{{ item.url }}</code> part.</p>
  <p>When triggering the action from the control panel, this part of the template</p>
  <pre><code>&lt;a href=&quot;{{ item.url }}&quot;&gt;Read more&lt;/a&gt;
  </code></pre>
  <p>renders the following:</p>
  <pre><code>&lt;a href=&quot;http://localhost:3000/posts/slug-of-post&quot;&gt;Read more&lt;/a&gt;
  </code></pre>
  <p>However, when running from the console, it renders the following:</p>
  <pre><code>&lt;a href=&quot;/posts/slug-of-post&quot;&gt;Read more&lt;/a&gt;
  </code></pre>
  <hr />
  <p>I've tried to isolate the getUrl() for easier testing. This also gives relative URLs.</p>
  <pre><code>use craft\console\Controller;
  
  public static function actionTestMe(): int
  {
      $entry = \craft\elements\Entry::find()
          -&gt;site('site')
          -&gt;section('posts')
          -&gt;one();
  
      echo $entry-&gt;getUrl(); // Output: /posts/slug-of-post
      (...)
  }
  </code></pre>
  
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-03-23T12:48:19.017Z
Comments.Text: What is your site's "Base URL" setting set to in the CP?
Comments.UserDisplayName: Mats Mikkel Rummelhoff
Comments.ContentLicense: CC BY-SA 4.0
Comments.CreationDate: 2023-03-23T12:52:38.310Z
Comments.Text: This is a multi-site project, but the Primary site's Base URL is `http://localhost:3000/`. For what it's worth adding `echo Craft::$app->sites->currentSite->baseUrl;` in my test action also gives `http://localhost:3000/`.
Comments.UserDisplayName: PWL
Tags: <plugin-development><craft4>
Title: Entry url in console action doesn't return absolute URL
ThreadText: # Entry url in console action doesn't return absolute URL
  
  (Asked by: username_0 on 2023-03-23)
  
  In an e-mail template in a custom plugin I want to render a link to an entry. This needs to be an absolute URL.
  
  I need this to work both when triggering the action from the control panel, and when running it as a console command. This means I cannot hard code the base URL in front of the `{{ item.url }}` part.
  
  When triggering the action from the control panel, this part of the template
  
  ```
  <a href="{{ item.url }}">Read more</a>
  
  ```
  
  renders the following:
  
  ```
  <a href="http://localhost:3000/posts/slug-of-post">Read more</a>
  
  ```
  
  However, when running from the console, it renders the following:
  
  ```
  <a href="/posts/slug-of-post">Read more</a>
  
  ```
  
  ---
  
  I've tried to isolate the getUrl() for easier testing. This also gives relative URLs.
  
  ```
  use craft\console\Controller;
  
  public static function actionTestMe(): int
  {
      $entry = \craft\elements\Entry::find()
          ->site('site')
          ->section('posts')
          ->one();
  
      echo $entry->getUrl(); // Output: /posts/slug-of-post
      (...)
  }
  
  ```
  
  **Tags:** plugin-development, craft4
  
  > **Comments:**
  > **username_1**: What is your site's "Base URL" setting set to in the CP?  
  > **username_0**: This is a multi-site project, but the Primary site's Base URL is `http://localhost:3000/`. For what it's worth adding `echo Craft::$app->sites->currentSite->baseUrl;` in my test action also gives `http://localhost:3000/`.  
  
  ---
  
  ## 1 answers
  
  ### Answer by username_1 on 2023-03-23. Score: 1
  
  My guess is that you're using the `@web` [alias](https://craftcms.com/docs/4.x/config/#aliases) for your sites' "Base URL" setting. Unless explicitly declared in your project, this alias will resolve to an empty string for console requests, since Craft isn't able to deduce what your host name is in that environment.
  
  To fix this issue, you should explicitly declare the `@web` alias by adding an environment variable `CRAFT_WEB_URL`, e.g. in your `.env` file:
  
  ```
  CRAFT_WEB_URL=http://localhost:3000
  
  ```
  
  Alternatively, you can override the `@web` alias via your `config/general.php` config file:
  
  ```php
  use craft\helpers\App;
  
  return [
      'aliases' => [
          '@web' => App::env('BASE_SITE_URL'),
      ],
  ];
  
  ```
  
  In addition to (likely) solving the relevant issue, explicitly setting the `@web` alias to a fully qualified URL is considered a good practice as it prevents a variety of security issues.
  
  
  ---
  
  