# Trigger 404 template from a filter

**URL:** https://discourse.roots.io/t/trigger-404-template-from-a-filter/15636
**Category:** sage
**Tags:** sage9
**Created:** 2019-05-23T14:07:07Z
**Posts:** 17

## Post 1 by @dangelion — 2019-05-23T14:07:07Z

I need to trigger the 404.blade.php template when a “post” page is opened.  
Basing on [this article](https://richjenks.com/wordpress-throw-404/), I’m trying this inside filters.php:

```
add_action( 'template_redirect', function() {
    if ( ! is_singular( 'post' ) )
        return;

    // 1. Ensure `is_*` functions work
    global $wp_query;
    $wp_query->set_404();

    // 2. Fix HTML title
    add_action( 'wp_title', function () {
        return '404: Not Found';
    }, 9999 );

    // 3. Throw 404
    status_header( 404 );
    nocache_headers();

    // 4. Show 404 template
    require get_404_template();
    //get_template_part( 404 );
    //include( get_query_template( '404' ) );

    // 5. Stop execution
    exit;
} );
```

but it returns a blank page with the blade code inside 404.blade.php:

```
@extends('layouts.app') @section('content') 

@if (!have_posts())

{{-- {!! get_search_form(false) !!} --}} @endif

@endsection
```

How can solve?  
Thanks

---

## Post 2 by @mmirus — 2019-05-23T15:53:09Z

Blade templates need to be compiled to PHP and then output, rather than included directly like a standard WordPress template file. So, if everything is working except you’re seeing the raw Blade code rather than the rendered template, then you probably just need to use the `template()` function to compile your template and then echo the result.

Try something like `echo template(get_404_template());` instead of `require get_404_template();`.

---

## Post 3 by @dangelion — 2019-05-23T16:13:03Z

Hi @mmirus  
awesome, we’re almost there. Now it renders the 404 template but from there I don’t have the variables passed by the `App.php` controller.  
I placed `@debug` in the 404 template and indeed it prints nothing.  
You know why?  
Thanks!

---

## Post 4 by @alwaysblank — 2019-05-23T16:25:13Z

When you call a Blade template using `template(get_404_template())` you need to pass variables too it directly; it won’t automatically inherit them from context. i.e. `template(get_404_template(), ['variable_name' => 'some data'])`.

Is there a reason you can’t do the same thing with `pre_get_posts` and just turn all post requests into 404s before you get to `template_redirect`? i.e.:

```
add_action('pre_get_posts', function(query) {
   if ( $query->is_single ) {
      $query->set_404();
   }
});
```

---

## Post 5 by @dangelion — 2019-05-23T20:14:21Z

> [@alwaysblank](#):
>
> add\_action(‘pre\_get\_posts’, function(query) { if ( $query-\>is\_single ) { $query-\>set\_404(); } });

Yes, I could use pre\_get\_posts but your code catch all single (including custom post type single), while I need to catch only “post” single (not custom post types). How can do it?

Also, should I add this steps?

```
// 2. Fix HTML title
add_action( 'wp_title', function () {
    return '404: Not Found';
}, 9999 );

// 3. Throw 404
status_header( 404 );
nocache_headers();

// 5. Stop execution
exit;
```

---

## Post 6 by @alwaysblank — 2019-05-23T20:27:40Z

> [@dangelion](#):
>
> Yes, I could use pre\_get\_posts but your code catch all single (including custom post type single), while I need to catch only “post” single (not custom post types). How can do it?

My code is just an example to get you started, not a literal replacement. There are a lot of conditionals on the `$query` object that you can check to make sure it only runs on the correct post type: [Class Reference/WP Query « WordPress Codex](https://codex.wordpress.org/Class_Reference/WP_Query#Methods_and_Properties)

> [@dangelion](#):
>
> Also, should I add this steps?

Does it work if you don’t?

---

## Post 7 by @dangelion — 2019-05-24T07:09:05Z

Hi @alwaysblank I’m trying to catch the “post” single but I can’t make it works. :frowning:

None of the following worked:

```
if ( $query->is_singular('post') ) ...

if ( $query->is_single('post') ) ...

if ( $query->query_vars['post_type'] == 'post' ) ...

if ( $query->get('post_type') === 'post' ) { ...
```

Some help?

---

## Post 8 by @alwaysblank — 2019-05-24T16:10:19Z

My first step is to check if my conditional is working by adding some code that I _know_ with have an effect I’ll see, like `die("I work!")`, to see if it’s my conditional that’s not working, or the actual effect I’m shooting for (in your case forcing a 404) not firing.

i.e.:

```
add_action('pre_get_posts', function(query) {
   if ( $query->is_single) {
      die('I work!');
   }
});
```

Also make sure that the code you’re hooking into `pre_get_posts` with is firing at a time when it’s possible for it to hook into that action.

---

## Post 9 by @dangelion — 2019-05-27T18:43:12Z

Hi @alwaysblank, tried your code and it prints `I work!` on any _single_ post types, while I need it worked just for default single post (not custom post types)  
I think the conditional `$query->is_single` catches any single and I can’t find the one I need…

---

## Post 10 by @folbert — 2019-05-27T19:27:56Z

Maybe try `var_dump($query)` before `die()` and then load one page with the standard post type and one with a custom post type? That way you should be able to find a property of `$query` that you can use in combination with the code that you got from @alwaysblank to target only the standard post type.

---

## Post 11 by @dangelion — 2019-05-28T08:08:30Z

Hi @folbert, tried your idea and these are what they outputs:

**"post" type =\> [http://localhost:3000/hello/](http://localhost:3000/hello/)**  
`object(WP_Query)#340 (47) { ["query"]=> array(2) { ["page"]=> string(0) "" ["name"]=> string(4) "hello" } ["query_vars"]=> array(53) { ["page"]=> string(0) "" ["name"]=> string(4) "hello" ["error"]=> string(0) "" ["m"]=> string(0) "" ["p"]=> int(0) ["post_parent"]=> string(0) "" ["subpost"]=> string(0) "" ["subpost_id"]=> string(0) "" ["attachment"]=> string(0) "" ["attachment_id"]=> int(0) ["static"]=> string(0) "" ["pagename"]=> string(0) "" ["page_id"]=> int(0) ["second"]=> string(0) "" ["minute"]=> string(0) "" ["hour"]=> string(0) "" ["day"]=> int(0) ["monthnum"]=> int(0) ["year"]=> int(0) ["w"]=> int(0) ["category_name"]=> string(0) "" ["tag"]=> string(0) "" ["cat"]=> string(0) "" ["tag_id"]=> string(0) "" ["author"]=> string(0) "" ["author_name"]=> string(0) "" ["feed"]=> string(0) "" ["tb"]=> string(0) "" ["paged"]=> int(0) ["meta_key"]=> string(0) "" ["meta_value"]=> string(0) "" ["preview"]=> string(0) "" ["s"]=> string(0) "" ["sentence"]=> string(0) "" ["title"]=> string(0) "" ["fields"]=> string(0) "" ["menu_order"]=> string(0) "" ["embed"]=> string(0) "" ["category__in"]=> array(0) { } ["category__not_in"]=> array(0) { } ["category__and"]=> array(0) { } ["post__in"]=> array(0) { } ["post__not_in"]=> array(0) { } ["post_name__in"]=> array(0) { } ["tag__in"]=> array(0) { } ["tag__not_in"]=> array(0) { } ["tag__and"]=> array(0) { } ["tag_slug__in"]=> array(0) { } ["tag_slug__and"]=> array(0) { } ["post_parent__in"]=> array(0) { } ["post_parent__not_in"]=> array(0) { } ["author__in"]=> array(0) { } ["author__not_in"]=> array(0) { } } ["tax_query"]=> NULL ["meta_query"]=> bool(false) ["date_query"]=> bool(false) ["post_count"]=> int(0) ["current_post"]=> int(-1) ["in_the_loop"]=> bool(false) ["comment_count"]=> int(0) ["current_comment"]=> int(-1) ["found_posts"]=> int(0) ["max_num_pages"]=> int(0) ["max_num_comment_pages"]=> int(0) ["is_single"]=> bool(true) ["is_preview"]=> bool(false) ["is_page"]=> bool(false) ["is_archive"]=> bool(false) ["is_date"]=> bool(false) ["is_year"]=> bool(false) ["is_month"]=> bool(false) ["is_day"]=> bool(false) ["is_time"]=> bool(false) ["is_author"]=> bool(false) ["is_category"]=> bool(false) ["is_tag"]=> bool(false) ["is_tax"]=> bool(false) ["is_search"]=> bool(false) ["is_feed"]=> bool(false) ["is_comment_feed"]=> bool(false) ["is_trackback"]=> bool(false) ["is_home"]=> bool(false) ["is_privacy_policy"]=> bool(false) ["is_404"]=> bool(false) ["is_embed"]=> bool(false) ["is_paged"]=> bool(false) ["is_admin"]=> bool(false) ["is_attachment"]=> bool(false) ["is_singular"]=> bool(true) ["is_robots"]=> bool(false) ["is_posts_page"]=> bool(false) ["is_post_type_archive"]=> bool(false) ["query_vars_hash":"WP_Query":private]=> string(32) "267f226a4936902f26db6f23ef85759d" ["query_vars_changed":"WP_Query":private]=> bool(false) ["thumbnails_cached"]=> bool(false) ["stopwords":"WP_Query":private]=> NULL ["compat_fields":"WP_Query":private]=> array(2) { [0]=> string(15) "query_vars_hash" [1]=> string(18) "query_vars_changed" } ["compat_methods":"WP_Query":private]=> array(2) { [0]=> string(16) "init_query_flags" [1]=> string(15) "parse_tax_query" } } I work!`

**"experience" post type =\> [http://localhost:3000/experiences/experience-1/](http://localhost:3000/experiences/experience-1/)**  
`object(WP_Query)#340 (47) { ["query"]=> array(4) { ["page"]=> string(0) "" ["experience"]=> string(27) "experience-1" ["post_type"]=> string(10) "experience" ["name"]=> string(27) "experience-1" } ["query_vars"]=> array(55) { ["page"]=> string(0) "" ["experience"]=> string(27) "experience-1" ["post_type"]=> string(10) "experience" ["name"]=> string(27) "experience-1" ["error"]=> string(0) "" ["m"]=> string(0) "" ["p"]=> int(0) ["post_parent"]=> string(0) "" ["subpost"]=> string(0) "" ["subpost_id"]=> string(0) "" ["attachment"]=> string(0) "" ["attachment_id"]=> int(0) ["static"]=> string(0) "" ["pagename"]=> string(0) "" ["page_id"]=> int(0) ["second"]=> string(0) "" ["minute"]=> string(0) "" ["hour"]=> string(0) "" ["day"]=> int(0) ["monthnum"]=> int(0) ["year"]=> int(0) ["w"]=> int(0) ["category_name"]=> string(0) "" ["tag"]=> string(0) "" ["cat"]=> string(0) "" ["tag_id"]=> string(0) "" ["author"]=> string(0) "" ["author_name"]=> string(0) "" ["feed"]=> string(0) "" ["tb"]=> string(0) "" ["paged"]=> int(0) ["meta_key"]=> string(0) "" ["meta_value"]=> string(0) "" ["preview"]=> string(0) "" ["s"]=> string(0) "" ["sentence"]=> string(0) "" ["title"]=> string(0) "" ["fields"]=> string(0) "" ["menu_order"]=> string(0) "" ["embed"]=> string(0) "" ["category__in"]=> array(0) { } ["category__not_in"]=> array(0) { } ["category__and"]=> array(0) { } ["post__in"]=> array(0) { } ["post__not_in"]=> array(0) { } ["post_name__in"]=> array(0) { } ["tag__in"]=> array(0) { } ["tag__not_in"]=> array(0) { } ["tag__and"]=> array(0) { } ["tag_slug__in"]=> array(0) { } ["tag_slug__and"]=> array(0) { } ["post_parent__in"]=> array(0) { } ["post_parent__not_in"]=> array(0) { } ["author__in"]=> array(0) { } ["author__not_in"]=> array(0) { } } ["tax_query"]=> NULL ["meta_query"]=> bool(false) ["date_query"]=> bool(false) ["post_count"]=> int(0) ["current_post"]=> int(-1) ["in_the_loop"]=> bool(false) ["comment_count"]=> int(0) ["current_comment"]=> int(-1) ["found_posts"]=> int(0) ["max_num_pages"]=> int(0) ["max_num_comment_pages"]=> int(0) ["is_single"]=> bool(true) ["is_preview"]=> bool(false) ["is_page"]=> bool(false) ["is_archive"]=> bool(false) ["is_date"]=> bool(false) ["is_year"]=> bool(false) ["is_month"]=> bool(false) ["is_day"]=> bool(false) ["is_time"]=> bool(false) ["is_author"]=> bool(false) ["is_category"]=> bool(false) ["is_tag"]=> bool(false) ["is_tax"]=> bool(false) ["is_search"]=> bool(false) ["is_feed"]=> bool(false) ["is_comment_feed"]=> bool(false) ["is_trackback"]=> bool(false) ["is_home"]=> bool(false) ["is_privacy_policy"]=> bool(false) ["is_404"]=> bool(false) ["is_embed"]=> bool(false) ["is_paged"]=> bool(false) ["is_admin"]=> bool(false) ["is_attachment"]=> bool(false) ["is_singular"]=> bool(true) ["is_robots"]=> bool(false) ["is_posts_page"]=> bool(false) ["is_post_type_archive"]=> bool(false) ["query_vars_hash":"WP_Query":private]=> string(32) "438563e1c3e1141da50810663a05029d" ["query_vars_changed":"WP_Query":private]=> bool(false) ["thumbnails_cached"]=> bool(false) ["stopwords":"WP_Query":private]=> NULL ["compat_fields":"WP_Query":private]=> array(2) { [0]=> string(15) "query_vars_hash" [1]=> string(18) "query_vars_changed" } ["compat_methods":"WP_Query":private]=> array(2) { [0]=> string(16) "init_query_flags" [1]=> string(15) "parse_tax_query" } } I work!`

I can’t see a property to targets the standard post type. Am I wrong?

p.s. notice that I also have to trigger the 404 for standard “post” archives

---

## Post 12 by @folbert — 2019-05-28T08:28:57Z

My bad. `$query` doesn’t seem to hold any post data that can be easily used to determine the post type when called using the `pre_get_posts` filter.

But what if you use the filter `template_include` instead of the action `template_redirect` that you used in your original post? As taken from the [documentation for template redirect](https://codex.wordpress.org/Plugin_API/Action_Reference/template_redirect#Loading_a_different_template): “Loading a different template is not a good use of this action hook.”

Something like:

```
add_action('template_include', function($template) {

  if (is_singular('post')) {

    global $wp_query;

    $wp_query->set_404();

    // In case you need to make sure that `have_posts()` return false.
    // Maybe there's a reset function on WP_Query but I couldn't find one.
    $wp_query->post_count = 0;
    $wp_query->posts = [];
    $wp_query->post = false;

    status_header(404);

    $template = get_404_template();

  }

  return $template;

});
```

---

## Post 13 by @dangelion — 2019-05-28T10:20:08Z

Wow @folbert it seems work well! It renders the **Blade** template and I have also the variables passed by `App.php` controller. Awesome.

Just some details to understand.

1. Basing on [this article](https://richjenks.com/wordpress-throw-404/), he adds `add_action(wp_title)...` and `nocache_headers();` and `exit` at the end. You didn’t add them in your code. Are they unnecessary?

2. How can I return 404 also for standard `post` archive? In general I need to return 404 for all URL related to standard `post`

Thanks **a lot**

---

## Post 14 by @folbert — 2019-05-28T11:43:28Z

Great.

1. 

- Title - If the `<title>` for the 404-page that you get is not what you want, use the code from the article. If you want to use the same custom title for all your 404 pages, put the code outside of my example code.

- `nocache_headers()` - since WPs execution will continue as normal, I assume that WP core will take care of applying that function if needed.

- `exit` - what happens if you add [`exit`](https://www.php.net/manual/en/function.exit.php) anywhere in the code?

1. Not to sound harsh but that is more a general WP question than related to Sage so to paraphrase Neo: "Where you go from here, is a choice I leave to you. " :slight_smile:

---

## Post 15 by @dangelion — 2019-05-28T13:18:19Z

Thanks @folbert

Placing `exit` before the `return` I get browser 404 page (no WP template loaded), while placing it after the `return` it works identical (it loads the WP 404 template).

Do you think is better to add it or not?

---

## Post 16 by @folbert — 2019-05-28T13:41:01Z

If you read the manual for [`exit`](https://www.php.net/manual/en/function.exit.php) (and maybe also [`return`](https://www.php.net/manual/en/function.return.php)), I am sure that you will find the answer yourself :slight_smile:

---

## Post 17 by @system — 2019-07-04T14:07:11Z

This topic was automatically closed after 42 days. New replies are no longer allowed.
