17

This function adds a tab named "Special Page" into "My Account" tab list:

add_filter( 'woocommerce_account_menu_items' , 'jc_menu_panel_nav' );

function jc_menu_panel_nav() {
    $items = array(
        'dashboard'       => __( 'Dashboard', 'woocommerce' ),
        'orders'          => __( 'Orders', 'woocommerce' ),
        'downloads'       => __( 'Downloads', 'woocommerce' ),
        'edit-address'    => __( 'Addresses', 'woocommerce' ),
        'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
        'edit-account'    => __( 'Account Details', 'woocommerce' ),
        'special-page' => __( 'Special Page', 'woocommerce' ), // My custom tab here
        'customer-logout' => __( 'Logout', 'woocommerce' ),
    );

    return $items;
}

That results in this:

enter image description here

But the link points to my-account/special-page/, and naturally gives a 404 error.

How I can assign this URL to a file named special-page.php?

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
Dario Ferrer
  • 804
  • 1
  • 8
  • 22

4 Answers4

33

Finally I could solve the problem using a snippet provided for the same people of WooCommerce (There are more tips in that page). For anyone interested, paste all the following code in functions.php:

function my_custom_endpoints() {
    add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}

add_action( 'init', 'my_custom_endpoints' );

function my_custom_query_vars( $vars ) {
    $vars[] = 'special-page';

    return $vars;
}

add_filter( 'query_vars', 'my_custom_query_vars', 0 );

function my_custom_flush_rewrite_rules() {
    flush_rewrite_rules();
}

add_action( 'wp_loaded', 'my_custom_flush_rewrite_rules' );

I think this way allows more control to order/renaming the menu:

function my_custom_my_account_menu_items( $items ) {
    $items = array(
        'dashboard'         => __( 'Dashboard', 'woocommerce' ),
        'orders'            => __( 'Orders', 'woocommerce' ),
        //'downloads'       => __( 'Downloads', 'woocommerce' ),
        //'edit-address'    => __( 'Addresses', 'woocommerce' ),
        //'payment-methods' => __( 'Payment Methods', 'woocommerce' ),
        'edit-account'      => __( 'Edit Account', 'woocommerce' ),
        'special-page'      => 'Special Page',
        'customer-logout'   => __( 'Logout', 'woocommerce' ),
    );

    return $items;
}

add_filter( 'woocommerce_account_menu_items', 'my_custom_my_account_menu_items' );

In the following function I included the file to maintain some "order", but it also admits direct code.

Be sure to place the special-page.php file in the myaccount folder.

function my_custom_endpoint_content() {
    include 'woocommerce/myaccount/special-page.php'; 
}

add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );

Important: Once did this, go to Dashboard > Settings > Permalinks and click "Save Settings" in order to flush rewrite rules (thanks @optimiertes)

Source: Tabbed My Account page

Dario Ferrer
  • 804
  • 1
  • 8
  • 22
  • worked only in localhost, now am testing this online and the clients is forcing me to get this to work today ! –  Aug 08 '16 at 17:02
  • 5
    thx for solution. Tip: Change "after_switch_theme" hook to any other headers hook "wp_loaded" - for example. And It will works without swithing themes. – WebArtisan Aug 24 '16 at 09:54
  • 1
    Go to Dashboard > Settings > Permalinks and click "Save Settings" might be easier for flushing the rewrite rules. – optimiertes Mar 16 '17 at 16:04
9

First my-account/special-page/ should be myaccount/special-page/ in woocommerce 2.6+.

This solution is Incomplete and I am still working On…

You can use first this hook:

add_action( 'init', 'add_wc_endpoint' );
function add_wc_endpoint(){
    add_rewrite_endpoint( 'special-page', EP_ROOT | EP_PAGES );
}

Then filtering wc_get_templateto call your files when the request match your endpoint:

add_filter( 'wc_get_template', 'custom_vc_endpoint', 10, 5 );
function custom_vc_endpoint($located, $template_name, $args, $template_path, $default_path){

    if( $template_name == 'myaccount/special-page.php' ){
        global $wp_query;
        if(isset($wp_query->query['special-page'])){
            $located = get_template_directory() . '/woocommerce/myaccount/special-page.php';
        }
    }

    return $located;
}

If you use a child theme, replace get_template_directory() by get_stylesheet_directory()… Paste this code in function.php file of your active child theme or theme.

To avoid a 404 error "page not found", you will need to refresh rewrite rules adding to your code:

flush_rewrite_rules();

Update: Finally Dario (the OP) found a working solution. Look at his answer.

References:

LoicTheAztec
  • 229,944
  • 23
  • 356
  • 399
  • Hi. I did the same as in the above solution, but I'm getting a page not found 404 error. Is there anything that needs to be updated in wordpress 4? – Akash Agrawal Feb 20 '18 at 13:27
  • Flushing rewrite rules from Permalinks page didn't help. Though adding flush_rewrite_rules(); in the code did the trick. Thanks for you suggestion – Akash Agrawal Feb 21 '18 at 06:12
  • 1
    @AkashAgrawal Ok I have added this at the end of this answer. Thanks – LoicTheAztec Feb 21 '18 at 06:26
  • This is a my-account endpoint and my-account tab/pages and other tabs along with it are secured. The user has to login to access these pages, is there any procedure by which I can access my custom endpoint without login? – Akash Agrawal Feb 21 '18 at 08:16
  • 1
    @AkashAgrawal As this endpoints are part of tabbed my account menu, you will not be able to access them without login and I really don't know yet if it's possible todo what you are asking… It should be better to make an accessible clone of the related my account tabs in an other accessible section of your website (that you will display for non logged users)… – LoicTheAztec Feb 21 '18 at 08:24
3

There is a better way to use a template in your custom page in woocommerce:

function my_custom_endpoint_content() {
    wc_get_template( 'myaccount/special-page.php' ); 
}

add_action( 'woocommerce_account_special-page_endpoint', 'my_custom_endpoint_content' );

this should work without using the wc_get_template filter.

masitko
  • 610
  • 7
  • 9
1

You can add this code to your theme's function.php:

class My_Custom_My_Account_Endpoint {
/**
 * Custom endpoint name.
 *
 * @var string
 */
public static $endpoint = 'special-page';
/**
 * Plugin actions.
 */
public function __construct() {
    // Actions used to insert a new endpoint in the WordPress.
    add_action( 'init', array( $this, 'add_endpoints' ) );
    add_filter( 'query_vars', array( $this, 'add_query_vars' ), 0 );
    // Change the My Accout page title.
    add_filter( 'the_title', array( $this, 'endpoint_title' ) );
    // Insering your new tab/page into the My Account page.
    add_filter( 'woocommerce_account_menu_items', array( $this, 'new_menu_items' ) );
    add_action( 'woocommerce_account_' . self::$endpoint .  '_endpoint', array( $this, 'endpoint_content' ) );
}
/**
 * Register new endpoint to use inside My Account page.
 *
 * @see https://developer.wordpress.org/reference/functions/add_rewrite_endpoint/
 */
public function add_endpoints() {
    add_rewrite_endpoint( self::$endpoint, EP_ROOT | EP_PAGES );
}
/**
 * Add new query var.
 *
 * @param array $vars
 * @return array
 */
public function add_query_vars( $vars ) {
    $vars[] = self::$endpoint;
    return $vars;
}
/**
 * Set endpoint title.
 *
 * @param string $title
 * @return string
 */
public function endpoint_title( $title ) {
    global $wp_query;
    $is_endpoint = isset( $wp_query->query_vars[ self::$endpoint ] );
    if ( $is_endpoint && ! is_admin() && is_main_query() && in_the_loop() && is_account_page() ) {
        // New page title.
        $title = __( 'Special Page', 'woocommerce' );
        remove_filter( 'the_title', array( $this, 'endpoint_title' ) );
    }
    return $title;
}
/**
 * Insert the new endpoint into the My Account menu.
 *
 * @param array $items
 * @return array
 */
public function new_menu_items( $items ) {
    // Remove the logout menu item.
    $logout = $items['customer-logout'];
    unset( $items['customer-logout'] );
    // Insert your custom endpoint.
    $items[ self::$endpoint ] = __( 'Special Page', 'woocommerce' );
    // Insert back the logout item.
    $items['customer-logout'] = $logout;
    return $items;
}
/**
 * Endpoint HTML content.
 */
public function endpoint_content() {
    include('woocommerce/myaccount/special-page.php');
}
/**
 * Plugin install action.
 * Flush rewrite rules to make our custom endpoint available.
 */
public static function install() {
    flush_rewrite_rules();
}
}
new My_Custom_My_Account_Endpoint();
// Flush rewrite rules on plugin activation.
register_activation_hook( __FILE__, array( 'My_Custom_My_Account_Endpoint', 'install' ) );

If you don't know where is your theme's function.php:

1.Log in to the WordPress Admin interface
2.In the left sidebar, hover over Appearances, then click Theme Editor
3.In the right sidebar, click functions.php

Alireza Sabahi
  • 647
  • 1
  • 12
  • 35
  • 1
    This might be great code, but not such a great answer. Some extra explanation could be useful. More importantly: Advising to change the theme's functions.php through the Theme Editor is just plain bad practice, especially without mentioning that theme changes shoudl always be made in a child theme. – Ralph Smit Apr 19 '20 at 20:24
  • This answer code is mostly copied from official [WooCommerce "Tabbed “My Account” pages in 2.6"](https://developer.woocommerce.com/2016/04/21/tabbed-my-account-pages-in-2-6/) documentation and the author is Claudio Sanches (official WooCommerce developper)… It is already linked In [the OP answer](https://stackoverflow.com/a/38056768/3730754) – LoicTheAztec Oct 17 '20 at 01:34