Archive page for taxonomy of custom post type

Before I start, you have a bug in your code which you should have picked up if you had debug turned on. You are first assigning $r['cat'] to a variable before even checking if $r['cat'] is set. Because cat is not a default, it may not be set, which will cause a PHP error when cat is not set. You can refactor your code to something like this: (Requires PHP5.3+. I also assumed that this worked as intended, so I have not changed anything)

add_filter('getarchives_join', function ( $x, $r ) 
{
  global $wpdb;

  // Set $cat_ID to the value of $r['cat'] if it is set, otherwise set to false
  $cat_ID = isset( $r['cat'] ) ? $r['cat'] : false;

  // If $cat_ID is false, return $x as is
  if ( !$cat_ID )
    return $x;

  // We have a value in $cat_ID, lets modify and return the required sql string
  return $x . " INNER JOIN $wpdb->term_relationships ON ($wpdb->posts.ID = $wpdb->term_relationships.object_id) INNER JOIN $wpdb->term_taxonomy ON ($wpdb->term_relationships.term_taxonomy_id = $wpdb->term_taxonomy.term_taxonomy_id)";

}, 10, 2 );

Now that we got that out of the way, lets look at the real issue here. In order to get the correct posts on the archive page when an archive is selected, we need to

  • know where the request came from

  • filter the main query according to where the post came from to display the correct posts.

To tackle bullet point 1, we need some kind of referrer in order for us to know where the archive page request came from. This referrer will be our key which will enable us to display the correct posts according to term.

HTTP referrers is extremely unreliable as there are many client side factors that can alter or control the value of a referrer. The following section is a section I took from one of my previous answers as additional info to referrers, so you can take your time and read through the following

The problem with referrers is, they are set and controlled by user
side. Referrers can be disabled or blocked (like users accessing a
site behind a proxy). Just for interest sake, here is very interesting
answer to the question In what cases will http referrer be empty
taken from this post on
SO

It will/may be empty when the enduser

  • entered the site URL in browser address bar itself.
  • visited the site by a browser-maintained bookmark.
  • visited the site as first page in the window/tab.
  • switched from a https URL to a http URL.
  • switched from a https URL to a different https URL.
  • has security software installed (antivirus/firewall/etc) which strips the referrer from all requests.
  • is behind a proxy which strips the referrer from all requests.
  • visited the site programmatically (like, curl) without setting the referrer header (searchbots!).

You would want to read the other answers there as well for extra
insight

I sat with similar issue and was looking for a more reliable way to
set and pass referrers, and this led to [this question](
Get default permalink structure from pretty URL’s) and a wonderful
answer by @gmazzap

As I hinted in comments, we will pass a value in the URL that we will use as a referrer to show the correct posts according to term in the archive page. To accomplish this, we need to filter the get_archives_link() function to add our referrer to the archive URL and also add our referrer to the list of query_vars so that we can read and use it.

First, add the query_vars, lets call it ref, which is short for referrer. ref will hold a custom value which will be equivelent to the term ID

add_filter( 'query_vars', function ( $vars )
{
    $vars[] = 'ref';

    return $vars;
});

Now the ref is readable, lets add it to our archive link in the get_archives_link() function through the get_archives_link filter: (This requires PHP 5.4+ due to short array syntax ([]))

add_filter( 'get_archives_link', function ( $link_html ) {

    if( is_tax() ) { // Adjust this to target specific taxonomies or taxonomy terms if needed

        preg_match ( "/href="https://wordpress.stackexchange.com/questions/195110/(.+?)"https://wordpress.stackexchange.com/", $link_html, $url );

        $old_url = $url[1];
        $new_url = add_query_arg( ['ref' => get_queried_object_id()], $old_url );
        $link_html = str_replace( $old_url, $new_url, $link_html );

    }

    return $link_html;

});

You will now see that if you click on an archive link from a taxonomy page, you will see something the following being added to the URL, this will now be our referrer

 ?ref=1

where one is the ID of our term

The last part (2nd bullet point) is to filter our query accordingly. Here we need to

  • check if ref is set

  • if ref is set, get its value (Don’t forget to sanitize to avoid data injection)

  • filter the main query accordingly

The final part of the code looks like this: (Requires at least PHP 5.4+ due to short array syntax)

add_action( 'pre_get_posts', function ( $q )
{
    // VERY VERY IMPORTANT: Check if `ref` is set as $_GET variable, get the value and validate as an integer
    $referrer = filter_var( INPUT_GET, 'ref', FILTER_VALIDATE_INT );

    if (    !is_admin() // Only target front end queries
         && $q->is_main_query() // Only target the main query
         && $q->is_date() // Only targets date archive pages, adjust as needed
         && $referrer // Only proceed if $referrer has a value
    ) {
        // To avoid bugs in a multi custom taxonomy install, check if the term is valid
        if ( term_exists( $referrer, 'CUSTOM_TAXONOMY_NAME' ) ) { // IMPORTANT: Use the correct taxonomy name here
            // Set our taxonomy term filter, again, set the correct taxonomy name
            $tax_query = [
                [
                    'taxonomy' => 'CUSTOM_TAXONOMY_NAME',
                    'terms' => $referrer,
                    'include_children' => false,
                ]
            ];
            $q->set( 'tax_query', $tax_query );
            $q->set( 'post_type', ['post', 'YOUR_CUSTOM_POST_TYPE'] ); // Adds custom post type to date archives
        }
    }
}, PHP_MAX_INT );

TAKE NOTE:

Most of the code above is untested, so it might be buggy. Also, most of the code requires PHP5.4+, this should be the minimum PHP version you have installed as all older versions have been EOL’ed and is therefor no longer supported. Although they still work, they do not get security updates, and this can cause serious harm to your site’s overall security

Leave a Comment