Search code examples
phpwordpresswoocommerceendpointorders

Change "view-order/order-id" url/endpoint in WooCommerce My account - orders to "orders/order-id"


Currently the URL, under the WooCommerce 'My orders' tab, for the button when you view an order in detail is equal to /my-account/view-order/ORDER-ID/

I would like to change this url to /my-account/orders/ORDER-ID/ - So:

  • current url: /my-account/view-order/ORDER-ID/

  • new url: /my-account/orders/ORDER-ID/


Therefore, via the WooCommerce settings I changed the view-order endpoint to orders

This works, the url of the button to view the order in detail has effectively been changed, only I get the following message on the order detail page

'No order has been made yet'.

I believe through the following code, which can be found in /plugins/woocommerce/includes/class-wc-order.php | line 1675

/**
 * Generates a URL to view an order from the my account page.
 *
 * @return string
 */
public function get_view_order_url() {
    return apply_filters( 'woocommerce_get_view_order_url', wc_get_endpoint_url( 'view-order', $this->get_id(), wc_get_page_permalink( 'myaccount' ) ), $this );
}

I can achieve my goal, but I could use some advice. Anyone who can guide me?


Solution

  • Changing the /my-account/view-order/ORDER-ID/ url to /my-account/orders/ORDER-ID/ can be done by applying a few steps.


    Step 1) change the view order endpoint

    The URL for each endpoint can be customized in WooCommerce > Settings > Advanced in the page setup section

    account endpoints

    OR you use the woocommerce_get_endpoint_url filter hook instead

    function filter_woocommerce_get_endpoint_url( $url, $endpoint, $value, $permalink ) {
        // Specific endpoint
        if ( $endpoint === 'view-order' ) {
            // New URL
            $url = $permalink . 'orders/' . $value;
        }
    
        return $url;
    }
    add_filter( 'woocommerce_get_endpoint_url', 'filter_woocommerce_get_endpoint_url', 10, 4 );
    

    While the endpoint is now changed, you will see the following message when viewing the new url:

    'No order has been made yet'.

    This is because the /myaccount/orders.php template file is loaded, while this should be the /myaccount/view-order.php template


    Step 2) provide that the correct template file is loaded, this for both the /my-account/orders/ and /my-account/orders/ORDER-ID/ url.

    Therefore we need to overwrite the existing woocommerce_account_orders() function, which can be found in the /includes/wc-template-functions.php file. So that our custom function is executed

    function woocommerce_account_orders( $current_page ) {
        global $wp;
    
        // For view-order template file
        if ( isset( $wp->query_vars['orders'] ) && is_numeric( $wp->query_vars['orders'] ) ) {
            $order_id = $wp->query_vars['orders'];
    
            $order = wc_get_order( $order_id );
    
            if ( ! $order || ! current_user_can( 'view_order', $order_id ) ) {
                echo '<div class="woocommerce-error">' . esc_html__( 'Invalid order.', 'woocommerce' ) . ' <a href="' . esc_url( wc_get_page_permalink( 'myaccount' ) ) . '" class="wc-forward">' . esc_html__( 'My account', 'woocommerce' ) . '</a></div>';
    
                return;
            }
    
            // Backwards compatibility.
            $status       = new stdClass();
            $status->name = wc_get_order_status_name( $order->get_status() );
    
            wc_get_template(
                'myaccount/view-order.php',
                array(
                    'status'   => $status, // @deprecated 2.2.
                    'order'    => $order,
                    'order_id' => $order->get_id(),
                )
            );
        } else {
            $current_page    = empty( $current_page ) ? 1 : absint( $current_page );
            $customer_orders = wc_get_orders(
                apply_filters(
                    'woocommerce_my_account_my_orders_query',
                    array(
                        'customer' => get_current_user_id(),
                        'page'     => $current_page,
                        'paginate' => true,
                    )
                )
            );
    
            wc_get_template(
                'myaccount/orders.php',
                array(
                    'current_page'    => absint( $current_page ),
                    'customer_orders' => $customer_orders,
                    'has_orders'      => 0 < $customer_orders->total,
                )
            );
        }
    }
    

    Important: it is not the intention to change this function by changing the core file!! you can simply add this to functions.php, this is because this function is embedded by if ( ! function_exists( 'woocommerce_account_orders' ) ) {


    Step 3) this step is optional. This ensures that the /my-account/view-order/ORDER-ID/ url (which is now the old url) is no longer reachable

    function action_woocommerce_account_view_order_endpoint() {
        remove_action( 'woocommerce_account_view-order_endpoint', 'woocommerce_account_view_order' );
    }
    add_action( 'woocommerce_account_view-order_endpoint', 'action_woocommerce_account_view_order_endpoint', 1 );
    

    Code from step 1, 2 and 3 goes in functions.php file of the active child theme (or active theme).


    Related: Change title custom "view-order" endpoint in WooCommerce My account