Sorting By Custom Posts With Attachments

I think I’ve got this figured out and I’d like to make sure I’m not missing anything obvious.

My goal is to prioritize a list of results by custom posts with attachments. So, I have a query returning say 60 results and, of those 60, 40 have attachments. I’d like those to show first, then continue with the posts that don’t have any attachments.

Read More

Given the limitations of the “orderby” parameter my method of attack is as follows:

  1. Create a custom field (“has_attachment”) that is updated “true” if the post has any attachments. Tie the update into an action (e.g. “attachment_fields_to_save”).

  2. Run a query to set the value to true on posts that already have attachments.

I would like to make this bulletproof and go so far as to empty the field in the event that all attachments to the post are deleted. That’s not necessary in my use-case, though, as the likelihood is slim.

Anyway, I’d like to see if any of you have suggestions for improving my method or ideas for a different way to approach this. Otherwise, I’ll get to work!

Related posts

Leave a Reply

1 comment

  1. Surprisingly, WordPress does not make it very straightforward. Even though lots of people have had similar questions on the wordpress.org forums, I believe yours is unique in that you want to keep the order and sort.

    This is by no means quality code, but does exactly what you’re looking for.

    class WP_Query_Custom extends WP_Query {
        static $filters = array( 'join', 'groupby', 'fields', 'results' );
    
        function get_posts() {
            $this->enable_filters();
            $posts = parent::get_posts();
            $this->disable_filters();
            return $posts;
        }
    
        function enable_filters() {
            foreach( self::$filters as $filter ) {
                add_filter( 'posts_' . $filter, array( __CLASS__, 'filter_' . $filter ), 10, 1 );
            }
        }
    
        function disable_filters() {
            foreach( self::$filters as $filter ) {
                remove_filter( 'posts_' . $filter, array( __CLASS__, 'filter_' . $filter ), 10, 1 );
            }
        }
    
        function filter_join($join) {
            global $wpdb;
            return "{$join} LEFT JOIN {$wpdb->posts} AS post_attachment ON {$wpdb->posts}.ID=post_attachment.post_parent AND post_attachment.post_type='attachment' ";
        }
    
        function filter_groupby($groupby) {
            global $wpdb;
            if ( ! empty($groupby) ) {
                $groupby = ",$groupby";
            }
            return "{$wpdb->posts}.ID{$groupby}";
        }
    
        function filter_fields($fields) {
            $fields = "GROUP_CONCAT(post_attachment.ID) AS post_attachments, ".$fields;
            return $fields;
        }
    
        function filter_results($posts) {
            $num_posts = count($posts);
            $offset = 0;
            $new_posts = array();
            for ( $i = 0; $i < $num_posts; $i++ ) {
                if ( ! empty($posts[$i]->post_attachments) ) {
                    array_push( $new_posts, $posts[$i] );
                    unset( $posts[$i] );
                }
            }
            return array_merge( $new_posts, $posts );
        }
    }
    
    $query = new WP_Query_Custom('post_type=post');