7

I am writing a plugin that will moderate all posts regardless of what level user posted them. It will check the post content and title against a list of words and if any are in the post, I want to put the post in the moderation queue as if it were posted by a contributor. This part works fine, but I also want it to automatically delete posts with really bad words. This is how I currently have it:

function filter_handler( $data , $postarr ) {
    // Get vars from data
    $content = $data['post_content'];
    $title = $data['post_title'];
    // Array of words that will hold a post for aproval
    $badWords = array(
        "link=", "content-type", "bcc:", "cc:", "document.cookie", 
            "onclick", "onload", "javascript"
    );
    $reallyBadWords = array(
        "query", "pluginTesting"
    );
    // If bad words exist in post, set post_status to pending
    foreach ( $badWords as $word ) {
        if ( 
            strpos( strtolower( $content ), strtolower( $word ) ) || 
            strpos( strtolower( $title ), strtolower( $word ) ) 
        ) {
            $data['post_status'] = "pending";
        }
    }
    // If really bad words exist, delete post
    foreach ( $reallyBadWords as $word ) {
        if ( 
            strpos( strtolower( $content ), strtolower( $word ) ) || 
            strpos( strtolower( $title ), strtolower( $word ) ) 
        ) {
            $data['post_status'] = 'trash';
        }
    }
    return $data;
}
add_filter( 'wp_insert_post_data', 'filter_handler', '99', 2 );

This works for the regular words but requires two really bad words to set a post to trash. Also using this method, when a user publishes a post with really bad words, they get directed to an error page telling them they are not allowed to edit posts in the trash.

What would be a good way to fix this so that it sends users back to the posts page and displays an error message informing them that their post was deleted?

Also, how can I fix the fact that it requires two really bad words before deletion?

1
  • This seems deceptively simple and clever. Good work! I don't understand though why it requires two 'really bad words' before deletion - with a quick look at the code, it should be one. Do you know why it is requiring two words?
    – Tim Malone
    Jun 26, 2016 at 7:52

1 Answer 1

2

This is a partial answer, because as I mentioned in my comment I'm not sure why your code is requiring two 'really bad words' at the moment. It's also an untested attempt.

I'll deal with your first question: how to send a user back to the posts page and display a suitable error message, rather than an error about editing posts in the trash.

A way to do this that comes to mind is using wp_redirect() with a custom querystring parameter, that you can then detect and display your error message with the admin_notices action.

However we can't redirect right away, because we need the wp_insert_post_data hook to complete its work first. Looking in the source, we could potentially redirect at the end of the wp_insert_post() function, in the save_post or wp_insert_post actions. We'll also need a way to check at this stage if a redirect is needed - which we can probably safely do by checking if the post_status is 'trash' and if it's a new post (because when else would a new post be going to the trash?).

Here's a potential workflow:

// if this is a new post but it's in the trash, redirect with a custom error

add_action( 'wp_insert_post', 'wpse_215752_redirect_from_trash', 10, 3 );

function wpse_215752_redirect_from_trash( $post_ID, $post, $update ) {
  if( !$update && 'trash' === $post->post_status ) {
    wp_redirect( admin_url( 'edit.php?custom_error=badwords' ) );
    die();
  }        
}

// if our custom error is set in the querystring, make sure we show it

if( isset( $_GET['custom_error'] ) && 'badwords' === $_GET['custom_error']) {
  add_action( 'admin_notices', 'wpse_215752_badwords_error' );
}

function wpse_215752_badwords_error() {
    $class = 'notice notice-error';
    $message = __( 'Sorry, that post cannot be made.', 'your-text-domain' );
    printf( '<div class="%1$s"><p>%2$s</p></div>', $class, $message ); 
}

I haven't tested this, mind you, but I trust this gives you something to get started with!

Other options to look at might include the wp_transition_post_status actions, particularly new_to_trash, which - by looking at the source - should also be called in your situation.

Finally, if I was a user, I might want the opportunity to edit my post rather than have it automatically trashed, but this is a user experience decision on your part.

Disclaimer: This might not necessarily be the best way to do this, but I hope it gives you some direction nonetheless, and perhaps others can chime in if there's a better way.

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.