Question

I am trying to add a new account submenu page that takes a query parameter.

I have the following which works:

add_action('init', function() {
  add_rewrite_endpoint('scheduled-order-create', EP_PAGES);
});

add_action('woocommerce_account_scheduled-order-create_endpoint', function() {
  include 'scheduled-order-create.php';
});

Then I can see the page at /my-account/scheduled-order-create.

Now I want this page to accept a query parameter, but if I just navigate to /my-account/scheduled-order-create?product=1 the page is a 404.

I've tried this for my init hook:

add_action('init', function() {
  add_rewrite_tag('%product%', '([0-9]+)');
  add_rewrite_endpoint('scheduled-orders', EP_PAGES);
  add_rewrite_endpoint("scheduled-order-create/([0-9]+)/?", 'index.php?product=$matches[1]', EP_PAGES);
});

But now the page is always a 404 even without the parameter.

I am refreshing the permalinks page after all changes.

Was it helpful?

Solution

That add_rewrite_endpoint("scheduled-order-create/([0-9]+)/?", ...); doesn't work because add_rewrite_endpoint() doesn't work with custom RegEx pattern.

And remember that in addition to default public query vars like cat, tag, year and author, WordPress also makes all public post types and taxonomies (with a non-empty query_var value when registered — see register_post_type() and register_taxonomy()) be readable from the URL and used with the main query, so make sure your query string name does not conflict with those query vars. Otherwise, you'd end up with a 404 error because WordPress tried to query something else than what should've been queried.

Therefore, despite that add_rewrite_endpoint('scheduled-order-create', EP_PAGES); does work, navigating to /my-account/scheduled-order-create?product=1 results in the 404 error because WordPress (or WP_Query) couldn't find a (public/published) product post with the slug 1product is a post type registered by WooCommerce with the query var defaults to the post type slug.

So you need to use another name for the URL query string, e.g. use prod_id in place of product as in https://example.com/my-account/scheduled-order-create?prod_id=1.

Additional Notes

In WooCommerce, there's actually a filter hook you can use to easily add custom my-account endpoints, and I'd use that hook unless if I wanted to enable the endpoint for all Pages:

add_filter( 'woocommerce_get_query_vars', function ( $query_vars ) {
    $query_vars['scheduled-order-create'] = 'scheduled-order-create';
    return $query_vars;
} );

However, you still need to flush/re-generate the permalinks (just visit the permalink settings page).

Additional Code

Or as an alternative to using the prod_id query string in the URL.

  • You can use path-based rewrite endpoints such as scheduled-order-create/product:

    // Manually using add_rewrite_endpoint():
    add_action( 'init', function () {
        add_rewrite_endpoint( 'scheduled-order-create/product', EP_PAGES,
          'scheduled-order-create' );
    } );
    
    // Or using the WooCommerce's filter hook:
    add_filter( 'woocommerce_get_query_vars', function ( $query_vars ) {
        $query_vars['scheduled-order-create'] = 'scheduled-order-create/product';
        return $query_vars;
    } );
    
    // To get the product ID (e.g. 123 as in example.com/my-account/scheduled-order-create/product/123):
    $product_id = get_query_var( 'scheduled-order-create' );
    
Licensed under: CC-BY-SA with attribution
Not affiliated with wordpress.stackexchange
scroll top