I created a plugin that sets up a custom route and then loads a template file for that url. Everything works fine, except that WordPress seems to think it's a 404 even though it's correctly rendering my template.

For instance it says 404 in the document title and an error404 class is added to <body>

The custom url is domain.com/path/:id where :id is a dynamic value corresponding to a post id, so the URL could be domain.com/path/275. In the example below some_id is used as the post id variable.

Here's a reduced version of my plugin:


class MyPlugin {
  public function __construct() {
    add_action( 'init', array($this, 'add_response_endpoint') );
    add_filter( 'template_include', array($this, 'add_response_template') );

  public function add_response_endpoint() {

    add_rewrite_tag('%some_id%', '([^&]+)');

  public function add_response_template($template) {
    if ( get_query_var( 'pagename' ) === 'my_custom_url' ) {
      $template = trailingslashit( dirname( __FILE__ ) ) . 'templates/custom-page-template.php';

    return $template;

new MyPlugin();

Am I missing something here? Or should I start looking for this bug elsewhere?

  • Did you flush your rewrite rules? codex.wordpress.org/Function_Reference/flush_rewrite_rules – jgraup Jun 1 '16 at 13:30
  • Yes. Flushed the rewrite rules. Both manually and in the plugin's activation hook. – Ahrengot Jun 2 '16 at 10:16
  • Rewrite rules have to result in a successful main query. If my_custom_url is not the slug of an actual page, you will get a 404. If some_id is a valid post ID, then set the correct native query vars with that ID so the query succeeds. – Milo Mar 1 '17 at 16:08
  • That's just not always an option. For instance, if I want to provide a "My profile" frontend page for my users where they can update basic information about themselves. There's no post associated with such a page, but I still need a URL for it. In any case, I figured out a solution and posted my answer below. – Ahrengot Mar 1 '17 at 19:27
  • 1
    Here's an example of an approach that short-circuits the query parsing phase and doesn't produce a query that's just doomed to fail. – Milo Mar 2 '17 at 4:27

Manually setting is_404 = false; fixed my issue. However I'm not sure this is the best way to do it. I tried using the pre_get_posts filter instead without any luck.

Anyway, for anyone else in the same boat, you can do this to get rid of the 404 state:

public function add_response_template($template) {
  global $wp_query;
  if ( 'my_custom_url' === get_query_var( 'pagename' ) ) {
    $wp_query->is_404 = false;
    $template = trailingslashit( dirname( __FILE__ ) ) . 'templates/custom-page-template.php';

  return $template;

And to update the document title (The stuff inside <title> in the <head> section) here's a snippet for making that work nicely too.

add_filter( 'document_title_parts', function($title_arr) {
  if ( 'my_custom_url' === get_query_var('pagename') ) {
    $title_arr['title'] = "Document title for my custom route";

  return $title_arr;
}, 10, 1 );

If anyone knows of a better way please let me know.

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.