Filter have_posts()/ the_post()

Actually, you’re going about this the wrong way. Don’t filter the posts in functions.php, instead, define custom loops and include them when needed.

In a simplified example, let’s say your theme only has header.php, footer.php, sidebar.php, and index.php for the structural files. Your index.php would look something like:

<?php get_header(); ?>

<div id="content">
    <?php if ( have_posts() ) : while ( have_posts() ) : the_post(); ?>
        <h2><?php the_title();?></h2>
        <div id="main">
            <?php the_content(); ?>
        </div>
    <?php endwhile; else: ?>
        <p><?php _e('Sorry, no posts matched your criteria.'); ?></p>
    <?php endif; ?>
</div>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

Pretty simple. You have a header, a sidebar, and a footer in external files and the main page content defined in the main file.

But you can add some logic here and, rather than include a generic loop each time, you can have a custom loop for everything. So instead, your index.php would look like:

<?php get_header(); ?>

<div id="content">
    <?php
    if( is_home() ) {
        get_template_part( 'loop', 'home' );
    } else if ( is_single() ) {
        get_template_part( 'loop', 'single' );
    } else {
        get_template_part( 'loop' );
    }
    ?>
</div>

<?php get_sidebar(); ?>

<?php get_footer(); ?>

Then you define your custom loops in loop-home.php, loop-single.php, and loop.php. These custom loop pages can define any custom query you can think of.