Best way for a plugin to define a custom post type archive template?

In case anyone else comes upon this question, I’m posting the solution I ended up going with for my “Recommended Links” plugin. I think it solves most of the problems I that I anticipated pretty well.

  1. For users who want to completely customize the output, give the option of using the default WP archive template.

    This is the best solution because it fully leverages all of WordPress query features and conditionals, although its way too intensive for the average user to have to create their own archive-reclinks.php template and populate it with the correct logic and markup. I expect probably less than 5% of users will choose this option, but its there for those who want to.

  2. For ease of setup, allow users to choose an existing page to hold the archive.

    I borrowed the style from this from the Settings > Page for Posts dialog and stored the page selected in an option. The I just filtered the_content for that page with my own archive.

  3. For overridable archive styling, use locate_template() to allow users to override the plugins markup from their theme directory.

    This was the most elegant solution I could come up with. I included a mock template file in my plugin directory called loop-reclinks.php and included it in my filter on the content of the user-defined archive page using locate_template() like this:

    $old_query = $wp_query;
    $wp_query = new WP_Query( array(
        //  ... my archive query settings here
    ) );
    ob_start();
    if ( '' === locate_template( 'loop-reclinks.php', true, false ) )
        include( 'loop-reclinks.php' );
    $links_archive = ob_get_clean();
    
    $wp_query = $old_query;
    wp_reset_query();
    
    return $content . $links_archive;
    

    (truncated for clarity)

    So, the end result is that overriding the loop template I defined is as easy as copying my loop-reclinks.php to the current theme directory and modifying it; while all the business and query logic is still handled by the plugin.

Hope this helps someone else. I’m still curious as the best way other have found for handling this, so I’d like to hear any feedback, or examples of other plugins that have gotten this “righter”.