Before I start again, I just want to reinforce the fact you should not run a custom query in place of the main query on your archive pages. Please see this post to learn when you should use a custom query and where not. I you do not switch back to the default loop, then my solution will not work
In the previous post we have already solved the issue to only show the archives from the currently viewed category. The next issue is to only show posts from the current category when you visit the date archive from the current category
To accomplish this, we are going to make use of the following filters and actions
In order for the date archive page to know if the request came from a category page and to serve up the posts from only that category, we need to set some kind of referrer. As wp_get_referer()
and $_SERVER['HTTP_REFERER']
is very unreliable (see this post for more info), we are going to use extra parameters in the URL to set values which we will check and use to determine which posts to serve up. To achieve this, we will set a new query variable cq
which will hold the current category ID.
Next we need to modify the archive links from wp_get_archives()
when they are displayed on category pages. We need to add the category ID to the URL so that we can read the category ID when we are on the archive page to alter the main query. To alter the links to include our custom query variable, we will make use of the get_archives_link
filter to alter the links and add_query_arg
to add the custom query variables to the new links
Now that we have the new links, if we click on the links from the category pages, you will see something like this added to your URL on the date archive pages ?cq=21
. 21
is the category ID in my test site.
We must now check whenever we are on a date archive page if the new quey variable is appended to the URL. We will use filter_input( INPUT_GET, 'cq', FILTER_VALIDATE_INT );
to get the value, sanitize and validate the value from the URL. If the new query variable is appended to the URL, we need to adjust our main query to only return posts from the category which ID is added as a value to cq
. pre_get_posts
will be used here
Here is the complete code:
add_filter( 'query_vars', function ( $vars ) {
$query_vars = [
'cq'
];
$vars = array_merge( $vars, $query_vars );
return $vars;
});
add_filter( 'get_archives_link', function ( $link_html ) {
if( is_category() ) {
preg_match ( "/href='(.+?)'/", $link_html, $url );
$old_url = $url[1];
$new_url = add_query_arg( ['cq' => get_queried_object_id()], $old_url );
$link_html = str_replace( $old_url, $new_url, $link_html );
}
return $link_html;
});
add_action( 'pre_get_posts', function ( $q ) {
$cat_id = filter_input( INPUT_GET, 'cq', FILTER_VALIDATE_INT );
if( !is_admin() // Target only the front end
&& $q->is_main_query() // Target only the main query
&& $q->is_date() // Only target the date archive pages
&& $cat_id // Only run the condition if we have a valid ID
) {
$q->set( 'cat', $cat_id );
}
});
pre_get_posts
. Remove the custom query and use the default loop