Lately, I’ve been struggling a lot with permalinks, permastructures, hierarchy slugs, and so on, for a plugin I’m working on. During these days of core reading I’ve bumped into a function called get_page_uri(), a super simple function but still deserving a full post about it.

From the Codex you’ll get:

Builds and returns a URI for a page from a page id.
If the page has parents, those are prepended to the URI to provide a full path. For example, a third level page might return a URI like this:

    top-level-page/sub-page/current-page

Custom Post Types deserve it

Well, Codex is not telling all the truth behind it since looking to the WordPress core file /wp-includes/post.php where this function is standing, there are no limitation whatsoever to the type accepted as input object id.

<?php get_page_uri( $object_id ) ?>

So, you may call the function for any post type (being hierarchical or not, being a page or not). It will always return the full object URI, being just the post->post_name or the full hierarchic URI.

Also related with this, you may find useful to check how to register a custom post type and how to retrieve the post parents (ancestors).