3

We have created a CPT which allows our customer to upload files from the admin page to a folder outside of the wp-content/uploads folder. Files are uploaded and manipulated using wp_handle_upload and wp_insert_attachment.

How do we prevent these files from showing in the media library? Can we filter by post type?

Thanks in advance for any help!

UPDATE: here's the code we've implemented so far. New uploads are still not showing in the media library.

/*FORCE LIST VIEW IN MEDIA LIBRARY*/
add_action('admin_init', function() {
    $_GET['mode'] = 'list';
}, 100);

/*HIDE GRID BUTTON IN MEDIA LIBRARY*/
add_action('admin_head', function() {
    $css = '<style type="text/css">
        .view-switch .view-grid {
            display: none;
        }
    <style>';
    echo $css;
});

/*REGISTER CUSTOM TAXONOMY*/
function create_hidden_taxonomy() {
    register_taxonomy(
        'hidden_taxonomy',
        'attachment',
        array(
            'label' => __( 'Hidden Taxonomy' ),
            'public' => false,
            'rewrite' => false,
            'hierarchical' => false,
        )
    );
}
add_action( 'init', 'create_hidden_taxonomy' );

/*CHECK IF PARENT POST TYPE IS ASSET. IF NOT ADD 'show_in_media_library' TERM*/
function assets_add_term( $post_id, \WP_Post $p, $update ) {

    if ( 'attachment' !== $p->post_type ) {
        error_log("fail1");            
        return;
    }
    if ( wp_is_post_revision( $post_id ) ) {
        error_log("fail2");            
        return;
    }
    if ( $post->post_parent ) {
        $excluded_types = array( 'assets' );
        if ( in_array( get_post_type( $p->post_parent ), $excluded_types ) ) {
        error_log("fail3");                
        return;
        }
    }
    $result = wp_set_object_terms( $post_id, 'show_in_media_library', 'hidden_taxonomy', false );
    if ( !is_array( $result ) || is_wp_error( $result ) ) {
        error_log("fail4");
    }else{
        error_log("it worked!");
    }
}
add_action( 'save_post', 'assets_add_term', 10, 2 );

/*HIDE MEDIA WITH CPT ASSETS FROM MEDIA LIBRARY*/
function assets_load_media() {
   add_action('pre_get_posts','assets_hide_media',10,1);
}
add_action( 'load-upload.php' , 'assets_load_media' );

function assets_hide_media($query){
    global $pagenow;

// there is no need to check for update.php as we are already hooking to it, but anyway
    if( 'upload.php' != $pagenow  || !is_admin())
        return;

    if(is_main_query()){
        $excluded_cpt_ids = get_posts('post_type=assets&posts_per_page=-1&fields=ids');
        $query->set('post_parent__not_in', $excluded_cpt_ids);
        //$query->set('hidden_taxonomy', 'show_in_media_library' );
    }

    return $query;
}

/*HIDE MEDIA WITH CPT ASSETS FROM MEDIA LIBRARY MODAL*/
function assets_hide_media_modal( $query = array() ){
    $query['post_parent__not_in'] = $excluded_cpt_ids;
    return $query;
}
add_action('ajax_query_attachments_args','assets_hide_media_modal',10,1);
4

Media items are just like posts with post_type = attachment and post_status = inherit.

when we are on upload.php page, we have two views:

  • List View
  • Grid View

Grid view is populated via JavaScript and list view is extending normal WP_List_Table.

Since it (List view) is using normal post query we can use pre_get_posts to alter the query to hide required media items.

How do we prevent these files from showing in the media library?
Can we filter by post type?

We can't just filter the media items by post_type since media items post_type is attachment. What you want is to filter media items by their post_parent's post ids.

add_action( 'load-upload.php' , 'wp_231165_load_media' );
function wp_231165_load_media() {
   add_action('pre_get_posts','wp_231165_hide_media',10,1);
}

function wp_231165_hide_media($query){
    global $pagenow;

// there is no need to check for update.php as we are already hooking to it, but anyway
    if( 'upload.php' != $pagenow  || !is_admin())
        return;

    if(is_main_query()){
        $excluded_cpt_ids = array();//find a way to get all cpt post ids
        $query->set('post_parent__not_in', $excluded_cpt_ids);
    }

    return $query;
}

Check this question to get id's of a certain post type.

As @tomjnowell pointed out it works for list view but it's an expensive query.

One thing you can do is that add some meta value while uploading and query against that meta value

  • This will work, but it's expensive due to the not_in part – Tom J Nowell Jul 1 '16 at 14:52
  • Yes and it also doesn't work with grid view. – bravokeyl Jul 1 '16 at 14:57
  • Thanks bravokeyl. We're trying to implement your and Tom's code but still having problems getting the hidden taxonomy to work (see above). Your post_parent_not_in gave us a 500 server error. I'm guessing the query is causing to it crash. – Richard Tinkler Jul 5 '16 at 8:46
  • BTW it's post_parent__not_in check two underscores after parent – bravokeyl Jul 5 '16 at 8:57
  • Thanks bravokeyl. post_parent__not_in was correct in the code! Have updated my question with the my current code. New uploads still not showing. – Richard Tinkler Jul 5 '16 at 14:43
4

When you create an attachment, do the following:

  • If attachments parent ID is for a post with an excluded post type, do nothing
  • If it isn't in the list of excluded post types, assign it a tag in a hidden custom taxonomy

e.g.

function create_hidden_taxonomy() {
    register_taxonomy(
        'hidden_taxonomy',
        'attachment',
        array(
            'label' => __( 'Hidden Attachment Taxonomy' ),
            'public' => false, // it's hidden!
            'rewrite' => false,
            'hierarchical' => false,
        )
    );
}
add_action( 'init', 'create_hidden_taxonomy' );

function tomjn_add_term( $post_id, \WP_Post $p, $update ) {

    if ( 'attachment' !== $p->post_type ) {
        return;
    }
    if ( wp_is_post_revision( $post_id ) ) {
        return;
    }
    if ( $post->post_parent ) {
        $excluded_types = array( 'example_post_type', 'other_post_type' );
        if ( in_array( get_post_type( $p->post_parent ), $excluded_types ) ) {
            return;
        }
    }
    $result = wp_set_object_terms( $post_id, 'show_in_media_library', 'hidden_taxonomy', false );
    if ( !is_array( $result ) || is_wp_error( $result ) ) {
        wp_die( "Error setting up terms") ;
    }
}
add_action( 'save_post', 'tomjn_add_term', 10, 2 );

Now, take the code in bravokeyls answer and instead of using post_parent__not_in, search for the tag in the hidden custom taxonomy:

add_action( 'pre_get_posts' , 'assets_hide_media' );
/**
 * Only show attachments tagged as show_in_media_library
 **/
function assets_hide_media( \WP_Query $query ){
    if ( !is_admin() ) {
        return;
    }
    global $pagenow;
    if ( 'upload.php' != $pagenow && 'media-upload.php' != $pagenow ) {
        return;
    }

    if ( $query->is_main_query() ) {
        $query->set('hidden_taxonomy', 'show_in_media_library' );
    }

    return $query;
}

This should have a significant performance boost and scale better than using post_parent__not_in, and provides a taxonomy you can use to filter on other things

This leaves you with one final problem. Attachments will only show if they have this term, but what about all the attachments you've already uploaded? We need to go back and add the term to those. To do this you would run a piece of code such as this once:

$q = new WP_Query( array(
    'post_type' => 'attachment',
    'post_status' => 'any',
    'nopaging' => true,
) );

if ( $q->have_posts() ) {
    global $post;
    while ( $q->have_posts() ) {
        $q->the_post();

        $excluded_types = array( 'example_post_type', 'other_post_type' );
        if ( $post->post_parent ) {
            if ( in_array( get_post_type( $post->post_parent ), $excluded_types ) ) {
                echo "Skipping ".intval( $post_id )." ".esc_html( get_the_title() )."\n";
                continue;
            }
        }
        echo "Setting term for ".intval( $post_id )." ".esc_html( get_the_title() )."\n";
        $result = wp_set_object_terms( $post_id, 'show_in_media_library', 'hidden_taxonomy', false );
        if ( !is_array( $result ) || is_wp_error( $result ) ) {
            echo "Error setting up terms";
        }
    }
    wp_reset_postdata();
} else {
    echo "No attachments found!\n";
}

I would recommend running this as a WP CLI command, especially if you have a lot of attachments that need processing

  • Thanks Tom. We have created a hidden taxonomy using the following but now there are no media files showing in the media library: function create_hidden_taxonomy() { register_taxonomy( 'hidden_taxonomy', 'assets', array( 'label' => __( 'Hidden_Taxonomy' ), 'public' => false, 'rewrite' => false, 'hierarchical' => true, ) ); } add_action( 'init', 'create_hidden_taxonomy' ); – Richard Tinkler Jul 5 '16 at 8:43
  • Keep in mind that the hook on save_post only adds the tag to show the post in media on save. Anything that isn't tagged will not show, aka all the stuff you uploaded prior to adding that code. Try removing the filtering code, and keeping the save hook, and going into each attachment and updating it. Alternatively, query every attachment, and run the check on its post parent, and add the term in a loop – Tom J Nowell Jul 5 '16 at 9:55
  • @RichardTinkler I've added a piece of code that will go through and add the term to all attachments that need it retroactively, and a minor modification to the save hook so that attachments that have no parent are now included – Tom J Nowell Jul 5 '16 at 10:08
  • Thanks Tom. New uploads still not showing. Perhaps I am registering the custom taxonomy wrongly? – Richard Tinkler Jul 5 '16 at 14:42
  • Possibly, I see your custom taxonomy is being used for posts, it should be registered to the attachment post type instead. I've updated the code examples, so that the loop tells you what it's doing, I've also included taxonomy registration. You don't need to use the add_action( 'load-upload.php' , 'assets_load_media' );, you can just do the pre_get_posts filter addition directly – Tom J Nowell Jul 5 '16 at 16:25
0
add_action( 'ajax_query_attachments_args' , 'custom_ajax_query_attachments_args' );

function custom_ajax_query_attachments_args( $query ) {

    if( $query['post_type'] != 'attachment' ) {

        return $query;

    }


    $posts = get_posts([
      'post_type' => 'YOUR_CUSTOM_POST_TYPE',
      'post_status' => 'publish',
      'numberposts' => -1
    ]);

    foreach($posts as $post){

        $excluded_cpt_ids[] = $post->ID;
    }  

    $query['post_parent__not_in'] = $excluded_cpt_ids;

    return $query;

}

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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