Lately I've been learning all I can on leveraging the functionality of the Thesis theme for WordPress. When I first heard about the versatility and power of Thesis in a blog post by Rae Hoffman, I was immediately interested in what benefits I could offer my customers that opted to have me design and build them a custom WordPress site. Having customized and hacked several of Chris Pearson's WordPress themes in the past, I figured I should just go for it and purchase the Thesis developer theme - Chris' greatest accomplishment thus far.
I have to admit, when I first took a look into the core of the Thesis framework, I was a bit intimidated - Thesis was nothing like I expected under the hood. First off, Thesis comes with lots of customization options right out of the box ... [Take a look here] So, getting to know what was available from the core install was quite an undertaking in itself. The good news is, when you purchase Thesis, you not only get a lifetime subscription to the theme, you also get the exceptional tech support of the Thesis designer / developer community. The support community is always available to help you along the way as you learn how to negotiate the Thesis framework.
I'm definitely not the kind of guy that is happy with being 'okay'. If there's a way to make something better, stronger or faster - then that's what I'm gonna' try to do next. So, when I saw that there wasn't a simple way of making custom page templates in Thesis - I knew that I needed to set out to tackle that issue. One of the first things I wanted to do in my own Thesis themes, was to create and XHTML sitemap like some other WordPress themes had. In the past, I would simply create a custom page template for my sitemap page and then rip out and modify the code from a theme that I admired. Simple. However, in Thesis things aren't so easy. First of all, the Thesis was of customizing pages is to make all your custom changes to pages that won't be affected in future upgrades. Thesis does so by offering customization through manipulating two files; styles.css, custom_functions.php, both of which are available under the theme's custom folder. However, most of the customization are actually 'hooked' in to the framework by creating your own custom functions. The old way of simply creating a new template and then assigning it to a page or post won't work with Thesis.
So basically I had to answer the question ...
After searching online, I finally found an answer to my problem. Creating Custom Classes. In Gary Jones' tutorial in creating an XHTML sitemap for Thesis, I recognized the ultimate solution to customizations in Thesis - leveraging the Object Oriented nature of the Thesis framework. Gary basically makes all customizations in a custom classes file as in this example for an XHTML sitemap. Following Gary's example, we create a file for our new class entitled GT_Sitemap.php, and place it in a directory named classes which is located in under our Thesis custom directory.
ColdFISH is developed by Jason Delmore. Source code and license information available at coldfish.riaforge.org
<?php
/**
* Allows XHTML sitemap to be added
*
* @package GT_Sitemap
* @author Gary Jones
* @version 2010-05-19
* @since 2010-03-20
*/
class GT_Sitemap {
/**
* @var string
*/
protected $_pagesText;
/**
* @var string
*/
protected $_postsText;
/**
* @var string
*/
protected $_archivesText;
/**
* @var int
*/
protected $_headingLevel;
/**
* @var array
*/
protected $_order = array();
/**
* @var bool
*/
protected $_showPageDate;
/**
* @var string
*/
protected $_showPostDate;
/**
* @var bool
*/
protected $_showPostCount;
/**
* @var string
*/
protected $_archivesType;
/**
* @var string
*/
protected $_pagesDateFormat;
/**
* @var string
*/
protected $_postsDateFormat;
/**
* @var string
*/
protected $_customPagesQuery = '';
/**
* PHP4 compatible constructor
*/
public function GT_Sitemap() {
if(version_compare(PHP_VERSION,"5.0.0","__construct")) {
register_shutdown_function(array($this,"__destruct"));
}
}
/**
* PHP5 constructor, setting defaults
*/
public function __construct() {
$this->_pagesText = 'Pages';
$this->_postsText = 'Posts';
$this->_archivesText = 'Monthly Archives';
$this->_headingLevel = 3;
$this->_order = array('pages', 'posts', 'archives');
$this->_showPageDate = true;
$this->_showPostDate = 'published';
$this->_showPostCount = true;
$this->_archivesType = 'monthly';
$this->_pagesDateFormat = get_option('date_format');
$this->_postsDateFormat = get_option('date_format');
$this->_customPagesQuery = '';
}
/**
* @param string $id
*/
public function setPagesText($id) {
$this->_pagesText = $id;
return $this;
}
/**
* @param string $id
*/
public function setPostsText($id) {
$this->_postsText = $id;
return $this;
}
/**
* @param string $id
*/
public function setArchivesText($id) {
$this->_archivesText = $id;
return $this;
}
/**
* @param array $id
*/
public function setOrder($arg1, $arg2 = null, $arg3 = null) {
$this->_order = func_get_args();
return $this;
}
/**
* @param int $id
*/
public function setHeadingLevel($id) {
$this->_headingLevel = $id;
return $this;
}
/**
* @param string $id
*/
public function setPageDateFormat($id) {
if ( 0 === func_num_args() ) {
$this->_showPageDate = '';
} else {
$this->_pagesDateFormat = $id;
}
return $this;
}
/**
* @param string $id
*/
public function setPostDateFormat($id) {
if ( 0 === func_num_args() ) {
$this->_showPostDate = '';
} else {
$this->_postsDateFormat = $id;
}
return $this;
}
/**
* @param string $id
*/
public function setDateFormat($id) {
$this->setPageDateFormat($id);
$this->setPostDateFormat($id);
return $this;
}
/**
*
*/
public function hidePostCount() {
$this->_showPostCount = false;
return $this;
}
/**
* @param string $id
*/
public function setArchivesType($id) {
$archiveTypes = array('yearly', 'monthly', 'daily', 'weekly', 'postbypost', 'alpha');
if ( in_array($id, $archiveTypes) ) {
$this->_archivesType = $id;
$this->setArchivesText(substr_replace($id, strtoupper(substr($id, 0, 1)), 0, 1) . ' Archives');
}
return $this;
}
/**
* @param string $id
*/
function setCustomPagesQuery($id) {
$this->_customPagesQuery = $id;
return $this;
}
/**
* @param string $shortcode The shortcode keyword that will be used to output the sitemap
*/
public function shortcode($shortcode) {
add_shortcode( $shortcode, array(&$this, 'build') );
}
/**
* Does the main work of creating the output
*/
public function build() {
foreach ($this->_order as $section) {
if ( 'pages' === $section ) {
$output .= '<h' . $this->_headingLevel . '>' . $this->_pagesText . '</h' . $this->_headingLevel . '>' . "\n"
. '<ul>' . "\n" . wp_list_pages('echo=0&show_date=' . $this->_showPageDate . '&date_format=' . $this->_pagesDateFormat . '&title_li=&' . $this->_customPagesQuery) . '</ul>' . "\n";
}
if ( 'posts' === $section ) {
$output .= '<h' . $this->_headingLevel . '>' . $this->_postsText . '</h'. $this->_headingLevel . '>'."\n"
. '<ul>' . "\n" . $this->_posts_by_category() . '</ul>' . "\n";
}
if ( 'archives' === $section ) {
$output .= '<h' . $this->_headingLevel . '>' . $this->_archivesText . '</h'. $this->_headingLevel . '>' . "\n"
. '<ul>' . "\n" . wp_get_archives('type=' . $this->_archivesType . '&echo=0&show_post_count=' . $this->_showPostCount). '</ul>' . "\n";
}
}
return $output;
}
protected function _posts_by_category() {
global $wpdb, $post;
$tp = $wpdb->prefix;
$sort_code = 'ORDER BY name ASC, post_date DESC';
$the_output = NULL;
$last_posts = (array)$wpdb->get_results("SELECT {$tp}terms.name, {$tp}terms.term_id, {$tp}term_taxonomy.term_taxonomy_id FROM {$tp}terms, {$tp}term_taxonomy WHERE {$tp}terms.term_id = {$tp}term_taxonomy.term_id AND {$tp}term_taxonomy.taxonomy = 'category'");
if (empty($last_posts)) {
return NULL;
}
$the_output .= '';
$used_cats = array();
$i = 0;
foreach ($last_posts as $posts) {
if (in_array($posts->name, $used_cats)) {
unset($last_posts[$i]);
} else {
$used_cats[] = $posts->name;
}
$i++;
}
$last_posts = array_values($last_posts);
foreach ($last_posts as $posts) {
$the_output .= '<li><a href="' . get_category_link($posts->term_id) .' "<strong>' . apply_filters('list_cats', $posts->name, $posts) . '</strong></a><ul>';
$arcresults = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' AND ID IN (SELECT object_id FROM {$tp}term_relationships, {$tp}terms WHERE {$tp}term_relationships.term_taxonomy_id =" . $posts->term_taxonomy_id . ") ORDER BY post_date DESC");
foreach ( $arcresults as $arcresult ) {
$the_output .= '<li><a href="' . get_permalink($arcresult->ID) . '">' . apply_filters('the_title', $arcresult->post_title) . '</a> ';
if ($this->_showPostDate) {
$the_output .= date($this->_postsDateFormat,strtotime($arcresult->post_date));
}
$the_output .= '</li>';
}
$the_output .= '</ul></li>';
}
return $the_output;
}
}
?>
1<?php
2/**
3* Allows XHTML sitemap to be added
4*
5* @package GT_Sitemap
6* @author Gary Jones
7* @version 2010-05-19
8* @since 2010-03-20
9*/
10
11class GT_Sitemap {
12 /**
13 * @var string
14 */
15 protected $_pagesText;
16 /**
17 * @var string
18 */
19 protected $_postsText;
20 /**
21 * @var string
22 */
23 protected $_archivesText;
24 /**
25 * @var int
26 */
27 protected $_headingLevel;
28 /**
29 * @var array
30 */
31 protected $_order = array();
32 /**
33 * @var bool
34 */
35 protected $_showPageDate;
36 /**
37 * @var string
38 */
39 protected $_showPostDate;
40 /**
41 * @var bool
42 */
43 protected $_showPostCount;
44 /**
45 * @var string
46 */
47 protected $_archivesType;
48 /**
49 * @var string
50 */
51 protected $_pagesDateFormat;
52 /**
53 * @var string
54 */
55 protected $_postsDateFormat;
56 /**
57 * @var string
58 */
59 protected $_customPagesQuery = '';
60 /**
61 * PHP4 compatible constructor
62 */
63 public function GT_Sitemap() {
64 if(version_compare(PHP_VERSION,"5.0.0","__construct")) {
65 register_shutdown_function(array($this,"__destruct"));
66 }
67 }
68 /**
69 * PHP5 constructor, setting defaults
70 */
71 public function __construct() {
72 $this->_pagesText = 'Pages';
73 $this->_postsText = 'Posts';
74 $this->_archivesText = 'Monthly Archives';
75 $this->_headingLevel = 3;
76 $this->_order = array('pages', 'posts', 'archives');
77 $this->_showPageDate = true;
78 $this->_showPostDate = 'published';
79 $this->_showPostCount = true;
80 $this->_archivesType = 'monthly';
81 $this->_pagesDateFormat = get_option('date_format');
82 $this->_postsDateFormat = get_option('date_format');
83 $this->_customPagesQuery = '';
84 }85 /**
86 * @param string $id
87 */88 public function setPagesText($id)
{89 $this->_pagesText = $id;
90 return $this;
91 }92 /**
93 * @param string $id
94 */95 public function setPostsText($id)
{96 $this->_postsText = $id;
97 return $this;
98 }99 /**
100 * @param string $id
101 */102 public function setArchivesText($id)
{103 $this->_archivesText = $id;
104 return $this;
105 }106 /**
107 * @param array $id
108 */109 public function setOrder($arg1, $arg2 = null, $arg3 = null)
{110 $this->_order = func_get_args();
111 return $this;
112 }113 /**
114 * @param int $id
115 */116 public function setHeadingLevel($id)
{117 $this->_headingLevel = $id;
118 return $this;
119 }120 /**
121 * @param string $id
122 */123 public function setPageDateFormat($id)
{124 if ( 0 === func_num_args() )
{125 $this->_showPageDate = '';
126 } else
{127 $this->_pagesDateFormat = $id;
128 }129 return $this;
130 }131 /**
132 * @param string $id
133 */134 public function setPostDateFormat($id)
{135 if ( 0 === func_num_args() )
{136 $this->_showPostDate = '';
137 } else
{138 $this->_postsDateFormat = $id;
139 }140 return $this;
141 }142 /**
143 * @param string $id
144 */145 public function setDateFormat($id)
{146 $this->setPageDateFormat($id);
147 $this->setPostDateFormat($id);
148 return $this;
149 }150 /**
151 *
152 */153 public function hidePostCount()
{154 $this->_showPostCount = false;
155 return $this;
156 }157 /**
158 * @param string $id
159 */160 public function setArchivesType($id)
{161 $archiveTypes = array('yearly', 'monthly', 'daily', 'weekly', 'postbypost', 'alpha');
162 if ( in_array($id, $archiveTypes) )
{163 $this->_archivesType = $id;
164 $this->setArchivesText(substr_replace($id, strtoupper(substr($id, 0, 1)), 0, 1) . ' Archives');
165 }166 return $this;
167 }168 /**
169 * @param string $id
170 */171 function setCustomPagesQuery($id)
{172 $this->_customPagesQuery = $id;
173 return $this;
174 }175 /**
176 * @param string $shortcode The shortcode keyword that will be used to output the sitemap
177 */178 public function shortcode($shortcode)
{179 add_shortcode( $shortcode, array(&$this, 'build') );
180 }181 /**
182 * Does the main work of creating the output
183 */184 public function build()
{185 foreach ($this->_order as $section)
{186 if ( 'pages' === $section )
{187 $output .= '
<h' . $this->_headingLevel . '>' . $this->_pagesText . '
</h' . $this->_headingLevel . '>' . "\n"
188 . '
<ul>' . "\n" . wp_list_pages('echo=0&show_date=' . $this->_showPageDate . '&date_format=' . $this->_pagesDateFormat . '&title_li=&' . $this->_customPagesQuery) . '
</ul>' . "\n";
189 }190 if ( 'posts' === $section )
{191 $output .= '
<h' . $this->_headingLevel . '>' . $this->_postsText . '
</h'. $this->_headingLevel . '>'."\n"
192 . '
<ul>' . "\n" . $this->_posts_by_category() . '
</ul>' . "\n";
193 }194 if ( 'archives' === $section )
{195 $output .= '
<h' . $this->_headingLevel . '>' . $this->_archivesText . '
</h'. $this->_headingLevel . '>' . "\n"
196 . '
<ul>' . "\n" . wp_get_archives('type=' . $this->_archivesType . '&echo=0&show_post_count=' . $this->_showPostCount). '
</ul>' . "\n";
197 }198 }199 return $output;
200 }201 protected function _posts_by_category()
{202 global $wpdb, $post;
203 $tp = $wpdb->prefix;
204 $sort_code = 'ORDER BY name ASC, post_date DESC';
205 $the_output = NULL;
206 $last_posts = (array)$wpdb->get_results("SELECT
{$tp
}terms.name,
{$tp
}terms.term_id,
{$tp
}term_taxonomy.term_taxonomy_id FROM
{$tp
}terms,
{$tp
}term_taxonomy WHERE
{$tp
}terms.term_id =
{$tp
}term_taxonomy.term_id AND
{$tp
}term_taxonomy.taxonomy = 'category'");
207 if (empty($last_posts))
{208 return NULL;
209 }210 $the_output .= '';
211 $used_cats = array();
212 $i = 0;
213 foreach ($last_posts as $posts)
{214 if (in_array($posts->name, $used_cats))
{215 unset($last_posts[$i]);
216 } else
{217 $used_cats[] = $posts->name;
218 }219 $i++;
220 }221 $last_posts = array_values($last_posts);
222 foreach ($last_posts as $posts)
{223 $the_output .= '<li><a href="' . get_category_link($posts->term_id) .' "<strong>' . apply_filters('list_cats', $posts->name, $posts) . '</strong></a><ul>';
224 225 $arcresults = $wpdb->get_results("SELECT * FROM $wpdb->posts WHERE post_type = 'post' AND post_status = 'publish' AND ID IN (SELECT object_id FROM
{$tp
}term_relationships,
{$tp
}terms WHERE
{$tp
}term_relationships.term_taxonomy_id =" . $posts->term_taxonomy_id . ") ORDER BY post_date DESC");
226 227 foreach ( $arcresults as $arcresult )
{228 $the_output .= '<li><a href="' . get_permalink($arcresult->ID) . '">' . apply_filters('the_title', $arcresult->post_title) . '</a> ';
229 if ($this->_showPostDate)
{230 $the_output .= date($this->_postsDateFormat,strtotime($arcresult->post_date));
231 }232 $the_output .= '</li>';
233 }234 $the_output .= '</ul></li>';
235 }236 return $the_output;
237 }238 }239 ?>
Then, we simply add the next three lines of code in our custom_functions.php file:
The first line simply includes our custom class file. The second line then instantiates a new sitemap object and third, we assign the variable $sitemap to the shortcode 'sitemap' so that all we need to do is to add the shortcode in the body of a new page or post and voila' - we have a new sitemap.
Note: If you wish to implement this code, I had to modify several lines from the code I found on Gary's site - In a comparison with Gary's code, you'll see there are several differences. Apparently Gary made some changes to the current code which were not updated. I modified the current code on his site with some of the older code I found here. In short, I had to debug several lines to come up with the code above. If it works for you great. If not - Hey, I got it to work but I can't guarantee it for you ...