Sorting By Custom Posts With Attachments

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');