Answers.Body: <p>I finally use this simple solution, which works pretty fine:</p>
  
  <pre><code>Event::on(
      Element::class,
      Element::EVENT_BEFORE_SAVE,
      function(craft\events\ModelEvent $event) {
          $entry = $event-&gt;sender;
          if (!\craft\helpers\ElementHelper::isDraftOrRevision($entry)) {
              if (!empty($entry-&gt;id)) {
                  $entry-&gt;slug = $entry-&gt;title;
              }
          }
      },
      false
  );
  </code></pre>
  
  <p>Where <code>$entry-&gt;slug = $entry-&gt;title</code> syncs the slug to the title if the entry is not new (<code>!empty($entry-&gt;id)</code>).</p>
  
  <p><strong>UPDATE:</strong></p>
  
  <pre><code>$entry-&gt;slug = ($entry-&gt;title !== null) ? \craft\helpers\StringHelper::slugify($entry-&gt;title) : $entry-&gt;slug;
  </code></pre>
  
  <p>This prevents to get a wrong slug on first save.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-10-02T08:32:15.537Z
Answers.Text: Due to the draft changes, this is the right approach for Craft 3.2 and later.
Answers.UserDisplayName: Fred Carlsen
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-09-23T10:58:13.797Z
Answers.LastActivityDate: 2019-10-02T08:35:50.137Z
Answers.LastEditDate: 2019-10-02T08:35:50.137Z
Answers.UserDisplayName: Romain P.
Answers.Body: <p>You can change the value in the DB directly instead of using the <code>Elements</code> service</p>
  
  <pre class="lang-PHP prettyprint-override"><code>$entry = $event-&gt;element;
  $elementId = $entry-&gt;id;
  $siteId = $entry-&gt;siteId;
  Craft::$app-&gt;getDb()-&gt;createCommand()
      -&gt;update(
          '{{%elements_sites}}',
          ['slug' =&gt; ElementHelper::createSlug('new-slug')],
          [
              'elementId' =&gt; $elementId,
              'siteId'    =&gt; $siteId
          ]
      )-&gt;execute();
  </code></pre>
  
  <p>By the way the following condition <code>[] !== $entry</code> won't be any good when you fetch an element with <code>one()</code> because <code>one</code> returns an object of instance <code>ElementInterface</code> or <code>null</code> but never an empty array. You can check <code>!== null</code> instead and if you fetch things via <code>all</code> you can perform an empty check <code>if( empty($entries) === false)</code></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-13T13:28:19.447Z
Answers.Text: Awesome, thank you! I had never thought of the DB way. Thank you also for the other explanations and advice, I really appreciate.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-02-13T12:51:23.680Z
Answers.LastActivityDate: 2019-02-13T12:56:38.673Z
Answers.LastEditDate: 2019-02-13T12:56:38.673Z
Answers.UserDisplayName: Robin Schambach
Answers.Body: <p>Another shorter and probably slightly more performant solution, using EVENT_BEFORE_SAVE:</p>
  
  <pre><code>/*
  * Automatically update Element slugs to match the title if updated.
  */
  Event::on(
      Element::class,
      Element::EVENT_BEFORE_SAVE,
      function(craft\events\ModelEvent $event) {
          $entry = $event-&gt;sender;
          $entry-&gt;slug = ElementHelper::createSlug($entry-&gt;title);
      },
      false
  );
  </code></pre>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-04-29T15:53:40.587Z
Answers.Text: This solution is not working, you should review the suggested code.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-04-29T16:57:33.700Z
Answers.Text: Works fine for me (it's tested and being used). Did you actually try it?
Answers.UserDisplayName: Udo
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-04-29T17:03:44.300Z
Answers.Text: @RomainPoirier it will not work with EVENT_AFTER_SAVE_ELEMENT but it does with EVENT_BEFORE_SAVE_ELEMENT
Answers.UserDisplayName: Udo
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-04-30T08:10:52.627Z
Answers.Text: Yep, I tried but but too quickly, I'm sorry. I was missing the loading of `craft\base\Element` and `craft\helpers\ElementHelper`.
  Would you use `EVENT_BEFORE_SAVE_ELEMENT` instead of `EVENT_BEFORE_SAVE`? I can't find official reference of `EVENT_BEFORE_SAVE` in the Craft 3 docs.
  If you know, can you explain the utility of `false` at the end? Thank you!
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-09-23T09:23:29.443Z
Answers.Text: Since recent Craft updates, `$entry->slug = ElementHelper::createSlug($entry->title);` doesn't works as expected: the slug is sometimes saved as empty. Delete `$entry->slug =` and only keep `ElementHelper::createSlug($entry->title);` seems to fix it.
Answers.UserDisplayName: Romain P.
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-04-29T15:42:49.530Z
Answers.LastActivityDate: 2019-04-29T19:43:48.320Z
Answers.LastEditDate: 2019-04-29T19:43:48.320Z
Answers.UserDisplayName: Udo
Body: <p>My entries' titles are auto-generated from several fields values on first save.</p>
  
  <p>When one of these fields values change, I would like to update the auto-generated slug also:</p>
  
  <pre class="lang-php prettyprint-override"><code>Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (Event $event) {
          $entry = Entry::find()
              -&gt;id($event-&gt;element-&gt;id)
              -&gt;one();
  
          if ([] !== $entry) {
              $title = craft\helpers\StringHelper::toAscii($entry-&gt;id.'-'.$entry-&gt;title);
              $title = craft\helpers\StringHelper::toLowerCase($title);
              $title = str_replace(' ', '-', $title);
  
              //  I tried this below, but none works
              $entry-&gt;slug = $title; // ⬅️ Not working
              $entry-&gt;setFieldValue('slug', $title); // ⬅️ Error
              Craft::$app-&gt;elements-&gt;saveElement($entry); // ⬅️ Infinite loop
              $event-&gt;element-&gt;slug = $event-&gt;element-&gt;id; // ⬅️ Not working
          }
      }
  );
  </code></pre>
  
  <p>Unfortunately, none of these methods works. Any idea how to achieve this?</p>
  
Tags: <events><slug><modules><onsaveentry>
Title: How to change an entry's slug on EVENT_AFTER_SAVE_ELEMENT?
ThreadText: # How to change an entry's slug on EVENT_AFTER_SAVE_ELEMENT?
  
  (Asked by: username_0 on 2019-02-13)
  
  My entries' titles are auto-generated from several fields values on first save.
  
  When one of these fields values change, I would like to update the auto-generated slug also:
  
  ```php
  Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (Event $event) {
          $entry = Entry::find()
              ->id($event->element->id)
              ->one();
  
          if ([] !== $entry) {
              $title = craft\helpers\StringHelper::toAscii($entry->id.'-'.$entry->title);
              $title = craft\helpers\StringHelper::toLowerCase($title);
              $title = str_replace(' ', '-', $title);
  
              //  I tried this below, but none works
              $entry->slug = $title; // ⬅️ Not working
              $entry->setFieldValue('slug', $title); // ⬅️ Error
              Craft::$app->elements->saveElement($entry); // ⬅️ Infinite loop
              $event->element->slug = $event->element->id; // ⬅️ Not working
          }
      }
  );
  
  ```
  
  Unfortunately, none of these methods works. Any idea how to achieve this?
  
  **Tags:** events, slug, modules, onsaveentry
  
  
  ---
  
  ## 3 answers
  
  ### Answer by username_0 on 2019-09-23. Score: 1 | Accepted answer
  
  I finally use this simple solution, which works pretty fine:
  
  ```
  Event::on(
      Element::class,
      Element::EVENT_BEFORE_SAVE,
      function(craft\events\ModelEvent $event) {
          $entry = $event->sender;
          if (!\craft\helpers\ElementHelper::isDraftOrRevision($entry)) {
              if (!empty($entry->id)) {
                  $entry->slug = $entry->title;
              }
          }
      },
      false
  );
  
  ```
  
  Where `$entry->slug = $entry->title` syncs the slug to the title if the entry is not new (`!empty($entry->id)`).
  
  **UPDATE:**
  
  ```
  $entry->slug = ($entry->title !== null) ? \craft\helpers\StringHelper::slugify($entry->title) : $entry->slug;
  
  ```
  
  This prevents to get a wrong slug on first save.
  
  > **Comments:**
  > **username_1**: Due to the draft changes, this is the right approach for Craft 3.2 and later.  
  
  ---
  
  ### Answer by username_2 on 2019-02-13. Score: 4
  
  You can change the value in the DB directly instead of using the `Elements` service
  
  ```PHP
  $entry = $event->element;
  $elementId = $entry->id;
  $siteId = $entry->siteId;
  Craft::$app->getDb()->createCommand()
      ->update(
          '{{%elements_sites}}',
          ['slug' => ElementHelper::createSlug('new-slug')],
          [
              'elementId' => $elementId,
              'siteId'    => $siteId
          ]
      )->execute();
  
  ```
  
  By the way the following condition `[] !== $entry` won't be any good when you fetch an element with `one()` because `one` returns an object of instance `ElementInterface` or `null` but never an empty array. You can check `!== null` instead and if you fetch things via `all` you can perform an empty check `if( empty($entries) === false)`
  
  > **Comments:**
  > **username_0**: Awesome, thank you! I had never thought of the DB way. Thank you also for the other explanations and advice, I really appreciate.  
  
  ---
  
  ### Answer by username_3 on 2019-04-29. Score: 2
  
  Another shorter and probably slightly more performant solution, using EVENT\_BEFORE\_SAVE:
  
  ```
  /*
  * Automatically update Element slugs to match the title if updated.
  */
  Event::on(
      Element::class,
      Element::EVENT_BEFORE_SAVE,
      function(craft\events\ModelEvent $event) {
          $entry = $event->sender;
          $entry->slug = ElementHelper::createSlug($entry->title);
      },
      false
  );
  
  ```
  
  > **Comments:**
  > **username_0**: This solution is not working, you should review the suggested code.  
  > **username_3**: Works fine for me (it's tested and being used). Did you actually try it?  
  > **username_3**: @RomainPoirier it will not work with EVENT_AFTER_SAVE_ELEMENT but it does with EVENT_BEFORE_SAVE_ELEMENT  
  > **username_0**: Yep, I tried but but too quickly, I'm sorry. I was missing the loading of `craft\base\Element` and `craft\helpers\ElementHelper`. Would you use `EVENT_BEFORE_SAVE_ELEMENT` instead of `EVENT_BEFORE_SAVE`? I can't find official reference of `EVENT_BEFORE_SAVE` in the Craft 3 docs. If you know, can you explain the utility of `false` at the end? Thank you!  
  > **username_0**: Since recent Craft updates, `$entry->slug = ElementHelper::createSlug($entry->title);` doesn't works as expected: the slug is sometimes saved as empty. Delete `$entry->slug =` and only keep `ElementHelper::createSlug($entry->title);` seems to fix it.  
  
  ---
  
  