Question

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:

<?php 
                // 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>

                    </nav>

                </div>

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.

Was it helpful?

Solution

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;
}
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top