I run a relatively popular Drupal-powered site that entirely depends on user-generated content. Because the site has a decent amount of clout with the search engines, and because the principle of the site is about sharing links, it tends to get hammered with spam.
The vast majority of spam is submitted by bots, which is relatively easy to combat (I use reCAPTCHA and Spamicide). However, and somewhat surprisingly, there is still a solid amount of manually-submitted spam.
By “manually-submitted”, I mean someone is actually taking the time to create a (probably fake) e-mail address, registering on the site, confirming the e-mail and then submitting their pieces of spam one-by-one. When last I counted, I receive about 100 to 200 spam content items by this method per week. That the spam never sees the public eye doesn’t seem to deter spammers in the least. None of this spam is ever “published” on the site, it is all held in a queue until I can manually delete it. A pain for me, and of absolutely no value to spammers. I’d e-mail them and ask why they bother if I thought it would result in an answer.
Under the assumption that my pleas to stop would go unanswered, I decided to sit down and come up with an efficient way of dealing with it. The problem is that the queue could potentially hold submitted material from new users (once a user has submitted good content, they immediately get a role that allows them to bypass the queue), so each item must be vetted as either ham or spam.
A while back I began using the Spambot module, which does a great job. With it you can click a “Spam” link on a user’s profile page and immediately delete them and all their content. What’s more, you can report them to the excellent Stop Forum Spam service and give the spammers a slightly harder time respamming (or spamming others).
Spambot is great, but slow. To moderate, I need to look at a piece of content, determine if it’s spam, click the submitter’s name, click the “spam” menu item, select some options and then delete. For intermittent spam submissions this would be fine, but for dozens of spammers every few days, it’s too labourious.
And so today I came up with a better system of bulk/batch killing mass amounts of manually submitted spam in one fell swoop, and also report the spammers to Stop Forum Spam. The following is what I did and how I did it. Please, please read the disclaimer + warning at the bottom of the post before proceeding.
How To Do It
My goal was to create a system whereby I could simply select all the spam content directly from the main list of Drupal content, select a “Kill Spam” action from the “Update” dropdown and be done with it. So if a spammer submitted 10 articles, I could simply select one, flag it as spam and the system would kill all the content by that user, delete the user and report them to Stop Forum Spam.
First things first, you’re going to need a few Drupal modules:
Once we have those installed, we need to configure each one to do what we need.
Create a “Spam” flag
The first step is to create an action we can use on the Content page to flag our content as spam (and then automatically do something with it). For this we turn to the appropriately named “Flag” module — /build/flags/add — give the flag any name you wish (eg. “kill_spam”) and then click “submit”. The following screen will give you a number of fields to fill in to define your flag. The key fields are:
- Flag Link Text: this is the text that will be shown as the update action on our Content page. Set it to something obvious (“Flag as Spam”)
- Global flag: make sure it’s checked
- Roles that may use this flag: You’ll probably want to limit this to the administrator (or moderators)
- What nodes this flag may be used on: You can limit which content types this flag can be applied to
Create a VBO View to list all content by a certain author
Things are going to start to get a bit trickier, but hold on tight and we’ll get through this together. Next up is creating a list of content we can perform batch operations to. We want to be able to select a single piece of content and from that get the user who submitted it, and all their other content. To do this we use the extremely powerful combination of Views and Views Bulk Operations (VBO).
Create a new View (Site Building -> Views -> Add), call it whatever you’d like (eg. “content_by_user”) and make sure View type is set to “node”. The settings for the view are:
- Style: Bulk Operations — Under the Style Options you’ll be presented with a long list of available operations. Put a check beside “Delete Node“.
- Items to display: Unlimited
- Add an Argument of User: Uid — This filters the results by a specific user ID. Very important, as we don’t want to bulk delete just any old content. See this screenshot for detailed settings.
- Fields — strictly speaking, you do not need to add fields, as the bulk operation isn’t going to use them. However, I found it handy for testing and so added a few.
- Filter — The only filter I set was for “Published” and then set it to “no”. This was a bit of a failsafe to assure that I could only ever bulk kill unpublished nodes.
That’s it, if you set everything right, it should look similar to the screenshot below. You can test and see if the right results are occurring by putting a spam user’s UID in the argument field for the preview section below the view (you’ll need to have added some fields as mentioned in the points above). It should list all the spammer’s content. If no argument is given, no content should show up. If content does show up when no argument is present, double check your settings.
Creating the Rule & putting it all together
The final step is to create an action (or rule) that triggers when the content is flagged. We do this with the (again, appropriately named) Rules module — /admin/rules/trigger/add.
Give it a label, any label, and then select A node has been flagged, under “Spam Flag” for the event. The next screen will allow you to choose conditions (IF) and actions (DO).
We only need one condition, and if that is optional.
- Content is Published: NOT. You need to check the “Negate” checkbox to get the NOT part. This is another failsafe so that the action will never get triggered unless the content you’re flagging is unpublished. It’s not strictly necessary, and may not be applicable in all cases (ie. if your spam content could potentially be published when moderating it).
We will add four actions: Load the flagged content author, Use user object to execute a VBO programmatically, Report to StopForumSpam.com, Delete user.
- Load the flagged content author: From the select box choose Content->Load the content author. This is where we get the author (ie. spammer) UID to pass to our VBO View we created above. The “Content” select box under “Argument configuration” should have “flagged content” selected.
- Use user object to execute a VBO programmatically: This action deletes all content by our spammer based on the Bulk Operations view we created above. The key part of this step is supplying the View with the user UID of our spammer. On the edit screen, use the following options (screen capture):
- Object: We choose “flagged content author”.
- View: We select the view we created earlier, in my case it’s called content_by_user.
- Operation: Assuming you followed the directions above, you should only have one option here, Delete Node.
- View Arguments: This is where we pass the UID argument to the view. Simply input the following into the box: return array($object->uid);
- Report to StopForumSpam.com: This is an optional action that will report the spammer to StopForumSpam.com and hopefully help prevent the spammer from spamming your site or mine in the future. For this step you’re going to need a free API key from StopForumSpam.com. To create it we create a new action of the type “Execute custom PHP code”. Give the action a label (eg. “Report to StopForumSpam.com”) and put the following PHP in the PHP Code area. NOTE: You should not include the <?php or ?> delimiters:
Much credit for this code is owed to Spambot, as a good chunk of it was lifted directly from that module. The code hunts down various IPs that the user used to access the site, including Sessions, Comments, Statistics (if enabled) and User Stats (if enabled — the User Stats module is required).
- Delete user: The final action simply kills the spammer user account. Make sure the User setting is set to Flagged content author.
Your Rule should now look something like the following:
If you made it this far, give yourself a pat on the back — that wasn’t for the faint of heart. You should now be able to head over to your Content list, select the spam content items and choose your flag from the “Update options” list. As soon as you hit update, your system should trigger the rule, which will delete the spam content items, report the spammer and delete the spam user’s account.
Disclaimer + Warning
Please be aware that while I’ve tried to be thorough in the above information, and everything is working fine on my own site, you should not attempt any of the above if you’re not confident working with Drupal or some of the above is clear and logical to you. This how-to is written for advanced Drupal users in mind, there is a very real potential to delete content and users unintentionally if the above is implemented incorrectly. And remember, backup, backup, backup. Oh, and don’t forget to backup.