How to moderate posts

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
1

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.

Leave a Comment