$term_id, 'hide_empty' => true ]; // User-controlled exclusion list for nested category rendering — exclude is required UX. // phpcs:disable WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude if ( isset( $terms_exclude ) ) { $_terms_args['exclude'] = $terms_exclude; } elseif ( isset( $exclude ) ) { $_terms_args['exclude'] = $exclude; } // phpcs:enable WordPressVIPMinimum.Performance.WPQueryParams.PostNotIn_exclude $nested_terms_query = isset( $nested_terms_query ) ? array_merge( $_terms_args, $nested_terms_query ) : $_terms_args; $_nested_categories = get_terms( betterdocs()->query->terms_query( apply_filters( 'betterdocs_nested_terms_args', $nested_terms_query ) ) ); if ( empty( $_nested_categories ) ) { return; } $_nested_term_ids = wp_list_pluck( $_nested_categories, 'term_id' ); if ( ! empty( $_nested_term_ids ) ) { update_termmeta_cache( $_nested_term_ids ); } // Fragment cache: cache the rendered HTML of the entire nested subtree at the // outermost invocation. The active-branch highlighting is baked into the // rendered HTML server-side (see the $classes / inline-style computation // below), so the cache key must vary by the current page's identity as well as // the top-level term, caps, and kb (see the key composition further down). // (`static` at file scope doesn't persist across the recursive include, so // the depth tracker has to live on a global.) global $bd_nested_depth; if ( ! isset( $bd_nested_depth ) ) { $bd_nested_depth = 0; } $bd_is_outermost = ( $bd_nested_depth === 0 ); $bd_cache_key = ''; if ( $bd_is_outermost ) { $bd_can_priv = current_user_can( 'read_private_docs' ) ? 1 : 0; $bd_multi_kb = isset( $multiple_knowledge_base ) && $multiple_knowledge_base ? 1 : 0; $bd_kb_slug = isset( $kb_slug ) ? $kb_slug : ''; $bd_cat_icon = isset( $category_icon ) ? (string) $category_icon : ''; // Active-state highlighting is now baked into the rendered HTML (see // $classes / inline style computation below). That means the cache key // must also vary by the current page's identity, otherwise a fragment // rendered while viewing page A would be served unchanged to page B with // the wrong .active branch. $bd_queried = (int) get_queried_object_id(); $bd_is_single = is_singular( 'docs' ) ? 1 : 0; $bd_version = betterdocs()->database->get_cache_version( 'betterdocs_term_counts' ); $bd_icon_disc = md5( wp_json_encode( isset( $list_icon_name ) ? $list_icon_name : "" ) ); $bd_show_icon = ( isset( $show_list_icon ) && $show_list_icon === false ) ? 0 : 1; $bd_order_disc = md5( wp_json_encode( array( isset( $nested_terms_query ) ? $nested_terms_query : array(), isset( $nested_docs_query_args ) ? $nested_docs_query_args : array() ) ) ); $bd_cache_key = 'bd_nested_frag_' . md5( "v{$bd_version}_term{$term_id}_m{$bd_multi_kb}_k{$bd_kb_slug}_p{$bd_can_priv}_i{$bd_cat_icon}_q{$bd_queried}_s{$bd_is_single}_ic{$bd_icon_disc}_si{$bd_show_icon}_o{$bd_order_disc}" ); $bd_cached = get_transient( $bd_cache_key ); if ( false !== $bd_cached ) { echo $bd_cached; //phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped return; } ob_start(); } $bd_nested_depth++; // Ensure $layout_type is set if ( ! isset( $layout_type ) ) { $layout_type = ''; } // if there have list icon url from customizer or shortcodes attribites format it to $list_icon_name if ( $layout_type == 'template' && isset( $list_icon_url ) && $list_icon_url ) { $list_icon_name = array( 'value' => array( 'url' => $list_icon_url ) ); } // Check if list icon should be shown $_show_list_icon = true; if ( isset( $show_list_icon ) && $show_list_icon === false ) { $_show_list_icon = false; } $_icon = $_show_list_icon ? betterdocs()->template_helper->icon( isset( $list_icon_name ) ? $list_icon_name : 'list' ) : ''; // Active-branch detection (mirrors master). Used to set .active class + // display:block on each nested-category-list