Create a WordPress Index List with Tags as Headers

I’ve been going through my inspiration folders and blogging about the items I find cool or useful, but I wanted an easier way for readers and clients to browse my inspiration pieces.  In the past I’d managed a hard-coded list with links, not something I wanted to maintain now.  Since I write posts about most of these items, it made sense to find a way for WordPress to compile the index itself  using tags.  The criteria:

  • Each tag would be a header with a list of posts under it
  • Some posts would appear in multiple tags
  • Only the categorizing tags would appear in the list (i.e. not every tag I use, just those I want in the index)
  • The list of posts would consist of the title which is linked to the demo (not the post itself).  If there is no separate demo, it will link to the post.

The result:

First, I created a new page template.  Because I use the Genesis framework, this would be the easy part.

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
<?php
/*
Template Name: Inspiration
*/
/** Remove the standard loop */
remove_action( 'genesis_loop', 'genesis_do_loop' );
add_action('genesis_loop', 'bp_do_loop');

&nbsp;

&nbsp;

/** Add the Portfolio widget area */
/*
add_action( 'genesis_loop', 'lifestyle_portfolio_widget' );
function lifestyle_portfolio_widget() {
dynamic_sidebar( 'portfolio' );
}
*/
genesis();

 

 

I removed the standard genesis loop which actually creates the content of a page and added a call to my own custom loop….which I now needed to write.  But first, I created the new page  in WordPress (Dashboard->Pages->Add New) and applied the template so I could test everything as I went along.  I also created a category called “Inspiration Index”.

The Loop

We are actually doing something pretty complicated here.  First, we want to get a list of all of the tags in the category “Inspiration Index”.  Then we want to go through each tag, print it as a header and then find all of the posts that are in “Inspiration Index” and use that tag.

I was lucky and found a ready made search function in the WordPress forums :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
function get_category_tags($args) {
global $wpdb;
$tags = $wpdb-&gt;get_results
("
SELECT DISTINCT terms2.term_id as tag_id, terms2.name as tag_name, null as tag_link
FROM
wp_posts as p1
LEFT JOIN wp_term_relationships as r1 ON p1.ID = r1.object_ID
LEFT JOIN wp_term_taxonomy as t1 ON r1.term_taxonomy_id = t1.term_taxonomy_id
LEFT JOIN wp_terms as terms1 ON t1.term_id = terms1.term_id,

wp_posts as p2
LEFT JOIN wp_term_relationships as r2 ON p2.ID = r2.object_ID
LEFT JOIN wp_term_taxonomy as t2 ON r2.term_taxonomy_id = t2.term_taxonomy_id
LEFT JOIN wp_terms as terms2 ON t2.term_id = terms2.term_id
WHERE
t1.taxonomy = 'category' AND p1.post_status = 'publish' AND terms1.term_id IN (".$args['categories'].") AND
t2.taxonomy = 'post_tag' AND p2.post_status = 'publish'
AND p1.ID = p2.ID
ORDER by tag_name
");
$count = 0;
foreach ($tags as $tag) {
$tags[$count]-&gt;tag_link = get_tag_link($tag-&gt;tag_id);
$count++;
}
return $tags;
}

 

This function takes an array of category ids and returns all of the tags for those categories, which is half the work!  I added the function to my functions.php file and created a new function for my custom loop:

1
2
3
function bp_do_loop(){

}

 

I get the list of tags for my category “Inspiration Index” (which has an id of 209):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
$args = array('categories' => '209');
$tags = get_category_tags($args);

}

&nbsp;

and create a loop to step through each tag in my list:

{code type=php}

foreach ($tags as $tag) {
if($tag->tag_name != 'bp' && $tag->tag_name != 'featured content'){
echo "<h3>".ucfirst($tag->tag_name)."</h3><ul class='no-list'>";

}

}

&nbsp;

The if statement removes two tags from consideration, "bp" and "featured content".  I don't want these tags in my list because they are used in other contexts.  I am also creating the tag header here.  Now for the search:

{code type=php}

$the_query = new WP_Query(array('tag'=>$tag->tag_name, 'cat' =>209));

 

I now have the posts for my particular tag, so I just print them out and reset the postdata before going on to the next tag and doing it all over

1
2
3
4
5
6
7
8
9
while ( $the_query->have_posts() ) : $the_query->the_post();
$thelink = get_post_custom_values('bp_inspiration_url');
?><li><a href="<?php echo($thelink[0]) ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>" target="_blank"><?php the_title(); ?></a></li><?php
endwhile;

// Reset Post Data
wp_reset_postdata();
}
}

 

 

Remember when I said I wanted the post link to go to the demo?  I used a custom field (bp_inspiration_url) to hold the URL I want the link to go to.

I added some page and list formatting to the loop and here is the code in its entirety:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
function get_category_tags($args) {
global $wpdb;
$tags = $wpdb->get_results
("
SELECT DISTINCT terms2.term_id as tag_id, terms2.name as tag_name, null as tag_link
FROM
wp_posts as p1
LEFT JOIN wp_term_relationships as r1 ON p1.ID = r1.object_ID
LEFT JOIN wp_term_taxonomy as t1 ON r1.term_taxonomy_id = t1.term_taxonomy_id
LEFT JOIN wp_terms as terms1 ON t1.term_id = terms1.term_id,

wp_posts as p2
LEFT JOIN wp_term_relationships as r2 ON p2.ID = r2.object_ID
LEFT JOIN wp_term_taxonomy as t2 ON r2.term_taxonomy_id = t2.term_taxonomy_id
LEFT JOIN wp_terms as terms2 ON t2.term_id = terms2.term_id
WHERE
t1.taxonomy = 'category' AND p1.post_status = 'publish' AND terms1.term_id IN (".$args['categories'].") AND
t2.taxonomy = 'post_tag' AND p2.post_status = 'publish'
AND p1.ID = p2.ID
ORDER by tag_name
");
$count = 0;
foreach ($tags as $tag) {
$tags[$count]->tag_link = get_tag_link($tag->tag_id);
$count++;
}
return $tags;
}

function bp_do_loop(){

$args = array('categories' => '209');
$tags = get_category_tags($args);


echo '<div class="page inspirationindex">';
echo"<h2>Inspiration Index</h2>";


foreach ($tags as $tag) {
if($tag->tag_name != 'bp' && $tag->tag_name != 'featured content'){
echo "<h3>".ucfirst($tag->tag_name)."</h3><ul class='no-list'>";

$the_query = new WP_Query(array('tag'=>$tag->tag_name, 'cat' =>209));

while ( $the_query->have_posts() ) : $the_query->the_post();
$thelink = get_post_custom_values('bp_inspiration_url');
?><li><a href="<?php echo($thelink[0]) ?>" rel="bookmark" title="Permanent Link to <?php the_title_attribute(); ?>" target="_blank"><?php the_title(); ?></a></li><?php
endwhile;


echo"</ul>";
// Reset Post Data
wp_reset_postdata();
}
}
echo '</div>';
}

You can see the result here.


Diane Ensey
Follow me

Diane Ensey

Programming Diva and CEO at Beyond Paper
For more than 10 years I've been making websites work for clients world-wide using WordPress, Google Maps, forms and custom applications. You can see my work portfolio and case studies at Beyond Paper.
Diane Ensey
Follow me

Submit a Comment