Take the 2-minute tour ×
WordPress Development Stack Exchange is a question and answer site for WordPress developers and administrators. It's 100% free, no registration required.

I am using a blog to keep track of citations I may want to use for a thesis. Each citation is a Post, authors are categories, which are parents to subcategories that are named for the titles of books or articles by that author. In the description of the book/article subcategories, I put the publishing information, e.g. “Penguin: London, 2007”.

Let’s assume that a particular author category is called “Mill, John Stuart” (for whom there are four citations), the book subcategory “On Liberty” (for which there are two citations), and the description “Bantam Classic: London, 1993”. Now, I would like to add a Page that shows all the sources that I have gathered, automatically outputting HTML code like this:

<p class="lit-author"><a href="../category/mill-john-stuart/">Mill, John Stuart</a> (4)</p>
<p class="lit-work"><a href="../category/mill-john-stuart/on-liberty/"><i>On Liberty<i></a>. Bantam Classic: London, 1993. (2)</p>

This might just as well be done with <ul>s, I’m really only interested in being able to format the output using CSS and having in on a Page. (It’s pretty much just the contents of a Categories widget, but on a Page, plus the category description.)

How would I do this, and where would I have to put the relevant code so that it would be displayed on a specific Page?

(WP 3.2.1, Graphene 1.4.1)

share|improve this question

2 Answers 2

First you need to get all the categories that don't have parents (top-level categories). We're going to use get_terms for this. Get terms will either return an empty array, a WP_Error object, or an array of objects representing terms. So we need to make sure our call works before continuing as well.

<?php
// very hackish get_terms call with the 0 as a string to return top level terms
$cats = get_terms( 'category', array( 'parent' => '0' ) );
if( ! $cats || is_wp_error( $cats ) ) return;

With that in place we can start by outputing a container div, then starting a foreach loop to loop through all the categories. We'll output the term and link inside a paragraph as per your request above.

<?php
$out = '<div id="ref-list">' . "\n";
foreach( $cats as $cat )
{
    $out .= sprintf( 
        '<p class="lit-author"><a href="%s">%s</a></p>',
        esc_url( get_term_link( $cat ) ),
        sanitize_term_field( 'name', $cat->name, $cat->term_id, 'category', 'display' )
    );

    $out .= "\n"; // add some newlines to prettify our source

Still inside our foreach( $cats as $cat ) loop, we can loop for term children. If we find them, we'll loop through each child, getting its link, name, and description.

     <?php
    $children = get_term_children( $cat->term_id, 'category' );
    if( $children && ! is_wp_error( $children ) )
    {
        foreach( $children as $child )
        {
            $child = get_term( $child, 'category' );
            if( is_wp_error( $child ) ) continue;
            $out .= sprintf( 
                '<p class="lit-work"><a href="%s"><em>%s</em></a>. %s</p>',
                esc_url( get_term_link( $child ) ),
                sanitize_term_field( 'name', $child->name, $child->term_id, 'category', 'display' ),
                esc_attr( $child->description ) // sanitize_term_field adds autop, no good for this situation
            );
            $out .= "\n"; // prettifying newline
        }
    }
} // end of the foreach( $cats as $cat ) loop
$out .= "</div>\n";
return $out;

You can encapsulate this entire mess in a function (note: counts are added here, forgot them above).

<?php
function wpse25157_ref_list()
{
    // very hackish get_terms call with the 0 as a string to return top level terms
    $cats = get_terms( 'category', array( 'parent' => '0' ) );
    if( ! $cats || is_wp_error( $cats ) ) return;
    $out = '<div id="ref-list">' . "\n";
    foreach( $cats as $cat )
    {
        $out .= sprintf( 
            '<p class="lit-author"><a href="%s">%s</a> (%s)</p>',
            esc_url( get_term_link( $cat ) ),
            sanitize_term_field( 'name', $cat->name, $cat->term_id, 'category', 'display' ),
            sanitize_term_field( 'count', $cat->count, $cat->term_id, 'category', 'display' )
        );

        $out .= "\n"; // add some newlines to prettify our source

        $children = get_term_children( $cat->term_id, 'category' );
        if( $children && ! is_wp_error( $children ) )
        {
            foreach( $children as $child )
            {
                $child = get_term( $child, 'category' );
                if( is_wp_error( $child ) ) continue;
                $out .= sprintf( 
                    '<p class="lit-work"><a href="%s"><em>%s</em></a>. %s (%s)</p>',
                    esc_url( get_term_link( $child ) ),
                    sanitize_term_field( 'name', $child->name, $child->term_id, 'category', 'display' ),
                    esc_attr( $child->description ),
                    sanitize_term_field( 'count', $child->count, $child->term_id, 'category', 'display' )
                );
                $out .= "\n"; // prettifying newline
            }
        }
    } // end of the foreach( $cats as $cat ) loop
    $out .= "</div>\n";
    return $out;
}

And add a shortcode to display it all on any page/post you like.

<?php
add_action( 'init', 'wpse25157_init' );
function wpse25157_init()
{
    add_shortcode( 'ref-list', 'wpse25157_ref_list' );  
}

As a plugin: https://gist.github.com/1196457

share|improve this answer

Copy page.php in your theme root and name it page-list-of-categories.php. Put the following at the top:

<?php
/**
 * Template Name: Page Category Display
 */
?>

Somewhere after <?php the_title()?> place the following...

<?php
$args = array('title_li' => '');
?>
<ul id="myCategories"><?php wp_list_categories($args);?></ul>

Then make a page and select "Page Category Display" from the dropdown under "Template" in the "Page Attributes" box.

The css classes you have above won't be output, but you will be able to style them because it appears that your lit-work categories are always children of author categories. So you can refer to authors with ul#myCategories li and works as ul#myCategories li li.

There are other options -- passed in the $args array -- for wp_list_categories that you can look into.

share|improve this answer
    
Sorry, couldn’t get this to work. In the theme I’m using, Graphene, there is no page.php, and all attempts to insert your solution into loop.php and single.php, respectively, were unsuccessful. :( –  Peter Beattie Aug 6 '11 at 18:53

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.