I have a simple rewrite to pass a variable:

// Add custom URL parameters
function add_custom_query_var( $vars ){
  $vars[] = "item_id";
  return $vars;

add_filter( 'query_vars', 'add_custom_query_var' );

// Add rewrite for custom query vars
function custom_rewrite_basic() 
    add_rewrite_rule('^add-item/([0-9]+)/?', 'add-item/?item_id=$1', 'top');

add_action( 'init', 'custom_rewrite_basic' );

On the add-item page, the variable is fetched as such:

$item_id = filter_input( INPUT_GET, "item_id", FILTER_SANITIZE_NUMBER_INT );

if(!empty($item_id)) {

When the page is called with add-item/1, var_dump($item_id) comes back with NULL. Any other number (including 0) work fine. Any ideas?


Rewrite rules in WordPress should point to index.php, and to substitute a matched value (number from address) to URL parameter (item_id) you must use $matches[1] instead of $1.

So your rule should look like this:

add_rewrite_rule('^add-item/([0-9]+)/?', 'index.php?item_id=$matches[1]', 'top');

You usually need to complete the rule with information about what is displayed. For display:

  • single post / page - add to rewrite &p={post_id} or &postname={post_slug}
  • archive page - &post_type={post_type_slug}
  • custom category - &{taxonomy_slug}={term_slug}.

This rule setting only the item_id query var, so if you have not added your own function to template_include filter hook, WP will display the homepage.


Rules with and without index.php
Rewrite rules begining with index.php are stored in DB. When parsing request, WordPress get them from the DB and tries to match the request URL to one of the rules.

Rules that do not start with an index.php, do not go to the database. They are not checked when the request is being parsed by WordPress. It is possible that they will be saved in .htaccess file, but only if you use Apache and file permissions allow for writing.

Why $item_id is NULL
example.com/add-item/1 address is recognized as a post (post type can be page or post) with several pages (post pagination). You should know that WordPress removes page number from URL if it equal to "1".
WordPress checks whether the requested url is canonical by comparing the url with the one it generates. Canonical URL in this case (first page of post) is example.com/add-item/ and it is not the same as the requested one example.com/add-item/1, so redirecting will be done.

I do not know what type of post is the add-item (custom post type or built in), but try this way:

add_action( 'init', 'se336565_custom_rewrite_basic' );
add_filter( 'query_vars', 'se336565_add_custom_query_var' );

function se336565_add_custom_query_var( $vars ){
  $vars[] = "item_id";
  return $vars;
function se336565_custom_rewrite_basic() 
        'index.php?post_type={custom_post_type_slug}&pagename=add-item&name=add-item&item_id=$matches[1]', 'top');

Replace {custom_post_type_slug} and flush the rewrite rules.

Finally, on the actual page use get_query_var( 'item_id' ).

  • I'm not sure I understand the reason to use index.php. Is there some documentation around this? – Kermit Apr 29 at 13:19
  • Also see my previous question on using $matches[1] vs $1 – Kermit Apr 29 at 14:07
  • @Kermit I've edited the answer – nmr Apr 30 at 9:18
  • 2
    @Kermit, add_rewrite_rule( '^add-item/([0-9]+)/?', 'index.php?pagename=add-item&item_id=$matches[1]', 'top' ) works fine for me. And to get the item_id value, you should use get_query_var( 'item_id' ) and not $_GET['item_id'] when redirecting to index.php. – Sally CJ May 16 at 18:49
  • 1
    @Kermit filter_input( INPUT_GET, 'item_id' ) get variable from "superglobal" array of URL parameters (passed after ? mark), but there are no parameters in address like /add-item/{some_number_here}, so $_GET array is empty. Wordpress is looking for the first rewrite rule that matching the requested URL, and sets variables in the global $wp_query object according to this rule (in you case item_id=$matches[1]). To get variable from $wp_query object, the get_query_var() function is used. – nmr May 17 at 14:00

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.