I am trying to add custom end point url to custom post type posts. After much searching I have added the add_rewrite_endpoints to functions.php

    function psf_game_endpoints() {
    add_rewrite_endpoint( 'related-articles', EP_PERMALINK );
    add_rewrite_endpoint( 'review', EP_PERMALINK );
    add_rewrite_endpoint( 'screenshots', EP_PERMALINK );
add_action( 'init', 'psf_game_endpoints' );

I have also added a filter for query vars (don;t really know what that means but found the code on here) This code is also in functions.php

add_filter( 'request', 'wpse42279_filter_request' );
function wpse42279_filter_request( $vars )
    if( isset( $vars['related-articles'] ) ) $vars['related-articles'] = true;
    if( isset( $vars['review'] ) ) $vars['review'] = true;
    if( isset( $vars['screenshots'] ) ) $vars['screenshots'] = true;
    return $vars;

And I have also added a function to functions.php to load the templates I have made for each endpoint, this is also in functions.php

    function wpd_game_template( $template = '' ) {
    global $wp_query;
    if( ! array_key_exists( 'review', $wp_query->query_vars ) ) return $template;

    $template = locate_template( 'single-game-review.php' );
    if( ! array_key_exists( 'related-articles', $wp_query->query_vars ) ) return $template;

    $template = locate_template( 'single-game-related.php' );
    if( ! array_key_exists( 'screenshots', $wp_query->query_vars ) ) return $template;

    $template = locate_template( 'single-game-screenshots.php' );
    return $template;
add_filter( 'single_template', 'wpd_game_template' );

on the main custom post type template (single-game.php), I have added a navigation menu to take you to the relevant endpoint URL:

                // Permalink structure for tab URls
                if ( ! get_option( 'permalink_structure' ) ) {
                    $permalink_structure = '&';
                    $trailing_slash = '';
                } else {
                    $permalink_structure = '';
                    $trailing_slash = '/';

                <div class="game-post-tabs">
                    <nav class="game-tab-nav">
                        <a href="<?php echo get_permalink(); ?>">Overview</a>
                        <a href="<?php echo get_permalink() . $permalink_structure . 'related-articles' . $trailing_slash ; ?>">Related Articles</a>
                        <a href="<?php echo get_permalink() . $permalink_structure . 'review' . $trailing_slash ; ?>">Review</a>
                        <a href="<?php echo get_permalink() . $permalink_structure . 'screenshots' . $trailing_slash ; ?>">Screenshots</a>



The main single-game.php template loads fine and displays the_content() like it should, but the other endpoint URL's all return 4040 page not found errors. I am doing this on a test site with WP_DEBUG and DEBUG LOG enabled but I am getting no errors at all, so I am at a complete loss as to what is going wrong.

Any help would be much appreciated, thanks.


1 Answer 1


So I'm not sure why are you getting the 404 error page, but there are two possible reasons why could that happen:

  1. Whenever you do anything that changes the permalink structures, e.g. you registered a new post type or taxonomy, or you programmatically added a custom rewrite rule or endpoint, then don't forget to flush the rewrite rules so that WordPress recognizes the new rewrite rules and regenerate them in the database (or in certain cases/setup, WordPress might instead write all the rewrite rules to the .htaccess file).

    So if you haven't done so, flushing the rewrite rules is easy — just visit the permalink settings page without making any changes (i.e. without having to click on the "save" button).

  2. Another possibility is that you may have an existing post type or taxonomy which is using the same query var as your custom endpoint — when you call add_rewrite_endpoint(), the query var is the 3rd parameter which defaults to the 1st parameter.

    add_rewrite_endpoint( 'review', EP_PERMALINK );
    // The above call is equivalent to:
    add_rewrite_endpoint( 'review', EP_PERMALINK, 'review' );
    // .. and both will register a *public* query var named 'review'

    PS: Public query var means WordPress will read it from the URL, e.g. https://example.com/my-post/?review=foo.

    So make sure that there's no query var clash on your website. E.g. If you have a post type with review being the query var, then for your custom endpoint, define a different query var like review2..

But even after fixing the 404 error, the logic in your wpd_game_template() function doesn't seem correct, so you should also fix that. So try with:

function wpd_game_template( $template = '' ) {
    global $wp_query;

    if ( isset( $wp_query->query_vars['review'] ) ) {
        return locate_template( 'single-game-review.php' );

    if ( isset( $wp_query->query_vars['related-articles'] ) ) {
        return locate_template( 'single-game-related.php' );

    if ( isset( $wp_query->query_vars['screenshots'] ) ) {
        return locate_template( 'single-game-screenshots.php' );

    return $template;

Or using get_query_var(): (works only if the query var is not empty)

function wpd_game_template( $template = '' ) {
    if ( get_query_var( 'review' ) ) {
        return locate_template( 'single-game-review.php' );

    if ( get_query_var( 'related-articles' ) ) {
        return locate_template( 'single-game-related.php' );

    if ( get_query_var( 'screenshots' ) ) {
        return locate_template( 'single-game-screenshots.php' );

    return $template;

I hope that helps?

I have also added a filter for query vars (don't really know what that means but found the code on here)

That code is basically used to make get_query_var() works when checking if a query var is set and not empty. I.e. Consider these examples:

URL: https://example.com/my-post/review/this-part
get_query_var( 'review' ) = 'this-part'

URL: https://example.com/my-post/review
get_query_var( 'review' ) = '' (empty string)

So with that code in the question, the second example above would return true.

But the thing is, when a custom query var value is set in the URL like the first example above, then get_query_var( 'review' ) would always return true.

However, you can fix that by using isset and empty in the wpse42279_filter_request() function, e.g.

if ( isset( $vars['related-articles'] ) && empty( $vars['related-articles'] ) ) {
    $vars['related-articles'] = true;
  • Hi, Thank you for your help. The code worked perfectly, no 404 errors now. And thankyou for the explanation on the query var code, I'm slowly but surely learning a bit more about wordpress amnd php. Now I just need to figure out how to add the endpoint url to Yoast breadcrumbs. Thank you again. Commented Jun 10, 2020 at 17:14
  • So would you mind accepting or voting up the answer? Regarding the Yoast thing, you'd need to check their docs or you can try asking on Stack Overflow.
    – Sally CJ
    Commented Jun 10, 2020 at 17:25
  • 1
    Hi, accepted and voted up the answer. I also figured out the Yoast thing too. Commented Jun 10, 2020 at 18:01
  • Thank you and I was actually editing the answer, so hopefully the extra paragraphs would be helpful to you and others as well. PS: Glad you figured that Yoast thing. Happy coding!
    – Sally CJ
    Commented Jun 10, 2020 at 18:34

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.