My Account Endpoints

My Account endpoints are URL “extensions” registered by WooCommerce that map parts of the My Account area to specific routes—e.g., /my-account/orders/, /my-account/edit-address/, /my-account/payment-methods/. Internally, each endpoint is a rewrite endpoint + query var (e.g., orders, view-order) that WooCommerce listens to and renders with the correct template/content.

Endpoints let WooCommerce (and extensions) provide a modular, SEO-friendly account area without creating separate WordPress pages for everything. They’re translatable and customizable (you can change the slugs), survive theme swaps, and are safe to link to using helper functions so you don’t hardcode paths. Plugins can add their own endpoints (e.g., subscriptions, wishlists), and you can register custom ones for bespoke dashboards or B2B features.

In classic (shortcode) templates, WooCommerce renders a left-hand account navigation bound to these endpoints. With the My Account block, the UI is block-based, but the underlying endpoints remain the routing mechanism. Either way, the customer must be authenticated to access most endpoints.

Default endpoints (core)

  • orders/my-account/orders/
  • view-order/<id>/my-account/view-order/1234/
  • downloads/my-account/downloads/
  • edit-address[/billing|/shipping]/my-account/edit-address/billing/
  • payment-methods/my-account/payment-methods/
  • add-payment-method/my-account/add-payment-method/
  • edit-account (Account details) → /my-account/edit-account/
  • lost-password/my-account/lost-password/
  • customer-logout/my-account/customer-logout/

Extensions may add more (e.g., subscriptions, support-tickets). The root /my-account/ (often called dashboard) is not itself an endpoint.

URLs & helpers you should use

Build links programmatically so they keep working if slugs change:

// Base My Account URL
$account_url = wc_get_page_permalink('myaccount');

// Generic helper: append endpoint to any base permalink
$url = wc_get_endpoint_url( 'orders', '', $account_url );

// Convenience helper (base inferred as My Account)
$url = wc_get_account_endpoint_url( 'orders' );

Check where you are:

if ( is_account_page() && is_wc_endpoint_url( 'orders' ) ) {
    // On /my-account/orders/
}

Get the “value” segment (e.g., order ID for view-order):

$order_id = absint( get_query_var( 'view-order' ) );

Customizing slugs (rename endpoints)

You can change endpoint slugs in WooCommerce → Settings → Advanced → My account endpoints. To do it in code:

add_filter('woocommerce_get_query_vars', function ($vars) {
    // Rename "edit-account" to "profile"
    $vars['edit-account'] = 'profile';
    return $vars;
});

After changing slugs, flush permalinks (Settings → Permalinks → Save).

Reordering/renaming the account menu

// Change labels, hide items, reorder
add_filter('woocommerce_account_menu_items', function ($items) {
    // Rename
    $items['orders']        = __('My Orders', 'your-txt');
    $items['edit-account']  = __('Profile', 'your-txt');

    // Remove downloads if you don’t sell files
    unset($items['downloads']);

    // Reorder explicitly
    return [
        'dashboard'        => $items['dashboard'],
        'orders'           => $items['orders'],
        'edit-address'     => $items['edit-address'],
        'payment-methods'  => $items['payment-methods'],
        'edit-account'     => $items['edit-account'],
        'customer-logout'  => $items['customer-logout'],
    ];
});

Adding a custom endpoint (with menu + content)

// 1) Register endpoint (runs on init)
function lc_register_projects_endpoint() {
    add_rewrite_endpoint('projects', EP_ROOT | EP_PAGES);
}
add_action('init', 'lc_register_projects_endpoint');

// 2) Tell WooCommerce about the query var (slug)
add_filter('woocommerce_get_query_vars', function ($vars) {
    $vars['projects'] = 'projects';
    return $vars;
}, 0);

// 3) Add it to the account navigation
add_filter('woocommerce_account_menu_items', function ($items) {
    // Insert before logout
    $new = [];
    foreach ($items as $key => $label) {
        if ($key === 'customer-logout') {
            $new['projects'] = __('Projects', 'your-txt');
        }
        $new[$key] = $label;
    }
    return $new;
});

// 4) Render endpoint content
add_action('woocommerce_account_projects_endpoint', function () {
    echo '<h3>' . esc_html__('Your Projects', 'your-txt') . '</h3>';
    echo '<p>' . esc_html__('List custom data here…', 'your-txt') . '</p>';
});

// 5) Flush rewrite rules on activation only (plugin file)
register_activation_hook(__FILE__, function () {
    lc_register_projects_endpoint();
    flush_rewrite_rules();
});
register_deactivation_hook(__FILE__, function () {
    flush_rewrite_rules();
});

Blocks vs classic templates

  • Classic shortcode ([woocommerce_my_account]): the woocommerce_account_* actions render endpoint content; woocommerce_account_menu_items controls the nav list.
  • My Account block: endpoints still define URLs; the menu is block-rendered. If you need full control, create a custom account template/page using the block suite or override the block template in a child theme.

Tips & pitfalls

  • Don’t hardcode /my-account/... — always use the helpers so custom slugs and multilingual sites work.
  • Flush permalinks after adding/renaming endpoints; otherwise you’ll hit 404s.
  • Secure actions (e.g., delete payment method) with nonces and capability checks.
  • Multilingual: set endpoint slugs per language context (or via filters) to keep URLs localized.
  • Test logged-out behavior: some endpoints should redirect to login; confirm your flow.