Index: wp-includes/category-template.php
===================================================================
--- wp-includes/category-template.php	(revision 30416)
+++ wp-includes/category-template.php	(working copy)
@@ -36,30 +36,10 @@
  * @param bool $link Optional, default is false. Whether to format with link.
  * @param string $separator Optional, default is '/'. How to separate categories.
  * @param bool $nicename Optional, default is false. Whether to use nice name for display.
- * @param array $visited Optional. Already linked to categories to prevent duplicates.
- * @return string|WP_Error A list of category parents on success, WP_Error on failure.
+ * @return string A list of category parents on success, empty string on failure.
  */
-function get_category_parents( $id, $link = false, $separator = '/', $nicename = false, $visited = array() ) {
-	$chain = '';
-	$parent = get_term( $id, 'category' );
-	if ( is_wp_error( $parent ) )
-		return $parent;
-
-	if ( $nicename )
-		$name = $parent->slug;
-	else
-		$name = $parent->name;
-
-	if ( $parent->parent && ( $parent->parent != $parent->term_id ) && !in_array( $parent->parent, $visited ) ) {
-		$visited[] = $parent->parent;
-		$chain .= get_category_parents( $parent->parent, $link, $separator, $nicename, $visited );
-	}
-
-	if ( $link )
-		$chain .= '<a href="' . esc_url( get_category_link( $parent->term_id ) ) . '">'.$name.'</a>' . $separator;
-	else
-		$chain .= $name.$separator;
-	return $chain;
+function get_category_parents( $id, $link = false, $separator = '/', $nicename = false ) {
+	return get_term_parents_html( $id, 'category', $link, $separator, $nicename );
 }
 
 /**
Index: wp-includes/taxonomy.php
===================================================================
--- wp-includes/taxonomy.php	(revision 30416)
+++ wp-includes/taxonomy.php	(working copy)
@@ -1496,6 +1496,102 @@
 }
 
 /**
+ * Return a hierarchical array of a given term's parents.
+ *
+ * @since 4.1.0
+ *
+ * @param string $term_id ID of Term to get parents.
+ * @param string $taxonomy Taxonomy name.
+ * @param boolean $reverse Optional, default to false. Whether to return terms array in reverse order.
+ * @return array|WP_Error List of Term IDs. WP_Error returned if $taxonomy does not exist or $taxonomy is not hierarchical.
+ */
+function get_term_parents( $term_id, $taxonomy, $reverse = false ) {
+
+	if ( ! taxonomy_exists( $taxonomy ) ) {
+		return new WP_Error( 'invalid_taxonomy', __( 'Invalid taxonomy' ) );
+	}
+
+	if( ! is_taxonomy_hierarchical( $taxonomy ) ) {
+		return new WP_Error( 'taxonomy_not_hierarchical', sprintf( __( 'The "%s" taxonomy is not hierarchical.' ), $taxonomy ) );
+	}
+
+	$term_id = intval( $term_id );
+
+	$term = get_term( $term_id, $taxonomy );
+
+	if ( is_wp_error( $term ) ) {
+		return $term;
+	}
+
+	$parents = array();
+	while( ! is_wp_error( $term ) ) {
+		if ( $term->parent && ( $term->parent != $term->term_id ) ) {
+			$parents[] = $term->parent;
+			$term = get_term( $term->parent, $taxonomy );
+		} else {
+			break;
+		}
+	}
+
+	if( $reverse ) {
+		$parents = array_reverse( $parents );
+	}
+
+	return $parents;
+}
+
+/**
+ * Return term parents with a given separator.
+ *
+ * @since 4.1.0
+ *
+ * @param string $term_id ID of Term to get parents.
+ * @param string $taxonomy Optional, default is 'category. Taxonomy name.
+ * @param bool $link Optional, default is false. Whether to format with link.
+ * @param string $separator Optional, default is '/'. How to separate categories.
+ * @param bool $nicename Optional, default is false. Whether to use nice name for display.
+ * @return string A list of term parents on success, empty string on failure.
+ */
+function get_term_parents_html( $term_id, $taxonomy = 'category', $link = false, $separator = '/', $nicename = false ) {
+
+	$parents = (array) get_term_parents( $term_id, $taxonomy, true );
+
+	$chain = '';
+
+	if( 0 == count( $parents ) ) {
+		return $chain;
+	}
+
+	foreach( $parents as $parent ) {
+
+		$term = get_term( $parent, $taxonomy );
+
+		if ( is_wp_error( $term ) ) {
+			continue;
+		}
+
+		if ( $nicename ) {
+			$name = $term->slug;
+		} else {
+			$name = $term->name;
+		}
+
+		if( $chain ) {
+			$chain .= $separator;
+		}
+
+		if ( $link ) {
+			$chain .= '<a href="' . esc_url( get_term_link( $term->term_id, $taxonomy ) ) . '">' . $name . '</a>';
+		} else {
+			$chain .= $name;
+		}
+
+	}
+
+	return $chain;
+}
+
+/**
  * Get sanitized Term field.
  *
  * Does checks for $term, based on the $taxonomy. The function is for contextual
