One of our clients runs a WordPress website with many contributors. With so many people writing content for their website, it’s very important for posts to conform to guidelines for the sake of consistency. One of these guidelines is that the featured image of the “post” (default blog) post type be set. We set out to implement a feature that allows users to publish their post only if they set the featured image.

This feature needed to meet these requirements:

  • Always save the post
  • Display a notification to the user that their post has been updated
  • Display a notification to the user that their post has not been published
  • After adding a featured image, publish the post with no extra steps

This featured proved to be slightly tricky. As I understand it (the author), Wordpress follows this process when saving a post.

  1. User creates new post
  2. User adds content to post
  3. User hits publish
  4. Wordpress POSTS data
  5. Wordpress completes POST request, then does a GET request to display any notifications to the user

My original idea was to just catch a POST request and conditionally react to it. But, this proved to be an issue. The problem was that, I had to wait for the completion of the GET request before I could know if the user provided a featured image. If they didn’t, I would fire off a second GET request to change the post to draft. This was a bad experience for both the author user and the guest user. The author user would see too many redirects. And the guest user might see posts quickly be created and then removed on the frontend.

So, I decided I needed to know if the featured image was added before the POST request was sent. Then, if the user didn’t add a featured image, change the post status to draft, then allow the post to be saved to the database. Afterwards, when the GET request happens, I need to add a notification to the user. I also need to remove the post updated notification, because that could be confusing to the user.

Here’s how I did it


// This function will set the post to draft if no featured image is set
function isolary_check_post_thumbnail($data, $postarr) {
  if (array_key_exists('_thumbnail_id', $postarr) && $postarr['_thumbnail_id'] == -1 && get_post_type($postarr['ID']) == 'post') {
    $data['post_status'] = 'draft';
  }
  return $data;
}
add_filter( 'wp_insert_post_data' , 'isolary_check_post_thumbnail' , '99', 2 );

// This function checks if the user included a featured image, if not it throws an error and tells Wordpress to show a error message
function isolary_save_post($post_id) {
  // Error is false by default, as we assume there aren't any errors.
  $error = false;

  // Check if the post is a "post" post type, if not, return true (we don't do any checks against custom post types at the moment)
  if (get_post_type($post_id) != 'post') {
    return true;
  }

  if (!has_post_thumbnail($post_id) && get_post_type($post_id) == 'post') {
    $error = new WP_Error(422, 'Your post, {get_the_title($post_id)}, could not be published as it does not have a featured image');
  }

  if ($error && get_post_type($post_id) == 'post') {
    add_filter('redirect_post_location', function($location) use ($error) {
      return add_query_arg('isolary_save_post_error', $error->get_error_code(), $location);
    });
  }

  return true;
}
add_action('save_post', 'isolary_save_post');

// This function is the error message that gets thrown if no featured image is included
function isolary_no_featured_image_error_message() {
  if (array_key_exists('isolary_save_post_error', $_GET)) { ?>
    <div class="error">
      <p>
        <?php
          switch($_GET['isolary_save_post_error']) {
            case 422:
				// TODO: Replace with the actual WP_Error message
              echo 'Your post has been set to draft because you did not include a featured image. Add a featured image and update your post to publish it';
              break;
            default:
              echo 'An error occured when saving the post';
              break;
          }
        ?>
      </p>
    </div> <?php
  }
}
add_action( 'admin_notices', 'isolary_no_featured_image_error_message' );

// This function removes the "post published" notification when our featured image error is thrown
function isolary_remove_post_published_featured_image($messages)
{
    if (array_key_exists('isolary_save_post_error', $_GET)) {
      unset($messages['post']['6']);
      return $messages;
    }
    return $messages;
}
add_filter( 'post_updated_messages', 'isolary_remove_post_published_featured_image' );