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.