0

Based on a condition I want to show 404 page and I have the following PHP code in functions.php

function wpse91900_force_404(string $template): string {
    global $wp;
    $current_url = home_url(add_query_arg(array(), $wp->request));
    if (str_contains($current_url, '/page/')) {
             global $wp_query;
            $wp_query->set_404();
            status_header( 404 );
            get_template_part( 404 ); exit();
    }

    return $template;
}
add_filter("template_include", "wpse91900_force_404");

The output when the above condition matches is 404 page but its not the same 404 page that is shown when I enter a random URL like website.com/abc

The difference is in the headers. Most importantly the robots header in case of code based 404 is:

<meta name="robots" content="follow, index, max-snippet:-1, max-video-preview:-1, max-image-preview:large"/>

The robots header in case of wrong URL entered is:

<meta name="robots" content="follow, noindex"/>

Other notable differences are the title of 404 page, wrong url 404 page has breadcrumbs where as the 404 page shown by above code doesn't.

enter image description here

3
  • You should instead use the pre_handle_404 filter - see example here. But why are you doing this - or are you sure you want to 404 all URLs having a /page/, e.g. example.com/page/2/ and example.com/category/foo/page/2/?
    – Sally CJ
    Aug 18, 2022 at 8:12
  • @SallyCJ Yes I want to 404 all urls containing the string /page/ at any place in the URL. So my code above is throwing 404 for all such cases but this 404 is different from a 404 shown when user enters invalid URL in browser. Since in my code, I am already inside the function for template_include filter, how do I plug the pre_handle_404 filter in my case?
    – Sandeep
    Aug 18, 2022 at 10:49
  • I've posted 2 examples, so comment out your add_filter() code and try any of my examples. Let me know.
    – Sally CJ
    Aug 18, 2022 at 13:40

1 Answer 1

1

template_include is a filter hook, so you are supposed to always return the full absolute filesystem path to a template, and not doing the get_template_part() and exit calls.

And as for setting the 404 status, I would instead use the pre_handle_404 filter, but the wp action can also be used: (note that these examples are not using PHP 8 syntaxes/functions, and secondly, I'm checking against the request path and not the full URL)

  • Using the pre_handle_404 filter:

    add_filter( 'pre_handle_404', 'my_filter_pre_handle_404', 1, 2 );
    function my_filter_pre_handle_404( $preempt, $wp_query ) {
        global $wp;
        if ( false !== strpos( $wp->request, '/page/' ) ) {
            $wp_query->set_404();
            status_header( 404 );
        }
    
        return $preempt;
    }
    
  • Using the wp action:

    add_action( 'wp', 'my_action_wp', 1 );
    function my_action_wp( $wp ) {
        global $wp_query;
        if ( false !== strpos( $wp->request, '/page/' ) ) {
            $wp_query->set_404();
            status_header( 404 );
        }
    }
    

So whichever option you chose, you should now see the proper 404 headers and template, just like what we would see when visiting a page which truly did not exist.

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.