I've come accross this WP issue: https://core.trac.wordpress.org/ticket/41445

In short: when you make a request to a post over the REST API, if the featured image was originally uploaded to a different post and this post is not accessible via the REST API (eg. the original post is trashed, is a draft, etc), you get a 403 error.

This is a bug in the WordPress API and it has not been fixed yet.

Apparently, this is happening because all attachments inherit the status from their parent post (in the database, post_status='inherit')

Possible Workarounds:

  • Following this suggestion, I've updated the status of all the images I currently have in the DB:
UPDATE wp_posts
SET post_status='publish'
WHERE post_type = 'attachment'
AND post_mime_type LIKE 'image/%';

This fixes the issue for all the images I currently have... but it obviously doesn't fix any images that will be uploaded in the future.

In my case, it worked by adding edit_posts, edit_private_posts and edit_others_posts.

Solves the problem but it's definitely not ideal...

Permanent Solution?

I wonder what's the best way to get a permanent fix for this. Maybe creating a hook with add_attachment and changing the status right after an image is uploaded to WP?

Am I missing something here? Is there a better approach?

UPDATE (june 2019)

As stated in the comments, @cjbj's answer does exactly what I was asking for (when a new attachment is uploaded, it sets the status of this attachment to 'publish'). Unfortunately, it seems that this solution will break the Media Library, as it does not display images/attachments with post_status='publish'.

For anyone facing this same issue, I recommend taking the route of adding extra capabilities to users.

1 Answer 1


If I understand you correctly, you want all attachment status set to 'publish' on upload in stead of 'inherit' to prevent that status changing when the parent post status changes. Let's take a look at wp_insert_post if it offers any possibilities.

First on line 3483 (current version) the post status is set to 'inherit' in case of attachment posts:

if ( 'attachment' === $post_type && ! in_array( $post_status, array( 'inherit', 'private', 'trash', 'auto-draft' ), true ) ) {
    $post_status = 'inherit';

Later on (line 3683) all post parameters are compacted into an array called data:

$data = compact( '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', 'post_mime_type', 'guid' );

Then further on (line 3703) there is this filter:

$data = apply_filters( 'wp_insert_attachment_data', $data, $postarr );

So there you have it, a filter that allows you to change the attachment data right before it is actually stored into the database. You may exploit it like this:

add_filter ('wp_insert_attachment_data','wpse448037_force_attachment_publish', 10, 2)
function wpse448037_force_attachment_publish ($data, $postarr) {
  $data['post_status'] = 'publish';
  return $data;

Note that I didn't test this code, so some debugging may be necessary.

  • This solution indeed works.
    – jsalvata
    Jun 7, 2019 at 10:06
  • 1
    HEADS UP! @cjbj 's answer is an excellent answer (and it does exactly what I asked for) but we've just realised that applying this change breaks WP media library, as it will not display images with post_status='publish'.
    – ludovico
    Jun 27, 2019 at 16:24

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.