WordPress at Your Fingertips

add_rewrite_endpoint()WP 2.1.0

Adds a URL endpoint, such as /trackback/. Adds additional rewrite rules for friendly URL - adds the specified endpoint.

When rewrite endpoint is added to the rewrite rules, additional URL rewrite rules are added for each URL type specified in the second parameter $places. These can be: post, page, column, author, search, etc. For example:

add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );

Will add a new rule ending in json(/(.*))?/?$ for each rewrite structure that describes the friendly URL for posts or pages. The final query parameter will look like this: [basic parameters]&json=$match, where $match is the part of the friendly URL after the endpoint. For example, if the link is [permalink]/json/foo/ then $match would be foo and the query would be [permalink parameters]?json=foo.

This function adds the name of the endpoint to the white list of query variables as well. For the example above the name of endpoint is json.

When specifying the $places parameter, make sure you use a working constant of type EP_*` (you can use multiple parameters with|``).

https://make.wordpress.org/plugins/2012/06/07/rewrite-endpoints-api/ - how it works (Rewrite endpoints API tutorial).

Be sure to flush the rewrite rules.

In order for the changes to apply, you need to reset rewrite rules, with flush_rewrite_rules() when activating / deactivating the plugin.

Or, to reset, you can simply visit the Settings > Permalinks admin page.

The function must be called at wp or init action-hooks. See examples.

1 time — 0.000001 sec (speed of light) | 50000 times — 0.07 sec (speed of light) | PHP 7.3.20, WP 5.5.3

No Hooks.


null. Nothing (null).


add_rewrite_endpoint( $name, $places, $query_var );
$name(string) (required)
Name of the endpoint.
$places(int) (required)

Endpoint mask describing the places the endpoint should be added. Accepts a mask of:

  • EP_NONE - default endpoint mask - does not apply to anything. Bitwise value: 0.
  • EP_PERMALINK - permanent link of any post. Bitwise value: 1.
  • EP_ATTACHMENT - attachments. Bitwise value: 2.
  • EP_DATE - date. Bitwise value: 4.
  • EP_YEAR - year. Bitwise value: 8.
  • EP_MONTH - month. Bitwise value: 16.
  • EP_DAY - day. Bitwise value: 32.
  • EP_ROOT - root. Bitwise value: 64.
  • EP_COMMENTS - comments. Bitwise value: 128.
  • EP_SEARCH - search. Bitwise value: 256.
  • EP_CATEGORIES - categories. Bitwise value: 512.
  • EP_TAGS - tags. Bitwise value: 1024.
  • EP_AUTHORS - authors. Bitwise value: 2048.
  • EP_PAGES - permanent pages. Bitwise value: 4096.
  • EP_ALL_ARCHIVES - all archive views. Same as using EP_DATE | EP_YEAR | EP_MONTH | EP_DAY | EP_CATEGORIES | EP_TAGS | EP_AUTHORS.
  • EP_ALL - all at once (everything). Same as using EP_PERMALINK | EP_ATTACHMENT | EP_ROOT | EP_COMMENTS | EP_SEARCH | EP_PAGES | EP_ALL_ARCHIVES.
The name of the query variable for this endpoint, by default equals to endpoint name ($name parameter). Specify false to prevent the function from adding a query variable.
Default: true



#1 Add an endpoint for posts and pages URLs

add_action( 'init', 'add_my_endpoint' );

function add_my_endpoint() {
	add_rewrite_endpoint( 'json', EP_PERMALINK | EP_PAGES );

Now we need to handle the URL - assign to it a template file which will be responsible for the output. This can be done with the template_include hook.

add_action( 'template_include', 'makeplugins_json_template_include' );

function makeplugins_json_template_include( $template ) {
	global $wp_query;

	// if this is a request for json or a singular object then bail
	// include custom template
	if ( isset( $wp_query->query_vars['json'] ) && is_singular() ){
		$template = __DIR__ . '/json-template.php';

	return $template;

See example for plugin: https://gist.github.com/joncave/2891111


#2 Add a friendly URL for the plugin page in the front-end

This example shows how to create a page for the plugin on the fly (without creating the real page in DB). For the output of such page will be responsible our php template file. And we no need to create a page in the admin panel for such a page.

To do this, first we need to add an endpoint for the main page.

add_action( 'init', 'add_my_endpoint' );

function add_my_endpoint(){
	add_rewrite_endpoint( 'myplug-page', EP_ROOT );

Now, we need to reset the friendly URL rewrites and we will have such working URL:

  • site.com/myplug-page.
  • or site.com/myplug-page/my-query_parameter.

For such a page, it is a good idea to reset the parameters of the main query, so as not to waste resources on a query that we do not use anyway. In this case, the query gets all the latest posts.

You can do it like this:

// truncate the main query for the main page of the site,
// so improve load performance.
add_filter( 'posts_clauses_request', 'skip_main_query_for_myplugpage', 10, 2 );

function skip_main_query_for_myplugpage( $pieces, $wp_query ){

	if( isset( $wp_query->query['myplug-page'] ) && $wp_query->is_main_query() ){
		$pieces['where'] = ' AND ID = 0';

	return $pieces;
Create a page template

On a page like is_front_page() we can get the query parameter like this:

$var = get_query_var( 'myplug-page' );

Now let's process the query and include our template file using template_include hook.

add_action( 'template_include', 'myplugpage_template_file', 20 );

function myplugpage_template_file( $template ) {
	global $wp_query;

	// our query
	if ( isset( $wp_query->query['myplug-page'] ) ) {
		$template = __DIR__ . '/path/to/myplug-page-template.php';

	return $template;


#3 Separate page for post comments

See this note for the code.


  • Global. WP_Rewrite. $wp_rewrite WordPress rewrite component.


Since 2.1.0 Introduced.
Since 4.3.0 Added support for skipping query var registration by passing false to $query_var.

add_rewrite_endpoint() code WP 6.5.3

function add_rewrite_endpoint( $name, $places, $query_var = true ) {
	global $wp_rewrite;
	$wp_rewrite->add_endpoint( $name, $places, $query_var );
1 comment
    Log In