Skip to content
mgburns edited this page Feb 24, 2013 · 18 revisions

The navigation library provides several low-level functions for querying large amounts of posts hierarchically.

Two functions in particuar are used through the navigation plugin to selectively fetch posts in specific "sections" (any post with at least one child is considered to be a section).

  • bu_navigation_gather_sections() - Load ancestors or descendants of a specific post
  • bu_navigation_get_posts() - Alternative to WP_Query, allows you to get posts in specific sections

Using the navigation library

For example, let's consider the following page hierarchy:

  • About
    • Our staff
      • John Smith
      • Jane Doe
    • Contact Us
    • Our Mission

Assuming that the post ID for the "About" page is 5, the following lines of code would fetch all pages in the "About" section:

<?php
$section_args = array(
    'post_types' => 'page',
    'direction' => 'down'
);
$sections = bu_navigation_gather_sections( 5, $section_args );
$pages = bu_navigation_get_posts( array( 'sections' => $sections, 'post_types' => 'page' ) );
$pages_by_parent = bu_navigation_posts_by_parent( $pages );

Filters

One of the more powerful features of using WP_Query is that you get post meta and other post-related meta data (such as taxonomy) for free. Since the navigation library was designed to be a leaner alternative in order to work with large page counts, it is up to clients of the navigation library to fetch any additionally required data.

The navigation library provides several filters which can be used to modify the results returned by library function calls.

The following example, taken from the navigation plugin, uses the bu_navigation_filter_pages filter to fetch multiple custom post meta values in one query and append the results to each post object. In this example the meta data is the custom navigation label, entered using the text field in the "Placement in Navigation" metabox.

<?php
// Name of meta_key used to hold navigation labels
define('BU_NAV_META_PAGE_LABEL', '_bu_cms_navigation_page_label');

function bu_navigation_filter_pages_navlabels( $pages ) {
    global $wpdb;

    $filtered = array();

    if ( is_array( $pages ) && count( $pages ) > 0 ) {

        $ids = array_keys( $pages );
        $query = sprintf( "SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s) AND meta_value != ''",
            $wpdb->postmeta,
            BU_NAV_META_PAGE_LABEL,
            implode( ',', $ids )
            );

        $labels = $wpdb->get_results( $query, OBJECT_K );

        if ( is_array( $labels ) && count( $labels ) > 0 ) {
            foreach ( $pages as $page ) {
                if ( array_key_exists( $page->ID, $labels ) ) {
                    $label = $labels[ $page->ID ];
                    $page->navigation_label = $label->meta_value;
                }
                $filtered[ $page->ID ] = $page;
            }
        } else {
            $filtered = $pages;
        }
    }

    return $filtered;
}

add_filter( 'bu_navigation_filter_pages', 'bu_navigation_filter_pages_navlabels' );

Adding this filter before a call to bu_navigation_get_posts() will result in post objects being returned with navigation label meta data attached to the objects themselves.

Another example use case from the navigation plugin - removing posts that have been marked as hidden from navigation lists by unchecking the "Display page in navigation lists" checkbox.

<?php
// Name of meta_key used to exclude pages from navigation
define( 'BU_NAV_META_PAGE_EXCLUDE', '_bu_cms_navigation_exclude' );

function bu_navigation_filter_pages_exclude( $pages ) {
    global $wpdb;

    $filtered = array();

    if ( is_array( $pages ) && count( $pages ) > 0 ) {
        $ids = array_keys( $pages );

        $query = sprintf( "SELECT post_id, meta_value FROM %s WHERE meta_key = '%s' AND post_id IN (%s) AND meta_value != '0'",
            $wpdb->postmeta,
            BU_NAV_META_PAGE_EXCLUDE,
            implode( ',', $ids )
            );
        $exclusions = $wpdb->get_results( $query, OBJECT_K );

        if ( is_array( $exclusions ) && count( $exclusions ) > 0 ) {
            foreach ( $pages as $page ) {
                if ( ! array_key_exists( $page->ID, $exclusions ) ) {
                    $filtered[ $page->ID ] = $page;
                }
            }
        } else {
            $filtered = $pages;
        }
    }

    return $filtered;
}

add_filter( 'bu_navigation_filter_pages', 'bu_navigation_filter_pages_exclude' );
Clone this wiki locally