0

I'm not even sure how to ask this question… :(

I want to create a new way to view my posts, where they are paged by weeks. (That is to say, a "page" is not a specific number of posts.)

I want to set this up without modifying any of the existing WP behavior. How do I set up another instance of "displaying of posts" so that I can begin to modify the WP Query?

(I understand this will require determining the specific date-range for the WP Query which corresponds to each "page number" of the pagination. The first page will be the posts for the date range of the most-recent, complete week; which is not simply the most recent posts. Page 2 will be the week before that. Etc.)

3
  • 3
    what about a weekly list with wp_get_archives( array( 'type' => 'weekly' ) ); that generates links like example.com?m=2023&w=1
    – birgire
    Commented Apr 16, 2023 at 21:35
  • How do I get a new "view"… I need a new template so that I can overhaul how the selected posts are displayed—that's the part I can't figure out. I don't want to change the Post-Format on the posts though. I want to keep everything else about WP as-is... or perhaps, since I'm not currently using the usual Archives, I can just edit the template that applies to an Archive page's display. Commented Apr 17, 2023 at 10:25
  • 1
    Maybe adding a weekly body class via filter (check e.g. for is_date() archive and the w query variable) can help for CSS only adjustments. Otherwise mods on the archive page template/template-parts sounds like a good plan.
    – birgire
    Commented Apr 17, 2023 at 21:27

1 Answer 1

1

Here's what I ended up with:

  • Everything within my child-theme
  • file example-single.php for displaying individual posts within a template
  • file example.php a new template as a destination for new routes.
  • new routes and a filter on 'pre_get_posts'

All of the following can simply go in functions.php in the child theme:

function example_routes() {
    // add "/example/" routes
    add_rewrite_rule(
        '^example/(\d+)[/]?$', // for "/example/42" paging of posts
        'index.php?example=1&number=$matches[1]',
        'top'
    );
    add_rewrite_rule(
        '^example/?$',  // for "/example/" display of current posts
        'index.php?example=1&number=current',
        'top'
    );
}
add_action('init', 'example_routes'); // visit Permalinks pg to intialize

Next example and number are new query vars that need defining…

add_filter(
    'query_vars',
    function($query_vars) {
        $query_vars[] = 'example';
        $query_vars[] = 'number';
        return $query_vars;
    }
);

When to load that new example.php template file from the child theme…

add_action(
    'template_include',
    function($template) {
        if ( get_query_var('example') == false || get_query_var('example') == '' ) {
            return $template;
        }
        // get_stylesheet_directory() will path to the active child theme.
        // get_template_directory() does not.
        return get_stylesheet_directory() .'/example.php';
    }
);

Finally, modify the query when the template loads via the new routes. There's also a calculation function (rather than simple inline code) because this calculation is also useful on the template's page. The October 2022 dates in the code are the specific dates of posts for my particular use case.

function example_current_number() {
    $origin = new DateTimeImmutable('2022-10-09'); // the very first issue's pub date
    $today = new DateTimeImmutable(date('Y-m-d'));
    $interval = $origin->diff($today);
    $days = $interval->format('%a'); // %a is number of days
    return 1 +floor($days/7.0); 
}
add_action(
    'pre_get_posts',
    function($query) {

        // Query modification for "example" pages…
        if ( true == get_query_var('example') && $query->is_main_query() && !is_single() ) {
            $current = example_current_number();
            if ( 'current' == ($number=get_query_var('number')) ) {
                $number = $current;
                set_query_var('number', $number);
            }
            if ( $number > $current ) {
                $number = $current; // no peeking ahead
                set_query_var('number', $number);
            }
            $offset = ' +'.($number-1).' weeks';

            $query->set(
                'date_query',
                [[ // note array of arrays
                    'after' => '00:00 October 3, 2022'.$offset,
                    'before' => '23:59 October 9, 2022'.$offset,
                    'inclusive' => true
                ]]
            );
        }

        return $query;
    }
);

And then all-together it works like this, https://constantine.name/7-for-sunday/

ɕ

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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