5

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):

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

2 Answers 2

7

After using Andrew's debugging tip, 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 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.

2
  • 2
    Nicely done tracking it down! If you're using Craft 3.2, there's a helper: ElementHelper::isDraftOrRevision($element) Aug 19, 2019 at 11:56
  • @andrew.welch ahh, good to know. Thanks!
    – Wei
    Aug 20, 2019 at 4:16
5

You can find out what the stack trace is (who is calling you) by putting something like this in your anonymous function:

                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

1
  • 1
    Great tip! Thanks, Andrew!
    – Wei
    Aug 19, 2019 at 1:10

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.