Mandatory excerpt for custom post type

This is proving to be a challenge.

I’m trying to make the excerpt a required field, but only when editing/saving a post in a custom post type.

Read More

The following code makes the excerpt a required field for all posts, but doesn’t take into account for narrowing its affect to a single custom post type.

function mandatory_excerpt($data) {
  $excerpt = $data['post_excerpt'];

  if (empty($excerpt)) {
    if ($data['post_status'] === 'publish') {
      add_filter('redirect_post_location', 'excerpt_error_message_redirect', '99');
    }

    $data['post_status'] = 'draft';
  }

  return $data;
}

add_filter('wp_insert_post_data', 'mandatory_excerpt');

function excerpt_error_message_redirect($location) {
  remove_filter('redirect_post_location', __FILTER__, '99');
  return add_query_arg('excerpt_required', 1, $location);
}

function excerpt_admin_notice() {
  if (!isset($_GET['excerpt_required'])) return;

  switch (absint($_GET['excerpt_required'])) {
    case 1:
      $message = 'Excerpt is required to publish a post.';
      break;
    default:
      $message = 'Unexpected error';
  }

  echo '<div id="notice" class="error"><p>' . $message . '</p></div>';
}

add_action('admin_notices', 'excerpt_admin_notice');

Related posts

4 comments

  1. The code adds a filter to wp_insert_post_data:

    add_filter('wp_insert_post_data', 'mandatory_excerpt');
    

    And here’s the callback:

    function mandatory_excerpt($data) {
      $excerpt = $data['post_excerpt'];
    
      if (empty($excerpt)) {
        if ($data['post_status'] === 'publish') {
          add_filter('redirect_post_location', 'excerpt_error_message_redirect', '99');
        }
    
        $data['post_status'] = 'draft';
      }
    
      return $data;
    }
    

    The filter callback is passed $data, which as per the Codex includes the following post data:

    'post_author',
    'post_date',
    'post_date_gmt',
    'post_content',
    'post_content_filtered',
    'post_title',
    'post_excerpt',
    'post_status',
    'post_type',
    'comment_status',
    'ping_status',
    'post_password',
    'post_name',
    'to_ping',
    'pinged',
    'post_modified',
    'post_modified_gmt',
    'post_parent',
    'menu_order',
    'guid'
    

    Those data include 'post_type', which means you can use that inside the callback:

    function mandatory_excerpt($data) {
        if ( 'custom-posttype-slug' != $data['post_type'] ) {
            return $data;
        } else {
            $excerpt = $data['post_excerpt'];
    
            if (empty($excerpt)) {
                if ($data['post_status'] === 'publish') {
                    add_filter('redirect_post_location', 'excerpt_error_message_redirect', '99');
                }     
                $data['post_status'] = 'draft';
            }
        }     
        return $data;
    }
    
  2. The solution to the problem with posts not being able to be removed or even published is adding an extra check to make sure the mandatory_excerpt() function only fires when there is no $_GET['action'] provided. Otherwise, the function will always return an error when removing a post or changing it’s publish status.

    So the altered function would be:

    function mandatory_excerpt($data) {
        if ( 'custom-post-type-here' != $data['post_type'] || $_GET['action'] ) {
            return $data;
        } else {
            $excerpt = $data['post_excerpt'];
    
            if (empty($excerpt)) {
                if ($data['post_status'] === 'publish') {
                    add_filter('redirect_post_location', 'bstcm_excerpt_error_message_redirect', '99');
                }     
                $data['post_status'] = 'draft';
            }
        }     
        return $data;
    }
    
  3. I don’t have enough reputation on this site to comment.

    Note that the code you’re using doesn’t have the appropriate checks for the post status. As a result, your admin dashboard will fill up with lots of Auto Drafts which are usually empty, which will never be cleaned up.

    A simple fix is to do something like:

        function mandatory_excerpt($data) {
                if (empty($data['post_excerpt']) && $data['post_type'] != 'custom-post-type' && !isset($_GET['action'])) {
    
                        if ($data['post_status'] === 'publish') {
                                add_filter('redirect_post_location', 'excerpt_error_message_redirect', '99');
                        }
    
                        if ($data['post_status'] == 'publish' || $data['post_status'] == 'future' || $data['post_status'] == 'pending') {
                                $data['post_status'] = 'draft';
                        }
                }
    
                return $data;
        }
    
  4. It seems the above solution did not work so well for me (as @slowaways mentioned earlier, with WordPress 5+).
    So I came up with a new solution. Since I am using ACF, I created a new ‘short description’ field (‘extrait’) and made it mandatory. So I can use the validation features of ACF, and update excerpt value on the fly :

    /**
     * Set excerpt from ACF field
     */
    add_action('acf/save_post', function($post_id) {
    
      $post_excerpt   = get_field( 'extrait', $post_id );
    
      if ( ( !empty( $post_id ) ) AND ( $post_excerpt ) ) {
    
        // Update post options array
        $update_post_excerpt_args = array(
          'ID'          => $post_id,
          'post_excerpt'    => $post_excerpt,
        );
    
        wp_update_post( $update_post_excerpt_args );
    
      }
    
    }, 50);
    

    To give credit where credit is due i found this code here : https://gist.github.com/MWDelaney/fd0bed89b891e3ff0850428703786397

    Hope this helps.

Comments are closed.