Answers.Body: <p>You can find out what the stack trace is (who is calling you) by putting something like this in your anonymous function:</p>
  
  <pre class="lang-php prettyprint-override"><code>                try {
                      throw new \Exception();
                  } catch (\Exception $e) {
                      Craft::debug(
                          'EVENT_AFTER_SAVE_ELEMENT '.$e-&gt;getTraceAsString(),
                          __METHOD__
                      );
                  }
  </code></pre>
  
  <p>Then search on <code>EVENT_AFTER_SAVE_ELEMENT</code> in your <code>web.log</code></p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T01:10:46.257Z
Answers.Text: Great tip! Thanks, Andrew!
Answers.UserDisplayName: Wei
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-16T03:36:42.057Z
Answers.LastActivityDate: 2019-08-16T03:36:42.057Z
Answers.UserDisplayName: andrew.welch
Answers.Body: <p>After using Andrew's <a href="https://craftcms.stackexchange.com/a/31236/7136">debugging tip</a>, I found out one event was triggered by saving the element itself, and the other was triggered by saving the revision of the element. So I modified my event listener to be like the following, and it solved the double-up issue:</p>
  
  <pre><code>Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (\craft\events\ElementEvent $event) {
          $element = $event-&gt;element;
          if(
              $element instanceof \craft\elements\Entry // is entry
              &amp;&amp; $element-&gt;getSection()-&gt;handle == 'pages' // is in 'pages' section
              &amp;&amp; !$element-&gt;getIsRevision() // is not revision
              &amp;&amp; !$element-&gt;getIsDraft() // is not draft
              // &amp;&amp; !$element-&gt;propagating // not during propagating (avoid batch propagating)
              // &amp;&amp; !$element-&gt;resaving // not during resaving (avoid batch resaving)
          ) {
              // --------------- My Stuff -------------- //
              // $entry is the $element
              // $isNew = $event-&gt;isNew
              // ...
          }
      }
  );
  </code></pre>
  
  <p>Depending on what you are trying to do in the event handler, you might want to toggle some if conditions. For example, you might want to avoid the same handler executed hundreds of times during a batch of <a href="https://docs.craftcms.com/api/v3/craft-services-elements.html#method-resaveelements" rel="noreferrer">re-saving action</a> which is triggered when a section's setting is updated and Craft automatically re-saves all the entries under the section. In this case, you might consider having a separate EVENT_AFTER_RESAVE_ELEMENTS event handler.</p>
  
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T11:56:36.000Z
Answers.Text: Nicely done tracking it down! If you're using Craft 3.2, there's a helper: `ElementHelper::isDraftOrRevision($element)`
Answers.UserDisplayName: andrew.welch
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-20T04:16:13.837Z
Answers.Text: @andrew.welch ahh, good to know. Thanks!
Answers.UserDisplayName: Wei
Answers.ContentLicense: CC BY-SA 4.0
Answers.CreationDate: 2019-08-19T01:17:53.733Z
Answers.LastActivityDate: 2019-08-19T02:06:11.730Z
Answers.LastEditDate: 2019-08-19T02:06:11.730Z
Answers.UserDisplayName: Wei
Body: <p>I had this weird issue, not sure if that happens to you guys or not.</p>
  
  <p>I'm trying to catch the 'after entry is saved' event, using the following code in my custom module's init() function (The module's code is generated by <a href="https://pluginfactory.io/" rel="noreferrer">pluginfactory.io</a>):</p>
  
  <pre><code>Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (\craft\events\ElementEvent $event) {
          $element = $event-&gt;element;
          if($element instanceof \craft\elements\Entry) {
              // Craft::info('Entry saved: ' . $element-&gt;title, __METHOD__);
          }
      }
  );
  </code></pre>
  
  <p>It seems to work by testing on saving an entry in the CP, but the weird thing is this event seems to be triggered twice according to the log:</p>
  
  <pre><code>2019-08-16 12:21:52 [-][1][-][info][modules\testmodule\{closure}] Entry saved: Document translation
  2019-08-16 12:21:52 [-][1][-][info][modules\testmodule\{closure}] Entry saved: Document translation
  2019-08-16 12:21:52 [-][1][-][info][application] $_GET = [
      'p' =&gt; 'admin/entries/pages/234-document-translation'
  ]
  </code></pre>
  
  <p>I also tried Andrew's answer in this post: <a href="https://craftcms.stackexchange.com/a/26815/7136">https://craftcms.stackexchange.com/a/26815/7136</a>, but same thing happened.</p>
  
  <pre><code>Event::on(
      \craft\elements\Entry::class,
      \craft\elements\Entry::EVENT_AFTER_SAVE,
      function (\craft\events\ModelEvent $event) {
          Craft::debug(
              '\craft\elements\Entry::EVENT_AFTER_SAVE',
              __METHOD__
          );
      }
  );
  </code></pre>
  
  <p>I certainly don't want my custom code to be executed twice. Is this a bug or an expected behavior?</p>
  
  <p>Craft version: 3.2.10</p>
  
Tags: <craft3><events>
Title: EVENT_AFTER_SAVE_ELEMENT triggered twice after saving an entry
ThreadText: # EVENT_AFTER_SAVE_ELEMENT triggered twice after saving an entry
  
  (Asked by: username_0 on 2019-08-16)
  
  I had this weird issue, not sure if that happens to you guys or not.
  
  I'm trying to catch the 'after entry is saved' event, using the following code in my custom module's init() function (The module's code is generated by [pluginfactory.io](https://pluginfactory.io/)):
  
  ```
  Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (\craft\events\ElementEvent $event) {
          $element = $event->element;
          if($element instanceof \craft\elements\Entry) {
              // Craft::info('Entry saved: ' . $element->title, __METHOD__);
          }
      }
  );
  
  ```
  
  It seems to work by testing on saving an entry in the CP, but the weird thing is this event seems to be triggered twice according to the log:
  
  ```
  2019-08-16 12:21:52 [-][1][-][info][modules\testmodule\{closure}] Entry saved: Document translation
  2019-08-16 12:21:52 [-][1][-][info][modules\testmodule\{closure}] Entry saved: Document translation
  2019-08-16 12:21:52 [-][1][-][info][application] $_GET = [
      'p' => 'admin/entries/pages/234-document-translation'
  ]
  
  ```
  
  I also tried Andrew's answer in this post: <https://craftcms.stackexchange.com/a/26815/7136>, but same thing happened.
  
  ```
  Event::on(
      \craft\elements\Entry::class,
      \craft\elements\Entry::EVENT_AFTER_SAVE,
      function (\craft\events\ModelEvent $event) {
          Craft::debug(
              '\craft\elements\Entry::EVENT_AFTER_SAVE',
              __METHOD__
          );
      }
  );
  
  ```
  
  I certainly don't want my custom code to be executed twice. Is this a bug or an expected behavior?
  
  Craft version: 3.2.10
  
  **Tags:** craft3, events
  
  
  ---
  
  ## 2 answers
  
  ### Answer by username_0 on 2019-08-19. Score: 7 | Accepted answer
  
  After using Andrew's [debugging tip](https://craftcms.stackexchange.com/a/31236/7136), I found out one event was triggered by saving the element itself, and the other was triggered by saving the revision of the element. So I modified my event listener to be like the following, and it solved the double-up issue:
  
  ```
  Event::on(
      \craft\services\Elements::class,
      \craft\services\Elements::EVENT_AFTER_SAVE_ELEMENT,
      function (\craft\events\ElementEvent $event) {
          $element = $event->element;
          if(
              $element instanceof \craft\elements\Entry // is entry
              && $element->getSection()->handle == 'pages' // is in 'pages' section
              && !$element->getIsRevision() // is not revision
              && !$element->getIsDraft() // is not draft
              // && !$element->propagating // not during propagating (avoid batch propagating)
              // && !$element->resaving // not during resaving (avoid batch resaving)
          ) {
              // --------------- My Stuff -------------- //
              // $entry is the $element
              // $isNew = $event->isNew
              // ...
          }
      }
  );
  
  ```
  
  Depending on what you are trying to do in the event handler, you might want to toggle some if conditions. For example, you might want to avoid the same handler executed hundreds of times during a batch of [re-saving action](https://docs.craftcms.com/api/v3/craft-services-elements.html#method-resaveelements) which is triggered when a section's setting is updated and Craft automatically re-saves all the entries under the section. In this case, you might consider having a separate EVENT\_AFTER\_RESAVE\_ELEMENTS event handler.
  
  > **Comments:**
  > **username_1**: Nicely done tracking it down! If you're using Craft 3.2, there's a helper: `ElementHelper::isDraftOrRevision($element)`  
  > **username_0**: @username_1 ahh, good to know. Thanks!  
  
  ---
  
  ### Answer by username_1 on 2019-08-16. Score: 6
  
  You can find out what the stack trace is (who is calling you) by putting something like this in your anonymous function:
  
  ```php
                  try {
                      throw new \Exception();
                  } catch (\Exception $e) {
                      Craft::debug(
                          'EVENT_AFTER_SAVE_ELEMENT '.$e->getTraceAsString(),
                          __METHOD__
                      );
                  }
  
  ```
  
  Then search on `EVENT_AFTER_SAVE_ELEMENT` in your `web.log`
  
  > **Comments:**
  > **username_0**: Great tip! Thanks, Andrew!  
  
  ---
  
  