I am trying to block the visualization of a custom post, of type 'product', if it is assigned to certain values of the taxonomy 'product_cat'.

Strictly speaking, I would like to block the visualization of a product if it falls under certain categories.

I can not make this work, even by hardcoding a forbidden name for a product_cat ('plus' in this example).

function filter($query){
   if ($query->is_single && is_main_query()) {
        $tax_query = array(
                'taxonomy' => 'product_cat',
                'field' => 'name',
                'terms' => array('plus'),
                'operator' => 'NOT IN',
        $query->set( 'tax_query', $tax_query );

If I try to visualize a product falling under the 'plus' category, Wordpress shows it despite this filter.

What am I missing here?


Edit: This code goes in a Wordpress plugin, I forgot to mention this. I am not allowed to touch any template..

  • It looks like you are doing this on a single post view, right? I'm not sure the effect of trying to block the single post being displayed, but it cannot turn out good. It would probably be a better approach to try and not filter out those entries but rather display some message or preset content instead of the item based on the taxonomy values you want suppressed.
    – Ed Burns
    Jan 2 '13 at 16:10
  • Yes Ed, I am trying this on a single post view. On the other hand, how can I assume that by filtering archive queries, nobody will ever reach the post by using the direct URL for it? This is what I am trying to achieve..hope it was clear
    – user24742
    Jan 2 '13 at 16:31

You are not going to be able to prevent anyone from ever loading that page. Even if there is no link to it, you probably have a sitemap generated that creates links to all items. So wanting to block it is the right thing to do but changing the query to try and do it is not.

Probably the best and easiest approach is to use loop templates in your single.php. If you have loop-single.php (for legitimate items) and then loop-disallow.php (for the ones you do not want used), then the following code would help:

$template = 'single';
if(<in taxonomy logic here>) $template = 'disallow';
get_template_part('loop', $template);

Then for your disallow loop, you can just display an Item Not Found or something along those lines. You could also consider adding logic to the header to issue a 404 when one of these pages are hit.

--- UPDATE ---

If you want to do this in a plugin, it is actually a fairly simple process. You can create a filter on the_content that only changes the content when your taxonomy is encountered.

Another approach would be to simply force a 404 when the taxonomy is detected on a single page using:

include( get_query_template( '404' ) );

You would have to experiment about the best place to put this and you may need some other code (an exit call perhaps - which scares me!) to make sure the normal template doesn't load after the 404.

  • I forgot to mention that I am developing this code in a Wordpress plugin, sorry!
    – user24742
    Jan 2 '13 at 16:44
  • I think that actually makes it easier. I'll update that as an option in my answer.
    – Ed Burns
    Jan 2 '13 at 16:47
  • Cheers, you pointed me in the right direction. I hooked up the action woocommerce_before_single_product and put the 404 related code of this other answer: wordpress.stackexchange.com/a/27124/24742
    – user24742
    Jan 2 '13 at 17:09

The first thing I've noticed here is that you're checking that it's a single query. Should this only be blocking the single view? If you're looking at filtering an archive page, you will never fall into the if block.

Aside from that, you are using the "name" field where the "slug" might be more appropriate in most cases. The name field includes spaces and capitalization, where the slug field is as the term appears in the URL. Swapping these might make a difference.

Finally, I believe this is from copying the code in, but there is a syntax error in your code due to not closing your if block that will need to be addressed.

Edit: Following up on your feedback about hitting the URL directly, you can use the filter as outlined, in which case it would return a 404 response. If that is not what you desire, you could capture the request any time after the query parameters are set and redirect the request as you see fit.

Edit again: When using a filter, always return the first parameter you receive in your function, whether or not an edit is made.

  • Cheers, I corrected the typo from the snippet. Unfortunately, it was not the real issue as you suspected :) See the comment on my question: I already block at "archive" level. I am trying to block people accessing single pages. Using the slug does not solve the issue. Thanks for the info anyway, I will use slugs from now on!
    – user24742
    Jan 2 '13 at 16:34
  • Oh, I missed the obvious. You're using a filter. Be sure to return the first parameter you received. (In this case, be sure to return the $query object you received and modified).
    – devbyday
    Jan 2 '13 at 16:38
  • Thanks for all the edits. It is not a problem for me to return the $query parameter. However, aren't WP devs claiming it is not necessary? See codex.wordpress.org/Plugin_API/Action_Reference/… In any case, this is not the point of my question. Are you suggesting in your answer ("you can use the filter as outlined") that my filter should just work?
    – user24742
    Jan 2 '13 at 16:43
  • Ah, I had not reviewed "pre_get_posts" which is run as an action instead of a filter. In that case, what you are doing should work. Have you logged or printed out the query object after modification to determine what the query looks like that it's trying to run?
    – devbyday
    Jan 2 '13 at 16:45
  • Yup, the modification is included: [tax_query] => Array ( [0] => Array ( [taxonomy] => product_cat [field] => name [terms] => Array ( [0] => plus ) [operator] => NOT IN ) ) ) However, Wordpress ignores it..
    – user24742
    Jan 2 '13 at 16:52

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy