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:

<?php

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_rule(
      '^path/([0-9]+)/?',
      'index.php?pagename=my_custom_url&some_id=$matches[1]',
      'top'
    );

    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?

2 s
2

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.

Leave a Reply

Your email address will not be published. Required fields are marked *