• Skip to secondary menu
  • Skip to main content
  • Skip to primary sidebar
  • Home
  • Projects
  • Products
  • Themes
  • Tools
  • Request for Quote

Vengala Vinay

Having 12+ Years of Experience in Software Development

  • Home
  • WordPress
  • PHP
    • Codeigniter
  • Django
  • Magento
  • Selenium
  • Server
Home » How to build custom WooCommerce core overrides extensions utilizing modern Rewrite API custom endpoints schemas

How to build custom WooCommerce core overrides extensions utilizing modern Rewrite API custom endpoints schemas

Leveraging the Rewrite API for Custom WooCommerce Endpoints

When extending WooCommerce, you’ll inevitably encounter scenarios where the default endpoints for product pages, cart, checkout, or account sections aren’t sufficient. You might need to add custom actions, display unique data, or integrate with external services in a way that requires a distinct URL structure. The WordPress Rewrite API, in conjunction with WooCommerce’s own endpoint system, provides a robust and clean mechanism for achieving this without directly modifying core WooCommerce files. This approach ensures your customizations are upgrade-safe and maintainable.

Understanding WooCommerce Endpoints and the Rewrite API

WooCommerce utilizes WordPress’s built-in rewrite rules to manage its various pages and endpoints. Endpoints are essentially query variables appended to a base URL (like a shop page or my account page) that trigger specific content displays or actions. For example, /my-account/orders/ uses the orders endpoint to display the user’s order history. The Rewrite API allows us to register new query variables and define how they map to actual URLs.

The core functions we’ll be working with are:

  • add_rewrite_rule(): Registers a new URL pattern and its corresponding query arguments.
  • add_rewrite_tag(): Registers a new query variable that WordPress can recognize.
  • flush_rewrite_rules(): Crucial for making new rewrite rules active. This should be done judiciously, typically on plugin activation/deactivation or when rules are added/removed.

Scenario: Adding a Custom Endpoint to the My Account Page

Let’s imagine we want to add a new section to the WooCommerce My Account page for users to manage their “Loyalty Points.” This will require a new endpoint, say loyalty-points.

Step 1: Registering the Custom Endpoint and Rewrite Rule

We’ll hook into WordPress’s init action to register our custom endpoint and rewrite rule. It’s best practice to encapsulate this logic within a plugin or theme’s functions.php file.

/**
 * Register custom endpoint and rewrite rule for My Account page.
 */
function my_custom_loyalty_points_endpoint() {
    // Add the custom endpoint query variable.
    // The first argument is the query variable name.
    // The second argument is the URL segment that will trigger this endpoint.
    add_rewrite_tag( 'loyalty_points', 'loyalty-points' );

    // Add the rewrite rule.
    // The first argument is the regex pattern for the URL.
    // The second argument is the query string that will be appended to the URL.
    // The third argument specifies where to append the query (top or bottom).
    // We target the My Account page base URL.
    $myaccount_page_id = get_option( 'woocommerce_myaccount_page_id' );
    if ( $myaccount_page_id ) {
        $myaccount_endpoint_slug = 'loyalty-points'; // Must match the add_rewrite_tag slug
        $myaccount_page_slug = get_post_field( 'post_name', $myaccount_page_id );

        // Pattern: ^my-account/loyalty-points/?$
        // Query: index.php?pagename=my-account&loyalty_points=1
        add_rewrite_rule(
            '^' . $myaccount_page_slug . '/' . $myaccount_endpoint_slug . '/?$',
            'index.php?pagename=' . $myaccount_page_slug . '&loyalty_points=1',
            'top'
        );
    }
}
add_action( 'init', 'my_custom_loyalty_points_endpoint' );

In this code:

  • add_rewrite_tag( 'loyalty_points', 'loyalty-points' ); registers loyalty_points as a query variable. When WordPress sees ?loyalty_points=1 in the URL, it will recognize it. The second argument, loyalty-points, is the URL-friendly slug that will appear in the browser’s address bar.
  • We dynamically fetch the My Account page ID and slug to ensure compatibility.
  • add_rewrite_rule() creates the actual URL mapping. The regex ^' . $myaccount_page_slug . '/' . $myaccount_endpoint_slug . '/?$' matches URLs like /my-account/loyalty-points/. The replacement 'index.php?pagename=' . $myaccount_page_slug . '&loyalty_points=1' tells WordPress to load the My Account page but also set the loyalty_points query variable to 1.
  • 'top' ensures this rule is checked before other, more general rules, preventing conflicts.

Step 2: Flushing Rewrite Rules

For the new rewrite rules to take effect, you must flush them. The most common way to do this for development is to visit the Permalinks settings page in the WordPress admin (Settings > Permalinks). For production environments, it’s best to flush rules programmatically on plugin activation/deactivation.

/**
 * Flush rewrite rules on plugin activation.
 */
function my_custom_loyalty_points_rewrite_flush() {
    my_custom_loyalty_points_endpoint(); // Ensure rules are registered before flushing
    flush_rewrite_rules();
}
register_activation_hook( __FILE__, 'my_custom_loyalty_points_rewrite_flush' );

/**
 * Flush rewrite rules on plugin deactivation.
 */
function my_custom_loyalty_points_rewrite_deactivate_flush() {
    // Optionally remove custom rules here if needed, then flush.
    // For simplicity, we'll just flush.
    flush_rewrite_rules();
}
register_deactivation_hook( __FILE__, 'my_custom_loyalty_points_rewrite_deactivate_flush' );

Place this code in your main plugin file. When the plugin is activated, flush_rewrite_rules() will be called, making your new endpoint accessible. When deactivated, it’s good practice to flush again to clean up any leftover rules.

Step 3: Adding the Endpoint to the My Account Navigation

Now that the endpoint is registered, we need to add a link to it in the My Account navigation menu.

/**
 * Add custom endpoint link to My Account navigation.
 *
 * @param array $menu_links Existing menu links.
 * @return array Modified menu links.
 */
function my_custom_loyalty_points_add_to_my_account_menu( $menu_links ) {
    // Add the new link.
    // The key is the endpoint slug, the value is the link text.
    $menu_links['loyalty-points'] = __( 'Loyalty Points', 'your-text-domain' );
    return $menu_links;
}
add_filter( 'woocommerce_account_menu_items', 'my_custom_loyalty_points_add_to_my_account_menu' );

This filter hook woocommerce_account_menu_items allows us to modify the array of navigation items displayed in the My Account sidebar. We simply add a new key-value pair where the key is our endpoint slug (loyalty-points) and the value is the desired display text.

Step 4: Displaying Content for the Custom Endpoint

Finally, we need to tell WooCommerce what to display when our custom endpoint is accessed. We do this by hooking into the woocommerce_account_content action and checking if our custom query variable is set.

/**
 * Display content for the custom loyalty points endpoint.
 */
function my_custom_loyalty_points_endpoint_content() {
    // Check if our custom query variable is set.
    if ( isset( $_GET['loyalty_points'] ) && $_GET['loyalty_points'] == 1 ) {
        // Get the current user.
        $current_user = wp_get_current_user();

        // Display your custom content here.
        // This could involve fetching user-specific loyalty data,
        // displaying forms, or integrating with external APIs.
        ?>
        

display_name ) ); ?>

ID, 'loyalty_points', true ); // echo '

Loyalty points balance: ' . esc_html( $loyalty_points ) . '

'; } } add_action( 'woocommerce_account_content', 'my_custom_loyalty_points_endpoint_content' );

This function checks for the presence of the loyalty_points query variable. If it’s set, it renders the custom HTML content. This is where you’d integrate your specific logic for displaying and managing loyalty points.

Advanced Considerations and Best Practices

Handling Different Endpoint Slugs

The example uses a hardcoded slug loyalty-points. For more complex plugins, you might want to make this configurable or dynamically generate it based on other settings. You can achieve this by storing the slug in plugin options and retrieving it using get_option().

Customizing the Rewrite Rule Regex

The regex '^' . $myaccount_page_slug . '/' . $myaccount_endpoint_slug . '/?$' is a basic example. You might need more complex regex if your endpoint requires additional parameters, e.g., '^my-account/orders/(\d+)/?$' to capture an order ID.

// Example with a parameter (e.g., viewing a specific loyalty transaction)
$myaccount_endpoint_slug = 'loyalty-points';
$myaccount_page_slug = get_post_field( 'post_name', $myaccount_page_id );

// Pattern: ^my-account/loyalty-points/(\d+)/?$
// Query: index.php?pagename=my-account&loyalty_points_transaction=$matches[1]
add_rewrite_rule(
    '^' . $myaccount_page_slug . '/' . $myaccount_endpoint_slug . '/(\d+)/?$',
    'index.php?pagename=' . $myaccount_page_slug . '&loyalty_points_transaction=$matches[1]',
    'top'
);

// You would then register 'loyalty_points_transaction' with add_rewrite_tag()
// and check for it in your content display function.
add_rewrite_tag( 'loyalty_points_transaction', '([^/]+)' ); // Allows any character except '/'

Performance Implications of Flushing Rewrite Rules

flush_rewrite_rules() is an expensive operation. Calling it on every page load or even on every init hook is highly discouraged in production. The recommended approach is to flush only when necessary: on plugin activation/deactivation, or when a user explicitly saves permalink settings. If you are dynamically generating rules based on user settings, you might need a more sophisticated mechanism to detect changes and trigger a flush.

Integrating with WooCommerce Core Functionality

For more deeply integrated overrides or additions that affect core WooCommerce pages (like the product page or cart), you might need to leverage WooCommerce’s own hooks and filters more extensively. For instance, to add a custom tab to the single product page, you’d use woocommerce_product_tabs. However, for distinct URL-based functionalities, the Rewrite API remains the primary tool.

Security Considerations

Always sanitize and escape any user-provided data or data fetched from the database before displaying it. Use functions like esc_html(), esc_attr(), and sanitize_text_field(). When dealing with sensitive data or actions, ensure proper user authentication and authorization checks are in place.

Conclusion

By mastering the WordPress Rewrite API and understanding how WooCommerce leverages it, you can build sophisticated, custom extensions that offer unique user experiences and functionalities. This approach ensures your code is clean, maintainable, and resilient to future WordPress and WooCommerce updates, avoiding the pitfalls of direct core modifications.

Primary Sidebar

A little about the Author

Having 12+ Years of Experience in Software Development, Vinay is a principal software architect, senior systems engineer, and elite technical consultant. He specializes in bespoke PHP/WordPress development, high-performance Magento 2 & Shopify architectures, custom plugin/theme development from scratch, and legacy code modernization (including VB6, VB.NET, PyQt, and Crystal Reports). Known for solving complex database bottlenecks, speed optimization (Core Web Vitals), and advanced security code auditing, Vinay engineers production-ready systems designed to scale under heavy concurrent load conditions.



Chat on WhatsApp

Recent Posts

  • Building GDPR-compliant data export and deletion engines inside legacy user profile systems
  • WordPress Development Recipe: Secure token-based API authentication for Shopify headless API in custom plugins
  • Advanced Diagnostics: Locating slow Action-hook Event Mediator query bottlenecks in WooCommerce custom checkout pipelines
  • WordPress Development Recipe: Leveraging Constructor Property Promotion to build type-safe, auto-wired hooks
  • How to design a modular Repository and Interface Structure architecture for enterprise-level custom plugins

Categories

  • apache (1)
  • Business & Monetization (390)
  • Centos (4)
  • Comparisons & Decision Making (55)
  • Debian (2)
  • Debugging & Troubleshooting (658)
  • Desktop Applications (14)
  • DevOps (7)
  • DevOps & Cloud Scaling (962)
  • Django (1)
  • Laravel (4)
  • Migration & Architecture (192)
  • Mobile Applications (24)
  • MySQL (1)
  • Performance & Optimization (872)
  • PHP (5)
  • PHP Development (48)
  • Plugins & Themes (244)
  • Programming Languages (9)
  • Python (20)
  • Ruby on Rails (1)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Server (23)
  • Ubuntu (9)
  • VB6 & VB.NET (8)
  • Web Applications & Frontend (19)
  • Web Assembly (Wasm) (2)
  • WordPress (22)
  • WordPress Plugin Development (158)
  • WordPress Plugin Development (180)
  • WordPress Plugin Development (330)
  • WordPress Theme Development (357)

Recent Posts

  • Building GDPR-compliant data export and deletion engines inside legacy user profile systems
  • WordPress Development Recipe: Secure token-based API authentication for Shopify headless API in custom plugins
  • Advanced Diagnostics: Locating slow Action-hook Event Mediator query bottlenecks in WooCommerce custom checkout pipelines

Top Categories

  • DevOps & Cloud Scaling (962)
  • Performance & Optimization (872)
  • Debugging & Troubleshooting (658)
  • Security & Compliance (639)
  • SEO & Growth (492)
  • Business & Monetization (390)

Our Products

  • ERP & LMS Systems (4)
  • Directories & Marketplaces (4)
  • Healthcare Portals (3)
  • Point of Sale (POS) (2)
  • E-Commerce Engines (2)

Our Services

  • E-Commerce Development (10)
  • WordPress Development (8)
  • Python & Desktop GUI (7)
  • General Consulting (7)
  • Legacy Modernization (5)
  • Mobile App Development (4)

Copyright © 2026 · Vinay Vengala