<p>Don't hack your code into Craft's source files. You very rarely want to modify vendor code, so that dependencies can always be cleanly installed using Composer. Instead, use an event to hook into the <code>EVENT_BEFORE_SAVE_ENTRY</code> event and add your spam checking logic there. You can use the <a href="https://craftcms.com/docs/4.x/extend/events.html#event-code-generator" rel="nofollow noreferrer">event code generator</a> to get started with some code examples. Put your code in a <a href="https://craftcms.com/docs/4.x/extend/module-guide.html" rel="nofollow noreferrer">custom module</a>.</p>
<p>In the code you posted above, you can see that the plugin triggers the event and checks <code>$event-&gt;isSpam</code>. You can use this in your hook - if the submission is caught by your spam filter, set <code>$event-&gt;isSpam = true;</code> and the plugin will block the submission.</p>
<hr />
<p>A blacklist of words will only get you so far, you'll never catch everything with it. A slightly more robust way to check for spam is a security question. Those won't help you against targeted spam, but is very effective for your run-of-the-mill bot spam. Put a question like this in your form:</p>
<blockquote>
<p>What city are our company headquarters located in?<br />
<sub>You can find the answer on our contact page</sub></p>
</blockquote>
<p>This will be easy to answer for humans, but not so much for bots (at least most simple bots, advanced bots that utilize machine learning might still get through).</p>
<p>Then define a list of correct answers (make sure to accept all possible spellings) and only let submissions through that include the correct answer. This has proven very effective for many sites I've worked on, while being quite simple to implement. It also doesn't require any external CAPTCHA service, those are problematic in regards to data privacy (and basically impossible to use in the EU in a GDPR-compliant way).</p>

CC BY-SA 4.0
2023-02-04T12:04:21.103Z
2023-02-04T12:04:21.103Z
MoritzLost
<p>I am using the guest entries plugin and i get specific spam on a contact form.
So I have edited the controller to test the message for certain words coming thru the message eg &quot;SEO&quot;, &quot;marketing&quot;. When these words are found I then return to prevent saving.</p>
<p>I've tested this locally with a duplicate of the spam message and it works.  However in the real world the spam messages are still getting through my hacky word filter. My addition is below. Im not so much looking for comment on the code - though very welcome - but wondering how can they keep getting through?</p>
<pre><code>        // Fire an 'onBeforeSave' event
        $event = new SaveEvent(['entry' =&gt; $entry]);
        $this-&gt;trigger(self::EVENT_BEFORE_SAVE_ENTRY, $event);

        if (!$event-&gt;isValid) {
            return $this-&gt;_returnError($settings, $entry);
        }

        if(preg_match('(marketing|eric|SEO|Hacked|Bitcoin|AI|ai|FREE|CLICK|LINK|links|marketing|traffic|Eric|http://skytrafficpro.com|boost|technology|Visitor )', $entry-&gt;contactMessage) === 1) {

            Craft::info('Guest entry submission spam detected.'.$entry-&gt;contactEmail, __METHOD__);

            Craft::info('Guest entry submission spam detected.'.$entry-&gt;contactMessage, __METHOD__);

            return $this-&gt;_returnSuccess($entry, true);

        } else {

            if ($event-&gt;isSpam) {
                Craft::info('Guest entry submission suspected to be spam.', __METHOD__);
                // Pretend it worked.
                return $this-&gt;_returnSuccess($entry, true);
            }

            // Try to save it
            if ($sectionSettings-&gt;runValidation) {
                $entry-&gt;setScenario(Element::SCENARIO_LIVE);
            }

            if (!Craft::$app-&gt;getElements()-&gt;saveElement($entry)) {
                return $this-&gt;_returnError($settings, $entry);
            }

            return $this-&gt;_returnSuccess($entry);
        }

</code></pre>

CC BY-SA 4.0
2023-02-01T13:47:52.200Z
Not sure what you're asking about here – is your problem that messages with your blacklisted words are still getting through? Or are you looking for better ways to detect spam messages that _don't_ include the blacklisted words? Also, where is this code placed, in a controller? Why are you triggering the save event manually instead of just hooking into the save event that is triggered by the elements service?
MoritzLost
CC BY-SA 4.0
2023-02-02T14:28:54.920Z
Yes messages with blacklisted words are still getting thru but didnt when tested locally.
Code is hacked in where save function is called
joomkit
<guest-entries><plugin-guestentries><spam>
How to stop spam with guest entries plugin?
# How to stop spam with guest entries plugin?

(Asked by: username_0 on 2023-02-01)

I am using the guest entries plugin and i get specific spam on a contact form.
So I have edited the controller to test the message for certain words coming thru the message eg "SEO", "marketing". When these words are found I then return to prevent saving.
I've tested this locally with a duplicate of the spam message and it works.  However in the real world the spam messages are still getting through my hacky word filter. My addition is below. Im not so much looking for comment on the code - though very welcome - but wondering how can they keep getting through?
        // Fire an 'onBeforeSave' event
        $event = new SaveEvent(['entry' => $entry]);
        $this->trigger(self::EVENT_BEFORE_SAVE_ENTRY, $event);

        if (!$event->isValid) {
            return $this->_returnError($settings, $entry);
        }

        if(preg_match('(marketing|eric|SEO|Hacked|Bitcoin|AI|ai|FREE|CLICK|LINK|links|marketing|traffic|Eric|http://skytrafficpro.com|boost|technology|Visitor )', $entry->contactMessage) === 1) {

            Craft::info('Guest entry submission spam detected.'.$entry->contactEmail, __METHOD__);

            Craft::info('Guest entry submission spam detected.'.$entry->contactMessage, __METHOD__);

            return $this->_returnSuccess($entry, true);

        } else {

            if ($event->isSpam) {
                Craft::info('Guest entry submission suspected to be spam.', __METHOD__);
                // Pretend it worked.
                return $this->_returnSuccess($entry, true);
            }

            // Try to save it
            if ($sectionSettings->runValidation) {
                $entry->setScenario(Element::SCENARIO_LIVE);
            }

            if (!Craft::$app->getElements()->saveElement($entry)) {
                return $this->_returnError($settings, $entry);
            }

            return $this->_returnSuccess($entry);
        }

**Tags:** guest-entries, plugin-guestentries, spam

> **Comments:**
> **username_1**: Not sure what you're asking about here – is your problem that messages with your blacklisted words are still getting through? Or are you looking for better ways to detect spam messages that _don't_ include the blacklisted words? Also, where is this code placed, in a controller? Why are you triggering the save event manually instead of just hooking into the save event that is triggered by the elements service?  
> **username_0**: Yes messages with blacklisted words are still getting thru but didnt when tested locally. Code is hacked in where save function is called  

---

## 1 answers

### Answer by username_1 on 2023-02-04. Score: 1 | Accepted answer

Don't hack your code into Craft's source files. You very rarely want to modify vendor code, so that dependencies can always be cleanly installed using Composer. Instead, use an event to hook into the `EVENT_BEFORE_SAVE_ENTRY` event and add your spam checking logic there. You can use the [event code generator](https://craftcms.com/docs/4.x/extend/events.html#event-code-generator) to get started with some code examples. Put your code in a [custom module](https://craftcms.com/docs/4.x/extend/module-guide.html).

In the code you posted above, you can see that the plugin triggers the event and checks `$event->isSpam`. You can use this in your hook - if the submission is caught by your spam filter, set `$event->isSpam = true;` and the plugin will block the submission.

---

A blacklist of words will only get you so far, you'll never catch everything with it. A slightly more robust way to check for spam is a security question. Those won't help you against targeted spam, but is very effective for your run-of-the-mill bot spam. Put a question like this in your form:

> What city are our company headquarters located in?  
> You can find the answer on our contact page

This will be easy to answer for humans, but not so much for bots (at least most simple bots, advanced bots that utilize machine learning might still get through).

Then define a list of correct answers (make sure to accept all possible spellings) and only let submissions through that include the correct answer. This has proven very effective for many sites I've worked on, while being quite simple to implement. It also doesn't require any external CAPTCHA service, those are problematic in regards to data privacy (and basically impossible to use in the EU in a GDPR-compliant way).


---

