Custom Permalink Plugin and Current Page/Ancestor in Menus

I’m looking for a custom permalink plugin that is able to interact with menu classes.

For instance, I have a menu that includes the parent website.com/shop as one of its list items. If a page, say website.com/shop/product, includes that menu, the list item for website.com/shop will get a class, something like current-page-ancestor. This is useful for styling that link so users know what section of the website they are on.

Read More

But I will have pages whose parent will not be website.com/shop (a feature I can’t change), but I want it to appear that website.com/shop is the parent. For instance, the page is website.com/foo/product-2. I’m currently using the Custom Permalinks plugin to change the permalink to website.com/shop/product-2. But in doing this, the menu does not recognize that website.com/shop is the parent, and no class is added to the menu’s list item.

Is there any workaround for this, or does anyone know of a custom permalinks plugin that would support menu ancestry?


Edit

I feel like I’m right there, but missing one thing…

function getUrl() {
      $url  = @( $_SERVER["HTTPS"] != 'on' ) ? 'http://'.$_SERVER["SERVER_NAME"] :  'https://'.$_SERVER["SERVER_NAME"];
      $url .= ( $_SERVER["SERVER_PORT"] !== 80 ) ? ":".$_SERVER["SERVER_PORT"] : "";
      $url .= $_SERVER["REQUEST_URI"];
      return $url;
    }
    function getDir($foo) {
        $url = $foo;
        $info = parse_url($url);
        $dir = dirname($info["path"]);
        return $dir;
    }
    function wpa83498_nav_class( $classes, $item ){
        // if Shop is the current menu item being output
        // and we're viewing a single product post type
        $currentDirPath = getDir(getUrl());
        if( ('Sales' == $item->title && is_singular( 'product' )) || (parse_url($item->url, PHP_URL_PATH) == $currentDirPath && is_singular( 'product' )) )
            $classes[] = 'current-page-ancestor';
        return $classes;
    }
    add_filter( 'nav_menu_css_class', 'wpa83498_nav_class', 10, 2 );

Related posts

Leave a Reply

2 comments

  1. You could add classes to wp_nav_menu via the nav_menu_css_class filter:

    function wpa83498_nav_class( $classes, $item ){
        // if Shop is the current menu item being output
        // and we're viewing a single product post type
        if( 'Shop' == $item->title && is_singular( 'product' ) )
            $classes[] = 'current-page-ancestor';
        return $classes;
    }
    add_filter( 'nav_menu_css_class', 'wpa83498_nav_class', 10, 2 );
    

    EDIT-

    Try this to see how the objects that make up a menu are constructed. Perhaps it will shed some light on how you can manipulate menu output. Look at things like menu_item_parent and object_id to see how menu items are related to each other and the posts / pages they represent. Warning- do not do this on a live site!

    function wpa_inspect_menu_objects( $menu ) {    
        echo '<pre>';
        print_r( $menu );
        echo '</pre>';  
        die();  
    }
    add_filter( 'wp_nav_menu_objects' , 'wpa_inspect_menu_objects' );
    
  2. Here was the final solution I came up with. I spent a lot of looking into whether I could change the the custom post type “product” to hierarchical and set its page parent appropriately so that the menus would add the correct ancestor classes naturally. But I hit a road block and eventually came back to a solution based on the new permalink.

    So I imagine this should work for anyone who is aiming to fake a page parent hierarchy when using custom permalinks.

    We get the current page url (set by the custom permalinks plugin), then strip it down to the path and save it as the $currentDirPath variable. Then we evaluate whether a menu item’s url path is contained within the $currentDirPath, and if so we add the current-page-ancestor class.

    function getUrl() {
      $url  = @( $_SERVER["HTTPS"] != 'on' ) ? 'http://'.$_SERVER["SERVER_NAME"] :  'https://'.$_SERVER["SERVER_NAME"];
      $url .= ( $_SERVER["SERVER_PORT"] !== 80 ) ? ":".$_SERVER["SERVER_PORT"] : "";
      $url .= $_SERVER["REQUEST_URI"];
      return $url;
    }
    function getDir($foo) {
        $url = $foo;
        $info = parse_url($url);
        $dir = dirname($info["path"]);
        return $dir;
    }
    function wpa83498_nav_class( $classes, $item ){
        $currentDirPath = getDir(getUrl());
        if( (strpos($currentDirPath,(parse_url($item->url, PHP_URL_PATH))) !== false) && is_singular( 'product' ) )
            $classes[] = 'current-page-ancestor';
        return $classes;
    }
    add_filter( 'nav_menu_css_class', 'wpa83498_nav_class', 10, 2 );