Skip to content

Instantly share code, notes, and snippets.

@Rahmon
Last active June 21, 2023 11:43
Show Gist options
  • Save Rahmon/b03f7a014b9d686beb2dbf11035a708e to your computer and use it in GitHub Desktop.
Save Rahmon/b03f7a014b9d686beb2dbf11035a708e to your computer and use it in GitHub Desktop.
Get the post categories preserving the hierarchical order (WordPress)
<?php
/**
* Get the post categories preserving the hierarchical order
*
* This function returns an array with the following structure
*
* [
* [parent_term_id] => [
* [children] => [
* [child_term_id] => [
* [children] => [
* [...]
* ],
* [name] => 'child_term_name',
* ],
* ],
* [name] => 'parent_term_name
* ]
* [...]
* ]
*
* @author Ramon Ahnert <https://profiles.wordpress.org/rahmohn/>, Felipe Elia <https://profiles.wordpress.org/felipeelia/>
* @param int $post_id The post ID
* @return array
*/
function get_post_categories( $post_id ) {
$categories = wp_list_sort( get_the_category( $post_id ), 'term_id' );
$transient_key = 'post-' . $post_id . '-categories-tree';
if ( empty( $categories ) ) {
delete_transient( $transient_key );
return [];
}
/**
* Return an array with term_id, name and parent
*
* @param WP_Term $category
* @return array
*/
$map_termid_name_parent = function ( $category ) {
return [
'term_id' => $category->term_id,
'name' => $category->name,
'parent' => $category->parent,
];
};
$cached_categories = get_transient( $transient_key );
// If categories don't changed, we'll return a cached value.
if (
false !== $cached_categories &&
is_array( $cached_categories ) &&
! empty( $cached_categories['categories_tree'] ) &&
! empty( $cached_categories['term_id_name_parent_json'] )
) {
// We rely on term_id, name and parent to check if categories have changed
$categories_termid_name_parent_json = wp_json_encode( array_map( $map_termid_name_parent, $categories ) );
if ( $categories_termid_name_parent_json === $cached_categories['term_id_name_parent_json'] ) {
return $cached_categories['categories_tree'];
}
}
/**
* Build the category tree
*
* This function returns an array with the following structure
*
* [
* [parent_term_id] => [
* [children] => [
* [child_term_id] => [
* [name] => 'child_term_name',
* [children] => [
* [...]
* ]
* ]
* ]
* ]
* [...]
* ]
*
* @param array $categories_tree Array used to hold the categories (passed by reference)
* @param WP_Term $child_category Child category
* @param array $ancestors The ancestors ids of child category from highest to lowest in the hierarchy
* @param integer $key Position in the hierarchy of ancestors
* @param integer $depth_level Check how depth we are to avoid an infinite loop
* @return void
*/
$build_category_tree = function ( &$categories_tree, $child_category, $ancestors, $key = 0, $depth_level = 0 ) use ( &$build_category_tree ) {
$count = count( $ancestors );
if ( $key < $count && 200 > $depth_level ) {
// If the category is not on the category tree, add it.
if ( ! array_key_exists( $ancestors[ $key ], $categories_tree ) ) {
$categories_tree[ $ancestors[ $key ] ]['children'] = [];
}
// Fill with child category name
if ( $ancestors[ $key ] === $child_category->parent ) {
$categories_tree[ $ancestors[ $key ] ]['children'][ $child_category->term_id ]['name'] = $child_category->name;
}
// Go to the next level of hierarchy
$build_category_tree( $categories_tree[ $ancestors[ $key ] ]['children'], $child_category, $ancestors, $key + 1, $depth_level + 1 );
}
};
$categories_tree = [];
// Build the category tree with all levels
foreach ( $categories as $category ) {
// Fill the category tree with the information of root categories
if ( 0 === $category->parent ) {
$categories_tree[ $category->term_id ]['name'] = $category->name;
continue;
}
$ancestors = array_reverse( get_ancestors( $category->term_id, 'category', 'taxonomy' ) );
$build_category_tree( $categories_tree, $category, $ancestors );
}
// Rely on term_id, name and parent to verify if categories have changed
$categories_termid_name_parent = array_map( $map_termid_name_parent, $categories );
set_transient(
$transient_key,
[
'term_id_name_parent_json' => wp_json_encode( $categories_termid_name_parent ),
'categories_tree' => $categories_tree,
]
);
return $categories_tree;
}
// print_r( get_post_categories( $YOUR_POST_ID ) );
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment